From: "Marek Behún" <kabel@kernel.org>
To: netdev@vger.kernel.org, Russell King <rmk+kernel@armlinux.org.uk>
Cc: "David S . Miller" <davem@davemloft.net>,
"Florian Fainelli" <f.fainelli@gmail.com>,
"Heiner Kallweit" <hkallweit1@gmail.com>,
kuba@kernel.org, "Marek Behún" <kabel@kernel.org>
Subject: [PATCH net-next v3 08/18] include: add library helpers for variadic macro expansion
Date: Wed, 7 Apr 2021 00:10:57 +0200 [thread overview]
Message-ID: <20210406221107.1004-9-kabel@kernel.org> (raw)
In-Reply-To: <20210406221107.1004-1-kabel@kernel.org>
Add a library with useful helpers to expand variadic macros.
We have the macro DECLARE_BITMAP(name, bits), but no way of compile-time
initialization of such bitmaps. Since C does not support consteval
functions, this can only be done via macros.
This macro library can be (among other things) used to implement a sane
way for compile-time bitmap initialization, something like
static DECLARE_BITMAP(bm, 100) = INITIALIZE_BITMAP(100, 7, 9, 66, 98);
Signed-off-by: Marek Behún <kabel@kernel.org>
---
include/linux/variadic-macro.h | 221 +++++++++++++++++++++++++++++++++
1 file changed, 221 insertions(+)
create mode 100644 include/linux/variadic-macro.h
diff --git a/include/linux/variadic-macro.h b/include/linux/variadic-macro.h
new file mode 100644
index 000000000000..5b21a66884e4
--- /dev/null
+++ b/include/linux/variadic-macro.h
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Helpers for expanding variadic macros in useful ways
+ *
+ * 2021 by Marek Behún <kabel@kernel.org>
+ */
+
+#ifndef __VARIADIC_MACRO_H__
+#define __VARIADIC_MACRO_H__
+
+/*
+ * Helpers for variadic macros with up to 32 arguments.
+ * Pretty simple to extend.
+ */
+
+#define _VM_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
+ _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, \
+ _27, _28, _29, _30, _31, _32, N, ...) N
+
+#define _VM_HELP_0(_f, _d, ...)
+#define _VM_HELP_1(_f, _d, x, ...) _f(x, _d)
+#define _VM_HELP_2(_f, _d, x, ...) _f(x, _d) _VM_HELP_1(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_3(_f, _d, x, ...) _f(x, _d) _VM_HELP_2(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_4(_f, _d, x, ...) _f(x, _d) _VM_HELP_3(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_5(_f, _d, x, ...) _f(x, _d) _VM_HELP_4(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_6(_f, _d, x, ...) _f(x, _d) _VM_HELP_5(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_7(_f, _d, x, ...) _f(x, _d) _VM_HELP_6(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_8(_f, _d, x, ...) _f(x, _d) _VM_HELP_7(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_9(_f, _d, x, ...) _f(x, _d) _VM_HELP_8(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_10(_f, _d, x, ...) _f(x, _d) _VM_HELP_9(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_11(_f, _d, x, ...) _f(x, _d) _VM_HELP_10(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_12(_f, _d, x, ...) _f(x, _d) _VM_HELP_11(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_13(_f, _d, x, ...) _f(x, _d) _VM_HELP_12(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_14(_f, _d, x, ...) _f(x, _d) _VM_HELP_13(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_15(_f, _d, x, ...) _f(x, _d) _VM_HELP_14(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_16(_f, _d, x, ...) _f(x, _d) _VM_HELP_15(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_17(_f, _d, x, ...) _f(x, _d) _VM_HELP_16(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_18(_f, _d, x, ...) _f(x, _d) _VM_HELP_17(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_19(_f, _d, x, ...) _f(x, _d) _VM_HELP_18(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_20(_f, _d, x, ...) _f(x, _d) _VM_HELP_19(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_21(_f, _d, x, ...) _f(x, _d) _VM_HELP_20(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_22(_f, _d, x, ...) _f(x, _d) _VM_HELP_21(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_23(_f, _d, x, ...) _f(x, _d) _VM_HELP_22(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_24(_f, _d, x, ...) _f(x, _d) _VM_HELP_23(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_25(_f, _d, x, ...) _f(x, _d) _VM_HELP_24(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_26(_f, _d, x, ...) _f(x, _d) _VM_HELP_25(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_27(_f, _d, x, ...) _f(x, _d) _VM_HELP_26(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_28(_f, _d, x, ...) _f(x, _d) _VM_HELP_27(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_29(_f, _d, x, ...) _f(x, _d) _VM_HELP_28(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_30(_f, _d, x, ...) _f(x, _d) _VM_HELP_29(_f, _d, ##__VA_ARGS__)
+#define _VM_HELP_31(_f, _d, x, ...) _f(x, _d) _VM_HELP_30(_f, _d, ##__VA_ARGS__)
+
+/*
+ * EXPAND_FOR_EACH(_functor, _data, args...) - expand a call to functor for
+ * each argument
+ * @_functor: name of the functor to expand a call to
+ * @_data: private data to apply to the functor
+ * @args...: for each of these arguments a call to functor will be expanded
+ *
+ * This macro will expand to a call to _functor(arg, _data) for all arguments
+ * after the _data argument, i.e.
+ * EXPAND_FOR_EACH(f, d, 1, 2, 3)
+ * will expand to
+ * f(1, d) f(2, d) f(3, d)
+ *
+ * ATTENTION: the functor cannot call EXPAND_FOR_EACH again.
+ * For recursive calls to EXPAND_FOR_EACH to be allowed, use EXPAND_FOR_EACH_R
+ * together with EXPAND_EVAL.
+ * Or you can call EXPAND_FOR_EACH in the functor for EXPAND_FOR_EACH_PASS_ARGS.
+ *
+ * Example:
+ *
+ * ::
+ *
+ * #define __BIT_OR(x, dummy) | BIT(x)
+ * #define BIT_OR(...) (0 EXPAND_FOR_EACH(__BIT_OR, dummy, ##__VA_ARGS__))
+ *
+ * int x = BIT_OR(1, 7, 9, 13);
+ * assert(x == (BIT(1) | BIT(7) | BIT(9) | BIT(13)));
+ */
+#define EXPAND_FOR_EACH(_functor, _data, ...) \
+ _VM_GET_NTH_ARG("", ##__VA_ARGS__, _VM_HELP_31, _VM_HELP_30, \
+ _VM_HELP_29, _VM_HELP_28, _VM_HELP_27, _VM_HELP_26, _VM_HELP_25, \
+ _VM_HELP_24, _VM_HELP_23, _VM_HELP_22, _VM_HELP_21, _VM_HELP_20, \
+ _VM_HELP_19, _VM_HELP_18, _VM_HELP_17, _VM_HELP_16, _VM_HELP_15, \
+ _VM_HELP_14, _VM_HELP_13, _VM_HELP_12, _VM_HELP_11, _VM_HELP_10, \
+ _VM_HELP_9, _VM_HELP_8, _VM_HELP_7, _VM_HELP_6, _VM_HELP_5, \
+ _VM_HELP_4, _VM_HELP_3, _VM_HELP_2, _VM_HELP_1, \
+ _VM_HELP_0)(_functor, _data, ##__VA_ARGS__)
+
+/*
+ * Black magic to prevent macros from creating disabling contexts
+ */
+#define _VM_EMPTY(...)
+#define _VM_DEFER(...) __VA_ARGS__ _VM_EMPTY()
+
+#define EXPAND_EVAL(...) _VM_EVAL1(_VM_EVAL1(_VM_EVAL1(__VA_ARGS__)))
+#define _VM_EVAL1(...) _VM_EVAL2(_VM_EVAL2(_VM_EVAL2(__VA_ARGS__)))
+#define _VM_EVAL2(...) _VM_EVAL3(_VM_EVAL3(_VM_EVAL3(__VA_ARGS__)))
+#define _VM_EVAL3(...) __VA_ARGS__
+
+#define _VM_APPLY(x, _functor, _data, ...) _functor(x, _data, ##__VA_ARGS__)
+#define _VM_APPLY_INDIRECT() _VM_APPLY
+#define _VM_APPLY_HELPER(x, __args) \
+ _VM_DEFER(_VM_APPLY_INDIRECT)()(x, _VM_DEFER __args)
+
+#define _VM_EXPAND_FOR_EACH_INDIRECT() EXPAND_FOR_EACH
+
+/*
+ * EXPAND_FOR_EACH_R(_functor, _data, args...) - expand a call to functor for
+ * each argument, recursive calls
+ * allowed
+ * @_functor: name of the functor to expand a call to
+ * @_data: private data to apply to the functor
+ * @args...: for each of these arguments a call to functor will be expanded
+ *
+ * Does the same as EXPAND_FOR_EACH(_functor, _data, args...), but _functor is
+ * allowed to call EXPAND_FOR_EACH_R again.
+ *
+ * ATTENTION: in order for this to work, the outermost call to this macro must
+ * be wrapped inside the EXPAND_EVAL macro.
+ *
+ * Example:
+ *
+ * ::
+ *
+ * #define EXP_3(y, x) x ## y
+ * #define EXP_2(x, ...) EXPAND_FOR_EACH_R(EXP_3, x, ##__VA_ARGS__)
+ * #define EXP_1(x, dummy) EXP_2(x, 1, 2, 3)
+ * #define EXP(...) EXPAND_EVAL(EXPAND_FOR_EACH_R(EXP_1, dummy, ##__VA_ARGS__))
+ *
+ * EXP(a, b, c)
+ * // expands to: a1 a2 a3 b1 b2 b3 c1 c2 c3
+ */
+#define EXPAND_FOR_EACH_R _VM_DEFER(_VM_EXPAND_FOR_EACH_INDIRECT)()
+
+#define _VM_EXPAND_FOR_EACH_PASS_ARGS(_functor, _data, ...) \
+ _VM_DEFER(_VM_EXPAND_FOR_EACH_INDIRECT)()(_VM_APPLY_HELPER, \
+ (_functor, _data, ##__VA_ARGS__), ##__VA_ARGS__)
+
+/*
+ * EXPAND_FOR_EACH_PASS_ARGS(_functor, _data, args...) -
+ * expand a call to functor for each argument, pass all arguments to each call
+ * @_functor: name of the functor to expand a call to
+ * @_data: private data to apply to the functor
+ * @args...: for each of these arguments a call to functor will be expanded
+ *
+ * For each argument after the _data argument, a call to
+ * _functor(arg, _data, args...) will be expanded.
+ * This is similar to EXPAND_FOR_EACH, but each expanded call will also be
+ * passed all the original arguments, i.e.
+ * EXPAND_FOR_EACH_PASS_ARGS(f, d, 1, 2, 3)
+ * will expand to
+ * f(1, d, 1, 2, 3) f(2, d, 1, 2, 3) f(3, d, 1, 2, 3)
+ *
+ * This is useful when one needs to call EXPAND_FOR_EACH in the functor again,
+ * to expand all the arguments in some way for each argument.
+ *
+ * ATTENTION: the functor cannot call EXPAND_FOR_EACH_PASS_ARGS again.
+ * For recursive calls to EXPAND_FOR_EACH_PASS_ARGS to be allowed, use
+ * EXPAND_FOR_EACH_PASS_ARGS_R together with EXPAND_EVAL.
+ *
+ * Example (a mechanism to compile time bitmap initialization):
+ *
+ * ::
+ *
+ * #define __BIT_OR(x, dummy) | BIT(x)
+ * #define BIT_OR(...) (0 EXPAND_FOR_EACH(__BIT_OR, dummy, ##__VA_ARGS__))
+ * #define BM_MEMB(bit) ((bit) / BITS_PER_LONG)
+ * #define BM_OR(bit, member) \
+ * | (BM_MEMB(bit) == member ? BIT((bit) % BITS_PER_LONG) : 0)
+ * #define INIT_BITMAP_MEMBER(bit, dummy, ...) \
+ * [BM_MEMB(bit)] = (0 EXPAND_FOR_EACH(BM_OR, BM_MEMB(bit), ##__VA_ARGS__)),
+ * #define INIT_BITMAP(...) \
+ * { \
+ * EXPAND_FOR_EACH_PASS_ARGS(INIT_BITMAP_MEMBER, dummy, ##__VA_ARGS__) \
+ * }
+ *
+ * static const DECLARE_BITMAP(bm, 90) =
+ * INIT_BITMAP(1, 2, 15, 32, 36, 80);
+ */
+#define EXPAND_FOR_EACH_PASS_ARGS(_functor, _data, ...) \
+ EXPAND_EVAL(_VM_EXPAND_FOR_EACH_PASS_ARGS(_functor, \
+ _data, ##__VA_ARGS__))
+
+#define _VM_EXPAND_FOR_EACH_PASS_ARGS_INDIRECT() _VM_EXPAND_FOR_EACH_PASS_ARGS
+
+/*
+ * EXPAND_FOR_EACH_PASS_ARGS_R(_functor, _data, args...) -
+ * expand a call to functor for each argument, pass all arguments to each
+ * call, recursive calls allowed
+ * @_functor: name of the functor to expand a call to
+ * @_data: private data to apply to the functor
+ * @args...: for each of these arguments a call to functor will be expanded
+ *
+ * Does the same as EXPAND_FOR_EACH_PASS_ARGS(_functor, _data, args...), but
+ * _functor is allowed to call EXPAND_FOR_EACH_PASS_ARGS_R again.
+ *
+ * ATTENTION: in order for this to work, the outermost call to this macro must
+ * be wrapped inside the EXPAND_EVAL macro.
+ *
+ * Example:
+ *
+ * ::
+ *
+ * #define EXP_4(xy, z) z ## xy
+ * #define EXP_3(y, x, ...) EXPAND_FOR_EACH(EXP_4, x ## y, ##__VA_ARGS__)
+ * #define EXP_2(x, ...) EXPAND_FOR_EACH_PASS_ARGS_R(EXP_3, x, ##__VA_ARGS__)
+ * #define EXP_1(x, dummy, ...) EXP_2(x, __VA_ARGS__)
+ * #define EXP(...) \
+ * EXPAND_EVAL(EXPAND_FOR_EACH_PASS_ARGS_R(EXP_1, dummy, ##__VA_ARGS__))
+ *
+ * EXP(a, b, c)
+ * // expands to: aaa aab aac aba abb abc aca acb acc
+ * // baa bab bac bba bbb bbc bca bcb bcc
+ * // caa cab cac cba cbb cbc cca ccb ccc
+ */
+#define EXPAND_FOR_EACH_PASS_ARGS_R \
+ _VM_DEFER(_VM_EXPAND_FOR_EACH_PASS_ARGS_INDIRECT)()
+
+#endif /* __VARIADIC_MACRO_H__ */
--
2.26.2
next prev parent reply other threads:[~2021-04-06 22:12 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-04-06 22:10 [PATCH net-next v3 00/18] net: phy: marvell10g updates Marek Behún
2021-04-06 22:10 ` [PATCH net-next v3 01/18] net: phy: marvell10g: rename register Marek Behún
2021-04-06 22:37 ` Andrew Lunn
2021-04-06 22:10 ` [PATCH net-next v3 02/18] net: phy: marvell10g: fix typo Marek Behún
2021-04-06 22:38 ` Andrew Lunn
2021-04-06 22:10 ` [PATCH net-next v3 03/18] net: phy: marvell10g: allow 5gbase-r and usxgmii Marek Behún
2021-04-06 22:39 ` Andrew Lunn
2021-04-06 22:10 ` [PATCH net-next v3 04/18] net: phy: marvell10g: indicate 88X33x0 only port control registers Marek Behún
2021-04-07 0:10 ` Andrew Lunn
2021-04-07 0:22 ` Marek Behún
2021-04-06 22:10 ` [PATCH net-next v3 05/18] net: phy: marvell10g: add all MACTYPE definitions for 88X33x0 Marek Behún
2021-04-06 23:22 ` Andrew Lunn
2021-04-06 22:10 ` [PATCH net-next v3 06/18] net: phy: marvell10g: add MACTYPE definitions for 88E21xx Marek Behún
2021-04-06 23:22 ` Andrew Lunn
2021-04-06 22:10 ` [PATCH net-next v3 07/18] net: phy: marvell10g: support all rate matching modes Marek Behún
2021-04-06 23:30 ` Andrew Lunn
2021-04-06 23:36 ` Marek Behún
2021-04-06 23:33 ` Andrew Lunn
2021-04-06 23:53 ` Marek Behún
2021-04-06 22:10 ` Marek Behún [this message]
2021-04-06 22:10 ` [PATCH net-next v3 09/18] include: bitmap: add macro for bitmap initialization Marek Behún
2021-04-06 23:38 ` Andrew Lunn
2021-04-06 23:50 ` Marek Behún
2021-04-06 22:10 ` [PATCH net-next v3 10/18] net: phy: marvell10g: check for correct supported interface mode Marek Behún
2021-04-06 23:40 ` Andrew Lunn
2021-04-07 9:04 ` kernel test robot
2021-04-06 22:11 ` [PATCH net-next v3 11/18] net: phy: marvell10g: store temperature read method in chip strucutre Marek Behún
2021-04-06 23:42 ` Andrew Lunn
2021-04-06 22:11 ` [PATCH net-next v3 12/18] net: phy: marvell10g: support other MACTYPEs Marek Behún
2021-04-06 22:11 ` [PATCH net-next v3 13/18] net: phy: marvell10g: add separate structure for 88X3340 Marek Behún
2021-04-06 23:47 ` Andrew Lunn
2021-04-06 22:11 ` [PATCH net-next v3 14/18] net: phy: marvell10g: fix driver name for mv88e2110 Marek Behún
2021-04-06 23:49 ` Andrew Lunn
2021-04-06 22:11 ` [PATCH net-next v3 15/18] net: phy: add constants for 2.5G and 5G speed in PCS speed register Marek Behún
2021-04-06 23:59 ` Andrew Lunn
2021-04-06 22:11 ` [PATCH net-next v3 16/18] net: phy: marvell10g: differentiate 88E2110 vs 88E2111 Marek Behún
2021-04-07 0:01 ` Andrew Lunn
2021-04-06 22:11 ` [PATCH net-next v3 17/18] net: phy: marvell10g: change module description Marek Behún
2021-04-07 0:01 ` Andrew Lunn
2021-04-06 22:11 ` [PATCH net-next v3 18/18] MAINTAINERS: add myself as maintainer of marvell10g driver Marek Behún
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210406221107.1004-9-kabel@kernel.org \
--to=kabel@kernel.org \
--cc=davem@davemloft.net \
--cc=f.fainelli@gmail.com \
--cc=hkallweit1@gmail.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=rmk+kernel@armlinux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.