From 903b58ef950b8bd5598c45909744309f58c03c45 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 13 Aug 2008 09:12:28 -0600 Subject: [PATCH] Implement m4_transform_pair, to speed up AS_IF. * lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair): New macros, undocumented for now. * lib/m4sugar/foreach.m4 (m4_transform, m4_transform_pair): Also the m4 1.4.x counterparts. * lib/m4sugar/m4sh.m4 (AS_IF, AS_CASE): Use it. * tests/m4sh.at (AS@&t@_IF and AS@&t@_CASE): Test it. Signed-off-by: Eric Blake --- ChangeLog | 10 ++++++++++ lib/m4sugar/foreach.m4 | 41 +++++++++++++++++++++++++++++++++++++++++ lib/m4sugar/m4sh.m4 | 21 +++++++++------------ lib/m4sugar/m4sugar.m4 | 32 ++++++++++++++++++++++++++++++++ tests/m4sh.at | 27 +++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index a2e209f5..9df0fa66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-08-14 Eric Blake + + Implement m4_transform_pair, to speed up AS_IF. + * lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair): New + macros, undocumented for now. + * lib/m4sugar/foreach.m4 (m4_transform, m4_transform_pair): Also + the m4 1.4.x counterparts. + * lib/m4sugar/m4sh.m4 (AS_IF, AS_CASE): Use it. + * tests/m4sh.at (AS@&t@_IF and AS@&t@_CASE): Test it. + 2008-08-14 Ralf Wildenhues * lib/autoconf/programs.m4 (AC_PATH_TARGET_TOOL) diff --git a/lib/m4sugar/foreach.m4 b/lib/m4sugar/foreach.m4 index 816ee608..53a2c7e2 100644 --- a/lib/m4sugar/foreach.m4 +++ b/lib/m4sugar/foreach.m4 @@ -263,6 +263,47 @@ m4_define([_m4_map], [m4_foreach([_m4_elt], [m4_shift2($@)], [m4_apply([$1], m4_defn([_m4_elt]))])])]) +# m4_transform(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], +[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_], +[[$$1([$$2])[]]]) + +# m4_transform_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]) +# 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], +[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])], + [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])], + [$#], [2], [], + [$#], [3], [m4_default([$2], [$1])([$3])[]], + [m4_define([_$0], m4_pushdef([_$0])_m4_for([_$0], [3], + 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_], +[[$$1([$$2], [$$3])[]]]) + +m4_define([_m4_transform_pair_end], +[m4_if(m4_eval([$3 & 1]), [1], [[m4_default([$$2], [$$1])([$$3])[]]])]) + # m4_join(SEP, ARG1, ARG2...) # --------------------------- # Produce ARG1SEPARG2...SEPARGn. Avoid back-to-back SEP when a given ARG diff --git a/lib/m4sugar/m4sh.m4 b/lib/m4sugar/m4sh.m4 index 74d83778..15176309 100644 --- a/lib/m4sugar/m4sh.m4 +++ b/lib/m4sugar/m4sh.m4 @@ -453,16 +453,15 @@ m4_defun([AS_PREPARE], # | *) DEFAULT ;; # | esac m4_define([_AS_CASE], -[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])], - [$#], 1, [ *) $1 ;;], - [$#], 2, [ $1) m4_default([$2], [:]) ;;], - [ $1) m4_default([$2], [:]) ;; -$0(m4_shift2($@))])dnl +[ $1[)] m4_default([$2], [:]) ;; +]) +m4_define([_AS_CASE_DEFAULT], +[ *[)] $1 ;; ]) m4_defun([AS_CASE], [m4_ifval([$2$3], [case $1 in -_AS_CASE(m4_shift($@)) +m4_transform_pair([_$0], [_$0_DEFAULT], m4_shift($@))dnl esac ])dnl ])# AS_CASE @@ -496,20 +495,18 @@ m4_define([AS_EXIT], # with simplifications if IF-TRUE1 and/or IF-FALSE is empty. # m4_define([_AS_IF], -[m4_ifval([$2$3], [elif $1; then m4_default([$2], [:]) -m4_ifval([$3], [$0(m4_shift2($@))])], +]) +m4_define([_AS_IF_ELSE], [m4_ifvaln([$1], [else - $1])dnl -])dnl -])# _AS_IF + $1])]) m4_defun([AS_IF], [m4_ifval([$2$3], [if $1; then m4_default([$2], [:]) -m4_ifval([$3], [_$0(m4_shift2($@))])[]dnl +m4_transform_pair([_$0], [_$0_ELSE], m4_shift2($@))dnl fi ])dnl ])# AS_IF diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4 index 22af6efb..a5a07b96 100644 --- a/lib/m4sugar/m4sugar.m4 +++ b/lib/m4sugar/m4sugar.m4 @@ -1028,6 +1028,38 @@ m4_define([m4_map_sep], [m4_apply([$1], m4_car($3))_m4_map([[$2]$1], $3)])]) +# m4_transform(EXPRESSION, ARG...) +# -------------------------------- +# Expand EXPRESSION([ARG]) for each argument. More efficient than +# m4_foreach([var], [ARG...], [EXPRESSION(m4_defn([var]))]) +m4_define([m4_transform], +[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...) +# -------------------------------------------------------------- +# 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 +# => (a,b) +# => (c,d) +# => (e) +m4_define([m4_transform_pair], +[m4_if([$#], [0], [m4_fatal([$0: too few arguments: $#])], + [$#], [1], [m4_fatal([$0: too few arguments: $#: $1])], + [$#], [2], [], + [$#], [3], [m4_default([$2], [$1])([$3])[]], + [$#], [4], [$1([$3], [$4])[]], + [$1([$3], [$4])[]$0([$1], [$2], m4_shift(m4_shift3($@)))])]) + + ## --------------------------- ## ## 9. More diversion support. ## ## --------------------------- ## diff --git a/tests/m4sh.at b/tests/m4sh.at index e01f769f..ac5f8ba8 100644 --- a/tests/m4sh.at +++ b/tests/m4sh.at @@ -634,6 +634,8 @@ AT_CLEANUP AT_SETUP([AS@&t@_IF and AS@&t@_CASE]) +AT_KEYWORDS([m4@&t@_foreach_pair]) + AT_DATA_M4SH([script.as], [[dnl AS_INIT # Syntax checks: cope with empty arguments. @@ -725,6 +727,31 @@ foo8=8 bar8=8 foo9=9 bar9=9 ]]) +dnl stress test for large number of conditionals +AT_DATA_M4SH([script.as], [[dnl +AS_INIT +AS_IF(m4_shift(m4_for([i], [1], [1000], [], [, test $[1] = i, echo i]))) +AS_IF(m4_shift(m4_for([i], [1], [1000], [], [, test $[1] = i, echo i])), + [echo default]) +AS_CASE([$[1]]m4_for([i], [1], [1000], [], [, i, echo i])) +AS_CASE([$[1]]m4_for([i], [1], [1000], [], [, i, echo i]), [echo default]) +]]) + +AT_CHECK_M4SH +AT_CHECK([./script 1], [0], [[1 +1 +1 +1 +]]) +AT_CHECK([./script 1000], [0], [[1000 +1000 +1000 +1000 +]]) +AT_CHECK([./script default], [0], [[default +default +]]) + AT_CLEANUP -- 2.11.4.GIT