From 694606d3388848d4cf2ddbc9b329851e0a88f706 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 30 Jul 2008 16:44:03 -0600 Subject: [PATCH] Add linear m4_cond for m4 1.4.x. * lib/m4sugar/m4sugar.m4 (m4_cond): Split into... (_m4_cond): ...this, for fewer macros per iteration. * lib/m4sugar/foreach.m4 (_m4_cond): New implementation. * tests/m4sugar.at (recursion): Test it. * NEWS: Document the linear guarantee. Signed-off-by: Eric Blake --- ChangeLog | 7 +++++++ NEWS | 4 ++-- lib/m4sugar/foreach.m4 | 24 +++++++++++++++++++++++- lib/m4sugar/m4sugar.m4 | 10 ++++++++-- tests/m4sugar.at | 13 ++++++++++--- 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index a00502b0..60b3ee54 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2008-08-06 Eric Blake + Add linear m4_cond for m4 1.4.x. + * lib/m4sugar/m4sugar.m4 (m4_cond): Split into... + (_m4_cond): ...this, for fewer macros per iteration. + * lib/m4sugar/foreach.m4 (_m4_cond): New implementation. + * tests/m4sugar.at (recursion): Test it. + * NEWS: Document the linear guarantee. + Speed up diversion handling. * lib/m4sugar/m4sugar.m4 (m4_divert, m4_divert_push) (m4_divert_pop, m4_divert_text): Avoid dnl for fewer macro diff --git a/NEWS b/NEWS index 30f0f4ea..efd7f46e 100644 --- a/NEWS +++ b/NEWS @@ -33,8 +33,8 @@ GNU Autoconf NEWS - User visible changes. previously had linear scaling with m4 1.6 but quadratic scaling when using m4 1.4.x. All macros built on top of these also gain the scaling improvements. - m4_bpatsubsts m4_case m4_do m4_dquote_elt m4_foreach m4_join - m4_list_cmp m4_map m4_map_sep m4_max m4_min m4_shiftn + m4_bpatsubsts m4_case m4_cond m4_do m4_dquote_elt m4_foreach + m4_join m4_list_cmp m4_map m4_map_sep m4_max m4_min m4_shiftn ** AT_KEYWORDS once again performs expansion on its argument, such that AT_KEYWORDS([m4_if([$1], [], [default])]) no longer complains about diff --git a/lib/m4sugar/foreach.m4 b/lib/m4sugar/foreach.m4 index 3109a8f8..78779c40 100644 --- a/lib/m4sugar/foreach.m4 +++ b/lib/m4sugar/foreach.m4 @@ -121,6 +121,29 @@ m4_define([m4_case], m4_define([_m4_case_], [[[$$1],[$$2],[$$3],]]) +# m4_cond(TEST1, VAL1, IF-VAL1, TEST2, VAL2, IF-VAL2, ..., [DEFAULT]) +# ------------------------------------------------------------------- +# Similar to m4_if, except that each TEST is expanded when encountered. +# If the expansion of TESTn matches the string VALn, the result is IF-VALn. +# The result is DEFAULT if no tests passed. This macro allows +# short-circuiting of expensive tests, where it pays to arrange quick +# filter tests to run first. +# +# m4_cond already guarantees either 3*n or 3*n + 1 arguments, 1 <= n. +# We only have to speed up _m4_cond, by building the temporary _m4_c: +# m4_define([_m4_c], _m4_defn([m4_unquote]))_m4_c([m4_if(($1), [($2)], +# [$3[]m4_define([_m4_c])])])_m4_c([m4_if(($4), [($5)], +# [$6[]m4_define([_m4_c])])])..._m4_c([m4_if(($m-2), [($m-1)], +# [$m[]m4_define([_m4_c])])])_m4_c([$m+1]_m4_popdef([_m4_c])) +m4_define([_m4_cond], +[m4_define([_m4_c], m4_pushdef([_m4_c])[m4_define([_m4_c], + _m4_defn([m4_unquote]))]_m4_for([_m4_c], [2], m4_eval([$# / 3 * 3 - 1]), [3], + [$0_(m4_decr(_m4_c), _m4_c, m4_incr(_m4_c))])[_m4_c(]m4_dquote( + [$]m4_eval([$# / 3 * 3 + 1]))[_m4_popdef([_m4_c]))])_m4_c($@)]) + +m4_define([_m4_cond_], +[[_m4_c([m4_if(($$1), [($$2)], [$$3[]m4_define([_m4_c])])])]]) + # m4_bpatsubsts(STRING, RE1, SUBST1, RE2, SUBST2, ...) # ---------------------------------------------------- # m4 equivalent of @@ -147,7 +170,6 @@ m4_define([_m4_bpatsubsts_], [[m4_define([_m4_p], m4_bpatsubst(m4_dquote(_m4_defn([_m4_p])), [$$1], [$$2]))]]) - # m4_shiftn(N, ...) # ----------------- # Returns ... shifted N times. Useful for recursive "varargs" constructs. diff --git a/lib/m4sugar/m4sugar.m4 b/lib/m4sugar/m4sugar.m4 index 450d7a91..22af6efb 100644 --- a/lib/m4sugar/m4sugar.m4 +++ b/lib/m4sugar/m4sugar.m4 @@ -449,8 +449,14 @@ m4_define([_m4_cdr], m4_define([m4_cond], [m4_if([$#], [0], [m4_fatal([$0: cannot be called without arguments])], [$#], [1], [$1], - [$#], [2], [m4_fatal([$0: missing an argument])], - [m4_if($1, [$2], [$3], [$0(m4_shift3($@))])])]) + m4_eval([$# % 3]), [2], [m4_fatal([$0: missing an argument])], + [_$0($@)])]) + +m4_define([_m4_cond], +[m4_if(($1), [($2)], [$3], + [$#], [3], [], + [$#], [4], [$4], + [$0(m4_shift3($@))])]) ## ---------------------------------------- ## diff --git a/tests/m4sugar.at b/tests/m4sugar.at index 516881e9..60910de8 100644 --- a/tests/m4sugar.at +++ b/tests/m4sugar.at @@ -816,9 +816,9 @@ AT_CLEANUP AT_SETUP([recursion]) -AT_KEYWORDS([m4@&t@_foreach m4@&t@_foreach_w m4@&t@_case m4@&t@_bpatsubsts -m4@&t@_shiftn m4@&t@_do m4@&t@_dquote_elt m4@&t@_reverse m4@&t@_map -m4@&t@_join m4@&t@_joinall m4@&t@_list_cmp m4@&t@_max m4@&t@_min]) +AT_KEYWORDS([m4@&t@_foreach m4@&t@_foreach_w m4@&t@_case m4@&t@_cond +m4@&t@_bpatsubsts m4@&t@_shiftn m4@&t@_do m4@&t@_dquote_elt m4@&t@_reverse +m4@&t@_map m4@&t@_join m4@&t@_joinall m4@&t@_list_cmp m4@&t@_max m4@&t@_min]) 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, @@ -843,6 +843,8 @@ m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0]) m4_for([i], [1], [10000], [], [m4_define(i)])dnl m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), [a2], [A]) +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_divert_pop(0) ]]) @@ -856,6 +858,7 @@ end 0 0 A +9990 9990 ]]) AT_DATA_M4SUGAR([script.4s], @@ -871,6 +874,7 @@ end 0 0 A +9990 9990 m4_exit([0])]) m4_init m4_divert_push(0)[]dnl @@ -889,6 +893,8 @@ m4_list_cmp([0m4_for([i], [1], [10000], [], [,0])], [0]) m4_for([i], [1], [10000], [], [m4_define(i)])dnl m4_undefine(1m4_for([i], [2], [10000], [], [,i]))dnl m4_bpatsubsts([a1]m4_for([i], [1], [10000], [], [,i]), [a2], [A]) +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]) m4_divert_pop(0) ]]) @@ -902,6 +908,7 @@ end 0 0 A +9990 9990 ]]) AT_CLEANUP -- 2.11.4.GIT