Merge branch 'develop' of https://github.com/nlohmann/json into clang_windows

 Conflicts:
	include/nlohmann/detail/input/binary_reader.hpp
	include/nlohmann/detail/input/json_sax.hpp
	include/nlohmann/detail/input/lexer.hpp
	include/nlohmann/detail/input/parser.hpp
	include/nlohmann/detail/json_pointer.hpp
	include/nlohmann/detail/output/serializer.hpp
	include/nlohmann/json.hpp
	single_include/nlohmann/json.hpp
This commit is contained in:
Niels Lohmann 2020-07-11 14:04:40 +02:00
commit dc06f100be
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
28 changed files with 1441 additions and 910 deletions

54
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,54 @@
name: "Code scanning - action"
on:
push:
branches: [develop, ]
pull_request:
# The branches below must be a subset of the branches above
branches: [develop]
schedule:
- cron: '0 19 * * 1'
jobs:
CodeQL-Build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View file

@ -79,6 +79,12 @@ if (MSVC)
)
endif()
# Install a pkg-config file, so other tools can find this.
CONFIGURE_FILE(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
)
##
## TESTS
## create and configure the unit test target
@ -139,4 +145,8 @@ endif()
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
install(
FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION lib/pkgconfig
)
endif()

View file

@ -97,6 +97,7 @@ doctest:
# -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
# -Wno-keyword-macro: unit-tests use "#define private public"
# -Wno-missing-prototypes: for NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
# -Wno-padded: padding is nothing to warn about
# -Wno-range-loop-analysis: items tests "for(const auto i...)"
# -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
@ -113,6 +114,7 @@ pedantic_clang:
-Wno-exit-time-destructors \
-Wno-float-equal \
-Wno-keyword-macro \
-Wno-missing-prototypes \
-Wno-padded \
-Wno-range-loop-analysis \
-Wno-switch-enum -Wno-covered-switch-default \
@ -253,7 +255,7 @@ pedantic_gcc:
-Wmismatched-tags \
-Wmissing-attributes \
-Wmissing-braces \
-Wmissing-declarations \
-Wno-missing-declarations \
-Wmissing-field-initializers \
-Wmissing-include-dirs \
-Wmissing-profile \

View file

