Compare commits

..
Author SHA1 Message Date
Niels Lohmann d8dfc0d0f9 Fix unused-result warnings in the contains and parse_error examples (#5788)
contains(json_pointer) is marked JSON_HEDLEY_WARN_UNUSED_RESULT since #5477,
and parse() has been for longer. The contains example ignored the result in
two try blocks waiting for a parse_error that contains() never throws, so
they printed nothing; print the result for those pointers instead.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-08 16:21:59 +02:00
Niels Lohmann 3d7f554927 Use the with_*_t aliases in tests, examples, and docs (#5787)
* Use the with_*_t aliases in tests, examples, and docs

Replace spelled-out basic_json<...> instantiations that only change one
or two template parameters with nlohmann::json::with_*_t (or
ordered_json::with_*_t when the object type is ordered_map). Types that
change all three number types chain with_integers_t and with_float_t.

The raw basic_json<...> spelling stays where the template parameter
list itself is the subject: the alias tests in unit-udt.cpp, explicit
instantiations, and the ordered_json/compile-time docs.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Fix unit-large_json for clang and JSON_DIAGNOSTICS

Two test problems from #5781 broke CI on develop: CAPTURE(depth); trips
clang's -Wextra-semi-stmt, and the type_error.321 messages did not
account for the diagnostics path prefix.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Use static_cast in unit-hash for clang-tidy

#5772 added functional casts that clang-tidy reports as C-style casts
(google-readability-casting). Also append a char instead of a
one-character string in unit-large_json.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Declare the expected message prefix const in unit-large_json

Without JSON_DIAGNOSTICS the prefix was never modified, which
clang-tidy reports (misc-const-correctness).

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-08 16:11:16 +02:00
Suyog Verma a269794db7 Use MSVC intrinsics for full multiplication (#5782)
* Use MSVC intrinsics for full multiplication

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>

* Fix formatting in unit-class_lexer

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>

* Address review feedback

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>

---------

Signed-off-by: Suyog Verma <suyogverma0057@gmail.com>
2026-10-08 08:49:32 +02:00
28 changed files with 141 additions and 184 deletions

No files matched your search

@@ -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::basic_json<std::map, std::vector, std::wstring>; using wjson = nlohmann::json::with_string_t<std::wstring>;
void load(const nlohmann::json& j); void load(const nlohmann::json& j);
+9 -23
View File
@@ -36,26 +36,13 @@ 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, unless that code opts in to a change with a macro as described [below](#version-40). In that uses the public API. In particular, a 3.x release does not:
particular, a 3.x release does not:
- make breaking changes to the signature of a function: the types or order of its existing parameters, its return type, - change the signature of a function (its parameter types, return type, number of parameters, or the const-ness of a
its `noexcept` or `constexpr` specifier, or the const-ness of a member function. New parameters may be added if they member function);
have a default value; - remove or rename a function or class;
- 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 change or remove existing default arguments. New default arguments may be added; - change access specifiers or default arguments.
- 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).
@@ -64,14 +51,13 @@ 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. The - The ABI, including `sizeof(basic_json)` and the memory layout of its values. Recompile your code when you upgrade the
[versioned inline namespace](../features/namespace.md) turns mixing versions into a link error. library. The [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).
Breaking changes are only added behind a macro whose default keeps the 3.x behavior. See [Version 4.0](#version-40) and Changes that would break the public API are only added behind a macro whose default keeps the 3.x behavior, see
the [macro overview](../features/macros.md). [Version 4.0](#version-40).
## Version 4.0 ## Version 4.0
@@ -19,25 +19,9 @@ int main()
<< j.contains("/array/1"_json_pointer) << '\n' << j.contains("/array/1"_json_pointer) << '\n'
<< j.contains("/array/-"_json_pointer) << '\n' << j.contains("/array/-"_json_pointer) << '\n'
<< j.contains("/array/4"_json_pointer) << '\n' << j.contains("/array/4"_json_pointer) << '\n'
<< j.contains("/baz"_json_pointer) << std::endl; << j.contains("/baz"_json_pointer) << '\n'
// an array index with a leading '0' is not found
try << j.contains("/array/01"_json_pointer) << '\n'
{ // an array index that is not a number is not found
// try to use an array index with leading '0' << j.contains("/array/one"_json_pointer) << std::endl;
j.contains("/array/01"_json_pointer);
}
catch (const json::parse_error& e)
{
std::cout << e.what() << '\n';
}
try
{
// try to use an array index that is not a number
j.contains("/array/one"_json_pointer);
}
catch (const json::parse_error& e)
{
std::cout << e.what() << '\n';
}
} }
@@ -5,3 +5,5 @@ true
false false
false false
false false
false
false
@@ -1,11 +1,10 @@
#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::basic_json<std::map, custom_array_type>; using custom_json = nlohmann::json::with_array_t<custom_array_type>;
int main() int main()
{ {
@@ -1,16 +1,10 @@
#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::basic_json<std::map, std::vector, std::string, bool, using custom_json = nlohmann::json::with_binary_t<custom_binary_type>;
std::int64_t, std::uint64_t, double, std::allocator,
nlohmann::adl_serializer, custom_binary_type>;
int main() int main()
{ {
@@ -1,12 +1,11 @@
#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::basic_json<custom_object_type, std::vector>; using custom_json = nlohmann::json::with_object_t<custom_object_type>;
int main() int main()
{ {
@@ -1,12 +1,10 @@
#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::basic_json<std::map, std::vector, custom_string_type>; using custom_json = nlohmann::json::with_string_t<custom_string_type>;
int main() int main()
{ {
+1 -1
View File
@@ -8,7 +8,7 @@ int main()
try try
{ {
// parsing input with a syntax error // parsing input with a syntax error
json::parse("[1,2,3,]"); json j = json::parse("[1,2,3,]");
} }
catch (const json::parse_error& e) catch (const json::parse_error& e)
{ {
@@ -351,9 +351,8 @@ 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="2" ```cpp hl_lines="1"
using json_ld = nlohmann::basic_json<std::map, std::vector, std::string, bool, using json_ld = nlohmann::json::with_float_t<long double>;
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,6 +8,10 @@ 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:
@@ -143,7 +147,7 @@ struct unordered_map_object
using base_t::base_t; using base_t::base_t;
}; };
using unordered_json = nlohmann::basic_json<unordered_map_object>; using unordered_json = nlohmann::json::with_object_t<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
@@ -176,7 +180,7 @@ struct flat_hash_object
using base_t::base_t; using base_t::base_t;
}; };
using flat_hash_json = nlohmann::basic_json<flat_hash_object>; using flat_hash_json = nlohmann::json::with_object_t<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::basic_json<std::map, std::vector, my_string_type>; using my_json = nlohmann::json::with_string_t<my_string_type>;
nlohmann::json_pointer<my_json> ptr("/foo/bar/1"); nlohmann::json_pointer<my_json> ptr("/foo/bar/1");
``` ```
+11 -2
View File
@@ -9,12 +9,15 @@
#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 where available and plain C++ otherwise, so they need no // compiler builtins or platform-specific intrinsics where available and plain
// platform headers and work regardless of byte order. // C++ otherwise, so they work regardless of byte order.
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail
@@ -52,6 +55,12 @@ 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;
+11 -2
View File
@@ -8791,13 +8791,16 @@ NLOHMANN_JSON_NAMESPACE_END
#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 where available and plain C++ otherwise, so they need no // compiler builtins or platform-specific intrinsics where available and plain
// platform headers and work regardless of byte order. // C++ otherwise, so they work regardless of byte order.
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail
@@ -8835,6 +8838,12 @@ 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;
+6 -48
View File
@@ -370,14 +370,7 @@ 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::basic_json<std::map, using bad_alloc_json = nlohmann::json::with_allocator_t<nth_alloc_fails_allocator>;
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);
@@ -385,14 +378,7 @@ 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::basic_json<nlohmann::ordered_map, using bad_alloc_ordered_json = nlohmann::ordered_json::with_allocator_t<nth_alloc_fails_allocator>;
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);
@@ -450,14 +436,7 @@ 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::basic_json<std::map, using counting_json = nlohmann::json::with_allocator_t<scratch_counting_allocator>;
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
@@ -516,14 +495,7 @@ 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::basic_json<std::map, using countdown_json = nlohmann::json::with_allocator_t<countdown_allocator>;
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
@@ -631,14 +603,7 @@ 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::basic_json<std::map, using counting_json = nlohmann::json::with_allocator_t<counting_allocator>;
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
counting_allocator>;
SECTION("array") SECTION("array")
{ {
@@ -683,14 +648,7 @@ 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::basic_json<std::map, using my_json = nlohmann::json::with_allocator_t<my_allocator>;
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
+1 -1
View File
@@ -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::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint32_t, float>; using narrow_json = nlohmann::json::with_integers_t<std::int32_t, std::uint32_t>::with_float_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)
+34 -3
View File
@@ -17,6 +17,7 @@ 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
@@ -891,8 +892,39 @@ 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) // 128-bit integer type or a builtin / intrinsic)
std::uint64_t state = 42; std::uint64_t state = 42;
for (int i = 0; i < 10000; ++i) for (int i = 0; i < 10000; ++i)
{ {
@@ -901,8 +933,7 @@ 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);
const auto product = nlohmann::detail::full_multiplication(a, b); check_product(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));
+3 -3
View File
@@ -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::basic_json<unordered_object_t>; using unordered_json = nlohmann::json::with_object_t<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::basic_json<key_case_map>; using key_case_json = nlohmann::json::with_object_t<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::basic_json<case_insensitive_map>; using ci_json = nlohmann::json::with_object_t<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")
+2 -2
View File
@@ -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::basic_json<std::map, std::deque>; using deque_json = nlohmann::json::with_array_t<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::basic_json<std::map, vector_without_at>; using no_at_json = nlohmann::json::with_array_t<vector_without_at>;
} // namespace } // namespace
+3 -3
View File
@@ -179,7 +179,7 @@ class no_key_compare_map
} }
}; };
using no_key_compare_json = nlohmann::basic_json<no_key_compare_map>; using no_key_compare_json = nlohmann::json::with_object_t<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::basic_json<void_erase_map>; using void_erase_json = nlohmann::json::with_object_t<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::basic_json<forward_only_map>; using forward_only_json = nlohmann::json::with_object_t<forward_only_map>;
} // namespace } // namespace
+3 -3
View File
@@ -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 = json::number_unsigned_t(1) << 63U; const auto two_63 = static_cast<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(json::number_unsigned_t(int_max)) == json(int_max)); CHECK(json(static_cast<json::number_unsigned_t>(int_max)) == json(int_max));
CHECK(std::hash<json> {}(json(json::number_unsigned_t(int_max))) == std::hash<json> {}(json(int_max))); CHECK(std::hash<json> {}(json(static_cast<json::number_unsigned_t>(int_max))) == std::hash<json> {}(json(int_max)));
} }
TEST_CASE("hash<nlohmann::ordered_json>") TEST_CASE("hash<nlohmann::ordered_json>")
+18 -6
View File
@@ -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,10 +505,22 @@ 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);
CHECK_THROWS_WITH_AS(json::to_cbor(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to CBOR", json::type_error); // with diagnostics, the message names the path to the discarded leaf
CHECK_THROWS_WITH_AS(json::to_msgpack(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to MessagePack", json::type_error); #if JSON_DIAGNOSTICS
CHECK_THROWS_WITH_AS(json::to_ubjson(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to UBJSON", json::type_error); std::string path;
CHECK_THROWS_WITH_AS(json::to_bjdata(deep_discarded), "[json.exception.type_error.321] cannot serialize discarded value to BJData", json::type_error); for (std::size_t i = 0; i < depth; ++i)
{
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")
+3 -3
View File
@@ -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::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>; using long_double_json = nlohmann::json::with_float_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::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>; using long_double_json = nlohmann::json::with_float_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::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, long double>; using long_double_json = nlohmann::json::with_float_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) ||
+2 -2
View File
@@ -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::basic_json<std::map, std::vector, std::string, bool, std::int32_t, std::uint64_t, double>; using int32_json = nlohmann::json::with_integers_t<std::int32_t, std::uint64_t>;
using int16_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int16_t, std::uint64_t, double>; using int16_json = nlohmann::json::with_integers_t<std::int16_t, std::uint64_t>;
SECTION("number_integer_t = std::int32_t") SECTION("number_integer_t = std::int32_t")
{ {
+6 -8
View File
@@ -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::basic_json<my_workaround_fifo_map>; using my_json = nlohmann::json::with_object_t<my_workaround_fifo_map>;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// for #977 // for #977
@@ -86,8 +86,7 @@ struct foo_serializer < T, typename std::enable_if < !std::is_same<foo, T>::valu
}; };
} // namespace ns } // namespace ns
using foo_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, using foo_json = nlohmann::json::with_json_serializer_t<ns::foo_serializer>;
std::uint64_t, double, std::allocator, ns::foo_serializer, std::vector<std::uint8_t>>;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// for #805 // for #805
@@ -254,7 +253,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::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>; nlohmann::json::with_integers_t<std::int32_t, std::uint32_t>::with_float_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);
@@ -470,18 +469,17 @@ TEST_CASE("regression tests 1")
// create JSON class with nonstandard float number type // create JSON class with nonstandard float number type
// float // float
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> const j_float = nlohmann::json::with_integers_t<std::int32_t, std::uint32_t>::with_float_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::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> const j_double = nlohmann::json 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::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double> nlohmann::json::with_float_t<long double> const j_long_double = 1.23e45L;
const j_long_double = 1.23e45L;
CHECK(j_long_double.get<long double>() == 1.23e45L); CHECK(j_long_double.get<long double>() == 1.23e45L);
} }
+4 -17
View File
@@ -64,18 +64,7 @@ using ordered_json = nlohmann::ordered_json;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// for #4804 // for #4804
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
using json_4804 = nlohmann::basic_json<std::map, // ObjectType using json_4804 = nlohmann::json::with_binary_t<std::vector<std::byte>>;
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
@@ -107,7 +96,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
// for #1021 // for #1021
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>; using float_json = nlohmann::json::with_float_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
@@ -155,10 +144,8 @@ struct failing_allocator : std::allocator<T>
}; };
}; };
using failing_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, using failing_json = nlohmann::json::with_allocator_t<failing_allocator>;
std::int64_t, std::uint64_t, double, failing_allocator>; using failing_ordered_json = nlohmann::ordered_json::with_allocator_t<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
+2 -13
View File
@@ -62,18 +62,7 @@ using ordered_json = nlohmann::ordered_json;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// for #4804 // for #4804
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
using json_4804 = nlohmann::basic_json<std::map, // ObjectType using json_4804 = nlohmann::json::with_binary_t<std::vector<std::byte>>;
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
@@ -930,7 +919,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::basic_json<std::map, std::deque>; using deque_json = nlohmann::json::with_array_t<std::deque>;
SECTION("std::deque") SECTION("std::deque")
{ {
+1 -2
View File
@@ -367,8 +367,7 @@ 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::basic_json<std::map, std::vector, std::string, using long_double_json = nlohmann::json::with_float_t<long double>;
bool, std::int64_t, std::uint64_t, long double>;
SECTION("round-trip dump/parse") SECTION("round-trip dump/parse")
{ {