Skip to content

Commit dc86bd2

Browse files
committed
include/nuttx/macro.h: Add FOREACH_IDX_ARG() and fix REVERSE_ARG()
FOREACH_ARG() passes the argument index as an expression (count - N), which cannot be pasted into an identifier. FOREACH_IDX_ARG() passes it as a two digit literal (00, 01, ...), so the index can become part of a symbol name and, through SORT_BY_NAME(), part of the order the linker gives to the objects registered with the iterable sections. It dispatches with CONCATENATE() and GET_ARG_COUNT(), reverses the list with REVERSE_ARG() so that each arity emits its own literal, and expands to nothing for an empty list. REVERSE_ARG() had to be fixed first. It expanded to REVERSE_ARG_(##__VA_ARGS__), and because the token before the ## is "(" rather than a comma, the preprocessor pastes it with the first argument and fails with "pasting "(" and "x" does not give a valid preprocessing token". Dropping the ## expands the arguments as intended and leaves the empty case unchanged. The iterable sections documentation already said that an instance may encode its order in its name; point it at the new macro, which is the way to do that. Assisted-by: Claude Code Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
1 parent 0c88b8f commit dc86bd2

2 files changed

Lines changed: 62 additions & 3 deletions

File tree

Documentation/components/iterable_sections.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ Available macros:
5858
* ``STRUCT_SECTION_ITERABLE(type, varname)`` -- define an instance inside
5959
the iterable section ``._<type>.static.<varname>``. The variable name
6060
is part of the input section name, so the linker's ``SORT_BY_NAME()``
61-
defines the iteration order (instances may encode ordering in their
62-
names).
61+
defines the iteration order. A subsystem that needs a specific order
62+
encodes it in the name, usually with a fixed width index:
63+
``FOREACH_IDX_ARG()`` from ``nuttx/macro.h`` hands the position of each
64+
item to the definition macro as a two digit literal for that purpose.
6365
* ``STRUCT_SECTION_DECLARE(type)`` -- declare the boundary symbols (file
6466
scope), required before iterating.
6567
* ``STRUCT_SECTION_FOREACH(type, iterator)`` -- for-loop over all

include/nuttx/macro.h

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
REVERSE_08, REVERSE_07, REVERSE_06, REVERSE_05, REVERSE_04, REVERSE_03, \
100100
REVERSE_02, REVERSE_01, REVERSE_00)(__VA_ARGS__)
101101

102-
#define REVERSE_ARG(...) REVERSE_ARG_(##__VA_ARGS__)
102+
#define REVERSE_ARG(...) REVERSE_ARG_(__VA_ARGS__)
103103

104104
/* Apply the macro to each argument */
105105

