]> git.ipfire.org Git - thirdparty/autoconf.git/commitdiff
Optimize m4_for.
authorEric Blake <ebb9@byu.net>
Tue, 29 Jul 2008 18:21:25 +0000 (12:21 -0600)
committerEric Blake <ebb9@byu.net>
Wed, 30 Jul 2008 01:36:18 +0000 (19:36 -0600)
* lib/m4sugar/m4sugar.m4 (m4_for): Use fewer macros.
(_m4_for): Take additional parameter, for fewer m4_indir calls.
* lib/m4sugar/foreach.m4 (_m4_foreach, _m4_shiftn, m4_do)
(m4_reverse, _m4_list_pad, _m4_list_cmp): Adjust all callers.
* doc/autoconf.texi (Looping constructs) <m4_for>: Document subtle
semantic change caused by the optimization.
* tests/m4sugar.at (M4 loops): Test the new semantics.

Signed-off-by: Eric Blake <ebb9@byu.net>
ChangeLog
doc/autoconf.texi
lib/m4sugar/foreach.m4
lib/m4sugar/m4sugar.m4
tests/m4sugar.at

index 877eb28436b8e919b250750b74acd9ca64be8ed6..fe6d7b71e632f4efd10de1c21b14d5afe96be6e3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2008-07-29  Eric Blake  <ebb9@byu.net>
 
+       Optimize m4_for.
+       * lib/m4sugar/m4sugar.m4 (m4_for): Use fewer macros.
+       (_m4_for): Take additional parameter, for fewer m4_indir calls.
+       * lib/m4sugar/foreach.m4 (_m4_foreach, _m4_shiftn, m4_do)
+       (m4_reverse, _m4_list_pad, _m4_list_cmp): Adjust all callers.
+       * doc/autoconf.texi (Looping constructs) <m4_for>: Document subtle
+       semantic change caused by the optimization.
+       * tests/m4sugar.at (M4 loops): Test the new semantics.
+
        One more m4_list_cmp tweak.
        * lib/m4sugar/m4sugar.m4 (_m4_list_cmp_1): Don't defer shift.
        * lib/m4sugar/foreach.m4 (m4_list_cmp): Fix comment.
index b3b416c88a3534b2ea0b9ab14a874111d47416bf..7dc44053fde98a080ea8c4e3df7d4912cd148f26 100644 (file)
@@ -10779,7 +10779,9 @@ including bounds by increments of @var{step}.  For each iteration,
 expand @var{expression} with the numeric value assigned to @var{var}.
 If @var{step} is omitted, it defaults to @samp{1} or @samp{-1} depending
 on the order of the limits.  If given, @var{step} has to match this
-order.
+order.  The number of iterations is determined independently from
+definition of @var{var}; iteration cannot be short-circuited or
+lengthened by modifying @var{var} from within @var{expression}.
 @end defmac
 
 @defmac m4_foreach (@var{var}, @var{list}, @var{expression})