@ -27,6 +27,7 @@
- [Integration](#integration)
- [CMake](#cmake)
- [Package Managers](#package-managers)
- [Pkg-config](#pkg-config)
- [Examples](#examples)
- [JSON as first-class data type](#json-as-first-class-data-type)
- [Serialization / Deserialization](#serialization--deserialization)
@ -230,6 +231,20 @@ Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if
If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch.
### Pkg-config
If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed:
```sh
pkg-config nlohmann_json --cflags
```
Users of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`:
```meson
json = dependency('nlohmann_json', required: true)
```
## Examples
Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).
@ -869,6 +884,42 @@ Some important things:
* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
#### Simplify your life with macros
If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate.
There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object:
- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for.
- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members.
In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members.
##### Examples
The `to_json`/`from_json` functions for the `person` struct above can be created with:
```cpp
namespace ns {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
```
Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed:
```cpp
namespace ns {
class address {
private:
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
}
```
#### How do I convert third-party types?
@ -1536,7 +1587,7 @@ Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924).
### Further notes
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8).
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`.
- As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.
- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag.
- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER´` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.

4
cmake/pkg-config.pc.in Normal file
View file

@ -0,0 +1,4 @@
Name: ${PROJECT_NAME}
Description: JSON for Modern C++
Version: ${PROJECT_VERSION}
Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}

View file

@ -81,6 +81,43 @@ Some important things:
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
## Simplify your life with macros
If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate.
There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object:
- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for.
- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members.
In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members.
??? example
The `to_json`/`from_json` functions for the `person` struct above can be created with:
```cpp
namespace ns {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
```
Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed:
```cpp
namespace ns {
class address {
private:
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
}
```
## How do I convert third-party types?
This requires a bit more advanced technique. But first, let's see how this conversion mechanism works:

View file

@ -0,0 +1,55 @@
# Supported Macros
Some aspects of the library can be configured by defining preprocessor macros before including the `json.hpp` header.
## `JSON_CATCH_USER(exception)`
This macro overrides `#!cpp catch` calls inside the library. The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range` exceptions internally to rethrow them as [`json::out_of_range`](../home/exceptions.md#out-of-range) exceptions. The macro is always followed by a scope.
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
## `JSON_NOEXCEPTION`
Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`.
When defining `JSON_NOEXCEPTION`, `#!cpp try` is replaced by `#!cpp if (true)`,
`#!cpp catch` is replaced by `#!cpp if (false)`, and `#!cpp throw` is replaced by `#!cpp std::abort()`.
The same effect is achieved by setting the compiler flag `-fno-exceptions`.
## `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`
When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows to use the library with compilers that do not fully support C++11 and may only work if unsupported features are not used.
## `JSON_THROW_USER(exception)`
This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
## `JSON_TRY_USER`
This macro overrides `#!cpp try` calls inside the library. It has no arguments and is always followed by a scope.
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
## `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)`
This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object.
The macro is to be defined inside of the class/struct to create code for. Unlike [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](#nlohmann_define_type_non_intrusivetype-member), it can access private members.
The first parameter is the name of the class/struct, and all remaining parameters name the members.
See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example.
## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)`
This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object.
The macro is to be defined inside of the namespace of the class/struct to create code for. Private members cannot be accessed. Use [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](#nlohmann_define_type_intrusivetype-member) in these scenarios.
The first parameter is the name of the class/struct, and all remaining parameters name the members.
See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example.
## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)`
This macro simplifies the serialization/deserialization of enum types. See [Specializing enum conversion](enum_conversion.md) for more information.

View file

@ -32,6 +32,24 @@ Exceptions are used widely within the library. They can, however, be switched of
Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
??? example
The code below switches off exceptions and creates a log entry with a detailed error message in case of errors.
```cpp
#include <iostream>
#define JSON_TRY_USER if(true)
#define JSON_CATCH_USER(exception) if(false)
#define JSON_THROW_USER(exception) \
{std::clog << "Error in " << __FILE__ << ":" << __LINE__ \
<< " (function " << __FUNCTION__ << ") - " \
<< (exception).what() << std::endl; \
std::abort();}
#include <nlohmann/json.hpp>
```
## Parse errors
This exception is thrown by the library when a parse error occurs. Parse errors

View file

@ -49,6 +49,7 @@ nav:
- features/json_patch.md
- features/merge_patch.md
- features/enum_conversion.md
- features/macros.md
- Parsing:
- features/parsing/index.md
- features/parsing/parse_exceptions.md

View file

@ -1,7 +1,6 @@
#pragma once
#include <array> // array
#include <cassert> // assert
#include <cmath> // signbit, isfinite
#include <cstdint> // intN_t, uintN_t
#include <cstring> // memcpy, memmove
@ -63,8 +62,8 @@ struct diyfp // f * 2^e
*/
static diyfp sub(const diyfp& x, const diyfp& y) noexcept
{
assert(x.e == y.e);
assert(x.f >= y.f);
JSON_ASSERT(x.e == y.e);
JSON_ASSERT(x.f >= y.f);
return {x.f - y.f, x.e};
}
@ -140,7 +139,7 @@ struct diyfp // f * 2^e
*/
static diyfp normalize(diyfp x) noexcept
{
assert(x.f != 0);
JSON_ASSERT(x.f != 0);
while ((x.f >> 63u) == 0)
{
@ -159,8 +158,8 @@ struct diyfp // f * 2^e
{
const int delta = x.e - target_exponent;
assert(delta >= 0);
assert(((x.f << delta) >> delta) == x.f);
JSON_ASSERT(delta >= 0);
JSON_ASSERT(((x.f << delta) >> delta) == x.f);
return {x.f << delta, target_exponent};
}
@ -182,8 +181,8 @@ boundaries.
template<typename FloatType>
boundaries compute_boundaries(FloatType value)
{
assert(std::isfinite(value));
assert(value > 0);
JSON_ASSERT(std::isfinite(value));
JSON_ASSERT(value > 0);
// Convert the IEEE representation into a diyfp.
//
@ -463,18 +462,18 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
// k = ceil((kAlpha - e - 1) * 0.30102999566398114)
// for |e| <= 1500, but doesn't require floating-point operations.
// NB: log_10(2) ~= 78913 / 2^18
assert(e >= -1500);
assert(e <= 1500);
JSON_ASSERT(e >= -1500);
JSON_ASSERT(e <= 1500);
const int f = kAlpha - e - 1;
const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
assert(index >= 0);
assert(static_cast<std::size_t>(index) < kCachedPowers.size());
JSON_ASSERT(index >= 0);
JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
assert(kAlpha <= cached.e + e + 64);
assert(kGamma >= cached.e + e + 64);
JSON_ASSERT(kAlpha <= cached.e + e + 64);
JSON_ASSERT(kGamma >= cached.e + e + 64);
return cached;
}
@ -542,10 +541,10 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
std::uint64_t rest, std::uint64_t ten_k)
{
assert(len >= 1);
assert(dist <= delta);
assert(rest <= delta);
assert(ten_k > 0);
JSON_ASSERT(len >= 1);
JSON_ASSERT(dist <= delta);
JSON_ASSERT(rest <= delta);
JSON_ASSERT(ten_k > 0);
// <--------------------------- delta ---->
// <---- dist --------->
@ -570,7 +569,7 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d
&& delta - rest >= ten_k
&& (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
{
assert(buf[len - 1] != '0');
JSON_ASSERT(buf[len - 1] != '0');
buf[len - 1]--;
rest += ten_k;
}
@ -598,8 +597,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// Grisu2 generates the digits of M+ from left to right and stops as soon as
// V is in [M-,M+].
assert(M_plus.e >= kAlpha);
assert(M_plus.e <= kGamma);
JSON_ASSERT(M_plus.e >= kAlpha);
JSON_ASSERT(M_plus.e <= kGamma);
std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e)
@ -620,7 +619,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
//
// Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
assert(p1 > 0);
JSON_ASSERT(p1 > 0);
std::uint32_t pow10;
const int k = find_largest_pow10(p1, pow10);
@ -656,7 +655,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
//
assert(d <= 9);
JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
//
// M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
@ -743,7 +742,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
//
// and stop as soon as 10^-m * r * 2^e <= delta * 2^e
assert(p2 > delta);
JSON_ASSERT(p2 > delta);
int m = 0;
for (;;)
@ -754,7 +753,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
//
assert(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
p2 *= 10;
const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e
const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
@ -763,7 +762,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
//
assert(d <= 9);
JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
//
// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
@ -824,8 +823,8 @@ JSON_HEDLEY_NON_NULL(1)
inline void grisu2(char* buf, int& len, int& decimal_exponent,
diyfp m_minus, diyfp v, diyfp m_plus)
{
assert(m_plus.e == m_minus.e);
assert(m_plus.e == v.e);
JSON_ASSERT(m_plus.e == m_minus.e);
JSON_ASSERT(m_plus.e == v.e);
// --------(-----------------------+-----------------------)-------- (A)
// m- v m+
@ -886,8 +885,8 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
"internal error: not enough precision");
assert(std::isfinite(value));
assert(value > 0);
JSON_ASSERT(std::isfinite(value));
JSON_ASSERT(value > 0);
// If the neighbors (and boundaries) of 'value' are always computed for double-precision
// numbers, all float's can be recovered using strtod (and strtof). However, the resulting
@ -923,8 +922,8 @@ JSON_HEDLEY_NON_NULL(1)
JSON_HEDLEY_RETURNS_NON_NULL
inline char* append_exponent(char* buf, int e)
{
assert(e > -1000);
assert(e < 1000);
JSON_ASSERT(e > -1000);
JSON_ASSERT(e < 1000);
if (e < 0)
{
@ -976,8 +975,8 @@ JSON_HEDLEY_RETURNS_NON_NULL
inline char* format_buffer(char* buf, int len, int decimal_exponent,
int min_exp, int max_exp)
{
assert(min_exp < 0);
assert(max_exp > 0);
JSON_ASSERT(min_exp < 0);
JSON_ASSERT(max_exp > 0);
const int k = len;
const int n = len + decimal_exponent;
@ -1003,7 +1002,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
// dig.its
// len <= max_digits10 + 1
assert(k > n);
JSON_ASSERT(k > n);
std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
buf[n] = '.';
@ -1061,7 +1060,7 @@ JSON_HEDLEY_RETURNS_NON_NULL
char* to_chars(char* first, const char* last, FloatType value)
{
static_cast<void>(last); // maybe unused - fix warning
assert(std::isfinite(value));
JSON_ASSERT(std::isfinite(value));
// Use signbit(value) instead of (value < 0) since signbit works for -0.
if (std::signbit(value))
@ -1079,7 +1078,7 @@ char* to_chars(char* first, const char* last, FloatType value)
return first;
}
assert(last - first >= std::numeric_limits<FloatType>::max_digits10);
JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
// Compute v = buffer * 10^decimal_exponent.
// The decimal digits are stored in the buffer, which needs to be interpreted
@ -1089,16 +1088,16 @@ char* to_chars(char* first, const char* last, FloatType value)
int decimal_exponent = 0;
dtoa_impl::grisu2(first, len, decimal_exponent, value);
assert(len <= std::numeric_limits<FloatType>::max_digits10);
JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
// Format the buffer like printf("%.*g", prec, value)
constexpr int kMinExp = -4;
// Use digits10 here to increase compatibility with version 2.
constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
assert(last - first >= kMaxExp + 2);
assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
JSON_ASSERT(last - first >= kMaxExp + 2);
JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
}

View file

@ -2,7 +2,6 @@
#include <algorithm> // generate_n
#include <array> // array
#include <cassert> // assert
#include <cmath> // ldexp
#include <cstddef> // size_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
@ -109,7 +108,7 @@ class binary_reader
break;
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
// strict mode: next byte must be EOF
@ -717,8 +716,8 @@ class binary_reader
{
const int exp = (half >> 10u) & 0x1Fu;
const unsigned int mant = half & 0x3FFu;
assert(0 <= exp&& exp <= 32);
assert(mant <= 1024);
JSON_ASSERT(0 <= exp&& exp <= 32);
JSON_ASSERT(mant <= 1024);
switch (exp)
{
case 0:
@ -2295,7 +2294,7 @@ class binary_reader
break;
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
return error_msg + " " + context + ": " + detail;

View file

@ -1,7 +1,6 @@
#pragma once
#include <array> // array
#include <cassert> // assert
#include <cstddef> // size_t
#include <cstdio> //FILE *
#include <cstring> // strlen
@ -297,13 +296,13 @@ class wide_string_input_adapter
{
fill_buffer<sizeof(WideCharType)>();
assert(utf8_bytes_filled > 0);
assert(utf8_bytes_index == 0);
JSON_ASSERT(utf8_bytes_filled > 0);
JSON_ASSERT(utf8_bytes_index == 0);
}
// use buffer
assert(utf8_bytes_filled > 0);
assert(utf8_bytes_index < utf8_bytes_filled);
JSON_ASSERT(utf8_bytes_filled > 0);
JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
return utf8_bytes[utf8_bytes_index++];
}

View file

@ -1,6 +1,5 @@
#pragma once
#include <cassert> // assert
#include <cstddef>
#include <string> // string
#include <utility> // move
@ -280,7 +279,7 @@ class json_sax_dom_parser
case 5:
JSON_THROW(*dynamic_cast<const detail::other_error*>(&ex));
default:
assert(false);
JSON_ASSERT(false);
// LCOV_EXCL_STOP
}
}
@ -309,7 +308,7 @@ class json_sax_dom_parser
return &root;
}
assert(ref_stack.back()->is_array() || ref_stack.back()->is_object());
JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
if (ref_stack.back()->is_array())
{
@ -317,8 +316,8 @@ class json_sax_dom_parser
return &(ref_stack.back()->m_value.array->back());
}
assert(ref_stack.back()->is_object());
assert(object_element);
JSON_ASSERT(ref_stack.back()->is_object());
JSON_ASSERT(object_element);
*object_element = BasicJsonType(std::forward<Value>(v));
return object_element;
}
@ -447,8 +446,8 @@ class json_sax_dom_callback_parser
*ref_stack.back() = discarded;
}
assert(!ref_stack.empty());
assert(!keep_stack.empty());
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
@ -499,8 +498,8 @@ class json_sax_dom_callback_parser
}
}
assert(!ref_stack.empty());
assert(!keep_stack.empty());
JSON_ASSERT(!ref_stack.empty());
JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
@ -534,7 +533,7 @@ class json_sax_dom_callback_parser
case 5:
JSON_THROW(*dynamic_cast<const detail::other_error*>(&ex));
default:
assert(false);
JSON_ASSERT(false);
// LCOV_EXCL_STOP
}
}
@ -565,7 +564,7 @@ class json_sax_dom_callback_parser
template<typename Value>
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
{
assert(!keep_stack.empty());
JSON_ASSERT(!keep_stack.empty());
// do not handle this value if we know it would be added to a discarded
// container
@ -600,7 +599,7 @@ class json_sax_dom_callback_parser
}
// we now only expect arrays and objects
assert(ref_stack.back()->is_array() || ref_stack.back()->is_object());
JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
// array
if (ref_stack.back()->is_array())
@ -610,9 +609,9 @@ class json_sax_dom_callback_parser
}
// object
assert(ref_stack.back()->is_object());
JSON_ASSERT(ref_stack.back()->is_object());
// check if we should store an element for the current key
assert(!key_keep_stack.empty());
JSON_ASSERT(!key_keep_stack.empty());
const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back();
@ -621,7 +620,7 @@ class json_sax_dom_callback_parser
return {false, nullptr};
}
assert(object_element);
JSON_ASSERT(object_element);
*object_element = std::move(value);
return {true, object_element};
}

View file

@ -135,7 +135,7 @@ class lexer : public lexer_base<BasicJsonType>
static char get_decimal_point() noexcept
{
const auto* loc = localeconv();
assert(loc != nullptr);
JSON_ASSERT(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
}
@ -161,7 +161,7 @@ class lexer : public lexer_base<BasicJsonType>
int get_codepoint()
{
// this function only makes sense after reading `\u`
assert(current == 'u');
JSON_ASSERT(current == 'u');
int codepoint = 0;
const auto factors = { 12u, 8u, 4u, 0u };
@ -187,7 +187,7 @@ class lexer : public lexer_base<BasicJsonType>
}
}
assert(0x0000 <= codepoint && codepoint <= 0xFFFF);
JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
return codepoint;
}
@ -208,7 +208,7 @@ class lexer : public lexer_base<BasicJsonType>
*/
bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
{
assert(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
add(current);
for (auto range = ranges.begin(); range != ranges.end(); ++range)
@ -249,7 +249,7 @@ class lexer : public lexer_base<BasicJsonType>
reset();
// we entered the function by reading an open quote
assert(current == '\"');
JSON_ASSERT(current == '\"');
while (true)
{
@ -369,7 +369,7 @@ class lexer : public lexer_base<BasicJsonType>
}
// result of the above calculation yields a proper codepoint
assert(0x00 <= codepoint && codepoint <= 0x10FFFF);
JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
// translate codepoint into bytes
if (codepoint < 0x80)
@ -998,7 +998,7 @@ class lexer : public lexer_base<BasicJsonType>
// all other characters are rejected outside scan_number()
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
scan_number_minus:
@ -1245,7 +1245,7 @@ scan_number_done:
const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
// we checked the number format before
assert(endptr == token_buffer.data() + token_buffer.size());
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (errno == 0)
{
@ -1261,7 +1261,7 @@ scan_number_done:
const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
// we checked the number format before
assert(endptr == token_buffer.data() + token_buffer.size());
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (errno == 0)
{
@ -1278,7 +1278,7 @@ scan_number_done:
strtof(value_float, token_buffer.data(), &endptr);
// we checked the number format before
assert(endptr == token_buffer.data() + token_buffer.size());
JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
return token_type::value_float;
}
@ -1292,7 +1292,7 @@ scan_number_done:
token_type scan_literal(const char_type* literal_text, const std::size_t length,
token_type return_type)
{
assert(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
for (std::size_t i = 1; i < length; ++i)
{
if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))
@ -1384,7 +1384,7 @@ scan_number_done:
if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
{
assert(!token_string.empty());
JSON_ASSERT(!token_string.empty());
token_string.pop_back();
}
}

View file

@ -1,6 +1,5 @@
#pragma once
#include <cassert> // assert
#include <cmath> // isfinite
#include <cstdint> // uint8_t
#include <functional> // function
@ -383,7 +382,7 @@ class parser
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
assert(!states.empty());
JSON_ASSERT(!states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
@ -439,7 +438,7 @@ class parser
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
assert(!states.empty());
JSON_ASSERT(!states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;

View file

@ -85,7 +85,7 @@ class iter_impl
*/
explicit iter_impl(pointer object) noexcept : m_object(object)
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -171,7 +171,7 @@ class iter_impl
*/
void set_begin() noexcept
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -208,7 +208,7 @@ class iter_impl
*/
void set_end() noexcept
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -239,19 +239,19 @@ class iter_impl
*/
reference operator*() const
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
case value_t::object:
{
assert(m_it.object_iterator != m_object->m_value.object->end());
JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
return m_it.object_iterator->second;
}
case value_t::array:
{
assert(m_it.array_iterator != m_object->m_value.array->end());
JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
return *m_it.array_iterator;
}
@ -276,19 +276,19 @@ class iter_impl
*/
pointer operator->() const
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
case value_t::object:
{
assert(m_it.object_iterator != m_object->m_value.object->end());
JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
return &(m_it.object_iterator->second);
}
case value_t::array:
{
assert(m_it.array_iterator != m_object->m_value.array->end());
JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
return &*m_it.array_iterator;
}
@ -321,7 +321,7 @@ class iter_impl
*/
iter_impl& operator++()
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -364,7 +364,7 @@ class iter_impl
*/
iter_impl& operator--()
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -402,7 +402,7 @@ class iter_impl
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
}
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -438,7 +438,7 @@ class iter_impl
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
}
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -486,7 +486,7 @@ class iter_impl
*/
iter_impl& operator+=(difference_type i)
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -557,7 +557,7 @@ class iter_impl
*/
difference_type operator-(const iter_impl& other) const
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -578,7 +578,7 @@ class iter_impl
*/
reference operator[](difference_type n) const
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type)
{
@ -609,7 +609,7 @@ class iter_impl
*/
const typename object_t::key_type& key() const
{
assert(m_object != nullptr);
JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->is_object()))
{

View file

@ -74,7 +74,7 @@ template<typename IteratorType> class iteration_proxy_value
/// return key of the iterator
const string_type& key() const
{
assert(anchor.m_object != nullptr);
JSON_ASSERT(anchor.m_object != nullptr);
switch (anchor.m_object->type())
{

View file

@ -1,7 +1,6 @@
#pragma once
#include <algorithm> // all_of
#include <cassert> // assert
#include <cctype> // isdigit
#include <limits> // max
#include <numeric> // accumulate
@ -398,7 +397,6 @@ class json_pointer
*/
BasicJsonType& get_and_create(BasicJsonType& j) const
{
using size_type = typename BasicJsonType::size_type;
auto result = &j;
// in case no reference tokens exist, return a reference to the JSON value
@ -471,7 +469,6 @@ class json_pointer
*/
BasicJsonType& get_unchecked(BasicJsonType* ptr) const
{
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
// convert null values to arrays or objects before continuing
@ -531,7 +528,6 @@ class json_pointer
*/
BasicJsonType& get_checked(BasicJsonType* ptr) const
{
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
@ -581,7 +577,6 @@ class json_pointer
*/
const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
{
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
@ -624,7 +619,6 @@ class json_pointer
*/
const BasicJsonType& get_checked(const BasicJsonType* ptr) const
{
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
@ -665,7 +659,6 @@ class json_pointer
*/
bool contains(const BasicJsonType* ptr) const
{
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
@ -787,7 +780,7 @@ class json_pointer
pos != std::string::npos;
pos = reference_token.find_first_of('~', pos + 1))
{
assert(reference_token[pos] == '~');
JSON_ASSERT(reference_token[pos] == '~');
// ~ must be followed by 0 or 1
if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
@ -822,7 +815,7 @@ class json_pointer
static void replace_substring(std::string& s, const std::string& f,
const std::string& t)
{
assert(!f.empty());
JSON_ASSERT(!f.empty());
for (auto pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t, and

View file

@ -77,6 +77,12 @@
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
#endif
// allow to override assert
#if !defined(JSON_ASSERT)
#include <cassert> // assert
#define JSON_ASSERT(x) assert(x)
#endif
/*!
@brief macro to briefly define a mapping between an enum and JSON
@def NLOHMANN_JSON_SERIALIZE_ENUM
@ -124,3 +130,44 @@
basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer, BinaryType>
// Macros to simplify conversion from/to types
#define NLOHMANN_JSON_EXPAND( x ) x
#define NLOHMANN_JSON_GET_MACRO(_1,_2,_3,_4,_5,_6, _7, _8, _9, _10, _11, NAME,...) NAME
#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, NLOHMANN_JSON_PASTE11, \
NLOHMANN_JSON_PASTE10, NLOHMANN_JSON_PASTE9, NLOHMANN_JSON_PASTE8, NLOHMANN_JSON_PASTE7, \
NLOHMANN_JSON_PASTE6, NLOHMANN_JSON_PASTE5, NLOHMANN_JSON_PASTE4, NLOHMANN_JSON_PASTE3, \
NLOHMANN_JSON_PASTE2, NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9)
#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
#define NLOHMANN_JSON_TO(v1) j[#v1] = t.v1;
#define NLOHMANN_JSON_FROM(v1) j.at(#v1).get_to(t.v1);
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
friend void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }

View file

@ -9,6 +9,7 @@
#endif
// clean up
#undef JSON_ASSERT
#undef JSON_INTERNAL_CATCH
#undef JSON_CATCH
#undef JSON_THROW

View file

@ -38,7 +38,7 @@ class binary_writer
*/
explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
{
assert(oa);
JSON_ASSERT(oa);
}
/*!
@ -754,7 +754,7 @@ class binary_writer
bool prefix_required = true;
if (use_type && !j.m_value.array->empty())
{
assert(use_count);
JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
[this, first_prefix](const BasicJsonType & v)
@ -798,7 +798,7 @@ class binary_writer
if (use_type && !j.m_value.binary->empty())
{
assert(use_count);
JSON_ASSERT(use_count);
oa->write_character(to_char_type('$'));
oa->write_character('U');
}
@ -842,7 +842,7 @@ class binary_writer
bool prefix_required = true;
if (use_type && !j.m_value.object->empty())
{
assert(use_count);
JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin(), j.end(),
[this, first_prefix](const BasicJsonType & v)
@ -1134,7 +1134,7 @@ class binary_writer
// LCOV_EXCL_START
default:
assert(false);
JSON_ASSERT(false);
return 0ul;
// LCOV_EXCL_STOP
}
@ -1181,7 +1181,7 @@ class binary_writer
// LCOV_EXCL_START
default:
assert(false);
JSON_ASSERT(false);
return;
// LCOV_EXCL_STOP
}

View file

@ -2,7 +2,6 @@
#include <algorithm> // reverse, remove, fill, find, none_of
#include <array> // array
#include <cassert> // assert
#include <clocale> // localeconv, lconv
#include <cmath> // labs, isfinite, isnan, signbit
#include <cstddef> // size_t, ptrdiff_t
@ -135,8 +134,8 @@ class serializer
}
// last element
assert(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend());
JSON_ASSERT(i != val.m_value.object->cend());
JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_characters(indent_string.c_str(), new_indent);
o->write_character('\"');
dump_escaped(i->first, ensure_ascii);
@ -163,8 +162,8 @@ class serializer
}
// last element
assert(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend());
JSON_ASSERT(i != val.m_value.object->cend());
JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_character('\"');
dump_escaped(i->first, ensure_ascii);
o->write_characters("\":", 2);
@ -205,7 +204,7 @@ class serializer
}
// last element
assert(!val.m_value.array->empty());
JSON_ASSERT(!val.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent);
dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
@ -226,7 +225,7 @@ class serializer
}
// last element
assert(!val.m_value.array->empty());
JSON_ASSERT(!val.m_value.array->empty());
dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
o->write_character(']');
@ -360,7 +359,7 @@ class serializer
}
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
}
@ -559,7 +558,7 @@ class serializer
}
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
break;
}
@ -622,7 +621,7 @@ class serializer
}
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
}
}
@ -723,7 +722,7 @@ class serializer
}
// spare 1 byte for '\0'
assert(n_chars < number_buffer.size() - 1);
JSON_ASSERT(n_chars < number_buffer.size() - 1);
// jump to the end to generate the string from backward
// so we later avoid reversing the result
@ -799,9 +798,9 @@ class serializer
std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
// negative value indicates an error
assert(len > 0);
JSON_ASSERT(len > 0);
// check if buffer was large enough
assert(static_cast<std::size_t>(len) < number_buffer.size());
JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
// erase thousands separator
if (thousands_sep != '\0')
@ -809,7 +808,7 @@ class serializer
const auto end = std::remove(number_buffer.begin(),
number_buffer.begin() + len, thousands_sep);
std::fill(end, number_buffer.end(), '\0');
assert((end - number_buffer.begin()) <= len);
JSON_ASSERT((end - number_buffer.begin()) <= len);
len = (end - number_buffer.begin());
}
@ -889,7 +888,7 @@ class serializer
: (0xFFu >> type) & (byte);
std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
assert(index < 400);
JSON_ASSERT(index < 400);
state = utf8d[index];
return state;
}
@ -901,7 +900,7 @@ class serializer
*/
number_unsigned_t remove_sign(number_unsigned_t x)
{
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE
}
@ -916,7 +915,7 @@ class serializer
*/
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
{
assert(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());
JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
}

View file

@ -35,7 +35,6 @@ SOFTWARE.
#define NLOHMANN_JSON_VERSION_PATCH 0
#include <algorithm> // all_of, find, for_each
#include <cassert> // assert
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <functional> // hash, less
#include <initializer_list> // initializer_list
@ -924,7 +923,7 @@ class basic_json
};
std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
assert(object != nullptr);
JSON_ASSERT(object != nullptr);
return object.release();
}
@ -1219,10 +1218,10 @@ class basic_json
*/
void assert_invariant() const noexcept
{
assert(m_type != value_t::object || m_value.object != nullptr);
assert(m_type != value_t::array || m_value.array != nullptr);
assert(m_type != value_t::string || m_value.string != nullptr);
assert(m_type != value_t::binary || m_value.binary != nullptr);
JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);
JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);
JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);
JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);
}
public:
@ -1515,7 +1514,7 @@ class basic_json
m_type = value_t::discarded;
break;
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
assert_invariant();
}
@ -1915,8 +1914,8 @@ class basic_json
std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
basic_json(InputIT first, InputIT last)
{
assert(first.m_object != nullptr);
assert(last.m_object != nullptr);
JSON_ASSERT(first.m_object != nullptr);
JSON_ASSERT(last.m_object != nullptr);
// make sure iterator fits the current value
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
@ -2238,7 +2237,8 @@ class basic_json
@param[in] error_handler how to react on decoding errors; there are three
possible values: `strict` (throws and exception in case a decoding error
occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),
and `ignore` (ignore invalid UTF-8 sequences during serialization).
and `ignore` (ignore invalid UTF-8 sequences during serialization; all
bytes are copied to the output unchanged).
@return string containing the serialization of the JSON value
@ -3019,6 +3019,18 @@ class basic_json
return v;
}
// specialization to allow to call get_to with a basic_json value
// see https://github.com/nlohmann/json/issues/2175
template<typename ValueType,
detail::enable_if_t <
detail::is_basic_json<ValueType>::value,
int> = 0>
ValueType & get_to(ValueType& v) const
{
v = *this;
return v;
}
template <
typename T, std::size_t N,
typename Array = T (&)[N],
@ -3620,7 +3632,7 @@ class basic_json
// const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
assert(m_value.object->find(key) != m_value.object->end());
JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
@ -3712,7 +3724,7 @@ class basic_json
// at only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
{
assert(m_value.object->find(key) != m_value.object->end());
JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
@ -3772,7 +3784,7 @@ class basic_json
template < class ValueType, typename std::enable_if <
std::is_convertible<basic_json_t, ValueType>::value
&& !std::is_same<value_t, ValueType>::value, int >::type = 0 >
ValueType value(const typename object_t::key_type& key, ValueType && default_value) const
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
{
// at only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
@ -3784,7 +3796,7 @@ class basic_json
return *it;
}
return std::move(default_value);
return default_value;
}
JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
@ -3796,7 +3808,7 @@ class basic_json
*/
string_t value(const typename object_t::key_type& key, const char* default_value) const
{
return value(key, std::move(string_t(default_value)));
return value(key, string_t(default_value));
}
/*!
@ -3844,7 +3856,7 @@ class basic_json
*/
template<class ValueType, typename std::enable_if<
std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
ValueType value(const json_pointer& ptr, ValueType && default_value) const
ValueType value(const json_pointer& ptr, const ValueType& default_value) const
{
// at only works for objects
if (JSON_HEDLEY_LIKELY(is_object()))
@ -3856,7 +3868,7 @@ class basic_json
}
JSON_INTERNAL_CATCH (out_of_range&)
{
return std::move(default_value);
return default_value;
}
}
@ -3870,7 +3882,7 @@ class basic_json
JSON_HEDLEY_NON_NULL(3)
string_t value(const json_pointer& ptr, const char* default_value) const
{
return value(ptr, std::move(string_t(default_value)));
return value(ptr, string_t(default_value));
}
/*!
@ -5480,7 +5492,7 @@ class basic_json
iterator insert_iterator(const_iterator pos, Args&& ... args)
{
iterator result(this);
assert(m_value.array != nullptr);
JSON_ASSERT(m_value.array != nullptr);
auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);
m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
@ -8245,7 +8257,7 @@ class basic_json
// if there exists a parent it cannot be primitive
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
}
};

File diff suppressed because it is too large Load diff

View file

@ -95,6 +95,7 @@ set(files
src/unit-algorithms.cpp
src/unit-allocator.cpp
src/unit-alt-string.cpp
src/unit-assert_macro.cpp
src/unit-bson.cpp
src/unit-capacity.cpp
src/unit-cbor.cpp
@ -132,6 +133,7 @@ set(files
src/unit-to_chars.cpp
src/unit-ubjson.cpp
src/unit-udt.cpp
src/unit-udt_macro.cpp
src/unit-unicode.cpp
src/unit-user_defined_input.cpp
src/unit-wstring.cpp)

View file

@ -0,0 +1,65 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// avoid warning when assert does not abort
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wstrict-overflow"
#endif
#include "doctest_compatibility.h"
/// global variable to record side effect of assert calls
static int assert_counter;
/// set failure variable to true instead of calling assert(x)
#define JSON_ASSERT(x) {if (!(x)) ++assert_counter; }
#include <nlohmann/json.hpp>
using nlohmann::json;
// the test assumes exceptions to work
#if not defined(JSON_NOEXCEPTION)
TEST_CASE("JSON_ASSERT(x)")
{
SECTION("basic_json(first, second)")
{
assert_counter = 0;
CHECK(assert_counter == 0);
json::iterator it;
json j;
// in case assertions do not abort execution, an exception is thrown
CHECK_THROWS_WITH_AS(json(it, j.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator);
// check that assertion actually happened
CHECK(assert_counter == 1);
}
}
#endif

View file

@ -1945,6 +1945,15 @@ TEST_CASE("regression tests")
)
);
}
SECTION("PR #2181 - regression bug with lvalue")
{
// see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060
json j{{"x", "test"}};
std::string defval = "default value";
auto val = j.value("x", defval);
auto val2 = j.value("y", defval);
}
}
#if !defined(JSON_NOEXCEPTION)

130
test/src/unit-udt_macro.cpp Normal file
View file

@ -0,0 +1,130 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
using nlohmann::json;
namespace persons
{
class person_with_private_data
{
private:
std::string name = "";
int age = 0;
json metadata = nullptr;
public:
bool operator==(const person_with_private_data& rhs) const
{
return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
}
person_with_private_data() = default;
person_with_private_data(std::string name_, int age_, json metadata_)
: name(std::move(name_))
, age(age_)
, metadata(std::move(metadata_))
{}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata)
};
class person_without_private_data_1
{
public:
std::string name = "";
int age = 0;
json metadata = nullptr;
bool operator==(const person_without_private_data_1& rhs) const
{
return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
}
person_without_private_data_1() = default;
person_without_private_data_1(std::string name_, int age_, json metadata_)
: name(std::move(name_))
, age(age_)
, metadata(std::move(metadata_))
{}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name, metadata)
};
class person_without_private_data_2
{
public:
std::string name = "";
int age = 0;
json metadata = nullptr;
bool operator==(const person_without_private_data_2& rhs) const
{
return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
}
person_without_private_data_2() = default;
person_without_private_data_2(std::string name_, int age_, json metadata_)
: name(std::move(name_))
, age(age_)
, metadata(std::move(metadata_))
{}
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata)
} // namespace persons
TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE", T,
persons::person_with_private_data,
persons::person_without_private_data_1,
persons::person_without_private_data_2)
{
SECTION("person")
{
// serialization
T p1("Erik", 1, {{"haircuts", 2}});
CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}");
// deserialization
T p2 = json(p1);
CHECK(p2 == p1);
// roundtrip
CHECK(T(json(p1)) == p1);
CHECK(json(T(json(p1))) == json(p1));
// check exception in case of missing field
json j = json(p1);
j.erase("age");
T p3;
CHECK_THROWS_WITH_AS(p3 = json(j), "[json.exception.out_of_range.403] key 'age' not found", json::out_of_range);
}
}