@@ -149,4 +149,61 @@
149149
#define FOREACH_ARG(action, param, ...) \
150150
FOREACH_ARG_(action, GET_ARG_COUNT(__VA_ARGS__), param, ##__VA_ARGS__)
151151

152+
/* Apply the macro to each argument, passing the position of the argument
153+
* as a two digit literal (00, 01, 02, ...) rather than as an expression.
154+
* Use it when the index has to be pasted into an identifier, for instance
155+
* to build a symbol name the linker can sort. The arguments are reversed
156+
* before the expansion, so the actions are emitted from the last argument
157+
* to the first while the indexes still follow the original order, which is
158+
* transparent for the declarations this form is meant to generate.
159+
*/
160+
161+
#define FOREACH_IDX_0(action, param, ...)
162+
#define FOREACH_IDX_1(action, param, arg, ...) action(param, arg, 00)
163+
#define FOREACH_IDX_2(action, param, arg, ...) action(param, arg, 01) FOREACH_IDX_1(action, param, __VA_ARGS__)
164+
#define FOREACH_IDX_3(action, param, arg, ...) action(param, arg, 02) FOREACH_IDX_2(action, param, __VA_ARGS__)
165+
#define FOREACH_IDX_4(action, param, arg, ...) action(param, arg, 03) FOREACH_IDX_3(action, param, __VA_ARGS__)
166+
#define FOREACH_IDX_5(action, param, arg, ...) action(param, arg, 04) FOREACH_IDX_4(action, param, __VA_ARGS__)
167+
#define FOREACH_IDX_6(action, param, arg, ...) action(param, arg, 05) FOREACH_IDX_5(action, param, __VA_ARGS__)
168+
#define FOREACH_IDX_7(action, param, arg, ...) action(param, arg, 06) FOREACH_IDX_6(action, param, __VA_ARGS__)
169+
#define FOREACH_IDX_8(action, param, arg, ...) action(param, arg, 07) FOREACH_IDX_7(action, param, __VA_ARGS__)
170+
#define FOREACH_IDX_9(action, param, arg, ...) action(param, arg, 08) FOREACH_IDX_8(action, param, __VA_ARGS__)
171+
#define FOREACH_IDX_10(action, param, arg, ...) action(param, arg, 09) FOREACH_IDX_9(action, param, __VA_ARGS__)
172+
#define FOREACH_IDX_11(action, param, arg, ...) action(param, arg, 10) FOREACH_IDX_10(action, param, __VA_ARGS__)
173+
#define FOREACH_IDX_12(action, param, arg, ...) action(param, arg, 11) FOREACH_IDX_11(action, param, __VA_ARGS__)
174+
#define FOREACH_IDX_13(action, param, arg, ...) action(param, arg, 12) FOREACH_IDX_12(action, param, __VA_ARGS__)
175+
#define FOREACH_IDX_14(action, param, arg, ...) action(param, arg, 13) FOREACH_IDX_13(action, param, __VA_ARGS__)
176+
#define FOREACH_IDX_15(action, param, arg, ...) action(param, arg, 14) FOREACH_IDX_14(action, param, __VA_ARGS__)
177+
#define FOREACH_IDX_16(action, param, arg, ...) action(param, arg, 15) FOREACH_IDX_15(action, param, __VA_ARGS__)
178+
#define FOREACH_IDX_17(action, param, arg, ...) action(param, arg, 16) FOREACH_IDX_16(action, param, __VA_ARGS__)
179+
#define FOREACH_IDX_18(action, param, arg, ...) action(param, arg, 17) FOREACH_IDX_17(action, param, __VA_ARGS__)
180+
#define FOREACH_IDX_19(action, param, arg, ...) action(param, arg, 18) FOREACH_IDX_18(action, param, __VA_ARGS__)
181+
#define FOREACH_IDX_20(action, param, arg, ...) action(param, arg, 19) FOREACH_IDX_19(action, param, __VA_ARGS__)
182+
#define FOREACH_IDX_21(action, param, arg, ...) action(param, arg, 20) FOREACH_IDX_20(action, param, __VA_ARGS__)
183+
#define FOREACH_IDX_22(action, param, arg, ...) action(param, arg, 21) FOREACH_IDX_21(action, param, __VA_ARGS__)
184+
#define FOREACH_IDX_23(action, param, arg, ...) action(param, arg, 22) FOREACH_IDX_22(action, param, __VA_ARGS__)
185+
#define FOREACH_IDX_24(action, param, arg, ...) action(param, arg, 23) FOREACH_IDX_23(action, param, __VA_ARGS__)
186+
#define FOREACH_IDX_25(action, param, arg, ...) action(param, arg, 24) FOREACH_IDX_24(action, param, __VA_ARGS__)
187+
#define FOREACH_IDX_26(action, param, arg, ...) action(param, arg, 25) FOREACH_IDX_25(action, param, __VA_ARGS__)
188+
#define FOREACH_IDX_27(action, param, arg, ...) action(param, arg, 26) FOREACH_IDX_26(action, param, __VA_ARGS__)
189+
#define FOREACH_IDX_28(action, param, arg, ...) action(param, arg, 27) FOREACH_IDX_27(action, param, __VA_ARGS__)
190+
#define FOREACH_IDX_29(action, param, arg, ...) action(param, arg, 28) FOREACH_IDX_28(action, param, __VA_ARGS__)
191+
#define FOREACH_IDX_30(action, param, arg, ...) action(param, arg, 29) FOREACH_IDX_29(action, param, __VA_ARGS__)
192+
#define FOREACH_IDX_31(action, param, arg, ...) action(param, arg, 30) FOREACH_IDX_30(action, param, __VA_ARGS__)
193+
#define FOREACH_IDX_32(action, param, arg, ...) action(param, arg, 31) FOREACH_IDX_31(action, param, __VA_ARGS__)
194+
195+
/* The reversed list has to be expanded before the arguments are counted,
196+
* hence the extra indirection: a macro counts the tokens it receives, not
197+
* what they expand to.
198+
*/
199+
200+
#define FOREACH_IDX_ARG__(action, param, ...) \
201+
CONCATENATE(FOREACH_IDX_, GET_ARG_COUNT(__VA_ARGS__)) \
202+
(action, param, __VA_ARGS__)
203+
204+
#define FOREACH_IDX_ARG_(...) FOREACH_IDX_ARG__(__VA_ARGS__)
205+
206+
#define FOREACH_IDX_ARG(action, param, ...) \
207+
FOREACH_IDX_ARG_(action, param, REVERSE_ARG(__VA_ARGS__))
208+
152209
#endif /* __INCLUDE_NUTTX_MACRO_H */

0 commit comments

Comments
 (0)