mirror of
https://github.com/nlohmann/json.git
synced 2026-10-08 15:37:13 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f57dbdc1e8 | ||
|
|
e7fe98180e |
No files matched your search
@@ -31,51 +31,6 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --target ci_test_gcc
|
run: cmake --build build --target ci_test_gcc
|
||||||
|
|
||||||
ci_meson_install:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
- name: Get latest CMake and ninja
|
|
||||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
|
||||||
- name: Check that Meson and pkg-config offer the CMake options
|
|
||||||
run: make check_build_options
|
|
||||||
- name: Install Meson
|
|
||||||
run: pip install meson
|
|
||||||
- name: Install with Meson
|
|
||||||
run: |
|
|
||||||
meson setup build-meson --prefix=${{ github.workspace }}/install
|
|
||||||
meson install -C build-meson
|
|
||||||
- name: Use the installed package with find_package
|
|
||||||
run: |
|
|
||||||
cmake -S tests/cmake_import/project -B build-import -DCMAKE_PREFIX_PATH=${{ github.workspace }}/install
|
|
||||||
cmake --build build-import
|
|
||||||
- name: Install with Meson and non-default options
|
|
||||||
run: |
|
|
||||||
meson setup build-meson-options --prefix=${{ github.workspace }}/install-options -DMultipleHeaders=true -DDiagnostics=true -DGlobalUDLs=false -DDisableTupleReferenceConversion=true -DStrictBinaryUTF8=true -DDeleteDeprecatedFunctions=true
|
|
||||||
meson install -C build-meson-options
|
|
||||||
- name: Check that the options reach the installed files
|
|
||||||
run: |
|
|
||||||
test -d install-options/include/nlohmann/detail
|
|
||||||
cflags=$(PKG_CONFIG_PATH=${{ github.workspace }}/install-options/share/pkgconfig pkg-config --cflags nlohmann_json)
|
|
||||||
echo "$cflags"
|
|
||||||
echo "$cflags" | grep -q -- '-DJSON_DIAGNOSTICS=1'
|
|
||||||
echo "$cflags" | grep -q -- '-DJSON_USE_GLOBAL_UDLS=0'
|
|
||||||
echo "$cflags" | grep -q -- '-DJSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1'
|
|
||||||
echo "$cflags" | grep -q -- '-DJSON_STRICT_BINARY_UTF8=1'
|
|
||||||
echo "$cflags" | grep -q -- '-DJSON_DELETE_DEPRECATED_FUNCTIONS=1'
|
|
||||||
grep -q 'JSON_USE_GLOBAL_UDLS=0;JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1;JSON_DIAGNOSTICS=1' install-options/share/cmake/nlohmann_json/nlohmann_jsonTargets.cmake
|
|
||||||
grep -q 'JSON_STRICT_BINARY_UTF8=1;JSON_DELETE_DEPRECATED_FUNCTIONS=1' install-options/share/cmake/nlohmann_json/nlohmann_jsonTargets.cmake
|
|
||||||
cmake -S tests/cmake_import/project -B build-import-options -DCMAKE_PREFIX_PATH=${{ github.workspace }}/install-options
|
|
||||||
cmake --build build-import-options
|
|
||||||
- name: Install with Meson and the include directory outside the prefix
|
|
||||||
run: |
|
|
||||||
meson setup build-meson-split --prefix=${{ github.workspace }}/install-split --includedir=${{ github.workspace }}/install-split-dev/include
|
|
||||||
meson install -C build-meson-split
|
|
||||||
cmake -S tests/cmake_import/project -B build-import-split -DCMAKE_PREFIX_PATH=${{ github.workspace }}/install-split
|
|
||||||
cmake --build build-import-split
|
|
||||||
|
|
||||||
ci_infer:
|
ci_infer:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
+1
-33
@@ -189,39 +189,7 @@ if (MSVC)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Install a pkg-config file, so other tools can find this. It carries the same
|
# Install a pkg-config file, so other tools can find this.
|
||||||
# compile definitions as the target above.
|
|
||||||
set(NLOHMANN_JSON_PKGCONFIG_CFLAGS "")
|
|
||||||
if (NOT JSON_GlobalUDLs)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_USE_GLOBAL_UDLS=0")
|
|
||||||
endif()
|
|
||||||
if (NOT JSON_ImplicitConversions)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_USE_IMPLICIT_CONVERSIONS=0")
|
|
||||||
endif()
|
|
||||||
if (JSON_DisableEnumSerialization)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_DISABLE_ENUM_SERIALIZATION=1")
|
|
||||||
endif()
|
|
||||||
if (JSON_DisableTupleReferenceConversion)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1")
|
|
||||||
endif()
|
|
||||||
if (JSON_Diagnostics)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_DIAGNOSTICS=1")
|
|
||||||
endif()
|
|
||||||
if (JSON_Diagnostic_Positions)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_DIAGNOSTIC_POSITIONS=1")
|
|
||||||
endif()
|
|
||||||
if (JSON_LegacyDiscardedValueComparison)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1")
|
|
||||||
endif()
|
|
||||||
if (JSON_StrictNulHandling)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_STRICT_NUL_HANDLING=1")
|
|
||||||
endif()
|
|
||||||
if (JSON_StrictBinaryUTF8)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_STRICT_BINARY_UTF8=1")
|
|
||||||
endif()
|
|
||||||
if (JSON_DeleteDeprecatedFunctions)
|
|
||||||
string(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -DJSON_DELETE_DEPRECATED_FUNCTIONS=1")
|
|
||||||
endif()
|
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
|
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
|
||||||
|
|||||||
@@ -249,31 +249,9 @@ make BUILD.bazel
|
|||||||
|
|
||||||
The "Check amalgamation" workflow fails if the file is out of date.
|
The "Check amalgamation" workflow fails if the file is out of date.
|
||||||
|
|
||||||
### `meson.build` and `meson_options.txt`
|
### `meson.build`
|
||||||
|
|
||||||
Meson build definitions suitable for use as a subproject ("wrap" in Meson terminology).
|
The build definition for the [Meson](https://mesonbuild.com) build system.
|
||||||
|
|
||||||
Projects wishing to use the wrap can execute:
|
|
||||||
```sh
|
|
||||||
meson wrap install nlohmann_json
|
|
||||||
```
|
|
||||||
|
|
||||||
Which allows Meson to build from source when a system provided dependency isn't available.
|
|
||||||
|
|
||||||
To build directly:
|
|
||||||
```sh
|
|
||||||
meson setup builddir
|
|
||||||
ninja -C builddir
|
|
||||||
```
|
|
||||||
|
|
||||||
`meson_options.txt` defines the options, which mirror the CMake options that change the library's target (for example,
|
|
||||||
`-DDiagnostics=true`). Meson requires this file next to `meson.build`, so it is also part of `include.zip`. `make check_build_options`
|
|
||||||
([`tools/check_build_options`](tools/check_build_options/README.md)) checks in CI that both files and the pkg-config files
|
|
||||||
stay in sync with the CMake options.
|
|
||||||
|
|
||||||
When installing, `meson.build` installs the headers, a pkg-config file, and the CMake package config files, so that
|
|
||||||
`find_package(nlohmann_json)` works. As Meson cannot generate `nlohmann_jsonTargets.cmake` itself, it is created from
|
|
||||||
the template `cmake/nlohmann_jsonTargets.cmake.in`, which is only used by Meson.
|
|
||||||
|
|
||||||
### `Package.swift`
|
### `Package.swift`
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check check_build_options
|
.PHONY: pretty clean ChangeLog.md release update_hedley update_hedley_undef BUILD.bazel natvis macro_builder_check
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
# configuration
|
# configuration
|
||||||
@@ -127,10 +127,6 @@ macro_builder_check:
|
|||||||
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/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)
|
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 that the Meson build and the pkg-config files offer the options of the CMake target
|
|
||||||
check_build_options:
|
|
||||||
python3 tools/check_build_options/check_build_options.py .
|
|
||||||
|
|
||||||
# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources
|
# check if file single_include/nlohmann/json.hpp has been amalgamated from the nlohmann sources
|
||||||
check-amalgamation:
|
check-amalgamation:
|
||||||
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~
|
@mv $(AMALGAMATED_FILE) $(AMALGAMATED_FILE)~
|
||||||
@@ -188,7 +184,7 @@ json.tar.xz:
|
|||||||
# We use `-X` to make the resulting ZIP file reproducible, see
|
# We use `-X` to make the resulting ZIP file reproducible, see
|
||||||
# <https://content.pivotal.io/blog/barriers-to-deterministic-reproducible-zip-files>.
|
# <https://content.pivotal.io/blog/barriers-to-deterministic-reproducible-zip-files>.
|
||||||
include.zip: BUILD.bazel
|
include.zip: BUILD.bazel
|
||||||
zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel MODULE.bazel meson.build meson_options.txt LICENSE.MIT
|
zip -9 --recurse-paths -X include.zip $(SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) $(AMALGAMATED_LITERALS_FILE) BUILD.bazel MODULE.bazel meson.build LICENSE.MIT
|
||||||
|
|
||||||
# Create the files for a release and add signatures and hashes.
|
# Create the files for a release and add signatures and hashes.
|
||||||
release: include.zip json.tar.xz
|
release: include.zip json.tar.xz
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
# Imported target for installations made with Meson (see meson.build).
|
|
||||||
#
|
|
||||||
# CMake installations generate this file with install(EXPORT ...). Meson cannot
|
|
||||||
# do that, but as the library is header-only, the target only needs an include
|
|
||||||
# directory, the C++ standard, and the compile definitions of the options that
|
|
||||||
# differ from their defaults. Paths are computed relative to this file so that
|
|
||||||
# the installation can be relocated (e.g., into a sysroot), unless includedir or
|
|
||||||
# datadir is outside the prefix.
|
|
||||||
|
|
||||||
if(TARGET @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_CONFIG_TO_PREFIX@" ABSOLUTE)
|
|
||||||
# As in CMake's generated file: avoid "//include" for an installation to "/".
|
|
||||||
if(_IMPORT_PREFIX STREQUAL "/")
|
|
||||||
set(_IMPORT_PREFIX "")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(@PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@ INTERFACE IMPORTED)
|
|
||||||
set_target_properties(@PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES
|
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "@NLOHMANN_JSON_INCLUDE_DIR@"
|
|
||||||
)
|
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.8)
|
|
||||||
set_target_properties(@PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES
|
|
||||||
INTERFACE_COMPILE_FEATURES cxx_range_for
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
set_target_properties(@PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES
|
|
||||||
INTERFACE_COMPILE_FEATURES cxx_std_11
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(_NLOHMANN_JSON_COMPILE_DEFINITIONS "@NLOHMANN_JSON_COMPILE_DEFINITIONS@")
|
|
||||||
if(_NLOHMANN_JSON_COMPILE_DEFINITIONS)
|
|
||||||
set_target_properties(@PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES
|
|
||||||
INTERFACE_COMPILE_DEFINITIONS "${_NLOHMANN_JSON_COMPILE_DEFINITIONS}"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
unset(_NLOHMANN_JSON_COMPILE_DEFINITIONS)
|
|
||||||
unset(_IMPORT_PREFIX)
|
|
||||||
@@ -4,4 +4,4 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
|||||||
Name: @PROJECT_NAME@
|
Name: @PROJECT_NAME@
|
||||||
Description: JSON for Modern C++
|
Description: JSON for Modern C++
|
||||||
Version: @PROJECT_VERSION@
|
Version: @PROJECT_VERSION@
|
||||||
Cflags: -I${includedir}@NLOHMANN_JSON_PKGCONFIG_CFLAGS@
|
Cflags: -I${includedir}
|
||||||
@@ -67,7 +67,7 @@ By default, implicit conversions are enabled.
|
|||||||
`JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`:
|
`JSON_USE_IMPLICIT_CONVERSIONS` is defined to `0`:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
using wjson = nlohmann::json::with_string_t<std::wstring>;
|
using wjson = nlohmann::basic_json<std::map, std::vector, std::wstring>;
|
||||||
|
|
||||||
void load(const nlohmann::json& j);
|
void load(const nlohmann::json& j);
|
||||||
|
|
||||||
|
|||||||
@@ -36,13 +36,26 @@ work items are tracked in the [GitHub milestones](https://github.com/nlohmann/js
|
|||||||
## API stability
|
## API stability
|
||||||
|
|
||||||
Releases follow [semantic versioning](https://semver.org): a minor or patch release of version 3.x does not break code
|
Releases follow [semantic versioning](https://semver.org): a minor or patch release of version 3.x does not break code
|
||||||
that uses the public API. In particular, a 3.x release does not:
|
that uses the public API, unless that code opts in to a change with a macro as described [below](#version-40). In
|
||||||
|
particular, a 3.x release does not:
|
||||||
|
|
||||||
- change the signature of a function (its parameter types, return type, number of parameters, or the const-ness of a
|
- make breaking changes to the signature of a function: the types or order of its existing parameters, its return type,
|
||||||
member function);
|
its `noexcept` or `constexpr` specifier, or the const-ness of a member function. New parameters may be added if they
|
||||||
- remove or rename a function or class;
|
have a default value;
|
||||||
|
- remove or rename a function or class, or change the template parameters of a public class template;
|
||||||
- change which exceptions a function throws, or the [exception ids](../home/exceptions.md);
|
- change which exceptions a function throws, or the [exception ids](../home/exceptions.md);
|
||||||
- change access specifiers or default arguments.
|
- change access specifiers, or change or remove existing default arguments. New default arguments may be added;
|
||||||
|
- change the JSON type that a valid input parses to, or the text that `dump()` produces for a valid value;
|
||||||
|
- accept input that was rejected before, or reject input that was accepted before;
|
||||||
|
- change the order in which the keys of an object are iterated. The default type sorts keys, and
|
||||||
|
[`ordered_json`](../api/ordered_json.md) keeps insertion order;
|
||||||
|
- change when iterators, pointers, or references are invalidated, or the state of a moved-from `basic_json`;
|
||||||
|
- add or remove implicit conversions from `basic_json`;
|
||||||
|
- change how `to_json` and `from_json` functions are found, or the behavior of
|
||||||
|
[`adl_serializer`](../api/adl_serializer/index.md);
|
||||||
|
- add pure virtual functions to the [`json_sax`](../api/json_sax/index.md) interface;
|
||||||
|
- remove, rename, renumber, or add enumerators of `value_t`;
|
||||||
|
- remove or rename a documented macro, CMake option, CMake target, or header, or change what a documented macro does.
|
||||||
|
|
||||||
Exceptions to these rules, for instance when fixing a bug requires changing the exception a function throws, are
|
Exceptions to these rules, for instance when fixing a bug requires changing the exception a function throws, are
|
||||||
documented in the [release notes](../home/releases.md).
|
documented in the [release notes](../home/releases.md).
|
||||||
@@ -51,13 +64,14 @@ The following are **not** part of the public API and may change in any release,
|
|||||||
|
|
||||||
- The text of exception messages returned by `what()`. Use the [exception id](../home/exceptions.md) to tell errors
|
- The text of exception messages returned by `what()`. Use the [exception id](../home/exceptions.md) to tell errors
|
||||||
apart.
|
apart.
|
||||||
- The ABI, including `sizeof(basic_json)` and the memory layout of its values. Recompile your code when you upgrade the
|
- The ABI, including `sizeof(basic_json)` and the memory layout of its values. The
|
||||||
library. The [versioned inline namespace](../features/namespace.md) turns mixing versions into a link error.
|
[versioned inline namespace](../features/namespace.md) turns mixing versions into a link error.
|
||||||
|
- The hash values returned by `std::hash` for `basic_json`. Numbers that compare equal still hash equally.
|
||||||
- Everything in namespace `nlohmann::detail`, and macros and type traits that are not documented in the
|
- Everything in namespace `nlohmann::detail`, and macros and type traits that are not documented in the
|
||||||
[API reference](../api/basic_json/index.md).
|
[API reference](../api/basic_json/index.md).
|
||||||
|
|
||||||
Changes that would break the public API are only added behind a macro whose default keeps the 3.x behavior, see
|
Breaking changes are only added behind a macro whose default keeps the 3.x behavior. See [Version 4.0](#version-40) and
|
||||||
[Version 4.0](#version-40).
|
the [macro overview](../features/macros.md).
|
||||||
|
|
||||||
## Version 4.0
|
## Version 4.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "custom_array_type.hpp"
|
#include "custom_array_type.hpp"
|
||||||
|
|
||||||
using custom_json = nlohmann::json::with_array_t<custom_array_type>;
|
using custom_json = nlohmann::basic_json<std::map, custom_array_type>;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "custom_binary_type.hpp"
|
#include "custom_binary_type.hpp"
|
||||||
|
|
||||||
using custom_json = nlohmann::json::with_binary_t<custom_binary_type>;
|
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool,
|
||||||
|
std::int64_t, std::uint64_t, double, std::allocator,
|
||||||
|
nlohmann::adl_serializer, custom_binary_type>;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "custom_object_type.hpp"
|
#include "custom_object_type.hpp"
|
||||||
|
|
||||||
using custom_json = nlohmann::json::with_object_t<custom_object_type>;
|
using custom_json = nlohmann::basic_json<custom_object_type, std::vector>;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "custom_string_type.hpp"
|
#include "custom_string_type.hpp"
|
||||||
|
|
||||||
using custom_json = nlohmann::json::with_string_t<custom_string_type>;
|
using custom_json = nlohmann::basic_json<std::map, std::vector, custom_string_type>;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -351,8 +351,9 @@ The number types can be changed with template parameters.
|
|||||||
|
|
||||||
A `basic_json` type that uses `#!c long double` as floating-point type.
|
A `basic_json` type that uses `#!c long double` as floating-point type.
|
||||||
|
|
||||||
```cpp hl_lines="1"
|
```cpp hl_lines="2"
|
||||||
using json_ld = nlohmann::json::with_float_t<long double>;
|
using json_ld = nlohmann::basic_json<std::map, std::vector, std::string, bool,
|
||||||
|
std::int64_t, std::uint64_t, long double>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Note values should then be parsed with `json_ld::parse` rather than `json::parse` as the latter would parse
|
Note values should then be parsed with `json_ld::parse` rather than `json::parse` as the latter would parse
|
||||||
|
|||||||
@@ -8,10 +8,6 @@ these requirements so they do not have to be discovered by trial and error. Each
|
|||||||
that are known to work for that parameter and the ones that do not, checked against Boost 1.83, Abseil 20250127.0,
|
that are known to work for that parameter and the ones that do not, checked against Boost 1.83, Abseil 20250127.0,
|
||||||
Folly, EASTL 3.21, `ankerl::unordered_dense`, `phmap`, `gtl`, `robin_hood`, `tsl::ordered_map`, and Qt 6.
|
Folly, EASTL 3.21, `ankerl::unordered_dense`, `phmap`, `gtl`, `robin_hood`, `tsl::ordered_map`, and Qt 6.
|
||||||
|
|
||||||
To change a single template parameter and keep the others, use the member alias templates
|
|
||||||
[`with_*_t`](../../api/basic_json/with_t.md); for instance, `nlohmann::json::with_float_t<long double>` is `json` with
|
|
||||||
`#!cpp long double` as [`number_float_t`](../../api/basic_json/number_float_t.md).
|
|
||||||
|
|
||||||
## How to read this page
|
## How to read this page
|
||||||
|
|
||||||
Requirements are split into two groups:
|
Requirements are split into two groups:
|
||||||
@@ -147,7 +143,7 @@ struct unordered_map_object
|
|||||||
using base_t::base_t;
|
using base_t::base_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
using unordered_json = nlohmann::json::with_object_t<unordered_map_object>;
|
using unordered_json = nlohmann::basic_json<unordered_map_object>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Whether `#!cpp std::unordered_map` can be instantiated at all depends on the standard library: `object_t` is formed
|
Whether `#!cpp std::unordered_map` can be instantiated at all depends on the standard library: `object_t` is formed
|
||||||
@@ -180,7 +176,7 @@ struct flat_hash_object
|
|||||||
using base_t::base_t;
|
using base_t::base_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
using flat_hash_json = nlohmann::json::with_object_t<flat_hash_object>;
|
using flat_hash_json = nlohmann::basic_json<flat_hash_object>;
|
||||||
```
|
```
|
||||||
|
|
||||||
`absl::node_hash_map` keeps references to the mapped values valid across insertions; `absl::flat_hash_map` does not,
|
`absl::node_hash_map` keeps references to the mapped values valid across insertions; `absl::flat_hash_map` does not,
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ function to use instead.
|
|||||||
=== "Deprecated"
|
=== "Deprecated"
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
using my_json = nlohmann::json::with_string_t<my_string_type>;
|
using my_json = nlohmann::basic_json<std::map, std::vector, my_string_type>;
|
||||||
nlohmann::json_pointer<my_json> ptr("/foo/bar/1");
|
nlohmann::json_pointer<my_json> ptr("/foo/bar/1");
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -125,24 +125,10 @@ meson wrap install nlohmann_json
|
|||||||
Please see the Meson project for any issues regarding the packaging.
|
Please see the Meson project for any issues regarding the packaging.
|
||||||
|
|
||||||
The provided `meson.build` can also be used as an alternative to CMake for installing `nlohmann_json` system-wide in
|
The provided `meson.build` can also be used as an alternative to CMake for installing `nlohmann_json` system-wide in
|
||||||
which case a [pkg-config](pkg-config.md) file and the CMake package config files are installed. To use it, have your build system require
|
which case a [pkg-config](pkg-config.md) file is installed. To use it, have your build system require the
|
||||||
the `nlohmann_json` pkg-config dependency, or use [`find_package(nlohmann_json)`](cmake.md#external) in CMake. In Meson,
|
`nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the
|
||||||
it is preferred to use the [`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a
|
[`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than
|
||||||
subproject fallback, rather than using the subproject directly.
|
using the subproject directly.
|
||||||
|
|
||||||
The options that change the library's configuration are available in Meson as well, named like the
|
|
||||||
[CMake options](cmake.md#cmake-options) without the `JSON_` prefix: `MultipleHeaders`, `GlobalUDLs`,
|
|
||||||
`ImplicitConversions`, `DisableEnumSerialization`, `DisableTupleReferenceConversion`, `Diagnostics`,
|
|
||||||
`Diagnostic_Positions`, `LegacyDiscardedValueComparison`, `StrictNulHandling`, `StrictBinaryUTF8`, and
|
|
||||||
`DeleteDeprecatedFunctions`. They have the same defaults as in CMake, except that
|
|
||||||
`MultipleHeaders` is `false`. Set them with `-D` when setting up the build, or with the subproject name as prefix when
|
|
||||||
the library is used as a subproject:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
meson setup build -Dnlohmann_json:Diagnostics=true
|
|
||||||
```
|
|
||||||
|
|
||||||
The resulting compile definitions are part of the Meson dependency, the pkg-config file, and the CMake target.
|
|
||||||
|
|
||||||
??? example "Example: Wrap"
|
??? example "Example: Wrap"
|
||||||
|
|
||||||
|
|||||||
@@ -9,15 +9,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint> // uint64_t
|
#include <cstdint> // uint64_t
|
||||||
#if !defined(__SIZEOF_INT128__) && defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
|
|
||||||
#include <intrin0.h> // __umulh, _umul128
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <nlohmann/detail/abi_macros.hpp>
|
#include <nlohmann/detail/abi_macros.hpp>
|
||||||
|
|
||||||
// Portable bit-level helpers for the number and string scanners. They use
|
// Portable bit-level helpers for the number and string scanners. They use
|
||||||
// compiler builtins or platform-specific intrinsics where available and plain
|
// compiler builtins where available and plain C++ otherwise, so they need no
|
||||||
// C++ otherwise, so they work regardless of byte order.
|
// platform headers and work regardless of byte order.
|
||||||
|
|
||||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
namespace detail
|
namespace detail
|
||||||
@@ -55,12 +52,6 @@ inline uint128_parts full_multiplication(std::uint64_t a, std::uint64_t b) noexc
|
|||||||
__extension__ using uint128 = unsigned __int128;
|
__extension__ using uint128 = unsigned __int128;
|
||||||
const uint128 r = static_cast<uint128>(a) * b;
|
const uint128 r = static_cast<uint128>(a) * b;
|
||||||
return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)};
|
return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)};
|
||||||
#elif defined(_MSC_VER) && defined(_M_X64)
|
|
||||||
std::uint64_t high = 0;
|
|
||||||
const std::uint64_t low = _umul128(a, b, &high);
|
|
||||||
return {low, high};
|
|
||||||
#elif defined(_MSC_VER) && defined(_M_ARM64)
|
|
||||||
return {a * b, __umulh(a, b)};
|
|
||||||
#else
|
#else
|
||||||
const std::uint64_t a_lo = a & 0xFFFFFFFFu;
|
const std::uint64_t a_lo = a & 0xFFFFFFFFu;
|
||||||
const std::uint64_t a_hi = a >> 32u;
|
const std::uint64_t a_hi = a >> 32u;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("null", j);
|
JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
n = nullptr;
|
n = nullptr;
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
|||||||
case value_t::binary:
|
case value_t::binary:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
throw_type_must_be("number", j);
|
JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t&
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("boolean", j);
|
JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t&
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("string", j);
|
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ inline void from_json(const BasicJsonType& j, StringType& s)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("string", j);
|
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
@@ -183,7 +183,7 @@ inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("array", j);
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
l.clear();
|
l.clear();
|
||||||
std::transform(j.rbegin(), j.rend(),
|
std::transform(j.rbegin(), j.rend(),
|
||||||
@@ -200,7 +200,7 @@ inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("array", j);
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
l.resize(j.size());
|
l.resize(j.size());
|
||||||
std::transform(j.begin(), j.end(), std::begin(l),
|
std::transform(j.begin(), j.end(), std::begin(l),
|
||||||
@@ -305,7 +305,7 @@ void())
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("array", j);
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
from_json_array_impl(j, arr, priority_tag<3> {});
|
from_json_array_impl(j, arr, priority_tag<3> {});
|
||||||
@@ -324,7 +324,7 @@ auto from_json(const BasicJsonType& j, identity_tag<std::array<T, N>> tag)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("array", j);
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
return from_json_inplace_array_impl(j, tag, make_index_sequence<N> {});
|
return from_json_inplace_array_impl(j, tag, make_index_sequence<N> {});
|
||||||
@@ -335,7 +335,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t&
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("binary", j);
|
JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
|
||||||
@@ -356,7 +356,7 @@ inline void from_json(const BasicJsonType& j, CompatibleArrayType& bin)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw_type_must_be("binary or array", j);
|
JSON_THROW(type_error::create(302, concat("type must be binary or array, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +377,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("object", j);
|
JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstructibleObjectType ret;
|
ConstructibleObjectType ret;
|
||||||
@@ -432,7 +432,7 @@ inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
|||||||
case value_t::binary:
|
case value_t::binary:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
throw_type_must_be("number", j);
|
JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +504,7 @@ auto from_json(const BasicJsonType& j, TupleRelated&& t)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("array", j);
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
return from_json_tuple_impl(j, std::forward<TupleRelated>(t), priority_tag<3> {});
|
return from_json_tuple_impl(j, std::forward<TupleRelated>(t), priority_tag<3> {});
|
||||||
@@ -517,14 +517,14 @@ void from_json_pair_array_to_map(const BasicJsonType& j, MapType& m)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("array", j);
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
m.clear();
|
m.clear();
|
||||||
for (const auto& p : j)
|
for (const auto& p : j)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("array", p);
|
JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &p));
|
||||||
}
|
}
|
||||||
m.emplace(p.at(0).template get<typename MapType::key_type>(), p.at(1).template get<typename MapType::mapped_type>());
|
m.emplace(p.at(0).template get<typename MapType::key_type>(), p.at(1).template get<typename MapType::mapped_type>());
|
||||||
}
|
}
|
||||||
@@ -591,7 +591,7 @@ inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("string", j);
|
JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
|
||||||
// Checking for C++20 standard or later can be insufficient in case the
|
// Checking for C++20 standard or later can be insufficient in case the
|
||||||
|
|||||||
@@ -414,13 +414,13 @@ inline void to_json(BasicJsonType& j, const EnumKeyedMap& map)
|
|||||||
BasicJsonType key = p.first;
|
BasicJsonType key = p.first;
|
||||||
if (JSON_HEDLEY_UNLIKELY(!key.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(!key.is_string()))
|
||||||
{
|
{
|
||||||
throw_type_must_be("string", key);
|
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*>();
|
auto& key_string = *key.template get_ptr<typename BasicJsonType::string_t*>();
|
||||||
if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second))
|
if (JSON_HEDLEY_UNLIKELY(!obj.emplace(key_string, BasicJsonType(p.second)).second))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(exception_id::enum_key_duplicate, concat("duplicate object key '", key_string, "'"), &key));
|
JSON_THROW(type_error::create(318, concat("duplicate object key '", key_string, "'"), &key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
external_constructor<value_t::object>::construct(j, std::move(obj));
|
external_constructor<value_t::object>::construct(j, std::move(obj));
|
||||||
|
|||||||
@@ -45,84 +45,6 @@ namespace detail
|
|||||||
// exceptions //
|
// exceptions //
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief the ids of the exceptions thrown by the library
|
|
||||||
@note The values are part of the public API: they are the `id` member of the
|
|
||||||
exceptions and appear in their `what()` messages.
|
|
||||||
@sa https://json.nlohmann.me/home/exceptions/
|
|
||||||
*/
|
|
||||||
enum class exception_id : int
|
|
||||||
{
|
|
||||||
// parse_error
|
|
||||||
syntax_error = 101, ///< unexpected token or invalid literal while parsing JSON
|
|
||||||
patch_not_an_array = 104, ///< a JSON Patch document is not an array of objects
|
|
||||||
patch_invalid_operation = 105, ///< a JSON Patch operation is malformed
|
|
||||||
pointer_index_leading_zero = 106, ///< a JSON Pointer array index has a leading zero
|
|
||||||
pointer_missing_slash = 107, ///< a JSON Pointer does not start with '/'
|
|
||||||
pointer_invalid_escape = 108, ///< a JSON Pointer contains an escape other than ~0 and ~1
|
|
||||||
pointer_index_not_a_number = 109, ///< a JSON Pointer array index is not a number
|
|
||||||
unexpected_end_of_input = 110, ///< a binary input ends early, or has bytes left at its end
|
|
||||||
unexpected_byte = 112, ///< a binary input contains an unexpected byte or invalid length
|
|
||||||
invalid_string_or_size = 113, ///< a binary input contains an invalid string or size specification
|
|
||||||
bson_unsupported_type = 114, ///< a BSON record type is not supported
|
|
||||||
invalid_high_precision_number = 115, ///< a UBJSON/BJData high-precision number cannot be parsed
|
|
||||||
// invalid_iterator
|
|
||||||
iterators_incompatible = 201, ///< the iterators of a range belong to different values
|
|
||||||
iterator_from_other_value = 202, ///< an iterator does not belong to the value it is used with
|
|
||||||
iterator_range_from_other_value = 203, ///< an iterator range does not belong to the value it is used with
|
|
||||||
iterator_range_out_of_range = 204, ///< an iterator range of a primitive value is not [begin, end)
|
|
||||||
iterator_out_of_range = 205, ///< an iterator of a primitive value is not begin()
|
|
||||||
iterator_range_of_null = 206, ///< an iterator range belongs to a null value
|
|
||||||
iterator_key_not_object = 207, ///< key() is called on an iterator of a non-object
|
|
||||||
iterator_subscript_on_object = 208, ///< operator[] is called on an iterator of an object
|
|
||||||
iterator_arithmetic_on_object = 209, ///< an offset operator is used on an iterator of an object
|
|
||||||
insert_range_incompatible = 210, ///< the iterators of an inserted range belong to different values
|
|
||||||
insert_range_into_itself = 211, ///< an inserted range belongs to the value it is inserted into
|
|
||||||
iterators_compare_different_values = 212, ///< iterators of different values are compared
|
|
||||||
iterator_order_on_object = 213, ///< iterators of an object are compared by order
|
|
||||||
iterator_value_unavailable = 214, ///< an iterator does not refer to a value
|
|
||||||
// type_error
|
|
||||||
object_from_non_pairs = 301, ///< an object is created from an initializer list that is not a list of pairs
|
|
||||||
type_mismatch = 302, ///< a value has the wrong type for a conversion
|
|
||||||
incompatible_reference_type = 303, ///< get_ref() is called with a reference type that does not match the value
|
|
||||||
at_wrong_type = 304, ///< at() is called on a value of the wrong type
|
|
||||||
subscript_wrong_type = 305, ///< operator[] is called on a value of the wrong type
|
|
||||||
value_wrong_type = 306, ///< value() is called on a value of the wrong type
|
|
||||||
erase_wrong_type = 307, ///< erase() is called on a value of the wrong type
|
|
||||||
push_back_wrong_type = 308, ///< push_back() or operator+= is called on a value of the wrong type
|
|
||||||
insert_wrong_type = 309, ///< insert() is called on a value of the wrong type
|
|
||||||
swap_wrong_type = 310, ///< swap() is called on a value of the wrong type
|
|
||||||
emplace_wrong_type = 311, ///< emplace() or emplace_back() is called on a value of the wrong type
|
|
||||||
update_wrong_type = 312, ///< update() is called on a value of the wrong type
|
|
||||||
unflatten_invalid_value = 313, ///< unflatten() finds conflicting paths
|
|
||||||
unflatten_not_object = 314, ///< unflatten() is called on a non-object
|
|
||||||
unflatten_value_not_primitive = 315, ///< unflatten() is called on an object with non-primitive values
|
|
||||||
invalid_utf8 = 316, ///< dump() finds a string that is not valid UTF-8
|
|
||||||
type_not_serializable = 317, ///< a value cannot be serialized to the requested binary format
|
|
||||||
enum_key_duplicate = 318, ///< an enum-keyed map has two keys that serialize to the same string
|
|
||||||
discarded_value_used = 321, ///< a discarded value is used
|
|
||||||
// out_of_range
|
|
||||||
array_index_out_of_range = 401, ///< an array index is out of range
|
|
||||||
pointer_past_the_end_index = 402, ///< a JSON Pointer uses the array index '-'
|
|
||||||
key_not_found = 403, ///< an object key is not found
|
|
||||||
pointer_unresolved = 404, ///< a JSON Pointer reference token cannot be resolved
|
|
||||||
patch_on_root = 405, ///< the root of a value has no parent, e.g. for a JSON Patch 'remove' or 'add' at the root
|
|
||||||
number_overflow = 406, ///< a number cannot be stored without overflowing to NaN or INF
|
|
||||||
integer_too_large = 407, ///< an integer cannot be represented in the binary format
|
|
||||||
container_too_large = 408, ///< the size of a container in a binary input exceeds the maximal capacity
|
|
||||||
bson_key_with_null = 409, ///< a BSON key contains U+0000
|
|
||||||
value_out_of_range = 410, ///< an enum value is undefined, or a JSON Pointer array index exceeds size_type
|
|
||||||
patch_add_parent_not_container = 411, ///< the parent of a JSON Patch 'add' target is not a container
|
|
||||||
length_too_large = 412, ///< a length does not fit into the length field of a binary format
|
|
||||||
patch_remove_parent_not_container = 413, ///< the parent of a JSON Patch 'remove' target is not a container
|
|
||||||
patch_move_into_child = 414, ///< a JSON Patch 'move' moves a value into one of its children
|
|
||||||
subtype_out_of_range = 415, ///< a binary subtype does not fit into one byte
|
|
||||||
// other_error
|
|
||||||
internal_error = 500, ///< unreachable code was reached
|
|
||||||
patch_test_failed = 501, ///< a JSON Patch 'test' operation failed
|
|
||||||
size_marker_required = 502 ///< UBJSON/BJData output with type markers requires size markers
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @brief general exception of the @ref basic_json class
|
/// @brief general exception of the @ref basic_json class
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/exception/
|
/// @sa https://json.nlohmann.me/api/basic_json/exception/
|
||||||
class exception : public std::exception
|
class exception : public std::exception
|
||||||
@@ -273,18 +195,6 @@ class parse_error : public exception
|
|||||||
return {id_, byte_, w.c_str()};
|
return {id_, byte_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
|
||||||
static parse_error create(exception_id id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
|
|
||||||
{
|
|
||||||
return create(static_cast<int>(id_), pos, what_arg, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
|
||||||
static parse_error create(exception_id id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
|
|
||||||
{
|
|
||||||
return create(static_cast<int>(id_), byte_, what_arg, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief byte index of the parse error
|
@brief byte index of the parse error
|
||||||
|
|
||||||
@@ -319,12 +229,6 @@ class invalid_iterator : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
|
||||||
static invalid_iterator create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
|
||||||
{
|
|
||||||
return create(static_cast<int>(id_), what_arg, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
invalid_iterator(int id_, const char* what_arg)
|
invalid_iterator(int id_, const char* what_arg)
|
||||||
@@ -343,12 +247,6 @@ class type_error : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
|
||||||
static type_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
|
||||||
{
|
|
||||||
return create(static_cast<int>(id_), what_arg, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
@@ -366,12 +264,6 @@ class out_of_range : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
|
||||||
static out_of_range create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
|
||||||
{
|
|
||||||
return create(static_cast<int>(id_), what_arg, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
@@ -389,12 +281,6 @@ class other_error : public exception
|
|||||||
return {id_, w.c_str()};
|
return {id_, w.c_str()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
|
|
||||||
static other_error create(exception_id id_, const std::string& what_arg, BasicJsonContext context)
|
|
||||||
{
|
|
||||||
return create(static_cast<int>(id_), what_arg, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSON_HEDLEY_NON_NULL(3)
|
JSON_HEDLEY_NON_NULL(3)
|
||||||
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
|
||||||
@@ -421,36 +307,6 @@ void templated_json_throw(ExceptionType exception)
|
|||||||
(void)exception;
|
(void)exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief throws because @a j does not have the type a conversion expects
|
|
||||||
@param[in] expected the expected type(s), e.g. "array" or "binary or array"
|
|
||||||
@param[in] j the value with the wrong type
|
|
||||||
@throw type_error.302 always
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
JSON_HEDLEY_NO_RETURN inline void throw_type_must_be(const char* expected, const BasicJsonType& j)
|
|
||||||
{
|
|
||||||
static_cast<void>(expected); // unused when JSON_NOEXCEPTION is defined
|
|
||||||
static_cast<void>(j);
|
|
||||||
JSON_THROW(type_error::create(exception_id::type_mismatch, concat("type must be ", expected, ", but is ", j.type_name()), &j));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief throws because an operation is not supported for the type of @a j
|
|
||||||
@param[in] id_ the id of the type_error exception (at_wrong_type..update_wrong_type)
|
|
||||||
@param[in] operation the operation, e.g. "erase()"
|
|
||||||
@param[in] j the value the operation was called on
|
|
||||||
@throw type_error always
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType>
|
|
||||||
JSON_HEDLEY_NO_RETURN inline void throw_cannot_use_with(const exception_id id_, const char* operation, const BasicJsonType& j)
|
|
||||||
{
|
|
||||||
static_cast<void>(id_); // unused when JSON_NOEXCEPTION is defined
|
|
||||||
static_cast<void>(operation);
|
|
||||||
static_cast<void>(j);
|
|
||||||
JSON_THROW(type_error::create(id_, concat("cannot use ", operation, " with ", j.type_name()), &j));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <cmath> // ldexp
|
#include <cmath> // ldexp
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t, uintmax_t
|
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t, uintmax_t
|
||||||
|
#include <cstdio> // snprintf
|
||||||
#include <cstring> // memcpy
|
#include <cstring> // memcpy
|
||||||
#include <iterator> // back_inserter
|
#include <iterator> // back_inserter
|
||||||
#include <limits> // numeric_limits
|
#include <limits> // numeric_limits
|
||||||
@@ -195,7 +196,8 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
|
if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_end_of_input, concat("expected end of input; last byte: 0x", get_token_string()), "value");
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
|
||||||
|
exception_message(concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +319,8 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast<std::size_t>(document_size) != chars_read - document_start))
|
if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast<std::size_t>(document_size) != chars_read - document_start))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document");
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("document size ", std::to_string(document_size), " does not match the number of bytes read (", std::to_string(chars_read - document_start), ")"), "document"), nullptr));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -509,7 +512,9 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(len < 1))
|
if (JSON_HEDLEY_UNLIKELY(len < 1))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, concat("string length must be at least 1, is ", std::to_string(len)), "string");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast<NumberType>(1), result)))
|
if (JSON_HEDLEY_UNLIKELY(!get_string(len - static_cast<NumberType>(1), result)))
|
||||||
@@ -519,7 +524,10 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(get() != 0x00))
|
if (JSON_HEDLEY_UNLIKELY(get() != 0x00))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, "BSON string is not null-terminated", "string");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message("BSON string is not null-terminated",
|
||||||
|
"string"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return check_string_utf8(result, "string");
|
return check_string_utf8(result, "string");
|
||||||
@@ -539,7 +547,9 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// All BSON binary values have a subtype
|
// All BSON binary values have a subtype
|
||||||
@@ -629,9 +639,11 @@ class binary_reader
|
|||||||
|
|
||||||
default: // anything else is not supported (yet)
|
default: // anything else is not supported (yet)
|
||||||
{
|
{
|
||||||
const std::string cr_str = hex_byte(static_cast<std::uint8_t>(element_type));
|
std::array<char, 3> cr{{}};
|
||||||
|
static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
const std::string cr_str{cr.data()};
|
||||||
return sax->parse_error(element_type_parse_position, cr_str,
|
return sax->parse_error(element_type_parse_position, cr_str,
|
||||||
parse_error::create(exception_id::bson_unsupported_type, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
|
parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -955,7 +967,9 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (tag_handler == cbor_tag_handler_t::error)
|
if (tag_handler == cbor_tag_handler_t::error)
|
||||||
{
|
{
|
||||||
return invalid_byte("value");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore and store: the tag value is already in the head, so
|
// ignore and store: the tag value is already in the head, so
|
||||||
@@ -975,7 +989,9 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
case cbor_tag_handler_t::error:
|
case cbor_tag_handler_t::error:
|
||||||
{
|
{
|
||||||
return invalid_byte("value");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
case cbor_tag_handler_t::ignore:
|
case cbor_tag_handler_t::ignore:
|
||||||
@@ -1049,7 +1065,9 @@ class binary_reader
|
|||||||
|
|
||||||
default: // anything else (0xFF is handled inside the other types)
|
default: // anything else (0xFF is handled inside the other types)
|
||||||
{
|
{
|
||||||
return invalid_byte("value");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1062,7 +1080,10 @@ class binary_reader
|
|||||||
*/
|
*/
|
||||||
bool cbor_indefinite_string_error(const char* type_name, const char* context)
|
bool cbor_indefinite_string_error(const char* type_name, const char* context)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, concat("indefinite-length ", type_name, " is not allowed inside indefinite-length ", type_name, "; last byte: 0x", get_token_string()), context);
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message(concat("indefinite-length ", type_name,
|
||||||
|
" is not allowed inside indefinite-length ", type_name, "; last byte: 0x", last_token), context), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1139,7 +1160,9 @@ class binary_reader
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", get_token_string()), "string");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message(concat("expected length specification (0x60-0x7B)", inside_indefinite ? "" : " or indefinite string type (0x7F)", "; last byte: 0x", last_token), "string"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1269,7 +1292,9 @@ class binary_reader
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1350,7 +1375,9 @@ class binary_reader
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", get_token_string()), "binary");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message(concat("expected length specification (0x40-0x5B)", inside_indefinite ? "" : " or indefinite binary array type (0x5F)", "; last byte: 0x", last_token), "binary"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1496,7 +1523,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
|
||||||
exception_message(concat("excessive ", context, " size"), "size"), nullptr));
|
exception_message(concat("excessive ", context, " size"), "size"), nullptr));
|
||||||
}
|
}
|
||||||
result = conditional_static_cast<std::size_t>(len);
|
result = conditional_static_cast<std::size_t>(len);
|
||||||
@@ -1984,7 +2011,9 @@ class binary_reader
|
|||||||
|
|
||||||
default: // anything else
|
default: // anything else
|
||||||
{
|
{
|
||||||
return invalid_byte("value");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("invalid byte: 0x", last_token), "value"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2065,7 +2094,9 @@ class binary_reader
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", get_token_string()), "string");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message(concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2157,7 +2188,9 @@ class binary_reader
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, concat("only string keys are supported, but found ", found, "; last byte: 0x", get_token_string()), "object key");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message(concat("only string keys are supported, but found ", found, "; last byte: 0x", last_token), "object key"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -2466,7 +2499,8 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, "string length must not be negative", "string");
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
||||||
|
exception_message("string length must not be negative", "string"), nullptr));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2566,7 +2600,18 @@ class binary_reader
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return length_type_error("", "string");
|
auto last_token = get_token_string();
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
if (input_format != input_format_t::bjdata)
|
||||||
|
{
|
||||||
|
message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
|
||||||
|
}
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "string"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -2651,11 +2696,12 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(number < 0))
|
if (JSON_HEDLEY_UNLIKELY(number < 0))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, "count in an optimized container must be positive", "size");
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
||||||
|
exception_message("count in an optimized container must be positive", "size"), nullptr));
|
||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(number)))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(number)))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
|
||||||
exception_message("integer value overflow", "size"), nullptr));
|
exception_message("integer value overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
||||||
@@ -2753,7 +2799,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (!value_in_range_of<std::size_t>(number))
|
if (!value_in_range_of<std::size_t>(number))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
|
||||||
exception_message("integer value overflow", "size"), nullptr));
|
exception_message("integer value overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
result = detail::conditional_static_cast<std::size_t>(number);
|
result = detail::conditional_static_cast<std::size_t>(number);
|
||||||
@@ -2768,7 +2814,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array
|
if (is_ndarray) // ndarray dimensional vector can only contain integers and cannot embed another array
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, "ndarray dimensional vector is not allowed", "size");
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message("ndarray dimensional vector is not allowed", "size"), nullptr));
|
||||||
}
|
}
|
||||||
std::vector<size_t> dim;
|
std::vector<size_t> dim;
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
|
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
|
||||||
@@ -2804,7 +2850,9 @@ class binary_reader
|
|||||||
const char* type_name = bjd_type_name(ndarray_dtype);
|
const char* type_name = bjd_type_name(ndarray_dtype);
|
||||||
if (JSON_HEDLEY_UNLIKELY(type_name == nullptr))
|
if (JSON_HEDLEY_UNLIKELY(type_name == nullptr))
|
||||||
{
|
{
|
||||||
return invalid_byte("type");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message("invalid byte: 0x" + last_token, "type"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t type_key = "_ArrayType_";
|
string_t type_key = "_ArrayType_";
|
||||||
@@ -2832,7 +2880,7 @@ class binary_reader
|
|||||||
// or SIZE_MAX.
|
// or SIZE_MAX.
|
||||||
if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits<std::size_t>::max)() / i))
|
if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits<std::size_t>::max)() / i))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
result *= i;
|
result *= i;
|
||||||
// the pre-check above already rules out result becoming 0
|
// the pre-check above already rules out result becoming 0
|
||||||
@@ -2841,7 +2889,7 @@ class binary_reader
|
|||||||
// unknown-size container (see get_ubjson_size_type())
|
// unknown-size container (see get_ubjson_size_type())
|
||||||
if (result == npos)
|
if (result == npos)
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message("excessive ndarray size caused overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i)))
|
if (JSON_HEDLEY_UNLIKELY(!emit_unsigned(i)))
|
||||||
{
|
{
|
||||||
@@ -2858,7 +2906,18 @@ class binary_reader
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return length_type_error(" after '#'", "size");
|
auto last_token = get_token_string();
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
if (input_format != input_format_t::bjdata)
|
||||||
|
{
|
||||||
|
message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
|
||||||
|
}
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(message, "size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -2891,7 +2950,9 @@ class binary_reader
|
|||||||
if (input_format == input_format_t::bjdata
|
if (input_format == input_format_t::bjdata
|
||||||
&& JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second)))
|
&& JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second)))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, concat("marker 0x", get_token_string(), " is not a permitted optimized array type"), "type");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
||||||
@@ -2906,7 +2967,9 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return last_byte_error(exception_id::unexpected_byte, concat("expected '#' after type information; last byte: 0x", get_token_string()), "size");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray, 0, result.second);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray, 0, result.second);
|
||||||
@@ -2925,7 +2988,8 @@ class binary_reader
|
|||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size");
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
|
||||||
|
exception_message("ndarray requires both type and size", "size"), nullptr));
|
||||||
}
|
}
|
||||||
return is_error;
|
return is_error;
|
||||||
}
|
}
|
||||||
@@ -3057,7 +3121,9 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(current > 127))
|
if (JSON_HEDLEY_UNLIKELY(current > 127))
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", get_token_string()), "char");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message(concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
|
||||||
}
|
}
|
||||||
string_t s(1, static_cast<typename string_t::value_type>(current));
|
string_t s(1, static_cast<typename string_t::value_type>(current));
|
||||||
return sax->string(s);
|
return sax->string(s);
|
||||||
@@ -3078,7 +3144,8 @@ class binary_reader
|
|||||||
default: // anything else
|
default: // anything else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return invalid_byte("value");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message("invalid byte: 0x" + last_token, "value"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3141,7 +3208,7 @@ class binary_reader
|
|||||||
if (JSON_HEDLEY_UNLIKELY((size_and_type.second == 'Z' || size_and_type.second == 'T' || size_and_type.second == 'F')
|
if (JSON_HEDLEY_UNLIKELY((size_and_type.second == 'Z' || size_and_type.second == 'T' || size_and_type.second == 'F')
|
||||||
&& size_and_type.first > max_valueless_container_size))
|
&& size_and_type.first > max_valueless_container_size))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(exception_id::container_too_large,
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
|
||||||
exception_message("excessive array size", "size"), nullptr));
|
exception_message("excessive array size", "size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3177,7 +3244,9 @@ class binary_reader
|
|||||||
// do not accept ND-array size in objects in BJData
|
// do not accept ND-array size in objects in BJData
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object");
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message("BJData object does not support ND-array size in optimized format", "object"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size_and_type.first != npos)
|
if (size_and_type.first != npos)
|
||||||
@@ -3214,7 +3283,7 @@ class binary_reader
|
|||||||
// the lexer would stop at a NUL and accept the digits before it
|
// the lexer would stop at a NUL and accept the digits before it
|
||||||
if (JSON_HEDLEY_UNLIKELY(current == '\0'))
|
if (JSON_HEDLEY_UNLIKELY(current == '\0'))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, "00", parse_error::create(exception_id::invalid_high_precision_number, chars_read,
|
return sax->parse_error(chars_read, "00", parse_error::create(115, chars_read,
|
||||||
exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr));
|
exception_message("invalid number text; last byte: 0x00", "high-precision number"), nullptr));
|
||||||
}
|
}
|
||||||
number_vector.push_back(static_cast<char>(current));
|
number_vector.push_back(static_cast<char>(current));
|
||||||
@@ -3231,7 +3300,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
|
if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read,
|
return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
|
||||||
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
|
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3249,7 +3318,7 @@ class binary_reader
|
|||||||
return sax->parse_error(
|
return sax->parse_error(
|
||||||
chars_read,
|
chars_read,
|
||||||
number_string,
|
number_string,
|
||||||
out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", number_string, '\''), nullptr));
|
out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr));
|
||||||
}
|
}
|
||||||
// number_string is a std::string, while the SAX interface takes a
|
// number_string is a std::string, while the SAX interface takes a
|
||||||
// string_t; convert explicitly, as the two are only implicitly
|
// string_t; convert explicitly, as the two are only implicitly
|
||||||
@@ -3271,7 +3340,7 @@ class binary_reader
|
|||||||
case token_type::end_of_input:
|
case token_type::end_of_input:
|
||||||
case token_type::literal_or_value:
|
case token_type::literal_or_value:
|
||||||
default:
|
default:
|
||||||
return sax->parse_error(chars_read, number_string, parse_error::create(exception_id::invalid_high_precision_number, chars_read,
|
return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
|
||||||
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
|
exception_message(concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3330,6 +3399,20 @@ class binary_reader
|
|||||||
return 0x80 <= c && c <= 0xBF;
|
return 0x80 <= c && c <= 0xBF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief report a parse error at the last read byte
|
||||||
|
|
||||||
|
@param[in] detail a detailed error message
|
||||||
|
@param[in] context further context information
|
||||||
|
@return false
|
||||||
|
*/
|
||||||
|
bool bon8_error(const std::string& detail, const char* context)
|
||||||
|
{
|
||||||
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
|
exception_message(concat(detail, ": 0x", last_token), context), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief read a BON8 value and everything nested inside it
|
@brief read a BON8 value and everything nested inside it
|
||||||
|
|
||||||
@@ -3545,7 +3628,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0xFE: end of container where a value is expected
|
// 0xFE: end of container where a value is expected
|
||||||
return invalid_byte("value");
|
return bon8_error("invalid byte", "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3672,7 +3755,7 @@ class binary_reader
|
|||||||
current = byte;
|
current = byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
return unexpected_byte("expected a string; last byte", "key");
|
return bon8_error("expected a string; last byte", "key");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3795,7 +3878,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!valid_second))
|
if (JSON_HEDLEY_UNLIKELY(!valid_second))
|
||||||
{
|
{
|
||||||
return unexpected_byte("invalid UTF-8 byte", "string");
|
return bon8_error("invalid UTF-8 byte", "string");
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push_back(static_cast<typename string_t::value_type>(byte));
|
result.push_back(static_cast<typename string_t::value_type>(byte));
|
||||||
@@ -3809,7 +3892,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_bon8_continuation(current)))
|
if (JSON_HEDLEY_UNLIKELY(!is_bon8_continuation(current)))
|
||||||
{
|
{
|
||||||
return unexpected_byte("invalid UTF-8 byte", "string");
|
return bon8_error("invalid UTF-8 byte", "string");
|
||||||
}
|
}
|
||||||
result.push_back(static_cast<typename string_t::value_type>(current));
|
result.push_back(static_cast<typename string_t::value_type>(current));
|
||||||
}
|
}
|
||||||
@@ -3854,7 +3937,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
// in case of failure, advance position by 1 to report the failing location
|
// in case of failure, advance position by 1 to report the failing location
|
||||||
++chars_read;
|
++chars_read;
|
||||||
sax->parse_error(chars_read, "<end of file>", parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr));
|
sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -4008,7 +4091,7 @@ class binary_reader
|
|||||||
if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result)))
|
if (JSON_HEDLEY_UNLIKELY(std::isfinite(number) && !std::isfinite(result)))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(),
|
return sax->parse_error(chars_read, get_token_string(),
|
||||||
out_of_range::create(exception_id::number_overflow, exception_message("number overflow", "value"), nullptr));
|
out_of_range::create(406, exception_message("number overflow", "value"), nullptr));
|
||||||
}
|
}
|
||||||
return sax->number_float(result, "");
|
return sax->number_float(result, "");
|
||||||
}
|
}
|
||||||
@@ -4128,7 +4211,9 @@ class binary_reader
|
|||||||
|
|
||||||
if (error_handler == error_handler_t::strict)
|
if (error_handler == error_handler_t::strict)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::invalid_string_or_size, "invalid string: ill-formed UTF-8 byte", context);
|
auto last_token = get_token_string();
|
||||||
|
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||||
|
exception_message("invalid string: ill-formed UTF-8 byte", context), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
result = sanitize_utf8(result, error_handler);
|
result = sanitize_utf8(result, error_handler);
|
||||||
@@ -4224,63 +4309,19 @@ class binary_reader
|
|||||||
if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
|
if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, "<end of file>",
|
return sax->parse_error(chars_read, "<end of file>",
|
||||||
parse_error::create(exception_id::unexpected_end_of_input, chars_read, exception_message("unexpected end of input", context), nullptr));
|
parse_error::create(110, chars_read, exception_message("unexpected end of input", context), nullptr));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief reports a parse error at the last read byte
|
|
||||||
@param[in] id_ the id of the parse_error exception
|
|
||||||
@param[in] detail a detailed error message
|
|
||||||
@param[in] context further context information
|
|
||||||
@return the result of the SAX parser's parse_error()
|
|
||||||
*/
|
|
||||||
bool last_byte_error(const exception_id id_, const std::string& detail, const std::string& context) const
|
|
||||||
{
|
|
||||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(id_, chars_read, exception_message(detail, context), nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief reports the last read byte as unexpected (parse_error.112)
|
|
||||||
@param[in] detail what is wrong with the byte, e.g. "invalid byte"
|
|
||||||
@param[in] context further context information
|
|
||||||
@return the result of the SAX parser's parse_error()
|
|
||||||
*/
|
|
||||||
bool unexpected_byte(const char* detail, const std::string& context) const
|
|
||||||
{
|
|
||||||
return last_byte_error(exception_id::unexpected_byte, concat(detail, ": 0x", get_token_string()), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief reports the last read byte as invalid (parse_error.112)
|
|
||||||
@param[in] context further context information
|
|
||||||
@return the result of the SAX parser's parse_error()
|
|
||||||
*/
|
|
||||||
bool invalid_byte(const char* context) const
|
|
||||||
{
|
|
||||||
return unexpected_byte("invalid byte", context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief reports that the last read byte is not a UBJSON/BJData length type (parse_error.113)
|
|
||||||
@param[in] position where the length type was expected, e.g. " after '#'"
|
|
||||||
@param[in] context further context information
|
|
||||||
@return the result of the SAX parser's parse_error()
|
|
||||||
*/
|
|
||||||
bool length_type_error(const char* position, const char* context) const
|
|
||||||
{
|
|
||||||
const char* types = input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L";
|
|
||||||
return last_byte_error(exception_id::invalid_string_or_size,
|
|
||||||
concat("expected length type specification (", types, ")", position, "; last byte: 0x", get_token_string()), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@return a string representation of the last read byte
|
@return a string representation of the last read byte
|
||||||
*/
|
*/
|
||||||
std::string get_token_string() const
|
std::string get_token_string() const
|
||||||
{
|
{
|
||||||
return hex_byte(static_cast<std::uint8_t>(current));
|
std::array<char, 3> cr{{}};
|
||||||
|
static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||||
|
return std::string{cr.data()};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -581,7 +581,7 @@ class wide_string_input_adapter
|
|||||||
template<class T>
|
template<class T>
|
||||||
JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1)
|
JSON_HEDLEY_NO_RETURN std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(exception_id::unexpected_byte, 1, "wide string type cannot be interpreted as binary data", nullptr));
|
JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -793,7 +793,7 @@ inline file_input_adapter input_adapter(std::FILE* file)
|
|||||||
{
|
{
|
||||||
if (file == nullptr)
|
if (file == nullptr)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
}
|
}
|
||||||
return file_input_adapter(file);
|
return file_input_adapter(file);
|
||||||
}
|
}
|
||||||
@@ -802,7 +802,7 @@ inline input_stream_adapter input_adapter(std::istream& stream)
|
|||||||
{
|
{
|
||||||
if (stream.rdbuf() == nullptr)
|
if (stream.rdbuf() == nullptr)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
}
|
}
|
||||||
return input_stream_adapter(stream);
|
return input_stream_adapter(stream);
|
||||||
}
|
}
|
||||||
@@ -827,7 +827,7 @@ contiguous_bytes_input_adapter input_adapter(CharT b)
|
|||||||
{
|
{
|
||||||
if (b == nullptr)
|
if (b == nullptr)
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(exception_id::syntax_error, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
}
|
}
|
||||||
auto length = std::strlen(reinterpret_cast<const char*>(b));
|
auto length = std::strlen(reinterpret_cast<const char*>(b));
|
||||||
const auto* ptr = reinterpret_cast<const char*>(b);
|
const auto* ptr = reinterpret_cast<const char*>(b);
|
||||||
|
|||||||
@@ -176,27 +176,6 @@ template<typename ArrayType>
|
|||||||
inline void reserve_array(ArrayType& /*arr*/, std::size_t /*len*/, priority_tag<0> /*unused*/)
|
inline void reserve_array(ArrayType& /*arr*/, std::size_t /*len*/, priority_tag<0> /*unused*/)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief reports an object or array whose announced size exceeds max_size()
|
|
||||||
|
|
||||||
Shared by json_sax_dom_parser and json_sax_dom_callback_parser.
|
|
||||||
|
|
||||||
@param[in] sax the SAX parser to report the error to
|
|
||||||
@param[in] len the number of elements announced by the input, or unknown_size()
|
|
||||||
@param[in] kind "object" or "array"
|
|
||||||
@param[in] ref the object or array that was just created
|
|
||||||
@return whether parsing should continue (false after reporting out_of_range.408)
|
|
||||||
*/
|
|
||||||
template<typename SAX, typename BasicJsonType>
|
|
||||||
bool check_container_size(SAX& sax, std::size_t len, const char* kind, BasicJsonType* ref)
|
|
||||||
{
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref->max_size()))
|
|
||||||
{
|
|
||||||
return sax.parse_error(0, "", out_of_range::create(exception_id::container_too_large, concat("excessive ", kind, " size: ", std::to_string(len)), ref));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
/*!
|
/*!
|
||||||
@brief set the diagnostic positions of a value the DOM SAX parsers just stored
|
@brief set the diagnostic positions of a value the DOM SAX parsers just stored
|
||||||
@@ -206,35 +185,6 @@ befriends this struct, as the position members are private.
|
|||||||
*/
|
*/
|
||||||
struct diagnostic_positions
|
struct diagnostic_positions
|
||||||
{
|
{
|
||||||
/*!
|
|
||||||
@param[in,out] v the object or array whose opening brace or bracket was just read
|
|
||||||
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType, typename LexerType>
|
|
||||||
static void set_container_start(BasicJsonType& v, LexerType* lexer)
|
|
||||||
{
|
|
||||||
if (lexer)
|
|
||||||
{
|
|
||||||
// Lexer has read the first character of the container, so
|
|
||||||
// subtract 1 from the position to get the correct start position.
|
|
||||||
v.start_position = lexer->get_position() - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@param[in,out] v the object or array whose closing brace or bracket was just read
|
|
||||||
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
|
||||||
*/
|
|
||||||
template<typename BasicJsonType, typename LexerType>
|
|
||||||
static void set_container_end(BasicJsonType& v, LexerType* lexer)
|
|
||||||
{
|
|
||||||
if (lexer)
|
|
||||||
{
|
|
||||||
// Lexer's position is past the closing brace or bracket, so set that as the end position.
|
|
||||||
v.end_position = lexer->get_position();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@param[in,out] v the value that was just parsed
|
@param[in,out] v the value that was just parsed
|
||||||
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
@param[in] lexer the lexer that read it, or nullptr to leave @a v alone
|
||||||
@@ -399,11 +349,22 @@ class json_sax_dom_parser
|
|||||||
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
|
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
// Manually set the start position of the object here.
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
// Lexer has read the first character of the object, so
|
||||||
|
// subtract 1 from the position to get the correct start position.
|
||||||
|
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return check_container_size(*this, len, "object", ref_stack.back());
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
|
{
|
||||||
|
return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool key(string_t& val)
|
bool key(string_t& val)
|
||||||
@@ -422,7 +383,11 @@ class json_sax_dom_parser
|
|||||||
JSON_ASSERT(ref_stack.back()->is_object());
|
JSON_ASSERT(ref_stack.back()->is_object());
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
// Lexer's position is past the closing brace, so set that as the end position.
|
||||||
|
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -435,13 +400,17 @@ class json_sax_dom_parser
|
|||||||
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
|
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
// Manually set the start position of the array here.
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!check_container_size(*this, len, "array", ref_stack.back())))
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
{
|
{
|
||||||
return false;
|
return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len != detail::unknown_size())
|
if (len != detail::unknown_size())
|
||||||
@@ -458,7 +427,11 @@ class json_sax_dom_parser
|
|||||||
JSON_ASSERT(ref_stack.back()->is_array());
|
JSON_ASSERT(ref_stack.back()->is_array());
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
// Lexer's position is past the closing bracket, so set that as the end position.
|
||||||
|
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -638,11 +611,21 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
// Manually set the start position of the object here.
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
// Lexer has read the first character of the object, so
|
||||||
|
// subtract 1 from the position to get the correct start position.
|
||||||
|
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return check_container_size(*this, len, "object", ref_stack.back());
|
// check object limit
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
|
{
|
||||||
|
return parse_error(0, "", out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -712,7 +695,11 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
// Lexer's position is past the closing brace, so set that as the end position.
|
||||||
|
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -723,7 +710,13 @@ class json_sax_dom_callback_parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const string_t object_key = pop_container();
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(!keep_stack.empty());
|
||||||
|
JSON_ASSERT(!container_key_stack.empty());
|
||||||
|
ref_stack.pop_back();
|
||||||
|
keep_stack.pop_back();
|
||||||
|
const string_t object_key = std::move(container_key_stack.back());
|
||||||
|
container_key_stack.pop_back();
|
||||||
|
|
||||||
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
|
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
|
||||||
{
|
{
|
||||||
@@ -749,13 +742,20 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
|
// Manually set the start position of the array here.
|
||||||
// Ensure this is after the call to handle_value to ensure correct start position.
|
// Ensure this is after the call to handle_value to ensure correct start position.
|
||||||
diagnostic_positions::set_container_start(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
// Lexer has read the first character of the array, so
|
||||||
|
// subtract 1 from the position to get the correct start position.
|
||||||
|
ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!check_container_size(*this, len, "array", ref_stack.back())))
|
// check array limit
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))
|
||||||
{
|
{
|
||||||
return false;
|
return parse_error(0, "", out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len != detail::unknown_size())
|
if (len != detail::unknown_size())
|
||||||
@@ -779,7 +779,11 @@ class json_sax_dom_callback_parser
|
|||||||
{
|
{
|
||||||
|
|
||||||
#if JSON_DIAGNOSTIC_POSITIONS
|
#if JSON_DIAGNOSTIC_POSITIONS
|
||||||
diagnostic_positions::set_container_end(*ref_stack.back(), m_lexer_ref);
|
if (m_lexer_ref)
|
||||||
|
{
|
||||||
|
// Lexer's position is past the closing bracket, so set that as the end position.
|
||||||
|
ref_stack.back()->end_position = m_lexer_ref->get_position();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ref_stack.back()->set_parents();
|
ref_stack.back()->set_parents();
|
||||||
@@ -805,7 +809,13 @@ class json_sax_dom_callback_parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const string_t object_key = pop_container();
|
JSON_ASSERT(!ref_stack.empty());
|
||||||
|
JSON_ASSERT(!keep_stack.empty());
|
||||||
|
JSON_ASSERT(!container_key_stack.empty());
|
||||||
|
ref_stack.pop_back();
|
||||||
|
keep_stack.pop_back();
|
||||||
|
const string_t object_key = std::move(container_key_stack.back());
|
||||||
|
container_key_stack.pop_back();
|
||||||
|
|
||||||
// remove discarded value
|
// remove discarded value
|
||||||
if (!ref_stack.empty() && ref_stack.back())
|
if (!ref_stack.empty() && ref_stack.back())
|
||||||
@@ -892,23 +902,6 @@ class json_sax_dom_callback_parser
|
|||||||
return string_t{};
|
return string_t{};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief leave the object or array that end_object()/end_array() just closed
|
|
||||||
@return the key the container is stored under in its parent (see
|
|
||||||
container_key_stack)
|
|
||||||
*/
|
|
||||||
string_t pop_container()
|
|
||||||
{
|
|
||||||
JSON_ASSERT(!ref_stack.empty());
|
|
||||||
JSON_ASSERT(!keep_stack.empty());
|
|
||||||
JSON_ASSERT(!container_key_stack.empty());
|
|
||||||
ref_stack.pop_back();
|
|
||||||
keep_stack.pop_back();
|
|
||||||
string_t object_key = std::move(container_key_stack.back());
|
|
||||||
container_key_stack.pop_back();
|
|
||||||
return object_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief remove the discarded value the callback rejected from its parent,
|
@brief remove the discarded value the callback rejected from its parent,
|
||||||
unless it is a duplicate key's slot with a stashed previous value, in
|
unless it is a duplicate key's slot with a stashed previous value, in
|
||||||
|
|||||||
@@ -156,7 +156,9 @@ class parser
|
|||||||
// strict mode: next byte must be EOF
|
// strict mode: next byte must be EOF
|
||||||
if (get_token() != token_type::end_of_input)
|
if (get_token() != token_type::end_of_input)
|
||||||
{
|
{
|
||||||
return syntax_error(*sax, exception_message(token_type::end_of_input, "value"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -195,7 +197,10 @@ class parser
|
|||||||
// in strict mode, input must be completely read
|
// in strict mode, input must be completely read
|
||||||
if (get_token() != token_type::end_of_input)
|
if (get_token() != token_type::end_of_input)
|
||||||
{
|
{
|
||||||
syntax_error(sdp, exception_message(token_type::end_of_input, "value"));
|
sdp.parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(),
|
||||||
|
exception_message(token_type::end_of_input, "value"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -245,7 +250,9 @@ class parser
|
|||||||
// parse key
|
// parse key
|
||||||
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
||||||
{
|
{
|
||||||
return syntax_error(*sax, exception_message(token_type::value_string, "object key"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||||
}
|
}
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||||
{
|
{
|
||||||
@@ -255,7 +262,9 @@ class parser
|
|||||||
// parse separator (:)
|
// parse separator (:)
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator)))
|
if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator)))
|
||||||
{
|
{
|
||||||
return syntax_error(*sax, exception_message(token_type::name_separator, "object separator"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember we are now inside an object
|
// remember we are now inside an object
|
||||||
@@ -298,7 +307,7 @@ class parser
|
|||||||
{
|
{
|
||||||
return sax->parse_error(m_lexer.get_position(),
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
m_lexer.get_token_string(),
|
m_lexer.get_token_string(),
|
||||||
out_of_range::create(exception_id::number_overflow, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));
|
out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
|
||||||
@@ -366,16 +375,23 @@ class parser
|
|||||||
case token_type::parse_error:
|
case token_type::parse_error:
|
||||||
{
|
{
|
||||||
// using "uninitialized" to avoid an "expected" message
|
// using "uninitialized" to avoid an "expected" message
|
||||||
return syntax_error(*sax, exception_message(token_type::uninitialized, "value"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
|
||||||
}
|
}
|
||||||
case token_type::end_of_input:
|
case token_type::end_of_input:
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
|
if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
|
||||||
{
|
{
|
||||||
return syntax_error(*sax, "attempting to parse an empty input; check that your input string or stream contains the expected JSON");
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(),
|
||||||
|
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return syntax_error(*sax, exception_message(token_type::literal_or_value, "value"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
|
||||||
}
|
}
|
||||||
case token_type::uninitialized:
|
case token_type::uninitialized:
|
||||||
case token_type::end_array:
|
case token_type::end_array:
|
||||||
@@ -385,7 +401,9 @@ class parser
|
|||||||
case token_type::literal_or_value:
|
case token_type::literal_or_value:
|
||||||
default: // the last token was unexpected
|
default: // the last token was unexpected
|
||||||
{
|
{
|
||||||
return syntax_error(*sax, exception_message(token_type::literal_or_value, "value"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,7 +454,9 @@ class parser
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return syntax_error(*sax, exception_message(token_type::end_array, "array"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// states.back() is false -> object
|
// states.back() is false -> object
|
||||||
@@ -453,7 +473,9 @@ class parser
|
|||||||
// parse key
|
// parse key
|
||||||
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
|
||||||
{
|
{
|
||||||
return syntax_error(*sax, exception_message(token_type::value_string, "object key"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
|
||||||
@@ -464,7 +486,9 @@ class parser
|
|||||||
// parse separator (:)
|
// parse separator (:)
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator)))
|
if (JSON_HEDLEY_UNLIKELY(!get_token_expecting(token_type::name_separator)))
|
||||||
{
|
{
|
||||||
return syntax_error(*sax, exception_message(token_type::name_separator, "object separator"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse values
|
// parse values
|
||||||
@@ -492,7 +516,9 @@ class parser
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return syntax_error(*sax, exception_message(token_type::end_object, "object"));
|
return sax->parse_error(m_lexer.get_position(),
|
||||||
|
m_lexer.get_token_string(),
|
||||||
|
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,19 +535,6 @@ class parser
|
|||||||
return (last_token = m_lexer.scan_expecting(expected_type)) == expected_type;
|
return (last_token = m_lexer.scan_expecting(expected_type)) == expected_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief reports a syntax error at the current token (parse_error.101)
|
|
||||||
@param[in] sax the SAX parser to report the error to
|
|
||||||
@param[in] message the error message
|
|
||||||
@return the result of the SAX parser's parse_error()
|
|
||||||
*/
|
|
||||||
template<typename SAX>
|
|
||||||
bool syntax_error(SAX& sax, const std::string& message)
|
|
||||||
{
|
|
||||||
return sax.parse_error(m_lexer.get_position(), m_lexer.get_token_string(),
|
|
||||||
parse_error::create(exception_id::syntax_error, m_lexer.get_position(), message, nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string exception_message(const token_type expected, const std::string& context)
|
std::string exception_message(const token_type expected, const std::string& context)
|
||||||
{
|
{
|
||||||
std::string error_msg = "syntax error ";
|
std::string error_msg = "syntax error ";
|
||||||
|
|||||||
@@ -279,12 +279,6 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @throw invalid_iterator.214 always
|
|
||||||
JSON_HEDLEY_NO_RETURN void throw_cannot_get_value() const
|
|
||||||
{
|
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterator_value_unavailable, "cannot get value", m_object));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*!
|
/*!
|
||||||
@brief return a reference to the value pointed to by the iterator
|
@brief return a reference to the value pointed to by the iterator
|
||||||
@@ -309,7 +303,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
}
|
}
|
||||||
|
|
||||||
case value_t::null:
|
case value_t::null:
|
||||||
throw_cannot_get_value();
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
@@ -325,7 +319,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_cannot_get_value();
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +361,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return m_object;
|
return m_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_cannot_get_value();
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -484,7 +478,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
// if objects are not the same, the comparison is undefined
|
// if objects are not the same, the comparison is undefined
|
||||||
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object));
|
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
||||||
@@ -533,7 +527,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
// if objects are not the same, the comparison is undefined
|
// if objects are not the same, the comparison is undefined
|
||||||
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterators_compare_different_values, "cannot compare iterators of different containers", m_object));
|
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
// value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493
|
||||||
@@ -546,7 +540,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterator_order_on_object, "cannot compare order of object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
return (m_it.array_iterator < other.m_it.array_iterator);
|
return (m_it.array_iterator < other.m_it.array_iterator);
|
||||||
@@ -602,7 +596,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
@@ -681,7 +675,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterator_arithmetic_on_object, "cannot use offsets with object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
return m_it.array_iterator - other.m_it.array_iterator;
|
return m_it.array_iterator - other.m_it.array_iterator;
|
||||||
@@ -710,13 +704,13 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
switch (m_object->m_data.m_type)
|
switch (m_object->m_data.m_type)
|
||||||
{
|
{
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterator_subscript_on_object, "cannot use operator[] for object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
return *std::next(m_it.array_iterator, n);
|
return *std::next(m_it.array_iterator, n);
|
||||||
|
|
||||||
case value_t::null:
|
case value_t::null:
|
||||||
throw_cannot_get_value();
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
case value_t::boolean:
|
case value_t::boolean:
|
||||||
@@ -732,7 +726,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_cannot_get_value();
|
JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -750,7 +744,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
|||||||
return m_it.object_iterator->first;
|
return m_it.object_iterator->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(invalid_iterator::create(exception_id::iterator_key_not_object, "cannot use key() for non-object iterators", m_object));
|
JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
throw_no_parent();
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
reference_tokens.erase(reference_tokens.begin());
|
reference_tokens.erase(reference_tokens.begin());
|
||||||
@@ -178,7 +178,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
throw_no_parent();
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return reference_tokens.front();
|
return reference_tokens.front();
|
||||||
@@ -204,7 +204,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
throw_no_parent();
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
reference_tokens.pop_back();
|
reference_tokens.pop_back();
|
||||||
@@ -216,7 +216,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
throw_no_parent();
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return reference_tokens.back();
|
return reference_tokens.back();
|
||||||
@@ -244,21 +244,6 @@ class json_pointer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @throw out_of_range.405 always
|
|
||||||
JSON_HEDLEY_NO_RETURN static void throw_no_parent()
|
|
||||||
{
|
|
||||||
JSON_THROW(detail::out_of_range::create(detail::exception_id::patch_on_root, "JSON pointer has no parent", nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @throw out_of_range.404 always
|
|
||||||
template<typename BasicJsonContext>
|
|
||||||
JSON_HEDLEY_NO_RETURN static void throw_unresolved(const string_t& reference_token, BasicJsonContext context)
|
|
||||||
{
|
|
||||||
static_cast<void>(reference_token); // unused when JSON_NOEXCEPTION is defined
|
|
||||||
static_cast<void>(context);
|
|
||||||
JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_unresolved, detail::concat("unresolved reference token '", reference_token, "'"), context));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief result of @ref parse_array_index
|
@brief result of @ref parse_array_index
|
||||||
|
|
||||||
@@ -344,13 +329,13 @@ class json_pointer
|
|||||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||||
case array_index_status::leading_zero:
|
case array_index_status::leading_zero:
|
||||||
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
|
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
|
||||||
case array_index_status::not_a_number:
|
case array_index_status::not_a_number:
|
||||||
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
|
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
|
||||||
case array_index_status::unresolved:
|
case array_index_status::unresolved:
|
||||||
throw_unresolved(s, nullptr);
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
|
||||||
case array_index_status::exceeds_size_type:
|
case array_index_status::exceeds_size_type:
|
||||||
JSON_THROW(detail::out_of_range::create(detail::exception_id::value_out_of_range, detail::concat("array index ", s, " exceeds size_type"), nullptr));
|
JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr));
|
||||||
case array_index_status::ok:
|
case array_index_status::ok:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -364,7 +349,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(empty()))
|
if (JSON_HEDLEY_UNLIKELY(empty()))
|
||||||
{
|
{
|
||||||
throw_no_parent();
|
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
json_pointer result = *this;
|
json_pointer result = *this;
|
||||||
@@ -452,7 +437,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_invalid_value, "invalid value to unflatten", &j));
|
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix.push_back(reference_token);
|
prefix.push_back(reference_token);
|
||||||
@@ -535,7 +520,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
throw_unresolved(reference_token, ptr);
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +552,7 @@ class json_pointer
|
|||||||
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
{
|
{
|
||||||
// "-" always fails the range check
|
// "-" always fails the range check
|
||||||
JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat(
|
JSON_THROW(detail::out_of_range::create(402, detail::concat(
|
||||||
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
|
||||||
") is out of range"), ptr));
|
") is out of range"), ptr));
|
||||||
}
|
}
|
||||||
@@ -576,7 +561,7 @@ class json_pointer
|
|||||||
// Bounds check before access to avoid exception with JSON_NOEXCEPTION
|
// Bounds check before access to avoid exception with JSON_NOEXCEPTION
|
||||||
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
if (JSON_HEDLEY_UNLIKELY(idx >= ptr->m_data.m_value.array->size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat(
|
JSON_THROW(detail::out_of_range::create(401, detail::concat(
|
||||||
"array index ", std::to_string(idx), " is out of range"), ptr));
|
"array index ", std::to_string(idx), " is out of range"), ptr));
|
||||||
}
|
}
|
||||||
ptr = &ptr->operator[](idx);
|
ptr = &ptr->operator[](idx);
|
||||||
@@ -592,7 +577,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
throw_unresolved(reference_token, ptr);
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,7 +621,7 @@ class json_pointer
|
|||||||
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
|
||||||
{
|
{
|
||||||
// "-" cannot be used for const access
|
// "-" cannot be used for const access
|
||||||
JSON_THROW(detail::out_of_range::create(detail::exception_id::pointer_past_the_end_index, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
|
JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// use unchecked array access; the const operator[]
|
// use unchecked array access; the const operator[]
|
||||||
@@ -654,7 +639,7 @@ class json_pointer
|
|||||||
case detail::value_t::binary:
|
case detail::value_t::binary:
|
||||||
case detail::value_t::discarded:
|
case detail::value_t::discarded:
|
||||||
default:
|
default:
|
||||||
throw_unresolved(reference_token, ptr);
|
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,9 +694,9 @@ class json_pointer
|
|||||||
// the branches differ in their messages, not after JSON_THROW's expansion
|
// the branches differ in their messages, not after JSON_THROW's expansion
|
||||||
// NOLINTNEXTLINE(bugprone-branch-clone)
|
// NOLINTNEXTLINE(bugprone-branch-clone)
|
||||||
case array_index_status::leading_zero:
|
case array_index_status::leading_zero:
|
||||||
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_leading_zero, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr));
|
JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", reference_token, "' must not begin with '0'"), nullptr));
|
||||||
case array_index_status::not_a_number:
|
case array_index_status::not_a_number:
|
||||||
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_index_not_a_number, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr));
|
JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", reference_token, "' is not a number"), nullptr));
|
||||||
case array_index_status::unresolved:
|
case array_index_status::unresolved:
|
||||||
case array_index_status::exceeds_size_type:
|
case array_index_status::exceeds_size_type:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -838,7 +823,7 @@ class json_pointer
|
|||||||
// check if a nonempty reference string begins with slash
|
// check if a nonempty reference string begins with slash
|
||||||
if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
|
if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_missing_slash, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
|
JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the reference tokens:
|
// extract the reference tokens:
|
||||||
@@ -874,7 +859,7 @@ class json_pointer
|
|||||||
(reference_token[pos + 1] != '0' &&
|
(reference_token[pos + 1] != '0' &&
|
||||||
reference_token[pos + 1] != '1')))
|
reference_token[pos + 1] != '1')))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::parse_error::create(detail::exception_id::pointer_invalid_escape, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
|
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -971,7 +956,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_not_object, "only objects can be unflattened", &value));
|
JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicJsonType result;
|
BasicJsonType result;
|
||||||
@@ -999,7 +984,7 @@ class json_pointer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
|
if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
|
||||||
{
|
{
|
||||||
JSON_THROW(detail::type_error::create(detail::exception_id::unflatten_value_not_primitive, "values in object must be primitive", &element.second));
|
JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign the value to the reference pointed to by JSON pointer. Note
|
// Assign the value to the reference pointed to by JSON pointer. Note
|
||||||
|
|||||||
@@ -312,7 +312,7 @@
|
|||||||
return ej_pair.first == e; \
|
return ej_pair.first == e; \
|
||||||
}); \
|
}); \
|
||||||
if (it != std::end(m)) j = it->second; \
|
if (it != std::end(m)) j = it->second; \
|
||||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range,"enum value out of range for " #ENUM_TYPE, nullptr)); \
|
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410,"enum value out of range for " #ENUM_TYPE, nullptr)); \
|
||||||
} \
|
} \
|
||||||
template<typename BasicJsonType> \
|
template<typename BasicJsonType> \
|
||||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
|
||||||
@@ -327,7 +327,7 @@
|
|||||||
return ej_pair.second == j; \
|
return ej_pair.second == j; \
|
||||||
}); \
|
}); \
|
||||||
if (it != std::end(m)) e = it->first; \
|
if (it != std::end(m)) e = it->first; \
|
||||||
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(nlohmann::detail::exception_id::value_out_of_range, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
|
else ::nlohmann::detail::templated_json_throw<nlohmann::detail::out_of_range>(nlohmann::detail::out_of_range::create(410, nlohmann::detail::concat("enum value out of range for " #ENUM_TYPE ": ", j.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace)), &j)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ class binary_writer
|
|||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(exception_id::type_not_serializable, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
|
JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,7 +354,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::uint32_t>(length)))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::uint32_t>(length)))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits<std::uint32_t>::max)())), &j));
|
JSON_THROW(out_of_range::create(412, concat("MessagePack length ", std::to_string(length), " exceeds maximum of ", std::to_string((std::numeric_limits<std::uint32_t>::max)())), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
static_cast<void>(j);
|
static_cast<void>(j);
|
||||||
@@ -613,7 +613,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(j.m_data.m_value.binary->subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
if (JSON_HEDLEY_UNLIKELY(j.m_data.m_value.binary->subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j));
|
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(j.m_data.m_value.binary->subtype()), " is too large for the MessagePack ext type (max 255)"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
|
write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
|
||||||
@@ -767,7 +767,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j));
|
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||||
}
|
}
|
||||||
oa.write_character(to_char_type('$'));
|
oa.write_character(to_char_type('$'));
|
||||||
oa.write_character(bjdata_draft3 ? 'B' : 'U');
|
oa.write_character(bjdata_draft3 ? 'B' : 'U');
|
||||||
@@ -866,7 +866,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
static_cast<void>(j); // unused when JSON_NOEXCEPTION is defined
|
static_cast<void>(j); // unused when JSON_NOEXCEPTION is defined
|
||||||
static_cast<void>(format_name);
|
static_cast<void>(format_name);
|
||||||
JSON_THROW(type_error::create(exception_id::discarded_value_used, concat("cannot serialize discarded value to ", format_name), &j));
|
JSON_THROW(type_error::create(321, concat("cannot serialize discarded value to ", format_name), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_msgpack_array_prefix(const std::size_t N, const BasicJsonType& j)
|
void write_msgpack_array_prefix(const std::size_t N, const BasicJsonType& j)
|
||||||
@@ -1132,7 +1132,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j));
|
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||||
}
|
}
|
||||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||||
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
||||||
@@ -1182,7 +1182,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(exception_id::size_marker_required, "use_type requires use_size = true", &j));
|
JSON_THROW(other_error::create(502, "use_type requires use_size = true", &j));
|
||||||
}
|
}
|
||||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||||
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
||||||
@@ -1397,7 +1397,7 @@ class binary_writer
|
|||||||
const auto it = name.find(static_cast<typename string_t::value_type>(0));
|
const auto it = name.find(static_cast<typename string_t::value_type>(0));
|
||||||
if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
|
if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(exception_id::bson_key_with_null, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
|
JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t storage;
|
string_t storage;
|
||||||
@@ -1415,7 +1415,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(size)))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::int32_t>(size)))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(exception_id::length_too_large, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits<std::int32_t>::max)())), nullptr));
|
JSON_THROW(out_of_range::create(412, concat("BSON length ", std::to_string(size), " exceeds maximum of ", std::to_string((std::numeric_limits<std::int32_t>::max)())), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<std::int32_t>(size);
|
return static_cast<std::int32_t>(size);
|
||||||
@@ -1601,7 +1601,7 @@ class binary_writer
|
|||||||
|
|
||||||
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(exception_id::subtype_out_of_range, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j));
|
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sizeof(std::int32_t) + value.size() + 1ul;
|
return sizeof(std::int32_t) + value.size() + 1ul;
|
||||||
@@ -2551,7 +2551,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
if (j.m_data.m_value.number_unsigned > static_cast<typename BasicJsonType::number_unsigned_t>((std::numeric_limits<std::int64_t>::max)()))
|
if (j.m_data.m_value.number_unsigned > static_cast<typename BasicJsonType::number_unsigned_t>((std::numeric_limits<std::int64_t>::max)()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(exception_id::integer_too_large, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j));
|
JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BON8 as it does not fit int64"), &j));
|
||||||
}
|
}
|
||||||
write_bon8_integer(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned));
|
write_bon8_integer(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned));
|
||||||
string_open = false;
|
string_open = false;
|
||||||
@@ -2704,7 +2704,7 @@ class binary_writer
|
|||||||
const std::size_t valid = valid_utf8_prefix(data, s.size());
|
const std::size_t valid = valid_utf8_prefix(data, s.size());
|
||||||
if (JSON_HEDLEY_UNLIKELY(valid != s.size()))
|
if (JSON_HEDLEY_UNLIKELY(valid != s.size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context));
|
JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(valid), ": 0x", detail::hex_byte(data[valid])), &context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -888,7 +888,7 @@ class serializer
|
|||||||
{
|
{
|
||||||
case error_handler_t::strict:
|
case error_handler_t::strict:
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr));
|
JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", detail::hex_byte(byte)), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::ignore:
|
case error_handler_t::ignore:
|
||||||
@@ -1021,7 +1021,7 @@ class serializer
|
|||||||
{
|
{
|
||||||
case error_handler_t::strict:
|
case error_handler_t::strict:
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(exception_id::invalid_utf8, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast<std::uint8_t>(s[s.size() - 1]))), nullptr));
|
JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", detail::hex_byte(static_cast<std::uint8_t>(s[s.size() - 1]))), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
case error_handler_t::ignore:
|
case error_handler_t::ignore:
|
||||||
|
|||||||
+71
-80
@@ -639,7 +639,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
object = nullptr; // silence warning, see #821
|
object = nullptr; // silence warning, see #821
|
||||||
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
|
if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(detail::exception_id::internal_error, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE
|
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0", nullptr)); // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2287,7 +2287,7 @@ public:
|
|||||||
// if an object is wanted but impossible, throw an exception
|
// if an object is wanted but impossible, throw an exception
|
||||||
if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
|
if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(type_error::create(detail::exception_id::object_from_non_pairs, "cannot create object from initializer list", nullptr));
|
JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2407,7 +2407,7 @@ public:
|
|||||||
// make sure the iterator fits the current value
|
// make sure the iterator fits the current value
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterators_incompatible, "iterators are not compatible", nullptr));
|
JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy type from the first iterator
|
// copy type from the first iterator
|
||||||
@@ -2426,7 +2426,7 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
||||||
|| !last.m_it.primitive_iterator.is_end()))
|
|| !last.m_it.primitive_iterator.is_end()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", first.m_object));
|
JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2494,7 +2494,7 @@ public:
|
|||||||
case value_t::null:
|
case value_t::null:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_of_null, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
|
JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
set_parents();
|
set_parents();
|
||||||
@@ -2882,7 +2882,7 @@ public:
|
|||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSON_THROW(type_error::create(detail::exception_id::incompatible_reference_type, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
|
JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -3266,7 +3266,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!is_binary())
|
if (!is_binary())
|
||||||
{
|
{
|
||||||
detail::throw_type_must_be("binary", *this);
|
JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
return *get_ptr<binary_t*>();
|
return *get_ptr<binary_t*>();
|
||||||
@@ -3278,7 +3278,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!is_binary())
|
if (!is_binary())
|
||||||
{
|
{
|
||||||
detail::throw_type_must_be("binary", *this);
|
JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
return *get_ptr<const binary_t*>();
|
return *get_ptr<const binary_t*>();
|
||||||
@@ -3320,7 +3320,7 @@ public:
|
|||||||
// at only works for objects
|
// at only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j);
|
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = object_lookup(j, std::forward<KeyType>(key));
|
auto it = object_lookup(j, std::forward<KeyType>(key));
|
||||||
@@ -3330,7 +3330,7 @@ public:
|
|||||||
// std::map or ordered_map) never moves from its argument, so key is still
|
// std::map or ordered_map) never moves from its argument, so key is still
|
||||||
// valid here regardless of whether KeyType was deduced as an rvalue reference
|
// valid here regardless of whether KeyType was deduced as an rvalue reference
|
||||||
// NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved)
|
// NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved)
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", string_t(key), "' not found"), &j));
|
JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(key), "' not found"), &j));
|
||||||
}
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
@@ -3345,12 +3345,12 @@ public:
|
|||||||
// at only works for arrays
|
// at only works for arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::at_wrong_type, "at()", j);
|
JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(idx >= j.m_data.m_value.array->size()))
|
if (JSON_HEDLEY_UNLIKELY(idx >= j.m_data.m_value.array->size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &j));
|
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (*j.m_data.m_value.array)[idx];
|
return (*j.m_data.m_value.array)[idx];
|
||||||
@@ -3383,15 +3383,6 @@ public:
|
|||||||
m_data.m_type = value_t::object;
|
m_data.m_type = value_t::object;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief throws because operator[] is not supported for the type of this value
|
|
||||||
/// @param[in] argument the kind of the operator's argument, "numeric" or "string"
|
|
||||||
/// @throw type_error.305 always
|
|
||||||
JSON_HEDLEY_NO_RETURN void throw_subscript_wrong_type(const char* argument) const
|
|
||||||
{
|
|
||||||
detail::throw_cannot_use_with(detail::exception_id::subscript_wrong_type,
|
|
||||||
detail::concat("operator[] with a ", argument, " argument").c_str(), *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
////////////////////
|
////////////////////
|
||||||
// element access //
|
// element access //
|
||||||
@@ -3496,7 +3487,7 @@ public:
|
|||||||
return m_data.m_value.array->operator[](idx);
|
return m_data.m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_subscript_wrong_type("numeric");
|
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified array element
|
/// @brief access specified array element
|
||||||
@@ -3510,7 +3501,7 @@ public:
|
|||||||
return m_data.m_value.array->operator[](idx);
|
return m_data.m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_subscript_wrong_type("numeric");
|
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified object element
|
/// @brief access specified object element
|
||||||
@@ -3530,7 +3521,7 @@ public:
|
|||||||
return set_parent(result.first->second);
|
return set_parent(result.first->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_subscript_wrong_type("string");
|
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified object element
|
/// @brief access specified object element
|
||||||
@@ -3545,7 +3536,7 @@ public:
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_subscript_wrong_type("string");
|
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
// these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
|
||||||
@@ -3581,7 +3572,7 @@ public:
|
|||||||
return set_parent(result.first->second);
|
return set_parent(result.first->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_subscript_wrong_type("string");
|
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief access specified object element
|
/// @brief access specified object element
|
||||||
@@ -3598,7 +3589,7 @@ public:
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_subscript_wrong_type("string");
|
JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -3622,7 +3613,7 @@ public:
|
|||||||
// value only works for objects
|
// value only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this);
|
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto it = find(std::forward<KeyType>(key));
|
const auto it = find(std::forward<KeyType>(key));
|
||||||
@@ -3637,7 +3628,7 @@ public:
|
|||||||
// value only works for arrays and objects
|
// value only works for arrays and objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_structured()))
|
if (JSON_HEDLEY_UNLIKELY(!is_structured()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::value_wrong_type, "value()", *this);
|
JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptr.get_checked_or_null(this);
|
return ptr.get_checked_or_null(this);
|
||||||
@@ -3804,7 +3795,7 @@ public:
|
|||||||
// make sure the iterator fits the current value
|
// make sure the iterator fits the current value
|
||||||
if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
|
if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorType result = end();
|
IteratorType result = end();
|
||||||
@@ -3820,7 +3811,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
|
if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_out_of_range, "iterator out of range", this));
|
JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.destroy(m_data.m_type);
|
m_data.m_value.destroy(m_data.m_type);
|
||||||
@@ -3846,7 +3837,7 @@ public:
|
|||||||
case value_t::null:
|
case value_t::null:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -3862,7 +3853,7 @@ public:
|
|||||||
// make sure the iterator fits the current value
|
// make sure the iterator fits the current value
|
||||||
if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_from_other_value, "iterators do not fit current value", this));
|
JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
IteratorType result = end();
|
IteratorType result = end();
|
||||||
@@ -3879,7 +3870,7 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
|
||||||
|| !last.m_it.primitive_iterator.is_end()))
|
|| !last.m_it.primitive_iterator.is_end()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_range_out_of_range, "iterators out of range", this));
|
JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.destroy(m_data.m_type);
|
m_data.m_value.destroy(m_data.m_type);
|
||||||
@@ -3907,7 +3898,7 @@ public:
|
|||||||
case value_t::null:
|
case value_t::null:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -3921,7 +3912,7 @@ public:
|
|||||||
// this erase only works for objects
|
// this erase only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto erased = m_data.m_value.object->erase(std::forward<KeyType>(key));
|
const auto erased = m_data.m_value.object->erase(std::forward<KeyType>(key));
|
||||||
@@ -3936,7 +3927,7 @@ public:
|
|||||||
// this erase only works for objects
|
// this erase only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto it = object_lookup(*this, std::forward<KeyType>(key));
|
const auto it = object_lookup(*this, std::forward<KeyType>(key));
|
||||||
@@ -3978,14 +3969,14 @@ public:
|
|||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(idx >= size()))
|
if (JSON_HEDLEY_UNLIKELY(idx >= size()))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
|
m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::erase_wrong_type, "erase()", *this);
|
JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4474,7 +4465,7 @@ public:
|
|||||||
// push_back only works for null objects or arrays
|
// push_back only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this);
|
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
@@ -4505,7 +4496,7 @@ public:
|
|||||||
// push_back only works for null objects or arrays
|
// push_back only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this);
|
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
@@ -4535,7 +4526,7 @@ public:
|
|||||||
// push_back only works for null objects or objects
|
// push_back only works for null objects or objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::push_back_wrong_type, "push_back()", *this);
|
JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
@@ -4589,7 +4580,7 @@ public:
|
|||||||
// emplace_back only works for null objects or arrays
|
// emplace_back only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace_back()", *this);
|
JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an array
|
// transform a null object into an array
|
||||||
@@ -4612,7 +4603,7 @@ public:
|
|||||||
// emplace only works for null objects or arrays
|
// emplace only works for null objects or arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::emplace_wrong_type, "emplace()", *this);
|
JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform a null object into an object
|
// transform a null object into an object
|
||||||
@@ -4664,14 +4655,14 @@ public:
|
|||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert to array and return iterator
|
// insert to array and return iterator
|
||||||
return insert_iterator(pos, val);
|
return insert_iterator(pos, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief inserts element into array
|
/// @brief inserts element into array
|
||||||
@@ -4684,7 +4675,7 @@ public:
|
|||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// moving into a local first keeps this safe even if val aliases
|
// moving into a local first keeps this safe even if val aliases
|
||||||
@@ -4693,7 +4684,7 @@ public:
|
|||||||
return insert_iterator(pos, std::move(tmp));
|
return insert_iterator(pos, std::move(tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief inserts copies of element into array
|
/// @brief inserts copies of element into array
|
||||||
@@ -4706,14 +4697,14 @@ public:
|
|||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert to array and return iterator
|
// insert to array and return iterator
|
||||||
return insert_iterator(pos, cnt, val);
|
return insert_iterator(pos, cnt, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief inserts range of elements into array
|
/// @brief inserts range of elements into array
|
||||||
@@ -4723,30 +4714,30 @@ public:
|
|||||||
// insert only works for arrays
|
// insert only works for arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if range iterators belong to the same JSON object
|
// check if range iterators belong to the same JSON object
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this));
|
JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_into_itself, "passed iterators may not belong to container", this));
|
JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed iterators must belong to arrays
|
// passed iterators must belong to arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to arrays", this));
|
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to arrays", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert to array and return iterator
|
// insert to array and return iterator
|
||||||
@@ -4760,13 +4751,13 @@ public:
|
|||||||
// insert only works for arrays
|
// insert only works for arrays
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!is_array()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if iterator pos fits to this JSON value
|
// check if iterator pos fits to this JSON value
|
||||||
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterator does not fit current value", this));
|
JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy the values first: ilist may refer to elements of this array
|
// copy the values first: ilist may refer to elements of this array
|
||||||
@@ -4788,19 +4779,19 @@ public:
|
|||||||
// insert only works for objects
|
// insert only works for objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::insert_wrong_type, "insert()", *this);
|
JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if range iterators belong to the same JSON object
|
// check if range iterators belong to the same JSON object
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this));
|
JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed iterators must belong to objects
|
// passed iterators must belong to objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::iterator_from_other_value, "iterators first and last must point to objects", this));
|
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
|
m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
|
||||||
@@ -4817,7 +4808,7 @@ public:
|
|||||||
// j, not the copy made below)
|
// j, not the copy made below)
|
||||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", j);
|
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", j.type_name()), &j));
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy first: j may be *this or one of its descendants, and is
|
// copy first: j may be *this or one of its descendants, and is
|
||||||
@@ -4835,13 +4826,13 @@ public:
|
|||||||
// check if range iterators belong to the same JSON object
|
// check if range iterators belong to the same JSON object
|
||||||
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
|
||||||
{
|
{
|
||||||
JSON_THROW(invalid_iterator::create(detail::exception_id::insert_range_incompatible, "iterators do not fit", this));
|
JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// passed iterators must belong to objects
|
// passed iterators must belong to objects
|
||||||
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *first.m_object);
|
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy first: the range may belong to *this or one of its
|
// copy first: the range may belong to *this or one of its
|
||||||
@@ -4877,7 +4868,7 @@ public:
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!is_object()))
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::update_wrong_type, "update()", *this);
|
JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5040,7 +5031,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(array_t&)", *this);
|
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5057,7 +5048,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(object_t&)", *this);
|
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5073,7 +5064,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(string_t&)", *this);
|
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5089,7 +5080,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t&)", *this);
|
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5105,7 +5096,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
detail::throw_cannot_use_with(detail::exception_id::swap_wrong_type, "swap(binary_t::container_type&)", *this);
|
JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6567,7 +6558,7 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
|
if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
|
||||||
{
|
{
|
||||||
// avoid undefined behavior
|
// avoid undefined behavior
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::array_index_out_of_range, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
|
JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
// default case: insert add offset
|
// default case: insert add offset
|
||||||
@@ -6586,7 +6577,7 @@ public:
|
|||||||
case value_t::binary:
|
case value_t::binary:
|
||||||
case value_t::discarded:
|
case value_t::discarded:
|
||||||
default:
|
default:
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::patch_add_parent_not_container, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
JSON_THROW(out_of_range::create(411, detail::concat("cannot add value: the JSON Patch 'add' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6609,7 +6600,7 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", last_path, "' not found"), this));
|
JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parent.is_array())
|
else if (parent.is_array())
|
||||||
@@ -6621,7 +6612,7 @@ public:
|
|||||||
{
|
{
|
||||||
// the parent of a "remove" target must be an object or array
|
// the parent of a "remove" target must be an object or array
|
||||||
// (see #5396)
|
// (see #5396)
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::patch_remove_parent_not_container, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
JSON_THROW(out_of_range::create(413, detail::concat("cannot remove value: the JSON Patch 'remove' target's parent is of type ", parent.type_name(), ", but must be an object or array"), &parent));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -6652,7 +6643,7 @@ public:
|
|||||||
// type check: top level value must be an array
|
// type check: top level value must be an array
|
||||||
if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
|
if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &json_patch));
|
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate and apply the operations
|
// iterate and apply the operations
|
||||||
@@ -6673,14 +6664,14 @@ public:
|
|||||||
if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
|
if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
||||||
JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
|
JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the result is of type string
|
// check if the result is of type string
|
||||||
if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
|
if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
||||||
JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
|
JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// no error: return value
|
// no error: return value
|
||||||
@@ -6690,7 +6681,7 @@ public:
|
|||||||
// type check: every element of the array must be an object
|
// type check: every element of the array must be an object
|
||||||
if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
|
if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
|
||||||
{
|
{
|
||||||
JSON_THROW(parse_error::create(detail::exception_id::patch_not_an_array, 0, "JSON patch must be an array of objects", &val));
|
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect mandatory members
|
// collect mandatory members
|
||||||
@@ -6726,7 +6717,7 @@ public:
|
|||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr)))
|
if (JSON_HEDLEY_UNLIKELY(is_proper_prefix(from_ptr, ptr)))
|
||||||
{
|
{
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::patch_move_into_child, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result));
|
JSON_THROW(out_of_range::create(414, detail::concat("cannot move value: 'from' path '", from_path, "' is a proper prefix of 'path' '", path, "'"), &result));
|
||||||
}
|
}
|
||||||
|
|
||||||
// the "from" location must exist - use at()
|
// the "from" location must exist - use at()
|
||||||
@@ -6773,7 +6764,7 @@ public:
|
|||||||
// throw an exception if the test fails
|
// throw an exception if the test fails
|
||||||
if (JSON_HEDLEY_UNLIKELY(!success))
|
if (JSON_HEDLEY_UNLIKELY(!success))
|
||||||
{
|
{
|
||||||
JSON_THROW(other_error::create(detail::exception_id::patch_test_failed, detail::concat("unsuccessful: ", val.dump()), &val));
|
JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -6784,7 +6775,7 @@ public:
|
|||||||
{
|
{
|
||||||
// op must be "add", "remove", "replace", "move", "copy", or
|
// op must be "add", "remove", "replace", "move", "copy", or
|
||||||
// "test"
|
// "test"
|
||||||
JSON_THROW(parse_error::create(detail::exception_id::patch_invalid_operation, 0, detail::concat("operation value '", op, "' is invalid"), &val));
|
JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,19 +90,6 @@ private:
|
|||||||
return self.end();
|
return self.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief shared implementation of the const and non-const at() overloads
|
|
||||||
/// @throw std::out_of_range if @a key is not found
|
|
||||||
template<typename Self, typename KeyType>
|
|
||||||
static auto at_impl(Self& self, const KeyType& key) -> decltype((self.begin()->second))
|
|
||||||
{
|
|
||||||
const auto it = find_impl(self, key);
|
|
||||||
if (it == self.end())
|
|
||||||
{
|
|
||||||
JSON_THROW(std::out_of_range("key not found"));
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief remove the entry @a it points to, preserving order
|
/// @brief remove the entry @a it points to, preserving order
|
||||||
/// @note keys are not movable, so the tail is destroyed and re-constructed in place
|
/// @note keys are not movable, so the tail is destroyed and re-constructed in place
|
||||||
void erase_at(iterator it)
|
void erase_at(iterator it)
|
||||||
@@ -169,26 +156,46 @@ public:
|
|||||||
|
|
||||||
T& at(const key_type& key)
|
T& at(const key_type& key)
|
||||||
{
|
{
|
||||||
return at_impl(*this, key);
|
const auto it = find_impl(*this, key);
|
||||||
|
if (it == this->end())
|
||||||
|
{
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
{
|
{
|
||||||
return at_impl(*this, key);
|
const auto it = find_impl(*this, key);
|
||||||
|
if (it == this->end())
|
||||||
|
{
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& at(const key_type& key) const
|
const T& at(const key_type& key) const
|
||||||
{
|
{
|
||||||
return at_impl(*this, key);
|
const auto it = find_impl(*this, key);
|
||||||
|
if (it == this->end())
|
||||||
|
{
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class KeyType, detail::enable_if_t<
|
template<class KeyType, detail::enable_if_t<
|
||||||
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
|
||||||
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
|
||||||
{
|
{
|
||||||
return at_impl(*this, key);
|
const auto it = find_impl(*this, key);
|
||||||
|
if (it == this->end())
|
||||||
|
{
|
||||||
|
JSON_THROW(std::out_of_range("key not found"));
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type erase(const key_type& key)
|
size_type erase(const key_type& key)
|
||||||
|
|||||||
+8
-104
@@ -2,120 +2,24 @@ project('nlohmann_json',
|
|||||||
'cpp',
|
'cpp',
|
||||||
version : '3.12.0',
|
version : '3.12.0',
|
||||||
license : 'MIT',
|
license : 'MIT',
|
||||||
meson_version : '>= 0.64',
|
|
||||||
default_options: ['cpp_std=c++11'],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if get_option('MultipleHeaders')
|
|
||||||
incdir = 'include'
|
|
||||||
else
|
|
||||||
incdir = 'single_include'
|
|
||||||
endif
|
|
||||||
|
|
||||||
# The same compile definitions as the CMake target (see target_compile_definitions
|
|
||||||
# in CMakeLists.txt): only an option that differs from its default adds one.
|
|
||||||
json_defines = []
|
|
||||||
if not get_option('GlobalUDLs')
|
|
||||||
json_defines += 'JSON_USE_GLOBAL_UDLS=0'
|
|
||||||
endif
|
|
||||||
if not get_option('ImplicitConversions')
|
|
||||||
json_defines += 'JSON_USE_IMPLICIT_CONVERSIONS=0'
|
|
||||||
endif
|
|
||||||
if get_option('DisableEnumSerialization')
|
|
||||||
json_defines += 'JSON_DISABLE_ENUM_SERIALIZATION=1'
|
|
||||||
endif
|
|
||||||
if get_option('DisableTupleReferenceConversion')
|
|
||||||
json_defines += 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1'
|
|
||||||
endif
|
|
||||||
if get_option('Diagnostics')
|
|
||||||
json_defines += 'JSON_DIAGNOSTICS=1'
|
|
||||||
endif
|
|
||||||
if get_option('Diagnostic_Positions')
|
|
||||||
json_defines += 'JSON_DIAGNOSTIC_POSITIONS=1'
|
|
||||||
endif
|
|
||||||
if get_option('LegacyDiscardedValueComparison')
|
|
||||||
json_defines += 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1'
|
|
||||||
endif
|
|
||||||
if get_option('StrictNulHandling')
|
|
||||||
json_defines += 'JSON_STRICT_NUL_HANDLING=1'
|
|
||||||
endif
|
|
||||||
if get_option('StrictBinaryUTF8')
|
|
||||||
json_defines += 'JSON_STRICT_BINARY_UTF8=1'
|
|
||||||
endif
|
|
||||||
if get_option('DeleteDeprecatedFunctions')
|
|
||||||
json_defines += 'JSON_DELETE_DEPRECATED_FUNCTIONS=1'
|
|
||||||
endif
|
|
||||||
|
|
||||||
cpp_args = []
|
|
||||||
foreach define : json_defines
|
|
||||||
cpp_args += '-D' + define
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
nlohmann_json_dep = declare_dependency(
|
nlohmann_json_dep = declare_dependency(
|
||||||
compile_args: cpp_args,
|
include_directories: include_directories('single_include')
|
||||||
include_directories: include_directories(incdir)
|
|
||||||
)
|
)
|
||||||
meson.override_dependency('nlohmann_json', nlohmann_json_dep)
|
|
||||||
|
|
||||||
# The multi-header version under the name earlier versions of this file used
|
|
||||||
nlohmann_json_multiple_headers = declare_dependency(
|
nlohmann_json_multiple_headers = declare_dependency(
|
||||||
compile_args: cpp_args,
|
|
||||||
include_directories: include_directories('include')
|
include_directories: include_directories('include')
|
||||||
)
|
)
|
||||||
|
|
||||||
if not meson.is_subproject()
|
if not meson.is_subproject()
|
||||||
install_subdir(
|
install_headers('single_include/nlohmann/json.hpp', subdir: 'nlohmann')
|
||||||
incdir / 'nlohmann',
|
install_headers('single_include/nlohmann/json_fwd.hpp', subdir: 'nlohmann')
|
||||||
install_dir: get_option('includedir'),
|
install_headers('single_include/nlohmann/json_literals.hpp', subdir: 'nlohmann')
|
||||||
install_tag: 'devel',
|
|
||||||
)
|
|
||||||
|
|
||||||
pkgc = import('pkgconfig')
|
pkgc = import('pkgconfig')
|
||||||
pkgc.generate(name: 'nlohmann_json',
|
pkgc.generate(name: 'nlohmann_json',
|
||||||
version: meson.project_version(),
|
version: meson.project_version(),
|
||||||
description: 'JSON for Modern C++',
|
description: 'JSON for Modern C++'
|
||||||
extra_cflags: cpp_args,
|
)
|
||||||
install_dir: get_option('datadir') / 'pkgconfig',
|
|
||||||
)
|
|
||||||
|
|
||||||
# CMake package config files, so that find_package(nlohmann_json) works. The
|
|
||||||
# include directory is given relative to the config files, so that the
|
|
||||||
# installation can be relocated. This is not possible if includedir or datadir
|
|
||||||
# is an absolute path outside the prefix (e.g., with the separate outputs of
|
|
||||||
# Nix); then the absolute include directory is used, as CMake does.
|
|
||||||
fs = import('fs')
|
|
||||||
cmake_install_dir = get_option('datadir') / 'cmake' / meson.project_name()
|
|
||||||
cmake_to_prefix = []
|
|
||||||
if fs.is_absolute(get_option('includedir')) or fs.is_absolute(cmake_install_dir)
|
|
||||||
cmake_include_dir = (get_option('prefix') / get_option('includedir')).replace('\\', '/')
|
|
||||||
else
|
|
||||||
foreach component : cmake_install_dir.split('/')
|
|
||||||
cmake_to_prefix += '..'
|
|
||||||
endforeach
|
|
||||||
cmake_include_dir = '${_IMPORT_PREFIX}/' + get_option('includedir')
|
|
||||||
endif
|
|
||||||
|
|
||||||
cmake_conf = configuration_data()
|
|
||||||
cmake_conf.set('PROJECT_NAME', meson.project_name())
|
|
||||||
cmake_conf.set('PROJECT_VERSION', meson.project_version())
|
|
||||||
cmake_conf.set('PROJECT_VERSION_MAJOR', meson.project_version().split('.')[0])
|
|
||||||
cmake_conf.set('NLOHMANN_JSON_TARGET_NAME', meson.project_name())
|
|
||||||
cmake_conf.set('NLOHMANN_JSON_TARGETS_EXPORT_NAME', meson.project_name() + 'Targets')
|
|
||||||
cmake_conf.set('NLOHMANN_JSON_INCLUDE_DIR', cmake_include_dir)
|
|
||||||
cmake_conf.set('NLOHMANN_JSON_CONFIG_TO_PREFIX', '/'.join(cmake_to_prefix))
|
|
||||||
cmake_conf.set('NLOHMANN_JSON_COMPILE_DEFINITIONS', ';'.join(json_defines))
|
|
||||||
|
|
||||||
foreach cmake_file : [
|
|
||||||
['cmake/config.cmake.in', 'nlohmann_jsonConfig.cmake'],
|
|
||||||
['cmake/nlohmann_jsonConfigVersion.cmake.in', 'nlohmann_jsonConfigVersion.cmake'],
|
|
||||||
['cmake/nlohmann_jsonTargets.cmake.in', 'nlohmann_jsonTargets.cmake'],
|
|
||||||
]
|
|
||||||
configure_file(
|
|
||||||
input: cmake_file[0],
|
|
||||||
output: cmake_file[1],
|
|
||||||
configuration: cmake_conf,
|
|
||||||
format: 'cmake@',
|
|
||||||
install_dir: cmake_install_dir,
|
|
||||||
)
|
|
||||||
endforeach
|
|
||||||
endif
|
endif
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
option(
|
|
||||||
'MultipleHeaders',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Use non-amalgamated version of the library',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'GlobalUDLs',
|
|
||||||
type: 'boolean',
|
|
||||||
value: true,
|
|
||||||
description: 'Place user-defined string literals in the global namespace',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'ImplicitConversions',
|
|
||||||
type: 'boolean',
|
|
||||||
value: true,
|
|
||||||
description: 'Enable implicit conversions',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'DisableEnumSerialization',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Disable default integer enum serialization',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'DisableTupleReferenceConversion',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Disable conversion from a one-element tuple of a JSON reference',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'Diagnostics',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Use extended diagnostic messages',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'Diagnostic_Positions',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Enable diagnostic positions',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'LegacyDiscardedValueComparison',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Enable legacy discarded value comparison',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'StrictNulHandling',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Enable strict NUL-byte handling',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'StrictBinaryUTF8',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Enable UTF-8 checks in the CBOR, UBJSON, BJData, and BSON writers',
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
'DeleteDeprecatedFunctions',
|
|
||||||
type: 'boolean',
|
|
||||||
value: false,
|
|
||||||
description: 'Delete the deprecated functions instead of only deprecating them',
|
|
||||||
)
|
|
||||||
+420
-549
File diff suppressed because it is too large.
Load diff
@@ -138,7 +138,8 @@ json_test_set_test_options(test-disabled_exceptions
|
|||||||
# only the #972 regression test needs thirdparty/fifo_map on its include path
|
# only the #972 regression test needs thirdparty/fifo_map on its include path
|
||||||
json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include)
|
json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include)
|
||||||
|
|
||||||
# GCC's false -Warray-bounds error with JSON_DIAGNOSTICS only shows up when optimizing (#5742).
|
# Regression test for GCC's false -Warray-bounds error with JSON_DIAGNOSTICS (#5742, fixed in #5585). It only
|
||||||
|
# showed up when optimizing, so build this test with -O3 and the warning as an error.
|
||||||
# -O3 makes the optimizer-driven warnings of the ci_test_gcc flag set (-Winline,
|
# -O3 makes the optimizer-driven warnings of the ci_test_gcc flag set (-Winline,
|
||||||
# -Wsuggest-attribute=...) fire on the library's inline functions; they are not
|
# -Wsuggest-attribute=...) fire on the library's inline functions; they are not
|
||||||
# what this test checks, so turn them off for it.
|
# what this test checks, so turn them off for it.
|
||||||
|
|||||||
@@ -51,7 +51,22 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuzzer_common.hpp"
|
#include <cassert>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// the round-trip checks below are assertions; NDEBUG would compile them away
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error "the fuzzer drivers must be built without NDEBUG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
||||||
|
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
||||||
|
static bool same_value(const json& lhs, const json& rhs)
|
||||||
|
{
|
||||||
|
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
||||||
|
}
|
||||||
|
|
||||||
// value-stable comparison for the round-trip checks below; see the note
|
// value-stable comparison for the round-trip checks below; see the note
|
||||||
// above on why this compares dump()s rather than the json values directly
|
// above on why this compares dump()s rather than the json values directly
|
||||||
@@ -65,9 +80,23 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
{
|
{
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions
|
// step 0: parse input without exceptions; a parse error must then be
|
||||||
|
// reported as a discarded value, never thrown
|
||||||
|
json j_noexcept;
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
json const j_noexcept = parse_without_exceptions([&] { return json::from_bjdata(vec1, true, false); }, noexcept_threw);
|
try
|
||||||
|
{
|
||||||
|
j_noexcept = json::from_bjdata(vec1, true, false);
|
||||||
|
}
|
||||||
|
catch (const json::parse_error&)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const json::exception&)
|
||||||
|
{
|
||||||
|
// type and out-of-range errors are not parse errors and still throw
|
||||||
|
noexcept_threw = true;
|
||||||
|
}
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -25,8 +25,23 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "fuzzer_common.hpp"
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// the round-trip checks below are assertions; NDEBUG would compile them away
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error "the fuzzer drivers must be built without NDEBUG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
||||||
|
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
||||||
|
static bool same_value(const json& lhs, const json& rhs)
|
||||||
|
{
|
||||||
|
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@@ -57,9 +72,23 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
|||||||
|
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions
|
// step 0: parse input without exceptions; a parse error must then be
|
||||||
|
// reported as a discarded value, never thrown
|
||||||
|
json j_noexcept;
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
json const j_noexcept = parse_without_exceptions([&] { return json::from_bon8(vec1, true, false); }, noexcept_threw);
|
try
|
||||||
|
{
|
||||||
|
j_noexcept = json::from_bon8(vec1, true, false);
|
||||||
|
}
|
||||||
|
catch (const json::parse_error&)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const json::exception&)
|
||||||
|
{
|
||||||
|
// type and out-of-range errors are not parse errors and still throw
|
||||||
|
noexcept_threw = true;
|
||||||
|
}
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -21,16 +21,45 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuzzer_common.hpp"
|
#include <cassert>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// the round-trip checks below are assertions; NDEBUG would compile them away
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error "the fuzzer drivers must be built without NDEBUG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
||||||
|
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
||||||
|
static bool same_value(const json& lhs, const json& rhs)
|
||||||
|
{
|
||||||
|
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
||||||
|
}
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions
|
// step 0: parse input without exceptions; a parse error must then be
|
||||||
|
// reported as a discarded value, never thrown
|
||||||
|
json j_noexcept;
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
json const j_noexcept = parse_without_exceptions([&] { return json::from_bson(vec1, true, false); }, noexcept_threw);
|
try
|
||||||
|
{
|
||||||
|
j_noexcept = json::from_bson(vec1, true, false);
|
||||||
|
}
|
||||||
|
catch (const json::parse_error&)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const json::exception&)
|
||||||
|
{
|
||||||
|
// type and out-of-range errors are not parse errors and still throw
|
||||||
|
noexcept_threw = true;
|
||||||
|
}
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -21,16 +21,45 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuzzer_common.hpp"
|
#include <cassert>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// the round-trip checks below are assertions; NDEBUG would compile them away
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error "the fuzzer drivers must be built without NDEBUG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
||||||
|
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
||||||
|
static bool same_value(const json& lhs, const json& rhs)
|
||||||
|
{
|
||||||
|
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
||||||
|
}
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions
|
// step 0: parse input without exceptions; a parse error must then be
|
||||||
|
// reported as a discarded value, never thrown
|
||||||
|
json j_noexcept;
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
json const j_noexcept = parse_without_exceptions([&] { return json::from_cbor(vec1, true, false); }, noexcept_threw);
|
try
|
||||||
|
{
|
||||||
|
j_noexcept = json::from_cbor(vec1, true, false);
|
||||||
|
}
|
||||||
|
catch (const json::parse_error&)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const json::exception&)
|
||||||
|
{
|
||||||
|
// type and out-of-range errors are not parse errors and still throw
|
||||||
|
noexcept_threw = true;
|
||||||
|
}
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -22,14 +22,43 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuzzer_common.hpp"
|
#include <cassert>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// the round-trip checks below are assertions; NDEBUG would compile them away
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error "the fuzzer drivers must be built without NDEBUG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
||||||
|
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
||||||
|
static bool same_value(const json& lhs, const json& rhs)
|
||||||
|
{
|
||||||
|
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
||||||
|
}
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
// step 0: parse input without exceptions
|
// step 0: parse input without exceptions; a parse error must then be
|
||||||
|
// reported as a discarded value, never thrown
|
||||||
|
json j_noexcept;
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
json const j_noexcept = parse_without_exceptions([&] { return json::parse(data, data + size, nullptr, false); }, noexcept_threw);
|
try
|
||||||
|
{
|
||||||
|
j_noexcept = json::parse(data, data + size, nullptr, false);
|
||||||
|
}
|
||||||
|
catch (const json::parse_error&)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const json::exception&)
|
||||||
|
{
|
||||||
|
// type and out-of-range errors are not parse errors and still throw
|
||||||
|
noexcept_threw = true;
|
||||||
|
}
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -21,16 +21,45 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuzzer_common.hpp"
|
#include <cassert>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// the round-trip checks below are assertions; NDEBUG would compile them away
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error "the fuzzer drivers must be built without NDEBUG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
||||||
|
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
||||||
|
static bool same_value(const json& lhs, const json& rhs)
|
||||||
|
{
|
||||||
|
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
||||||
|
}
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions
|
// step 0: parse input without exceptions; a parse error must then be
|
||||||
|
// reported as a discarded value, never thrown
|
||||||
|
json j_noexcept;
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
json const j_noexcept = parse_without_exceptions([&] { return json::from_msgpack(vec1, true, false); }, noexcept_threw);
|
try
|
||||||
|
{
|
||||||
|
j_noexcept = json::from_msgpack(vec1, true, false);
|
||||||
|
}
|
||||||
|
catch (const json::parse_error&)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const json::exception&)
|
||||||
|
{
|
||||||
|
// type and out-of-range errors are not parse errors and still throw
|
||||||
|
noexcept_threw = true;
|
||||||
|
}
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -30,16 +30,45 @@ The provided function `LLVMFuzzerTestOneInput` can be used in different fuzzer
|
|||||||
drivers.
|
drivers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuzzer_common.hpp"
|
#include <cassert>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
// the round-trip checks below are assertions; NDEBUG would compile them away
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error "the fuzzer drivers must be built without NDEBUG"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
||||||
|
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
||||||
|
static bool same_value(const json& lhs, const json& rhs)
|
||||||
|
{
|
||||||
|
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
||||||
|
}
|
||||||
|
|
||||||
// see http://llvm.org/docs/LibFuzzer.html
|
// see http://llvm.org/docs/LibFuzzer.html
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> const vec1(data, data + size);
|
std::vector<uint8_t> const vec1(data, data + size);
|
||||||
|
|
||||||
// step 0: parse input without exceptions
|
// step 0: parse input without exceptions; a parse error must then be
|
||||||
|
// reported as a discarded value, never thrown
|
||||||
|
json j_noexcept;
|
||||||
bool noexcept_threw = false;
|
bool noexcept_threw = false;
|
||||||
json const j_noexcept = parse_without_exceptions([&] { return json::from_ubjson(vec1, true, false); }, noexcept_threw);
|
try
|
||||||
|
{
|
||||||
|
j_noexcept = json::from_ubjson(vec1, true, false);
|
||||||
|
}
|
||||||
|
catch (const json::parse_error&)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (const json::exception&)
|
||||||
|
{
|
||||||
|
// type and out-of-range errors are not parse errors and still throw
|
||||||
|
noexcept_threw = true;
|
||||||
|
}
|
||||||
// whether step 1 succeeded; if not, the catch blocks below check that
|
// whether step 1 succeeded; if not, the catch blocks below check that
|
||||||
// step 0 failed, too
|
// step 0 failed, too
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
|
|||||||
@@ -1,51 +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
|
|
||||||
|
|
||||||
// code shared by the fuzzer drivers tests/src/fuzzer-parse_*.cpp
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cassert> // assert
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
using nlohmann::json; // NOLINT(google-global-names-in-headers): shared by all fuzzer drivers
|
|
||||||
|
|
||||||
// the round-trip checks of the drivers are assertions; NDEBUG would compile them away
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error "the fuzzer drivers must be built without NDEBUG"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// compares dumps rather than values, because NaN != NaN; keep writes strings
|
|
||||||
// byte for byte, so ill-formed UTF-8 that a binary reader accepts cannot throw
|
|
||||||
inline bool same_value(const json& lhs, const json& rhs)
|
|
||||||
{
|
|
||||||
return lhs.dump(-1, ' ', false, json::error_handler_t::keep) == rhs.dump(-1, ' ', false, json::error_handler_t::keep);
|
|
||||||
}
|
|
||||||
|
|
||||||
// step 0 of each driver: parse the input without exceptions; a parse error
|
|
||||||
// must then be reported as a discarded value, never thrown. Type and
|
|
||||||
// out-of-range errors are not parse errors and still throw; then @a threw is
|
|
||||||
// set and null is returned.
|
|
||||||
template<typename Parse>
|
|
||||||
json parse_without_exceptions(Parse parse, bool& threw)
|
|
||||||
{
|
|
||||||
threw = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return parse();
|
|
||||||
}
|
|
||||||
catch (const json::parse_error&)
|
|
||||||
{
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
catch (const json::exception&)
|
|
||||||
{
|
|
||||||
threw = true;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
@@ -1,185 +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
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstddef> // size_t
|
|
||||||
#include <cstdint> // uint8_t (via json::binary_t)
|
|
||||||
#include <limits> // numeric_limits
|
|
||||||
#include <string> // string, to_string
|
|
||||||
#include <vector> // vector
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
// the loggers are defined in this header only, so their vtables are emitted in
|
|
||||||
// every test that includes it
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wweak-vtables"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace utils
|
|
||||||
{
|
|
||||||
/// a SAX event consumer that records every event it receives as a
|
|
||||||
/// human-readable string, used by the deserialization tests to check the
|
|
||||||
/// exact sequence of SAX events a parse run produces
|
|
||||||
struct SaxEventLogger : public nlohmann::json_sax<nlohmann::json>
|
|
||||||
{
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
bool null() override
|
|
||||||
{
|
|
||||||
events.emplace_back("null()");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool boolean(bool val) override
|
|
||||||
{
|
|
||||||
events.emplace_back(val ? "boolean(true)" : "boolean(false)");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool number_integer(json::number_integer_t val) override
|
|
||||||
{
|
|
||||||
events.push_back("number_integer(" + std::to_string(val) + ")");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool number_unsigned(json::number_unsigned_t val) override
|
|
||||||
{
|
|
||||||
events.push_back("number_unsigned(" + std::to_string(val) + ")");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool number_float(json::number_float_t /*val*/, const std::string& s) override
|
|
||||||
{
|
|
||||||
events.push_back("number_float(" + s + ")");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool string(std::string& val) override
|
|
||||||
{
|
|
||||||
events.push_back("string(" + val + ")");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool binary(json::binary_t& val) override
|
|
||||||
{
|
|
||||||
std::string binary_contents = "binary(";
|
|
||||||
std::string comma_space;
|
|
||||||
for (const auto b : val)
|
|
||||||
{
|
|
||||||
binary_contents.append(comma_space);
|
|
||||||
binary_contents.append(std::to_string(static_cast<int>(b)));
|
|
||||||
comma_space = ", ";
|
|
||||||
}
|
|
||||||
binary_contents.append(")");
|
|
||||||
events.push_back(binary_contents);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool start_object(std::size_t elements) override
|
|
||||||
{
|
|
||||||
if (elements == (std::numeric_limits<std::size_t>::max)())
|
|
||||||
{
|
|
||||||
events.emplace_back("start_object()");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
events.push_back("start_object(" + std::to_string(elements) + ")");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool key(std::string& val) override
|
|
||||||
{
|
|
||||||
events.push_back("key(" + val + ")");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool end_object() override
|
|
||||||
{
|
|
||||||
events.emplace_back("end_object()");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool start_array(std::size_t elements) override
|
|
||||||
{
|
|
||||||
if (elements == (std::numeric_limits<std::size_t>::max)())
|
|
||||||
{
|
|
||||||
events.emplace_back("start_array()");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
events.push_back("start_array(" + std::to_string(elements) + ")");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool end_array() override
|
|
||||||
{
|
|
||||||
events.emplace_back("end_array()");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool parse_error(std::size_t position, const std::string& /*last_token*/, const json::exception& /*ex*/) override
|
|
||||||
{
|
|
||||||
errored = true;
|
|
||||||
events.push_back("parse_error(" + std::to_string(position) + ")");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> events {}; // NOLINT(readability-redundant-member-init)
|
|
||||||
bool errored = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger
|
|
||||||
{
|
|
||||||
bool start_object(std::size_t elements) override
|
|
||||||
{
|
|
||||||
if (elements == (std::numeric_limits<std::size_t>::max)())
|
|
||||||
{
|
|
||||||
events.emplace_back("start_object()");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
events.push_back("start_object(" + std::to_string(elements) + ")");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SaxEventLoggerExitAfterKey : public SaxEventLogger
|
|
||||||
{
|
|
||||||
bool key(std::string& val) override
|
|
||||||
{
|
|
||||||
events.push_back("key(" + val + ")");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SaxEventLoggerExitAfterStartArray : public SaxEventLogger
|
|
||||||
{
|
|
||||||
bool start_array(std::size_t elements) override
|
|
||||||
{
|
|
||||||
if (elements == (std::numeric_limits<std::size_t>::max)())
|
|
||||||
{
|
|
||||||
events.emplace_back("start_array()");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
events.push_back("start_array(" + std::to_string(elements) + ")");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace utils
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
@@ -370,7 +370,14 @@ TEST_CASE("copy of a deeply nested value survives a failing allocation (#5640)")
|
|||||||
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
||||||
SECTION("std::map-backed object_t")
|
SECTION("std::map-backed object_t")
|
||||||
{
|
{
|
||||||
using bad_alloc_json = nlohmann::json::with_allocator_t<nth_alloc_fails_allocator>;
|
using bad_alloc_json = nlohmann::basic_json<std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
nth_alloc_fails_allocator>;
|
||||||
|
|
||||||
check_deep_copy_survives_failing_allocation<bad_alloc_json>(false);
|
check_deep_copy_survives_failing_allocation<bad_alloc_json>(false);
|
||||||
check_deep_copy_survives_failing_allocation<bad_alloc_json>(true);
|
check_deep_copy_survives_failing_allocation<bad_alloc_json>(true);
|
||||||
@@ -378,7 +385,14 @@ TEST_CASE("copy of a deeply nested value survives a failing allocation (#5640)")
|
|||||||
|
|
||||||
SECTION("ordered_map-backed object_t")
|
SECTION("ordered_map-backed object_t")
|
||||||
{
|
{
|
||||||
using bad_alloc_ordered_json = nlohmann::ordered_json::with_allocator_t<nth_alloc_fails_allocator>;
|
using bad_alloc_ordered_json = nlohmann::basic_json<nlohmann::ordered_map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
nth_alloc_fails_allocator>;
|
||||||
|
|
||||||
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(false);
|
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(false);
|
||||||
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(true);
|
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(true);
|
||||||
@@ -436,7 +450,14 @@ struct scratch_counting_allocator : std::allocator<T>
|
|||||||
|
|
||||||
TEST_CASE("deep copy uses the provided allocator")
|
TEST_CASE("deep copy uses the provided allocator")
|
||||||
{
|
{
|
||||||
using counting_json = nlohmann::json::with_allocator_t<scratch_counting_allocator>;
|
using counting_json = nlohmann::basic_json<std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
scratch_counting_allocator>;
|
||||||
|
|
||||||
// deeper than the 128 levels the copy constructor descends into, so the
|
// deeper than the 128 levels the copy constructor descends into, so the
|
||||||
// innermost objects are copied by the iterative deep copy
|
// innermost objects are copied by the iterative deep copy
|
||||||
@@ -495,7 +516,14 @@ TEST_CASE("converting a deeply nested value from another specialization fails cl
|
|||||||
// the allocator in noexcept constructors, so a failing construction crashes
|
// the allocator in noexcept constructors, so a failing construction crashes
|
||||||
// the program there instead of throwing std::bad_alloc. Nothing to check.
|
// the program there instead of throwing std::bad_alloc. Nothing to check.
|
||||||
#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
#if !(defined(_MSC_VER) && _MSC_VER < 1910 && defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
||||||
using countdown_json = nlohmann::json::with_allocator_t<countdown_allocator>;
|
using countdown_json = nlohmann::basic_json<std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
countdown_allocator>;
|
||||||
|
|
||||||
// deeper than the 128 levels the converting constructor descends into, so
|
// deeper than the 128 levels the converting constructor descends into, so
|
||||||
// that failures land on both sides of the bound - or, built with
|
// that failures land on both sides of the bound - or, built with
|
||||||
@@ -603,7 +631,14 @@ TEST_CASE("destructor performs no allocation, only deallocation")
|
|||||||
// Since that stack could itself throw bad_alloc from inside the
|
// Since that stack could itself throw bad_alloc from inside the
|
||||||
// noexcept destructor (#5135), destroy() no longer allocates anything:
|
// noexcept destructor (#5135), destroy() no longer allocates anything:
|
||||||
// it only ever frees what is already there.
|
// it only ever frees what is already there.
|
||||||
using counting_json = nlohmann::json::with_allocator_t<counting_allocator>;
|
using counting_json = nlohmann::basic_json<std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
counting_allocator>;
|
||||||
|
|
||||||
SECTION("array")
|
SECTION("array")
|
||||||
{
|
{
|
||||||
@@ -648,7 +683,14 @@ TEST_CASE("destructor performs no allocation, only deallocation")
|
|||||||
TEST_CASE("a failed allocation leaves the value unchanged")
|
TEST_CASE("a failed allocation leaves the value unchanged")
|
||||||
{
|
{
|
||||||
// create JSON type using the throwing allocator
|
// create JSON type using the throwing allocator
|
||||||
using my_json = nlohmann::json::with_allocator_t<my_allocator>;
|
using my_json = nlohmann::basic_json<std::map,
|
||||||
|
std::vector,
|
||||||
|
std::string,
|
||||||
|
bool,
|
||||||
|
std::int64_t,
|
||||||
|
std::uint64_t,
|
||||||
|
double,
|
||||||
|
my_allocator>;
|
||||||
|
|
||||||
// Each of these creates a string, array, object, or binary value. The
|
// Each of these creates a string, array, object, or binary value. The
|
||||||
// value must be created before the type is changed: otherwise, a failed
|
// value must be created before the type is changed: otherwise, a failed
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ namespace
|
|||||||
// the binary formats as function pointers for "Binary formats with narrow number types";
|
// the binary formats as function pointers for "Binary formats with narrow number types";
|
||||||
// named functions rather than lambdas, because clang 3.5 cannot convert a lambda
|
// named functions rather than lambdas, because clang 3.5 cannot convert a lambda
|
||||||
// to a function pointer in the braced initializer of the format table
|
// to a function pointer in the braced initializer of the format table
|
||||||
using narrow_json = nlohmann::json::with_integers_t<std::int32_t, std::uint32_t>::with_float_t<float>;
|
using narrow_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint32_t, float>;
|
||||||
using bytes = std::vector<std::uint8_t>;
|
using bytes = std::vector<std::uint8_t>;
|
||||||
|
|
||||||
bytes encode_cbor(const json& j)
|
bytes encode_cbor(const json& j)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ using nlohmann::json;
|
|||||||
#include <cstdint> // uint32_t, uint64_t
|
#include <cstdint> // uint32_t, uint64_t
|
||||||
#include <cstdlib> // strtod
|
#include <cstdlib> // strtod
|
||||||
#include <cstring> // memcpy
|
#include <cstring> // memcpy
|
||||||
#include <limits> // numeric_limits
|
|
||||||
#include <sstream> // stringstream
|
#include <sstream> // stringstream
|
||||||
#include <string> // string
|
#include <string> // string
|
||||||
#include <utility> // pair
|
#include <utility> // pair
|
||||||
@@ -892,39 +891,8 @@ TEST_CASE("Eisel-Lemire float conversion")
|
|||||||
|
|
||||||
SECTION("128-bit products and leading zeros")
|
SECTION("128-bit products and leading zeros")
|
||||||
{
|
{
|
||||||
const auto check_product = [](std::uint64_t a, std::uint64_t b)
|
|
||||||
{
|
|
||||||
const auto product = nlohmann::detail::full_multiplication(a, b);
|
|
||||||
CHECK(big_from(product.high, product.low) == big_mul(big_from(0, a), big_from(0, b)));
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::uint64_t max = (std::numeric_limits<std::uint64_t>::max)();
|
|
||||||
const std::array<std::pair<std::uint64_t, std::uint64_t>, 13> edge_cases =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
{0, 0},
|
|
||||||
{0, 1},
|
|
||||||
{1, 1},
|
|
||||||
{1, max},
|
|
||||||
{0xFFFFFFFFu, 0x100000000u},
|
|
||||||
{0x100000000u, 0x100000000u},
|
|
||||||
{0x100000001u, 0x100000001u},
|
|
||||||
{max, max},
|
|
||||||
{max, 2},
|
|
||||||
{0xFFFFFFFF00000000u, 0x100000001u},
|
|
||||||
{0x100000001u, 0xFFFFFFFF00000000u},
|
|
||||||
{max, 1},
|
|
||||||
{2, max},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& test : edge_cases)
|
|
||||||
{
|
|
||||||
check_product(test.first, test.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// whichever implementation the compiler gets (with or without a
|
// whichever implementation the compiler gets (with or without a
|
||||||
// 128-bit integer type or a builtin / intrinsic)
|
// 128-bit integer type or a builtin)
|
||||||
std::uint64_t state = 42;
|
std::uint64_t state = 42;
|
||||||
for (int i = 0; i < 10000; ++i)
|
for (int i = 0; i < 10000; ++i)
|
||||||
{
|
{
|
||||||
@@ -933,7 +901,8 @@ TEST_CASE("Eisel-Lemire float conversion")
|
|||||||
state ^= state << 17u;
|
state ^= state << 17u;
|
||||||
const std::uint64_t a = state;
|
const std::uint64_t a = state;
|
||||||
const std::uint64_t b = (state * 0x9E3779B97F4A7C15u) >> (i % 64);
|
const std::uint64_t b = (state * 0x9E3779B97F4A7C15u) >> (i % 64);
|
||||||
check_product(a, b);
|
const auto product = nlohmann::detail::full_multiplication(a, b);
|
||||||
|
CHECK(big_from(product.high, product.low) == big_mul(big_from(0, a), big_from(0, b)));
|
||||||
|
|
||||||
const int k = i % 64;
|
const int k = i % 64;
|
||||||
const std::uint64_t x = (std::uint64_t{1} << k) | (a & ((std::uint64_t{1} << k) - 1));
|
const std::uint64_t x = (std::uint64_t{1} << k) | (a & ((std::uint64_t{1} << k) - 1));
|
||||||
|
|||||||
@@ -37,15 +37,194 @@ using nlohmann::json;
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "sax_countdown.hpp"
|
|
||||||
#include "sax_event_loggers.hpp"
|
|
||||||
#include "test_utils.hpp"
|
#include "test_utils.hpp"
|
||||||
|
|
||||||
using utils::SaxCountdown;
|
|
||||||
using utils::SaxEventLogger;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
class SaxEventLogger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool null()
|
||||||
|
{
|
||||||
|
events.emplace_back("null()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool val)
|
||||||
|
{
|
||||||
|
events.emplace_back(val ? "boolean(true)" : "boolean(false)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(json::number_integer_t val)
|
||||||
|
{
|
||||||
|
events.push_back("number_integer(" + std::to_string(val) + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(json::number_unsigned_t val)
|
||||||
|
{
|
||||||
|
events.push_back("number_unsigned(" + std::to_string(val) + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(json::number_float_t /*unused*/, const std::string& s)
|
||||||
|
{
|
||||||
|
events.push_back("number_float(" + s + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(std::string& val)
|
||||||
|
{
|
||||||
|
events.push_back("string(" + val + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(json::binary_t& val)
|
||||||
|
{
|
||||||
|
std::string binary_contents = "binary(";
|
||||||
|
std::string comma_space;
|
||||||
|
for (auto b : val)
|
||||||
|
{
|
||||||
|
binary_contents.append(comma_space);
|
||||||
|
binary_contents.append(std::to_string(static_cast<int>(b)));
|
||||||
|
comma_space = ", ";
|
||||||
|
}
|
||||||
|
binary_contents.append(")");
|
||||||
|
events.push_back(binary_contents);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t elements)
|
||||||
|
{
|
||||||
|
if (elements == (std::numeric_limits<std::size_t>::max)())
|
||||||
|
{
|
||||||
|
events.emplace_back("start_object()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_object(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(std::string& val)
|
||||||
|
{
|
||||||
|
events.push_back("key(" + val + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object()
|
||||||
|
{
|
||||||
|
events.emplace_back("end_object()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t elements)
|
||||||
|
{
|
||||||
|
if (elements == (std::numeric_limits<std::size_t>::max)())
|
||||||
|
{
|
||||||
|
events.emplace_back("start_array()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_array(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array()
|
||||||
|
{
|
||||||
|
events.emplace_back("end_array()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/)
|
||||||
|
{
|
||||||
|
errored = true;
|
||||||
|
events.push_back("parse_error(" + std::to_string(position) + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> events {}; // NOLINT(readability-redundant-member-init)
|
||||||
|
bool errored = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SaxCountdown : public nlohmann::json::json_sax_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SaxCountdown(const int count) : events_left(count)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool null() override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool /*val*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(json::number_integer_t /*val*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(json::number_unsigned_t /*val*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(std::string& /*val*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(json::binary_t& /*val*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t /*elements*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(std::string& /*val*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object() override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t /*elements*/) override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array() override
|
||||||
|
{
|
||||||
|
return events_left-- > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int events_left = 0;
|
||||||
|
};
|
||||||
|
|
||||||
json parser_helper(const std::string& s);
|
json parser_helper(const std::string& s);
|
||||||
bool accept_helper(const std::string& s);
|
bool accept_helper(const std::string& s);
|
||||||
void comments_helper(const std::string& s);
|
void comments_helper(const std::string& s);
|
||||||
|
|||||||
@@ -824,7 +824,7 @@ struct unordered_object_t : std::map<Key, Value, directed_less<Key>, Allocator>
|
|||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
using unordered_json = nlohmann::json::with_object_t<unordered_object_t>;
|
using unordered_json = nlohmann::basic_json<unordered_object_t>;
|
||||||
|
|
||||||
// the entries "0" to "9", enumerated in ascending or in descending order
|
// the entries "0" to "9", enumerated in ascending or in descending order
|
||||||
unordered_json make_unordered_object(const bool descending)
|
unordered_json make_unordered_object(const bool descending)
|
||||||
@@ -875,7 +875,7 @@ struct key_case_less
|
|||||||
|
|
||||||
template<class Key, class Value, class /*Compare*/, class Allocator>
|
template<class Key, class Value, class /*Compare*/, class Allocator>
|
||||||
using key_case_map = std::map<Key, Value, key_case_less, Allocator>;
|
using key_case_map = std::map<Key, Value, key_case_less, Allocator>;
|
||||||
using key_case_json = nlohmann::json::with_object_t<key_case_map>;
|
using key_case_json = nlohmann::basic_json<key_case_map>;
|
||||||
|
|
||||||
// the innermost value of a chain of single-element arrays
|
// the innermost value of a chain of single-element arrays
|
||||||
template<typename Json>
|
template<typename Json>
|
||||||
@@ -905,7 +905,7 @@ struct case_insensitive_less
|
|||||||
|
|
||||||
template<class Key, class Value, class /*Compare*/, class Allocator>
|
template<class Key, class Value, class /*Compare*/, class Allocator>
|
||||||
using case_insensitive_map = std::map<Key, Value, case_insensitive_less, Allocator>;
|
using case_insensitive_map = std::map<Key, Value, case_insensitive_less, Allocator>;
|
||||||
using ci_json = nlohmann::json::with_object_t<case_insensitive_map>;
|
using ci_json = nlohmann::basic_json<case_insensitive_map>;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_CASE("equality of objects whose entries have no fixed order")
|
TEST_CASE("equality of objects whose entries have no fixed order")
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace
|
|||||||
|
|
||||||
// std::deque has no capacity() member function, which the library only needs
|
// std::deque has no capacity() member function, which the library only needs
|
||||||
// to detect a reallocation for JSON_DIAGNOSTICS
|
// to detect a reallocation for JSON_DIAGNOSTICS
|
||||||
using deque_json = nlohmann::json::with_array_t<std::deque>;
|
using deque_json = nlohmann::basic_json<std::map, std::deque>;
|
||||||
|
|
||||||
// a std::vector whose at() is hidden: the library performs its own bounds
|
// a std::vector whose at() is hidden: the library performs its own bounds
|
||||||
// check and must not fall back to the container's checked accessor
|
// check and must not fall back to the container's checked accessor
|
||||||
@@ -39,7 +39,7 @@ class vector_without_at : public std::vector<T, Allocator>
|
|||||||
void at() = delete;
|
void at() = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
using no_at_json = nlohmann::json::with_array_t<vector_without_at>;
|
using no_at_json = nlohmann::basic_json<std::map, vector_without_at>;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class no_key_compare_map
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using no_key_compare_json = nlohmann::json::with_object_t<no_key_compare_map>;
|
using no_key_compare_json = nlohmann::basic_json<no_key_compare_map>;
|
||||||
|
|
||||||
// An ObjectType whose erase(iterator) returns void rather than the following
|
// An ObjectType whose erase(iterator) returns void rather than the following
|
||||||
// iterator, as for instance Abseil's hash maps do
|
// iterator, as for instance Abseil's hash maps do
|
||||||
@@ -196,7 +196,7 @@ struct void_erase_map : std::map<Key, T, Compare, Allocator>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using void_erase_json = nlohmann::json::with_object_t<void_erase_map>;
|
using void_erase_json = nlohmann::basic_json<void_erase_map>;
|
||||||
|
|
||||||
// wraps an iterator, but only offers the LegacyForwardIterator operations,
|
// wraps an iterator, but only offers the LegacyForwardIterator operations,
|
||||||
// like the iterators of std::unordered_map and other hash maps
|
// like the iterators of std::unordered_map and other hash maps
|
||||||
@@ -388,7 +388,7 @@ class forward_only_map
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using forward_only_json = nlohmann::json::with_object_t<forward_only_map>;
|
using forward_only_json = nlohmann::basic_json<forward_only_map>;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@@ -36,15 +36,155 @@ using nlohmann::json;
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <valarray>
|
#include <valarray>
|
||||||
|
|
||||||
#include "sax_event_loggers.hpp"
|
|
||||||
|
|
||||||
using utils::SaxEventLogger;
|
|
||||||
using utils::SaxEventLoggerExitAfterKey;
|
|
||||||
using utils::SaxEventLoggerExitAfterStartArray;
|
|
||||||
using utils::SaxEventLoggerExitAfterStartObject;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
struct SaxEventLogger : public nlohmann::json_sax<json>
|
||||||
|
{
|
||||||
|
bool null() override
|
||||||
|
{
|
||||||
|
events.emplace_back("null()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boolean(bool val) override
|
||||||
|
{
|
||||||
|
events.emplace_back(val ? "boolean(true)" : "boolean(false)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_integer(json::number_integer_t val) override
|
||||||
|
{
|
||||||
|
events.push_back("number_integer(" + std::to_string(val) + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_unsigned(json::number_unsigned_t val) override
|
||||||
|
{
|
||||||
|
events.push_back("number_unsigned(" + std::to_string(val) + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool number_float(json::number_float_t /*val*/, const std::string& s) override
|
||||||
|
{
|
||||||
|
events.push_back("number_float(" + s + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string(std::string& val) override
|
||||||
|
{
|
||||||
|
events.push_back("string(" + val + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool binary(json::binary_t& val) override
|
||||||
|
{
|
||||||
|
std::string binary_contents = "binary(";
|
||||||
|
std::string comma_space;
|
||||||
|
for (auto b : val)
|
||||||
|
{
|
||||||
|
binary_contents.append(comma_space);
|
||||||
|
binary_contents.append(std::to_string(static_cast<int>(b)));
|
||||||
|
comma_space = ", ";
|
||||||
|
}
|
||||||
|
binary_contents.append(")");
|
||||||
|
events.push_back(binary_contents);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_object(std::size_t elements) override
|
||||||
|
{
|
||||||
|
if (elements == (std::numeric_limits<std::size_t>::max)())
|
||||||
|
{
|
||||||
|
events.emplace_back("start_object()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_object(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool key(std::string& val) override
|
||||||
|
{
|
||||||
|
events.push_back("key(" + val + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_object() override
|
||||||
|
{
|
||||||
|
events.emplace_back("end_object()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start_array(std::size_t elements) override
|
||||||
|
{
|
||||||
|
if (elements == (std::numeric_limits<std::size_t>::max)())
|
||||||
|
{
|
||||||
|
events.emplace_back("start_array()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_array(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool end_array() override
|
||||||
|
{
|
||||||
|
events.emplace_back("end_array()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_error(std::size_t position, const std::string& /*last_token*/, const json::exception& /*ex*/) override
|
||||||
|
{
|
||||||
|
events.push_back("parse_error(" + std::to_string(position) + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> events {}; // NOLINT(readability-redundant-member-init)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger
|
||||||
|
{
|
||||||
|
bool start_object(std::size_t elements) override
|
||||||
|
{
|
||||||
|
if (elements == (std::numeric_limits<std::size_t>::max)())
|
||||||
|
{
|
||||||
|
events.emplace_back("start_object()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_object(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SaxEventLoggerExitAfterKey : public SaxEventLogger
|
||||||
|
{
|
||||||
|
bool key(std::string& val) override
|
||||||
|
{
|
||||||
|
events.push_back("key(" + val + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SaxEventLoggerExitAfterStartArray : public SaxEventLogger
|
||||||
|
{
|
||||||
|
bool start_array(std::size_t elements) override
|
||||||
|
{
|
||||||
|
if (elements == (std::numeric_limits<std::size_t>::max)())
|
||||||
|
{
|
||||||
|
events.emplace_back("start_array()");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.push_back("start_array(" + std::to_string(elements) + ")");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class proxy_iterator
|
class proxy_iterator
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -157,13 +157,13 @@ TEST_CASE("hash<nlohmann::json>")
|
|||||||
// the ends of the integer ranges, which equal floats exactly
|
// the ends of the integer ranges, which equal floats exactly
|
||||||
const auto int_min = (std::numeric_limits<json::number_integer_t>::min)();
|
const auto int_min = (std::numeric_limits<json::number_integer_t>::min)();
|
||||||
const auto int_max = (std::numeric_limits<json::number_integer_t>::max)();
|
const auto int_max = (std::numeric_limits<json::number_integer_t>::max)();
|
||||||
const auto two_63 = static_cast<json::number_unsigned_t>(1) << 63U;
|
const auto two_63 = json::number_unsigned_t(1) << 63U;
|
||||||
CHECK(json(int_min) == json(-9223372036854775808.0));
|
CHECK(json(int_min) == json(-9223372036854775808.0));
|
||||||
CHECK(std::hash<json> {}(json(int_min)) == std::hash<json> {}(json(-9223372036854775808.0)));
|
CHECK(std::hash<json> {}(json(int_min)) == std::hash<json> {}(json(-9223372036854775808.0)));
|
||||||
CHECK(json(two_63) == json(9223372036854775808.0));
|
CHECK(json(two_63) == json(9223372036854775808.0));
|
||||||
CHECK(std::hash<json> {}(json(two_63)) == std::hash<json> {}(json(9223372036854775808.0)));
|
CHECK(std::hash<json> {}(json(two_63)) == std::hash<json> {}(json(9223372036854775808.0)));
|
||||||
CHECK(json(static_cast<json::number_unsigned_t>(int_max)) == json(int_max));
|
CHECK(json(json::number_unsigned_t(int_max)) == json(int_max));
|
||||||
CHECK(std::hash<json> {}(json(static_cast<json::number_unsigned_t>(int_max))) == std::hash<json> {}(json(int_max)));
|
CHECK(std::hash<json> {}(json(json::number_unsigned_t(int_max))) == std::hash<json> {}(json(int_max)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("hash<nlohmann::ordered_json>")
|
TEST_CASE("hash<nlohmann::ordered_json>")
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ TEST_CASE("issue #5392 - binary writers on deeply nested values")
|
|||||||
{
|
{
|
||||||
for (std::size_t depth = 120; depth <= 140; ++depth)
|
for (std::size_t depth = 120; depth <= 140; ++depth)
|
||||||
{
|
{
|
||||||
CAPTURE(depth)
|
CAPTURE(depth);
|
||||||
|
|
||||||
const json array = nested_array(depth, json(7));
|
const json array = nested_array(depth, json(7));
|
||||||
CHECK(json::from_cbor(json::to_cbor(array)) == array);
|
CHECK(json::from_cbor(json::to_cbor(array)) == array);
|
||||||
@@ -464,7 +464,7 @@ TEST_CASE("issue #5392 - binary writers on deeply nested values")
|
|||||||
nlohmann::detail::recursion_depth_limit() + 1, nlohmann::detail::recursion_depth_limit() + 2
|
nlohmann::detail::recursion_depth_limit() + 1, nlohmann::detail::recursion_depth_limit() + 2
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
CAPTURE(depth)
|
CAPTURE(depth);
|
||||||
const json array = nested_array(depth, json(0));
|
const json array = nested_array(depth, json(0));
|
||||||
|
|
||||||
std::vector<std::uint8_t> expected_cbor(depth, 0x81);
|
std::vector<std::uint8_t> expected_cbor(depth, 0x81);
|
||||||
@@ -505,22 +505,10 @@ TEST_CASE("issue #5392 - binary writers on deeply nested values")
|
|||||||
const json discarded_leaf(json::value_t::discarded);
|
const json discarded_leaf(json::value_t::discarded);
|
||||||
const json deep_discarded = nested_array(depth, discarded_leaf);
|
const json deep_discarded = nested_array(depth, discarded_leaf);
|
||||||
|
|
||||||
// with diagnostics, the message names the path to the discarded leaf
|
CHECK_THROWS_WITH_AS(json::to_cbor(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error);
|
||||||
#if JSON_DIAGNOSTICS
|
CHECK_THROWS_WITH_AS(json::to_msgpack(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error);
|
||||||
std::string path;
|
CHECK_THROWS_WITH_AS(json::to_ubjson(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error);
|
||||||
for (std::size_t i = 0; i < depth; ++i)
|
CHECK_THROWS_WITH_AS(json::to_bjdata(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error);
|
||||||
{
|
|
||||||
path += "/0";
|
|
||||||
}
|
|
||||||
const std::string prefix = "[json.exception.type_error.321] (" + path + ") ";
|
|
||||||
#else
|
|
||||||
const std::string prefix = "[json.exception.type_error.321] ";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CHECK_THROWS_WITH_AS(json::to_cbor(deep_discarded), (prefix + "cannot serialize discarded value to CBOR").c_str(), json::type_error);
|
|
||||||
CHECK_THROWS_WITH_AS(json::to_msgpack(deep_discarded), (prefix + "cannot serialize discarded value to MessagePack").c_str(), json::type_error);
|
|
||||||
CHECK_THROWS_WITH_AS(json::to_ubjson(deep_discarded), (prefix + "cannot serialize discarded value to UBJSON").c_str(), json::type_error);
|
|
||||||
CHECK_THROWS_WITH_AS(json::to_bjdata(deep_discarded), (prefix + "cannot serialize discarded value to BJData").c_str(), json::type_error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("does not overflow the C++ stack")
|
SECTION("does not overflow the C++ stack")
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ TEST_CASE("locale-dependent test (LC_NUMERIC=de_DE)")
|
|||||||
// a floating-point type that is not a float or a double is written
|
// a floating-point type that is not a float or a double is written
|
||||||
// with snprintf, whose locale-specific decimal point and thousands
|
// with snprintf, whose locale-specific decimal point and thousands
|
||||||
// separator are undone afterwards
|
// separator are undone afterwards
|
||||||
using long_double_json = nlohmann::json::with_float_t<long double>;
|
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>;
|
||||||
CHECK(long_double_json(12345.5L).dump() == "12345.5");
|
CHECK(long_double_json(12345.5L).dump() == "12345.5");
|
||||||
CHECK(long_double_json(1.0L).dump() == "1.0");
|
CHECK(long_double_json(1.0L).dump() == "1.0");
|
||||||
CHECK(long_double_json(-0.25L).dump() == "-0.25");
|
CHECK(long_double_json(-0.25L).dump() == "-0.25");
|
||||||
@@ -272,7 +272,7 @@ TEST_CASE("locale changes between lexer construction and number conversion (#519
|
|||||||
}
|
}
|
||||||
text += "]";
|
text += "]";
|
||||||
|
|
||||||
using long_double_json = nlohmann::json::with_float_t<long double>;
|
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>;
|
||||||
|
|
||||||
// reference values, parsed without a locale switch
|
// reference values, parsed without a locale switch
|
||||||
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
||||||
@@ -432,7 +432,7 @@ TEST_CASE("locale changes during a single dump() (#5709 item 3)")
|
|||||||
// long double on 64-bit Arm, where it is IEEE-754 double) takes the
|
// long double on 64-bit Arm, where it is IEEE-754 double) takes the
|
||||||
// locale-independent to_chars() path instead, and this test is a no-op
|
// locale-independent to_chars() path instead, and this test is a no-op
|
||||||
// there.
|
// there.
|
||||||
using long_double_json = nlohmann::json::with_float_t<long double>;
|
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>;
|
||||||
using ld_limits = std::numeric_limits<long_double_json::number_float_t>;
|
using ld_limits = std::numeric_limits<long_double_json::number_float_t>;
|
||||||
const bool is_ieee_single_or_double =
|
const bool is_ieee_single_or_double =
|
||||||
(ld_limits::is_iec559 && ld_limits::digits == 24 && ld_limits::max_exponent == 128) ||
|
(ld_limits::is_iec559 && ld_limits::digits == 24 && ld_limits::max_exponent == 128) ||
|
||||||
|
|||||||
@@ -2432,8 +2432,8 @@ TEST_CASE("MessagePack numbers use the active union member (see #5644)")
|
|||||||
// used to read the union member that was not the active one, writing
|
// used to read the union member that was not the active one, writing
|
||||||
// wrong bytes for some values; std::int64_t/std::uint64_t (the default
|
// wrong bytes for some values; std::int64_t/std::uint64_t (the default
|
||||||
// types, where both members have the same width) were not affected
|
// types, where both members have the same width) were not affected
|
||||||
using int32_json = nlohmann::json::with_integers_t<std::int32_t, std::uint64_t>;
|
using int32_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint64_t, double>;
|
||||||
using int16_json = nlohmann::json::with_integers_t<std::int16_t, std::uint64_t>;
|
using int16_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int16_t, std::uint64_t, double>;
|
||||||
|
|
||||||
SECTION("number_integer_t = std::int32_t")
|
SECTION("number_integer_t = std::int32_t")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ using nlohmann::json;
|
|||||||
|
|
||||||
template<class K, class V, class dummy_compare, class A>
|
template<class K, class V, class dummy_compare, class A>
|
||||||
using my_workaround_fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
|
using my_workaround_fifo_map = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
|
||||||
using my_json = nlohmann::json::with_object_t<my_workaround_fifo_map>;
|
using my_json = nlohmann::basic_json<my_workaround_fifo_map>;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// for #977
|
// for #977
|
||||||
@@ -86,7 +86,8 @@ struct foo_serializer < T, typename std::enable_if < !std::is_same<foo, T>::valu
|
|||||||
};
|
};
|
||||||
} // namespace ns
|
} // namespace ns
|
||||||
|
|
||||||
using foo_json = nlohmann::json::with_json_serializer_t<ns::foo_serializer>;
|
using foo_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t,
|
||||||
|
std::uint64_t, double, std::allocator, ns::foo_serializer, std::vector<std::uint8_t>>;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// for #805
|
// for #805
|
||||||
@@ -253,7 +254,7 @@ TEST_CASE("regression tests 1")
|
|||||||
{
|
{
|
||||||
// create JSON class with nonstandard integer number type
|
// create JSON class with nonstandard integer number type
|
||||||
using custom_json =
|
using custom_json =
|
||||||
nlohmann::json::with_integers_t<std::int32_t, std::uint32_t>::with_float_t<float>;
|
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>;
|
||||||
custom_json j;
|
custom_json j;
|
||||||
j["int_1"] = 1;
|
j["int_1"] = 1;
|
||||||
CHECK(j["int_1"] == 1);
|
CHECK(j["int_1"] == 1);
|
||||||
@@ -469,17 +470,18 @@ TEST_CASE("regression tests 1")
|
|||||||
// create JSON class with nonstandard float number type
|
// create JSON class with nonstandard float number type
|
||||||
|
|
||||||
// float
|
// float
|
||||||
nlohmann::json::with_integers_t<std::int32_t, std::uint32_t>::with_float_t<float> const j_float =
|
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> const j_float =
|
||||||
1.23e25f;
|
1.23e25f;
|
||||||
CHECK(j_float.get<float>() == 1.23e25f);
|
CHECK(j_float.get<float>() == 1.23e25f);
|
||||||
|
|
||||||
// double
|
// double
|
||||||
nlohmann::json const j_double =
|
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> const j_double =
|
||||||
1.23e35;
|
1.23e35;
|
||||||
CHECK(j_double.get<double>() == 1.23e35);
|
CHECK(j_double.get<double>() == 1.23e35);
|
||||||
|
|
||||||
// long double
|
// long double
|
||||||
nlohmann::json::with_float_t<long double> const j_long_double = 1.23e45L;
|
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double>
|
||||||
|
const j_long_double = 1.23e45L;
|
||||||
CHECK(j_long_double.get<long double>() == 1.23e45L);
|
CHECK(j_long_double.get<long double>() == 1.23e45L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,18 @@ using ordered_json = nlohmann::ordered_json;
|
|||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// for #4804
|
// for #4804
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
using json_4804 = nlohmann::json::with_binary_t<std::vector<std::byte>>;
|
using json_4804 = nlohmann::basic_json<std::map, // ObjectType
|
||||||
|
std::vector, // ArrayType
|
||||||
|
std::string, // StringType
|
||||||
|
bool, // BooleanType
|
||||||
|
std::int64_t, // NumberIntegerType
|
||||||
|
std::uint64_t, // NumberUnsignedType
|
||||||
|
double, // NumberFloatType
|
||||||
|
std::allocator, // AllocatorType
|
||||||
|
nlohmann::adl_serializer, // JSONSerializer
|
||||||
|
std::vector<std::byte>, // BinaryType
|
||||||
|
void // CustomBaseClass
|
||||||
|
>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JSON_HAS_CPP_20
|
#ifdef JSON_HAS_CPP_20
|
||||||
@@ -96,7 +107,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
|
|||||||
// for #1021
|
// for #1021
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
using float_json = nlohmann::json::with_float_t<float>;
|
using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
|
||||||
|
|
||||||
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
|
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
|
||||||
namespace
|
namespace
|
||||||
@@ -144,8 +155,10 @@ struct failing_allocator : std::allocator<T>
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
using failing_json = nlohmann::json::with_allocator_t<failing_allocator>;
|
using failing_json = nlohmann::basic_json<std::map, std::vector, std::string, bool,
|
||||||
using failing_ordered_json = nlohmann::ordered_json::with_allocator_t<failing_allocator>;
|
std::int64_t, std::uint64_t, double, failing_allocator>;
|
||||||
|
using failing_ordered_json = nlohmann::basic_json<nlohmann::ordered_map, std::vector, std::string, bool,
|
||||||
|
std::int64_t, std::uint64_t, double, failing_allocator>;
|
||||||
|
|
||||||
// builds `depth` levels of nesting around a scalar, iteratively (never
|
// builds `depth` levels of nesting around a scalar, iteratively (never
|
||||||
// recursing: each wrap only moves the previous, already-built value, which
|
// recursing: each wrap only moves the previous, already-built value, which
|
||||||
|
|||||||
@@ -62,7 +62,18 @@ using ordered_json = nlohmann::ordered_json;
|
|||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// for #4804
|
// for #4804
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
using json_4804 = nlohmann::json::with_binary_t<std::vector<std::byte>>;
|
using json_4804 = nlohmann::basic_json<std::map, // ObjectType
|
||||||
|
std::vector, // ArrayType
|
||||||
|
std::string, // StringType
|
||||||
|
bool, // BooleanType
|
||||||
|
std::int64_t, // NumberIntegerType
|
||||||
|
std::uint64_t, // NumberUnsignedType
|
||||||
|
double, // NumberFloatType
|
||||||
|
std::allocator, // AllocatorType
|
||||||
|
nlohmann::adl_serializer, // JSONSerializer
|
||||||
|
std::vector<std::byte>, // BinaryType
|
||||||
|
void // CustomBaseClass
|
||||||
|
>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JSON_HAS_CPP_20
|
#ifdef JSON_HAS_CPP_20
|
||||||
@@ -919,7 +930,7 @@ TEST_CASE("regression test #5476 - array type without reserve()")
|
|||||||
{
|
{
|
||||||
// the capacity reserved for definite-length arrays must not require the
|
// the capacity reserved for definite-length arrays must not require the
|
||||||
// array type to have a reserve() member function
|
// array type to have a reserve() member function
|
||||||
using deque_json = nlohmann::json::with_array_t<std::deque>;
|
using deque_json = nlohmann::basic_json<std::map, std::deque>;
|
||||||
|
|
||||||
SECTION("std::deque")
|
SECTION("std::deque")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -367,7 +367,8 @@ TEST_CASE("dump for basic_json with long double number_float_t")
|
|||||||
// serializer::dump_float(x, std::false_type). That branch must use the
|
// serializer::dump_float(x, std::false_type). That branch must use the
|
||||||
// "%.*Lg" format specifier; using "%.*g" with a long double argument is
|
// "%.*Lg" format specifier; using "%.*g" with a long double argument is
|
||||||
// undefined behavior and corrupts the output.
|
// undefined behavior and corrupts the output.
|
||||||
using long_double_json = nlohmann::json::with_float_t<long double>;
|
using long_double_json = nlohmann::basic_json<std::map, std::vector, std::string,
|
||||||
|
bool, std::int64_t, std::uint64_t, long double>;
|
||||||
|
|
||||||
SECTION("round-trip dump/parse")
|
SECTION("round-trip dump/parse")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
# check_build_options
|
|
||||||
|
|
||||||
Checks that the Meson build and the pkg-config files offer the same options as the CMake target, so that a new CMake
|
|
||||||
option is not forgotten in one of them.
|
|
||||||
|
|
||||||
The compile definitions of the CMake target (`target_compile_definitions` in [`CMakeLists.txt`](../../CMakeLists.txt))
|
|
||||||
are the reference. When you add an option there, also add it to
|
|
||||||
|
|
||||||
- the pkg-config block in `CMakeLists.txt` (`NLOHMANN_JSON_PKGCONFIG_CFLAGS`),
|
|
||||||
- [`meson_options.txt`](../../meson_options.txt), named without the `JSON_` prefix and with the same default,
|
|
||||||
- [`meson.build`](../../meson.build) (`json_defines`), and
|
|
||||||
- the list of Meson options in
|
|
||||||
[`docs/mkdocs/docs/integration/package_managers.md`](../../docs/mkdocs/docs/integration/package_managers.md).
|
|
||||||
|
|
||||||
Run the check with
|
|
||||||
|
|
||||||
```shell
|
|
||||||
make check_build_options
|
|
||||||
```
|
|
||||||
|
|
||||||
It needs only Python 3 and runs in the `ci_meson_install` CI job.
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Check that the Meson build and the pkg-config files offer the CMake options.
|
|
||||||
|
|
||||||
The compile definitions of the CMake target (target_compile_definitions in
|
|
||||||
CMakeLists.txt) are the reference. For every option used there, the script
|
|
||||||
checks that
|
|
||||||
|
|
||||||
- the CMake pkg-config file adds the same definition under the same condition,
|
|
||||||
- meson_options.txt has a boolean option of the same name without the "JSON_"
|
|
||||||
prefix and with the same default,
|
|
||||||
- meson.build adds the same definition under the same condition, and
|
|
||||||
- the Meson section of the package manager documentation lists the option.
|
|
||||||
|
|
||||||
Meson's MultipleHeaders option selects the include directory and adds no
|
|
||||||
definition; it is the only Meson option without a definition.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
REPO_ROOT = os.path.normpath(os.path.join(sys.path[0], '..', '..'))
|
|
||||||
DOCS = os.path.join('docs', 'mkdocs', 'docs', 'integration', 'package_managers.md')
|
|
||||||
|
|
||||||
# Meson options that add no compile definition, with their default
|
|
||||||
MESON_ONLY = {'MultipleHeaders': 'false'}
|
|
||||||
|
|
||||||
|
|
||||||
def read(root, path):
|
|
||||||
with open(os.path.join(root, path), encoding='utf-8') as f:
|
|
||||||
return f.read()
|
|
||||||
|
|
||||||
|
|
||||||
def cmake_target_definitions(cmake):
|
|
||||||
"""Return {option: (definition, add_if_on)} from target_compile_definitions."""
|
|
||||||
block = re.search(r'target_compile_definitions\(\s*\$\{NLOHMANN_JSON_TARGET_NAME\}\s*INTERFACE(.*?)\n\)', cmake, re.S)
|
|
||||||
if not block:
|
|
||||||
sys.exit('CMakeLists.txt: target_compile_definitions of the target not found')
|
|
||||||
result = {}
|
|
||||||
for line in block.group(1).split('\n'):
|
|
||||||
line = line.strip()
|
|
||||||
if not line:
|
|
||||||
continue
|
|
||||||
m = re.fullmatch(r'\$<\$<NOT:\$<BOOL:\$\{JSON_(\w+)\}>>:(\w+=\w+)>', line)
|
|
||||||
if m:
|
|
||||||
result[m.group(1)] = (m.group(2), False)
|
|
||||||
continue
|
|
||||||
m = re.fullmatch(r'\$<\$<BOOL:\$\{JSON_(\w+)\}>:(\w+=\w+)>', line)
|
|
||||||
if m:
|
|
||||||
result[m.group(1)] = (m.group(2), True)
|
|
||||||
continue
|
|
||||||
sys.exit(f'CMakeLists.txt: unexpected line in target_compile_definitions: {line}')
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def cmake_defaults(cmake):
|
|
||||||
"""Return {option: 'true'/'false'} for the option() calls of the form JSON_<name>."""
|
|
||||||
return {m.group(1): 'true' if m.group(2) == 'ON' else 'false'
|
|
||||||
for m in re.finditer(r'^option\(JSON_(\w+)\s+"[^"]*"\s+(ON|OFF)\)', cmake, re.M)}
|
|
||||||
|
|
||||||
|
|
||||||
def cmake_pkgconfig_definitions(cmake):
|
|
||||||
"""Return {option: (definition, add_if_on)} from the pkg-config block."""
|
|
||||||
return {m.group(2): (m.group(3), m.group(1) is None)
|
|
||||||
for m in re.finditer(r'if \((NOT )?JSON_(\w+)\)\s*\n\s*string\(APPEND NLOHMANN_JSON_PKGCONFIG_CFLAGS " -D(\w+=\w+)"\)', cmake)}
|
|
||||||
|
|
||||||
|
|
||||||
def meson_options(options):
|
|
||||||
"""Return {option: default} for the boolean options in meson_options.txt."""
|
|
||||||
result = {}
|
|
||||||
for block in re.findall(r'option\((.*?)\)', options, re.S):
|
|
||||||
name = re.search(r"'(\w+)'", block).group(1)
|
|
||||||
kind = re.search(r"type\s*:\s*'(\w+)'", block)
|
|
||||||
value = re.search(r'value\s*:\s*(\w+)', block)
|
|
||||||
result[name] = value.group(1) if kind and kind.group(1) == 'boolean' and value else None
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def meson_definitions(meson):
|
|
||||||
"""Return {option: (definition, add_if_on)} from meson.build."""
|
|
||||||
return {m.group(2): (m.group(3), m.group(1) is None)
|
|
||||||
for m in re.finditer(r"if (not )?get_option\('(\w+)'\)\s*\n\s*json_defines \+= '(\w+=\w+)'", meson)}
|
|
||||||
|
|
||||||
|
|
||||||
def describe(definition):
|
|
||||||
name, add_if_on = definition
|
|
||||||
return f'{name} if {"enabled" if add_if_on else "disabled"}'
|
|
||||||
|
|
||||||
|
|
||||||
def compare(errors, where, expected, actual):
|
|
||||||
for option, definition in expected.items():
|
|
||||||
if option not in actual:
|
|
||||||
errors.append(f'{where}: no definition for option {option} (expected {describe(definition)})')
|
|
||||||
elif actual[option] != definition:
|
|
||||||
errors.append(f'{where}: option {option} adds {describe(actual[option])}, expected {describe(definition)}')
|
|
||||||
for option in actual.keys() - expected.keys():
|
|
||||||
errors.append(f'{where}: definition for option {option}, which the CMake target does not have')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description=__doc__.split('\n')[0])
|
|
||||||
parser.add_argument('root', nargs='?', default=REPO_ROOT, help='repository root (default: %(default)s)')
|
|
||||||
root = parser.parse_args().root
|
|
||||||
|
|
||||||
cmake = read(root, 'CMakeLists.txt')
|
|
||||||
reference = cmake_target_definitions(cmake)
|
|
||||||
defaults = cmake_defaults(cmake)
|
|
||||||
errors = []
|
|
||||||
|
|
||||||
compare(errors, 'CMakeLists.txt (pkg-config)', reference, cmake_pkgconfig_definitions(cmake))
|
|
||||||
compare(errors, 'meson.build', reference, meson_definitions(read(root, 'meson.build')))
|
|
||||||
|
|
||||||
options = meson_options(read(root, 'meson_options.txt'))
|
|
||||||
for option in reference:
|
|
||||||
if option not in defaults:
|
|
||||||
errors.append(f'CMakeLists.txt: no option(JSON_{option} ... ON|OFF)')
|
|
||||||
elif option not in options:
|
|
||||||
errors.append(f'meson_options.txt: option {option} missing')
|
|
||||||
elif options[option] != defaults[option]:
|
|
||||||
errors.append(f'meson_options.txt: option {option} must be boolean with value {defaults[option]} as in CMake')
|
|
||||||
for option, default in MESON_ONLY.items():
|
|
||||||
if options.get(option) != default:
|
|
||||||
errors.append(f'meson_options.txt: option {option} must be boolean with value {default}')
|
|
||||||
for option in options.keys() - reference.keys() - MESON_ONLY.keys():
|
|
||||||
errors.append(f'meson_options.txt: option {option} has no counterpart in the CMake target')
|
|
||||||
|
|
||||||
docs = read(root, DOCS)
|
|
||||||
for option in sorted(set(options) & (reference.keys() | MESON_ONLY.keys())):
|
|
||||||
if f'`{option}`' not in docs:
|
|
||||||
errors.append(f'{DOCS}: Meson option {option} not listed')
|
|
||||||
|
|
||||||
for error in errors:
|
|
||||||
print(error, file=sys.stderr)
|
|
||||||
if errors:
|
|
||||||
print('The Meson build and the pkg-config files must offer the options of the CMake target; see '
|
|
||||||
'tools/check_build_options/README.md.', file=sys.stderr)
|
|
||||||
return 1
|
|
||||||
print(f'OK: {len(reference)} options with compile definitions agree between CMake, pkg-config, and Meson.')
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main())
|
|
||||||
Reference in new issue
Block a user