diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 3a4eb79f4..4de48bed0 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -359,6 +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) #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__, \ diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 576498738..dcb1e439e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2770,6 +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) #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__, \ diff --git a/tools/macro_builder/README.md b/tools/macro_builder/README.md new file mode 100644 index 000000000..de16c8a3c --- /dev/null +++ b/tools/macro_builder/README.md @@ -0,0 +1,43 @@ +# macro_builder + +Generates the argument-counting macros behind the `NLOHMANN_DEFINE_TYPE_*` and `NLOHMANN_DEFINE_DERIVED_TYPE_*` +macros in [`include/nlohmann/detail/macro_scope.hpp`](../../include/nlohmann/detail/macro_scope.hpp): + +- `NLOHMANN_JSON_EXPAND` +- `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` + +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. + +## Usage + +From the project root: + +```shell +c++ -std=c++11 tools/macro_builder/main.cpp -o macro_builder +./macro_builder +``` + +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. + +With an unchanged `main.cpp`, these steps reproduce the header byte for byte. + +## 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. diff --git a/tools/serve_header/serve_header.py b/tools/serve_header/serve_header.py index 1f29cb589..5b5bf03f4 100755 --- a/tools/serve_header/serve_header.py +++ b/tools/serve_header/serve_header.py @@ -5,6 +5,8 @@ import logging import os import re import shutil +import socket +import ssl import sys import subprocess @@ -34,7 +36,7 @@ JSON_VERSION_RE = re.compile(r'\s*#\s*define\s+NLOHMANN_JSON_VERSION_MAJOR\s+') class ExitHandler(logging.StreamHandler): def __init__(self, level): - """.""" + """Exit the process on log records at or above level.""" super().__init__() self.level = level @@ -54,7 +56,7 @@ def is_project_root(test_dir='.'): class DirectoryEventBucket: def __init__(self, callback, delay=1.2, threshold=0.8): - """.""" + """Batch directory events and pass their common path to callback.""" self.delay = delay self.threshold = timedelta(seconds=threshold) self.callback = callback @@ -99,7 +101,7 @@ class WorkTree: make_command = 'make' def __init__(self, root_dir, tree_dir): - """.""" + """Track the working tree at tree_dir and its amalgamated header.""" self.root_dir = root_dir self.tree_dir = tree_dir self.rel_dir = os.path.relpath(tree_dir, root_dir) @@ -114,11 +116,11 @@ class WorkTree: self.build_time = t.strftime(DATETIME_FORMAT) def __hash__(self): - """.""" + """Hash by working tree directory.""" return hash((self.tree_dir)) def __eq__(self, other): - """.""" + """Compare by working tree directory.""" if not isinstance(other, type(self)): return NotImplemented return self.tree_dir == other.tree_dir @@ -150,7 +152,7 @@ class WorkTree: class WorkTrees(FileSystemEventHandler): def __init__(self, root_dir): - """.""" + """Find the working trees below root_dir and watch it for changes.""" super().__init__() self.root_dir = root_dir self.trees = set([]) @@ -250,11 +252,11 @@ class WorkTrees(FileSystemEventHandler): self.observer.stop() self.observer.join() -class HeaderRequestHandler(SimpleHTTPRequestHandler): # lgtm[py/missing-call-to-init] +class HeaderRequestHandler(SimpleHTTPRequestHandler): cors_origins = DEFAULT_CORS_ORIGINS def __init__(self, request, client_address, server): - """.""" + """Handle a request for a header below the working trees' root directory.""" self.worktrees = server.worktrees self.worktree = None try: @@ -336,7 +338,7 @@ class HeaderRequestHandler(SimpleHTTPRequestHandler): # lgtm[py/missing-call-to- class DualStackServer(ThreadingHTTPServer): def __init__(self, addr, worktrees): - """.""" + """Serve the headers of worktrees on addr.""" self.worktrees = worktrees super().__init__(addr, HeaderRequestHandler) @@ -349,8 +351,6 @@ class DualStackServer(ThreadingHTTPServer): if __name__ == '__main__': import argparse - import ssl - import socket import yaml # exit code