autoconf-patches
[Top][All Lists]
Advanced

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

Re: naming m4_transform


From: Eric Blake
Subject: Re: naming m4_transform
Date: Tue, 14 Oct 2008 23:31:38 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Paolo Bonzini <bonzini <at> gnu.org> writes:

> > At any rate, I'm interested in documenting these macros, as well as adding
> > a counterpart macro for m4_set iteration (the recent
> > _AS_DETECT_BETTER_SHELL change can be sped up).  It turns out that m4 is
> > more efficient when you pass the list element as an argument to a macro
> > invocation than it is with m4_foreach semantics of doing m4_define of the
> > list element to a temporary name, then doing m4_defn of that temporary
> > name to get back to the list element.  I originally went with the name
> > m4_transform because m4_map was taken, but maybe m4_map_each and
> > m4_map_pair might make more sense?
> 
> ... or m4_map_args and m4_map_args_pair?

I like it.  Here's three preliminary patches along this front:

aaee3a9 Document m4_map_args.
4cd6caa Add m4_set_map.
3bdb8d4 Improve suggested test filtering.

Unfortunately, when I went to go replace uses of m4_foreach{,_w} with 
m4_map_args, I ran into the issue that this paradigm doesn't support function 
currying.  For a concrete example, look at the current implementation of 
AC_CHECK_FILES (after the typo fix in the third patch):

AC_DEFUN([AC_CHECK_FILES],
[m4_foreach_w([AC_FILE_NAME], [$1],
  [AC_CHECK_FILE(AC_FILE_NAME,
                 [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_[]AC_FILE_NAME), 1,
                                    [Define to 1 if you have the
                                     file `]AC_FILE_NAME['.])
$2],
                 [$3])])])


This is _not_ robust (suppose the user did AC_CHECK_FILES([dnl.h]) - expanding 
AC_FILE_NAME blows up).  And using three instances of m4_defn([AC_FILE_NAME]) 
is expensive in execution time.  If we used m5 instead of m4, this would be 
taken care of by m5's $$1 syntax which strips a $ from the string rather than 
performing parameter expansion, so that $1 is deferred but $2 and $3 expanded 
immediately in the m4_pushdef:

AC_DEFUN([AC_CHECK_FILES],
[m4_pushdef([tmp],[AC_CHECK_FILE([$$1],
  [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$$1]), 1,
    [Define to 1 if you have the file `$$1'.])
$2], [$3])])m4_map_args([tmp],
  m4_unquote(m4_split(m4_normalize($1),[ ])))m4_popdef([tmp])])

But m4 doesn't make it easy to write anonymous functions.  By making 
m4_map_args supply the ( and ) around a single argument, I no longer have a way 
to inject $2 and $3 into the mapping function, at least, not without some 
inefficiencies.  I've thought about something like this (untested, and I'm not 
even sure I'm using the best naming convention):

# m4_curry(MACRO, ARG...)
# -----------------------
# Can be used as a currying macro - the expansion of this macro expects
# to be expanded as another macro that takes one argument, which is then
# appended to the list of ARGs and passed to the invocation of MACRO.
# For example,
#   m4_curry([m4_do], [1], [2])([3])
# is identical to
#   m4_do([1], [2], [3])
m4_define([m4_curry], [$1(m4_shift($@), _$0])
m4_define([_m4_curry],                     [[$1])])

m4_define([_AC_CHECK_FILES],
[AC_CHECK_FILE([$3],
  [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$3]), 1,
    [Define to 1 if you have the file `$3'.])
$1], [$2])])

AC_DEFUN([AC_CHECK_FILES],
[m4_map_args([m4_curry([_$0], [$2], [$3])],
  m4_unquote(m4_split(m4_normalize($1),[ ])))])

but I'm not sure whether m4_curry would be efficient enough in practice.  I 
suppose I could call this interesting quoting paradigm.  It uses PRE ("_$0("), 
SEP ("[]"), and POST (", [$2], [$3])").  If it is faster, is there a slicker 
API for expressing the idea of using POST-SEP-PRE as the separator in 
m4_joinall, with the joined expression wrapped inside PRE-POST?

m4_define([_AC_CHECK_FILES],
[AC_CHECK_FILE([$1],
  [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1]), 1,
    [Define to 1 if you have the file `$1'.])
$2], [$3])])

