mirror of
https://github.com/nlohmann/json.git
synced 2026-10-03 13:10:33 +00:00
Merge remote-tracking branch 'origin/develop' into claude/fix-issue-3989-db7e45
Signed-off-by: Niels Lohmann <mail@nlohmann.me> # Conflicts: # tests/src/unit-alt-string.cpp
This commit is contained in:
@@ -276,6 +276,133 @@ TEST_CASE("controlled bad_alloc")
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// counts every allocation made on behalf of a basic_json value (of its own
|
||||
// object_t/array_t/string_t/binary_t or of its own type), and can be told to
|
||||
// fail one of them: the n-th call to allocate() throws std::bad_alloc instead
|
||||
// of allocating, whichever type it is allocating for
|
||||
std::size_t alloc_call_count = 0;
|
||||
long fail_at_alloc_call = -1; // -1: never fail
|
||||
|
||||
template<class T>
|
||||
struct nth_alloc_fails_allocator : std::allocator<T>
|
||||
{
|
||||
using std::allocator<T>::allocator;
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
const auto index = alloc_call_count++;
|
||||
if (fail_at_alloc_call >= 0 && index == static_cast<std::size_t>(fail_at_alloc_call))
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return std::allocator<T>::allocate(n);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
struct rebind
|
||||
{
|
||||
using other = nth_alloc_fails_allocator<U>;
|
||||
};
|
||||
};
|
||||
|
||||
// builds a value nested more than 128 levels deep - the bound the copy
|
||||
// constructor descends into before it continues without the call stack - and
|
||||
// checks that a copy survives any single allocation of it failing: every
|
||||
// attempt either throws std::bad_alloc, without crashing or leaving the
|
||||
// source altered, or completes the copy
|
||||
template<class BasicJsonType>
|
||||
void check_deep_copy_survives_failing_allocation(bool nest_objects)
|
||||
{
|
||||
CAPTURE(nest_objects);
|
||||
|
||||
fail_at_alloc_call = -1;
|
||||
|
||||
// [[[ ... [1] ... ]]], or the same nesting with objects, 130 levels deep
|
||||
BasicJsonType src = 1;
|
||||
for (std::size_t i = 0; i < 130; ++i)
|
||||
{
|
||||
if (nest_objects)
|
||||
{
|
||||
BasicJsonType wrapper = BasicJsonType::object();
|
||||
wrapper["a"] = std::move(src);
|
||||
src = std::move(wrapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
src = BasicJsonType::array({std::move(src)});
|
||||
}
|
||||
}
|
||||
|
||||
const std::string original_dump = src.dump();
|
||||
|
||||
// first measure how many allocations an unhindered copy takes
|
||||
alloc_call_count = 0;
|
||||
{
|
||||
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization): the copy is what is measured
|
||||
const BasicJsonType measure(src);
|
||||
}
|
||||
const std::size_t total_allocations = alloc_call_count;
|
||||
REQUIRE(total_allocations > 0);
|
||||
REQUIRE(src.dump() == original_dump);
|
||||
|
||||
// let the 0th, 1st, 2nd, ... allocation of the copy fail in turn; every
|
||||
// such copy must throw std::bad_alloc rather than crash, and the source
|
||||
// must come out exactly as it went in
|
||||
for (std::size_t n = 0; n < total_allocations; ++n)
|
||||
{
|
||||
CAPTURE(n);
|
||||
alloc_call_count = 0;
|
||||
fail_at_alloc_call = static_cast<long>(n);
|
||||
|
||||
CHECK_THROWS_AS(BasicJsonType(src), std::bad_alloc&);
|
||||
|
||||
fail_at_alloc_call = -1;
|
||||
CHECK(src.dump() == original_dump);
|
||||
}
|
||||
|
||||
// once no allocation is made to fail, the copy itself must succeed
|
||||
fail_at_alloc_call = -1;
|
||||
const BasicJsonType copy(src);
|
||||
CHECK(copy.dump() == original_dump);
|
||||
CHECK(src.dump() == original_dump);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("copy of a deeply nested value survives a failing allocation (#5640)")
|
||||
{
|
||||
SECTION("std::map-backed object_t")
|
||||
{
|
||||
using bad_alloc_json = nlohmann::basic_json<std::map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
nth_alloc_fails_allocator>;
|
||||
|
||||
check_deep_copy_survives_failing_allocation<bad_alloc_json>(false);
|
||||
check_deep_copy_survives_failing_allocation<bad_alloc_json>(true);
|
||||
}
|
||||
|
||||
SECTION("ordered_map-backed object_t")
|
||||
{
|
||||
using bad_alloc_ordered_json = nlohmann::basic_json<nlohmann::ordered_map,
|
||||
std::vector,
|
||||
std::string,
|
||||
bool,
|
||||
std::int64_t,
|
||||
std::uint64_t,
|
||||
double,
|
||||
nth_alloc_fails_allocator>;
|
||||
|
||||
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(false);
|
||||
check_deep_copy_survives_failing_allocation<bad_alloc_ordered_json>(true);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// counts the allocations of pairs with a non-const first member: the object
|
||||
|
||||
@@ -174,6 +174,15 @@ bool operator<(const char* op1, const alt_string& op2) noexcept
|
||||
return op1 < op2.str_impl;
|
||||
}
|
||||
|
||||
enum class alt_color { red, green };
|
||||
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage,misc-const-correctness,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(alt_color,
|
||||
{
|
||||
{alt_color::red, "red"},
|
||||
{alt_color::green, "green"},
|
||||
})
|
||||
|
||||
TEST_CASE("alternative string type")
|
||||
{
|
||||
SECTION("binary formats")
|
||||
@@ -414,4 +423,19 @@ TEST_CASE("alternative string type")
|
||||
CHECK(!alt_json::sax_parse(std::vector<std::uint8_t> {0xA2, 0x01, 0x02, 0x61, 'a', 0x03}, &cbor_sax, alt_json::input_format_t::cbor));
|
||||
CHECK(c.dump() == R"({"a":3})");
|
||||
}
|
||||
|
||||
SECTION("strict enum")
|
||||
{
|
||||
// regression test for #5667: NLOHMANN_JSON_SERIALIZE_ENUM_STRICT's from_json
|
||||
// built its exception message with "..." + j.dump(), which does not compile
|
||||
// when j.dump() returns a custom string_t (here alt_string) instead of
|
||||
// std::string
|
||||
alt_json doc;
|
||||
doc = "red";
|
||||
CHECK(doc.get<alt_color>() == alt_color::red);
|
||||
|
||||
alt_json _;
|
||||
doc = "blue";
|
||||
CHECK_THROWS_WITH_AS(_ = doc.get<alt_color>(), "[json.exception.out_of_range.410] enum value out of range for alt_color: \"blue\"", alt_json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -797,7 +797,11 @@ TEST_CASE("regression test - BSON binary subtype rejects a value that doesn't fi
|
||||
CHECK(json::from_bson(json::to_bson(doc255))["b"].get_binary().subtype() == 255);
|
||||
|
||||
CHECK_THROWS_AS(json::to_bson(json{{"b", json::binary({1, 2}, 256)}}), json::out_of_range);
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"b", json::binary({1, 2}, 300)}}), "[json.exception.out_of_range.415] subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"b", json::binary({1, 2}, 300)}}), "[json.exception.out_of_range.415] (/b) subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"b", json::binary({1, 2}, 300)}}), "[json.exception.out_of_range.415] subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("BSON input/output_adapters")
|
||||
@@ -1805,6 +1809,21 @@ value = depth % 2 == 0 ? json{{"a", std::move(value)}, {"b", {1, "x"}}} :
|
||||
CHECK(output.empty());
|
||||
}
|
||||
|
||||
SECTION("a binary subtype that doesn't fit a byte is rejected before anything is written (#5675)")
|
||||
{
|
||||
// the offending value is nested, so this also covers that the check
|
||||
// is not limited to a directly written value's own document
|
||||
json const j = {{"a", {{"b", json::binary({1, 2}, 300)}}}};
|
||||
|
||||
std::vector<std::uint8_t> vector_output;
|
||||
CHECK_THROWS_AS(json::to_bson(j, vector_output), json::out_of_range&);
|
||||
CHECK(vector_output.empty());
|
||||
|
||||
std::string string_output;
|
||||
CHECK_THROWS_AS(json::to_bson(j, string_output), json::out_of_range&);
|
||||
CHECK(string_output.empty());
|
||||
}
|
||||
|
||||
SECTION("values nested too deeply for the call stack (#5392)")
|
||||
{
|
||||
// serializing recursed once per nesting level, and computed every
|
||||
|
||||
@@ -12,10 +12,14 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <array> // array
|
||||
#include <cfloat> // FLT_EVAL_METHOD
|
||||
#include <cstdint> // uint32_t, uint64_t
|
||||
#include <cstdlib> // strtod
|
||||
#include <cstring> // memcpy
|
||||
#include <sstream> // stringstream
|
||||
#include <string> // string
|
||||
#include <utility> // pair
|
||||
#include <vector> // vector
|
||||
|
||||
namespace
|
||||
@@ -700,3 +704,614 @@ TEST_CASE("parse_float_fast declines what it cannot convert exactly")
|
||||
CHECK_FALSE(fast("1e23", out));
|
||||
CHECK_FALSE(fast("1e-23", out));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// arbitrary-precision unsigned integers, just enough to recompute the table of
|
||||
// powers of five (little-endian 32-bit limbs)
|
||||
using big_uint = std::vector<std::uint32_t>;
|
||||
|
||||
void big_trim(big_uint& a)
|
||||
{
|
||||
while (!a.empty() && a.back() == 0)
|
||||
{
|
||||
a.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
big_uint big_from(std::uint64_t high, std::uint64_t low)
|
||||
{
|
||||
big_uint a = {static_cast<std::uint32_t>(low), static_cast<std::uint32_t>(low >> 32u),
|
||||
static_cast<std::uint32_t>(high), static_cast<std::uint32_t>(high >> 32u)
|
||||
};
|
||||
big_trim(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
big_uint big_mul(const big_uint& a, const big_uint& b)
|
||||
{
|
||||
big_uint r(a.size() + b.size(), 0);
|
||||
for (std::size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
std::uint64_t carry = 0;
|
||||
for (std::size_t j = 0; j < b.size(); ++j)
|
||||
{
|
||||
const std::uint64_t t = (static_cast<std::uint64_t>(a[i]) * b[j]) + r[i + j] + carry;
|
||||
r[i + j] = static_cast<std::uint32_t>(t);
|
||||
carry = t >> 32u;
|
||||
}
|
||||
r[i + b.size()] = static_cast<std::uint32_t>(carry);
|
||||
}
|
||||
big_trim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
big_uint big_shl(const big_uint& a, std::size_t s)
|
||||
{
|
||||
big_uint r(s / 32, 0);
|
||||
std::uint32_t carry = 0;
|
||||
for (const std::uint32_t x : a)
|
||||
{
|
||||
const std::uint64_t t = static_cast<std::uint64_t>(x) << (s % 32);
|
||||
r.push_back(static_cast<std::uint32_t>(t) | carry);
|
||||
carry = static_cast<std::uint32_t>(t >> 32u);
|
||||
}
|
||||
r.push_back(carry);
|
||||
big_trim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// a + 1 (add) or a - 1 (!add, a > 0)
|
||||
big_uint big_step(big_uint a, bool add)
|
||||
{
|
||||
for (auto& x : a)
|
||||
{
|
||||
const std::uint32_t old = x;
|
||||
x = add ? x + 1 : x - 1;
|
||||
if ((add && x > old) || (!add && x < old))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add && (a.empty() || a.back() == 0))
|
||||
{
|
||||
a.push_back(1);
|
||||
}
|
||||
big_trim(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
bool big_less_equal(const big_uint& a, const big_uint& b)
|
||||
{
|
||||
if (a.size() != b.size())
|
||||
{
|
||||
return a.size() < b.size();
|
||||
}
|
||||
for (std::size_t i = a.size(); i-- > 0;)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
return a[i] < b[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t big_bit_length(const big_uint& a)
|
||||
{
|
||||
std::size_t n = a.size() * 32;
|
||||
for (std::uint32_t top = a.back(); (top & 0x80000000u) == 0; top <<= 1u)
|
||||
{
|
||||
--n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::uint64_t bits_of(double d)
|
||||
{
|
||||
std::uint64_t b = 0;
|
||||
std::memcpy(&b, &d, sizeof(b));
|
||||
return b;
|
||||
}
|
||||
|
||||
bool eisel_lemire(const std::string& s, double& out)
|
||||
{
|
||||
return nlohmann::detail::parse_float_eisel_lemire(s.data(), s.data() + s.size(), out);
|
||||
}
|
||||
|
||||
// significant digits of a token, without trailing zeros
|
||||
std::size_t significant_digits(const std::string& s)
|
||||
{
|
||||
std::string digits;
|
||||
for (const char c : s)
|
||||
{
|
||||
if (c == 'e' || c == 'E')
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (c >= '0' && c <= '9' && !(digits.empty() && c == '0'))
|
||||
{
|
||||
digits += c;
|
||||
}
|
||||
}
|
||||
while (!digits.empty() && digits.back() == '0')
|
||||
{
|
||||
digits.pop_back();
|
||||
}
|
||||
return digits.size();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Eisel-Lemire float conversion")
|
||||
{
|
||||
SECTION("the table of powers of five")
|
||||
{
|
||||
// Recompute every entry the way fast_float's table_generation.py
|
||||
// defines it, using only multiplications and comparisons: for q >= 0
|
||||
// the most significant 128 bits of 5^q; for q < 0 floor(2^b / 5^-q) + 1
|
||||
// for b = z + 127 (q >= -27), or that value for b = 2z + 128 cut to
|
||||
// its most significant 128 bits (q < -27), where z is the bit length
|
||||
// of 5^-q.
|
||||
const auto& table = nlohmann::detail::pow5_128();
|
||||
big_uint power5 = {1};
|
||||
for (std::int64_t q = 0; q <= nlohmann::detail::pow5_128_largest_power; ++q)
|
||||
{
|
||||
const auto index = static_cast<std::size_t>(2 * (q - nlohmann::detail::pow5_128_smallest_power));
|
||||
const big_uint entry = big_from(table[index], table[index + 1]);
|
||||
const std::size_t bits = big_bit_length(power5);
|
||||
if (bits <= 128)
|
||||
{
|
||||
CHECK(entry == big_shl(power5, 128 - bits));
|
||||
}
|
||||
else
|
||||
{
|
||||
// floor(5^q / 2^(bits - 128))
|
||||
CHECK(big_less_equal(big_shl(entry, bits - 128), power5));
|
||||
CHECK_FALSE(big_less_equal(big_shl(big_step(entry, true), bits - 128), power5));
|
||||
}
|
||||
power5 = big_mul(power5, {5});
|
||||
}
|
||||
|
||||
power5 = {5};
|
||||
for (std::int64_t q = -1; q >= nlohmann::detail::pow5_128_smallest_power; --q)
|
||||
{
|
||||
const auto index = static_cast<std::size_t>(2 * (q - nlohmann::detail::pow5_128_smallest_power));
|
||||
const big_uint entry = big_from(table[index], table[index + 1]);
|
||||
CHECK(big_bit_length(entry) == 128);
|
||||
const std::size_t z = big_bit_length(power5);
|
||||
const big_uint two_b = big_shl({1}, q >= -27 ? z + 127 : (2 * z) + 128);
|
||||
// c = floor(2^b / p) + 1, stored as floor(c / 2^s):
|
||||
// (entry * 2^s - 1) * p <= 2^b < ((entry + 1) * 2^s - 1) * p
|
||||
const std::size_t s = q >= -27 ? 0 : z + 1;
|
||||
CHECK(big_less_equal(big_mul(big_step(big_shl(entry, s), false), power5), two_b));
|
||||
CHECK_FALSE(big_less_equal(big_mul(big_step(big_shl(big_step(entry, true), s), false), power5), two_b));
|
||||
power5 = big_mul(power5, {5});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("128-bit products and leading zeros")
|
||||
{
|
||||
// whichever implementation the compiler gets (with or without a
|
||||
// 128-bit integer type or a builtin)
|
||||
std::uint64_t state = 42;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
state ^= state << 13u;
|
||||
state ^= state >> 7u;
|
||||
state ^= state << 17u;
|
||||
const std::uint64_t a = state;
|
||||
const std::uint64_t b = (state * 0x9E3779B97F4A7C15u) >> (i % 64);
|
||||
const auto product = nlohmann::detail::full_multiplication(a, b);
|
||||
CHECK(big_from(product.high, product.low) == big_mul(big_from(0, a), big_from(0, b)));
|
||||
|
||||
const int k = i % 64;
|
||||
const std::uint64_t x = (std::uint64_t{1} << k) | (a & ((std::uint64_t{1} << k) - 1));
|
||||
CHECK(nlohmann::detail::count_leading_zeros(x) == 63 - k);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("known values")
|
||||
{
|
||||
// Generated with Python, whose float() is correctly rounded:
|
||||
// cases = [<hard cases>, 2**53 + 2k + 1, 2**54 + 4k + 2, and exact midpoints
|
||||
// between neighbouring doubles, also 1e-60 above and below them]
|
||||
// print('{"%s", 0x%016xu},' % (s, struct.unpack('<Q', struct.pack('<d', float(s)))[0]))
|
||||
const std::vector<std::pair<std::string, std::uint64_t>> known =
|
||||
{
|
||||
{"0", 0x0000000000000000u},
|
||||
{"-0", 0x8000000000000000u},
|
||||
{"0.0", 0x0000000000000000u},
|
||||
{"-0.0", 0x8000000000000000u},
|
||||
{"0e5", 0x0000000000000000u},
|
||||
{"0.000e-9", 0x0000000000000000u},
|
||||
{"1", 0x3ff0000000000000u},
|
||||
{"-1", 0xbff0000000000000u},
|
||||
{"0.1", 0x3fb999999999999au},
|
||||
{"0.3", 0x3fd3333333333333u},
|
||||
{"1.5", 0x3ff8000000000000u},
|
||||
{"-2.5e-3", 0xbf647ae147ae147bu},
|
||||
{"1e23", 0x44b52d02c7e14af6u},
|
||||
{"1e22", 0x4480f0cf064dd592u},
|
||||
{"8.98846567431158e307", 0x7fe0000000000000u},
|
||||
{"2.2250738585072011e-308", 0x000fffffffffffffu},
|
||||
{"2.2250738585072012e-308", 0x0010000000000000u},
|
||||
{"2.2250738585072014e-308", 0x0010000000000000u},
|
||||
{"4.9406564584124654e-324", 0x0000000000000001u},
|
||||
{"2.4703282292062327e-324", 0x0000000000000000u},
|
||||
{"2.4703282292062328e-324", 0x0000000000000001u},
|
||||
{"1e-324", 0x0000000000000000u},
|
||||
{"3e-324", 0x0000000000000001u},
|
||||
{"1.7976931348623157e308", 0x7fefffffffffffffu},
|
||||
{"1.7976931348623158e308", 0x7fefffffffffffffu},
|
||||
{"1.7976931348623159e308", 0x7ff0000000000000u},
|
||||
{"1e308", 0x7fe1ccf385ebc8a0u},
|
||||
{"1e309", 0x7ff0000000000000u},
|
||||
{"-1e400", 0xfff0000000000000u},
|
||||
{"1e-400", 0x0000000000000000u},
|
||||
{"9007199254740991", 0x433fffffffffffffu},
|
||||
{"9007199254740992", 0x4340000000000000u},
|
||||
{"9007199254740993", 0x4340000000000000u},
|
||||
{"9007199254740995", 0x4340000000000002u},
|
||||
{"18014398509481986", 0x4350000000000000u},
|
||||
{"18014398509481990", 0x4350000000000002u},
|
||||
{"7.2057594037927933e16", 0x4370000000000000u},
|
||||
{"123456789012345678901234567890", 0x45f8ee90ff6c373eu},
|
||||
{"1.000000000000000111", 0x3ff0000000000000u},
|
||||
{"1.0000000000000001110223", 0x3ff0000000000000u},
|
||||
{"1.00000000000000011102230246251565404236316680908203125", 0x3ff0000000000000u},
|
||||
{"1.00000000000000011102230246251565404236316680908203126", 0x3ff0000000000001u},
|
||||
{"0.00000000000000000000000000000000000000000000000000000000000001", 0x3310747ddddf22a8u},
|
||||
{"100000000000000000000000000000000000000000000", 0x4911efc659cf7d4cu},
|
||||
{"1234567890123456789", 0x43b12210f47de981u},
|
||||
{"12345678901234567890", 0x43e56a95319d63e1u},
|
||||
{"1234567890123456789.5", 0x43b12210f47de981u},
|
||||
{"0.1234567890123456789012345", 0x3fbf9add3746f65fu},
|
||||
{"4.4501477170144023e-308", 0x001fffffffffffffu},
|
||||
{"2.4406961166466664e-309", 0x0001c14ae5310a48u},
|
||||
{"5e-324", 0x0000000000000001u},
|
||||
{"1.0e-307", 0x0031fa182c40c60du},
|
||||
{"179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368", 0x7fefffffffffffffu},
|
||||
{"4.9e-324", 0x0000000000000001u},
|
||||
{"9007199254740993", 0x4340000000000000u},
|
||||
{"18014398509481986", 0x4350000000000000u},
|
||||
{"9007199254740995", 0x4340000000000002u},
|
||||
{"18014398509481990", 0x4350000000000002u},
|
||||
{"9007199254740997", 0x4340000000000002u},
|
||||
{"18014398509481994", 0x4350000000000002u},
|
||||
{"9007199254740999", 0x4340000000000004u},
|
||||
{"18014398509481998", 0x4350000000000004u},
|
||||
{"9007199254741001", 0x4340000000000004u},
|
||||
{"18014398509482002", 0x4350000000000004u},
|
||||
{"9007199254741003", 0x4340000000000006u},
|
||||
{"18014398509482006", 0x4350000000000006u},
|
||||
{"9007199254741005", 0x4340000000000006u},
|
||||
{"18014398509482010", 0x4350000000000006u},
|
||||
{"9007199254741007", 0x4340000000000008u},
|
||||
{"18014398509482014", 0x4350000000000008u},
|
||||
{"9007199254741009", 0x4340000000000008u},
|
||||
{"18014398509482018", 0x4350000000000008u},
|
||||
{"9007199254741011", 0x434000000000000au},
|
||||
{"18014398509482022", 0x435000000000000au},
|
||||
{"9007199254741013", 0x434000000000000au},
|
||||
{"18014398509482026", 0x435000000000000au},
|
||||
{"9007199254741015", 0x434000000000000cu},
|
||||
{"18014398509482030", 0x435000000000000cu},
|
||||
{"9007199254741017", 0x434000000000000cu},
|
||||
{"18014398509482034", 0x435000000000000cu},
|
||||
{"9007199254741019", 0x434000000000000eu},
|
||||
{"18014398509482038", 0x435000000000000eu},
|
||||
{"9007199254741021", 0x434000000000000eu},
|
||||
{"18014398509482042", 0x435000000000000eu},
|
||||
{"9007199254741023", 0x4340000000000010u},
|
||||
{"18014398509482046", 0x4350000000000010u},
|
||||
{"9007199254741025", 0x4340000000000010u},
|
||||
{"18014398509482050", 0x4350000000000010u},
|
||||
{"9007199254741027", 0x4340000000000012u},
|
||||
{"18014398509482054", 0x4350000000000012u},
|
||||
{"9007199254741029", 0x4340000000000012u},
|
||||
{"18014398509482058", 0x4350000000000012u},
|
||||
{"9007199254741031", 0x4340000000000014u},
|
||||
{"18014398509482062", 0x4350000000000014u},
|
||||
{"9007199254741033", 0x4340000000000014u},
|
||||
{"18014398509482066", 0x4350000000000014u},
|
||||
{"9007199254741035", 0x4340000000000016u},
|
||||
{"18014398509482070", 0x4350000000000016u},
|
||||
{"9007199254741037", 0x4340000000000016u},
|
||||
{"18014398509482074", 0x4350000000000016u},
|
||||
{"9007199254741039", 0x4340000000000018u},
|
||||
{"18014398509482078", 0x4350000000000018u},
|
||||
{"9007199254741041", 0x4340000000000018u},
|
||||
{"18014398509482082", 0x4350000000000018u},
|
||||
{"9007199254741043", 0x434000000000001au},
|
||||
{"18014398509482086", 0x435000000000001au},
|
||||
{"9007199254741045", 0x434000000000001au},
|
||||
{"18014398509482090", 0x435000000000001au},
|
||||
{"9007199254741047", 0x434000000000001cu},
|
||||
{"18014398509482094", 0x435000000000001cu},
|
||||
{"9007199254741049", 0x434000000000001cu},
|
||||
{"18014398509482098", 0x435000000000001cu},
|
||||
{"9007199254741051", 0x434000000000001eu},
|
||||
{"18014398509482102", 0x435000000000001eu},
|
||||
{"9007199254741053", 0x434000000000001eu},
|
||||
{"18014398509482106", 0x435000000000001eu},
|
||||
{"9007199254741055", 0x4340000000000020u},
|
||||
{"18014398509482110", 0x4350000000000020u},
|
||||
{"9007199254741057", 0x4340000000000020u},
|
||||
{"18014398509482114", 0x4350000000000020u},
|
||||
{"9007199254741059", 0x4340000000000022u},
|
||||
{"18014398509482118", 0x4350000000000022u},
|
||||
{"9007199254741061", 0x4340000000000022u},
|
||||
{"18014398509482122", 0x4350000000000022u},
|
||||
{"9007199254741063", 0x4340000000000024u},
|
||||
{"18014398509482126", 0x4350000000000024u},
|
||||
{"9007199254741065", 0x4340000000000024u},
|
||||
{"18014398509482130", 0x4350000000000024u},
|
||||
{"9007199254741067", 0x4340000000000026u},
|
||||
{"18014398509482134", 0x4350000000000026u},
|
||||
{"9007199254741069", 0x4340000000000026u},
|
||||
{"18014398509482138", 0x4350000000000026u},
|
||||
{"9007199254741071", 0x4340000000000028u},
|
||||
{"18014398509482142", 0x4350000000000028u},
|
||||
{"0.00000000000000000142055942108419951085063380808124102279024543292671443374397544090470546507276594638824462890625", 0x3c3a3466f662d406u},
|
||||
{"0.000000000000000001420559421084199510850633808081241022790245432926714433743975440904705465072765946388244628906251", 0x3c3a3466f662d407u},
|
||||
{"0.00000000000000000142055942108419951085063380808124102279024543292671443374397444090470546507276594638824462890625", 0x3c3a3466f662d406u},
|
||||
{"8656.5250079159513916238211095333099365234375", 0x40c0e84333759a94u},
|
||||
{"8656.52500791595139162382110953330993652343751", 0x40c0e84333759a94u},
|
||||
{"8656.525007915951391623821109533309936523437499999999999999999", 0x40c0e84333759a93u},
|
||||
{"13.07696731650454946560557800694368779659271240234375", 0x402a276842967ef0u},
|
||||
{"13.076967316504549465605578006943687796592712402343751", 0x402a276842967ef0u},
|
||||
{"13.07696731650454946560557800694368779659271240234374999999999", 0x402a276842967eefu},
|
||||
{"74708253715391928", 0x437096ac2cc7ee5cu},
|
||||
{"747082537153919281", 0x43a4bc5737f9e9f2u},
|
||||
{"74708253715391927.99999999999999999999999999999999999999999999", 0x437096ac2cc7ee5bu},
|
||||
{"1809802988.27203977108001708984375", 0x41daf7d9bb11691au},
|
||||
{"1809802988.272039771080017089843751", 0x41daf7d9bb11691au},
|
||||
{"1809802988.272039771080017089843749999999999999999999999999999", 0x41daf7d9bb116919u},
|
||||
{"51.390809684186766759239617385901510715484619140625", 0x4049b2060d3e4568u},
|
||||
{"51.3908096841867667592396173859015107154846191406251", 0x4049b2060d3e4569u},
|
||||
{"51.39080968418676675923961738590151071548461914062499999999999", 0x4049b2060d3e4568u},
|
||||
{"9999807412.59738445281982421875", 0x4202a0479da4c772u},
|
||||
{"9999807412.597384452819824218751", 0x4202a0479da4c772u},
|
||||
{"9999807412.597384452819824218749999999999999999999999999999999", 0x4202a0479da4c771u},
|
||||
{"0.00000000023260971767101600534534272272645127367651785021962496102787554264068603515625", 0x3deff83a135dec10u},
|
||||
{"0.000000000232609717671016005345342722726451273676517850219624961027875542640686035156251", 0x3deff83a135dec11u},
|
||||
{"0.00000000023260971767101600534534272272645127367651785021962496102787544264068603515625", 0x3deff83a135dec10u},
|
||||
{"0.000000000497610482021202508216234789619066523902457532813059515319764614105224609375", 0x3e01190730d1ec48u},
|
||||
{"0.0000000004976104820212025082162347896190665239024575328130595153197646141052246093751", 0x3e01190730d1ec48u},
|
||||
{"0.000000000497610482021202508216234789619066523902457532813059515319764514105224609375", 0x3e01190730d1ec47u},
|
||||
{"0.0000000000291336422596533830691676779231223432149733287843673679162748157978057861328125", 0x3dc004321559736eu},
|
||||
{"0.00000000002913364225965338306916767792312234321497332878436736791627481579780578613281251", 0x3dc004321559736fu},
|
||||
{"0.0000000000291336422596533830691676779231223432149733287843673679162748057978057861328125", 0x3dc004321559736eu},
|
||||
{"0.000000000000000039237155154865396441907405399546892080260012902422940561653064150959835387766361236572265625", 0x3c869e61cfa3b8a4u},
|
||||
{"0.0000000000000000392371551548653964419074053995468920802600129024229405616530641509598353877663612365722656251", 0x3c869e61cfa3b8a5u},
|
||||
{"0.000000000000000039237155154865396441907405399546892080260012902422940561653054150959835387766361236572265625", 0x3c869e61cfa3b8a4u},
|
||||
{"0.00000000000000006496592863767266414092845207857846208631635335985395063307379359685000963509082794189453125", 0x3c92b9a3b219ee84u},
|
||||
{"0.000000000000000064965928637672664140928452078578462086316353359853950633073793596850009635090827941894531251", 0x3c92b9a3b219ee85u},
|
||||
{"0.00000000000000006496592863767266414092845207857846208631635335985395063307378359685000963509082794189453125", 0x3c92b9a3b219ee84u},
|
||||
{"0.0000000000448169607439179753541822628688597626549217078917308754171244800090789794921875", 0x3dc8a36d2e8094dau},
|
||||
{"0.00000000004481696074391797535418226286885976265492170789173087541712448000907897949218751", 0x3dc8a36d2e8094dau},
|
||||
{"0.0000000000448169607439179753541822628688597626549217078917308754171244700090789794921875", 0x3dc8a36d2e8094d9u},
|
||||
{"1800873890234250.875", 0x4319978a820cfe2cu},
|
||||
{"1800873890234250.8751", 0x4319978a820cfe2cu},
|
||||
{"1800873890234250.874999999999999999999999999999999999999999999", 0x4319978a820cfe2bu},
|
||||
{"0.000023941132739153309216405436654628857695570331998169422149658203125", 0x3ef91aa61d42e0e0u},
|
||||
{"0.0000239411327391533092164054366546288576955703319981694221496582031251", 0x3ef91aa61d42e0e1u},
|
||||
{"0.000023941132739153309216405436654628857695570331998169422149658193125", 0x3ef91aa61d42e0e0u},
|
||||
{"8339818978785937.5", 0x433da1056bb8ba92u},
|
||||
{"8339818978785937.51", 0x433da1056bb8ba92u},
|
||||
{"8339818978785937.499999999999999999999999999999999999999999999", 0x433da1056bb8ba91u},
|
||||
{"283649145986385328", 0x438f7dcb29dae42eu},
|
||||
{"2836491459863853281", 0x43c3ae9efa28ce9cu},
|
||||
{"283649145986385327.9999999999999999999999999999999999999999999", 0x438f7dcb29dae42du},
|
||||
{"0.0000000000000000004203729478287971874304476341685497759528753070014375965192388040492232903488911688327789306640625", 0x3c1f049ed78cb8a2u},
|
||||
{"0.00000000000000000042037294782879718743044763416854977595287530700143759651923880404922329034889116883277893066406251", 0x3c1f049ed78cb8a3u},
|
||||
{"0.0000000000000000004203729478287971874304476341685497759528753070014375965192387040492232903488911688327789306640625", 0x3c1f049ed78cb8a2u},
|
||||
{"340031.78635183119331486523151397705078125", 0x4114c0ff25396a18u},
|
||||
{"340031.786351831193314865231513977050781251", 0x4114c0ff25396a19u},
|
||||
{"340031.7863518311933148652315139770507812499999999999999999999", 0x4114c0ff25396a18u},
|
||||
{"0.0000000004543709717853330820053712055931242029538363880192264332436025142669677734375", 0x3dff3960f070bf76u},
|
||||
{"0.00000000045437097178533308200537120559312420295383638801922643324360251426696777343751", 0x3dff3960f070bf76u},
|
||||
{"0.0000000004543709717853330820053712055931242029538363880192264332436024142669677734375", 0x3dff3960f070bf75u},
|
||||
{"0.0000000000007937958898451257082591244100968761704503924570008877026339177973568439483642578125", 0x3d6bede0b40e37c2u},
|
||||
{"0.00000000000079379588984512570825912441009687617045039245700088770263391779735684394836425781251", 0x3d6bede0b40e37c3u},
|
||||
{"0.0000000000007937958898451257082591244100968761704503924570008877026339176973568439483642578125", 0x3d6bede0b40e37c2u},
|
||||
{"0.00000000000000068304843500200357021582520000166071595321259251644419041582523277611471712589263916015625", 0x3cc89c02848f8654u},
|
||||
{"0.000000000000000683048435002003570215825200001660715953212592516444190415825232776114717125892639160156251", 0x3cc89c02848f8655u},
|
||||
{"0.00000000000000068304843500200357021582520000166071595321259251644419041582513277611471712589263916015625", 0x3cc89c02848f8654u},
|
||||
{"0.00000000147705080029041786940146712084494760863773166192913777194917201995849609375", 0x3e1960235bc34d06u},
|
||||
{"0.000000001477050800290417869401467120844947608637731661929137771949172019958496093751", 0x3e1960235bc34d06u},
|
||||
{"0.00000000147705080029041786940146712084494760863773166192913777194917101995849609375", 0x3e1960235bc34d05u},
|
||||
{"2164972979236447104", 0x43be0b87743fb524u},
|
||||
{"21649729792364471041", 0x43f2c734a8a7d136u},
|
||||
{"2164972979236447103.999999999999999999999999999999999999999999", 0x43be0b87743fb523u},
|
||||
{"13124633159586767", 0x4347506464a469e8u},
|
||||
{"131246331595867671", 0x437d247d7dcd8461u},
|
||||
{"13124633159586766.99999999999999999999999999999999999999999999", 0x4347506464a469e7u},
|
||||
{"0.000000000000027605165650764659887597286048864477738779108113853499872902830247767269611358642578125", 0x3d1f14a5b417cb08u},
|
||||
{"0.0000000000000276051656507646598875972860488644777387791081138534998729028302477672696113586425781251", 0x3d1f14a5b417cb09u},
|
||||
{"0.000000000000027605165650764659887597286048864477738779108113853499872902820247767269611358642578125", 0x3d1f14a5b417cb08u},
|
||||
{"0.01727792833395616796388072344825559412129223346710205078125", 0x3f91b14e248c42c8u},
|
||||
{"0.017277928333956167963880723448255594121292233467102050781251", 0x3f91b14e248c42c9u},
|
||||
{"0.01727792833395616796388072344825559412129223346710205078124999", 0x3f91b14e248c42c8u},
|
||||
{"0.00000000000003096211381890547702500862566064822950373937142376501441276559489779174327850341796875", 0x3d216e1c61130b22u},
|
||||
{"0.000000000000030962113818905477025008625660648229503739371423765014412765594897791743278503417968751", 0x3d216e1c61130b22u},
|
||||
{"0.00000000000003096211381890547702500862566064822950373937142376501441276558489779174327850341796875", 0x3d216e1c61130b21u},
|
||||
{"0.0000000000000683414954481284270259359974108983284531919182025472281338807079009711742401123046875", 0x3d333c86137e5170u},
|
||||
{"0.00000000000006834149544812842702593599741089832845319191820254722813388070790097117424011230468751", 0x3d333c86137e5170u},
|
||||
{"0.0000000000000683414954481284270259359974108983284531919182025472281338806979009711742401123046875", 0x3d333c86137e516fu},
|
||||
{"3237539054990129.75", 0x4327010c9aa36664u},
|
||||
{"3237539054990129.751", 0x4327010c9aa36664u},
|
||||
{"3237539054990129.749999999999999999999999999999999999999999999", 0x4327010c9aa36663u},
|
||||
{"0.0000000000000105429301486355911969397173440055240907798901443814809653076736140064895153045654296875", 0x3d07bd95dfb8a1eeu},
|
||||
{"0.00000000000001054293014863559119693971734400552409077989014438148096530767361400648951530456542968751", 0x3d07bd95dfb8a1eeu},
|
||||
{"0.0000000000000105429301486355911969397173440055240907798901443814809653076636140064895153045654296875", 0x3d07bd95dfb8a1edu},
|
||||
{"9460.2061893763575426419265568256378173828125", 0x40c27a1a6469da1eu},
|
||||
{"9460.20618937635754264192655682563781738281251", 0x40c27a1a6469da1fu},
|
||||
{"9460.206189376357542641926556825637817382812499999999999999999", 0x40c27a1a6469da1eu},
|
||||
{"465000373656610.53125", 0x42fa6ea56179c228u},
|
||||
{"465000373656610.531251", 0x42fa6ea56179c229u},
|
||||
{"465000373656610.5312499999999999999999999999999999999999999999", 0x42fa6ea56179c228u},
|
||||
{"0.000000000107709773707743713401260815383950956818093214195641849073581397533416748046875", 0x3ddd9b66c974bb14u},
|
||||
{"0.0000000001077097737077437134012608153839509568180932141956418490735813975334167480468751", 0x3ddd9b66c974bb14u},
|
||||
{"0.000000000107709773707743713401260815383950956818093214195641849073581297533416748046875", 0x3ddd9b66c974bb13u},
|
||||
{"0.012083347821554271152300064073870089487172663211822509765625", 0x3f88bf277dc215f4u},
|
||||
{"0.0120833478215542711523000640738700894871726632118225097656251", 0x3f88bf277dc215f5u},
|
||||
{"0.01208334782155427115230006407387008948717266321182250976562499", 0x3f88bf277dc215f4u},
|
||||
{"2309804058391724800", 0x43c0070946d098e2u},
|
||||
{"23098040583917248001", 0x43f408cb9884bf1au},
|
||||
{"2309804058391724799.999999999999999999999999999999999999999999", 0x43c0070946d098e1u},
|
||||
{"0.000000000078286047058220682019445698291671103911937290575906445155851542949676513671875", 0x3dd584e40ca80638u},
|
||||
{"0.0000000000782860470582206820194456982916711039119372905759064451558515429496765136718751", 0x3dd584e40ca80638u},
|
||||
{"0.000000000078286047058220682019445698291671103911937290575906445155851532949676513671875", 0x3dd584e40ca80637u},
|
||||
{"2940024994425.709228515625", 0x4285643929d3cdacu},
|
||||
{"2940024994425.7092285156251", 0x4285643929d3cdadu},
|
||||
{"2940024994425.709228515624999999999999999999999999999999999999", 0x4285643929d3cdacu},
|
||||
{"9503358.427352792583405971527099609375", 0x4162204fcdacdfc4u},
|
||||
{"9503358.4273527925834059715270996093751", 0x4162204fcdacdfc4u},
|
||||
{"9503358.427352792583405971527099609374999999999999999999999999", 0x4162204fcdacdfc3u},
|
||||
{"0.00005589147834433423614399101542193903924271580763161182403564453125", 0x3f0d4da092aa5d6au},
|
||||
{"0.000055891478344334236143991015421939039242715807631611824035644531251", 0x3f0d4da092aa5d6bu},
|
||||
{"0.00005589147834433423614399101542193903924271580763161182403564452125", 0x3f0d4da092aa5d6au},
|
||||
{"0.0000000164797038506435664295103900420409737126448135313694365322589874267578125", 0x3e51b1e8107bd640u},
|
||||
{"0.00000001647970385064356642951039004204097371264481353136943653225898742675781251", 0x3e51b1e8107bd641u},
|
||||
{"0.0000000164797038506435664295103900420409737126448135313694365322589774267578125", 0x3e51b1e8107bd640u},
|
||||
{"73055.7873927834807545877993106842041015625", 0x40f1d5fc99292ce2u},
|
||||
{"73055.78739278348075458779931068420410156251", 0x40f1d5fc99292ce3u},
|
||||
{"73055.78739278348075458779931068420410156249999999999999999999", 0x40f1d5fc99292ce2u},
|
||||
{"0.00000000002558172364455232122427880575336067736115508441940846751094795763492584228515625", 0x3dbc209d7509115au},
|
||||
{"0.000000000025581723644552321224278805753360677361155084419408467510947957634925842285156251", 0x3dbc209d7509115bu},
|
||||
{"0.00000000002558172364455232122427880575336067736115508441940846751094794763492584228515625", 0x3dbc209d7509115au},
|
||||
{"0.000000000854497507560657937804791333430312443020238077906469698064029216766357421875", 0x3e0d5c3d540cc0d2u},
|
||||
{"0.0000000008544975075606579378047913334303124430202380779064696980640292167663574218751", 0x3e0d5c3d540cc0d2u},
|
||||
{"0.000000000854497507560657937804791333430312443020238077906469698064029116766357421875", 0x3e0d5c3d540cc0d1u},
|
||||
{"26671499731071461376", 0x43f722433b19970eu},
|
||||
{"266714997310714613761", 0x442cead409dffcd2u},
|
||||
{"26671499731071461375.99999999999999999999999999999999999999999", 0x43f722433b19970eu},
|
||||
{"0.0000000002725195963972150049060368088050545186395989816219298518262803554534912109375", 0x3df2ba37271cf5f2u},
|
||||
{"0.00000000027251959639721500490603680880505451863959898162192985182628035545349121093751", 0x3df2ba37271cf5f2u},
|
||||
{"0.0000000002725195963972150049060368088050545186395989816219298518262802554534912109375", 0x3df2ba37271cf5f1u},
|
||||
{"0.0000000000377224663702246439557904325637937886957218314165629635681398212909698486328125", 0x3dc4bcf7157af68eu},
|
||||
{"0.00000000003772246637022464395579043256379378869572183141656296356813982129096984863281251", 0x3dc4bcf7157af68fu},
|
||||
{"0.0000000000377224663702246439557904325637937886957218314165629635681398112909698486328125", 0x3dc4bcf7157af68eu},
|
||||
{"0.00000000000000009977342762593364154535842258994910996905560208471673566688053824691451154649257659912109375", 0x3c9cc1fac312e2a6u},
|
||||
{"0.000000000000000099773427625933641545358422589949109969055602084716735666880538246914511546492576599121093751", 0x3c9cc1fac312e2a6u},
|
||||
{"0.00000000000000009977342762593364154535842258994910996905560208471673566688052824691451154649257659912109375", 0x3c9cc1fac312e2a5u},
|
||||
{"0.0000000003146248171139977444431948290159907662133509376189977047033607959747314453125", 0x3df59ef03588a228u},
|
||||
{"0.00000000031462481711399774444319482901599076621335093761899770470336079597473144531251", 0x3df59ef03588a229u},
|
||||
{"0.0000000003146248171139977444431948290159907662133509376189977047033606959747314453125", 0x3df59ef03588a228u},
|
||||
{"488899209263030304", 0x439b23acf64c5e80u},
|
||||
{"4888992092630303041", 0x43d0f64c19efbb10u},
|
||||
{"488899209263030303.9999999999999999999999999999999999999999999", 0x439b23acf64c5e80u},
|
||||
{"1.88357157350592807620870416940306313335895538330078125", 0x3ffe231bf23e21acu},
|
||||
{"1.883571573505928076208704169403063133358955383300781251", 0x3ffe231bf23e21adu},
|
||||
{"1.883571573505928076208704169403063133358955383300781249999999", 0x3ffe231bf23e21acu},
|
||||
{"0.0000000216458400594294836451424756990254139044083103726734407246112823486328125", 0x3e573df694e72fb8u},
|
||||
{"0.00000002164584005942948364514247569902541390440831037267344072461128234863281251", 0x3e573df694e72fb9u},
|
||||
{"0.0000000216458400594294836451424756990254139044083103726734407246112723486328125", 0x3e573df694e72fb8u},
|
||||
{"5107.79271041116453488939441740512847900390625", 0x40b3f3caef11cb26u},
|
||||
{"5107.792710411164534889394417405128479003906251", 0x40b3f3caef11cb27u},
|
||||
{"5107.792710411164534889394417405128479003906249999999999999999", 0x40b3f3caef11cb26u},
|
||||
{"734059.8035226609208621084690093994140625", 0x412666d79b67527cu},
|
||||
{"734059.80352266092086210846900939941406251", 0x412666d79b67527du},
|
||||
{"734059.8035226609208621084690093994140624999999999999999999999", 0x412666d79b67527cu},
|
||||
{"61431562016722684", 0x436b47f5c40021e0u},
|
||||
{"614315620167226841", 0x43a10cf99a80152cu},
|
||||
{"61431562016722683.99999999999999999999999999999999999999999999", 0x436b47f5c40021dfu},
|
||||
{"2.0060840449445034305853141631814651191234588623046875", 0x40000c75cab08326u},
|
||||
{"2.00608404494450343058531416318146511912345886230468751", 0x40000c75cab08326u},
|
||||
{"2.006084044944503430585314163181465119123458862304687499999999", 0x40000c75cab08325u},
|
||||
{"0.0000001760623599453036952716420489480075861621344301966018974781036376953125", 0x3e87a174e55262cau},
|
||||
{"0.00000017606235994530369527164204894800758616213443019660189747810363769531251", 0x3e87a174e55262cbu},
|
||||
{"0.0000001760623599453036952716420489480075861621344301966018974781035376953125", 0x3e87a174e55262cau},
|
||||
{"0.833085849636964581588216560703585855662822723388671875", 0x3feaa8a3a7de6fb6u},
|
||||
{"0.8330858496369645815882165607035858556628227233886718751", 0x3feaa8a3a7de6fb6u},
|
||||
{"0.8330858496369645815882165607035858556628227233886718749999999", 0x3feaa8a3a7de6fb5u},
|
||||
{"45031428.4182307310402393341064453125", 0x418579002358895au},
|
||||
{"45031428.41823073104023933410644531251", 0x418579002358895bu},
|
||||
{"45031428.41823073104023933410644531249999999999999999999999999", 0x418579002358895au},
|
||||
{"5003361733758455296", 0x43d15be0bf39dd24u},
|
||||
{"50033617337584552961", 0x4405b2d8ef08546cu},
|
||||
{"5003361733758455295.999999999999999999999999999999999999999999", 0x43d15be0bf39dd23u},
|
||||
};
|
||||
|
||||
for (const auto& c : known)
|
||||
{
|
||||
CAPTURE(c.first);
|
||||
double out = 0;
|
||||
if (eisel_lemire(c.first, out))
|
||||
{
|
||||
CHECK(bits_of(out) == c.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// only tokens with more than 19 significant digits are left to
|
||||
// strtod: those whose value lies too close to a tie
|
||||
CHECK(significant_digits(c.first) > 19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("round trip")
|
||||
{
|
||||
// every double written by to_chars and read back, also with trailing
|
||||
// digits that make the token longer than 19 digits
|
||||
std::uint64_t state = 5295;
|
||||
std::size_t declined = 0;
|
||||
for (int i = 0; i < 200000; ++i)
|
||||
{
|
||||
state ^= state << 13u;
|
||||
state ^= state >> 7u;
|
||||
state ^= state << 17u;
|
||||
std::uint64_t b = state;
|
||||
if ((b & 0x7FF0000000000000u) == 0x7FF0000000000000u)
|
||||
{
|
||||
continue; // infinity or NaN
|
||||
}
|
||||
if (i % 4 == 0)
|
||||
{
|
||||
b &= 0x800FFFFFFFFFFFFFu; // subnormals
|
||||
}
|
||||
double d = 0;
|
||||
std::memcpy(&d, &b, sizeof(d));
|
||||
|
||||
std::array<char, 64> buffer{};
|
||||
const char* end = nlohmann::detail::to_chars(buffer.data(), buffer.data() + buffer.size(), d);
|
||||
const std::string token(buffer.data(), static_cast<std::size_t>(end - buffer.data()));
|
||||
CAPTURE(token);
|
||||
double out = 0;
|
||||
REQUIRE(eisel_lemire(token, out));
|
||||
CHECK(bits_of(out) == b);
|
||||
|
||||
// insert digits before the exponent: the value moves by far less
|
||||
// than the distance to the rounding boundary, so it must not change
|
||||
std::string longer = token;
|
||||
const std::size_t e = longer.find('e');
|
||||
const std::size_t dot = longer.find('.');
|
||||
const std::string extra = dot == std::string::npos ? ".000000000000000000001" : "000000000000000000001";
|
||||
longer.insert(e == std::string::npos ? longer.size() : e, extra);
|
||||
CAPTURE(longer);
|
||||
if (eisel_lemire(longer, out))
|
||||
{
|
||||
CHECK(bits_of(out) == b);
|
||||
}
|
||||
else
|
||||
{
|
||||
// w and w + 1 round differently: only when the value is very
|
||||
// close to a rounding boundary
|
||||
++declined;
|
||||
}
|
||||
}
|
||||
CHECK(declined < 1000); // 107 of the 200,000
|
||||
}
|
||||
|
||||
SECTION("used by the lexer")
|
||||
{
|
||||
// 17 significant digits: beyond Clinger's fast path
|
||||
CHECK(bits_of(json::parse("-65.613616999999977").get<double>()) == bits_of(-65.613616999999977));
|
||||
CHECK(bits_of(json::parse("2.2250738585072011e-308").get<double>()) == 0x000FFFFFFFFFFFFFu);
|
||||
CHECK(bits_of(json::parse("4.9406564584124654e-324").get<double>()) == 1u);
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse("1.7976931348623159e308"),
|
||||
"[json.exception.out_of_range.406] number overflow parsing '1.7976931348623159e308'", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -647,6 +647,30 @@ TEST_CASE("parser class")
|
||||
// carries a compiler-appended trailing '\0') still works,
|
||||
// even though a NUL byte is now rejected everywhere else
|
||||
CHECK(json::parse("123") == json(123));
|
||||
|
||||
// regression test for issue #5658: the same holds for wide,
|
||||
// UTF-16, UTF-32, and (C++20) UTF-8 string literals, whose
|
||||
// compiler-appended trailing '\0' is not of type `char`
|
||||
CHECK(json::parse(L"[1]") == json({1}));
|
||||
CHECK(json::accept(L"[1]"));
|
||||
CHECK(json::parse(u"[1]") == json({1}));
|
||||
CHECK(json::accept(u"[1]"));
|
||||
CHECK(json::parse(U"[1]") == json({1}));
|
||||
CHECK(json::accept(U"[1]"));
|
||||
#if defined(__cpp_char8_t)
|
||||
CHECK(json::parse(u8"[1]") == json({1}));
|
||||
CHECK(json::accept(u8"[1]"));
|
||||
#endif
|
||||
|
||||
// a NUL byte inside such a literal, as opposed to the single
|
||||
// compiler-appended trailing one, is still rejected
|
||||
{
|
||||
json _; // NOLINT(readability-identifier-naming)
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(L"[1\0]"),
|
||||
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - invalid literal; last read: '1<U+0000>'; expected ']'",
|
||||
json::parse_error&);
|
||||
CHECK_FALSE(json::accept(L"[1\0]"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1968,6 +1992,102 @@ TEST_CASE("parser class")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("no callback for the content of a discarded container (#5643)")
|
||||
{
|
||||
// discarding a container at its start event must also hide
|
||||
// everything inside it from the callback: none of the nested
|
||||
// keys, values, or nested containers' own start/end events may
|
||||
// be reported
|
||||
std::vector<std::string> log;
|
||||
bool first = true;
|
||||
const json j = json::parse(R"({"skip": {"k1": 1, "k2": [2, {"k3": 3}]}, "keep": 1})",
|
||||
[&](int depth, json::parse_event_t event, json & parsed)
|
||||
{
|
||||
static const char* const names[] = {"object_start", "object_end", "array_start", "array_end", "key", "value"};
|
||||
log.push_back(std::to_string(depth) + " " + names[static_cast<int>(event)] + " " + parsed.dump());
|
||||
|
||||
if (depth == 1 && event == json::parse_event_t::object_start && first)
|
||||
{
|
||||
// discard "skip" right at its object_start event
|
||||
first = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
CHECK(log == std::vector<std::string>
|
||||
{
|
||||
"0 object_start <discarded>",
|
||||
"1 key \"skip\"",
|
||||
"1 object_start <discarded>",
|
||||
"1 key \"keep\"",
|
||||
"1 value 1",
|
||||
"0 object_end {\"keep\":1}"
|
||||
});
|
||||
CHECK(j == json({{"keep", 1}}));
|
||||
}
|
||||
|
||||
SECTION("callback still called inside a container whose key was rejected (#5643)")
|
||||
{
|
||||
// rejecting a key does not discard its value's container at the
|
||||
// container's own start event, so the callback is still called
|
||||
// for that container's content; only storing the container
|
||||
// under the rejected key is skipped
|
||||
// (documented for parser_callback_t: "the callback is still
|
||||
// called for the associated value, but its return value has no
|
||||
// further effect")
|
||||
const auto record = [](std::vector<std::string>& log, int depth, json::parse_event_t event, const json & parsed)
|
||||
{
|
||||
static const char* const names[] = {"object_start", "object_end", "array_start", "array_end", "key", "value"};
|
||||
log.push_back(std::to_string(depth) + " " + names[static_cast<int>(event)] + " " + parsed.dump());
|
||||
};
|
||||
|
||||
std::vector<std::string> log_object;
|
||||
const json j_object = json::parse(R"({"skip": {"k1": 1}, "keep": 2})",
|
||||
[&](int depth, json::parse_event_t event, json & parsed)
|
||||
{
|
||||
record(log_object, depth, event, parsed);
|
||||
return !(event == json::parse_event_t::key && parsed == json("skip"));
|
||||
});
|
||||
|
||||
CHECK(log_object == std::vector<std::string>
|
||||
{
|
||||
"0 object_start <discarded>",
|
||||
"1 key \"skip\"",
|
||||
"1 object_start <discarded>",
|
||||
"2 key \"k1\"",
|
||||
"2 value 1",
|
||||
"1 key \"keep\"",
|
||||
"1 value 2",
|
||||
"0 object_end {\"keep\":2}"
|
||||
});
|
||||
CHECK(j_object == json({{"keep", 2}}));
|
||||
|
||||
// same for a rejected key whose value is an array rather than an object
|
||||
std::vector<std::string> log_array;
|
||||
const json j_array = json::parse(R"({"skip": [1, {"k1": 2}], "keep": 2})",
|
||||
[&](int depth, json::parse_event_t event, json & parsed)
|
||||
{
|
||||
record(log_array, depth, event, parsed);
|
||||
return !(event == json::parse_event_t::key && parsed == json("skip"));
|
||||
});
|
||||
|
||||
CHECK(log_array == std::vector<std::string>
|
||||
{
|
||||
"0 object_start <discarded>",
|
||||
"1 key \"skip\"",
|
||||
"1 array_start <discarded>",
|
||||
"2 value 1",
|
||||
"2 object_start <discarded>",
|
||||
"3 key \"k1\"",
|
||||
"3 value 2",
|
||||
"1 key \"keep\"",
|
||||
"1 value 2",
|
||||
"0 object_end {\"keep\":2}"
|
||||
});
|
||||
CHECK(j_array == json({{"keep", 2}}));
|
||||
}
|
||||
|
||||
SECTION("special cases")
|
||||
{
|
||||
// the following test cases cover the situation in which an empty
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -825,6 +826,24 @@ Json nest(Json j, const std::size_t depth)
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
// orders keys case-insensitively, so "key" and "KEY" compare equivalent
|
||||
// (neither less than the other) although they are not equal
|
||||
struct case_insensitive_less
|
||||
{
|
||||
bool operator()(const std::string& a, const std::string& b) const
|
||||
{
|
||||
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(),
|
||||
[](unsigned char x, unsigned char y)
|
||||
{
|
||||
return std::tolower(x) < std::tolower(y);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template<class Key, class Value, class /*Compare*/, class Allocator>
|
||||
using case_insensitive_map = std::map<Key, Value, case_insensitive_less, Allocator>;
|
||||
using ci_json = nlohmann::basic_json<case_insensitive_map>;
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("equality of objects whose entries have no fixed order")
|
||||
@@ -872,6 +891,33 @@ TEST_CASE("equality of objects whose entries have no fixed order")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("equality of an object whose comparator treats different keys as equivalent")
|
||||
{
|
||||
// https://github.com/nlohmann/json/issues/5655: past the nesting bound,
|
||||
// the entries are compared without the call stack, and a key that finds
|
||||
// no counterpart at the same position is looked up with find(), which
|
||||
// uses the object's own comparator. A case-insensitive comparator then
|
||||
// finds "KEY" for "key" and must not accept that pair as a match - the
|
||||
// object type's own operator==, like std::map's, compares keys with ==.
|
||||
ci_json a = ci_json::object();
|
||||
a["key"] = 1;
|
||||
ci_json b = ci_json::object();
|
||||
b["KEY"] = 1;
|
||||
|
||||
// sanity check: the object type's own comparison already disagrees
|
||||
CHECK_FALSE(a.get_ref<const ci_json::object_t&>() == b.get_ref<const ci_json::object_t&>());
|
||||
|
||||
for (const std::size_t depth : std::vector<std::size_t> {0, 127, 128, 200})
|
||||
{
|
||||
CAPTURE(depth);
|
||||
|
||||
const ci_json x = nest(a, depth);
|
||||
const ci_json y = nest(b, depth);
|
||||
CHECK_FALSE(x == y);
|
||||
CHECK(x != y);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("containers are compared element by element")
|
||||
{
|
||||
// Containers nested deeper than a bound are compared without the call
|
||||
|
||||
@@ -1648,6 +1648,20 @@ TEST_CASE("constructors")
|
||||
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
{
|
||||
json j = json::binary({1, 2, 3});
|
||||
CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
{
|
||||
json const j = json::binary({1, 2, 3});
|
||||
CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1358,6 +1358,14 @@ TEST_CASE("value conversion")
|
||||
CHECK(json(value_1).get<c_enum>() == value_1);
|
||||
CHECK(json(cpp_enum::value_1).get<cpp_enum>() == cpp_enum::value_1);
|
||||
}
|
||||
|
||||
SECTION("get an enum with underlying type bool (#5671)")
|
||||
{
|
||||
enum class bool_enum : bool { off, on };
|
||||
|
||||
CHECK(json(bool_enum::off).get<bool_enum>() == bool_enum::off);
|
||||
CHECK(json(bool_enum::on).get<bool_enum>() == bool_enum::on);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("more involved conversions")
|
||||
@@ -1740,6 +1748,12 @@ TEST_CASE("Strict JSON to enum mapping")
|
||||
|
||||
// conversion of unmapped enum -> exception thrown
|
||||
CHECK_THROWS_WITH_AS(json(strict_cards::andere), "[json.exception.out_of_range.410] enum value out of range for strict_cards", json::out_of_range&);
|
||||
|
||||
// invalid UTF-8 -> out_of_range.410, not the type_error.316 thrown while building the
|
||||
// message (regression test for #5667); such strings can reach get<Enum>() unvalidated,
|
||||
// e.g. from from_cbor()/from_msgpack() (#5529)
|
||||
const json j_invalid_utf8 = "\xFF";
|
||||
CHECK_THROWS_WITH_AS(_ = j_invalid_utf8.get<strict_cards>(), "[json.exception.out_of_range.410] enum value out of range for strict_cards: \"\xEF\xBF\xBD\"", json::out_of_range&);
|
||||
}
|
||||
|
||||
SECTION("traditional enum")
|
||||
@@ -1826,6 +1840,21 @@ TEST_CASE("std::u8string")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
namespace
|
||||
{
|
||||
// a type whose to_json reports an error by throwing, used below to check that
|
||||
// converting a std::optional<T> to JSON propagates an exception thrown while
|
||||
// converting its contained value instead of calling std::terminate (#5642)
|
||||
struct throwing_to_json_type {};
|
||||
|
||||
[[noreturn]] void to_json(json& /*unused*/, const throwing_to_json_type& /*unused*/)
|
||||
{
|
||||
throw std::runtime_error("cannot serialize throwing_to_json_type");
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
TEST_CASE("std::optional")
|
||||
{
|
||||
SECTION("null")
|
||||
@@ -1908,6 +1937,23 @@ TEST_CASE("std::optional")
|
||||
CHECK(json(opt_object) == j_object);
|
||||
CHECK(std::map<std::string, std::optional<int>>(j_object) == opt_object);
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
SECTION("exception from contained value's to_json propagates (#5642)")
|
||||
{
|
||||
// to_json(BasicJsonType&, const std::optional<T>&) must not be
|
||||
// noexcept: it calls T's to_json, which may throw (a user-defined
|
||||
// to_json that reports an error, or std::bad_alloc for T =
|
||||
// std::string/vector/json). Before the fix, this called
|
||||
// std::terminate() instead of letting the exception propagate.
|
||||
const std::optional<throwing_to_json_type> opt = throwing_to_json_type{};
|
||||
CHECK_THROWS_WITH_AS(json(opt), "cannot serialize throwing_to_json_type", std::runtime_error&);
|
||||
|
||||
// the conversion is noexcept exactly when converting the contained value is
|
||||
static_assert(!std::is_nothrow_constructible<json, const std::optional<throwing_to_json_type>&>::value, "");
|
||||
static_assert(std::is_nothrow_constructible<json, const std::optional<int>&>::value, "");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -117,6 +117,22 @@ TEST_CASE("array type without capacity()")
|
||||
CHECK(nested.flatten().unflatten() == nested);
|
||||
}
|
||||
|
||||
SECTION("insert(pos, initializer_list) compiles and works without reserve()")
|
||||
{
|
||||
// std::deque has no reserve() either; insert(pos, ilist) must not
|
||||
// require it (regression test for #5656, which also covers an ilist
|
||||
// that refers to elements of the array being inserted into)
|
||||
deque_json j = deque_json::array();
|
||||
j.push_back("a");
|
||||
j.push_back("b");
|
||||
j.push_back("c");
|
||||
|
||||
const deque_json& cj = j;
|
||||
auto it = j.insert(j.begin(), {cj[0], cj[1]});
|
||||
CHECK(*it == deque_json("a"));
|
||||
CHECK(j == deque_json({"a", "b", "a", "b", "c"}));
|
||||
}
|
||||
|
||||
SECTION("references stay valid while the array grows")
|
||||
{
|
||||
deque_json j = deque_json::array();
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
@@ -180,6 +182,76 @@ TEST_CASE("JSON Node Metadata")
|
||||
CHECK(val.metadata().at(1) == 2);
|
||||
}
|
||||
}
|
||||
SECTION("member swap")
|
||||
{
|
||||
using json = json_with_metadata<int>;
|
||||
json a = 1;
|
||||
a.metadata() = 100;
|
||||
json b = 2;
|
||||
b.metadata() = 200;
|
||||
|
||||
a.swap(b);
|
||||
|
||||
CHECK(a.get<int>() == 2);
|
||||
CHECK(b.get<int>() == 1);
|
||||
CHECK(a.metadata() == 200);
|
||||
CHECK(b.metadata() == 100);
|
||||
}
|
||||
SECTION("nonmember swap")
|
||||
{
|
||||
using json = json_with_metadata<int>;
|
||||
json a = 1;
|
||||
a.metadata() = 100;
|
||||
json b = 2;
|
||||
b.metadata() = 200;
|
||||
|
||||
using std::swap;
|
||||
swap(a, b);
|
||||
|
||||
CHECK(a.get<int>() == 2);
|
||||
CHECK(b.get<int>() == 1);
|
||||
CHECK(a.metadata() == 200);
|
||||
CHECK(b.metadata() == 100);
|
||||
}
|
||||
SECTION("std::swap")
|
||||
{
|
||||
using json = json_with_metadata<int>;
|
||||
json a = 1;
|
||||
a.metadata() = 100;
|
||||
json b = 2;
|
||||
b.metadata() = 200;
|
||||
|
||||
std::swap(a, b);
|
||||
|
||||
CHECK(a.get<int>() == 2);
|
||||
CHECK(b.get<int>() == 1);
|
||||
CHECK(a.metadata() == 200);
|
||||
CHECK(b.metadata() == 100);
|
||||
}
|
||||
SECTION("std::sort keeps metadata attached to its value")
|
||||
{
|
||||
// std::sort mixes swap() with moves; each value's metadata must
|
||||
// travel with it, just as it does for copy, move, and assignment
|
||||
using json = json_with_metadata<int>;
|
||||
std::vector<json> values;
|
||||
for (int v :
|
||||
{
|
||||
5, 3, 9, 1, 7, 2, 8, 4, 6, 0, 15, 13, 19, 11, 17, 12, 18, 14, 16, 10,
|
||||
25, 23, 29, 21, 27, 22, 28, 24, 26, 20, 35, 33
|
||||
})
|
||||
{
|
||||
json value = v;
|
||||
value.metadata() = v;
|
||||
values.push_back(value);
|
||||
}
|
||||
|
||||
std::sort(values.begin(), values.end());
|
||||
|
||||
for (const auto& value : values)
|
||||
{
|
||||
CHECK(value.metadata() == value.get<int>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test extending nlohmann::json by using a custom base class.
|
||||
|
||||
@@ -388,6 +388,37 @@ TEST_CASE("deserialization")
|
||||
}));
|
||||
}
|
||||
|
||||
SECTION("stream with eofbit in its exception mask (issue #5646)")
|
||||
{
|
||||
// reaching EOF while parsing a value that fills the whole input
|
||||
// (e.g., a number, or any value under strict parsing) makes
|
||||
// get_character() call std::istream::clear() to record eofbit;
|
||||
// with eofbit in the exception mask, that clear() itself throws
|
||||
// std::ios_base::failure - it must propagate to the caller instead
|
||||
// of ~input_stream_adapter() throwing a second exception while the
|
||||
// first is still unwinding, which would call std::terminate
|
||||
json _;
|
||||
|
||||
std::istringstream is1("1");
|
||||
is1.exceptions(std::ios::eofbit);
|
||||
CHECK_THROWS_AS(_ = json::parse(is1), std::ios_base::failure&);
|
||||
|
||||
// the same holds for the common std::ifstream::exceptions(failbit |
|
||||
// badbit | eofbit) pattern, because only eofbit ends up set
|
||||
std::istringstream is2("1");
|
||||
is2.exceptions(std::ios::failbit | std::ios::badbit | std::ios::eofbit);
|
||||
CHECK_THROWS_AS(_ = json::parse(is2), std::ios_base::failure&);
|
||||
}
|
||||
|
||||
SECTION("stream without a streambuf (issue #5646)")
|
||||
{
|
||||
// std::istream(nullptr) has badbit set and rdbuf() == nullptr;
|
||||
// get_character() must not dereference that null streambuf
|
||||
std::istream is(nullptr);
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(is), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json::string_t const s = R"(["foo",1,2,3,false,{"one":1})";
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
TEST_CASE("Better diagnostics")
|
||||
{
|
||||
SECTION("empty JSON Pointer")
|
||||
@@ -101,6 +104,12 @@ TEST_CASE("Regression tests for extended diagnostics")
|
||||
CHECK_THROWS_WITH_AS(j.unflatten(), "[json.exception.type_error.315] (/~1foo) values in object must be primitive", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #5675 - to_bson: out_of_range.415 has no diagnostics context")
|
||||
{
|
||||
json const j = {{"a", {{"b", json::binary({1, 2}, 300)}}}};
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.out_of_range.415] (/a/b) subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #2838 - Assertion failure when inserting into arrays with JSON_DIAGNOSTICS set")
|
||||
{
|
||||
// void push_back(basic_json&& val)
|
||||
@@ -331,6 +340,28 @@ TEST_CASE("Regression tests for extended diagnostics")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #5668 - wrong path for std::map/unordered_map with non-string keys")
|
||||
{
|
||||
// a map with non-string keys is read from an array of [key, value] arrays;
|
||||
// element 2 of "m" is not an array, so the path must point at "m/2", not "m"
|
||||
json j;
|
||||
j["outer"]["m"] = json::array({json::array({1, 2}), json::array({3, 4}), 5});
|
||||
|
||||
SECTION("std::map")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS((j["outer"]["m"].get<std::map<int, int>>()),
|
||||
"[json.exception.type_error.302] (/outer/m/2) type must be array, "
|
||||
"but is number", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS((j["outer"]["m"].get<std::unordered_map<int, int>>()),
|
||||
"[json.exception.type_error.302] (/outer/m/2) type must be array, "
|
||||
"but is number", json::type_error);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Regression test - swap(array_t&)/swap(object_t&) must update JSON_DIAGNOSTICS parent pointers")
|
||||
{
|
||||
// swap(array_t&)
|
||||
|
||||
@@ -46,6 +46,24 @@ TEST_CASE("Tests with disabled exceptions")
|
||||
CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'");
|
||||
delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
SECTION("growing an ordered_json object")
|
||||
{
|
||||
auto j = nlohmann::ordered_json::object();
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
j[std::to_string(i)] = {{"nested", i}};
|
||||
}
|
||||
|
||||
CHECK(j.size() == 100);
|
||||
int i = 0;
|
||||
for (const auto& element : j.items())
|
||||
{
|
||||
CHECK(element.key() == std::to_string(i));
|
||||
CHECK(element.value()["nested"] == i);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
|
||||
@@ -147,6 +147,24 @@ TEST_CASE("element access 1")
|
||||
CHECK(j_const[7] == json({1, 2, 3}));
|
||||
}
|
||||
|
||||
SECTION("SIZE_MAX index (#5647)")
|
||||
{
|
||||
// idx + 1 must not be computed for idx == SIZE_MAX: it wraps to 0,
|
||||
// which would empty the array and then write out of bounds instead
|
||||
// of growing it; reject it like an oversized resize() would and
|
||||
// leave the array unchanged
|
||||
const auto max_idx = (std::numeric_limits<json::size_type>::max)();
|
||||
const std::string expected = "array index " + std::to_string(max_idx) + " exceeds size_type";
|
||||
const json j_before = j; // NOLINT(performance-unnecessary-copy-initialization)
|
||||
|
||||
CHECK_THROWS_WITH_AS(j[max_idx] = 1, expected.c_str(), std::length_error&);
|
||||
CHECK(j == j_before);
|
||||
|
||||
json j_empty = json::array();
|
||||
CHECK_THROWS_WITH_AS(j_empty[max_idx] = 1, expected.c_str(), std::length_error&);
|
||||
CHECK(j_empty == json::array());
|
||||
}
|
||||
|
||||
SECTION("access on non-array type")
|
||||
{
|
||||
SECTION("null")
|
||||
|
||||
@@ -16,6 +16,40 @@
|
||||
// build test with C++14
|
||||
// JSON_HAS_CPP_14
|
||||
|
||||
// used to check at compile time (via is_detected) whether a call is well-formed; see
|
||||
// https://github.com/nlohmann/json/issues/5657
|
||||
//
|
||||
// note: an integer *literal* (rather than a std::declval<T>() of integral type T) is required to
|
||||
// reproduce the bug, because only a null pointer constant--an integer literal with value zero, not
|
||||
// merely a runtime value that happens to be zero--implicitly converts to a null const char*; that is
|
||||
// why can_call_*_with_0 below hard-code the literal 0 instead of taking it as a template argument
|
||||
template<typename BasicJsonType, typename T>
|
||||
using can_call_find = decltype(std::declval<BasicJsonType>().find(std::declval<T>()));
|
||||
|
||||
template<typename BasicJsonType, typename T>
|
||||
using can_call_count = decltype(std::declval<BasicJsonType>().count(std::declval<T>()));
|
||||
|
||||
template<typename BasicJsonType, typename T>
|
||||
using can_call_contains = decltype(std::declval<BasicJsonType>().contains(std::declval<T>()));
|
||||
|
||||
template<typename BasicJsonType, typename KeyType, typename ValueType>
|
||||
using can_call_value = decltype(std::declval<BasicJsonType>().value(std::declval<KeyType>(), std::declval<ValueType>()));
|
||||
|
||||
template<typename BasicJsonType>
|
||||
using can_call_find_with_0 = decltype(std::declval<BasicJsonType>().find(0));
|
||||
|
||||
template<typename BasicJsonType>
|
||||
using can_call_count_with_0 = decltype(std::declval<BasicJsonType>().count(0));
|
||||
|
||||
template<typename BasicJsonType>
|
||||
using can_call_contains_with_0 = decltype(std::declval<BasicJsonType>().contains(0));
|
||||
|
||||
template<typename BasicJsonType>
|
||||
using can_call_contains_with_0L = decltype(std::declval<BasicJsonType>().contains(0L));
|
||||
|
||||
template<typename BasicJsonType>
|
||||
using can_call_value_with_0 = decltype(std::declval<BasicJsonType>().value(0, 1));
|
||||
|
||||
TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_json) // NOLINT(readability-math-missing-parentheses, bugprone-throwing-static-initialization)
|
||||
{
|
||||
SECTION("object")
|
||||
@@ -1493,6 +1527,53 @@ TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_j
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("integral keys for object lookup are rejected at compile time")
|
||||
{
|
||||
// https://github.com/nlohmann/json/issues/5657: an integer literal like 0 is a null pointer
|
||||
// constant, which used to convert to a null const char* and from there--via undefined
|
||||
// behavior in the std::string constructor--to key_type, so contains(0), find(0), and
|
||||
// count(0) used to compile and then crash instead of failing to compile
|
||||
using nlohmann::detail::is_detected;
|
||||
|
||||
CHECK_FALSE(is_detected<can_call_find_with_0, Json&>::value);
|
||||
CHECK_FALSE(is_detected<can_call_find_with_0, const Json&>::value);
|
||||
CHECK_FALSE(is_detected<can_call_count_with_0, Json&>::value);
|
||||
CHECK_FALSE(is_detected<can_call_contains_with_0, Json&>::value);
|
||||
// value(0, ...) is only affected in C++11, where the comparator is not transparent; with a
|
||||
// transparent comparator (C++14 and later), int is already rejected for lacking a
|
||||
// comparison with the key type, independently of this fix
|
||||
CHECK_FALSE(is_detected<can_call_value_with_0, const Json&>::value);
|
||||
|
||||
// another integral literal type must be rejected as well, not just int
|
||||
CHECK_FALSE(is_detected<can_call_contains_with_0L, Json&>::value);
|
||||
|
||||
// the valid overloads must remain callable
|
||||
CHECK(is_detected<can_call_find, Json&, const char*>::value);
|
||||
CHECK(is_detected<can_call_find, Json&, std::string>::value);
|
||||
CHECK(is_detected<can_call_count, Json&, const char*>::value);
|
||||
CHECK(is_detected<can_call_contains, Json&, const char*>::value);
|
||||
CHECK(is_detected<can_call_contains, Json&, typename Json::json_pointer>::value);
|
||||
CHECK(is_detected<can_call_value, const Json&, const char*, int>::value);
|
||||
CHECK(is_detected<can_call_value, const Json&, typename Json::json_pointer, int>::value);
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
CHECK(is_detected<can_call_find, Json&, std::string_view>::value);
|
||||
CHECK(is_detected<can_call_count, Json&, std::string_view>::value);
|
||||
CHECK(is_detected<can_call_contains, Json&, std::string_view>::value);
|
||||
#endif
|
||||
|
||||
// the neighboring size_type overloads for array access are unaffected by the new
|
||||
// integral-key overloads above (at(), operator[](), and erase() take a size_type)
|
||||
Json arr = {10, 20, 30};
|
||||
const Json arr_const = arr;
|
||||
CHECK(arr.at(0) == 10);
|
||||
CHECK(arr_const.at(0) == 10);
|
||||
CHECK(arr[0] == 10);
|
||||
CHECK(arr_const[0] == 10);
|
||||
arr.erase(0);
|
||||
CHECK(arr.size() == 2);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
|
||||
@@ -1752,6 +1752,58 @@ TEST_CASE("JSON patch - diff emits array removals in descending index order")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JSON patch - diff() takes the fast path for non-reorderable object types (regression #5639)")
|
||||
{
|
||||
// #5465 added an order check to diff()'s object handling so a
|
||||
// member-by-member diff is only used when it would also reproduce
|
||||
// target's member *order* -- needed for ordered_json, whose object_t
|
||||
// keeps insertion order and whose patch() "add" op appends a new
|
||||
// member at the end. For json's default object_t (std::map, which
|
||||
// orders members by key regardless of insertion history), that check
|
||||
// could still fail: a new key that sorts before an existing common key
|
||||
// makes target's iteration interleave the new key between common keys,
|
||||
// even though nothing else about the object changed. That sent the
|
||||
// whole object through the slow (remove-every-member,
|
||||
// re-add-every-member) path instead of the minimal one.
|
||||
SECTION("json: added key sorts before an existing common key")
|
||||
{
|
||||
const json source = {{"a", 1}, {"c", {{"x", 1}, {"y", 2}}}};
|
||||
const json target = {{"a", 1}, {"b", 0}, {"c", {{"x", 1}, {"y", 2}}}};
|
||||
|
||||
const json patch = json::diff(source, target);
|
||||
|
||||
// only the new key is added; "a" and "c" are left alone instead of
|
||||
// being removed and re-added
|
||||
const json expected = R"([{"op": "add", "path": "/b", "value": 0}])"_json;
|
||||
CHECK(patch == expected);
|
||||
CHECK(source.patch(patch) == target);
|
||||
}
|
||||
|
||||
SECTION("ordered_json: reordering behavior from #5465 is unchanged")
|
||||
{
|
||||
using nlohmann::ordered_json;
|
||||
|
||||
// same key/value shape as the json case above, but for ordered_json
|
||||
// the *target*'s member order must be reproduced, so the slow path
|
||||
// is still required here.
|
||||
ordered_json source;
|
||||
source["a"] = 1;
|
||||
source["c"] = ordered_json{{"x", 1}, {"y", 2}};
|
||||
|
||||
ordered_json target;
|
||||
target["a"] = 1;
|
||||
target["b"] = 0;
|
||||
target["c"] = ordered_json{{"x", 1}, {"y", 2}};
|
||||
|
||||
const ordered_json patch = ordered_json::diff(source, target);
|
||||
|
||||
// unlike the json case: every member is still removed and re-added
|
||||
// so the result ends up in target's order (2 removes + 3 adds)
|
||||
CHECK(patch.size() == 5);
|
||||
CHECK(source.patch(patch) == target);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JSON patch - every operation on ordered_json")
|
||||
{
|
||||
using nlohmann::ordered_json;
|
||||
|
||||
@@ -380,6 +380,26 @@ TEST_CASE("JSON pointers")
|
||||
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
||||
|
||||
{
|
||||
// contains() must not throw for an empty reference token if the current
|
||||
// value is an array (cf. #5395) -- at() still reports out_of_range.404
|
||||
json j_nested = {{"a", {1, 2}}};
|
||||
const json& j_nested_const = j_nested;
|
||||
json::json_pointer const jp("/a/");
|
||||
std::string const throw_msg = "[json.exception.out_of_range.404] unresolved reference token ''";
|
||||
|
||||
CHECK_THROWS_WITH_AS(j_nested.at(jp), throw_msg.c_str(), json::out_of_range&);
|
||||
CHECK_THROWS_WITH_AS(j_nested_const.at(jp), throw_msg.c_str(), json::out_of_range&);
|
||||
|
||||
CHECK(j_nested.contains(json::json_pointer("/a/1")));
|
||||
CHECK(!j_nested.contains(jp));
|
||||
CHECK(!j_nested_const.contains(jp));
|
||||
|
||||
// same for an empty reference token on a top-level array
|
||||
CHECK(!j.contains(json::json_pointer("/")));
|
||||
CHECK(!j_const.contains(json::json_pointer("/")));
|
||||
}
|
||||
|
||||
CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1,
|
||||
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&);
|
||||
CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1,
|
||||
@@ -858,6 +878,25 @@ TEST_CASE("JSON pointers")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("value(json_pointer, default) with ordered_json #5664")
|
||||
{
|
||||
// ordered_json's transparent object comparator made value()'s
|
||||
// is_comparable_with_object_key check (which passes the pointer as
|
||||
// a reference) instantiate the deprecated json_pointer/string
|
||||
// comparison; this must compile without relying on it. The
|
||||
// deprecation warning itself is not observable here, since the
|
||||
// unit test build disables -Wdeprecated-declarations (see
|
||||
// cmake/clang_flags.cmake); it was checked manually instead.
|
||||
const nlohmann::ordered_json j = {{"n", 1}, {"s", "text"}};
|
||||
const nlohmann::ordered_json::json_pointer ptr_n("/n");
|
||||
const nlohmann::ordered_json::json_pointer ptr_s("/s");
|
||||
const nlohmann::ordered_json::json_pointer ptr_missing("/missing");
|
||||
|
||||
CHECK(j.value(ptr_n, 0) == 1);
|
||||
CHECK(j.value(ptr_s, std::string("x")) == "text");
|
||||
CHECK(j.value(ptr_missing, 42) == 42);
|
||||
}
|
||||
|
||||
// build with C++20
|
||||
// JSON_HAS_CPP_20
|
||||
#if defined(__cpp_char8_t)
|
||||
|
||||
@@ -155,6 +155,18 @@ TEST_CASE("modifiers")
|
||||
CHECK(j == json(json::value_t::binary));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
|
||||
SECTION("filled binary with subtype")
|
||||
{
|
||||
json j = json::binary({1, 2, 3, 4, 5}, 42);
|
||||
json const k = j;
|
||||
|
||||
j.clear();
|
||||
CHECK(!j.empty());
|
||||
CHECK(!j.get_binary().has_subtype());
|
||||
CHECK(j == json(json::value_t::binary));
|
||||
CHECK(j == json(k.type()));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number (integer)")
|
||||
@@ -761,6 +773,34 @@ TEST_CASE("modifiers")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("initializer list referring to the array's own elements (#5656)")
|
||||
{
|
||||
SECTION("sufficient capacity (no reallocation)")
|
||||
{
|
||||
json j_own = json::array();
|
||||
j_own.get_ref<json::array_t&>().reserve(8);
|
||||
j_own.push_back("a");
|
||||
j_own.push_back("b");
|
||||
j_own.push_back("c");
|
||||
|
||||
const json& j_own_cref = j_own;
|
||||
auto it = j_own.insert(j_own.begin(), {j_own_cref[0], j_own_cref[1]});
|
||||
CHECK(*it == json("a"));
|
||||
CHECK(j_own == json({"a", "b", "a", "b", "c"}));
|
||||
}
|
||||
|
||||
SECTION("insufficient capacity (reallocation)")
|
||||
{
|
||||
json j_own = {"a", "b", "c"};
|
||||
j_own.get_ref<json::array_t&>().shrink_to_fit();
|
||||
|
||||
const json& j_own_cref = j_own;
|
||||
auto it = j_own.insert(j_own.begin(), {j_own_cref[2]});
|
||||
CHECK(*it == json("c"));
|
||||
CHECK(j_own == json({"c", "a", "b", "c"}));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("invalid iterator")
|
||||
{
|
||||
// pass iterator to a different array
|
||||
|
||||
@@ -2475,3 +2475,60 @@ TEST_CASE("MessagePack lengths beyond UINT32_MAX cannot be serialized")
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MessagePack numbers use the active union member (see #5644)")
|
||||
{
|
||||
// when number_integer_t is narrower than number_unsigned_t, to_msgpack()
|
||||
// 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
|
||||
// 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 int16_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int16_t, std::uint64_t, double>;
|
||||
|
||||
SECTION("number_integer_t = std::int32_t")
|
||||
{
|
||||
SECTION("6442450944 (uint 64; the low 32 bits used to be sign-extended)")
|
||||
{
|
||||
const int32_json j = 6442450944ULL;
|
||||
CHECK(j.is_number_unsigned());
|
||||
|
||||
std::vector<uint8_t> const expected{0xcf, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00};
|
||||
const auto result = int32_json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(int32_json::from_msgpack(result) == j);
|
||||
}
|
||||
|
||||
SECTION("4294967496 (uint 64; the low 32 bits used to be the whole value)")
|
||||
{
|
||||
const int32_json j = 4294967496ULL;
|
||||
CHECK(j.is_number_unsigned());
|
||||
|
||||
std::vector<uint8_t> const expected{0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc8};
|
||||
const auto result = int32_json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(int32_json::from_msgpack(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number_integer_t = std::int16_t, 98304 (uint 32)")
|
||||
{
|
||||
const int16_json j = 98304ULL;
|
||||
CHECK(j.is_number_unsigned());
|
||||
|
||||
std::vector<uint8_t> const expected{0xce, 0x00, 0x01, 0x80, 0x00};
|
||||
const auto result = int16_json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(int16_json::from_msgpack(result) == j);
|
||||
}
|
||||
|
||||
SECTION("default types (std::int64_t/std::uint64_t) are unaffected")
|
||||
{
|
||||
const json j = 4294967496ULL;
|
||||
CHECK(j.is_number_unsigned());
|
||||
|
||||
std::vector<uint8_t> const expected{0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc8};
|
||||
const auto result = json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(json::from_msgpack(result) == j);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// This translation unit checks JSON_NO_AUTOMATIC_UDLS, which keeps
|
||||
// <nlohmann/json.hpp> from including <nlohmann/json_literals.hpp> and thereby
|
||||
// leaves out the user-defined string literals operator""_json and
|
||||
// operator""_json_pointer (see #5294), and that including
|
||||
// <nlohmann/json_literals.hpp> afterwards brings them back.
|
||||
#define JSON_NO_AUTOMATIC_UDLS 1
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
// An argument type whose associated namespace is the library namespace, so
|
||||
// argument-dependent lookup of a literal operator called by its function name
|
||||
// also searches the inline namespaces nlohmann::literals::json_literals.
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
struct no_automatic_udls_probe
|
||||
{
|
||||
operator const char* () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
namespace
|
||||
{
|
||||
// The calls below use a dependent argument, so a literal operator that is not
|
||||
// declared at all is a substitution failure rather than a hard error: lookup is
|
||||
// deferred to the point of instantiation, where it considers the declarations
|
||||
// visible from here (the global using-declarations of JSON_USE_GLOBAL_UDLS) plus
|
||||
// argument-dependent lookup (the literals in the library namespace).
|
||||
#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
|
||||
template<typename T>
|
||||
using json_udl_t = decltype(operator""_json(std::declval<T>(), std::size_t()));
|
||||
|
||||
template<typename T>
|
||||
using json_pointer_udl_t = decltype(operator""_json_pointer(std::declval<T>(), std::size_t()));
|
||||
#else
|
||||
// GCC 4.8 requires a space between "" and suffix
|
||||
template<typename T>
|
||||
using json_udl_t = decltype(operator"" _json(std::declval<T>(), std::size_t()));
|
||||
|
||||
template<typename T>
|
||||
using json_pointer_udl_t = decltype(operator"" _json_pointer(std::declval<T>(), std::size_t()));
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
using has_json_udl = nlohmann::detail::is_detected<json_udl_t, T>;
|
||||
|
||||
template<typename T>
|
||||
using has_json_pointer_udl = nlohmann::detail::is_detected<json_pointer_udl_t, T>;
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("JSON_NO_AUTOMATIC_UDLS")
|
||||
{
|
||||
SECTION("literals are not declared")
|
||||
{
|
||||
// global namespace (JSON_USE_GLOBAL_UDLS defaults to 1)
|
||||
CHECK_FALSE(has_json_udl<const char*>::value);
|
||||
CHECK_FALSE(has_json_pointer_udl<const char*>::value);
|
||||
|
||||
// nlohmann::literals::json_literals
|
||||
CHECK_FALSE(has_json_udl<nlohmann::no_automatic_udls_probe>::value);
|
||||
CHECK_FALSE(has_json_pointer_udl<nlohmann::no_automatic_udls_probe>::value);
|
||||
}
|
||||
|
||||
SECTION("the rest of the library keeps working")
|
||||
{
|
||||
const json j = json::parse(R"({"foo": {"bar": 42}})");
|
||||
CHECK(j.dump() == R"({"foo":{"bar":42}})");
|
||||
|
||||
const json::json_pointer ptr("/foo/bar");
|
||||
CHECK(j.at(ptr) == 42);
|
||||
CHECK(j.contains(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
// the literals can still be added where they are needed
|
||||
#include <nlohmann/json_literals.hpp>
|
||||
|
||||
TEST_CASE("JSON_NO_AUTOMATIC_UDLS with <nlohmann/json_literals.hpp>")
|
||||
{
|
||||
#if !defined(JSON_USE_GLOBAL_UDLS) || JSON_USE_GLOBAL_UDLS
|
||||
SECTION("global namespace")
|
||||
{
|
||||
CHECK("[1,2]"_json == json({1, 2}));
|
||||
CHECK("/a/0"_json_pointer == json::json_pointer("/a/0"));
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("nlohmann::literals::json_literals")
|
||||
{
|
||||
using namespace nlohmann::literals::json_literals; // NOLINT(google-build-using-namespace)
|
||||
CHECK(R"({"a":[42]})"_json.at("/a/0"_json_pointer) == 42);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,97 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::ordered_map;
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// The EDG front end (Intel icpc, NVIDIA nvc++) considers the defaulted move
|
||||
// constructor of std::pair<const Key, T> noexcept even if copying Key can
|
||||
// throw. std::vector then moves such elements itself when it grows (and calls
|
||||
// std::terminate if a key copy throws), so ordered_map leaves growing to it.
|
||||
#if defined(__EDG__)
|
||||
#define JSON_TEST_PAIR_MOVE_IS_NOEXCEPT
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
// number of copies made of counted values
|
||||
int value_copies = 0;
|
||||
|
||||
// a mapped type that counts its copies; moving from it leaves -1 behind
|
||||
struct counted // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
{
|
||||
int payload = 0;
|
||||
|
||||
counted() = default;
|
||||
explicit counted(int p) noexcept : payload(p) {}
|
||||
counted(const counted& other) : payload(other.payload)
|
||||
{
|
||||
++value_copies;
|
||||
}
|
||||
counted(counted&& other) noexcept : payload(other.payload)
|
||||
{
|
||||
other.payload = -1;
|
||||
}
|
||||
counted& operator=(const counted&) = delete;
|
||||
counted& operator=(counted&& other) noexcept
|
||||
{
|
||||
payload = other.payload;
|
||||
other.payload = -1;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION) && !defined(JSON_TEST_PAIR_MOVE_IS_NOEXCEPT)
|
||||
// number of throwing_key copies that still succeed; the next one throws
|
||||
// (a negative value means that copies never throw)
|
||||
int key_copies_until_throw = -1;
|
||||
|
||||
// a key type whose copy constructor can be made to throw
|
||||
struct throwing_key // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
explicit throwing_key(int i) noexcept : id(i) {}
|
||||
throwing_key(const throwing_key& other) : id(other.id)
|
||||
{
|
||||
if (key_copies_until_throw == 0)
|
||||
{
|
||||
throw std::runtime_error("key copy failed");
|
||||
}
|
||||
if (key_copies_until_throw > 0)
|
||||
{
|
||||
--key_copies_until_throw;
|
||||
}
|
||||
}
|
||||
throwing_key& operator=(const throwing_key&) = delete;
|
||||
|
||||
friend bool operator==(const throwing_key& lhs, const throwing_key& rhs) noexcept
|
||||
{
|
||||
return lhs.id == rhs.id;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// a mapped type that cannot be default-constructed
|
||||
struct no_default
|
||||
{
|
||||
explicit no_default(int v) noexcept : value(v) {}
|
||||
int value;
|
||||
};
|
||||
|
||||
// ordered_json must keep moving its values when an object grows
|
||||
using ordered_object_t = nlohmann::ordered_json::object_t;
|
||||
#if !defined(JSON_TEST_PAIR_MOVE_IS_NOEXCEPT)
|
||||
static_assert(!std::is_nothrow_move_constructible<ordered_object_t::value_type>::value, "std::vector would move the elements itself");
|
||||
#endif
|
||||
static_assert(std::is_copy_constructible<ordered_object_t::key_type>::value, "keys must be copyable");
|
||||
static_assert(std::is_default_constructible<ordered_object_t::mapped_type>::value, "values must be default-constructible");
|
||||
static_assert(std::is_nothrow_move_assignable<ordered_object_t::mapped_type>::value, "values must be nothrow move-assignable");
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("ordered_map")
|
||||
{
|
||||
SECTION("constructor")
|
||||
@@ -313,3 +404,270 @@ TEST_CASE("ordered_map")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("ordered_map growth")
|
||||
{
|
||||
SECTION("values are moved, not copied, when the storage grows")
|
||||
{
|
||||
ordered_map<std::string, counted> om;
|
||||
std::size_t growths = 0;
|
||||
value_copies = 0;
|
||||
|
||||
// inserts 100 elements with the given function and counts the growths
|
||||
const auto fill = [&om, &growths](void (*insert)(ordered_map<std::string, counted>&, int))
|
||||
{
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
const auto old_capacity = om.capacity();
|
||||
insert(om, i);
|
||||
if (om.capacity() > old_capacity)
|
||||
{
|
||||
++growths;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// checks that the elements are in insertion order with their values
|
||||
const auto check_contents = [&om]
|
||||
{
|
||||
CHECK(om.size() == 100);
|
||||
int i = 0;
|
||||
for (const auto& element : om)
|
||||
{
|
||||
CHECK(element.first == std::to_string(i));
|
||||
CHECK(element.second.payload == i);
|
||||
++i;
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("emplace")
|
||||
{
|
||||
fill([](ordered_map<std::string, counted>& m, int i)
|
||||
{
|
||||
m.emplace(std::to_string(i), counted(i));
|
||||
});
|
||||
CHECK(growths >= 3);
|
||||
CHECK(value_copies == 0);
|
||||
check_contents();
|
||||
}
|
||||
|
||||
SECTION("operator[]")
|
||||
{
|
||||
fill([](ordered_map<std::string, counted>& m, int i)
|
||||
{
|
||||
m[std::to_string(i)] = counted(i);
|
||||
});
|
||||
CHECK(growths >= 3);
|
||||
CHECK(value_copies == 0);
|
||||
check_contents();
|
||||
}
|
||||
|
||||
SECTION("insert(value_type&&)")
|
||||
{
|
||||
fill([](ordered_map<std::string, counted>& m, int i)
|
||||
{
|
||||
m.insert({std::to_string(i), counted(i)});
|
||||
});
|
||||
CHECK(growths >= 3);
|
||||
CHECK(value_copies == 0);
|
||||
check_contents();
|
||||
}
|
||||
|
||||
SECTION("insert(const value_type&)")
|
||||
{
|
||||
fill([](ordered_map<std::string, counted>& m, int i)
|
||||
{
|
||||
const std::pair<const std::string, counted> value(std::to_string(i), counted(i));
|
||||
m.insert(value);
|
||||
});
|
||||
CHECK(growths >= 3);
|
||||
// only the inserted values are copied
|
||||
CHECK(value_copies == 100);
|
||||
check_contents();
|
||||
}
|
||||
|
||||
SECTION("insert(first, last)")
|
||||
{
|
||||
std::vector<std::pair<const std::string, counted>> values;
|
||||
values.reserve(100);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
values.emplace_back(std::to_string(i), counted(i));
|
||||
}
|
||||
value_copies = 0;
|
||||
|
||||
om.insert(values.cbegin(), values.cend());
|
||||
// only the inserted values are copied
|
||||
CHECK(value_copies == 100);
|
||||
check_contents();
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("elements keep their order and values over many growths")
|
||||
{
|
||||
ordered_map<std::string, counted> om;
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
{
|
||||
om.emplace(std::to_string(i), counted(i));
|
||||
}
|
||||
|
||||
CHECK(om.size() == 1000);
|
||||
int i = 0;
|
||||
for (const auto& element : om)
|
||||
{
|
||||
CHECK(element.first == std::to_string(i));
|
||||
CHECK(element.second.payload == i);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("arguments may refer to elements of the full container")
|
||||
{
|
||||
SECTION("moving a value out of the container")
|
||||
{
|
||||
ordered_map<std::string, counted> om;
|
||||
om.reserve(4);
|
||||
while (om.size() < om.capacity())
|
||||
{
|
||||
const auto i = static_cast<int>(om.size());
|
||||
om.emplace(std::to_string(i), counted(i));
|
||||
}
|
||||
const auto size = om.size();
|
||||
|
||||
om.emplace("new", std::move(om.at("0")));
|
||||
CHECK(om.size() == size + 1);
|
||||
CHECK(om.at("new").payload == 0);
|
||||
CHECK(om.at("0").payload == -1);
|
||||
}
|
||||
|
||||
SECTION("using a value as key")
|
||||
{
|
||||
ordered_map<std::string, std::string> om;
|
||||
om.reserve(4);
|
||||
while (om.size() < om.capacity())
|
||||
{
|
||||
const auto i = std::to_string(om.size());
|
||||
om.emplace("k" + i, "v" + i);
|
||||
}
|
||||
const auto size = om.size();
|
||||
|
||||
om.emplace(om.at("k0"), std::string("x"));
|
||||
CHECK(om.size() == size + 1);
|
||||
CHECK(om.at("k0") == "v0");
|
||||
CHECK(om.at("v0") == "x");
|
||||
}
|
||||
|
||||
SECTION("ordered_json")
|
||||
{
|
||||
auto j = nlohmann::ordered_json::object();
|
||||
auto& object = j.get_ref<nlohmann::ordered_json::object_t&>();
|
||||
object.reserve(4);
|
||||
while (object.size() < object.capacity())
|
||||
{
|
||||
const auto i = std::to_string(object.size());
|
||||
j[i] = "a value that is too long for the small string optimization " + i;
|
||||
}
|
||||
const auto size = j.size();
|
||||
|
||||
j.emplace("new", std::move(j["0"]));
|
||||
CHECK(j.size() == size + 1);
|
||||
CHECK(j["new"] == "a value that is too long for the small string optimization 0");
|
||||
CHECK(j["0"].is_null());
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION) && !defined(JSON_TEST_PAIR_MOVE_IS_NOEXCEPT)
|
||||
SECTION("the container is unchanged if growing it throws")
|
||||
{
|
||||
ordered_map<throwing_key, counted> om;
|
||||
om.reserve(4);
|
||||
while (om.size() < om.capacity())
|
||||
{
|
||||
const auto i = static_cast<int>(om.size());
|
||||
om.emplace(throwing_key(i), counted(i));
|
||||
}
|
||||
const auto size = om.size();
|
||||
const auto capacity = om.capacity();
|
||||
|
||||
// checks that the elements are unchanged
|
||||
const auto check_unchanged = [&om, size, capacity]
|
||||
{
|
||||
CHECK(om.size() == size);
|
||||
CHECK(om.capacity() == capacity);
|
||||
int i = 0;
|
||||
for (const auto& element : om)
|
||||
{
|
||||
CHECK(element.first.id == i);
|
||||
CHECK(element.second.payload == i);
|
||||
++i;
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("emplace")
|
||||
{
|
||||
// growing copies the existing keys and then the new one; let each of these copies throw
|
||||
for (std::size_t k = 0; k <= size; ++k)
|
||||
{
|
||||
counted value(100);
|
||||
key_copies_until_throw = static_cast<int>(k);
|
||||
CHECK_THROWS_AS(om.emplace(throwing_key(100), std::move(value)), std::runtime_error);
|
||||
key_copies_until_throw = -1;
|
||||
|
||||
check_unchanged();
|
||||
CHECK(value.payload == 100); // NOLINT(bugprone-use-after-move,hicpp-invalid-access-moved)
|
||||
}
|
||||
|
||||
om.emplace(throwing_key(100), counted(100));
|
||||
CHECK(om.size() == size + 1);
|
||||
CHECK(om.capacity() > capacity);
|
||||
CHECK(om.at(throwing_key(100)).payload == 100);
|
||||
}
|
||||
|
||||
SECTION("insert(const value_type&)")
|
||||
{
|
||||
const std::pair<const throwing_key, counted> value(throwing_key(100), counted(100));
|
||||
value_copies = 0;
|
||||
|
||||
key_copies_until_throw = static_cast<int>(size / 2);
|
||||
CHECK_THROWS_AS(om.insert(value), std::runtime_error);
|
||||
key_copies_until_throw = -1;
|
||||
|
||||
check_unchanged();
|
||||
CHECK(value_copies == 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("elements that std::vector moves, or that cannot be moved back")
|
||||
{
|
||||
SECTION("nothrow move-constructible elements")
|
||||
{
|
||||
ordered_map<int, counted> om;
|
||||
value_copies = 0;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
om.emplace(i, counted(i));
|
||||
}
|
||||
CHECK(om.size() == 100);
|
||||
CHECK(value_copies == 0);
|
||||
}
|
||||
|
||||
SECTION("mapped type without default constructor")
|
||||
{
|
||||
ordered_map<std::string, no_default> om;
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
om.emplace(std::to_string(i), no_default(i));
|
||||
}
|
||||
|
||||
CHECK(om.size() == 100);
|
||||
int i = 0;
|
||||
for (const auto& element : om)
|
||||
{
|
||||
CHECK(element.first == std::to_string(i));
|
||||
CHECK(element.second.value == i);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,4 +234,33 @@ TEST_CASE("JSON_PRECISE_STREAM_POSITION")
|
||||
CHECK(j == json(1));
|
||||
CHECK(remaining(is) == "true");
|
||||
}
|
||||
|
||||
SECTION("stream with eofbit in its exception mask (issue #5646)")
|
||||
{
|
||||
// with JSON_PRECISE_STREAM_POSITION, get_character() peeks via
|
||||
// sb->sgetc() rather than consuming via sb->sbumpc(), but it still
|
||||
// calls std::istream::clear() to record eofbit once the streambuf is
|
||||
// exhausted; with eofbit in the exception mask, that clear() itself
|
||||
// throws std::ios_base::failure, which must propagate to the caller
|
||||
// instead of ~input_stream_adapter() throwing a second exception
|
||||
// while the first is still unwinding (which would call std::terminate)
|
||||
json _;
|
||||
|
||||
std::istringstream is1("1");
|
||||
is1.exceptions(std::ios::eofbit);
|
||||
CHECK_THROWS_AS(_ = json::parse(is1), std::ios_base::failure&);
|
||||
|
||||
std::istringstream is2("1");
|
||||
is2.exceptions(std::ios::failbit | std::ios::badbit | std::ios::eofbit);
|
||||
CHECK_THROWS_AS(_ = json::parse(is2), std::ios_base::failure&);
|
||||
}
|
||||
|
||||
SECTION("stream without a streambuf (issue #5646)")
|
||||
{
|
||||
// std::istream(nullptr) has badbit set and rdbuf() == nullptr;
|
||||
// get_character() must not dereference that null streambuf
|
||||
std::istream is(nullptr);
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse(is), "[json.exception.parse_error.101] parse error: attempting to parse an empty input; check that your input string or stream contains the expected JSON", json::parse_error&);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user