Bug 989460 - Part 2: Add MOZ_FOR_EACH macro. r=Waldo
authorBirunthan Mohanathas <birunthan@mohanathas.com>
Thu, 24 Apr 2014 10:49:00 +0200
changeset 180105 910de4b746382f35a350f534889c3b47743adbcb
parent 180104 c7399918527aae630408026e801464308a95419c
child 180106 2b02d933c39a96e44be37e955ed49dd4d8505a3d
child 180133 e6eeddc2625aeda1932c7d664771ad5d9e029a1b
push id26653
push usercbook@mozilla.com
push dateFri, 25 Apr 2014 10:50:28 +0000
treeherdermozilla-central@2b02d933c39a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs989460
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 989460 - Part 2: Add MOZ_FOR_EACH macro. r=Waldo
mfbt/MacroForEach.h
mfbt/moz.build
mfbt/tests/TestMacroForEach.cpp
mfbt/tests/moz.build
new file mode 100644
--- /dev/null
+++ b/mfbt/MacroForEach.h
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Implements a higher-order macro for iteratively calling another macro with
+ * fixed leading arguments, plus a trailing element picked from a second list
+ * of arguments.
+ */
+
+#ifndef mozilla_MacroForEach_h
+#define mozilla_MacroForEach_h
+
+#include "mozilla/MacroArgs.h"
+
+/*
+ * MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) expands to N calls to the macro
+ * |aMacro| where N is equal the number of items in the list |aArgs|. The
+ * arguments for each |aMacro| call are composed of *all* arguments in the list
+ * |aFixedArgs| as well as a single argument in the list |aArgs|. For example:
+ *
+ *   #define MACRO_A(x) x +
+ *   int a = MOZ_FOR_EACH(MACRO_A, (), (1, 2, 3)) 0;
+ *   // Expands to:     MACRO_A(1) MACRO_A(2) MACRO_A(3) 0;
+ *   // And further to: 1 + 2 + 3 + 0;
+ *
+ *   #define MACRO_B(k, x) (k + x) +
+ *   int b = MOZ_FOR_EACH(MACRO_B, (5,), (1, 2)) 0;
+ *   // Expands to: MACRO_B(5, 1) MACRO_B(5, 2) 0;
+ *
+ *   #define MACRO_C(k1, k2, x) (k1 + k2 + x) +
+ *   int c = MOZ_FOR_EACH(MACRO_C, (5, 8,), (1, 2)) 0;
+ *   // Expands to: MACRO_B(5, 8, 1) MACRO_B(5, 8, 2) 0;
+ *
+ * If the |aFixedArgs| list is not empty, a trailing comma must be included.
+ *
+ * The |aArgs| list must be not be empty and may be up to 50 items long. Use
+ * MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint
+ * results in a compile-time error.
+ */
+#define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__
+#define MOZ_FOR_EACH_GLUE(a, b) a b
+#define MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) \
+  MOZ_FOR_EACH_GLUE( \
+    MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \
+                                   MOZ_FOR_EACH_EXPAND_HELPER aArgs), \
+    (aMacro, aFixedArgs, aArgs))
+
+#define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b
+#define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \
+  MOZ_FOR_EACH_HELPER_GLUE( \
+    aMacro, \
+    (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs))
+
+#define MOZ_FOR_EACH_1(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a)
+#define MOZ_FOR_EACH_2(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_1(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_3(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_2(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_4(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_3(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_5(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_4(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_6(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_5(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_7(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_6(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_8(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_7(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_9(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_8(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_10(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_9(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_11(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_10(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_12(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_11(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_13(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_12(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_14(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_13(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_15(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_14(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_16(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_15(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_17(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_16(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_18(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_17(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_19(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_18(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_20(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_19(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_21(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_20(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_22(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_21(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_23(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_22(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_24(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_23(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_25(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_24(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_26(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_25(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_27(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_26(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_28(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_27(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_29(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_28(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_30(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_29(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_31(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_30(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_32(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_31(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_33(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_32(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_34(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_33(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_35(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_34(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_36(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_35(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_37(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_36(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_38(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_37(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_39(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_38(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_40(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_39(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_41(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_40(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_42(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_41(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_43(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_42(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_44(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_43(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_45(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_44(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_46(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_45(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_47(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_46(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_48(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_47(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_49(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_48(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_50(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_49(m, fa, (MOZ_ARGS_AFTER_1 a))
+
+#endif /* mozilla_MacroForEach_h */
--- a/mfbt/moz.build
+++ b/mfbt/moz.build
@@ -32,16 +32,17 @@ EXPORTS.mozilla = [
     'FloatingPoint.h',
     'GuardObjects.h',
     'HashFunctions.h',
     'IntegerPrintfMacros.h',
     'IntegerTypeTraits.h',
     'Likely.h',
     'LinkedList.h',
     'MacroArgs.h',
+    'MacroForEach.h',
     'MathAlgorithms.h',
     'Maybe.h',
     'MemoryChecking.h',
     'MemoryReporting.h',
     'Move.h',
     'MSIntTypes.h',
     'NullPtr.h',
     'NumericLimits.h',
new file mode 100644
--- /dev/null
+++ b/mfbt/tests/TestMacroForEach.cpp
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/MacroForEach.h"
+
+#define HELPER_IDENTITY_PLUS(x) x +
+static_assert(MOZ_FOR_EACH(HELPER_IDENTITY_PLUS, (), (10)) 0 == 10, "");
+static_assert(MOZ_FOR_EACH(HELPER_IDENTITY_PLUS, (), (1, 1, 1)) 0 == 3, "");
+
+#define HELPER_DEFINE_VAR(x) const int test1_##x = x;
+MOZ_FOR_EACH(HELPER_DEFINE_VAR, (), (10, 20))
+static_assert(test1_10 == 10 && test1_20 == 20, "");
+
+#define HELPER_DEFINE_VAR2(k, x) const int test2_##x = k + x;
+MOZ_FOR_EACH(HELPER_DEFINE_VAR2, (5,), (10, 20))
+static_assert(test2_10 == 15 && test2_20 == 25, "");
+
+#define HELPER_IDENTITY_COMMA(k1, k2, x) k1, k2, x,
+
+int main()
+{
+  const int a[] = { MOZ_FOR_EACH(HELPER_IDENTITY_COMMA, (1, 2,), (10, 20, 30)) };
+  MOZ_RELEASE_ASSERT(a[0] == 1 && a[1] == 2 && a[2] == 10 &&
+                     a[3] == 1 && a[4] == 2 && a[5] == 20 &&
+                     a[6] == 1 && a[7] == 2 && a[8] == 30,
+                     "MOZ_FOR_EACH args enumerated in incorrect order");
+}
--- a/mfbt/tests/moz.build
+++ b/mfbt/tests/moz.build
@@ -13,16 +13,17 @@ CPP_UNIT_TESTS += [
     'TestCheckedInt.cpp',
     'TestCountPopulation.cpp',
     'TestCountZeroes.cpp',
     'TestEndian.cpp',
     'TestEnumSet.cpp',
     'TestFloatingPoint.cpp',
     'TestIntegerPrintfMacros.cpp',
     'TestMacroArgs.cpp',
+    'TestMacroForEach.cpp',
     'TestRollingMean.cpp',
     'TestSHA1.cpp',
     'TestTypedEnum.cpp',
     'TestTypeTraits.cpp',
     'TestWeakPtr.cpp',
 ]
 
 if not CONFIG['MOZ_ASAN']: