A few more m4sugar improvements, to benefit libtool.

* lib/m4sugar/m4sugar.m4 (m4_bpatsubsts, _m4_shiftn): Reduce size
of expansion by avoiding extra uses of $@.
(m4_shiftn): Avoid extra dnl, and forbid shifting by 0.
(_m4_cdr): New helper macro.
(_m4_map, m4_map_sep): Use it to reduce size of expansion.
(_m4_shift3): New helper macro.
(_m4_foreach): Swap argument order, and use new macro to reduce
size of expansion.
* doc/autoconf.texi (Looping constructs) <m4_shiftn>: Mention that
count must be positive.

Signed-off-by: Eric Blake <ebb9@byu.net>
This commit is contained in:
Eric Blake 2007-10-16 06:22:56 -06:00
parent d5f5cd5bf3
commit f3b4cc104e
3 changed files with 65 additions and 15 deletions

View File

@ -1,5 +1,17 @@
2007-10-16 Eric Blake <ebb9@byu.net>
A few more m4sugar improvements, to benefit libtool.
* lib/m4sugar/m4sugar.m4 (m4_bpatsubsts, _m4_shiftn): Reduce size
of expansion by avoiding extra uses of $@.
(m4_shiftn): Avoid extra dnl, and forbid shifting by 0.
(_m4_cdr): New helper macro.
(_m4_map, m4_map_sep): Use it to reduce size of expansion.
(_m4_shift3): New helper macro.
(_m4_foreach): Swap argument order, and use new macro to reduce
size of expansion.
* doc/autoconf.texi (Looping constructs) <m4_shiftn>: Mention that
count must be positive.
* doc/autoconf.texi (Evaluation Macros) <m4_expand>: Fix typo.
Reported by Ralf Wildenhues.

View File

@ -10670,7 +10670,8 @@ The deprecated macro @code{AC_FOREACH} is an alias of
@msindex{shiftn}
@code{m4_shiftn} performs @var{count} iterations of @code{m4_shift},
along with validation that enough arguments were passed in to match the
shift count. @code{m4_shift2} and @code{m4_shift3} are specializations
shift count, and that the count is positive. @code{m4_shift2} and
@code{m4_shift3} are specializations
of @code{m4_shiftn}, introduced in Autoconf 2.62, and are more efficient
for two and three shifts, respectively.
@end defmac

View File