AC_DEFUN([AC_CHECK_FILES],
[m4_ifval([$1],
[_$0(m4_unquote(m4_joinall([[$2], [$3])[]_$0(],
  m4_unquote(m4_split(m4_normalize($1),[ ]))))), [$2], [$3])])])



>From aaee3a93684f2c77a91bbd78f7106834105f8b11 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Mon, 13 Oct 2008 10:46:40 -0600
Subject: [PATCH] Document m4_map_args.

* lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
Rename...
(m4_map_args, m4_map_args_pair): ...to these names, and document.
* lib/m4sugar/foreach.m4 (m4_map_args, m4_map_args_pair)
(_m4_map_args_, _m4_map_args_pair_, _m4_map_args_pair_end):
Likewise.
* lib/m4sugar/m4sh.m4 (AS_CASE, AS_IF): Adjust callers.
* tests/m4sugar.at (m4@&address@hidden): New test.
(recursion): Adjust caller.
* tests/m4sh.at (AS@&address@hidden and AS@&address@hidden): Likewise.
* doc/autoconf.texi (Looping constructs) <m4_map_args>: Document
this interface.
* NEWS: Mention the new macros.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog              |   17 +++++++++++++++++
 NEWS                   |    2 +-
 doc/autoconf.texi      |   35 +++++++++++++++++++++++++++++++++++
 lib/m4sugar/foreach.m4 |   26 +++++++++++++-------------
 lib/m4sugar/m4sh.m4    |    4 ++--
 lib/m4sugar/m4sugar.m4 |   14 +++++++-------
 tests/m4sh.at          |    2 +-
 tests/m4sugar.at       |   44 +++++++++++++++++++++++++++++++++++++++++---
 8 files changed, 117 insertions(+), 27 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 8a4504c..8baaad0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2008-10-13  Eric Blake  <address@hidden>
+
+       Document m4_map_args.
+       * lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
+       Rename...
+       (m4_map_args, m4_map_args_pair): ...to these names, and document.
+       * lib/m4sugar/foreach.m4 (m4_map_args, m4_map_args_pair)
+       (_m4_map_args_, _m4_map_args_pair_, _m4_map_args_pair_end):
+       Likewise.
+       * lib/m4sugar/m4sh.m4 (AS_CASE, AS_IF): Adjust callers.
+       * tests/m4sugar.at (m4@&address@hidden): New test.
+       (recursion): Adjust caller.
+       * tests/m4sh.at (AS@&address@hidden and AS@&address@hidden): Likewise.
+       * doc/autoconf.texi (Looping constructs) <m4_map_args>: Document
+       this interface.
+       * NEWS: Mention the new macros.
+
 2008-10-14  Eric Blake  <address@hidden>
 
        Correct previous patch.
diff --git a/NEWS b/NEWS
index 31e58c6..f85d58d 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,7 @@ GNU Autoconf NEWS - User visible changes.
 ** Configure scripts now use shell functions.
 
 ** The following m4sugar macros are new:
-   m4_default_quoted
+   m4_default_quoted  m4_map_args  m4_map_args_pair
 
 ** The following documented m4sh macros are new:
    AS_LINENO_PREPARE
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index ddd0638..77d27ef 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -10926,6 +10926,41 @@ Looping constructs
 @end example
 @end defmac
 
