From ce0298d64eb08c59d5116b07ff4e090111d289ed Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 12 Aug 2008 15:23:56 -0600 Subject: [PATCH] Optimize m4_bmatch. * lib/m4sugar/foreach.m4 (m4_bmatch): Provide linear implementation for m4 1.4.x. * tests/m4sugar.at (m4@&t@_bmatch): New test. (recursion): Test the linear nature. * NEWS: Document the fix. Signed-off-by: Eric Blake --- ChangeLog | 7 +++++++ NEWS | 5 +++-- lib/m4sugar/foreach.m4 | 33 +++++++++++++++++++++++++++++++++ tests/m4sugar.at | 40 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index d4600784..aa824655 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2008-08-12 Eric Blake + Optimize m4_bmatch. + * lib/m4sugar/foreach.m4 (m4_bmatch): Provide linear + implementation for m4 1.4.x. + * tests/m4sugar.at (m4@&t@_bmatch): New test. + (recursion): Test the linear nature. + * NEWS: Document the fix. + Fix m4_cond corner case. * lib/m4sugar/foreach.m4 (_m4_cond): Ensure alternate implementation allows concatenation with subsequent text. diff --git a/NEWS b/NEWS index dbff114c..2cf67471 100644 --- a/NEWS +++ b/NEWS @@ -38,8 +38,9 @@ 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_cond m4_do m4_dquote_elt m4_foreach - m4_join m4_list_cmp m4_map m4_map_sep m4_max m4_min m4_shiftn + m4_bmatch 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 b85fce2f..816ee608 100644 --- a/lib/m4sugar/foreach.m4 +++ b/lib/m4sugar/foreach.m4 @@ -121,6 +121,39 @@ m4_define([m4_case], m4_define([_m4_case_], [[[$$1],[$$2],[$$3],]]) +# m4_bmatch(SWITCH, RE1, VAL1, RE2, VAL2, ..., DEFAULT) +# ----------------------------------------------------- +# m4 equivalent of +# +# if (SWITCH =~ RE1) +# VAL1; +# elif (SWITCH =~ RE2) +# VAL2; +# elif ... +# ... +# else +# DEFAULT +# +# We build the temporary macro _m4_b: +# m4_define([_m4_b], _m4_defn([_m4_bmatch]))_m4_b([$1], [$2], [$3])... +# _m4_b([$1], [$m-1], [$m])_m4_b([], [], [$m+1]_m4_popdef([_m4_b])) +# then invoke m4_unquote(_m4_b($@)), for concatenation with later text. +m4_define([m4_bmatch], +[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])], + [$#], 1, [m4_fatal([$0: too few arguments: $#: $1])], + [$#], 2, [$2], + [m4_define([_m4_b], m4_pushdef([_m4_b])[m4_define([_m4_b], + _m4_defn([_$0]))]_m4_for([_m4_b], [3], m4_eval([($# + 1) / 2 * 2 - 1]), + [2], [_$0_([1], m4_decr(_m4_b), _m4_b)])[_m4_b([], [],]m4_dquote( + [$]m4_incr(_m4_b))[_m4_popdef([_m4_b]))])m4_unquote(_m4_b($@))])]) + +m4_define([_m4_bmatch], +[m4_if(m4_bregexp([$1], [$2]), [-1], [], [[$3]m4_define([$0])])]) + +m4_define([_m4_bmatch_], +[[_m4_b([$$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. diff --git a/tests/m4sugar.at b/tests/m4sugar.at index 8e5fd012..8e9885ae 100644 --- a/tests/m4sugar.at +++ b/tests/m4sugar.at @@ -573,6 +573,38 @@ AT_CHECK_M4RE([m4_re_string], [9a@_c]) AT_CLEANUP +## ----------- ## +## m4_bmatch. ## +## ----------- ## + +AT_SETUP([m4@&t@_bmatch]) + +AT_CHECK_M4SUGAR_TEXT( +[[m4_bmatch([abc], [default\]) +m4_bmatch([abc], [^a], [yes]) +m4_bmatch([abc], [^a], [yes], [no]) +m4_bmatch([abc], [^.a], [yes]) +m4_bmatch([abc], [^.a], [yes], [no\]) +m4_bmatch([abc], [a], [1], [b], [2]) +m4_bmatch([abc], [A], [1], [b], [2]) +m4_define([ab], [AB])dnl +m4_bmatch([$*], [a])b +m4_bmatch([$*], [\*], [a])b +m4_bmatch([$*], [1], [2], [a])b +]], [[default\ +yes +yes + +no\ +1 +2 +AB +AB +AB +]]) + +AT_CLEANUP + ## --------------- ## ## m4_bpatsubsts. ## ## --------------- ## @@ -870,7 +902,8 @@ AT_SETUP([recursion]) 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]) +m4@&t@_map m4@&t@_join m4@&t@_joinall m4@&t@_list_cmp m4@&t@_max m4@&t@_min +m4@&t@_bmatch]) 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, @@ -895,6 +928,7 @@ 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_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_divert_pop(0) @@ -910,6 +944,7 @@ end 0 0 A +^9998$ 9990 9990 ]]) @@ -926,6 +961,7 @@ end 0 0 A +^9998$ 9990 9990 m4_exit([0])]) m4_init @@ -945,6 +981,7 @@ 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_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]) m4_divert_pop(0) @@ -960,6 +997,7 @@ end 0 0 A +^9998$ 9990 9990 ]]) -- 2.11.4.GIT