summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libmisc/include/libmisc/macro.h41
1 files changed, 40 insertions, 1 deletions
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h
index 9bb068f..d11b99f 100644
--- a/libmisc/include/libmisc/macro.h
+++ b/libmisc/include/libmisc/macro.h
@@ -1,6 +1,6 @@
/* libmisc/macro.h - Useful C preprocessor macros
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -36,6 +36,7 @@
/* macro arguments */
+#define LM_FIRST(a, ...) a
#define LM_SECOND(a, b, ...) b
#define LM_EAT(...)
#define LM_EXPAND(...) __VA_ARGS__
@@ -52,4 +53,42 @@
#define _LM_IF__xxTxx(...) __VA_ARGS__ LM_EAT
#define _LM_IF__xxFxx(...) LM_EXPAND
+/* tuples */
+
+#define LM_IS_TUPLE(x) LM_IS_SENTINEL(_LM_IS_TUPLE x)
+#define _LM_IS_TUPLE(...) LM_SENTINEL()
+
+/* `tuples` is a sequence of `(tuple1)(tuple2)(tuple3)` */
+#define _LM_TUPLES_COMMA(tuple...) (tuple),
+#define LM_TUPLES_NONEMPTY(tuples) LM_IS_TUPLE(_LM_TUPLES_COMMA tuples)
+#define LM_TUPLES_HEAD(tuples) LM_EXPAND(LM_FIRST LM_EAT() (_LM_TUPLES_COMMA tuples))
+#define LM_TUPLES_TAIL(tuples) LM_EAT tuples
+
+/* iteration */
+
+/* BUG: LM_FOREACH_TUPLE maxes out at 1024 tuples. */
+#define LM_FOREACH_TUPLE(tuples, func, ...) \
+ _LM_EVAL(_LM_FOREACH_TUPLE(tuples, func, __VA_ARGS__))
+#define _LM_FOREACH_TUPLE(tuples, func, ...) \
+ LM_IF(LM_TUPLES_NONEMPTY(tuples))( \
+ _LM_DEFER2(func)(__VA_ARGS__ __VA_OPT__(,) LM_EXPAND LM_TUPLES_HEAD(tuples)) \
+ _LM_DEFER2(_LM_FOREACH_TUPLE_indirect)()(LM_TUPLES_TAIL(tuples), func, __VA_ARGS__) \
+ )()
+#define _LM_FOREACH_TUPLE_indirect() _LM_FOREACH_TUPLE
+
+#define _LM_DEFER2(macro) macro LM_EAT LM_EAT()()
+
+#define _LM_EVAL(...) _LM_EVAL__1024(__VA_ARGS__) /* 1024 iterations aught to be enough for anybody */
+#define _LM_EVAL__1024(...) _LM_EVAL__512(_LM_EVAL__512(__VA_ARGS__))
+#define _LM_EVAL__512(...) _LM_EVAL__256(_LM_EVAL__256(__VA_ARGS__))
+#define _LM_EVAL__256(...) _LM_EVAL__128(_LM_EVAL__128(__VA_ARGS__))
+#define _LM_EVAL__128(...) _LM_EVAL__64(_LM_EVAL__64(__VA_ARGS__))
+#define _LM_EVAL__64(...) _LM_EVAL__32(_LM_EVAL__32(__VA_ARGS__))
+#define _LM_EVAL__32(...) _LM_EVAL__16(_LM_EVAL__16(__VA_ARGS__))
+#define _LM_EVAL__16(...) _LM_EVAL__8(_LM_EVAL__8(__VA_ARGS__))
+#define _LM_EVAL__8(...) _LM_EVAL__4(_LM_EVAL__4(__VA_ARGS__))
+#define _LM_EVAL__4(...) _LM_EVAL__2(_LM_EVAL__2(__VA_ARGS__))
+#define _LM_EVAL__2(...) _LM_EVAL__1(_LM_EVAL__1(__VA_ARGS__))
+#define _LM_EVAL__1(...) __VA_ARGS__
+
#endif /* _LIBMISC_MACRO_H_ */