address@hidden m4_map_args (@var{macro}, @address@hidden)
address@hidden
+Repeatedly invoke @var{macro} with each successive @var{arg} as its
+argument.  In the following example, three solutions are presented with
+the same expansion; the solution using @code{m4_map_args} is the most
+efficient.
address@hidden
+m4_define([active], [ACTIVE])dnl
+m4_foreach([var], [[plain], [active]], [ m4_echo(m4_defn([var]))])
address@hidden plain active
+m4_map([ m4_echo], [[[plain]], [[active]]])
address@hidden plain active
+m4_map_args([ m4_echo], [plain], [active])
address@hidden plain active
address@hidden example
address@hidden defmac
+
address@hidden m4_map_args_pair (@var{macro}, @dvar{macro-end, macro}, @
+  @address@hidden)
address@hidden
+For every pair of arguments @var{arg}, invoke @var{macro} with two
+arguments.  If there is an odd number of arguments, invoke
address@hidden, which defaults to @var{macro}, with the remaining
+argument.
+
address@hidden
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3])
address@hidden, 2, 1, 3
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3])
address@hidden, 2, 1, [3]
+m4_map_args_pair([, m4_reverse], [, m4_dquote], [1], [2], [3], [4])
address@hidden, 2, 1, 4, 3
address@hidden example
address@hidden defmac
+
 @defmac m4_shiftn (@var{count}, @dots{})
 @defmacx m4_shift2 (@dots{})
 @defmacx m4_shift3 (@dots{})
diff --git a/lib/m4sugar/foreach.m4 b/lib/m4sugar/foreach.m4
index bfad301..9dc02e1 100644
--- a/lib/m4sugar/foreach.m4
+++ b/lib/m4sugar/foreach.m4
@@ -270,33 +270,33 @@ m4_define([_m4_map],
 m4_define([_m4_map_],
 [[$$1, [$$2])]])
 
-# m4_transform(EXPRESSION, ARG...)
-# --------------------------------
+# 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_transform, defined as:
-#   $1([$2])[]$1([$3])[]...$1([$m])[]_m4_popdef([_m4_transform])
-m4_define([m4_transform],
+# 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_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [2], [$#], [1],
    [_$0_([1], _$0)])[_m4_popdef([_$0])])_$0($@)])])
 
