m4-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: more testsuite coverage for autoconf idioms


From: Eric Blake
Subject: Re: more testsuite coverage for autoconf idioms
Date: Wed, 31 Oct 2007 15:04:26 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Eric Blake <ebb9 <at> byu.net> writes:

> I have been working away on a series of patches to speed up recursive
> macro handling (with a goal to make $@ handling linear instead of
> quadratic).  That series is not ready yet,

Still not ready to post, although I have made progress, and uncovered a couple 
more corner cases to be aware of.  Included in the patch below.

Also, as part of my patching progress, I have been hammering on a stress-test 
(also included in this patch).  So far, I have been able to shave the peak 
memory usage of 'm4 -Dlimit=1500 loop.m4' from 41 megabytes down to 14, with a 
slight speedup, once I convinced the input engine to handle references to 
previously parsed arguments; but I'm still trying to hammer out why 'm4 -
Dlimit=1500 -Dalt loop.m4' went from 19 megabytes to 109, even though it 
completes in the same amount of time.  And the quadratic scaling factor of tail-
recursive parsing is not gone yet, until I can convince shift to handle a 
reference to a group of arguments, rather than a group of references to 
individual arguments.

> For the branch, the testsuite is contained entirely within the
> m4.texinfo, hence adding some tests within @ignore blocks.  But for head,
> I will move those tests to a more appropriate tests/*.at file.

Some of these changes are in documented tests, but for those that aren't, the 
same rules will apply to my port of this patch to head.

From: Eric Blake <address@hidden>
Date: Wed, 31 Oct 2007 08:50:30 -0600
Subject: [PATCH] Test more corner cases.

* doc/m4.texinfo (Changecom, Pseudo Arguments): Beef up tests.
(Improved foreach): Document alternate foreachq style.
* examples/foreachq3.m4: New file.
* examples/loop.m4: New file.
* examples/Makefile.am (EXTRA_DIST): Distribute them.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog             |    9 +++++
 doc/m4.texinfo        |   85 +++++++++++++++++++++++++++++++++++++++++++-----
 examples/Makefile.am  |    2 +
 examples/foreachq3.m4 |   10 ++++++
 examples/loop.m4      |   16 +++++++++
 5 files changed, 113 insertions(+), 9 deletions(-)
 create mode 100644 examples/foreachq3.m4
 create mode 100644 examples/loop.m4

diff --git a/ChangeLog b/ChangeLog
index 737a6ec..a25c84d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2007-10-31  Eric Blake  <address@hidden>
+
+       Test more corner cases.
+       * doc/m4.texinfo (Changecom, Pseudo Arguments): Beef up tests.
+       (Improved foreach): Document alternate foreachq style.
+       * examples/foreachq3.m4: New file.
+       * examples/loop.m4: New file.
+       * examples/Makefile.am (EXTRA_DIST): Distribute them.
+
 2007-10-28  Eric Blake  <address@hidden>
 
        More test coverage for autoconf usage patterns.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index d7c8140..3fc6dfa 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -1942,11 +1942,17 @@ foo)
 @comment levels.
 
 @example
-define(`echo', `$@')dnl
+define(`echo', `$@@')dnl
 len((echo(`01234567890123456789',
           `01234567890123456789')echo(`98765432109876543210',
                                       `98765432109876543210')))
 @result{}84
+define(`argn', `$#')dnl
+define(`echo1', `-$@@-')define(`echo2', `,$@@,')dnl
+echo1(`1', `2', `3') argn(echo1(`1', `2', `3'))
address@hidden,2,3- 3
+echo2(`1', `2', `3') argn(echo2(`1', `2', `3'))
address@hidden,1,2,3, 5
 @end example
 @end ignore
 
@@ -3801,26 +3807,32 @@ implementations, it is a good idea to avoid @samp{(}, 
@samp{,}, and
 @samp{)} as the first character in @var{start}.
 
 @example
-define(`echo', `$#:$@@:')
+define(`echo', `$#:$*:$@@:')
 @result{}
 define(`hi', `HI')
 @result{}
 changecom(`(',`)')
 @result{}
 echo(hi)
address@hidden::(hi)
address@hidden:::(hi)
 changecom
 @result{}
 changecom(`((', `))')
 @result{}
 echo(hi)
address@hidden:HI:
address@hidden:HI:HI:
 echo((hi))
address@hidden::((hi))
address@hidden:::((hi))
 changecom(`,', `)')
 @result{}
 echo(hi,hi)bye)
address@hidden:HI,hi)bye:
address@hidden:HI,hi)bye:HI,hi)bye:
+changecom
address@hidden
+echo(hi,`,`'hi',hi)
address@hidden:HI,,HI,HI:HI,,`'hi,HI:
+echo(hi,`,`'hi',hi`'changecom(`,,', `hi'))
address@hidden:HI,,`'hi,HI:HI,,`'hi,HI:
 @end example
 
 It is an error if the end of file occurs within a comment.
@@ -6803,7 +6815,60 @@ Contrast the use of @address@hidden, which quotes the 
first list
 element, with @address@hidden of the earlier implementation that
 returned the first list element directly.
 
-For a different approach, the improved version of @code{foreach},
+The astute m4 programmer might notice that the solution above still uses
+more memory, and thus more time, than strictly necessary.  Note that
address@hidden, which contains an arbitrarily long quoted list, is expanded
+and rescanned three times per iteration of @code{_foreachq}.
+Furthermore, every iteration of the algorithm effectively unboxes then
+reboxes the list, which costs a couple of macro invocations.
+It is possible to rewrite the algorithm for a bit more speed by swapping
+the order of the arguments to @code{_foreachq} in order to operate on an
+unboxed list in the first place, and by using the fixed-length @samp{$#}
+instead of an arbitrary length list as the key to end recursion.  This
+alternative approach is available as
address@hidden@value{VERSION}/@/examples/@/foreach3.m4}:
+
address@hidden
+$ @kbd{m4 -I examples}
+include(`foreachq3.m4')
address@hidden
+undivert(`foreachq3.m4')dnl
address@hidden(`-1')
address@hidden foreachq(x, `item_1, item_2, ..., item_n', stmt)
address@hidden   quoted list, alternate improved version
address@hidden(`foreachq',
address@hidden(`$1')_$0(`$1', `$3'ifelse(`$2', `', `',
address@hidden  `, $2'))popdef(`$1')')
address@hidden(`_foreachq', `ifelse(`$#', `2', `',
address@hidden  `define(`$1', `$3')$2`'$0(`$1', `$2'ifelse(`$#', `3', `',
address@hidden    `, shift(shift(shift($@@)))'))')')
address@hidden'dnl
+traceon(`shift')debugmode(`aq')
address@hidden
+foreachq(`x', ``1', `2', `3', `4'', `x
+')dnl
address@hidden
address@hidden: -4- shift(`x', `x
address@hidden', `1', `2', `3', `4')
address@hidden: -3- shift(`x
address@hidden', `1', `2', `3', `4')
address@hidden: -2- shift(`1', `2', `3', `4')
address@hidden
address@hidden: -4- shift(`x', `x
address@hidden', `2', `3', `4')
address@hidden: -3- shift(`x
address@hidden', `2', `3', `4')
address@hidden: -2- shift(`2', `3', `4')
address@hidden
address@hidden: -4- shift(`x', `x
address@hidden', `3', `4')
address@hidden: -3- shift(`x
address@hidden', `3', `4')
address@hidden: -2- shift(`3', `4')
address@hidden
address@hidden example
+
+For yet another approach, the improved version of @code{foreach},
 available in @address@hidden/@/examples/@/foreach2.m4}, simply
 overquotes the arguments to @address@hidden to begin with, using
 @code{dquote_elt}.  Then @address@hidden can just use
@@ -6846,9 +6911,11 @@ In summary, recursion over list elements is trickier 
than it appeared at
 first glance, but provides a powerful idiom within @code{m4} processing.
 As a final demonstration, both list styles are now able to handle
 several scenarios that would wreak havoc on the original
-implementations.  This points out one other difference between the two
+implementations.  This points out one other difference between the
 list styles.  @code{foreach} evaluates unquoted list elements only once,
-in preparation for calling @address@hidden  But @code{foreachq}
+in preparation for calling @address@hidden, similary for
address@hidden as provided by @file{foreachq3.m4}.  But
address@hidden, as provided by @file{foreachq2.m4},
 evaluates unquoted list elements twice while visiting the first list
 element, once in @address@hidden and once in @address@hidden  When
 deciding which list style to use, one must take into account whether
diff --git a/examples/Makefile.am b/examples/Makefile.am
index e7672f9..b1ef68a 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -33,6 +33,7 @@ foreach.m4 \
 foreach2.m4 \
 foreachq.m4 \
 foreachq2.m4 \
+foreachq3.m4 \
 forloop.m4 \
 forloop2.m4 \
 fstab.m4 \
@@ -41,6 +42,7 @@ incl-test.m4 \
 incl.m4 \
 include.m4 \
 indir.m4 \
+loop.m4 \
 misc.m4 \
 multiquotes.m4 \
 patsubst.m4 \
diff --git a/examples/foreachq3.m4 b/examples/foreachq3.m4
new file mode 100644
index 0000000..beab455
--- /dev/null
+++ b/examples/foreachq3.m4
@@ -0,0 +1,10 @@
+divert(`-1')
+# foreachq(x, `item_1, item_2, ..., item_n', stmt)
+#   quoted list, alternate improved version
+define(`foreachq',
+`pushdef(`$1')_$0(`$1', `$3'ifelse(`$2', `', `',
+  `, $2'))popdef(`$1')')
+define(`_foreachq', `ifelse(`$#', `2', `',
+  `define(`$1', `$3')$2`'$0(`$1', `$2'ifelse(`$#', `3', `',
+    `, shift(shift(shift($@)))'))')')
+divert`'dnl
diff --git a/examples/loop.m4 b/examples/loop.m4
new file mode 100644
index 0000000..ee278fd
--- /dev/null
+++ b/examples/loop.m4
@@ -0,0 +1,16 @@
+dnl Stress test for recursion algorithms.  Usage:
+dnl m4 -Ipath/to/examples [-Doptions] loop.m4
+dnl Options include:
+dnl -Dalt - test with foreachq3 instead of foreachq2
+dnl -Dlimit=<num> - set upper limit of sequence to <num>, default 1000
+dnl -Dverbose - print the sequence to the screen, rather than discarding
+dnl -Ddebug[=<code>] - execute <code> after forloop but before foreach
+dnl -Dsleep=<num> - sleep for <num> seconds before exit, to allow time
+dnl   to examine peak process memory usage
+include(`forloop2.m4')dnl
+include(ifdef(`alt', ``foreachq3.m4'', ``foreachq2.m4''))dnl
+ifdef(`limit', `', `define(`limit', `1000')')dnl
+ifdef(`verbose', `', `divert(`-1')')dnl
+ifdef(`debug', `', `define(`debug')')
+foreachq(`i', dquote(1forloop(`i', `2', limit, `,i'))debug, ` i')
+ifdef(`sleep',`syscmd(`echo done>/dev/tty;sleep 'sleep)')dnl
-- 
1.5.3.2








reply via email to

[Prev in Thread] Current Thread [Next in Thread]