index 1b5d2f9cc76bb3d29c7a8c6fa5b653f17f747886..bedb4f5a4a035e1b1f523011cf55420d4c296ea5 100644 (file)
@@ -95,8 +95,8 @@ m4_define([m4_foreach],
 [m4_if([$2], [], [], [_$0([$1], [$3], $2)])])
 
 m4_define([_m4_foreach],
-[m4_define([$1], m4_pushdef([$1], [3])_m4_for([$1], [$#], [1],
-    [$0_([1], [2], m4_indir([$1]))])[m4_popdef([$1])])m4_indir([$1], $@)])
+[m4_define([$1], m4_pushdef([$1])_m4_for([$1], [3], [$#], [1],
+    [$0_([1], [2], _m4_defn([$1]))])[m4_popdef([$1])])m4_indir([$1], $@)])
 
 m4_define([_m4_foreach_],
 [[m4_define([$$1], [$$3])$$2[]]])
@@ -130,9 +130,9 @@ m4_define([_m4_case_],
 #   ,[$5],[$6],...,[$m]_m4_popdef([_m4_s])
 # before calling m4_shift(_m4_s($@)).
 m4_define([_m4_shiftn],
-[m4_define([_m4_s], m4_pushdef([_m4_s],
-                       m4_incr(m4_incr([$1])))_m4_for([_m4_s], [$#], [1],
-    [[,]m4_dquote([$]_m4_s)])[_m4_popdef([_m4_s])])m4_shift(_m4_s($@))])
+[m4_define([_m4_s],
+          m4_pushdef([_m4_s])_m4_for([_m4_s], m4_eval([$1 + 2]), [$#], [1],
+  [[,]m4_dquote([$]_m4_s)])[_m4_popdef([_m4_s])])m4_shift(_m4_s($@))])
 
 # m4_do(STRING, ...)
 # ------------------
@@ -143,8 +143,8 @@ m4_define([_m4_shiftn],
 # Here, we use the temporary macro _m4_do, defined as
 #   $1$2...$n[]_m4_popdef([_m4_do])
 m4_define([m4_do],
-[m4_define([_$0], m4_pushdef([_$0], [1])_m4_for([_$0], [$#], [1],
-    [$][_$0])[[]_m4_popdef([_$0])])_$0($@)])
+[m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [1], [$#], [1],
+    [$_$0])[[]_m4_popdef([_$0])])_$0($@)])
 
 # m4_dquote_elt(ARGS)
 # -------------------
@@ -162,8 +162,8 @@ m4_define([m4_dquote_elt],
 #   [$m], [$m-1], ..., [$2], [$1]_m4_popdef([_m4_r])
 m4_define([m4_reverse],
 [m4_if([$#], [0], [], [$#], [1], [[$1]],
-[m4_define([_m4_r], m4_dquote([$$#])m4_pushdef([_m4_r],
-    m4_decr([$#]))_m4_for([_m4_r], [1], [-1],
+[m4_define([_m4_r], m4_dquote([$$#])m4_pushdef([_m4_r])_m4_for([_m4_r],
+      m4_decr([$#]), [1], [-1],
     [[, ]m4_dquote([$]_m4_r)])[_m4_popdef([_m4_r])])_m4_r($@)])])
 
 
@@ -218,16 +218,17 @@ m4_define([m4_joinall],
 # then calls _m4_cmp([1+0], [0], [1], [2+0])
 m4_define([m4_list_cmp],
 [m4_if([$1], [$2], 0,
-       [_$0($1+0_m4_list_pad(m4_count($1), m4_count($2)),
-           $2+0_m4_list_pad(m4_count($2), m4_count($1)))])])
+  [m4_pushdef([_m4_size])_$0($1+0_m4_list_pad(m4_count($1), m4_count($2)),
+                            $2+0_m4_list_pad(m4_count($2), m4_count($1)))])])
 
 m4_define([_m4_list_pad],
-[m4_if(m4_eval($1 < $2), [1], [m4_for([], [$1 + 1], [$2], [], [,0])])])
+[m4_if(m4_eval($1 < $2), [1],
+       [_m4_for([_m4_size], m4_incr([$1]), [$2], [1], [,0])])])
 
 m4_define([_m4_list_cmp],
-[m4_pushdef([_m4_size], m4_eval([$# >> 1]))]dnl
-[m4_define([_m4_cmp], m4_pushdef([_m4_cmp], [1])[m4_if(]_m4_for([_m4_cmp],
-   _m4_size, [1], [$0_(_m4_cmp, m4_eval(_m4_cmp + _m4_size))])[
+[m4_define([_m4_size], m4_eval([$# >> 1]))]dnl
+[m4_define([_m4_cmp], m4_pushdef([_m4_cmp])[m4_if(]_m4_for([_m4_cmp],
+   [1], _m4_size, [1], [$0_(_m4_cmp, m4_eval(_m4_cmp + _m4_size))])[
       [0]_m4_popdef([_m4_cmp], [_m4_size]))])_m4_cmp($@)])
 
 m4_define([_m4_list_cmp_],
index a6059471f267ab7c3eeaccaa5afc9d83465ebeb1..11692afe4c2b1ade717ad89055b89fdf6bbd1e6c 100644 (file)
@@ -827,37 +827,36 @@ m4_define([m4_unquote], [$*])
 # m4_for(VARIABLE, FIRST, LAST, [STEP = +/-1], EXPRESSION)
 # --------------------------------------------------------
 # Expand EXPRESSION defining VARIABLE to FROM, FROM + 1, ..., TO with
-# increments of STEP.
-# Both limits are included, and bounds are checked for consistency.
-# The algorithm is robust to indirect VARIABLE names, and uses _m4_defn
-# where possible for speed.
+# increments of STEP.  Both limits are included, and bounds are
+# checked for consistency.  The algorithm is robust to indirect
+# VARIABLE names.  Changing VARIABLE inside EXPRESSION will not impact
+# the number of iterations.
+#
+# Uses _m4_defn for speed, and avoid dnl in the macro body.
 m4_define([m4_for],
-[m4_pushdef([$1], m4_eval([$2]))dnl
-m4_cond([m4_eval(([$3]) > _m4_defn([$1]))], 1,
-[m4_pushdef([_m4_step], m4_eval(m4_default([$4], 1)))dnl
-m4_assert(_m4_step > 0)dnl
-_m4_for([$1], m4_eval((([$3]) - _m4_defn([$1]))
-                     / _m4_step * _m4_step + _m4_defn([$1])),
-       _m4_step, [$5])],
-       [m4_eval(([$3]) < _m4_defn([$1]))], 1,
-[m4_pushdef([_m4_step], m4_eval(m4_default([$4], -1)))dnl
-m4_assert(_m4_step < 0)dnl
-_m4_for([$1], m4_eval((_m4_defn([$1]) - ([$3]))
-                     / -(_m4_step) * _m4_step + _m4_defn([$1])),
-       _m4_step, [$5])],
-       [m4_pushdef([_m4_step])dnl
-$5])[]dnl
-m4_popdef([_m4_step])dnl
-m4_popdef([$1])])
-
-
-# _m4_for(VARIABLE, LAST, STEP, EXPRESSION)
-# -----------------------------------------
-# Core of the loop, no consistency checks, all arguments are plain numbers.
+[m4_pushdef([$1], m4_eval([$2]))]dnl
+[m4_cond([m4_eval(([$3]) > ([$2]))], 1,
+          [m4_pushdef([_m4_step], m4_eval(m4_default([$4],
+             1)))m4_assert(_m4_step > 0)_$0([$1], _m4_defn([$1]),
+  m4_eval((([$3]) - ([$2])) / _m4_step * _m4_step + ([$2])),
+  _m4_step, [$5])],
+        [m4_eval(([$3]) < ([$2]))], 1,
+          [m4_pushdef([_m4_step], m4_eval(m4_default([$4],
+             -1)))m4_assert(_m4_step < 0)_$0([$1], _m4_defn([$1]),
+  m4_eval((([$2]) - ([$3])) / -(_m4_step) * _m4_step + ([$2])),
+  _m4_step, [$5])],
+        [m4_pushdef([_m4_step])$5])[]]dnl
+[m4_popdef([_m4_step], [$1])])
+
+
+# _m4_for(VARIABLE, COUNT, LAST, STEP, EXPRESSION)
+# ------------------------------------------------
+# Core of the loop, no consistency checks, all arguments are plain
+# numbers.  Define VARIABLE to COUNT, expand EXPRESSION, then alter
+# COUNT by STEP and iterate if COUNT is not LAST.
 m4_define([_m4_for],
-[$4[]dnl
-m4_if(m4_defn([$1]), [$2], [],
-      [m4_define([$1], m4_eval(m4_defn([$1])+[$3]))$0($@)])])
+[m4_define([$1], [$2])$5[]m4_if([$2], [$3], [],
+      [$0([$1], m4_eval([$2 + $4]), [$3], [$4], [$5])])])
 
 
 # Implementing `foreach' loops in m4 is much more tricky than it may
index 2b73188bf297ed0153ae75d4d067fed92fa8f37c..92945a474f9c22c0fcc14587c75b8d67d7710caa 100644 (file)
@@ -532,6 +532,8 @@ m4_for([myvar], -2+8, 3-5, , [ myvar])
 m4_for([myvar], 8, 16, 3 * 2, [ myvar])
 m4_for([myvar], 8, 16, -3 * -2, [ myvar])
 m4_for([myvar], [2<<2], [2<<3], [-3 * (-2)], [ myvar])
+dnl Modifying var does not affect the number of iterations
+m4_for([myvar], 1, 5, , [ myvar[]m4_define([myvar], 5)])
 dnl Make sure we can do nameless iteration
 m4_for(, 1, 10, , -)
 dnl foreach tests
@@ -567,6 +569,7 @@ myvar
  8 14
  8 14
  8 14
+ 1 2 3 4 5
 ----------
  a| b, c| d| e
 | f|