-m4_define([_m4_transform_],
+m4_define([_m4_map_args_],
 [[$$1([$$2])[]]])
 
-# m4_transform_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
-# --------------------------------------------------------------
+# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
+# -------------------------------------------------------------
 # Perform a pairwise grouping of consecutive ARGs, by expanding
 # EXPRESSION([ARG1], [ARG2]).  If there are an odd number of ARGs, the
 # final argument is expanded with END-EXPR([ARGn]).
 #
-# Build the temporary macro _m4_transform_pair, with the $2([$m+1])
+# Build the temporary macro _m4_map_args_pair, with the $2([$m+1])
 # only output if $# is odd:
 #   $1([$3], [$4])[]$1([$5], [$6])[]...$1([$m-1],
-#   [$m])[]m4_default([$2], [$1])([$m+1])[]_m4_popdef([_m4_transform_pair])
-m4_define([m4_transform_pair],
+#   [$m])[]m4_default([$2], [$1])([$m+1])[]_m4_popdef([_m4_map_args_pair])
+m4_define([m4_map_args_pair],
 [m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
        [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
        [$#], [2], [],
@@ -305,10 +305,10 @@ m4_define([m4_transform_pair],
    m4_eval([$# / 2 * 2 - 1]), [2], [_$0_([1], _$0, m4_incr(_$0))])_$0_end(
    [1], [2], [$#])[_m4_popdef([_$0])])_$0($@)])])
 
-m4_define([_m4_transform_pair_],
+m4_define([_m4_map_args_pair_],
 [[$$1([$$2], [$$3])[]]])
 
-m4_define([_m4_transform_pair_end],
+m4_define([_m4_map_args_pair_end],
 [m4_if(m4_eval([$3 & 1]), [1], [[m4_default([$$2], [$$1])([$$3])[]]])])
 
 # m4_join(SEP, ARG1, ARG2...)
diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index fbc4784..1f48234 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -466,7 +466,7 @@ m4_define([_AS_CASE_DEFAULT],
 m4_defun([AS_CASE],
 [m4_ifval([$2$3],
 [case $1 in
-m4_transform_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl
+m4_map_args_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl
 esac
 ])dnl
 ])# AS_CASE
@@ -511,7 +511,7 @@ m4_defun([AS_IF],
 [m4_ifval([$2$3],
 [if $1; then
   m4_default([$2], [:])
-m4_transform_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl
+m4_map_args_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl
 fi
 ])dnl
 ])# AS_IF
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 2e02a77..1e729df 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -1106,34 +1106,34 @@ m4_define([_m4_map],
 [m4_if([$#], [2], [],
        [$1, [$3])$0([$1], m4_shift2($@))])])
 
-# m4_transform(EXPRESSION, ARG...)
-# --------------------------------
+# 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_define([m4_transform],
+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_transform_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
-# --------------------------------------------------------------
+# m4_map_args_pair(EXPRESSION, [END-EXPR = EXPRESSION], ARG...)
+# -------------------------------------------------------------
 # Perform a pairwise grouping of consecutive ARGs, by expanding
 # EXPRESSION([ARG1], [ARG2]).  If there are an odd number of ARGs, the
 # final argument is expanded with END-EXPR([ARGn]).
 #
 # For example:
 #   m4_define([show], [($*)m4_newline])dnl
-#   m4_transform_pair([show], [], [a], [b], [c], [d], [e])dnl
+#   m4_map_args_pair([show], [], [a], [b], [c], [d], [e])dnl
 #   => (a,b)
 #   => (c,d)
 #   => (e)
 #
 # Please keep foreach.m4 in sync with any adjustments made here.
-m4_define([m4_transform_pair],
+m4_define([m4_map_args_pair],
 [m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])],
        [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])],
        [$#], [2], [],
diff --git a/tests/m4sh.at b/tests/m4sh.at
index 1f8f836..4498368 100644
--- a/tests/m4sh.at
+++ b/tests/m4sh.at
@@ -696,7 +696,7 @@ AT_CLEANUP
 ## ------------------- ##
 
 AT_SETUP([AS@&address@hidden and AS@&address@hidden)
-AT_KEYWORDS([m4sh m4@&address@hidden)
+AT_KEYWORDS([m4sh m4@&address@hidden)
 
 AT_DATA_M4SH([script.as], [[dnl
 AS_INIT
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 89109c6..72b7843 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -866,6 +866,44 @@ hi
 AT_CLEANUP
 
 
+## --------------------- ##
+## m4_map_args{,_pair}.  ##
+## --------------------- ##
+
+AT_SETUP([m4@&address@hidden)
+AT_KEYWORDS([m4@&address@hidden m4@&address@hidden)
+
+AT_CHECK_M4SUGAR_TEXT([[m4_define([active], [ACTIVE])dnl
+m4_map_args([ m4_echo])
+m4_map_args([ m4_echo], [plain], [active])
+m4_map_args([m4_unquote], [plain], [active])
+m4_map_args_pair([, m4_reverse], [])
+m4_map_args_pair([, m4_reverse], [], [1])
+m4_map_args_pair([, m4_reverse], [], [1], [2])
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3])
+m4_map_args_pair([, m4_reverse], [], [1], [2], [3], [4])
+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])
+]],
+[[
+ plain active
+plainACTIVE
+
+, 1
+, 2, 1
+, 2, 1, 3
+, 2, 1, 4, 3
+, [1]
+, 2, 1
+, 2, 1, [3]
+, 2, 1, 4, 3
+]])
+
+AT_CLEANUP
+
+
 ## ------------ ##
 ## m4_combine.  ##
 ## ------------ ##
@@ -981,7 +1019,7 @@ AT_SETUP([recursion])
 AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden 
m4@&address@hidden
 m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden 
m4@&address@hidden
 m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden 
m4@&address@hidden m4@&address@hidden
-m4@&address@hidden m4@&address@hidden m4@&address@hidden)
+m4@&address@hidden m4@&address@hidden m4@&address@hidden)
 
 dnl This test completes in a reasonable time if m4_foreach is linear,
 dnl but thrashes if it is quadratic.  If we are testing with m4 1.4.x,
@@ -1009,7 +1047,7 @@ m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), 
[a2], [A])
 m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$]))
 m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
 m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
-m4_count(m4_transform_pair([,m4_quote], []m4_transform([,m4_echo]m4_for([i],
+m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
   [1], [10000], [], [,i]))))
 m4_divert_pop(0)
 ]])
@@ -1066,7 +1104,7 @@ m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), 
[a2], [A])
 m4_bmatch([9997]m4_for([i], [1], [10000], [], [,^i$]))
 m4_define([up], [m4_define([$1], m4_incr($1))$1])m4_define([j], 0)dnl
 m4_cond(m4_for([i], [1], [10000], [], [[up([j])], [9990], i,]) [oops]) j
-m4_count(m4_transform_pair([,m4_quote], []m4_transform([,m4_echo]m4_for([i],
+m4_count(m4_map_args_pair([,m4_quote], []m4_map_args([,m4_echo]m4_for([i],
   [1], [10000], [], [,i]))))
 m4_divert_pop(0)
 ]])
-- 
1.6.0.2


>From 4cd6caa7854bf0ce28962521a2a3de49dec26f40 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Mon, 13 Oct 2008 15:37:31 -0600
Subject: [PATCH] Add m4_set_map.

* lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
* tests/m4sugar.at (m4@&address@hidden): Enhance test.
* doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
Document it.
* NEWS: Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog              |    9 +++++++++
 NEWS                   |    2 +-
 doc/autoconf.texi      |   14 +++++++++++++-
 lib/m4sugar/m4sugar.m4 |   15 ++++++++++++++-
 tests/m4sugar.at       |   12 ++++++++++--
 5 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 8baaad0..eb0f2d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2008-10-13  Eric Blake  <address@hidden>
 
+       Add m4_set_map.
+       * lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
+       * tests/m4sugar.at (m4@&address@hidden): Enhance test.
+       * doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
+       Document it.
+       * NEWS: Likewise.
+
+2008-10-13  Eric Blake  <address@hidden>
+
        Document m4_map_args.
        * lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
        Rename...
diff --git a/NEWS b/NEWS
index f85d58d..ba2779e 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,7 @@ GNU Autoconf NEWS - User visible changes.
 ** Configure scripts now use shell functions.
 
 ** The following m4sugar macros are new:
-   m4_default_quoted  m4_map_args  m4_map_args_pair
+   m4_default_quoted  m4_map_args  m4_map_args_pair  m4_set_map
 
 ** The following documented m4sh macros are new:
    AS_LINENO_PREPARE
diff --git a/doc/autoconf.texi b/doc/autoconf.texi
index 77d27ef..a56029b 100644
--- a/doc/autoconf.texi
+++ b/doc/autoconf.texi
@@ -11749,6 +11749,17 @@ Set manipulation Macros
 @end example
 @end defmac
 
address@hidden m4_set_map (@var{set}, @var{action})
address@hidden
+For each element in the set @var{set}, expand @var{action} with a single
+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))}.
address@hidden defmac
+
 @defmac m4_set_remove (@var{set}, @var{value}, @ovar{if-present}, @
  @ovar{if-absent})
 @msindex{set_remove}
@@ -11756,7 +11767,8 @@ Set manipulation Macros
 expand @var{if-present}.  Otherwise expand @var{if-absent}.  This macro
 operates in constant time so that multiple removals will scale linearly
 rather than quadratically; but when used outside of
address@hidden, it leaves memory occupied until the set is later
address@hidden or @code{m4_set_map}, it leaves memory occupied
+until the set is later
 compacted by @code{m4_set_contents} or @code{m4_set_list}.  Several
 other set operations are then less efficient between the time of element
 removal and subsequent memory compaction, but still maintain their
diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4
index 1e729df..59fb5ad 100644
--- a/lib/m4sugar/m4sugar.m4
+++ b/lib/m4sugar/m4sugar.m4
@@ -2711,6 +2711,19 @@ m4_define([m4_set_listc],
          [_m4_set_contents_1])([$1])_m4_set_contents_2([$1],
               [,_m4_defn([_m4_set_($1)])])])
 