@ -398,6 +398,18 @@ m4_define([m4_cdr],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
# _m4_cdr(LIST)
# -------------
# Like m4_cdr, except include a leading comma unless only one element
# remains. Why? Because comparing a large list against [] is more
# expensive in expansion time than comparing the number of arguments; so
# _m4_cdr can be used to reduce the number of arguments when it is time
# to end recursion.
m4_define([_m4_cdr],
[m4_if([$#], 1, [],
[, m4_dquote(m4_shift($@))])])
# m4_cond(TEST1, VAL1, IF-VAL1, TEST2, VAL2, IF-VAL2, ..., [DEFAULT])
# -------------------------------------------------------------------
@ -439,13 +451,12 @@ m4_define([m4_cond],
# -------------------
# Invoke MACRO($1), MACRO($2) etc. where $1, $2... are the elements
# of LIST (which can be lists themselves, for multiple arguments MACROs).
m4_define([m4_fst], [$1])
m4_define([m4_map],
[m4_if([$2], [[]], [],
[_m4_map([$1], [$2])])])
m4_define([_m4_map],
[m4_ifval([$2],
[$1(m4_fst($2))[]_m4_map([$1], m4_cdr($2))])])
[m4_if([$#], [1], [],
[$1(m4_unquote(m4_car($2)))[]_m4_map([$1]_m4_cdr($2))])])
# m4_map_sep(MACRO, SEPARATOR, LIST)
@ -455,7 +466,7 @@ m4_define([_m4_map],
# arguments MACROs).
m4_define([m4_map_sep],
[m4_if([$3], [[]], [],
[$1(m4_fst($3))[]_m4_map([$2[]$1], m4_cdr($3))])])
[$1(m4_unquote(m4_car($3)))[]_m4_map([$2[]$1]_m4_cdr($3))])])
## ---------------------------------------- ##
@ -483,7 +494,7 @@ m4_define([m4_map_sep],
m4_define([m4_bpatsubsts],
[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])],
[$#], 1, [m4_fatal([$0: too few arguments: $#: $1])],
[$#], 2, [m4_builtin([patsubst], $@)],
[$#], 2, [m4_builtin([patsubst], [$1], [$2])],
[_$0($@m4_if(m4_eval($# & 1), 0, [,]))])])
m4_define([_m4_bpatsubsts],
[m4_if([$#], 2, [$1],
@ -565,14 +576,24 @@ m4_define([m4_popdef],
# m4_shiftn(N, ...)
# -----------------
# Returns ... shifted N times. Useful for recursive "varargs" constructs.
#
# Autoconf does not use this macro, because it is inherently slower than
# calling the common cases of m4_shift2 or m4_shift3 directly. But it
# might as well be fast for other clients, such as Libtool. One way to
# do this is to expand $@ only once in _m4_shiftn (otherwise, for long
# lists, the expansion of m4_if takes twice as much memory as what the
# list itself occupies, only to throw away the unused branch). The end
# result is strictly equivalent to
# m4_if([$1], 1, [m4_shift(,m4_shift(m4_shift($@)))],
# [_m4_shiftn(m4_decr([$1]), m4_shift(m4_shift($@)))])
# but with the final `m4_shift(m4_shift($@)))' shared between the two
# paths. The first leg uses a no-op m4_shift(,$@) to balance out the ().
m4_define([m4_shiftn],
[m4_assert(0 <= $1 && $1 < $#)dnl
_m4_shiftn($@)])
[m4_assert(0 < $1 && $1 < $#)_$0($@)])
m4_define([_m4_shiftn],
[m4_if([$1], 0,
[m4_shift($@)],
[_m4_shiftn(m4_eval([$1]-1), m4_shift(m4_shift($@)))])])
[m4_if([$1], 1, [m4_shift(],
[$0(m4_decr([$1])]), m4_shift(m4_shift($@)))])
# m4_shift2(...)
# m4_shift3(...)
@ -581,6 +602,17 @@ m4_define([_m4_shiftn],
m4_define([m4_shift2], [m4_shift(m4_shift($@))])
m4_define([m4_shift3], [m4_shift(m4_shift(m4_shift($@)))])
# _m4_shift3(...)
# ---------------
# Like m4_shift3, except include a leading comma unless there were exactly
# three arguments. Why? Because in recursion, it is nice to distinguish
# between 1 element left and 0 elements left, based on how many arguments
# this shift expands to.
m4_define([_m4_shift3],
[m4_if([$#], [3], [],
[, m4_shift(m4_shift(m4_shift($@)))])])
# m4_undefine(NAME)
# -----------------
# Like the original, except don't tolerate undefining something which is
@ -827,13 +859,18 @@ m4_if(m4_defn([$1]), [$2], [],
# => -active--active-
#
# This macro is called frequently, so avoid extra expansions such as
# m4_ifval and dnl.
# m4_ifval and dnl. Also, since $2 might be quite large, try to use it
# as little as possible in _m4_foreach; each extra use requires that much
# more memory for expansion. So, rather than directly compare $2 against
# [] and use m4_car/m4_cdr for recursion, we instead unbox the list (which
# requires swapping the argument order in the helper) and use _m4_shift3
# to detect when recursion is complete.
m4_define([m4_foreach],
[m4_pushdef([$1])_$0($@)m4_popdef([$1])])
[m4_pushdef([$1])_$0([$1], [$3]m4_if([$2], [], [], [, $2]))m4_popdef([$1])])
m4_define([_m4_foreach],
[m4_if([$2], [], [],
[m4_define([$1], m4_car($2))$3[]$0([$1], m4_cdr($2), [$3])])])
[m4_if([$#], [2], [],
[m4_define([$1], [$3])$2[]$0([$1], [$2]_m4_shift3($@))])])
# m4_foreach_w(VARIABLE, LIST, EXPRESSION)