Replace the dummy arg from compound initializers in the C API with more macro magic (#4696)

The dummy argument {fmt_int} was there as a workaround for MSVC and to
avoid needing to rely on another GCC extension for zero-size arrays. Use
macro magic similar to FMT_NARG() instead that replaces the problematic
zero-size array with NULL.

In order to avoid a quadratic number of expansions, defer creating the
mapped argument list until after selection of whether to use NULL or
the fmt_arg array.

Signed-off-by: Ferdinand Bachmann <ferdinand.bachmann@yrlf.at>
This commit is contained in:
Ferdinand Bachmann 2026-03-07 16:55:51 +01:00 committed by GitHub
parent ab4f661521
commit eb03303099
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -130,7 +130,7 @@ typedef enum {} fmt_signed_char;
# define FMT_NARG_(_id, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16, N, ...) \
N
# define FMT_NARG(...) \
# define FMT_NARG(_dummy, ...) \
FMT_NARG_(dummy, ##__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, \
4, 3, 2, 1, 0)
@ -166,13 +166,24 @@ typedef enum {} fmt_signed_char;
f(n), f(o), f(p), f(q)
# define FMT_MAP(f, ...) \
FMT_CAT(FMT_MAP_, FMT_NARG(__VA_ARGS__))(f, ##__VA_ARGS__)
FMT_CAT(FMT_MAP_, FMT_NARG(, ##__VA_ARGS__))(f, ##__VA_ARGS__)
// select between two expressions depending on whether __VA_ARGS__ is empty
// expands to e if __VA_ARGS__ is empty and n otherwise
# define FMT_VA_SELECT(e, n, ...) \
FMT_NARG_(dummy, ##__VA_ARGS__, n, n, n, n, n, n, n, n, n, n, n, n, n, n, \
n, n, e)
# define FMT_MAKE_NULL(...) NULL
# define FMT_MAKE_ARGLIST(...) \
(fmt_arg[]) { FMT_MAP(FMT_MAKE_ARG, ##__VA_ARGS__) }
# define FMT_EXPAND(v) v
# define fmt_format(buffer, size, fmt, ...) \
fmt_vformat( \
(buffer), (size), (fmt), \
(fmt_arg[]){{fmt_int}, FMT_MAP(FMT_MAKE_ARG, ##__VA_ARGS__)} + 1, \
FMT_NARG(__VA_ARGS__))
fmt_vformat((buffer), (size), (fmt), \
FMT_EXPAND(FMT_VA_SELECT(FMT_MAKE_NULL, FMT_MAKE_ARGLIST, \
##__VA_ARGS__)(__VA_ARGS__)), \
FMT_NARG(, ##__VA_ARGS__))
#endif // __cplusplus