+# m4_set_map(SET, ACTION)
+# -----------------------
+# For each element of SET, expand ACTION with a single argument of the
+# 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
+#   m4_map_args([ACTION]m4_set_listc([SET]))
+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_defn([_m4_set_($1)]))])])
+
 # m4_set_remove(SET, VALUE, [IF-PRESENT], [IF-ABSENT])
 # ----------------------------------------------------
 # If VALUE is an element of SET, delete it and expand IF-PRESENT.
@@ -2720,7 +2733,7 @@ m4_define([m4_set_listc],
 #
 # Optimize if the element being removed is the most recently added,
 # since defining _m4_set_cleanup($1) slows down so many other macros.
-# In particular, this plays well with m4_set_foreach.
+# In particular, this plays well with m4_set_foreach and m4_set_map.
 m4_define([m4_set_remove],
 [m4_set_contains([$1], [$2], [_m4_set_size([$1],
     [m4_decr])m4_if(_m4_defn([_m4_set([$1])]), [$2],
diff --git a/tests/m4sugar.at b/tests/m4sugar.at
index 72b7843..d6f40a7 100644
--- a/tests/m4sugar.at
+++ b/tests/m4sugar.at
@@ -1136,7 +1136,8 @@ AT_SETUP([m4@&address@hidden)
 AT_KEYWORDS([m4@&address@hidden m4@&address@hidden m4@&address@hidden
 m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
 m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
-m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden)
+m4@&address@hidden m4@&address@hidden m4@&address@hidden m4@&address@hidden
+m4@&address@hidden)
 
 # Simple tests
 AT_CHECK_M4SUGAR_TEXT([[m4_set_contains([a], [1], [yes], [no])
@@ -1161,6 +1162,8 @@ m4_set_difference([a], [b])
 m4_set_difference([b], [a])
 m4_set_intersection([a], [b])
 m4_set_union([a], [b])
+m4_define([printodd], [m4_if(m4_eval([$1 & 1]), [1], [:$1])])dnl
+m4_set_map([a], [printodd])
 m4_set_foreach([a], [i], [m4_if(m4_eval(i & 1), [1], [m4_set_remove([a], i)])])
 m4_set_list([a])
 m4_set_add([a], [])
@@ -1196,6 +1199,7 @@ yes
 ,,4
 ,3
 ,1,2,3,,4
+:1:3
 
 2
 
@@ -1259,11 +1263,15 @@ m4_len(m4_set_contents([a]))
 m4_len(m4_set_foreach([b], [b], [m4_if(m4_eval(b & 1), [1],
   [m4_set_remove([b], b, [-])])]))
 m4_set_size([b])
+m4_define([prune3x], [m4_if(m4_eval([$1 % 3]), [0],
+  [m4_set_remove([a], [$1], [-])])])dnl
+m4_len(m4_set_map([a], [prune3x]))
 m4_count(m4_shift(m4_set_intersection([a], [b])))
 ]], [[38894
 5000
 5000
-5000
+3333
+3334
 ]])
 
 AT_CLEANUP
-- 
1.6.0.2


>From 3bdb8d4f420ed6b71f6b63e699c38558bf39020d Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Mon, 13 Oct 2008 17:09:09 -0600
Subject: [PATCH] Improve suggested test filtering.

* lib/m4sugar/m4sh.m4 (_AS_DETECT_SUGGESTED_PRUNE): New macro,
extracted from...
(_AS_DETECT_BETTER_SHELL): ...here, to use faster API.
* lib/autoconf/general.m4 (AC_CHECK_FILES): Fix typo.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog               |    8 ++++++++
 lib/autoconf/general.m4 |    2 +-
 lib/m4sugar/m4sh.m4     |   14 +++++++++-----
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index eb0f2d9..b2de9bd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2008-10-13  Eric Blake  <address@hidden>
 
+       Improve suggested test filtering.
+       * lib/m4sugar/m4sh.m4 (_AS_DETECT_SUGGESTED_PRUNE): New macro,
+       extracted from...
+       (_AS_DETECT_BETTER_SHELL): ...here, to use faster API.
+       * lib/autoconf/general.m4 (AC_CHECK_FILES): Fix typo.
+
+2008-10-13  Eric Blake  <address@hidden>
+
        Add m4_set_map.
        * lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
        * tests/m4sugar.at (m4@&address@hidden): Enhance test.
diff --git a/lib/autoconf/general.m4 b/lib/autoconf/general.m4
index 986b7af..9c3c7c3 100644
--- a/lib/autoconf/general.m4
+++ b/lib/autoconf/general.m4
@@ -2620,7 +2620,7 @@ AC_DEFUN([AC_CHECK_FILES],
   [AC_CHECK_FILE(AC_FILE_NAME,
                 [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_[]AC_FILE_NAME), 1,
                                    [Define to 1 if you have the
-                                    file `]AC_File['.])
+                                    file `]AC_FILE_NAME['.])
 $2],
                 [$3])])])
 
diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4
index 1f48234..61aa416 100644
--- a/lib/m4sugar/m4sh.m4
+++ b/lib/m4sugar/m4sh.m4
@@ -172,6 +172,14 @@ m4_set_add([_AS_DETECT_SUGGESTED_BODY],
 ])])
 
 
+# _AS_DETECT_SUGGESTED_PRUNE(TEST)
+# --------------------------------
+# If TEST is also a required test, remove it from the set of suggested tests.
+m4_define([_AS_DETECT_SUGGESTED_PRUNE],
+[m4_set_contains([_AS_DETECT_REQUIRED_BODY], [$1],
+                [m4_set_remove([_AS_DETECT_SUGGESTED_BODY], [$1])])])
+
+
 # _AS_DETECT_BETTER_SHELL
 # -----------------------
 # The real workhorse for detecting a shell with the correct
@@ -191,11 +199,7 @@ m4_defun_once([_AS_DETECT_BETTER_SHELL],
 m4_append([_AS_CLEANUP], [m4_divert_text([M4SH-SANITIZE], [
 if test "x$CONFIG_SHELL" = x; then
 dnl Remove any tests from suggested that are also required
-  m4_set_foreach([_AS_DETECT_SUGGESTED_BODY], [AS_snippet],
-                [m4_set_contains([_AS_DETECT_REQUIRED_BODY],
-                                 _m4_defn([AS_snippet]),
-                                 [m4_set_remove([_AS_DETECT_SUGGESTED_BODY],
-                                                _m4_defn([AS_snippet]))])])dnl
+  m4_set_map([_AS_DETECT_SUGGESTED_BODY], [_AS_DETECT_SUGGESTED_PRUNE])dnl
   m4_set_empty([_AS_DETECT_REQUIRED_BODY], [as_have_required=yes],
     [AS_IF([_AS_RUN(m4_set_contents([_AS_DETECT_REQUIRED_BODY])) 2>/dev/null],
          [as_have_required=yes],
-- 
1.6.0.2








reply via email to

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