summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2008-11-26 11:24:19 -0700
committerEric Blake <ebb9@byu.net>2008-11-26 11:25:01 -0700
commitb208b7e04a6a208fd74ce0eab0d28eee6c1a4f53 (patch)
tree1cce4c5837eafc852cb3d6882c2cbb4c37a97d13
parentd57af1812ef0a22dd4c40e36c1da2770515dc75b (diff)
downloadm4-b208b7e04a6a208fd74ce0eab0d28eee6c1a4f53.tar.gz
Document optimized forloop.
* doc/m4.texinfo (Improved forloop): Mention alternate style that avoids define overhead. * examples/forloop3.m4: New file. * Makefile.am (dist_pkgdata_DATA): Distribute it. Signed-off-by: Eric Blake <ebb9@byu.net> (cherry picked from commit 5ace13749e5afae1351d9b6035c2ba9309ac20cd)
-rw-r--r--ChangeLog6
-rw-r--r--Makefile.am1
-rw-r--r--doc/m4.texinfo52
-rw-r--r--examples/forloop3.m413
4 files changed, 72 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 1f6e7f8a..badacbe6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2008-11-26 Eric Blake <ebb9@byu.net>
+ Document optimized forloop.
+ * doc/m4.texinfo (Improved forloop): Mention alternate style that
+ avoids define overhead.
+ * examples/forloop3.m4: New file.
+ * Makefile.am (dist_pkgdata_DATA): Distribute it.
+
Document copy composite using stack_foreach and curry.
* doc/m4.texinfo (Stacks): New node, to document pushdef stack
manipulation.
diff --git a/Makefile.am b/Makefile.am
index de42581f..996afc24 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -326,6 +326,7 @@ dist_pkgdata_DATA = \
examples/foreachq4.m4 \
examples/forloop.m4 \
examples/forloop2.m4 \
+ examples/forloop3.m4 \
examples/fstab.m4 \
examples/hanoi.m4 \
examples/incl-test.m4 \
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 14b7172a..0287a60b 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -9283,6 +9283,58 @@ forloop2(i, 1, 5, ``ifelse('')forloop2(i, 1, 5, ``)'')
@error{}m4:stdin:12: recursion limit of 9 exceeded, use -L<N> to change it
@end example
+One more optimization is still possible. Instead of repeatedly
+assigning a variable then invoking or dereferencing it, it is possible
+to pass the current iterator value as a single argument. Coupled with
+@code{curry} if other arguments are needed (@pxref{Composition}), or
+with helper macros if the argument is needed in more than one place in
+the expansion, the output can be generated with three, rather than four,
+macros of overhead per iteration. Notice how the file
+@file{m4-@value{VERSION}/@/examples/@/forloop3.m4} rearranges the
+arguments of the helper @code{_forloop} to take two arguments that are
+placed around the current value. By splitting a balanced set of
+parantheses across multiple arguments, the helper macro can now be
+shared by @code{forloop} and the new @code{forloop_arg}.
+
+@comment examples
+@example
+$ @kbd{m4 -I examples}
+include(`forloop3.m4')
+@result{}
+undivert(`forloop3.m4')dnl
+@result{}divert(`-1')
+@result{}# forloop_arg(from, to, macro) - invoke MACRO(value) for
+@result{}# each value between FROM and TO, without define overhead
+@result{}define(`forloop_arg', `ifelse(eval(`($1) <= ($2)'), `1',
+@result{} `_forloop(`$1', eval(`$2'), `$3(', `)')')')
+@result{}# forloop(var, from, to, stmt) - refactored to share code
+@result{}define(`forloop', `ifelse(eval(`($2) <= ($3)'), `1',
+@result{} `pushdef(`$1')_forloop(eval(`$2'), eval(`$3'),
+@result{} `define(`$1',', `)$4')popdef(`$1')')')
+@result{}define(`_forloop',
+@result{} `$3`$1'$4`'ifelse(`$1', `$2', `',
+@result{} `$0(incr(`$1'), `$2', `$3', `$4')')')
+@result{}divert`'dnl
+forloop(`i', `1', `3', ` i')
+@result{} 1 2 3
+define(`echo', `$@@')
+@result{}
+forloop_arg(`1', `3', ` echo')
+@result{} 1 2 3
+include(`curry.m4')
+@result{}
+forloop_arg(`1', `3', `curry(`pushdef', `a')')
+@result{}
+a
+@result{}3
+popdef(`a')a
+@result{}2
+popdef(`a')a
+@result{}1
+popdef(`a')a
+@result{}a
+@end example
+
Of course, it is possible to make even more improvements, such as
adding an optional step argument, or allowing iteration through
descending sequences. @acronym{GNU} Autoconf provides some of these
diff --git a/examples/forloop3.m4 b/examples/forloop3.m4
new file mode 100644
index 00000000..98db20f3
--- /dev/null
+++ b/examples/forloop3.m4
@@ -0,0 +1,13 @@
+divert(`-1')
+# forloop_arg(from, to, macro) - invoke MACRO(value) for
+# each value between FROM and TO, without define overhead
+define(`forloop_arg', `ifelse(eval(`($1) <= ($2)'), `1',
+ `_forloop(`$1', eval(`$2'), `$3(', `)')')')
+# forloop(var, from, to, stmt) - refactored to share code
+define(`forloop', `ifelse(eval(`($2) <= ($3)'), `1',
+ `pushdef(`$1')_forloop(eval(`$2'), eval(`$3'),
+ `define(`$1',', `)$4')popdef(`$1')')')
+define(`_forloop',
+ `$3`$1'$4`'ifelse(`$1', `$2', `',
+ `$0(incr(`$1'), `$2', `$3', `$4')')')
+divert`'dnl