[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
faster m4_foreach, m4_set_foreach, m4_foreach_w [was: faster m4_for]
From: |
Eric Blake |
Subject: |
faster m4_foreach, m4_set_foreach, m4_foreach_w [was: faster m4_for] |
Date: |
Wed, 05 Nov 2008 20:39:09 -0700 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.17) Gecko/20080914 Thunderbird/2.0.0.17 Mnenhy/0.7.5.666 |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
According to Eric Blake on 11/4/2008 4:04 PM:
> m4_for now passes the two arguments [m4_define([var],], [)expr] in place of
> the
> old arguments [var], [expr] and keeps its original semantics (the unbalanced
> ()
> in pre and post are intentional, but at least they are better than _m4_map,
> where the unbalance is split across caller and callee rather than across two
> caller arguments; I have a pending patch to clean that up next).
More like a series of patches; all with the goal of providing a clean
PRE[arg]POST interface for the various m4_foreach/m4_map family of macros,
where PRE and POST can contain matching but unbalanced (), and can inject
more than one argument per iteration to a helper macro, when compared with
the clunkier EXPR(m4_defn([VAR])) of m4_foreach which is hammering on the
m4 symbol table by constantly redefining and accessing a temporary variable.
I'm still debating about documenting these new macros, but will probably
do so in the next week because of how much speedup they provided:
m4_map_args_sep
m4_map_args_w
m4_set_map_sep
I'm going ahead and applying this series of seven patches, because of the
huge speedups it gave me. I tested 'time autoconf -f' on coreutils with
m4 1.4.11 (things went from 15.911 to 13.175, 17% improvement), and with
m4.git branch-1.6 (things went from 13.680 to 11.566, 15% improvement);
the bulk of the speedup comes from the final patch, where I overhauled
m4_foreach_w to use fewer regular expressions and macro calls. I was
surprised to even find a use for m4_substr (in general, because m4_substr
doesn't quote its result, it is unsafe for most uses). Modulo version
number changes, I verified that the resulting configure file was
unchanged, just generated faster; and I ran a complete testsuite.
Eric Blake (7):
Improve m4_for performance.
Add m4_map_args_sep, undocumented for now.
Unify _m4_foreach and _m4_map.
Use _m4_foreach in more places.
Unify m4_set_foreach and m4_set_map.
Use m4_set_map_sep in more places.
Add m4_map_args_w.
> From: Eric Blake <address@hidden>
> Date: Tue, 4 Nov 2008 12:35:09 -0700
> Subject: [PATCH] Improve m4_for performance.
>
> * lib/m4sugar/m4sugar.m4 (_m4_for): Alter API to make it easier to
> avoid m4_define by some clients.
> (m4_for): Adjust caller.
> * lib/m4sugar/foreach.m4 (_m4_foreach, m4_case, m4_bmatch)
> (_m4_cond, _m4_bpatsubsts, _m4_shiftn, m4_do, m4_reverse)
> (_m4_map, m4_map_args, m4_map_args_pair, _m4_list_pad)
> (_m4_list_cmp): Likewise.
I'm applying this one unchanged. On top of it are the six new patches:
- --
Don't work too hard, make some time for fun as well!
Eric Blake address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEARECAAYFAkkSZt0ACgkQ84KuGfSFAYCSGgCfZXBabiiLRUgcNaq9E2fVEfEA
cLkAoKIei4zoFaPIWUoiCFNnK2/HDbdt
=zb5L
-----END PGP SIGNATURE-----
>From 1329287eb793d45ae2375414c0ec2fc17b10871d Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Mon, 3 Nov 2008 17:17:38 -0700
Subject: [PATCH] Add m4_map_args_sep, undocumented for now.
* lib/m4sugar/m4sugar.m4 (m4_map_args_sep): New macro.
(_m4_map): Change API to cover more of m4_map*.
* lib/m4sugar/foreach.m4 (_m4_map): Adjust to new API.
(m4_map_args): Delete.
* tests/m4sugar.at (m4@&address@hidden and m4@&address@hidden): Enhance
test.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 8 ++++++
lib/m4sugar/foreach.m4 | 40 +++++++++---------------------
lib/m4sugar/m4sugar.m4 | 62 +++++++++++++++++++++++++----------------------
tests/m4sugar.at | 13 +++++++---
4 files changed, 62 insertions(+), 61 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2cbc291..c8597fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2008-11-04 Eric Blake <address@hidden>
+ Add m4_map_args_sep, undocumented for now.
+ * lib/m4sugar/m4sugar.m4 (m4_map_args_sep): New macro.
+ (_m4_map): Change API to cover more of m4_map*.
+ * lib/m4sugar/foreach.m4 (_m4_map): Adjust to new API.
+ (m4_map_args): Delete.
+ * tests/m4sugar.at (m4@&address@hidden and m4@&address@hidden): Enhance
+ test.
+
Improve m4_for performance.
* lib/m4sugar/m4sugar.m4 (_m4_for): Alter API to make it easier to
avoid m4_define by some clients.
diff --git a/lib/m4sugar/foreach.m4 b/lib/m4sugar/foreach.m4
index cb08212..29c1a28 100644
--- a/lib/m4sugar/foreach.m4
+++ b/lib/m4sugar/foreach.m4
@@ -264,38 +264,22 @@ m4_define([m4_reverse],
[[, ]m4_dquote($], [)])[_m4_popdef([_m4_r])])_m4_r($@)])])
-# m4_map(MACRO, LIST)
-# -------------------
-# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements
-# of LIST. $1, $2... must in turn be lists, appropriate for m4_apply.
+# _m4_map(PRE, POST, IGNORED, LIST)
+# ---------------------------------
+# Form the common basis of the m4_map macros. For each element of
+# LIST, expand PRE[element]POST[]. The IGNORED argument makes
+# recursion easier, and must be supplied rather than implicit.
#
-# m4_map/m4_map_sep only execute once; the speedup comes in fixing
-# _m4_map. The mismatch in () is intentional, since $1 supplies the
-# opening `(' (but it sure looks odd!). Build the temporary _m4_m:
-# $1, [$3])$1, [$4])...$1, [$m])_m4_popdef([_m4_m])
+# m4_map{,all,_args}{,_sep} each only execute once; the speedup comes
+# in fixing _m4_map. Build the temporary _m4_m:
+# $1[$4]$2[]$1[$5]$2[]...$1[$m]$2[]_m4_popdef([_m4_m])
m4_define([_m4_map],
-[m4_if([$#], [2], [],
- [m4_pushdef([_m4_m], _m4_for([3], [$#], [1],
- [$0_([1],], [)])[_m4_popdef([_m4_m])])_m4_m($@)])])
+[m4_if([$#], [3], [],
+ [m4_pushdef([_m4_m], _m4_for([4], [$#], [1],
+ [$0_([1], [2],], [)])[_m4_popdef([_m4_m])])_m4_m($@)])])
m4_define([_m4_map_],
-[[$$1, [$$2])]])
-
-# m4_map_args(EXPRESSION, ARG...)
-# -------------------------------
-# Expand EXPRESSION([ARG]) for each argument. More efficient than
-# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
-#
-# Invoke the temporary macro _m4_map_args, defined as:
-# $1([$2])[]$1([$3])[]...$1([$m])[]_m4_popdef([_m4_map_args])
-m4_define([m4_map_args],
-[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
- [$#], [1], [],
- [m4_pushdef([_$0], _m4_for([2], [$#], [1],
- [_$0_([1],], [)])[_m4_popdef([_$0])])_$0($@)])])
-
-m4_define([_m4_map_args_],
-[[$$1([$$2])[]]])
+[[$$1[$$3]$$2[]]])
# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
# -------------------------------------------------------------
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index f866112..ded4edc 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1079,6 +1079,17 @@ m4_define([m4_foreach_w],
[m4_foreach([$1], m4_split(m4_normalize([$2]), [ ]), [$3])])
+# _m4_map(PRE, POST, IGNORED, LIST)
+# ---------------------------------
+# Form the common basis of the m4_map macros. For each element of
+# LIST, expand PRE[element]POST[]. The IGNORED argument makes
+# recursion easier, and must be supplied rather than implicit.
+#
+# Please keep foreach.m4 in sync with any adjustments made here.
+m4_define([_m4_map],
+[m4_if([$#], [3], [],
+ [$1[$4]$2[]$0([$1], [$2], m4_shift3($@))])])
+
# m4_map(MACRO, LIST)
# m4_mapall(MACRO, LIST)
# ----------------------
@@ -1089,19 +1100,15 @@ m4_define([m4_foreach_w],
#
# Since LIST may be quite large, we want to minimize how often it
# appears in the expansion. Rather than use m4_car/m4_cdr iteration,
-# we unbox the list, ignore the second argument, and use m4_shift2 to
-# detect the end of recursion. The mismatch in () is intentional; see
-# _m4_map. For m4_map, an empty list behaves like an empty sublist
-# and gets ignored; for m4_mapall, we must special-case the empty
-# list.
-#
-# Please keep foreach.m4 in sync with any adjustments made here.
+# we unbox the list, and use _m4_map for iteration. For m4_map, an
+# empty list behaves like an empty sublist and gets ignored; for
+# m4_mapall, we must special-case the empty list.
m4_define([m4_map],
-[_m4_map([_m4_apply([$1]], [], $2)])
+[_m4_map([_m4_apply([$1],], [)], [], $2)])
m4_define([m4_mapall],
[m4_if([$2], [], [],
- [_m4_map([m4_apply([$1]], [], $2)])])
+ [_m4_map([m4_apply([$1],], [)], [], $2)])])
# m4_map_sep(MACRO, SEPARATOR, LIST)
@@ -1123,39 +1130,24 @@ m4_define([m4_mapall],
# helper macro and use that as the separator instead.
m4_define([m4_map_sep],
[m4_pushdef([m4_Sep], [m4_define([m4_Sep], _m4_defn([m4_unquote]))])]dnl
-[_m4_map([_m4_apply([m4_Sep([$2])[]$1]], [], $3)m4_popdef([m4_Sep])])
+[_m4_map([_m4_apply([m4_Sep([$2])[]$1],], [)], [], $3)m4_popdef([m4_Sep])])
m4_define([m4_mapall_sep],
[m4_if([$3], [], [], [_$0([$1], [$2], $3)])])
m4_define([_m4_mapall_sep],
-[m4_apply([$1], [$3])_m4_map([m4_apply([$2[]$1]], m4_shift2($@))])
-
-# _m4_map(PREFIX, IGNORED, SUBLIST, ...)
-# --------------------------------------
-# Common implementation for all four m4_map variants. The mismatch in
-# the number of () is intentional. PREFIX must supply a form of
-# m4_apply, the open `(', and the MACRO to be applied. Each iteration
-# then appends `,', the current SUBLIST and the closing `)', then
-# recurses to the next SUBLIST. IGNORED is an aid to ending recursion
-# efficiently.
-#
-# Please keep foreach.m4 in sync with any adjustments made here.
-m4_define([_m4_map],
-[m4_if([$#], [2], [],
- [$1, [$3])$0([$1], m4_shift2($@))])])
+[m4_apply([$1], [$3])_m4_map([m4_apply([$2[]$1],], [)], m4_shift2($@))])
# m4_map_args(EXPRESSION, ARG...)
# -------------------------------
# Expand EXPRESSION([ARG]) for each argument. More efficient than
-# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
-#
-# Please keep foreach.m4 in sync with any adjustments made here.
+# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))])
+# Shorthand for m4_map_args_sep([EXPRESSION(], [)], [], ARG...).
m4_define([m4_map_args],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [],
[$#], [2], [$1([$2])[]],
- [$1([$2])[]$0([$1], m4_shift2($@))])])
+ [_m4_map([$1(], [)], $@)])])
# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
@@ -1181,6 +1173,18 @@ m4_define([m4_map_args_pair],
[$1([$3], [$4])[]$0([$1], [$2], m4_shift(m4_shift3($@)))])])
+# m4_map_args_sep(PRE, POST, SEP, ARG...)
+# ---------------------------------------
+# Expand PRE[ARG]POST for each argument, with SEP between arguments.
+m4_define([m4_map_args_sep],
+[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
+ [$#], [1], [],
+ [$#], [2], [],
+ [$#], [3], [],
+ [$#], [4], [$1[$4]$2[]],
+ [$1[$4]$2[]_m4_map([$3[]$1], [$2], m4_shift3($@))])])
+
+
# m4_stack_foreach(MACRO, FUNC)
# m4_stack_foreach_lifo(MACRO, FUNC)
# ----------------------------------
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 70bb24b..c8b22eb 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -1091,12 +1091,13 @@ hi
AT_CLEANUP
-## ---------------------------------- ##
-## m4_map_args{,_pair} and m4_curry. ##
-## ---------------------------------- ##
+## --------------------------------------- ##
+## m4_map_args{,_sep,_pair} and m4_curry. ##
+## --------------------------------------- ##
AT_SETUP([m4@&address@hidden and m4@&address@hidden)
-AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden
+m4@&address@hidden)
dnl First, make sure we can curry in isolation.
AT_CHECK_M4SUGAR_TEXT(
@@ -1125,6 +1126,8 @@ m4_map_args_pair([, m4_reverse], [, m4_dquote], [1])
m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2])
m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3])
m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4])
+m4_map_args_sep([<], [>], [:], [1], [2], [3])
+m4_map_args_sep([m4_echo(], [)], [ ], [plain], [active])
]],
[[
plain active
@@ -1138,6 +1141,8 @@ plainACTIVE
, 2, 1
, 2, 1, [3]
, 2, 1, 4, 3
+<1>:<2>:<3>
+plain active
]])
dnl Finally, put the two concepts together, to show the real power of the API.
--
1.6.0.2
>From aae086a2f71b316f2f29ad6ad3d45a8c69fffe3c Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 5 Nov 2008 07:15:56 -0700
Subject: [PATCH] Unify _m4_foreach and _m4_map.
* lib/m4sugar/m4sugar.m4 (_m4_map): Delete, merged with...
(_m4_foreach): ...this.
(m4_foreach, m4_map, m4_mapall, m4_map_sep, _m4_mapall_sep)
(m4_map_args, m4_map_args_sep): Adjust callers.
* lib/m4sugar/foreach.m4 (_m4_map): Rename...
(_m4_foreach): ...to this, overwriting old definition.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 10 +++++++++
lib/m4sugar/foreach.m4 | 53 ++++++++++++++++-------------------------------
lib/m4sugar/m4sugar.m4 | 44 ++++++++++++++++++---------------------
3 files changed, 48 insertions(+), 59 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index c8597fd..b5a82a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-11-05 Eric Blake <address@hidden>
+
+ Unify _m4_foreach and _m4_map.
+ * lib/m4sugar/m4sugar.m4 (_m4_map): Delete, merged with...
+ (_m4_foreach): ...this.
+ (m4_foreach, m4_map, m4_mapall, m4_map_sep, _m4_mapall_sep)
+ (m4_map_args, m4_map_args_sep): Adjust callers.
+ * lib/m4sugar/foreach.m4 (_m4_map): Rename...
+ (_m4_foreach): ...to this, overwriting old definition.
+
2008-11-04 Eric Blake <address@hidden>
Add m4_map_args_sep, undocumented for now.
diff --git a/lib/m4sugar/foreach.m4 b/lib/m4sugar/foreach.m4
index 29c1a28..f432598 100644
--- a/lib/m4sugar/foreach.m4
+++ b/lib/m4sugar/foreach.m4
@@ -79,29 +79,29 @@
#
# Please keep this file in sync with m4sugar.m4.
-# m4_foreach(VARIABLE, LIST, EXPRESSION)
-# --------------------------------------
-# Expand EXPRESSION assigning each value of the LIST to VARIABLE.
-# LIST should have the form `item_1, item_2, ..., item_n', i.e. the
-# whole list must *quoted*. Quote members too if you don't want them
-# to be expanded.
+# _m4_foreach(PRE, POST, IGNORED, ARG...)
+# ---------------------------------------
+# Form the common basis of the m4_foreach and m4_map macros. For each
+# ARG, expand PRE[ARG]POST[]. The IGNORED argument makes recursion
+# easier, and must be supplied rather than implicit.
#
# This version minimizes the number of times that $@ is evaluated by
-# using m4_for to generate a boilerplate into VARIABLE then passing $@
-# to that temporary macro. Thus, the recursion is done in m4_for
-# without reparsing any user input, and is not quadratic. For an idea
-# of how this works, note that m4_foreach(i,[1,2],[i]) defines i to be
-# m4_define([$1],[$3])$2[]m4_define([$1],[$4])$2[]m4_popdef([i])
-# then calls i([i],[i],[1],[2]).
-m4_define([m4_foreach],
-[m4_if([$2], [], [], [_$0([$1], [$3], $2)])])
-
+# using m4_for to generate a boilerplate into _m4_f then passing $@ to
+# that temporary macro. Thus, the recursion is done in m4_for without
+# reparsing any user input, and is not quadratic. For an idea of how
+# this works, note that m4_foreach(i,[1,2],[i]) calls
+# _m4_foreach([m4_define([i],],[)i],[],[1],[2])
+# which defines _m4_f:
+# $1[$4]$2[]$1[$5]$2[]_m4_popdef([_m4_f])
+# then calls _m4_f([m4_define([i],],[)i],[],[1],[2]) for a net result:
+# m4_define([i],[1])i[]m4_define([i],[2])i[]_m4_popdef([_m4_f]).
m4_define([_m4_foreach],
-[m4_pushdef([$1], _m4_for([3], [$#], [1],
- [$0_([1], [2],], [)])[m4_popdef([$1])])m4_indir([$1], $@)])
+[m4_if([$#], [3], [],
+ [m4_pushdef([_m4_f], _m4_for([4], [$#], [1],
+ [$0_([1], [2],], [)])[_m4_popdef([_m4_f])])_m4_f($@)])])
m4_define([_m4_foreach_],
-[[m4_define([$$1], [$$3])$$2[]]])
+[[$$1[$$3]$$2[]]])
# m4_case(SWITCH, VAL1, IF-VAL1, VAL2, IF-VAL2, ..., DEFAULT)
# -----------------------------------------------------------
@@ -264,23 +264,6 @@ m4_define([m4_reverse],
[[, ]m4_dquote($], [)])[_m4_popdef([_m4_r])])_m4_r($@)])])
-# _m4_map(PRE, POST, IGNORED, LIST)
-# ---------------------------------
-# Form the common basis of the m4_map macros. For each element of
-# LIST, expand PRE[element]POST[]. The IGNORED argument makes
-# recursion easier, and must be supplied rather than implicit.
-#
-# m4_map{,all,_args}{,_sep} each only execute once; the speedup comes
-# in fixing _m4_map. Build the temporary _m4_m:
-# $1[$4]$2[]$1[$5]$2[]...$1[$m]$2[]_m4_popdef([_m4_m])
-m4_define([_m4_map],
-[m4_if([$#], [3], [],
- [m4_pushdef([_m4_m], _m4_for([4], [$#], [1],
- [$0_([1], [2],], [)])[_m4_popdef([_m4_m])])_m4_m($@)])])
-
-m4_define([_m4_map_],
-[[$$1[$$3]$$2[]]])
-
# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
# -------------------------------------------------------------
# Perform a pairwise grouping of consecutive ARGs, by expanding
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index ded4edc..89d26c3 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1052,16 +1052,23 @@ m4_define([_m4_for],
# more memory for expansion. So, rather than directly compare $2 against
# [] and use m4_car/m4_cdr for recursion, we instead unbox the list (which
# requires swapping the argument order in the helper), insert an ignored
-# third argument, and use m4_shift3 to detect when recursion is complete.
-#
-# Please keep foreach.m4 in sync with any adjustments made here.
+# third argument, and use m4_shift3 to detect when recursion is complete,
+# at which point this looks very much like m4_map_args.
m4_define([m4_foreach],
[m4_if([$2], [], [],
- [m4_pushdef([$1])_$0([$1], [$3], [], $2)m4_popdef([$1])])])
+ [m4_pushdef([$1])_$0([m4_define([$1],], [)$3], [],
+ $2)m4_popdef([$1])])])
+# _m4_foreach(PRE, POST, IGNORED, ARG...)
+# ---------------------------------------
+# Form the common basis of the m4_foreach and m4_map macros. For each
+# ARG, expand PRE[ARG]POST[]. The IGNORED argument makes recursion
+# easier, and must be supplied rather than implicit.
+#
+# Please keep foreach.m4 in sync with any adjustments made here.
m4_define([_m4_foreach],
[m4_if([$#], [3], [],
- [m4_define([$1], [$4])$2[]$0([$1], [$2], m4_shift3($@))])])
+ [$1[$4]$2[]$0([$1], [$2], m4_shift3($@))])])
# m4_foreach_w(VARIABLE, LIST, EXPRESSION)
@@ -1079,17 +1086,6 @@ m4_define([m4_foreach_w],
[m4_foreach([$1], m4_split(m4_normalize([$2]), [ ]), [$3])])
-# _m4_map(PRE, POST, IGNORED, LIST)
-# ---------------------------------
-# Form the common basis of the m4_map macros. For each element of
-# LIST, expand PRE[element]POST[]. The IGNORED argument makes
-# recursion easier, and must be supplied rather than implicit.
-#
-# Please keep foreach.m4 in sync with any adjustments made here.
-m4_define([_m4_map],
-[m4_if([$#], [3], [],
- [$1[$4]$2[]$0([$1], [$2], m4_shift3($@))])])
-
# m4_map(MACRO, LIST)
# m4_mapall(MACRO, LIST)
# ----------------------
@@ -1100,15 +1096,15 @@ m4_define([_m4_map],
#
# Since LIST may be quite large, we want to minimize how often it
# appears in the expansion. Rather than use m4_car/m4_cdr iteration,
-# we unbox the list, and use _m4_map for iteration. For m4_map, an
-# empty list behaves like an empty sublist and gets ignored; for
+# we unbox the list, and use _m4_foreach for iteration. For m4_map,
+# an empty list behaves like an empty sublist and gets ignored; for
# m4_mapall, we must special-case the empty list.
m4_define([m4_map],
-[_m4_map([_m4_apply([$1],], [)], [], $2)])
+[_m4_foreach([_m4_apply([$1],], [)], [], $2)])
m4_define([m4_mapall],
[m4_if([$2], [], [],
- [_m4_map([m4_apply([$1],], [)], [], $2)])])
+ [_m4_foreach([m4_apply([$1],], [)], [], $2)])])
# m4_map_sep(MACRO, SEPARATOR, LIST)
@@ -1130,13 +1126,13 @@ m4_define([m4_mapall],
# helper macro and use that as the separator instead.
m4_define([m4_map_sep],
[m4_pushdef([m4_Sep], [m4_define([m4_Sep], _m4_defn([m4_unquote]))])]dnl
-[_m4_map([_m4_apply([m4_Sep([$2])[]$1],], [)], [], $3)m4_popdef([m4_Sep])])
+[_m4_foreach([_m4_apply([m4_Sep([$2])[]$1],], [)], [], $3)m4_popdef([m4_Sep])])
m4_define([m4_mapall_sep],
[m4_if([$3], [], [], [_$0([$1], [$2], $3)])])
m4_define([_m4_mapall_sep],
-[m4_apply([$1], [$3])_m4_map([m4_apply([$2[]$1],], [)], m4_shift2($@))])
+[m4_apply([$1], [$3])_m4_foreach([m4_apply([$2[]$1],], [)], m4_shift2($@))])
# m4_map_args(EXPRESSION, ARG...)
# -------------------------------
@@ -1147,7 +1143,7 @@ m4_define([m4_map_args],
[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
[$#], [1], [],
[$#], [2], [$1([$2])[]],
- [_m4_map([$1(], [)], $@)])])
+ [_m4_foreach([$1(], [)], $@)])])
# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
@@ -1182,7 +1178,7 @@ m4_define([m4_map_args_sep],
[$#], [2], [],
[$#], [3], [],
[$#], [4], [$1[$4]$2[]],
- [$1[$4]$2[]_m4_map([$3[]$1], [$2], m4_shift3($@))])])
+ [$1[$4]$2[]_m4_foreach([$3[]$1], [$2], m4_shift3($@))])])
# m4_stack_foreach(MACRO, FUNC)
--
1.6.0.2
>From 641487fb34b8bb642ece91340d9fa2a57d75d9ee Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 5 Nov 2008 11:12:42 -0700
Subject: [PATCH] Use _m4_foreach in more places.
* lib/m4sugar/foreach.m4 (m4_dquote_elt, m4_join, m4_joinall)
(_m4_minmax, m4_set_add_all): Use _m4_foreach instead of
m4_foreach.
* lib/m4sugar/m4sugar.m4 (_m4_joinall): Use m4_map_args_sep
instead of m4_foreach or m4_map_args.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 7 +++++++
lib/m4sugar/foreach.m4 | 42 +++++++++++++++++++++---------------------
lib/m4sugar/m4sugar.m4 | 20 +++++++-------------
3 files changed, 35 insertions(+), 34 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index b5a82a8..3be1d3a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2008-11-05 Eric Blake <address@hidden>
+ Use _m4_foreach in more places.
+ * lib/m4sugar/foreach.m4 (m4_dquote_elt, m4_join, m4_joinall)
+ (_m4_minmax, m4_set_add_all): Use _m4_foreach instead of
+ m4_foreach.
+ * lib/m4sugar/m4sugar.m4 (_m4_joinall): Use m4_map_args_sep
+ instead of m4_foreach or m4_map_args.
+
Unify _m4_foreach and _m4_map.
* lib/m4sugar/m4sugar.m4 (_m4_map): Delete, merged with...
(_m4_foreach): ...this.
diff --git a/lib/m4sugar/foreach.m4 b/lib/m4sugar/foreach.m4
index f432598..d9ebfe0 100644
--- a/lib/m4sugar/foreach.m4
+++ b/lib/m4sugar/foreach.m4
@@ -248,9 +248,9 @@ m4_define([m4_do],
# -------------------
# Return ARGS as an unquoted list of double-quoted arguments.
#
-# m4_foreach to the rescue. It's easier to shift off the leading comma.
+# _m4_foreach to the rescue.
m4_define([m4_dquote_elt],
-[m4_shift(m4_foreach([_m4_elt], address@hidden,
[,m4_dquote(_m4_defn([_m4_elt]))]))])
+[m4_if([$#], [0], [], [[[$1]]_m4_foreach([,m4_dquote(], [)], $@)])])
# m4_reverse(ARGS)
# ----------------
@@ -299,23 +299,23 @@ m4_define([_m4_map_args_pair_end],
#
# Use a self-modifying separator, since we don't know how many
# arguments might be skipped before a separator is first printed, but
-# be careful if the separator contains $. m4_foreach to the rescue.
+# be careful if the separator contains $. _m4_foreach to the rescue.
m4_define([m4_join],
[m4_pushdef([_m4_sep], [m4_define([_m4_sep], _m4_defn([m4_echo]))])]dnl
-[m4_foreach([_m4_arg], [m4_shift($@)],
- [m4_ifset([_m4_arg], [_m4_sep([$1])_m4_defn([_m4_arg])])])]dnl
-[_m4_popdef([_m4_sep])])
+[_m4_foreach([_$0([$1],], [)], $@)_m4_popdef([_m4_sep])])
+
+m4_define([_m4_join],
+[m4_if([$2], [], [], [_m4_sep([$1])[$2]])])
# m4_joinall(SEP, ARG1, ARG2...)
# ------------------------------
# Produce ARG1SEPARG2...SEPARGn. An empty ARG results in back-to-back SEP.
# No expansion is performed on SEP or ARGs.
#
-# A bit easier than m4_join. m4_foreach to the rescue.
+# A bit easier than m4_join. _m4_foreach to the rescue.
m4_define([m4_joinall],
[[$2]m4_if(m4_eval([$# <= 2]), [1], [],
- [m4_foreach([_m4_arg], [m4_shift2($@)],
- [[$1]_m4_defn([_m4_arg])])])])
+ [_m4_foreach([$1], [], m4_shift($@))])])
# m4_list_cmp(A, B)
# -----------------
@@ -358,12 +358,12 @@ m4_define([_m4_list_cmp__],
# Return the decimal value of the maximum (or minimum) in a series of
# integer expressions.
#
-# m4_foreach to the rescue; we only need to replace _m4_minmax. Here,
+# _m4_foreach to the rescue; we only need to replace _m4_minmax. Here,
# we need a temporary macro to track the best answer so far, so that
# the foreach expression is tractable.
m4_define([_m4_minmax],
-[m4_pushdef([_m4_best], m4_eval([$2]))m4_foreach([_m4_arg], [m4_shift2($@)],
- [m4_define([_m4_best], $1(_m4_best, _m4_defn([_m4_arg])))])]dnl
+[m4_pushdef([_m4_best], m4_eval([$2]))_m4_foreach(
+ [m4_define([_m4_best], $1(_m4_best,], [))], m4_shift($@))]dnl
[_m4_best[]_m4_popdef([_m4_best])])
# m4_set_add_all(SET, VALUE...)
@@ -371,15 +371,15 @@ m4_define([_m4_minmax],
# Add each VALUE into SET. This is O(n) in the number of VALUEs, and
# can be faster than calling m4_set_add for each VALUE.
#
-# m4_foreach to the rescue. If no deletions have occurred, then avoid
-# the speed penalty of m4_set_add.
+# _m4_foreach to the rescue. If no deletions have occurred, then
+# avoid the speed penalty of m4_set_add.
m4_define([m4_set_add_all],
[m4_if([$#], [0], [], [$#], [1], [],
[m4_define([_m4_set_size($1)], m4_eval(m4_set_size([$1])
- + m4_len(m4_foreach([_m4_arg], [m4_shift($@)],
- m4_ifdef([_m4_set_cleanup($1)],
- [[m4_set_add([$1], _m4_defn([_m4_arg]))]],
- [[m4_ifdef([_m4_set([$1],]_m4_defn([_m4_arg])[)], [],
- [m4_define([_m4_set([$1],]_m4_defn([_m4_arg])[)],
- [1])m4_pushdef([_m4_set([$1])],
- _m4_defn([_m4_arg]))-])]])))))])])
+ + m4_len(_m4_foreach(m4_ifdef([_m4_set_cleanup($1)],
+ [[m4_set_add]], [[_$0]])[([$1],], [)], $@))))])])
+
+m4_define([_m4_set_add_all],
+[m4_ifdef([_m4_set([$1],$2)], [],
+ [m4_define([_m4_set([$1],$2)],
+ [1])m4_pushdef([_m4_set([$1])], [$2])-])])
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 89d26c3..5107792 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -2171,20 +2171,14 @@ m4_define([_m4_joinall],
# m4_combine([, ], [[a], [b], [c]], [-], [1], [2], [3])
# => a-1, a-2, a-3, b-1, b-2, b-3, c-1, c-2, c-3
#
-# In order to have the correct number of SEPARATORs, we use a temporary
-# variable that redefines itself after the first use. We must use defn
-# rather than overquoting in case PREFIX or SUFFIX contains $1, but use
-# _m4_defn for speed. Likewise, we compute the m4_shift3 only once,
-# rather than in each iteration of the outer m4_foreach.
+# This definition is a bit hairy; the thing to realize is that we want
+# to construct m4_map_args_sep([[prefix$3]], [], [[$1]], m4_shift3($@))
+# as the inner loop, using each prefix generated by the outer loop,
+# and without recalculating m4_shift3 every outer iteration.
m4_define([m4_combine],
-[m4_if(m4_eval([$# > 3]), [1],
- [m4_pushdef([m4_Separator], [m4_define([m4_Separator],
- _m4_defn([m4_echo]))])]]dnl
-[[m4_foreach([m4_Prefix], [$2],
- [m4_map_args([m4_Separator([$1])]m4_dquote(_m4_defn(
- [m4_Prefix]))[[$3]m4_echo],
- ]]m4_dquote(m4_dquote(m4_shift3($@)))[[)])]]dnl
-[[_m4_popdef([m4_Separator])])])
+[m4_if([$2], [], [], m4_eval([$# > 3]), [1],
+[m4_map_args_sep([m4_map_args_sep(m4_dquote(], [)[[$3]], [], [[$1]],]]]dnl
+[m4_dquote(m4_dquote(m4_shift3($@)))[[)], [[$1]], $2)])])
# m4_append(MACRO-NAME, STRING, [SEPARATOR])
--
1.6.0.2
>From a8c4be749a992c2e9c2f0a59336f964f4cce6d4f Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 5 Nov 2008 11:47:04 -0700
Subject: [PATCH] Unify m4_set_foreach and m4_set_map.
* lib/m4sugar/m4sugar.m4 (m4_set_map_sep): New macro, undocumented
for now.
(m4_set_contents, m4_set_foreach, m4_set_list, m4_set_listc)
(m4_set_map): Adjust callers.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 6 ++++++
lib/m4sugar/m4sugar.m4 | 28 +++++++++++++++-------------
2 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 3be1d3a..d14b179 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2008-11-05 Eric Blake <address@hidden>
+ Unify m4_set_foreach and m4_set_map.
+ * lib/m4sugar/m4sugar.m4 (m4_set_map_sep): New macro, undocumented
+ for now.
+ (m4_set_contents, m4_set_foreach, m4_set_list, m4_set_listc)
+ (m4_set_map): Adjust callers.
+
Use _m4_foreach in more places.
* lib/m4sugar/foreach.m4 (m4_dquote_elt, m4_join, m4_joinall)
(_m4_minmax, m4_set_add_all): Use _m4_foreach instead of
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 5107792..15fd807 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -2688,8 +2688,7 @@ m4_define([m4_set_contains],
# Use _m4_popdef for speed. The existence of _m4_set_cleanup($1)
# determines which version of _1 helper we use.
m4_define([m4_set_contents],
-[m4_ifdef([_m4_set_cleanup($1)], [_$0_1c], [_$0_1])([$1])_$0_2([$1],
- [], [], [[$2]])])
+[m4_set_map_sep([$1], [], [], [[$2]])])
# _m4_set_contents_1(SET)
# _m4_set_contents_1c(SET)
@@ -2804,9 +2803,7 @@ m4_define([m4_set_empty],
# guaranteed. This is faster than the corresponding m4_foreach([VAR],
# m4_indir([m4_dquote]m4_set_listc([SET])), [ACTION])
m4_define([m4_set_foreach],
-[m4_pushdef([$2])m4_ifdef([_m4_set_cleanup($1)],
- [_m4_set_contents_1c], [_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
- [m4_define([$2],], [)$3[]])m4_popdef([$2])])
+[m4_pushdef([$2])m4_set_map_sep([$1], [m4_define([$2],], [)$3])])
# m4_set_intersection(SET1, SET2)
# -------------------------------
@@ -2835,12 +2832,10 @@ m4_define([m4_set_intersection],
# containing only the empty string; with m4_set_listc, a leading comma
# is output if there are any elements.
m4_define([m4_set_list],
-[m4_ifdef([_m4_set_cleanup($1)], [_m4_set_contents_1c],
- [_m4_set_contents_1])([$1])_m4_set_contents_2([$1], [], [], [,])])
+[m4_set_map_sep([$1], [], [], [,])])
m4_define([m4_set_listc],
-[m4_ifdef([_m4_set_cleanup($1)], [_m4_set_contents_1c],
- [_m4_set_contents_1])([$1])_m4_set_contents_2([$1], [,])])
+[m4_set_map_sep([$1], [,])])
# m4_set_map(SET, ACTION)
# -----------------------
@@ -2848,12 +2843,19 @@ m4_define([m4_set_listc],
# current element. ACTION should not recursively list SET's contents,
# add elements to SET, nor delete any element from SET except the one
# passed as an argument. The order that the elements are visited in
-# is not guaranteed. This is faster than the corresponding
+# is not guaranteed. This is faster than either of the corresponding
# m4_map_args([ACTION]m4_set_listc([SET]))
+# m4_set_foreach([SET], [VAR], [ACTION(m4_defn([VAR]))])
m4_define([m4_set_map],
-[m4_ifdef([_m4_set_cleanup($1)],
- [_m4_set_contents_1c], [_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
- [$2(], [)])])
+[m4_set_map_sep([$1], [$2(], [)])])
+
+# m4_set_map_sep(SET, PRE, POST, SEP)
+# -----------------------------------
+# For each element of SET, expand PRE[value]POST[], and expand SEP
+# between elements.
+m4_define([m4_set_map_sep],
+[m4_ifdef([_m4_set_cleanup($1)], [_m4_set_contents_1c],
+ [_m4_set_contents_1])([$1])_m4_set_contents_2($@)])
# m4_set_remove(SET, VALUE, [IF-PRESENT], [IF-ABSENT])
# ----------------------------------------------------
--
1.6.0.2
>From 4e009d522870613c74305ad49e6cc548133b6bab Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 5 Nov 2008 12:09:00 -0700
Subject: [PATCH] Use m4_set_map_sep in more places.
* lib/m4sugar/m4sugar.m4 (m4_set_difference, m4_set_intersection)
(m4_set_union): Use m4_set_map_sep rather than m4_set_foreach.
* doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
Enhance documentation.
<m4_set_foreach>: Mention faster alternative.
(Looping constructs) <m4_foreach>: Likewise.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 8 ++++++++
doc/autoconf.texi | 14 ++++++++++----
lib/m4sugar/m4sugar.m4 | 31 +++++++++++++++++--------------
3 files changed, 35 insertions(+), 18 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index d14b179..73e8095 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2008-11-05 Eric Blake <address@hidden>
+ Use m4_set_map_sep in more places.
+ * lib/m4sugar/m4sugar.m4 (m4_set_difference, m4_set_intersection)
+ (m4_set_union): Use m4_set_map_sep rather than m4_set_foreach.
+ * doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
+ Enhance documentation.
+ <m4_set_foreach>: Mention faster alternative.
+ (Looping constructs) <m4_foreach>: Likewise.
+
Unify m4_set_foreach and m4_set_map.
* lib/m4sugar/m4sugar.m4 (m4_set_map_sep): New macro, undocumented
for now.
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index bc46d77..e114992 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -10921,6 +10921,9 @@ Looping constructs
@result{}echo foo
@result{}echo bar, baz
@end example
+
+Note that for some forms of @var{expression}, it may be faster to use
address@hidden
@end defmac
@anchor{m4_foreach_w}
@@ -11786,7 +11789,8 @@ Set manipulation Macros
in any way other than removing the element currently contained in
@var{variable}. This macro is faster than the corresponding
@code{m4_foreach(address@hidden,
-m4_indir([m4_dquote]m4_set_listc(address@hidden)), address@hidden)}.
+m4_indir([m4_dquote]m4_set_listc(address@hidden)), address@hidden)},
+although @code{m4_set_map} might be faster still.
@example
m4_set_add_all([a]m4_for([i], [1], [5], [], [,i]))
@@ -11847,9 +11851,11 @@ Set manipulation Macros
argument of the set element. Behavior is unspecified if @var{action}
recursively lists the contents of @var{set} (although listing other sets
is acceptable), or if it modifies the set in any way other than removing
-the element passed as an argument. This macro is faster than the
-corresponding
address@hidden(address@hidden(address@hidden))}.
+the element passed as an argument. This macro is faster than either
+corresponding counterpart of
address@hidden(address@hidden(address@hidden))} or
address@hidden(address@hidden, [var],
address@hidden(m4_defn([var]))])}.
@end defmac
@defmac m4_set_remove (@var{set}, @var{value}, @ovar{if-present}, @
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 15fd807..5c2e1c8 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -2744,12 +2744,12 @@ m4_define([m4_set_delete],
# arguments, such as for m4_join, or wrapped inside quotes for use in
# m4_foreach. Order of the output is not guaranteed.
#
-# Short-circuit the idempotence relation. Use _m4_defn for speed.
+# Short-circuit the idempotence relation.
m4_define([m4_set_difference],
-[m4_if([$1], [$2], [],
- [m4_set_foreach([$1], [_m4_element],
- [m4_set_contains([$2], _m4_defn([_m4_element]), [],
- [,_m4_defn([_m4_element])])])])])
+[m4_if([$1], [$2], [], [m4_set_map_sep([$1], [_$0([$2],], [)])])])
+
+m4_define([_m4_set_difference],
+[m4_set_contains([$1], [$2], [], [,[$2]])])
# m4_set_dump(SET, [SEP])
# -----------------------
@@ -2814,13 +2814,14 @@ m4_define([m4_set_foreach],
# m4_foreach. Order of the output is not guaranteed.
#
# Iterate over the smaller set, and short-circuit the idempotence
-# relation. Use _m4_defn for speed.
+# relation.
m4_define([m4_set_intersection],
[m4_if([$1], [$2], [m4_set_listc([$1])],
m4_eval(m4_set_size([$2]) < m4_set_size([$1])), [1], [$0([$2], [$1])],
- [m4_set_foreach([$1], [_m4_element],
- [m4_set_contains([$2], _m4_defn([_m4_element]),
- [,_m4_defn([_m4_element])])])])])
+ [m4_set_map_sep([$1], [_$0([$2],], [)])])])
+
+m4_define([_m4_set_intersection],
+[m4_set_contains([$1], [$2], [,[$2]])])
# m4_set_list(SET)
# m4_set_listc(SET)
@@ -2901,12 +2902,14 @@ m4_define([_m4_set_size],
# not guaranteed.
#
# We can rely on the fact that m4_set_listc prunes SET1, so we don't
-# need to check _m4_set([$1],element) for 0. Use _m4_defn for speed.
-# Short-circuit the idempotence relation.
+# need to check _m4_set([$1],element) for 0. Short-circuit the
+# idempotence relation.
m4_define([m4_set_union],
-[m4_set_listc([$1])m4_if([$1], [$2], [], [m4_set_foreach([$2], [_m4_element],
- [m4_ifdef([_m4_set([$1],]_m4_defn([_m4_element])[)], [],
- [,_m4_defn([_m4_element])])])])])
+[m4_set_listc([$1])m4_if([$1], [$2], [],
+ [m4_set_map_sep([$2], [_$0([$1],], [)])])])
+
+m4_define([_m4_set_union],
+[m4_ifdef([_m4_set([$1],$2)], [], [,[$2]])])
## ------------------- ##
--
1.6.0.2
>From b07a2b3d74f02078b409f70666853a353f95dd94 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 5 Nov 2008 17:11:15 -0700
Subject: [PATCH] Add m4_map_args_w.
* lib/m4sugar/m4sugar.m4 (m4_map_args_w): New macro, undocumented
for now.
(_m4_split): Allow user control over separator.
(m4_split): Adjust caller.
(m4_foreach_w, m4_append_uniq_w, _m4_text_wrap): Rewrite to use
m4_map_args_w.
* tests/m4sugar.at (m4@&address@hidden): Augment test keywords.
(M4 loops): Test new interface.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 10 ++++++++
lib/m4sugar/m4sugar.m4 | 61 +++++++++++++++++++++++++++++++++---------------
tests/m4sugar.at | 10 +++++++-
3 files changed, 61 insertions(+), 20 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 73e8095..e6686fc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2008-11-05 Eric Blake <address@hidden>
+ Add m4_map_args_w.
+ * lib/m4sugar/m4sugar.m4 (m4_map_args_w): New macro, undocumented
+ for now.
+ (_m4_split): Allow user control over separator.
+ (m4_split): Adjust caller.
+ (m4_foreach_w, m4_append_uniq_w, _m4_text_wrap): Rewrite to use
+ m4_map_args_w.
+ * tests/m4sugar.at (m4@&address@hidden): Augment test keywords.
+ (M4 loops): Test new interface.
+
Use m4_set_map_sep in more places.
* lib/m4sugar/m4sugar.m4 (m4_set_difference, m4_set_intersection)
(m4_set_union): Use m4_set_map_sep rather than m4_set_foreach.
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 5c2e1c8..2a0d7ce 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1073,8 +1073,8 @@ m4_define([_m4_foreach],
# m4_foreach_w(VARIABLE, LIST, EXPRESSION)
# ----------------------------------------
-#
-# Like m4_foreach, but the list is whitespace separated.
+# Like m4_foreach, but the list is whitespace separated. Depending on
+# EXPRESSION, it may be more efficient to use m4_map_args_w.
#
# This macro is robust to active symbols:
# m4_foreach_w([Var], [ active
@@ -1082,8 +1082,11 @@ m4_define([_m4_foreach],
# ive ], [-Var-])end
# => -active--b--active-end
#
+# This used to use a slower implementation based on m4_foreach:
+# m4_foreach([$1], m4_split(m4_normalize([$2]), [ ]), [$3])
m4_define([m4_foreach_w],
-[m4_foreach([$1], m4_split(m4_normalize([$2]), [ ]), [$3])])
+[m4_pushdef([$1])m4_map_args_w([$2],
+ [m4_define([$1],], [)$3])m4_popdef([$1])])
# m4_map(MACRO, LIST)
@@ -1181,6 +1184,29 @@ m4_define([m4_map_args_sep],
[$1[$4]$2[]_m4_foreach([$3[]$1], [$2], m4_shift3($@))])])
+# m4_map_args_w(STRING, [PRE], [POST])
+# ------------------------------------
+# Perform the expansion of PRE[word]POST[] for each word in STRING
+# separated by whitespace. More efficient than:
+# m4_foreach_w([var], [STRING], [PRE[]m4_defn([var])POST])
+#
+# As long as we have to use m4_bpatsubst to split the string, we might
+# as well make it also apply PRE and POST; this avoids iteration
+# altogether. But we must be careful of any \ in PRE or POST.
+# _m4_strip returns a quoted string, but that's okay, since it also
+# supplies an empty leading and trailing argument due to our
+# intentional whitespace around STRING. We use m4_substr to strip the
+# empty elements and remove the extra layer of quoting.
+m4_define([m4_map_args_w],
+[_$0(_m4_split([ ]m4_flatten([$1])[ ], [[ ]+],
+ m4_if(m4_index([$2$3], [\]), [-1], [[$3[]$2]],
+ [m4_bpatsubst([[$3[]$2]], [\\], [\\\\])])),
+ m4_len([[]$3]), m4_len([$2[]]))])
+
+m4_define([_m4_map_args_w],
+[m4_substr([$1], [$2], m4_eval(m4_len([$1]) - [$2] - [$3]))])
+
+
# m4_stack_foreach(MACRO, FUNC)
# m4_stack_foreach_lifo(MACRO, FUNC)
# ----------------------------------
@@ -2024,7 +2050,6 @@ m4_define([m4_toupper],
# m4_split(STRING, [REGEXP])
# --------------------------
-#
# Split STRING into an m4 list of quoted elements. The elements are
# quoted with [ and ]. Beginning spaces and end spaces *are kept*.
# Use m4_strip to remove them.
@@ -2053,15 +2078,15 @@ m4_define([m4_toupper],
# so avoid unnecessary dnl inside the definition.
m4_define([m4_split],
[m4_if([$1], [], [],
- [$2], [ ], [m4_if(m4_index([$1], [ ]), [-1], [[[$1]]], [_$0($@)])],
- [$2], [], [_$0([$1], [[ ]+])],
- [_$0($@)])])
+ [$2], [ ], [m4_if(m4_index([$1], [ ]), [-1], [[[$1]]],
+ [_$0([$1], [$2], [, ])])],
+ [$2], [], [_$0([$1], [[ ]+], [, ])],
+ [_$0([$1], [$2], [, ])])])
m4_define([_m4_split],
[m4_changequote([-=<{(],[)}>=-])]dnl
[[m4_bpatsubst(-=<{(-=<{($1)}>=-)}>=-, -=<{($2)}>=-,
- -=<{(], [)}>=-)]m4_changequote([, ])])
-
+ -=<{(]$3[)}>=-)]m4_changequote([, ])])
# m4_flatten(STRING)
@@ -2267,8 +2292,7 @@ m4_define([_m4_append_uniq],
#
# Use _m4_defn for speed.
m4_define([m4_append_uniq_w],
-[m4_foreach_w([m4_Word], [$2],
- [_m4_append_uniq([$1], _m4_defn([m4_Word]), [ ])])])
+[m4_map_args_w([$2], [_m4_append_uniq([$1],], [, [ ])])])
# m4_text_wrap(STRING, [PREFIX], [FIRST-PREFIX], [WIDTH])
@@ -2342,17 +2366,16 @@ dnl check if the cursor would exceed the wrap column
dnl if so, reset cursor, and insert newline and prefix
dnl if not, insert the separator (usually a space)
dnl either way, insert the word
-[[m4_foreach_w([m4_Word], [$1],
- [m4_define([m4_Cursor],
- m4_eval(m4_Cursor + m4_qlen(_m4_defn([m4_Word]))
- + 1))m4_if(m4_eval(m4_Cursor > ([$4])),
- [1], [m4_define([m4_Cursor],
- m4_eval(m4_Indent + m4_qlen(_m4_defn([m4_Word])) + 1))
-[$2]],
- [m4_Separator[]])_m4_defn([m4_Word])])]],
+[[m4_map_args_w([$1], [$0_word(], [, [$2], [$4])])]],
dnl finally, clean up the local variables
[[_m4_popdef([m4_Separator], [m4_Cursor], [m4_Indent])]]))
+m4_define([_m4_text_wrap_word],
+[m4_define([m4_Cursor], m4_eval(m4_Cursor + m4_qlen([$1]) + 1))]dnl
+[m4_if(m4_eval(m4_Cursor > ([$3])),
+ [1], [m4_define([m4_Cursor], m4_eval(m4_Indent + m4_qlen([$1]) + 1))
+[$2]],
+ [m4_Separator[]])[$1]])
# m4_text_box(MESSAGE, [FRAME-CHARACTER = `-'])
# ---------------------------------------------
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index c8b22eb..5a90493 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -546,6 +546,7 @@ AT_CLEANUP
## ----------- ##
AT_SETUP([m4@&address@hidden)
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
AT_CHECK_M4SUGAR_TEXT(
[[m4_define([active], [ACTIVE])dnl
@@ -876,7 +877,7 @@ AT_CLEANUP
AT_SETUP([M4 loops])
-AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden)
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden
m4@&address@hidden)
AT_CHECK_M4SUGAR_TEXT([[dnl
m4_define([myvar], [outer value])dnl
@@ -921,6 +922,10 @@ m4_foreach([myvar], [[a], [b, c], [d], [e
m4_foreach_w([myvar], [a b c, d,e f
g], [ myvar|])
myvar
+m4_map_args_w([a b c, d,e f
+g], [ ], [|])
+m4_map_args_w([a b], [\1], [/])
+m4_map_args_w([a b], [/], [\1])
dnl only one side effect expansion, prior to visiting list elements
m4_foreach([i], [[1], [2], [3]m4_errprintn([hi])], [m4_errprintn(i)])dnl
dnl shifting forms an important part of loops
@@ -959,6 +964,9 @@ m4_shiftn(3,1,2,3):m4_shiftn(3,1,2,3,4)
| f|
a| b| c,| d,e| f| g|
outer value
+ a| b| c,| d,e| f| g|
+\1a/\1b/
+/a\1/b\1
::4
:4
]], [[hi
--
1.6.0.2
- faster m4_for, Eric Blake, 2008/11/04
- faster m4_foreach, m4_set_foreach, m4_foreach_w [was: faster m4_for],
Eric Blake <=