diff options
author | Eric Blake <ebb9@byu.net> | 2008-11-26 11:24:19 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2008-11-26 11:25:01 -0700 |
commit | b208b7e04a6a208fd74ce0eab0d28eee6c1a4f53 (patch) | |
tree | 1cce4c5837eafc852cb3d6882c2cbb4c37a97d13 | |
parent | d57af1812ef0a22dd4c40e36c1da2770515dc75b (diff) | |
download | m4-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-- | ChangeLog | 6 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | doc/m4.texinfo | 52 | ||||
-rw-r--r-- | examples/forloop3.m4 | 13 |
4 files changed, 72 insertions, 0 deletions
@@ -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 |