mirror of
https://github.com/nlohmann/json.git
synced 2026-10-03 05:00:30 +00:00
Extend tools/macro_builder to also generate DOUBLE_PASTE and TYPE_BODY
tools/macro_builder only emitted NLOHMANN_JSON_EXPAND..PASTE64, so two other tables that scale with the same max_args stayed hand-maintained with nothing checking them: NLOHMANN_JSON_DOUBLE_PASTE (added by hand in #4563 for the *_WITH_NAMES macros) and the 64-slot dispatch table of NLOHMANN_JSON_TYPE_BODY (the #4041 zero-member/one-or-more-member switch). Both tables pass one macro name per slot to the same NLOHMANN_JSON_GET_MACRO dispatch as PASTE, so they can drift out of sync with max_args exactly the way _dp did in the ABI tag list fixed by #5544. Extend main.cpp with build_double_paste_code() (same recursive-doubling shape as build_paste_code(), but DOUBLE_PASTE consumes two arguments per member, so an even slot index falls back to the next lower odd DOUBLE_PASTE<N>) and build_type_body_table() (max_args - 1 MEMBERS slots and one trailing EMPTY slot, 8 per line, matching how it is written by hand today). Add a "type_body" argument that selects the TYPE_BODY block, since it lives at a separate location in macro_scope.hpp from the EXPAND..DOUBLE_PASTE63 block; plain invocation is unchanged apart from covering the extended range. No longer emit the tool's old trailing blank line, so its output is directly diffable without post-processing. Verified with c++ -std=c++11: running the tool (with and without "type_body") and piping the raw output through the pinned astyle reproduces both blocks of the current macro_scope.hpp byte for byte. tests/src/unit-udt_macro.cpp (all NLOHMANN_DEFINE_TYPE_*/_WITH_NAMES/ zero-member variants) passes unchanged under -std=c++11 and -std=c++17 with -fsanitize=address,undefined. Add a "macro_builder_check" Makefile target that builds main.cpp, regenerates both blocks into a scratch directory inside the repository (astyle's --project lookup needs the target files under the same tree as .astylerc, unlike an external /tmp directory), and diffs them against the corresponding ranges of macro_scope.hpp; wire it into check-amalgamation next to the natvis check. Wire the same regeneration into check_amalgamation.yml, splicing the (still unindented) generated blocks back into the PR's own macro_scope.hpp before the existing astyle/amalgamation step runs, so that step's own tree-wide astyle pass both indents them and folds any drift into the amalgamation patch/diff the workflow already produces. Unlike amalgamate.py and generate_natvis.py, this step builds tools/macro_builder/main.cpp from the pull request's own checkout ($MAIN_DIR) rather than a separate checkout of tools/ at develop: this tool has no independent source of truth to regenerate against (its README documents that it must reproduce macro_scope.hpp byte for byte), so a develop-pinned copy would only reproduce the generate_natvis.py trap fixed in a previous commit on this branch, where a PR that teaches the tool to cover more of the file fails its own CI until that PR merges and updates the develop copy. Add tools/macro_builder/README.md documentation for both new tables and the two-invocation usage, and a short pointer comment above NLOHMANN_JSON_TYPE_BODY (the EXPAND pointer already covered the first block; extended its wording to include DOUBLE_PASTE63). Closes #5717 item 5 in full, completing what the documentation-only "Document tools/macro_builder..." commit already on this branch left open (that commit's README/pointer-comment half stands; it also covers item 7). Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -65,6 +65,45 @@ jobs:
|
||||
- name: Install generate_natvis dependencies
|
||||
run: pip3 install -r $NATVIS_TOOL_DIR/requirements.txt
|
||||
|
||||
- name: Regenerate the tools/macro_builder tables in macro_scope.hpp
|
||||
run: |
|
||||
cd $MAIN_DIR
|
||||
|
||||
# Built from this PR's own tools/macro_builder/main.cpp, not a
|
||||
# develop checkout: unlike amalgamate.py and generate_natvis.py,
|
||||
# this tool has no other source of truth to check against (its
|
||||
# own README documents that it must reproduce macro_scope.hpp
|
||||
# byte for byte), so there is nothing to gain from checking out a
|
||||
# separate copy, and doing so would make this step fail on a PR
|
||||
# that adds support for a new dispatch table until that PR itself
|
||||
# merges to develop, the same way generate_natvis.py's --version
|
||||
# requirement briefly did.
|
||||
TMPDIR=$(mktemp -d ./macro_builder_check.XXXXXX)
|
||||
c++ -std=c++11 tools/macro_builder/main.cpp -o "$TMPDIR/macro_builder"
|
||||
"$TMPDIR/macro_builder" > "$TMPDIR/paste.hpp"
|
||||
"$TMPDIR/macro_builder" type_body > "$TMPDIR/type_body.hpp"
|
||||
|
||||
# Splice the (still unindented) generated blocks back into
|
||||
# macro_scope.hpp; the astyle pass below indents their
|
||||
# continuation lines the same way it does for the rest of
|
||||
# include/, so a correctly regenerated file comes out unchanged.
|
||||
awk -v newfile="$TMPDIR/paste.hpp" '
|
||||
BEGIN { while ((getline line < newfile) > 0) { new = new line "\n" } }
|
||||
/^#define NLOHMANN_JSON_EXPAND\( x \) x$/ { printf "%s", new; skip=1 }
|
||||
skip && /^#define NLOHMANN_JSON_DOUBLE_PASTE63\(/ { skip=0; next }
|
||||
skip { next }
|
||||
{ print }
|
||||
' include/nlohmann/detail/macro_scope.hpp > "$TMPDIR/macro_scope_1.hpp"
|
||||
awk -v newfile="$TMPDIR/type_body.hpp" '
|
||||
BEGIN { while ((getline line < newfile) > 0) { new = new line "\n" } }
|
||||
/^#define NLOHMANN_JSON_TYPE_BODY\(Prefix, \.\.\.\)/ { printf "%s", new; skip=1 }
|
||||
skip && /^[[:space:]]*NLOHMANN_JSON_TYPE_BODY_SENTINEL\)\)$/ { skip=0; next }
|
||||
skip { next }
|
||||
{ print }
|
||||
' "$TMPDIR/macro_scope_1.hpp" > "$TMPDIR/macro_scope_2.hpp"
|
||||
mv "$TMPDIR/macro_scope_2.hpp" include/nlohmann/detail/macro_scope.hpp
|
||||
rm -rf "$TMPDIR"
|
||||
|
||||
- name: Regenerate amalgamation, formatting, and BUILD.bazel
|
||||
run: |
|
||||
cd $MAIN_DIR
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis
|
||||
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check
|
||||
|
||||
##########################################################################
|
||||
# configuration
|
||||
@@ -22,6 +22,9 @@ TESTS_SRCS=$(shell find tests -type f \( -name '*.hpp' -o -name '*.cpp' -o -name
|
||||
AMALGAMATED_FILE=single_include/nlohmann/json.hpp
|
||||
AMALGAMATED_FWD_FILE=single_include/nlohmann/json_fwd.hpp
|
||||
|
||||
# the header with the argument-counting macros generated by tools/macro_builder
|
||||
MACRO_SCOPE_HPP=include/nlohmann/detail/macro_scope.hpp
|
||||
|
||||
|
||||
##########################################################################
|
||||
# documentation of the Makefile's targets
|
||||
@@ -35,6 +38,7 @@ all:
|
||||
@echo "check-amalgamation - check whether sources have been amalgamated and BUILD.bazel is up to date"
|
||||
@echo "clean - remove built files"
|
||||
@echo "fuzzing - see tests/fuzzing.md for how to build and run the fuzzers"
|
||||
@echo "macro_builder_check - check that macro_scope.hpp matches tools/macro_builder's output"
|
||||
@echo "natvis - regenerate nlohmann_json.natvis from the current ABI tags and version"
|
||||
@echo "pretty - beautify code with Artistic Style"
|
||||
@echo "run_benchmarks - build and run benchmarks"
|
||||
@@ -99,6 +103,21 @@ $(AMALGAMATED_FWD_FILE): $(SRCS)
|
||||
natvis:
|
||||
python3 tools/generate_natvis/generate_natvis.py .
|
||||
|
||||
# regenerate the two tools/macro_builder blocks of $(MACRO_SCOPE_HPP) (see its README.md) and diff against the
|
||||
# checked-in header; phony, because it never writes $(MACRO_SCOPE_HPP) itself
|
||||
macro_builder_check:
|
||||
@set -e; \
|
||||
TMPDIR=$$(mktemp -d ./macro_builder_check.XXXXXX); \
|
||||
trap 'rm -rf "$$TMPDIR"' EXIT; \
|
||||
$(CXX) -std=c++11 tools/macro_builder/main.cpp -o "$$TMPDIR/macro_builder"; \
|
||||
"$$TMPDIR/macro_builder" > "$$TMPDIR/paste.hpp"; \
|
||||
"$$TMPDIR/macro_builder" type_body > "$$TMPDIR/type_body.hpp"; \
|
||||
$(ASTYLE) --project=tools/astyle/.astylerc --suffix=none --quiet "$$TMPDIR/paste.hpp" "$$TMPDIR/type_body.hpp"; \
|
||||
sed -n '/^#define NLOHMANN_JSON_EXPAND( x ) x$$/,/^#define NLOHMANN_JSON_DOUBLE_PASTE63(/p' $(MACRO_SCOPE_HPP) > "$$TMPDIR/paste_actual.hpp"; \
|
||||
sed -n '/^#define NLOHMANN_JSON_TYPE_BODY(Prefix, \.\.\.)/,/^ NLOHMANN_JSON_TYPE_BODY_SENTINEL))$$/p' $(MACRO_SCOPE_HPP) > "$$TMPDIR/type_body_actual.hpp"; \
|
||||
diff "$$TMPDIR/paste.hpp" "$$TMPDIR/paste_actual.hpp" || (echo "===================================================================\n $(MACRO_SCOPE_HPP) (NLOHMANN_JSON_EXPAND..NLOHMANN_JSON_DOUBLE_PASTE63) is out of date!\n Regenerate it, see tools/macro_builder/README.md.\n===================================================================" ; exit 1); \
|
||||
diff "$$TMPDIR/type_body.hpp" "$$TMPDIR/type_body_actual.hpp" || (echo "===================================================================\n $(MACRO_SCOPE_HPP) (NLOHMANN_JSON_TYPE_BODY) is out of date!\n Regenerate it, see tools/macro_builder/README.md.\n===================================================================" ; exit 1)
|
||||
|
||||
# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources
|
||||
check-amalgamation:
|
||||
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~
|
||||
@@ -116,6 +135,7 @@ check-amalgamation:
|
||||
@$(MAKE) natvis
|
||||
@diff nlohmann_json.natvis nlohmann_json.natvis~ || (echo "===================================================================\n nlohmann_json.natvis is out of date! Please run 'make natvis'.\n===================================================================" ; mv nlohmann_json.natvis~ nlohmann_json.natvis ; false)
|
||||
@mv nlohmann_json.natvis~ nlohmann_json.natvis
|
||||
@$(MAKE) macro_builder_check
|
||||
|
||||
# generate the Bazel BUILD file; phony, because a removed header would not trigger a rebuild
|
||||
BUILD.bazel:
|
||||
|
||||
@@ -359,7 +359,7 @@ void templated_json_throw(ExceptionType exception)
|
||||
|
||||
// Macros to simplify conversion from/to types
|
||||
|
||||
// NLOHMANN_JSON_EXPAND to NLOHMANN_JSON_PASTE64 are generated by tools/macro_builder (see its README.md)
|
||||
// NLOHMANN_JSON_EXPAND to NLOHMANN_JSON_DOUBLE_PASTE63 are generated by tools/macro_builder (see its README.md)
|
||||
#define NLOHMANN_JSON_EXPAND( x ) x
|
||||
#define NLOHMANN_JSON_GET_MACRO(_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, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
|
||||
#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
|
||||
@@ -622,6 +622,10 @@ void templated_json_throw(ExceptionType exception)
|
||||
// arguments, so dispatching on Type,BaseType,member... directly would run out
|
||||
// one slot early and cap the derived-type macros at 62 members instead of the
|
||||
// 63 that NLOHMANN_JSON_PASTE supports.
|
||||
//
|
||||
// The slot table below (down to the closing NLOHMANN_JSON_TYPE_BODY_SENTINEL))
|
||||
// is generated by tools/macro_builder (see its README.md; run with the
|
||||
// "type_body" argument).
|
||||
#define NLOHMANN_JSON_TYPE_BODY(Prefix, ...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
|
||||
Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, \
|
||||
Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, \
|
||||
|
||||
@@ -2770,7 +2770,7 @@ void templated_json_throw(ExceptionType exception)
|
||||
|
||||
// Macros to simplify conversion from/to types
|
||||
|
||||
// NLOHMANN_JSON_EXPAND to NLOHMANN_JSON_PASTE64 are generated by tools/macro_builder (see its README.md)
|
||||
// NLOHMANN_JSON_EXPAND to NLOHMANN_JSON_DOUBLE_PASTE63 are generated by tools/macro_builder (see its README.md)
|
||||
#define NLOHMANN_JSON_EXPAND( x ) x
|
||||
#define NLOHMANN_JSON_GET_MACRO(_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, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
|
||||
#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
|
||||
@@ -3033,6 +3033,10 @@ void templated_json_throw(ExceptionType exception)
|
||||
// arguments, so dispatching on Type,BaseType,member... directly would run out
|
||||
// one slot early and cap the derived-type macros at 62 members instead of the
|
||||
// 63 that NLOHMANN_JSON_PASTE supports.
|
||||
//
|
||||
// The slot table below (down to the closing NLOHMANN_JSON_TYPE_BODY_SENTINEL))
|
||||
// is generated by tools/macro_builder (see its README.md; run with the
|
||||
// "type_body" argument).
|
||||
#define NLOHMANN_JSON_TYPE_BODY(Prefix, ...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
|
||||
Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, \
|
||||
Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, Prefix ## MEMBERS, \
|
||||
|
||||
@@ -7,9 +7,16 @@ macros in [`include/nlohmann/detail/macro_scope.hpp`](../../include/nlohmann/det
|
||||
- `NLOHMANN_JSON_GET_MACRO`, which selects a macro by the number of its arguments (64 slots)
|
||||
- `NLOHMANN_JSON_PASTE`, which calls a function-like macro for each member, and its helpers `NLOHMANN_JSON_PASTE2`
|
||||
to `NLOHMANN_JSON_PASTE64`
|
||||
- `NLOHMANN_JSON_DOUBLE_PASTE`, which the `*_WITH_NAMES` macros use to call a function-like macro for each
|
||||
(JSON name, member) pair, and its helpers `NLOHMANN_JSON_DOUBLE_PASTE3` to `NLOHMANN_JSON_DOUBLE_PASTE63`
|
||||
- the slot table of `NLOHMANN_JSON_TYPE_BODY`, which dispatches `NLOHMANN_DEFINE_TYPE_*(Type)` (no further
|
||||
arguments) to the zero-member implementation and every other argument count to the one-or-more-member
|
||||
implementation
|
||||
|
||||
The number of slots (`max_args` in [`main.cpp`](main.cpp)) sets the member limit of these macros.
|
||||
`NLOHMANN_JSON_PASTE` takes the function as its first argument, so 64 slots allow 63 members.
|
||||
`NLOHMANN_JSON_PASTE` and `NLOHMANN_JSON_TYPE_BODY` take the function/prefix as their first argument, so 64 slots
|
||||
allow 63 members; `NLOHMANN_JSON_DOUBLE_PASTE` additionally consumes its members two at a time (name, member), so
|
||||
it only defines the odd helpers up to `NLOHMANN_JSON_DOUBLE_PASTE63`.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -18,26 +25,27 @@ From the project root:
|
||||
```shell
|
||||
c++ -std=c++11 tools/macro_builder/main.cpp -o macro_builder
|
||||
./macro_builder
|
||||
./macro_builder type_body
|
||||
```
|
||||
|
||||
1. In `include/nlohmann/detail/macro_scope.hpp`, replace the lines from `#define NLOHMANN_JSON_EXPAND( x ) x` to the
|
||||
`#define NLOHMANN_JSON_PASTE64(...)` line with the output, without its trailing empty line.
|
||||
2. Run `make amalgamate`. It updates `single_include/nlohmann/json.hpp` and runs `make pretty`, which indents the
|
||||
continuation lines of `NLOHMANN_JSON_PASTE` that the tool writes unindented.
|
||||
1. Run `./macro_builder` (no arguments). In `include/nlohmann/detail/macro_scope.hpp`, replace the lines from
|
||||
`#define NLOHMANN_JSON_EXPAND( x ) x` to the `#define NLOHMANN_JSON_DOUBLE_PASTE63(...)` line with the output,
|
||||
without its trailing empty line.
|
||||
2. Run `./macro_builder type_body`. Replace the lines from `#define NLOHMANN_JSON_TYPE_BODY(Prefix, ...)` to the
|
||||
`NLOHMANN_JSON_TYPE_BODY_SENTINEL))` line with the output.
|
||||
3. Run `make amalgamate`. It updates `single_include/nlohmann/json.hpp` and runs `make pretty`, which indents the
|
||||
continuation lines that the tool writes unindented.
|
||||
|
||||
With an unchanged `main.cpp`, these steps reproduce the header byte for byte.
|
||||
With an unchanged `main.cpp`, these steps reproduce both blocks of `macro_scope.hpp` byte for byte. `make
|
||||
macro_builder_check` (also run by CI, see `.github/workflows/check_amalgamation.yml`) automates this: it builds
|
||||
`main.cpp`, regenerates both blocks, and fails on a diff against the checked-in header.
|
||||
|
||||
## Maintained by hand
|
||||
|
||||
The tool does not generate everything that depends on the number of slots. When changing `max_args`, also update:
|
||||
|
||||
- the `NLOHMANN_JSON_DOUBLE_PASTE` table right after the generated block (`NLOHMANN_JSON_DOUBLE_PASTE` and
|
||||
`NLOHMANN_JSON_DOUBLE_PASTE3`, `NLOHMANN_JSON_DOUBLE_PASTE5`, ..., `NLOHMANN_JSON_DOUBLE_PASTE63`), which the
|
||||
`*_WITH_NAMES` macros use
|
||||
- the slot table of `NLOHMANN_JSON_TYPE_BODY`, which chooses between the implementations for zero members and for one
|
||||
or more members
|
||||
- the documented limit of 63 members in `docs/mkdocs/docs` and the tests at that limit in
|
||||
`tests/src/unit-udt_macro.cpp`
|
||||
|
||||
Both tables pass one macro name per slot to `NLOHMANN_JSON_GET_MACRO`, so they need exactly as many entries as it has
|
||||
slots.
|
||||
All three tables pass one macro name per slot to `NLOHMANN_JSON_GET_MACRO`, so they need exactly as many entries as
|
||||
it has slots.
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void build_code(int max_args)
|
||||
// Builds NLOHMANN_JSON_EXPAND, NLOHMANN_JSON_GET_MACRO, and the
|
||||
// NLOHMANN_JSON_PASTE / NLOHMANN_JSON_PASTE2..PASTE<max_args> dispatch table
|
||||
// and recursive definitions.
|
||||
string build_paste_code(int max_args)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "#define NLOHMANN_JSON_EXPAND( x ) x" << endl;
|
||||
@@ -12,32 +16,93 @@ void build_code(int max_args)
|
||||
for (int i = 0 ; i < max_args ; i++)
|
||||
ss << "_" << i + 1 << ", ";
|
||||
ss << "NAME,...) NAME" << endl;
|
||||
|
||||
|
||||
ss << "#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \\" << endl;
|
||||
for (int i = max_args ; i > 1 ; i--)
|
||||
ss << "NLOHMANN_JSON_PASTE" << i << ", \\" << endl;
|
||||
ss << "NLOHMANN_JSON_PASTE1)(__VA_ARGS__))" << endl;
|
||||
|
||||
|
||||
ss << "#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)" << endl;
|
||||
for (int i = 3 ; i <= max_args ; i++)
|
||||
{
|
||||
ss << "#define NLOHMANN_JSON_PASTE" << i << "(func, ";
|
||||
ss << "#define NLOHMANN_JSON_PASTE" << i << "(func, ";
|
||||
for (int j = 1 ; j < i -1 ; j++)
|
||||
ss << "v" << j << ", ";
|
||||
ss << "v" << j << ", ";
|
||||
ss << "v" << i-1 << ") NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE" << i-1 << "(func, ";
|
||||
for (int j = 2 ; j < i-1 ; j++)
|
||||
ss << "v" << j << ", ";
|
||||
ss << "v" << i-1 << ")" << endl;
|
||||
}
|
||||
|
||||
cout << ss.str() << endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
// Builds the NLOHMANN_JSON_DOUBLE_PASTE dispatch table and recursive
|
||||
// definitions used by the *_WITH_NAMES macros. Its GET_MACRO dispatch reuses
|
||||
// the same max_args slots as NLOHMANN_JSON_PASTE, but DOUBLE_PASTE consumes
|
||||
// its arguments two at a time (name, member), so an even slot count falls
|
||||
// back to the next lower odd NLOHMANN_JSON_DOUBLE_PASTE<N>.
|
||||
string build_double_paste_code(int max_args)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "#define NLOHMANN_JSON_DOUBLE_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \\" << endl;
|
||||
for (int i = max_args ; i > 1 ; i--)
|
||||
{
|
||||
int k = (i % 2 == 1) ? i : i - 1;
|
||||
ss << "NLOHMANN_JSON_DOUBLE_PASTE" << k << ", \\" << endl;
|
||||
}
|
||||
ss << "NLOHMANN_JSON_DOUBLE_PASTE1)(__VA_ARGS__))" << endl;
|
||||
|
||||
ss << "#define NLOHMANN_JSON_DOUBLE_PASTE3(func, v1, v2) func(v1, v2)" << endl;
|
||||
for (int k = 5 ; k <= max_args - 1 ; k += 2)
|
||||
{
|
||||
ss << "#define NLOHMANN_JSON_DOUBLE_PASTE" << k << "(func, ";
|
||||
for (int j = 1 ; j < k - 1 ; j++)
|
||||
ss << "v" << j << ", ";
|
||||
ss << "v" << k - 1 << ") NLOHMANN_JSON_DOUBLE_PASTE3(func, v1, v2) NLOHMANN_JSON_DOUBLE_PASTE" << k - 2 << "(func, ";
|
||||
for (int j = 3 ; j < k - 1 ; j++)
|
||||
ss << "v" << j << ", ";
|
||||
ss << "v" << k - 1 << ")" << endl;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Builds the NLOHMANN_JSON_TYPE_BODY dispatch table: max_args - 1 slots
|
||||
// selecting the *_MEMBERS implementation and a final slot selecting
|
||||
// *_EMPTY, so NLOHMANN_DEFINE_TYPE_*(Type) with no further arguments still
|
||||
// resolves (issue #4041).
|
||||
string build_type_body_table(int max_args)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "#define NLOHMANN_JSON_TYPE_BODY(Prefix, ...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \\" << endl;
|
||||
const int per_line = 8;
|
||||
for (int i = 1 ; i <= max_args ; i++)
|
||||
{
|
||||
ss << (i == max_args ? "Prefix ## EMPTY" : "Prefix ## MEMBERS") << ", ";
|
||||
if (i % per_line == 0)
|
||||
ss << "\\" << endl;
|
||||
}
|
||||
ss << "NLOHMANN_JSON_TYPE_BODY_SENTINEL))" << endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int max_args = 64;
|
||||
build_code(max_args);
|
||||
|
||||
|
||||
// With "type_body", print only the NLOHMANN_JSON_TYPE_BODY dispatch
|
||||
// table (a separate insertion point in macro_scope.hpp); otherwise
|
||||
// print the EXPAND/GET_MACRO/PASTE/DOUBLE_PASTE block that precedes it.
|
||||
if (argc > 1 && string(argv[1]) == "type_body")
|
||||
{
|
||||
cout << build_type_body_table(max_args);
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << build_paste_code(max_args) << build_double_paste_code(max_args);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user