Compare commits

..
Author SHA1 Message Date
Niels Lohmann ffc3691598 Migrate REUSE metadata from deprecated .reuse/dep5 to REUSE.toml
reuse==6.2.0 (pinned in cmake/requirements/requirements-reuse.txt) warns
"'.reuse/dep5' is deprecated. You are recommended to instead use
REUSE.toml. Use `reuse convert-dep5` to convert." on every
ci_reuse_compliance run. A later reuse release that drops DEP5 support
would break that CI job outright.

Generate REUSE.toml from the 9 Files: stanzas with `reuse convert-dep5`
and remove .reuse/dep5. `reuse lint` still reports full compliance with
spec 3.3 (1268/1268 files with copyright and license information,
unchanged), and `reuse spdx` produces the same per-file copyright and
license entries as before the conversion.

Update the three places that referenced the old file: FILES.md now
documents REUSE.toml with a spec 3.3 link, README.md's REUSE section
names REUSE.toml, and the comment in gen_hedley_undef_check.cmake now
refers to REUSE.toml's blanket path = "**" rule.

Overlaps #4663, which adds an entry to .reuse/dep5; that PR will need to
move its entry into REUSE.toml when rebased on this.

#5716 item 4

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 18:13:51 +02:00
Niels Lohmann ec38da53eb Document SwiftPM's #include <json.hpp> form and add CI coverage
Package.swift declares the json target with path: "single_include/nlohmann",
so SwiftPM consumers must write #include <json.hpp>; the <nlohmann/json.hpp>
form used throughout the rest of this documentation does not resolve. The
SwiftPM section of package_managers.md only had the summary box and did not
mention this, nor the #4650 linker problem: because the json target ships
only headers, SwiftPM/Xcode look for a json.o that is never built, so a
consumer needs at least one .cpp file of its own.

Add a usage example (docs/mkdocs/docs/integration/swift/) that depends on
the json product, includes <json.hpp>, and works around the linker problem
with its own example.cpp; verified it builds with `swift build` against a
local checkout. Also raise the deployment target from the deprecated
.watchOS(.v4) to .watchOS(.v9): Swift 6.4 warns "'v4' is deprecated: watchOS
9.0 is the oldest supported version" on every `swift package` invocation,
and `swift package dump-package` is now clean. This is the one behavior
change in this commit: it raises the minimum watchOS version the package
declares.

Add a macOS CI job that runs `swift package dump-package` (so a future
deprecation warning fails CI) and builds the new documentation example
against the checked-out repository with `swift build`, so a change to
Package.swift or the example is caught before release. No workflow
previously referenced Swift or Package.swift.

Adding an in-repository placeholder .cpp to the library itself, so the
issue does not occur for consumers at all, was proposed and declined in
#4650; the documented workaround is a consumer-side .cpp file instead.

#5716 item 3

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 18:10:49 +02:00
Niels Lohmann 30d5107b8d Add json_fwd.hpp to the Bazel singleheader-json target
The generator for BUILD.bazel only listed single_include/nlohmann/json.hpp
in the singleheader-json cc_library's hdrs. Bazel's sandboxing only exposes
declared headers, so a consumer of :singleheader-json that includes
<nlohmann/json_fwd.hpp> failed with "file not found" (verified with Bazel
9.2.0). Meson and include.zip already ship json_fwd.hpp; the Bazel target
was missing it.

Add single_include/nlohmann/json_fwd.hpp to the hdrs list and regenerate
BUILD.bazel. Verified that `bazel build //:json //:singleheader-json`
succeeds and that a consumer cc_binary depending on :singleheader-json can
now include <nlohmann/json_fwd.hpp>.

Overlaps #5621, which adds json_view.hpp to the same hdrs list in
gen_bazel_build_file.cmake; that PR will need a rebase.

#5716 item 2

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 17:59:47 +02:00
Niels Lohmann bdaa8381d7 Update the supported compiler list and the CITATION.cff repository link
The README's compiler list still named GCC 14.2, Clang 21.0, Apple
Clang 16.0, Intel C++ 17.0.2, nvcc 11.0.221, and MSVC up to 2022,
which no longer matches the CI matrix. List what the workflows test
now, with versions taken from the compiler identification in the CI
logs of the latest develop runs: GCC 4.8 - 16.2, Clang 3.4 - 22.1,
Apple Clang 15.0 - 21.0 (Xcode 15.0.1 up to macos-latest), icpc
2021.10, icpx 2025.3, nvcc 11.8 - 12.6, nvc++ 25.5, and MSVC 2015 -
2026. Apple Clang now starts at 15.0 because CI no longer runs older
Xcode versions; icpc 2021.10 is the last release of that compiler.

CITATION.cff pointed repository-code at the user profile instead of
the repository.

Documentation and metadata only; the library is unchanged.

Part of #5716

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:44:53 +02:00
Niels Lohmann 85fec73da7 Make the json.tar.xz release archive configure standalone
The json.tar.xz rule packed neither src/modules nor tests, but the
top-level CMakeLists.txt needs src/modules for
NLOHMANN_JSON_BUILD_MODULES=ON and defaulted JSON_BuildTests to ON for
a main project. A standalone configure of the extracted archive failed
at add_subdirectory(tests), and enabling the module failed at
add_subdirectory(src/modules).

Add src/modules to the archive, and default JSON_BuildTests to ON only
if tests/CMakeLists.txt exists, so a repository checkout still builds
the tests by default while the archive configures out of the box. Use
GNU tar via a TAR variable (gtar if present, else tar), the same way
SED is found, instead of hard-coding gtar. The library, its public API,
and its ABI are unchanged.

