* lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
* tests/m4sugar.at (m4@&t@_set): Enhance test.
* doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
Document it.
* NEWS: Likewise.
Signed-off-by: Eric Blake <ebb9@byu.net>
2008-10-17 Eric Blake <ebb9@byu.net>
+ Add m4_set_map.
+ * lib/m4sugar/m4sugar.m4 (m4_set_foreach): New macro.
+ * tests/m4sugar.at (m4@&t@_set): Enhance test.
+ * doc/autoconf.texi (Set manipulation Macros) <m4_set_map>:
+ Document it.
+ * NEWS: Likewise.
+
Document m4_map_args.
* lib/m4sugar/m4sugar.m4 (m4_transform, m4_transform_pair):
Rename...
** 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 AS_ME_PREPARE AS_VAR_COPY
@end example
@end defmac
+@defmac m4_set_map (@var{set}, @var{action})
+@msindex{set_map}
+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
+@code{m4_map_args([@var{action}]m4_set_listc([@var{set}]))}.
+@end defmac
+
@defmac m4_set_remove (@var{set}, @var{value}, @ovar{if-present}, @
@ovar{if-absent})
@msindex{set_remove}
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
-@code{m4_set_foreach}, it leaves memory occupied until the set is later
+@code{m4_set_foreach} 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
[_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.
#
# 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],
AT_KEYWORDS([m4@&t@_set_add m4@&t@_set_add_all m4@&t@_set_contains
m4@&t@_set_contents m4@&t@_set_delete m4@&t@_set_difference m4@&t@_set_dump
m4@&t@_set_empty m4@&t@_set_foreach m4@&t@_set_intersection m4@&t@_set_list
-m4@&t@_set_listc m4@&t@_set_remove m4@&t@_set_size m4@&t@_set_union])
+m4@&t@_set_listc m4@&t@_set_map m4@&t@_set_remove m4@&t@_set_size
+m4@&t@_set_union])
# Simple tests
AT_CHECK_M4SUGAR_TEXT([[m4_set_contains([a], [1], [yes], [no])
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], [])
,,4
,3
,1,2,3,,4
+:1:3
2
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