Part of #5716

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-09-30 09:40:26 +02:00
38 changed files with 189 additions and 4717 deletions
+35
View File
@@ -71,3 +71,38 @@ jobs:
run: cmake --build build --parallel 10
- name: Test
run: cd build ; ctest -j 10 --output-on-failure
swiftpm:
runs-on: macos-15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check that Package.swift resolves without a deprecation warning
run: swift package dump-package
- name: Build the SwiftPM documentation example against this checkout
run: |
mkdir -p /tmp/json-swiftpm-consumer/Sources/MyLibrary
cp docs/mkdocs/docs/integration/swift/example.cpp /tmp/json-swiftpm-consumer/Sources/MyLibrary/example.cpp
cat > /tmp/json-swiftpm-consumer/Package.swift << EOF
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
.package(path: "${{ github.workspace }}")
],
targets: [
.target(
name: "MyLibrary",
dependencies: [
.product(name: "json", package: "json")
],
publicHeadersPath: "."
)
]
)
EOF
cd /tmp/json-swiftpm-consumer
swift build
-40
View File
@@ -1,40 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: json
Upstream-Contact: Niels Lohmann <mail@nlohmann.me>
Source: https://github.com/nlohmann/json
Files: *
Copyright: 2013-2026 Niels Lohmann <https://nlohmann.me>
License: MIT
Files: include/nlohmann/thirdparty/hedley.hpp
Copyright: 2016-2021 Evan Nemerson <evan@nemerson.com>
License: CC0
Files: include/nlohmann/detail/meta/cpp_future.hpp
Copyright: 2013-2026 Niels Lohmann <https://nlohmann.me> and 2018 The Abseil Authors
License: MIT AND Apache-2.0
Files: tests/thirdparty/doctest/*
Copyright: 2016-2023 Viktor Kirilov
License: MIT
Files: tests/thirdparty/fifo_map/*
Copyright: 2015-2017 Niels Lohmann
License: MIT
Files: tests/thirdparty/Fuzzer/*
Copyright: 2003-2022 LLVM Project.
License: Apache-2.0
Files: tests/thirdparty/imapdl/*
Copyright: 2017 Georg Sauthoff <mail@gms.tf>
License: GPL-3.0-only
Files: tools/amalgamate/*
Copyright: 2012 Erik Edlund <erik.edlund@32767.se>
License: BSD-3-Clause
Files: tools/gdb_pretty_printer/*
Copyright: 2020 Hannes Domani <https://github.com/ssbssa>
License: MIT
+1
View File
@@ -77,6 +77,7 @@ cc_library(
name = "singleheader-json",
hdrs = [
"single_include/nlohmann/json.hpp",
"single_include/nlohmann/json_fwd.hpp",
],
includes = ["single_include"],
visibility = ["//visibility:public"],
+1 -1
View File
@@ -10,5 +10,5 @@ title: "JSON for Modern C++"
version: 3.12.0
date-released: 2025-04-07
license: MIT
repository-code: "https://github.com/nlohmann"
repository-code: "https://github.com/nlohmann/json"
url: https://json.nlohmann.me
+4 -1
View File
@@ -42,8 +42,11 @@ endif()
## OPTIONS
##
# Build the tests by default only for the main project and only if the tests
# directory exists (the release archive json.tar.xz does not contain it).
# VERSION_GREATER_EQUAL is not available in older CMake (< 3.7)
if(${MAIN_PROJECT} AND (${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13))
if(${MAIN_PROJECT} AND (${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION} VERSION_GREATER 3.13)
AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt")
set(JSON_BuildTests_INIT ON)
else()
set(JSON_BuildTests_INIT OFF)
+3 -3
View File
@@ -207,19 +207,19 @@ Further documentation:
## REUSE
### `.reuse/dep5`
### `REUSE.toml`
The file defines the licenses of certain third-party components in the repository. The root `Makefile` contains a target `reuse` that checks for compliance.
Further documentation:
- [DEP5](https://reuse.software/spec-3.2/#dep5-deprecated)
- [REUSE.toml](https://reuse.software/spec-3.3/#reusetoml)
- [reuse command-line tool](https://pypi.org/project/reuse/)
- [documentation of linting](https://reuse.readthedocs.io/en/stable/man/reuse-lint.html)
- [REUSE](http://reuse.software)
> [!IMPORTANT]
> The filename `.reuse/dep5` is predetermined by REUSE. Alternatively, a `REUSE.toml` file can be used.
> The filename `REUSE.toml` is predetermined by REUSE. Alternatively, a `.reuse/dep5` file (deprecated) can be used.
### `.reuse/templates`
+5 -2
View File
@@ -7,6 +7,9 @@
# find GNU sed to use `-i` parameter
SED:=$(shell command -v gsed || which sed)
# find GNU tar to use `--sort` and `--pax-option` parameters
TAR:=$(shell command -v gtar || which tar)
##########################################################################
# source files
@@ -215,8 +218,8 @@ ChangeLog.md:
# archive is created according to the advices of <https://reproducible-builds.org/docs/archives/>.
json.tar.xz:
mkdir json
rsync -R $(shell find LICENSE.MIT nlohmann_json.natvis CMakeLists.txt cmake/*.in include single_include -type f) json
gtar --sort=name --mtime="@$(shell git log -1 --pretty=%ct)" --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime --create --file - json | xz --compress -9e --threads=2 - > json.tar.xz
rsync -R $(shell find LICENSE.MIT nlohmann_json.natvis CMakeLists.txt cmake/*.in include single_include src/modules -type f) json
$(TAR) --sort=name --mtime="@$(shell git log -1 --pretty=%ct)" --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime --create --file - json | xz --compress -9e --threads=2 - > json.tar.xz
rm -fr json
# We use `-X` to make the resulting ZIP file reproducible, see
+1 -1
View File
@@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "nlohmann-json",
platforms: [
.iOS(.v12), .macOS(.v10_13), .tvOS(.v12), .watchOS(.v4), .visionOS(.v1)
.iOS(.v12), .macOS(.v10_13), .tvOS(.v12), .watchOS(.v9), .visionOS(.v1)
],
products: [
.library(name: "json", targets: ["json"])
+13 -10
View File
@@ -1204,15 +1204,18 @@ language bindings, format converters, and the like. See the curated [Ecosystem](
Though it's 2026 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
- GCC 4.8 - 14.2 (and possibly later)
- Clang 3.4 - 21.0 (and possibly later)
- Apple Clang 9.1 - 16.0 (and possibly later)
- Intel C++ Compiler 17.0.2 (and possibly later)
- Nvidia CUDA Compiler 11.0.221 (and possibly later)
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)
- Microsoft Visual C++ 2019 / Build Tools 16.3.1+1def00d3d (and possibly later)
- Microsoft Visual C++ 2022 / Build Tools 19.30.30709.0 (and possibly later)
- GCC 4.8 - 16.2 (and possibly later)
- Clang 3.4 - 22.1 (and possibly later)
- Apple Clang 15.0 - 21.0 (and possibly later)
- Intel C++ Compiler Classic (icpc) 2021.10
- Intel oneAPI DPC++/C++ Compiler (icpx) 2025.3 (and possibly later)
- NVIDIA CUDA Compiler (nvcc) 11.8 - 12.6 (and possibly later)
- NVIDIA HPC SDK C++ Compiler (nvc++) 25.5 (and possibly later)
- Microsoft Visual C++ 2015 / MSVC 19.0 (and possibly later)
- Microsoft Visual C++ 2017 / MSVC 19.16 (and possibly later)
- Microsoft Visual C++ 2019 / MSVC 19.29 (and possibly later)
- Microsoft Visual C++ 2022 / MSVC 19.44 (and possibly later)
- Microsoft Visual C++ 2026 / MSVC 19.51 (and possibly later)
I would be happy to learn about other compilers/versions.
@@ -1402,7 +1405,7 @@ The library is compliant to version 3.3 of the [**REUSE specification**](https:/
- Every source file contains an SPDX copyright header.
- The full text of all licenses used in the repository can be found in the `LICENSES` folder.
- File `.reuse/dep5` contains an overview of all files' copyrights and licenses.
- File `REUSE.toml` contains an overview of all files' copyrights and licenses.
- Run `pipx run reuse lint` to verify the project's REUSE compliance and `pipx run reuse spdx` to generate a SPDX SBOM.
## Contact
+58
View File
@@ -0,0 +1,58 @@
version = 1
SPDX-PackageName = "json"
SPDX-PackageSupplier = "Niels Lohmann <mail@nlohmann.me>"
SPDX-PackageDownloadLocation = "https://github.com/nlohmann/json"
[[annotations]]
path = "**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2013-2026 Niels Lohmann <https://nlohmann.me>"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "include/nlohmann/thirdparty/hedley.hpp"
precedence = "aggregate"
SPDX-FileCopyrightText = "2016-2021 Evan Nemerson <evan@nemerson.com>"
SPDX-License-Identifier = "CC0"
[[annotations]]
path = "include/nlohmann/detail/meta/cpp_future.hpp"
precedence = "aggregate"
SPDX-FileCopyrightText = "2013-2026 Niels Lohmann <https://nlohmann.me> and 2018 The Abseil Authors"
SPDX-License-Identifier = "MIT AND Apache-2.0"
[[annotations]]
path = "tests/thirdparty/doctest/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2016-2023 Viktor Kirilov"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "tests/thirdparty/fifo_map/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2015-2017 Niels Lohmann"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "tests/thirdparty/Fuzzer/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2003-2022 LLVM Project."
SPDX-License-Identifier = "Apache-2.0"
[[annotations]]
path = "tests/thirdparty/imapdl/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2017 Georg Sauthoff <mail@gms.tf>"
SPDX-License-Identifier = "GPL-3.0-only"
[[annotations]]
path = "tools/amalgamate/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2012 Erik Edlund <erik.edlund@32767.se>"
SPDX-License-Identifier = "BSD-3-Clause"
[[annotations]]
path = "tools/gdb_pretty_printer/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2020 Hannes Domani <https://github.com/ssbssa>"
SPDX-License-Identifier = "MIT"
+1
View File
@@ -48,6 +48,7 @@ cc_library(
name = "singleheader-json",
hdrs = [
"single_include/nlohmann/json.hpp",
"single_include/nlohmann/json_fwd.hpp",
],
includes = ["single_include"],
visibility = ["//visibility:public"],
+1 -1
View File
@@ -64,7 +64,7 @@ if(MODE STREQUAL "undef")
# recipe is self-contained and its output is byte-stable across reruns.
# The embedded SPDX tags below are part of the *generated* file's
# content, not a REUSE header for this .cmake script itself (which is
# already covered by the blanket "Files: *" rule in .reuse/dep5) -- keep
# already covered by the blanket path = "**" rule in REUSE.toml) -- keep
# them wrapped in REUSE-IgnoreStart/End so `reuse lint` does not try to
# parse "MIT\n")" as this file's own SPDX-License-Identifier value.
# REUSE-IgnoreStart
-2
View File
@@ -53,8 +53,6 @@ header. See also the [macro overview page](../../features/macros.md).
- [**JSON_BRACE_INIT_COPY_SEMANTICS**](json_brace_init_copy_semantics.md) - opt in to copy/move semantics for single-element brace initialization
- [**JSON_DISABLE_ENUM_SERIALIZATION**](json_disable_enum_serialization.md) - switch off default serialization/deserialization functions for enums
- [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions
- [**JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS**](json_use_objects_for_enum_keyed_maps.md) - opt in to storing maps with enum
keys as objects
## Comparison behavior
@@ -1,139 +0,0 @@
# JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
```cpp
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS /* value */
```
When defined to `1`, maps whose keys are enums (such as `std::map<E, T>` or `std::unordered_map<E, T>`) are stored as
JSON objects, using the enum's own conversion for the keys. By default, they are stored as arrays of `[key, value]`
pairs.
## Default definition
The default value is `0` (disabled — existing behavior is preserved).
```cpp
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0
```
## Notes
!!! note "Background"
JSON object keys are strings, so a map is only stored as an object if its keys can be converted to a string type.
Enums are not, even if [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) maps them to strings, so a
map with enum keys becomes an array of `[key, value]` pairs:
```json
[["stopped", "aa"], ["completed", "bb"]]
```
With this macro, the same map becomes an object
(see [#4378](https://github.com/nlohmann/json/issues/4378)):
```json
{"completed": "bb", "stopped": "aa"}
```
!!! note "Maps with non-unique keys"
Maps that allow duplicate keys, such as `std::multimap<E, T>` or `std::unordered_multimap<E, T>`, are not affected
by the macro and are still stored as arrays of `[key, value]` pairs, as an object cannot hold duplicate keys.
!!! note "Reading"
Reading is not affected by the macro: a map with enum keys can always be read from both an array of pairs and an
object. For the latter, each key is converted to the enum with its `from_json` function, e.g., the one defined by
[`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md). Data written without the macro can therefore
still be read after enabling it.
!!! warning "Keys must serialize to distinct strings"
Each key is converted with the enum's `to_json` function. If a key is not converted to a string (for instance, an
enum without [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md), which is stored as an integer, or an
enumerator mapped to `nullptr`), [`type_error.302`](../../home/exceptions.md#jsonexceptiontype_error302) is thrown.
If two keys are converted to the same string (for instance, because
[`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) maps an unlisted enumerator to the first entry),
[`type_error.318`](../../home/exceptions.md#jsonexceptiontype_error318) is thrown. In both cases, the target value
is not changed.
!!! warning "Opt-in only"
This macro must be defined **before** including `<nlohmann/json.hpp>`. Defining it after the include has no effect.
!!! note "ABI compatibility"
The value of this macro is encoded in the [namespace](../../features/namespace.md) (tag `_ekmo`), resulting in
distinct symbol names. Translation units compiled with and without it can therefore be linked into the same program
without One Definition Rule (ODR) violations, but they cannot exchange instances of library types.
## Examples
??? example "Default behavior (macro not defined)"
Without the macro, a map with enum keys is stored as an array of pairs:
```cpp
#include <map>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED };
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, {
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})
int main()
{
std::map<TaskState, std::string> m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
json j = m;
// j is [["stopped","aa"],["completed","bb"]]
}
```
??? example "Objects for enum-keyed maps (macro defined to 1)"
With the macro, the same map is stored as an object:
```cpp
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 1
#include <map>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
enum TaskState { TS_STOPPED, TS_RUNNING, TS_COMPLETED };
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, {
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})
int main()
{
std::map<TaskState, std::string> m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
json j = m;
// j is {"completed":"bb","stopped":"aa"}
auto m2 = j.get<std::map<TaskState, std::string>>();
// m2 == m
}
```
## See also
- [Specializing enum conversion](../../features/enum_conversion.md)
- [**NLOHMANN_JSON_SERIALIZE_ENUM**](nlohmann_json_serialize_enum.md) - serialize/deserialize an enum
- [**NLOHMANN_JSON_SERIALIZE_ENUM_STRICT**](nlohmann_json_serialize_enum_strict.md) - serialize/deserialize an enum with
exceptions
## Version history
- Added in version 3.13.0.
@@ -41,9 +41,6 @@ inline void from_json(const BasicJsonType& j, type& e);
conversion. Select this default pair carefully. See example 1 below.
- If an enum or JSON value is specified in multiple conversions, the first matching conversion from the top of the
list will be returned when converting to or from JSON. See example 2 below.
- Maps with enum keys (e.g., `std::map<ENUM_TYPE, T>`) are stored as arrays of `[key, value]` pairs by default.
Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects
with the converted keys. Such maps can be read from both forms.
## Examples
@@ -83,7 +80,6 @@ inline void from_json(const BasicJsonType& j, type& e);
- [Specializing enum conversion](../../features/enum_conversion.md)
- [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT`](./nlohmann_json_serialize_enum_strict.md)
- [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md)
- [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md)
## Version history
@@ -44,9 +44,6 @@ inline void from_json(const BasicJsonType& j, type& e);
`"enum value out of range for <type>"`.
- If an enum or JSON value is specified in multiple conversions, the first matching conversion from the top of the
list will be returned when converting to or from JSON. See example 2 below.
- Maps with enum keys (e.g., `std::map<ENUM_TYPE, T>`) are stored as arrays of `[key, value]` pairs by default.
Define [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md) to store them as objects
with the converted keys. Such maps can be read from both forms.
## Examples
@@ -102,7 +99,6 @@ inline void from_json(const BasicJsonType& j, type& e);
- [Specializing enum conversion](../../features/enum_conversion.md)
- [`NLOHMANN_JSON_SERIALIZE_ENUM`](./nlohmann_json_serialize_enum.md)
- [`JSON_DISABLE_ENUM_SERIALIZATION`](json_disable_enum_serialization.md)
- [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](json_use_objects_for_enum_keyed_maps.md)
## Version history
@@ -43,23 +43,6 @@ json jPi = 3.14;
assert(jPi.get<TaskState>() == TS_INVALID );
```
## Maps with enum keys
By default, maps with enum keys, such as `std::map<TaskState, std::string>`, are stored as arrays of `[key, value]`
pairs, because JSON object keys must be strings. Define
[`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md) before including the
library to store them as objects, with the keys converted by the enum's `to_json()` function:
```cpp
std::map<TaskState, std::string> m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
json j = m;
// default: [["stopped","aa"],["completed","bb"]]
// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS: {"completed":"bb","stopped":"aa"}
```
Either form can be read back, with or without the macro.
## Notes
Just as in [Arbitrary Type Conversions](arbitrary_types.md) above,
-7
View File
@@ -167,13 +167,6 @@ behavior is deprecated and switched off (`0`) by default.
See [full documentation of `JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../api/macros/json_use_legacy_discarded_value_comparison.md).
## `JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`
When defined to `1`, maps with enum keys (e.g., `std::map<E, T>`) are stored as objects, using the enum's conversion for
the keys, instead of arrays of `[key, value]` pairs. It is switched off (`0`) by default.
See [full documentation of `JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md).
## `JSON_USE_SIMDUTF`
When defined, UTF-8 validation of JSON strings read from contiguous byte input is delegated to the
-2
View File
@@ -20,8 +20,6 @@ The complete default namespace name is derived as follows:
`_bics`.
- [`JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md) defined non-zero appends `_psp`.
- [`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md) defined non-zero appends `_snul`.
- [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md) defined non-zero
appends `_ekmo`.
- The inline namespace ends with the suffix `_v` followed by the 3 components of the version number separated by
underscores. To omit the version component, see [Disabling the version component](#disabling-the-version-component)
below.
-16
View File
@@ -596,9 +596,6 @@ During implicit or explicit value conversion, the JSON type must be compatible w
[json.exception.type_error.302] type must be string, but is object
```
This exception is also thrown with [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md)
if a key of a map with enum keys is not converted to a string, for instance, because the enum is stored as an integer.
### json.exception.type_error.303
To retrieve a reference to a value stored in a `basic_json` object with `get_ref`, the type of the reference must match the value type. For instance, for a JSON array, the `ReferenceType` must be `array_t &`.
@@ -785,19 +782,6 @@ The dynamic type of the object cannot be represented in the requested serializat
Encapsulate the JSON value in an object. That is, instead of serializing `#!json true`, serialize `#!json {"value": true}`
### json.exception.type_error.318
With [`JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS`](../api/macros/json_use_objects_for_enum_keyed_maps.md), a map with enum
keys is stored as an object. This exception is thrown if two of its keys are converted to the same string, so one of the
entries would be lost. This happens, for instance, if [`NLOHMANN_JSON_SERIALIZE_ENUM`](../api/macros/nlohmann_json_serialize_enum.md)
does not list an enumerator and it is therefore converted like the first listed one.
!!! failure "Example message"
```
[json.exception.type_error.318] duplicate object key 'red'
```
## Out of range
This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance, in the case of array indices or nonexisting object keys.
+1 -1
View File
@@ -125,7 +125,7 @@ automatically download a release as a dependency at configure time.
### `JSON_BuildTests`
Build the unit tests when [`BUILD_TESTING`](https://cmake.org/cmake/help/latest/command/enable_testing.html) is enabled. This option is `ON` by default if the library's CMake project is the top project. That is, when integrating the library as described above, the test suite is not built unless explicitly switched on with this option.
Build the unit tests when [`BUILD_TESTING`](https://cmake.org/cmake/help/latest/command/enable_testing.html) is enabled. This option is `ON` by default if the library's CMake project is the top project and the `tests` directory exists (the release archive `json.tar.xz` does not contain it). That is, when integrating the library as described above, the test suite is not built unless explicitly switched on with this option.
### `JSON_CI`
@@ -443,6 +443,30 @@ installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nl
- :octicons-file-24: File issues at the [library issue tracker](https://github.com/nlohmann/json/issues)
- :octicons-question-24: [Xcode documentation](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app)
The `json` target's public headers live at `single_include/nlohmann`, so a consumer must write `#include <json.hpp>` rather than the
`#include <nlohmann/json.hpp>` form used elsewhere in this documentation. The `json` target also ships only headers, and SwiftPM/Xcode
expect every library target to produce an object file to link against; without one, linking a consumer fails with a missing `json.o`
([#4650](https://github.com/nlohmann/json/issues/4650)). The workaround is to add at least one `.cpp` file of your own to the target
that depends on `json`.
??? example
1. Create the following files:
```swift title="Package.swift"
--8<-- "integration/swift/Package.swift"
```
```cpp title="Sources/MyLibrary/example.cpp"
--8<-- "integration/swift/example.cpp"
```
2. Build
```shell
swift build
```
## NuGet
!!! abstract "Summary"
@@ -0,0 +1,20 @@
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
.package(url: "https://github.com/nlohmann/json.git", from: "3.12.0")
],
targets: [
// the C++ target that uses nlohmann/json
.target(
name: "MyLibrary",
dependencies: [
.product(name: "json", package: "json")
],
// works around missing public headers in MyLibrary; not related to nlohmann/json
publicHeadersPath: "."
)
]
)
@@ -0,0 +1,8 @@
// MyLibrary must contain at least one .cpp file, or SwiftPM/Xcode will
// not build a usable "json" library to link against (see nlohmann/json#4650)
#include <json.hpp>
nlohmann::json example()
{
return nlohmann::json::meta();
}
-1
View File
@@ -303,7 +303,6 @@ nav:
- 'JSON_USE_GLOBAL_UDLS': api/macros/json_use_global_udls.md
- 'JSON_USE_IMPLICIT_CONVERSIONS': api/macros/json_use_implicit_conversions.md
- 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md
- 'JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS': api/macros/json_use_objects_for_enum_keyed_maps.md
- 'JSON_USE_SIMDUTF': api/macros/json_use_simdutf.md
- 'NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_derived_type.md
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE': api/macros/nlohmann_define_type_intrusive.md
+4 -15
View File
@@ -46,10 +46,6 @@
#define JSON_STRICT_NUL_HANDLING 0
#endif
#ifndef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0
#endif
#if JSON_DIAGNOSTICS
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
#else
@@ -86,20 +82,14 @@
#define NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING
#endif
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS _ekmo
#else
#define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) json_abi ## a ## b ## c ## d ## e ## f ## g
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f) json_abi ## a ## b ## c ## d ## e ## f
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -108,8 +98,7 @@
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS, \
NLOHMANN_JSON_ABI_TAG_BRACE_INIT_COPY_SEMANTICS, \
NLOHMANN_JSON_ABI_TAG_PRECISE_STREAM_POSITION, \
NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING, \
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS)
NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
@@ -550,40 +550,11 @@ auto from_json(BasicJsonType&& j, TupleRelated&& t)
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
}
// read a map with enum keys from an object, using the enum's own from_json for
// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written
// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
template<typename BasicJsonType, typename Map>
inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/)
{
if (!j.is_object())
{
return false;
}
m.clear();
for (const auto& p : *j.template get_ptr<const typename BasicJsonType::object_t*>())
{
m.emplace(BasicJsonType(p.first).template get<typename Map::key_type>(), p.second.template get<typename Map::mapped_type>());
}
return true;
}
template<typename BasicJsonType, typename Map>
inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/)
{
return false;
}
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
{
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
if (from_json_enum_keyed_object(j, m, std::is_enum<Key> {}))
{
return;
}
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
@@ -604,11 +575,6 @@ template < typename BasicJsonType, typename Key, typename Value, typename Hash,
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
{
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
if (from_json_enum_keyed_object(j, m, std::is_enum<Key> {}))
{
return;
}
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
@@ -23,7 +23,6 @@
#include <valarray> // valarray
#include <vector> // vector
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/std_fs.hpp>
@@ -382,9 +381,6 @@ template < typename BasicJsonType, typename CompatibleArrayType,
!is_basic_json<CompatibleArrayType>::value
#if JSON_HAS_RANGES && !defined(__MINGW32__)
&& !is_compatible_range_view<CompatibleArrayType>::value
#endif
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
&& !is_enum_keyed_map<CompatibleArrayType>::value
#endif
,
int > = 0 >
@@ -439,33 +435,6 @@ inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
external_constructor<value_t::object>::construct(j, obj);
}
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
// store a map with enum keys as an object, using the enum's own to_json for the
// keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); without the macro, such maps
// are stored as arrays of [key, value] pairs
template < typename BasicJsonType, typename EnumKeyedMap,
enable_if_t < is_enum_keyed_map<EnumKeyedMap>::value&& !is_basic_json<EnumKeyedMap>::value, int > = 0 >
inline void to_json(BasicJsonType& j, const EnumKeyedMap& map)
{
typename BasicJsonType::object_t obj;
for (const auto& p : map)
{
BasicJsonType key = p.first;
if (JSON_HEDLEY_UNLIKELY(!key.is_string()))
{
JSON_THROW(type_error::create(302, concat("type must be string, but is ", key.type_name()), &key));
}
auto& key_string = *key.template get_ptr<typename BasicJsonType::string_t*>();
if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second))
{
JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key));
}
}
external_constructor<value_t::object>::construct(j, std::move(obj));
}
#endif
template<typename BasicJsonType>
inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
{
@@ -46,7 +46,6 @@
#undef JSON_BRACE_INIT_COPY_SEMANTICS
#undef JSON_PRECISE_STREAM_POSITION
#undef JSON_STRICT_NUL_HANDLING
#undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif
#include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
@@ -400,30 +400,6 @@ template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
template<typename T>
using insert_result_t = decltype(std::declval<T&>().insert(std::declval<const value_type_t<T>&>()));
template<typename T>
using insert_result_second_t = decltype(std::declval<T&>().insert(std::declval<const value_type_t<T>&>()).second);
// a map-like type (std::map, std::unordered_map, ...) whose keys are enums; see
// JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
template<typename T, typename = void>
struct is_enum_keyed_map : std::false_type {};
template<typename T>
struct is_enum_keyed_map <
T, enable_if_t < is_detected<mapped_type_t, T>::value&&
is_detected<key_type_t, T>::value >>
{
// maps with non-unique keys (std::multimap, std::unordered_multimap, ...)
// are excluded, because an object cannot hold duplicate keys; they are
// detected by insert() returning an iterator instead of a pair<iterator, bool>
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
static constexpr bool value = std::is_enum<typename T::key_type>::value &&
!(is_detected<insert_result_t, T>::value && !is_detected<insert_result_second_t, T>::value);
};
template<typename BasicJsonType, typename ConstructibleObjectType,
typename = void>
struct is_constructible_object_type_impl : std::false_type {};
-3840
View File
File diff suppressed because it is too large Load Diff
+4 -106
View File
@@ -103,10 +103,6 @@
#define JSON_STRICT_NUL_HANDLING 0
#endif
#ifndef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0
#endif
#if JSON_DIAGNOSTICS
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
#else
@@ -143,20 +139,14 @@
#define NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING
#endif
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS _ekmo
#else
#define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) json_abi ## a ## b ## c ## d ## e ## f ## g
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f) json_abi ## a ## b ## c ## d ## e ## f
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -165,8 +155,7 @@
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS, \
NLOHMANN_JSON_ABI_TAG_BRACE_INIT_COPY_SEMANTICS, \
NLOHMANN_JSON_ABI_TAG_PRECISE_STREAM_POSITION, \
NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING, \
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS)
NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
@@ -4421,30 +4410,6 @@ template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
template<typename T>
using insert_result_t = decltype(std::declval<T&>().insert(std::declval<const value_type_t<T>&>()));
template<typename T>
using insert_result_second_t = decltype(std::declval<T&>().insert(std::declval<const value_type_t<T>&>()).second);
// a map-like type (std::map, std::unordered_map, ...) whose keys are enums; see
// JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
template<typename T, typename = void>
struct is_enum_keyed_map : std::false_type {};
template<typename T>
struct is_enum_keyed_map <
T, enable_if_t < is_detected<mapped_type_t, T>::value&&
is_detected<key_type_t, T>::value >>
{
// maps with non-unique keys (std::multimap, std::unordered_multimap, ...)
// are excluded, because an object cannot hold duplicate keys; they are
// detected by insert() returning an iterator instead of a pair<iterator, bool>
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
static constexpr bool value = std::is_enum<typename T::key_type>::value &&
!(is_detected<insert_result_t, T>::value && !is_detected<insert_result_second_t, T>::value);
};
template<typename BasicJsonType, typename ConstructibleObjectType,
typename = void>
struct is_constructible_object_type_impl : std::false_type {};
@@ -6082,40 +6047,11 @@ auto from_json(BasicJsonType&& j, TupleRelated&& t)
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
}
// read a map with enum keys from an object, using the enum's own from_json for
// the keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); this is the form written
// with JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
template<typename BasicJsonType, typename Map>
inline bool from_json_enum_keyed_object(const BasicJsonType& j, Map& m, std::true_type /*key is enum*/)
{
if (!j.is_object())
{
return false;
}
m.clear();
for (const auto& p : *j.template get_ptr<const typename BasicJsonType::object_t*>())
{
m.emplace(BasicJsonType(p.first).template get<typename Map::key_type>(), p.second.template get<typename Map::mapped_type>());
}
return true;
}
template<typename BasicJsonType, typename Map>
inline bool from_json_enum_keyed_object(const BasicJsonType& /*j*/, Map& /*m*/, std::false_type /*key is enum*/)
{
return false;
}
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
{
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
if (from_json_enum_keyed_object(j, m, std::is_enum<Key> {}))
{
return;
}
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
@@ -6136,11 +6072,6 @@ template < typename BasicJsonType, typename Key, typename Value, typename Hash,
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
{
// NOLINTNEXTLINE(modernize-type-traits) we use C++11
if (from_json_enum_keyed_object(j, m, std::is_enum<Key> {}))
{
return;
}
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
@@ -6236,8 +6167,6 @@ NLOHMANN_JSON_NAMESPACE_END
#include <valarray> // valarray
#include <vector> // vector
// #include <nlohmann/detail/exceptions.hpp>
// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
@@ -6981,9 +6910,6 @@ template < typename BasicJsonType, typename CompatibleArrayType,
!is_basic_json<CompatibleArrayType>::value
#if JSON_HAS_RANGES && !defined(__MINGW32__)
&& !is_compatible_range_view<CompatibleArrayType>::value
#endif
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
&& !is_enum_keyed_map<CompatibleArrayType>::value
#endif
,
int > = 0 >
@@ -7038,33 +6964,6 @@ inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
external_constructor<value_t::object>::construct(j, obj);
}
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
// store a map with enum keys as an object, using the enum's own to_json for the
// keys (e.g., from NLOHMANN_JSON_SERIALIZE_ENUM); without the macro, such maps
// are stored as arrays of [key, value] pairs
template < typename BasicJsonType, typename EnumKeyedMap,
enable_if_t < is_enum_keyed_map<EnumKeyedMap>::value&& !is_basic_json<EnumKeyedMap>::value, int > = 0 >
inline void to_json(BasicJsonType& j, const EnumKeyedMap& map)
{
typename BasicJsonType::object_t obj;
for (const auto& p : map)
{
BasicJsonType key = p.first;
if (JSON_HEDLEY_UNLIKELY(!key.is_string()))
{
JSON_THROW(type_error::create(302, concat("type must be string, but is ", key.type_name()), &key));
}
auto& key_string = *key.template get_ptr<typename BasicJsonType::string_t*>();
if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second))
{
JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key));
}
}
external_constructor<value_t::object>::construct(j, std::move(obj));
}
#endif
template<typename BasicJsonType>
inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
{
@@ -32848,7 +32747,6 @@ struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-c
#undef JSON_BRACE_INIT_COPY_SEMANTICS
#undef JSON_PRECISE_STREAM_POSITION
#undef JSON_STRICT_NUL_HANDLING
#undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif
// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
+4 -15
View File
@@ -64,10 +64,6 @@
#define JSON_STRICT_NUL_HANDLING 0
#endif
#ifndef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 0
#endif
#if JSON_DIAGNOSTICS
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
#else
@@ -104,20 +100,14 @@
#define NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING
#endif
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS _ekmo
#else
#define NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g) json_abi ## a ## b ## c ## d ## e ## f ## g
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f, g) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f, g)
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f) json_abi ## a ## b ## c ## d ## e ## f
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c, d, e, f) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c, d, e, f)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
@@ -126,8 +116,7 @@
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS, \
NLOHMANN_JSON_ABI_TAG_BRACE_INIT_COPY_SEMANTICS, \
NLOHMANN_JSON_ABI_TAG_PRECISE_STREAM_POSITION, \
NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING, \
NLOHMANN_JSON_ABI_TAG_OBJECTS_FOR_ENUM_KEYED_MAPS)
NLOHMANN_JSON_ABI_TAG_STRICT_NUL_HANDLING)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
-4
View File
@@ -44,10 +44,6 @@ TEST_CASE("default namespace")
expected += "_snul";
#endif
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
expected += "_ekmo";
#endif
expected += "_v" STRINGIZE(NLOHMANN_JSON_VERSION_MAJOR);
expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_MINOR);
expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_PATCH) "::basic_json";
-4
View File
@@ -45,10 +45,6 @@ TEST_CASE("default namespace without version component")
expected += "_snul";
#endif
#if JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
expected += "_ekmo";
#endif
expected += "::basic_json";
// fallback for Clang
-246
View File
@@ -1,246 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include "doctest_compatibility.h"
// skip tests if JSON_DisableEnumSerialization=ON (#4384)
#if defined(JSON_DISABLE_ENUM_SERIALIZATION) && (JSON_DISABLE_ENUM_SERIALIZATION == 1)
#define SKIP_TESTS_FOR_ENUM_SERIALIZATION
#endif
// This file tests the opt-in JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS, so it defines
// the macro itself rather than relying on a -D flag, and runs in every build.
// The default behavior is tested in unit-enum_keyed_maps_default.cpp.
#ifdef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#undef JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
#endif
#define JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS 1
#include <nlohmann/json.hpp>
using nlohmann::json;
using nlohmann::ordered_json;
#include <cstddef>
#include <functional>
#include <map>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#define STRINGIZE_EX(x) #x
#define STRINGIZE(x) STRINGIZE_EX(x)
// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
namespace
{
// std::hash is only required for enums since C++14
struct enum_hash
{
template<typename T>
std::size_t operator()(T t) const noexcept
{
return static_cast<std::size_t>(t);
}
};
} // namespace
// the example from #4378
enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class)
{
TS_STOPPED,
TS_RUNNING,
TS_COMPLETED,
TS_INVALID = -1,
};
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState,
{
{TS_INVALID, nullptr},
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})
enum class color {red, green, blue}; // blue is not mapped and falls back to "red"
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(color,
{
{color::red, "red"},
{color::green, "green"},
})
enum class strict_color {red, green, blue}; // blue is not mapped
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(strict_color,
{
{strict_color::red, "red"},
{strict_color::green, "green"},
})
enum class digit {zero, one};
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(digit,
{
{digit::zero, 0},
{digit::one, 1},
})
#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION
enum class plain {zero, one}; // serialized as integer
#endif
TEST_CASE("JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS")
{
SECTION("the macro is part of the ABI tag")
{
const std::string ns = STRINGIZE(NLOHMANN_JSON_NAMESPACE);
CHECK(ns.find("_ekmo") != std::string::npos);
}
SECTION("std::map (#4378)")
{
using task_map = std::map<TaskState, std::string>;
const task_map m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
const json j = m;
CHECK(j == json::parse(R"({"stopped":"aa","completed":"bb"})"));
CHECK(j.get<task_map>() == m);
json j2;
j2["x"] = m;
CHECK(j2.dump() == R"({"x":{"completed":"bb","stopped":"aa"}})");
}
SECTION("std::map with custom comparator")
{
using task_map = std::map<TaskState, int, std::greater<TaskState>>;
const task_map m = {{TS_STOPPED, 1}, {TS_RUNNING, 2}};
const json j = m;
CHECK(j == json::parse(R"({"stopped":1,"running":2})"));
CHECK(j.get<task_map>() == m);
}
SECTION("std::unordered_map")
{
using task_map = std::unordered_map<TaskState, int, enum_hash>;
const task_map m = {{TS_STOPPED, 1}, {TS_RUNNING, 2}};
const json j = m;
CHECK(j == json::parse(R"({"stopped":1,"running":2})"));
CHECK(j.get<task_map>() == m);
}
SECTION("nested maps")
{
using nested_map = std::map<color, std::map<TaskState, int>>;
const nested_map m = {{color::green, {{TS_RUNNING, 1}}}, {color::red, {}}};
const json j = m;
CHECK(j == json::parse(R"({"green":{"running":1},"red":{}})"));
CHECK(j.get<nested_map>() == m);
}
SECTION("ordered_json keeps the order of the map")
{
using task_map = std::map<TaskState, int>;
const task_map m = {{TS_STOPPED, 1}, {TS_RUNNING, 2}, {TS_COMPLETED, 3}};
const ordered_json j = m;
CHECK(j.dump() == R"({"stopped":1,"running":2,"completed":3})");
CHECK(j.get<task_map>() == m);
}
SECTION("empty map")
{
const json j = std::map<TaskState, int>();
CHECK(j.is_object());
CHECK(j.empty());
}
SECTION("NLOHMANN_JSON_SERIALIZE_ENUM_STRICT")
{
using color_map = std::map<strict_color, int>;
const color_map m = {{strict_color::red, 1}, {strict_color::green, 2}};
const json j = m;
CHECK(j == json::parse(R"({"red":1,"green":2})"));
CHECK(j.get<color_map>() == m);
const color_map unmapped = {{strict_color::blue, 1}};
json _;
CHECK_THROWS_WITH_AS(_ = unmapped,
"[json.exception.out_of_range.410] enum value out of range for strict_color", json::out_of_range&);
}
SECTION("arrays of [key, value] pairs are still read")
{
using task_map = std::map<TaskState, int>;
const task_map m = {{TS_STOPPED, 1}};
CHECK(json::parse(R"([["stopped",1]])").get<task_map>() == m);
}
SECTION("other containers are not affected")
{
const std::vector<std::pair<TaskState, int>> pairs = {{TS_STOPPED, 1}};
const std::map<std::string, TaskState> string_keys = {{"a", TS_STOPPED}};
const std::map<int, int> int_keys = {{1, 2}};
CHECK(json(pairs) == json::parse(R"([["stopped",1]])"));
CHECK(json(string_keys) == json::parse(R"({"a":"stopped"})"));
CHECK(json(int_keys) == json::parse("[[1,2]]"));
}
SECTION("maps with non-unique keys are still stored as arrays of pairs")
{
const std::multimap<TaskState, int> mm = {{TS_STOPPED, 1}, {TS_STOPPED, 2}};
const std::unordered_multimap<TaskState, int, enum_hash> umm = {{TS_RUNNING, 3}, {TS_RUNNING, 3}};
CHECK(json(mm) == json::parse(R"([["stopped",1],["stopped",2]])"));
CHECK(json(umm) == json::parse(R"([["running",3],["running",3]])"));
}
SECTION("keys that do not serialize to strings")
{
const std::map<TaskState, int> null_key = {{TS_INVALID, 1}};
const std::map<digit, int> number_key = {{digit::zero, 1}};
json j = "unchanged";
// mapped to null
CHECK_THROWS_WITH_AS(j = null_key,
"[json.exception.type_error.302] type must be string, but is null", json::type_error&);
// mapped to a number
CHECK_THROWS_WITH_AS(j = number_key,
"[json.exception.type_error.302] type must be string, but is number", json::type_error&);
#ifndef SKIP_TESTS_FOR_ENUM_SERIALIZATION
// enum without NLOHMANN_JSON_SERIALIZE_ENUM
const std::map<plain, int> plain_key = {{plain::zero, 1}};
CHECK_THROWS_WITH_AS(j = plain_key,
"[json.exception.type_error.302] type must be string, but is number", json::type_error&);
#endif
CHECK(j == "unchanged");
}
SECTION("keys that serialize to the same string")
{
const std::map<color, int> m = {{color::red, 1}, {color::blue, 2}};
json j = "unchanged";
// color::blue is not mapped and falls back to "red"
CHECK_THROWS_WITH_AS(j = m,
"[json.exception.type_error.318] duplicate object key 'red'", json::type_error&);
CHECK(j == "unchanged");
}
}
DOCTEST_CLANG_SUPPRESS_WARNING_POP
-144
View File
@@ -1,144 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include "doctest_compatibility.h"
// This file tests maps with enum keys with the default setting of
// JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS (or whatever a -D flag sets it to).
// unit-enum_keyed_maps.cpp tests JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS=1.
// These tests are not part of unit-conversions.cpp, because that object file
// is already too big for the MinGW linker of some compilers.
#include <nlohmann/json.hpp>
using nlohmann::json;
#include <cstddef>
#include <functional>
#include <map>
#include <string>
#include <unordered_map>
// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
enum class cards {kreuz, pik, herz, karo};
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(cards,
{
{cards::kreuz, "kreuz"},
{cards::pik, "pik"},
{cards::herz, "herz"},
{cards::karo, "karo"}
})
enum TaskState // NOLINT(cert-int09-c,readability-enum-initial-value,cppcoreguidelines-use-enum-class)
{
TS_STOPPED,
TS_RUNNING,
TS_COMPLETED,
TS_INVALID = -1,
};
// NOLINTNEXTLINE(misc-const-correctness,misc-use-internal-linkage,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState,
{
{TS_INVALID, nullptr},
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"},
{TS_COMPLETED, "completed"},
})
enum class strict_cards {kreuz, pik, herz, karo, andere}; // andere not included in mapping
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(strict_cards,
{
{strict_cards::kreuz, "kreuz"},
{strict_cards::pik, "pik"},
{strict_cards::herz, "herz"},
{strict_cards::karo, "karo"}
})
namespace
{
// std::hash is only required for enums since C++14
struct enum_hash
{
template<typename T>
std::size_t operator()(T t) const noexcept
{
return static_cast<std::size_t>(t);
}
};
} // namespace
// see unit-enum_keyed_maps.cpp for JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS=1
TEST_CASE("maps with enum keys")
{
using task_map = std::map<TaskState, std::string>;
using task_umap = std::unordered_map<TaskState, std::string, enum_hash>;
using task_gmap = std::map<TaskState, std::string, std::greater<TaskState>>;
using nested_map = std::map<cards, std::map<TaskState, int>>;
using strict_map = std::map<strict_cards, int>;
using int_map = std::map<int, int>;
using int_umap = std::unordered_map<int, int>;
const task_map m = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
#if !JSON_USE_OBJECTS_FOR_ENUM_KEYED_MAPS
SECTION("stored as array of pairs")
{
CHECK(json(m) == json::parse(R"([["stopped","aa"],["completed","bb"]])"));
CHECK(json(task_umap {{TS_RUNNING, "cc"}}) == json::parse(R"([["running","cc"]])"));
}
#endif
SECTION("read from array of pairs")
{
CHECK(json::parse(R"([["stopped","aa"],["completed","bb"]])").get<task_map>() == m);
}
SECTION("read from object (#4378)")
{
const json j = json::parse(R"({"stopped":"aa","completed":"bb"})");
CHECK(j.get<task_map>() == m);
CHECK(j.get<task_umap>() == task_umap(m.begin(), m.end()));
CHECK(j.get<task_gmap>() == task_gmap(m.begin(), m.end()));
CHECK(json::parse(R"({"kreuz":{"stopped":1}})").get<nested_map>() == nested_map {{cards::kreuz, {{TS_STOPPED, 1}}}});
CHECK(nlohmann::ordered_json::parse(R"({"stopped":"aa","completed":"bb"})").get<task_map>() == m);
// object keys go through the enum's from_json
strict_map sm;
CHECK_THROWS_WITH_AS(json::parse(R"({"what?":1})").get_to(sm),
"[json.exception.out_of_range.410] enum value out of range for strict_cards: \"what?\"", json::out_of_range&);
}
SECTION("objects are only read for enum keys")
{
// built rather than parsed, so that the messages do not gain a byte
// range with JSON_DIAGNOSTIC_POSITIONS
const json j = {{"1", 2}};
int_map im;
int_umap ium;
CHECK_THROWS_WITH_AS(j.get_to(im),
"[json.exception.type_error.302] type must be array, but is object", json::type_error&);
CHECK_THROWS_WITH_AS(j.get_to(ium),
"[json.exception.type_error.302] type must be array, but is object", json::type_error&);
}
SECTION("other types are rejected")
{
task_map tm;
CHECK_THROWS_WITH_AS(json("stopped").get_to(tm),
"[json.exception.type_error.302] type must be array, but is string", json::type_error&);
}
}
DOCTEST_CLANG_SUPPRESS_WARNING_POP
+1 -1
View File
@@ -20,7 +20,7 @@ if __name__ == '__main__':
namespaces = ['nlohmann']
abi_prefix = 'json_abi'
abi_tags = ['_diag', '_ldvcmp', '_dp', '_bics', '_psp', '_snul', '_ekmo']
abi_tags = ['_diag', '_ldvcmp', '_dp', '_bics', '_psp', '_snul']
version = '_v' + args.version.replace('.', '_')
inline_namespaces = []