mirror of
https://github.com/nlohmann/json.git
synced 2026-09-29 19:20:30 +00:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27468fa77e | ||
|
|
a49d6e2e3b | ||
|
|
58ac756134 | ||
|
|
7917cfa0f4 | ||
|
|
b5da87a5e3 | ||
|
|
6d479d13ce | ||
|
|
ea5a1caf28 | ||
|
|
edfcff33c6 | ||
|
|
a14ac39bdd | ||
|
|
1ab017bbfe | ||
|
|
6936b95a65 | ||
|
|
a08f5501a7 | ||
|
|
31789f51cf | ||
|
|
f295970fb6 | ||
|
|
f6c115a9a6 | ||
|
|
33ef25099d |
+10
@@ -20,7 +20,9 @@ cc_library(
|
||||
hdrs = [
|
||||
"include/nlohmann/adl_serializer.hpp",
|
||||
"include/nlohmann/byte_container_with_subtype.hpp",
|
||||
"include/nlohmann/detail/abi_config.hpp",
|
||||
"include/nlohmann/detail/abi_macros.hpp",
|
||||
"include/nlohmann/detail/bit_ops.hpp",
|
||||
"include/nlohmann/detail/conversions/from_json.hpp",
|
||||
"include/nlohmann/detail/conversions/to_chars.hpp",
|
||||
"include/nlohmann/detail/conversions/to_json.hpp",
|
||||
@@ -33,6 +35,7 @@ cc_library(
|
||||
"include/nlohmann/detail/input/number_parse.hpp",
|
||||
"include/nlohmann/detail/input/parser.hpp",
|
||||
"include/nlohmann/detail/input/position_t.hpp",
|
||||
"include/nlohmann/detail/input/pow5_table.hpp",
|
||||
"include/nlohmann/detail/input/string_scan.hpp",
|
||||
"include/nlohmann/detail/iterators/internal_iterator.hpp",
|
||||
"include/nlohmann/detail/iterators/iter_impl.hpp",
|
||||
@@ -63,6 +66,13 @@ cc_library(
|
||||
"include/nlohmann/detail/string_escape.hpp",
|
||||
"include/nlohmann/detail/string_utils.hpp",
|
||||
"include/nlohmann/detail/value_t.hpp",
|
||||
"include/nlohmann/detail/view/builder.hpp",
|
||||
"include/nlohmann/detail/view/document_data.hpp",
|
||||
"include/nlohmann/detail/view/macro_scope.hpp",
|
||||
"include/nlohmann/detail/view/macro_unscope.hpp",
|
||||
"include/nlohmann/detail/view/node.hpp",
|
||||
"include/nlohmann/detail/view/scan.hpp",
|
||||
"include/nlohmann/detail/view/string_ref.hpp",
|
||||
"include/nlohmann/json.hpp",
|
||||
"include/nlohmann/json_fwd.hpp",
|
||||
"include/nlohmann/ordered_map.hpp",
|
||||
|
||||
@@ -1395,6 +1395,7 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
|
||||
- The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/)
|
||||
- The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
- The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
|
||||
- The class contains an adapted version of the Eisel-Lemire algorithm and its table of powers of five from [fast_float](https://github.com/fastfloat/fast_float) by Daniel Lemire and contributors, which is available under the [MIT License](https://opensource.org/licenses/MIT) (used here), the Apache 2.0 License, and the Boost Software License. Copyright © 2021 The fast_float authors
|
||||
|
||||
<img align="right" src="https://git.fsfe.org/reuse/reuse-ci/raw/branch/master/reuse-horizontal.png" alt="REUSE Software">
|
||||
|
||||
|
||||
@@ -19,3 +19,5 @@ The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed und
|
||||
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/)
|
||||
|
||||
The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
||||
The class contains an adapted version of the Eisel-Lemire algorithm and its table of powers of five from [fast_float](https://github.com/fastfloat/fast_float) by Daniel Lemire and contributors, which is available under the [MIT License](https://opensource.org/licenses/MIT) (used here), the Apache 2.0 License, and the Boost Software License. Copyright © 2021 The fast_float authors
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/*!
|
||||
@brief the configuration macros that change the library's behavior
|
||||
|
||||
json.hpp undefines these macros at its end (see macro_unscope.hpp), so code
|
||||
that builds on the library after it (json_view.hpp) reads them here. Like the
|
||||
macros, they are part of the ABI namespace, so they always match the
|
||||
basic_json they are used with.
|
||||
*/
|
||||
struct abi_config
|
||||
{
|
||||
/// JSON_STRICT_NUL_HANDLING: a null byte is an error, not the end of input
|
||||
static constexpr bool strict_nul_handling = JSON_STRICT_NUL_HANDLING != 0;
|
||||
/// JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
static constexpr bool legacy_discarded_value_comparison = JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON != 0;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -0,0 +1,105 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint64_t
|
||||
|
||||
#include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
// Portable bit-level helpers for the number and string scanners. They use
|
||||
// compiler builtins where available and plain C++ otherwise, so they need no
|
||||
// platform headers and work regardless of byte order.
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// number of leading zero bits of x (x != 0)
|
||||
inline int count_leading_zeros(std::uint64_t x) noexcept
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_clzll(x);
|
||||
#else
|
||||
int n = 0;
|
||||
for (int shift = 32; shift != 0; shift >>= 1)
|
||||
{
|
||||
if ((x >> (64 - shift)) == 0)
|
||||
{
|
||||
n += shift;
|
||||
x <<= shift;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// number of trailing zero bits of x (x != 0)
|
||||
inline int count_trailing_zeros(std::uint64_t x) noexcept
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_ctzll(x);
|
||||
#else
|
||||
int n = 0;
|
||||
for (int shift = 32; shift != 0; shift >>= 1)
|
||||
{
|
||||
if ((x << (64 - shift)) == 0)
|
||||
{
|
||||
n += shift;
|
||||
x >>= shift;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// the 128-bit product of two 64-bit numbers
|
||||
struct uint128_parts
|
||||
{
|
||||
std::uint64_t low;
|
||||
std::uint64_t high;
|
||||
};
|
||||
|
||||
inline uint128_parts full_multiplication(std::uint64_t a, std::uint64_t b) noexcept
|
||||
{
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
__extension__ using uint128 = unsigned __int128;
|
||||
const uint128 r = static_cast<uint128>(a) * b;
|
||||
return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)};
|
||||
#else
|
||||
const std::uint64_t a_lo = a & 0xFFFFFFFFu;
|
||||
const std::uint64_t a_hi = a >> 32u;
|
||||
const std::uint64_t b_lo = b & 0xFFFFFFFFu;
|
||||
const std::uint64_t b_hi = b >> 32u;
|
||||
const std::uint64_t lo_lo = a_lo * b_lo;
|
||||
const std::uint64_t hi_lo = a_hi * b_lo;
|
||||
const std::uint64_t lo_hi = a_lo * b_hi;
|
||||
const std::uint64_t hi_hi = a_hi * b_hi;
|
||||
const std::uint64_t cross = (lo_lo >> 32u) + (hi_lo & 0xFFFFFFFFu) + lo_hi;
|
||||
return {(cross << 32u) | (lo_lo & 0xFFFFFFFFu), (hi_lo >> 32u) + (cross >> 32u) + hi_hi};
|
||||
#endif
|
||||
}
|
||||
|
||||
/// eight bytes as a little-endian word (compilers fold this into one load on
|
||||
/// little-endian targets)
|
||||
inline std::uint64_t read_eight_bytes(const unsigned char* b) noexcept
|
||||
{
|
||||
return static_cast<std::uint64_t>(b[0]) | (static_cast<std::uint64_t>(b[1]) << 8u)
|
||||
| (static_cast<std::uint64_t>(b[2]) << 16u) | (static_cast<std::uint64_t>(b[3]) << 24u)
|
||||
| (static_cast<std::uint64_t>(b[4]) << 32u) | (static_cast<std::uint64_t>(b[5]) << 40u)
|
||||
| (static_cast<std::uint64_t>(b[6]) << 48u) | (static_cast<std::uint64_t>(b[7]) << 56u);
|
||||
}
|
||||
|
||||
/// eight bytes as a little-endian word
|
||||
inline std::uint64_t read_eight_bytes(const char* p) noexcept
|
||||
{
|
||||
return read_eight_bytes(reinterpret_cast<const unsigned char*>(p)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -9,10 +9,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <clocale> // localeconv
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdio> // snprintf
|
||||
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
|
||||
#include <initializer_list> // initializer_list
|
||||
#include <string> // char_traits, string
|
||||
#include <utility> // move
|
||||
@@ -217,22 +215,48 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
~lexer() = default;
|
||||
|
||||
private:
|
||||
/////////////////////
|
||||
// locales
|
||||
/////////////////////
|
||||
|
||||
/// return the decimal point of the current locale
|
||||
static char get_decimal_point() noexcept
|
||||
{
|
||||
const auto* loc = localeconv();
|
||||
JSON_ASSERT(loc != nullptr);
|
||||
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
// scan functions
|
||||
/////////////////////
|
||||
|
||||
/// contiguous input: try to decode the 4 hex digits following `\u`
|
||||
/// directly from the input buffer via hex_codepoint(), instead of 4 calls
|
||||
/// to get(). On success, advances the adapter and the position counters
|
||||
/// exactly as those 4 get() calls would (a hex digit is never '\n', so
|
||||
/// only the flat counters move) and leaves @a current holding the last of
|
||||
/// the 4 digits, just as the last such get() would; the codepoint is
|
||||
/// written to @a out. Makes no state change and returns false - for a
|
||||
/// pending unget, fewer than 4 remaining bytes, or any of the 4 bytes not
|
||||
/// being a hex digit - so the caller falls back unchanged to the
|
||||
/// per-character loop, which then reports the same diagnostic (stopping
|
||||
/// at the first invalid digit) as before this optimization.
|
||||
bool get_codepoint_bulk(std::true_type /*bulk*/, int& out)
|
||||
{
|
||||
if (next_unget || ia.bulk_remaining() < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const char_type* const raw = ia.bulk_data();
|
||||
const int codepoint = hex_codepoint(reinterpret_cast<const unsigned char*>(raw));
|
||||
if (codepoint < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ia.bulk_skip(4);
|
||||
// a hex digit is never a newline, so only the flat counters advance
|
||||
position.chars_read_total += 4;
|
||||
position.chars_read_current_line += 4;
|
||||
current = char_traits<char_type>::to_int_type(raw[3]);
|
||||
out = codepoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// streaming input: no bulk fast path
|
||||
bool get_codepoint_bulk(std::false_type /*bulk*/, int& /*out*/) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief get codepoint from 4 hex characters following `\u`
|
||||
|
||||
@@ -252,6 +276,14 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
{
|
||||
// this function only makes sense after reading `\u`
|
||||
JSON_ASSERT(current == 'u');
|
||||
|
||||
// contiguous input: decode all 4 hex digits directly from the buffer
|
||||
int fast_codepoint = 0;
|
||||
if (get_codepoint_bulk(std::integral_constant<bool, bulk_scan> {}, fast_codepoint))
|
||||
{
|
||||
return fast_codepoint;
|
||||
}
|
||||
|
||||
int codepoint = 0;
|
||||
|
||||
const auto factors = { 12u, 8u, 4u, 0u };
|
||||
@@ -1036,24 +1068,6 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
}
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static void strtof(float& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtof(str, endptr);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static void strtof(double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtod(str, endptr);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static void strtof(long double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtold(str, endptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief scan a number literal
|
||||
|
||||
@@ -1093,7 +1107,7 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
@note The scanner is independent of the current locale: token_buffer
|
||||
always holds `.`. Only the std::strtod fallback of convert_number()
|
||||
depends on the locale, and it looks up the decimal point right
|
||||
before converting (see convert_float_locale_aware()).
|
||||
before converting (see detail::convert_float_locale_aware()).
|
||||
*/
|
||||
token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated.
|
||||
{
|
||||
@@ -1424,59 +1438,6 @@ scan_number_done:
|
||||
return token_type::uninitialized;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief check whether Clinger's fast path can still succeed for this token
|
||||
|
||||
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
||||
more significant digits is at least 10^16 and therefore always exceeds it,
|
||||
so calling the fast path would walk the token one extra time only to
|
||||
decline before strtod has to run anyway.
|
||||
|
||||
Significant digits are the mantissa's digits from the first nonzero one on;
|
||||
the sign, the decimal point, leading zeros, and the exponent do not count.
|
||||
The answer is derived from indices - the digits are not scanned again - so
|
||||
this stays off the hot path of the number scanners.
|
||||
|
||||
@param[in] mantissa_end offset just past the last mantissa byte in
|
||||
token_buffer
|
||||
@return false if parse_float_fast() is guaranteed to decline
|
||||
*/
|
||||
bool mantissa_fits_clinger(std::size_t mantissa_end) const
|
||||
{
|
||||
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
||||
constexpr std::size_t limit = 17;
|
||||
|
||||
const std::size_t neg = (!token_buffer.empty() && token_buffer[0] == '-') ? 1u : 0u;
|
||||
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
||||
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
||||
// a leading zero can only be a lone "0", which is not significant
|
||||
const std::size_t lead_zero = (token_buffer[neg] == '0') ? 1u : 0u;
|
||||
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
||||
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(digits < limit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only a number below 1 can carry further insignificant zeros, and only
|
||||
// while the count stays at the limit does removing them change the
|
||||
// answer - so this loop is skipped for all but a few tokens. The
|
||||
// fraction is located through decimal_point_position rather than by
|
||||
// searching '.'.
|
||||
if (lead_zero != 0)
|
||||
{
|
||||
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
||||
for (std::size_t i = decimal_point_position + 1;
|
||||
digits >= limit && i < mantissa_end && token_buffer[i] == '0'; ++i)
|
||||
{
|
||||
--digits;
|
||||
}
|
||||
}
|
||||
|
||||
return digits < limit;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert the number text in token_buffer to its value and token type
|
||||
|
||||
@@ -1490,7 +1451,7 @@ scan_number_done:
|
||||
token_buffer (the index of 'e'/'E', or
|
||||
token_buffer.size() when there is no exponent);
|
||||
used to skip Clinger's fast path when it cannot
|
||||
possibly succeed - see mantissa_fits_clinger()
|
||||
possibly succeed - see detail::mantissa_fits_clinger()
|
||||
*/
|
||||
token_type convert_number(token_type number_type, std::size_t mantissa_end)
|
||||
{
|
||||
@@ -1563,77 +1524,15 @@ scan_number_done:
|
||||
// (Eisel-Lemire, locale-independent, correctly rounded) when available;
|
||||
// otherwise the exact Clinger fast path (double only); otherwise the
|
||||
// locale-aware strtof/strtod/strtold.
|
||||
if (parse_float_from_chars(num_begin, num_end, value_float))
|
||||
{
|
||||
return token_type::value_float;
|
||||
}
|
||||
// Skipping a fast path that cannot succeed is lossless and saves a full
|
||||
// extra pass over the token's bytes, which otherwise shows up on
|
||||
// high-precision inputs such as canada.json
|
||||
if (mantissa_fits_clinger(mantissa_end)
|
||||
&& parse_float_fast(num_begin, num_end, value_float))
|
||||
if (convert_float_fast(num_begin, num_end, decimal_point_position, mantissa_end, value_float))
|
||||
{
|
||||
return token_type::value_float;
|
||||
}
|
||||
|
||||
convert_float_locale_aware();
|
||||
convert_float_locale_aware(token_buffer, decimal_point_position, value_float);
|
||||
return token_type::value_float;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert the float in token_buffer with strtof/strtod/strtold
|
||||
|
||||
These functions expect the decimal point of the *current* locale, so it is
|
||||
looked up right before the conversion instead of once when the lexer is
|
||||
constructed: a locale change in between (by a parser callback, a SAX
|
||||
handler, or another thread) must not truncate the value (#5198). The
|
||||
token has been validated before, so if the conversion stops early and the
|
||||
decimal point changed in the meantime, the locale changed between the
|
||||
lookup and the call, and the conversion is repeated with the new decimal
|
||||
point. If the decimal point did not change, a retry cannot succeed: the
|
||||
locale's decimal point is not a single character (e.g., the two-byte
|
||||
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
||||
The value strtod parsed up to that point is kept, as before this change.
|
||||
|
||||
Note that changing the locale in another thread *while* strtod runs is
|
||||
undefined behavior of the C library, which this function cannot prevent.
|
||||
*/
|
||||
void convert_float_locale_aware()
|
||||
{
|
||||
const bool has_dot = decimal_point_position != std::string::npos;
|
||||
char decimal_point = get_decimal_point();
|
||||
for (;;)
|
||||
{
|
||||
const bool substitute = has_dot && decimal_point != '.';
|
||||
if (substitute)
|
||||
{
|
||||
token_buffer[decimal_point_position] = static_cast<typename string_t::value_type>(decimal_point);
|
||||
}
|
||||
|
||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
strtof(value_float, token_buffer.data(), &endptr);
|
||||
|
||||
if (substitute)
|
||||
{
|
||||
// get_string() hands the token to the SAX interface with '.'
|
||||
token_buffer[decimal_point_position] = '.';
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(endptr == token_buffer.data() + token_buffer.size()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// retry only if the locale changed; otherwise, this would loop forever
|
||||
const char current_decimal_point = get_decimal_point();
|
||||
if (current_decimal_point == decimal_point)
|
||||
{
|
||||
return;
|
||||
}
|
||||
decimal_point = current_decimal_point;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief contiguous fast path for scanning a number
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021 The fast_float authors <https://github.com/fastfloat/fast_float>
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
@@ -10,10 +11,16 @@
|
||||
|
||||
#include <array> // array
|
||||
#include <cfloat> // FLT_EVAL_METHOD
|
||||
#include <clocale> // localeconv
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <cstdlib> // strtof, strtod, strtold
|
||||
#include <cstring> // memcpy
|
||||
#include <limits> // numeric_limits
|
||||
#include <string> // string
|
||||
|
||||
#include <nlohmann/detail/bit_ops.hpp>
|
||||
#include <nlohmann/detail/input/pow5_table.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
// std::from_chars lives in <charconv>, but being in C++17 mode does not
|
||||
@@ -29,8 +36,9 @@
|
||||
|
||||
// This file contains the value-conversion helpers used by the lexer to turn an
|
||||
// already-validated number token into a value, without the locale/errno
|
||||
// overhead of std::strtoull/std::strtod. They are free functions so the lexer
|
||||
// stays focused on scanning; see lexer::convert_number().
|
||||
// overhead of std::strtoull/std::strtod where possible. They are free functions
|
||||
// so the lexer stays focused on scanning (see lexer::convert_number()) and so
|
||||
// that other parsers of JSON text can convert tokens exactly like it does.
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
@@ -293,5 +301,415 @@ bool parse_float_from_chars(const char* first, const char* last, FloatType& out)
|
||||
#endif
|
||||
}
|
||||
|
||||
/// whether the eight bytes of @a v (see read_eight_bytes()) are ASCII digits
|
||||
/// (after fast_float's is_made_of_eight_digits_fast)
|
||||
inline bool is_eight_digits(std::uint64_t v) noexcept
|
||||
{
|
||||
return ((v & 0xF0F0F0F0F0F0F0F0u) | (((v + 0x0606060606060606u) & 0xF0F0F0F0F0F0F0F0u) >> 4u)) == 0x3333333333333333u;
|
||||
}
|
||||
|
||||
/// the value of the eight ASCII digits in @a v (see read_eight_bytes()), three
|
||||
/// multiplications instead of eight (after simdjson and fast_float)
|
||||
inline std::uint32_t parse_eight_digits(std::uint64_t v) noexcept
|
||||
{
|
||||
v = ((v & 0x0F0F0F0F0F0F0F0Fu) * 2561u) >> 8u;
|
||||
v = ((v & 0x00FF00FF00FF00FFu) * 6553601u) >> 16u;
|
||||
return static_cast<std::uint32_t>(((v & 0x0000FFFF0000FFFFu) * 42949672960001u) >> 32u);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief the double nearest to w * 10^q (Eisel-Lemire)
|
||||
|
||||
The algorithm of Daniel Lemire, "Number Parsing at a Gigabyte per Second"
|
||||
(Software: Practice and Experience, 2021), after fast_float's compute_float
|
||||
(used under the MIT license). With a 128-bit approximation of 5^q, the product
|
||||
is always sufficient to round correctly for w with at most 19 digits (Noble
|
||||
Mushtak and Daniel Lemire, "Fast number parsing without fallback", Software:
|
||||
Practice and Experience, 2023). Only integer arithmetic is used, so the result
|
||||
does not depend on the floating-point environment.
|
||||
|
||||
@param[in] q decimal exponent
|
||||
@param[in] w significand, w != 0
|
||||
@return the IEEE-754 bits of the positive result (0 for underflow, infinity
|
||||
for overflow)
|
||||
*/
|
||||
inline std::uint64_t eisel_lemire(std::int64_t q, std::uint64_t w) noexcept
|
||||
{
|
||||
constexpr int mantissa_bits = 52;
|
||||
constexpr std::uint64_t infinity = std::uint64_t{0x7FF} << mantissa_bits;
|
||||
if (q < pow5_128_smallest_power)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (q > pow5_128_largest_power)
|
||||
{
|
||||
return infinity;
|
||||
}
|
||||
|
||||
const int lz = count_leading_zeros(w);
|
||||
w <<= static_cast<unsigned>(lz);
|
||||
const auto index = static_cast<std::size_t>(2 * (q - pow5_128_smallest_power));
|
||||
uint128_parts product = full_multiplication(w, pow5_128()[index]);
|
||||
constexpr std::uint64_t precision_mask = 0xFFFFFFFFFFFFFFFFu >> (mantissa_bits + 3);
|
||||
if ((product.high & precision_mask) == precision_mask)
|
||||
{
|
||||
// the lower bits may carry into the result: use the next 64 bits of 5^q
|
||||
const uint128_parts second = full_multiplication(w, pow5_128()[index + 1]);
|
||||
product.low += second.high;
|
||||
if (second.high > product.low)
|
||||
{
|
||||
++product.high;
|
||||
}
|
||||
}
|
||||
|
||||
const auto upperbit = static_cast<int>(product.high >> 63u);
|
||||
const int shift = upperbit + 64 - mantissa_bits - 3;
|
||||
std::uint64_t mantissa = product.high >> static_cast<unsigned>(shift);
|
||||
// floor(log2(10^q)) + 63 + 1023, with log2(10) ~ 217706 / 2^16
|
||||
std::int64_t power2 = (((152170 + 65536) * q) >> 16) + 63 + upperbit - lz + 1023;
|
||||
|
||||
if (power2 <= 0) // subnormal
|
||||
{
|
||||
if (-power2 + 1 >= 64)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
mantissa >>= static_cast<unsigned>(-power2 + 1);
|
||||
mantissa += (mantissa & 1u);
|
||||
mantissa >>= 1u;
|
||||
// rounding up may produce the smallest normal number
|
||||
power2 = (mantissa < (std::uint64_t{1} << mantissa_bits)) ? 0 : 1;
|
||||
return mantissa | (static_cast<std::uint64_t>(power2) << mantissa_bits);
|
||||
}
|
||||
|
||||
// a value exactly between two doubles rounds to even; this can only
|
||||
// happen for small |q|, where 5^q is exact
|
||||
if (product.low <= 1 && q >= -4 && q <= 23 && (mantissa & 3u) == 1
|
||||
&& (mantissa << static_cast<unsigned>(shift)) == product.high)
|
||||
{
|
||||
mantissa &= ~std::uint64_t{1};
|
||||
}
|
||||
mantissa += (mantissa & 1u);
|
||||
mantissa >>= 1u;
|
||||
if (mantissa >= (std::uint64_t{2} << mantissa_bits))
|
||||
{
|
||||
mantissa = std::uint64_t{1} << mantissa_bits;
|
||||
++power2;
|
||||
}
|
||||
mantissa &= ~(std::uint64_t{1} << mantissa_bits);
|
||||
if (power2 >= 0x7FF)
|
||||
{
|
||||
return infinity;
|
||||
}
|
||||
return mantissa | (static_cast<std::uint64_t>(power2) << mantissa_bits);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief parse a validated float token with the Eisel-Lemire algorithm
|
||||
|
||||
The significand is accumulated eight digits at a time where possible. A token
|
||||
with more than 19 significant digits is truncated to w; the value then lies
|
||||
in [w, w + 1) * 10^q, and it is only returned if both ends round to the same
|
||||
double, which covers all but a few such tokens.
|
||||
|
||||
@param[in] first pointer to the first character of the token
|
||||
@param[in] last pointer past the last character
|
||||
@param[out] out the correctly rounded value on success (±infinity if it
|
||||
overflows, like strtod)
|
||||
@return true on success; false if strtod must decide
|
||||
*/
|
||||
inline bool parse_float_eisel_lemire(const char* first, const char* last, double& out) noexcept
|
||||
{
|
||||
const char* p = first;
|
||||
const bool negative = (p != last && *p == '-');
|
||||
if (negative)
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
std::uint64_t w = 0;
|
||||
int digits = 0; // significant digits in w
|
||||
std::int64_t exponent = 0;
|
||||
bool truncated = false;
|
||||
bool in_fraction = false;
|
||||
for (;;)
|
||||
{
|
||||
// eight digits at a time, as long as they fit into w
|
||||
while (w != 0 && digits <= 19 - 8 && last - p >= 8)
|
||||
{
|
||||
const std::uint64_t v = read_eight_bytes(p);
|
||||
if (!is_eight_digits(v))
|
||||
{
|
||||
break;
|
||||
}
|
||||
w = (w * 100000000u) + parse_eight_digits(v);
|
||||
digits += 8;
|
||||
exponent -= in_fraction ? 8 : 0;
|
||||
p += 8;
|
||||
}
|
||||
if (p == last)
|
||||
{
|
||||
break;
|
||||
}
|
||||
const char c = *p;
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
if (w == 0 && c == '0')
|
||||
{
|
||||
// leading zeros are not significant, but scale a fraction
|
||||
exponent -= in_fraction ? 1 : 0;
|
||||
}
|
||||
else if (digits < 19)
|
||||
{
|
||||
w = (w * 10u) + static_cast<std::uint64_t>(c - '0');
|
||||
++digits;
|
||||
exponent -= in_fraction ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// dropped: the value lies between w and w + 1 (in units of
|
||||
// the last kept digit) unless all dropped digits are zero
|
||||
truncated = truncated || c != '0';
|
||||
exponent += in_fraction ? 0 : 1;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
in_fraction = true;
|
||||
++p;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // 'e' or 'E'
|
||||
}
|
||||
}
|
||||
|
||||
if (p != last)
|
||||
{
|
||||
++p; // 'e' or 'E'
|
||||
bool exp_negative = false;
|
||||
if (p != last && (*p == '-' || *p == '+'))
|
||||
{
|
||||
exp_negative = (*p == '-');
|
||||
++p;
|
||||
}
|
||||
std::int64_t exp_value = 0;
|
||||
for (; p != last; ++p)
|
||||
{
|
||||
// saturate: any exponent beyond this under- or overflows anyway
|
||||
if (exp_value < 100000)
|
||||
{
|
||||
exp_value = (exp_value * 10) + (*p - '0');
|
||||
}
|
||||
}
|
||||
exponent += exp_negative ? -exp_value : exp_value;
|
||||
}
|
||||
|
||||
std::uint64_t bits = 0;
|
||||
if (w != 0)
|
||||
{
|
||||
bits = eisel_lemire(exponent, w);
|
||||
if (truncated && (w + 1 == 0 || eisel_lemire(exponent, w + 1) != bits))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bits |= negative ? (std::uint64_t{1} << 63u) : 0u;
|
||||
static_assert(sizeof(double) == sizeof(std::uint64_t), "double must have 64 bits");
|
||||
std::memcpy(&out, &bits, sizeof(out));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Eisel-Lemire is only implemented for `double`
|
||||
template<typename FloatType>
|
||||
bool parse_float_eisel_lemire(const char* /*first*/, const char* /*last*/, FloatType& /*out*/) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief check whether Clinger's fast path can still succeed for a float token
|
||||
|
||||
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
||||
more significant digits is at least 10^16 and therefore always exceeds it,
|
||||
so calling the fast path would walk the token one extra time only to
|
||||
decline before strtod has to run anyway.
|
||||
|
||||
Significant digits are the mantissa's digits from the first nonzero one on;
|
||||
the sign, the decimal point, leading zeros, and the exponent do not count.
|
||||
The answer is derived from indices - the digits are not scanned again - so
|
||||
this stays off the hot path of the number scanners.
|
||||
|
||||
@param[in] token the validated number token ('.' as decimal point)
|
||||
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||
std::string::npos if there is none
|
||||
@param[in] mantissa_end offset just past the last mantissa byte
|
||||
@return false if parse_float_fast() is guaranteed to decline
|
||||
*/
|
||||
inline bool mantissa_fits_clinger(const char* token, std::size_t decimal_point_position, std::size_t mantissa_end) noexcept
|
||||
{
|
||||
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
||||
constexpr std::size_t limit = 17;
|
||||
|
||||
const std::size_t neg = (token[0] == '-') ? 1u : 0u;
|
||||
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
||||
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
||||
// a leading zero can only be a lone "0", which is not significant
|
||||
const std::size_t lead_zero = (token[neg] == '0') ? 1u : 0u;
|
||||
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
||||
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(digits < limit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only a number below 1 can carry further insignificant zeros, and only
|
||||
// while the count stays at the limit does removing them change the
|
||||
// answer - so this loop is skipped for all but a few tokens. The
|
||||
// fraction is located through decimal_point_position rather than by
|
||||
// searching '.'.
|
||||
if (lead_zero != 0)
|
||||
{
|
||||
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
||||
for (std::size_t i = decimal_point_position + 1;
|
||||
digits >= limit && i < mantissa_end && token[i] == '0'; ++i)
|
||||
{
|
||||
--digits;
|
||||
}
|
||||
}
|
||||
|
||||
return digits < limit;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert a validated float token without the C library, if possible
|
||||
|
||||
Tries std::from_chars (when available), Clinger's exact fast path (double
|
||||
only, skipped when it cannot succeed), and the Eisel-Lemire algorithm (double
|
||||
only).
|
||||
|
||||
@param[in] first pointer to the first character of the token
|
||||
@param[in] last pointer past the last character
|
||||
@param[in] decimal_point_position index of the '.' in the token, or
|
||||
std::string::npos if there is none
|
||||
@param[in] mantissa_end offset just past the last mantissa byte (the
|
||||
index of 'e'/'E', or the token length)
|
||||
@param[out] value the converted value on success
|
||||
@return true if the value was converted; false if convert_float_locale_aware()
|
||||
must convert it
|
||||
*/
|
||||
template<typename FloatType>
|
||||
bool convert_float_fast(const char* first, const char* last, std::size_t decimal_point_position,
|
||||
std::size_t mantissa_end, FloatType& value) noexcept
|
||||
{
|
||||
if (parse_float_from_chars(first, last, value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Skipping a fast path that cannot succeed is lossless and saves a full
|
||||
// extra pass over the token's bytes, which otherwise shows up on
|
||||
// high-precision inputs such as canada.json
|
||||
if (mantissa_fits_clinger(first, decimal_point_position, mantissa_end)
|
||||
&& parse_float_fast(first, last, value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return parse_float_eisel_lemire(first, last, value);
|
||||
}
|
||||
|
||||
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
inline void strtof_by_type(float& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtof(str, endptr);
|
||||
}
|
||||
|
||||
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
inline void strtof_by_type(double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtod(str, endptr);
|
||||
}
|
||||
|
||||
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
inline void strtof_by_type(long double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtold(str, endptr);
|
||||
}
|
||||
|
||||
/// return the decimal point of the current locale
|
||||
inline char get_decimal_point() noexcept
|
||||
{
|
||||
const auto* loc = localeconv();
|
||||
JSON_ASSERT(loc != nullptr);
|
||||
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert a validated float token with strtof/strtod/strtold
|
||||
|
||||
These functions expect the decimal point of the *current* locale, so it is
|
||||
looked up right before the conversion instead of once when the lexer is
|
||||
constructed: a locale change in between (by a parser callback, a SAX
|
||||
handler, or another thread) must not truncate the value (#5198). The
|
||||
token has been validated before, so if the conversion stops early and the
|
||||
decimal point changed in the meantime, the locale changed between the
|
||||
lookup and the call, and the conversion is repeated with the new decimal
|
||||
point. If the decimal point did not change, a retry cannot succeed: the
|
||||
locale's decimal point is not a single character (e.g., the two-byte
|
||||
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
||||
The value strtod parsed up to that point is kept, as before this change.
|
||||
|
||||
Note that changing the locale in another thread *while* strtod runs is
|
||||
undefined behavior of the C library, which this function cannot prevent.
|
||||
|
||||
@param[in,out] token the token with '.' as decimal point; its
|
||||
decimal point is replaced during the
|
||||
conversion and restored afterwards
|
||||
(data() must be NUL-terminated)
|
||||
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||
std::string::npos if there is none
|
||||
@param[out] value the converted value
|
||||
*/
|
||||
template<typename StringType, typename FloatType>
|
||||
void convert_float_locale_aware(StringType& token, std::size_t decimal_point_position, FloatType& value)
|
||||
{
|
||||
const bool has_dot = decimal_point_position != std::string::npos;
|
||||
char decimal_point = get_decimal_point();
|
||||
for (;;)
|
||||
{
|
||||
const bool substitute = has_dot && decimal_point != '.';
|
||||
if (substitute)
|
||||
{
|
||||
token[decimal_point_position] = static_cast<typename StringType::value_type>(decimal_point);
|
||||
}
|
||||
|
||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
strtof_by_type(value, token.data(), &endptr);
|
||||
|
||||
if (substitute)
|
||||
{
|
||||
// the caller hands the token on (e.g. to the SAX interface) with '.'
|
||||
token[decimal_point_position] = '.';
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(endptr == token.data() + token.size()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// retry only if the locale changed; otherwise, this would loop forever
|
||||
const char current_decimal_point = get_decimal_point();
|
||||
if (current_decimal_point == decimal_point)
|
||||
{
|
||||
return;
|
||||
}
|
||||
decimal_point = current_decimal_point;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -0,0 +1,371 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021 The fast_float authors <https://github.com/fastfloat/fast_float>
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
|
||||
#include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// the range of decimal exponents covered by pow5_128()
|
||||
constexpr std::int64_t pow5_128_smallest_power = -342;
|
||||
constexpr std::int64_t pow5_128_largest_power = 308;
|
||||
|
||||
/*!
|
||||
@brief 128-bit approximations of 5^q for q in [-342, 308]
|
||||
|
||||
Entry q (at index 2 * (q + 342)) holds the most significant 128 bits of 5^q,
|
||||
normalized so that the highest bit is set: for q >= 0 the truncated value, for
|
||||
q < 0 the value rounded up. This is the table of fast_float (Daniel Lemire and
|
||||
contributors, used under the MIT license), generated like its
|
||||
script/table_generation.py; unit-class_lexer.cpp recomputes every entry.
|
||||
*/
|
||||
inline const std::array<std::uint64_t, 1302>& pow5_128() noexcept
|
||||
{
|
||||
static const std::array<std::uint64_t, 1302> table =
|
||||
{
|
||||
{
|
||||
0xeef453d6923bd65au, 0x113faa2906a13b3fu, 0x9558b4661b6565f8u, 0x4ac7ca59a424c507u,
|
||||
0xbaaee17fa23ebf76u, 0x5d79bcf00d2df649u, 0xe95a99df8ace6f53u, 0xf4d82c2c107973dcu,
|
||||
0x91d8a02bb6c10594u, 0x79071b9b8a4be869u, 0xb64ec836a47146f9u, 0x9748e2826cdee284u,
|
||||
0xe3e27a444d8d98b7u, 0xfd1b1b2308169b25u, 0x8e6d8c6ab0787f72u, 0xfe30f0f5e50e20f7u,
|
||||
0xb208ef855c969f4fu, 0xbdbd2d335e51a935u, 0xde8b2b66b3bc4723u, 0xad2c788035e61382u,
|
||||
0x8b16fb203055ac76u, 0x4c3bcb5021afcc31u, 0xaddcb9e83c6b1793u, 0xdf4abe242a1bbf3du,
|
||||
0xd953e8624b85dd78u, 0xd71d6dad34a2af0du, 0x87d4713d6f33aa6bu, 0x8672648c40e5ad68u,
|
||||
0xa9c98d8ccb009506u, 0x680efdaf511f18c2u, 0xd43bf0effdc0ba48u, 0x0212bd1b2566def2u,
|
||||
0x84a57695fe98746du, 0x014bb630f7604b57u, 0xa5ced43b7e3e9188u, 0x419ea3bd35385e2du,
|
||||
0xcf42894a5dce35eau, 0x52064cac828675b9u, 0x818995ce7aa0e1b2u, 0x7343efebd1940993u,
|
||||
0xa1ebfb4219491a1fu, 0x1014ebe6c5f90bf8u, 0xca66fa129f9b60a6u, 0xd41a26e077774ef6u,
|
||||
0xfd00b897478238d0u, 0x8920b098955522b4u, 0x9e20735e8cb16382u, 0x55b46e5f5d5535b0u,
|
||||
0xc5a890362fddbc62u, 0xeb2189f734aa831du, 0xf712b443bbd52b7bu, 0xa5e9ec7501d523e4u,
|
||||
0x9a6bb0aa55653b2du, 0x47b233c92125366eu, 0xc1069cd4eabe89f8u, 0x999ec0bb696e840au,
|
||||
0xf148440a256e2c76u, 0xc00670ea43ca250du, 0x96cd2a865764dbcau, 0x380406926a5e5728u,
|
||||
0xbc807527ed3e12bcu, 0xc605083704f5ecf2u, 0xeba09271e88d976bu, 0xf7864a44c633682eu,
|
||||
0x93445b8731587ea3u, 0x7ab3ee6afbe0211du, 0xb8157268fdae9e4cu, 0x5960ea05bad82964u,
|
||||
0xe61acf033d1a45dfu, 0x6fb92487298e33bdu, 0x8fd0c16206306babu, 0xa5d3b6d479f8e056u,
|
||||
0xb3c4f1ba87bc8696u, 0x8f48a4899877186cu, 0xe0b62e2929aba83cu, 0x331acdabfe94de87u,
|
||||
0x8c71dcd9ba0b4925u, 0x9ff0c08b7f1d0b14u, 0xaf8e5410288e1b6fu, 0x07ecf0ae5ee44dd9u,
|
||||
0xdb71e91432b1a24au, 0xc9e82cd9f69d6150u, 0x892731ac9faf056eu, 0xbe311c083a225cd2u,
|
||||
0xab70fe17c79ac6cau, 0x6dbd630a48aaf406u, 0xd64d3d9db981787du, 0x092cbbccdad5b108u,
|
||||
0x85f0468293f0eb4eu, 0x25bbf56008c58ea5u, 0xa76c582338ed2621u, 0xaf2af2b80af6f24eu,
|
||||
0xd1476e2c07286faau, 0x1af5af660db4aee1u, 0x82cca4db847945cau, 0x50d98d9fc890ed4du,
|
||||
0xa37fce126597973cu, 0xe50ff107bab528a0u, 0xcc5fc196fefd7d0cu, 0x1e53ed49a96272c8u,
|
||||
0xff77b1fcbebcdc4fu, 0x25e8e89c13bb0f7au, 0x9faacf3df73609b1u, 0x77b191618c54e9acu,
|
||||
0xc795830d75038c1du, 0xd59df5b9ef6a2417u, 0xf97ae3d0d2446f25u, 0x4b0573286b44ad1du,
|
||||
0x9becce62836ac577u, 0x4ee367f9430aec32u, 0xc2e801fb244576d5u, 0x229c41f793cda73fu,
|
||||
0xf3a20279ed56d48au, 0x6b43527578c1110fu, 0x9845418c345644d6u, 0x830a13896b78aaa9u,
|
||||
0xbe5691ef416bd60cu, 0x23cc986bc656d553u, 0xedec366b11c6cb8fu, 0x2cbfbe86b7ec8aa8u,
|
||||
0x94b3a202eb1c3f39u, 0x7bf7d71432f3d6a9u, 0xb9e08a83a5e34f07u, 0xdaf5ccd93fb0cc53u,
|
||||
0xe858ad248f5c22c9u, 0xd1b3400f8f9cff68u, 0x91376c36d99995beu, 0x23100809b9c21fa1u,
|
||||
0xb58547448ffffb2du, 0xabd40a0c2832a78au, 0xe2e69915b3fff9f9u, 0x16c90c8f323f516cu,
|
||||
0x8dd01fad907ffc3bu, 0xae3da7d97f6792e3u, 0xb1442798f49ffb4au, 0x99cd11cfdf41779cu,
|
||||
0xdd95317f31c7fa1du, 0x40405643d711d583u, 0x8a7d3eef7f1cfc52u, 0x482835ea666b2572u,
|
||||
0xad1c8eab5ee43b66u, 0xda3243650005eecfu, 0xd863b256369d4a40u, 0x90bed43e40076a82u,
|
||||
0x873e4f75e2224e68u, 0x5a7744a6e804a291u, 0xa90de3535aaae202u, 0x711515d0a205cb36u,
|
||||
0xd3515c2831559a83u, 0x0d5a5b44ca873e03u, 0x8412d9991ed58091u, 0xe858790afe9486c2u,
|
||||
0xa5178fff668ae0b6u, 0x626e974dbe39a872u, 0xce5d73ff402d98e3u, 0xfb0a3d212dc8128fu,
|
||||
0x80fa687f881c7f8eu, 0x7ce66634bc9d0b99u, 0xa139029f6a239f72u, 0x1c1fffc1ebc44e80u,
|
||||
0xc987434744ac874eu, 0xa327ffb266b56220u, 0xfbe9141915d7a922u, 0x4bf1ff9f0062baa8u,
|
||||
0x9d71ac8fada6c9b5u, 0x6f773fc3603db4a9u, 0xc4ce17b399107c22u, 0xcb550fb4384d21d3u,
|
||||
0xf6019da07f549b2bu, 0x7e2a53a146606a48u, 0x99c102844f94e0fbu, 0x2eda7444cbfc426du,
|
||||
0xc0314325637a1939u, 0xfa911155fefb5308u, 0xf03d93eebc589f88u, 0x793555ab7eba27cau,
|
||||
0x96267c7535b763b5u, 0x4bc1558b2f3458deu, 0xbbb01b9283253ca2u, 0x9eb1aaedfb016f16u,
|
||||
0xea9c227723ee8bcbu, 0x465e15a979c1cadcu, 0x92a1958a7675175fu, 0x0bfacd89ec191ec9u,
|
||||
0xb749faed14125d36u, 0xcef980ec671f667bu, 0xe51c79a85916f484u, 0x82b7e12780e7401au,
|
||||
0x8f31cc0937ae58d2u, 0xd1b2ecb8b0908810u, 0xb2fe3f0b8599ef07u, 0x861fa7e6dcb4aa15u,
|
||||
0xdfbdcece67006ac9u, 0x67a791e093e1d49au, 0x8bd6a141006042bdu, 0xe0c8bb2c5c6d24e0u,
|
||||
0xaecc49914078536du, 0x58fae9f773886e18u, 0xda7f5bf590966848u, 0xaf39a475506a899eu,
|
||||
0x888f99797a5e012du, 0x6d8406c952429603u, 0xaab37fd7d8f58178u, 0xc8e5087ba6d33b83u,
|
||||
0xd5605fcdcf32e1d6u, 0xfb1e4a9a90880a64u, 0x855c3be0a17fcd26u, 0x5cf2eea09a55067fu,
|
||||
0xa6b34ad8c9dfc06fu, 0xf42faa48c0ea481eu, 0xd0601d8efc57b08bu, 0xf13b94daf124da26u,
|
||||
0x823c12795db6ce57u, 0x76c53d08d6b70858u, 0xa2cb1717b52481edu, 0x54768c4b0c64ca6eu,
|
||||
0xcb7ddcdda26da268u, 0xa9942f5dcf7dfd09u, 0xfe5d54150b090b02u, 0xd3f93b35435d7c4cu,
|
||||
0x9efa548d26e5a6e1u, 0xc47bc5014a1a6dafu, 0xc6b8e9b0709f109au, 0x359ab6419ca1091bu,
|
||||
0xf867241c8cc6d4c0u, 0xc30163d203c94b62u, 0x9b407691d7fc44f8u, 0x79e0de63425dcf1du,
|
||||
0xc21094364dfb5636u, 0x985915fc12f542e4u, 0xf294b943e17a2bc4u, 0x3e6f5b7b17b2939du,
|
||||
0x979cf3ca6cec5b5au, 0xa705992ceecf9c42u, 0xbd8430bd08277231u, 0x50c6ff782a838353u,
|
||||
0xece53cec4a314ebdu, 0xa4f8bf5635246428u, 0x940f4613ae5ed136u, 0x871b7795e136be99u,
|
||||
0xb913179899f68584u, 0x28e2557b59846e3fu, 0xe757dd7ec07426e5u, 0x331aeada2fe589cfu,
|
||||
0x9096ea6f3848984fu, 0x3ff0d2c85def7621u, 0xb4bca50b065abe63u, 0x0fed077a756b53a9u,
|
||||
0xe1ebce4dc7f16dfbu, 0xd3e8495912c62894u, 0x8d3360f09cf6e4bdu, 0x64712dd7abbbd95cu,
|
||||
0xb080392cc4349decu, 0xbd8d794d96aacfb3u, 0xdca04777f541c567u, 0xecf0d7a0fc5583a0u,
|
||||
0x89e42caaf9491b60u, 0xf41686c49db57244u, 0xac5d37d5b79b6239u, 0x311c2875c522ced5u,
|
||||
0xd77485cb25823ac7u, 0x7d633293366b828bu, 0x86a8d39ef77164bcu, 0xae5dff9c02033197u,
|
||||
0xa8530886b54dbdebu, 0xd9f57f830283fdfcu, 0xd267caa862a12d66u, 0xd072df63c324fd7bu,
|
||||
0x8380dea93da4bc60u, 0x4247cb9e59f71e6du, 0xa46116538d0deb78u, 0x52d9be85f074e608u,
|
||||
0xcd795be870516656u, 0x67902e276c921f8bu, 0x806bd9714632dff6u, 0x00ba1cd8a3db53b6u,
|
||||
0xa086cfcd97bf97f3u, 0x80e8a40eccd228a4u, 0xc8a883c0fdaf7df0u, 0x6122cd128006b2cdu,
|
||||
0xfad2a4b13d1b5d6cu, 0x796b805720085f81u, 0x9cc3a6eec6311a63u, 0xcbe3303674053bb0u,
|
||||
0xc3f490aa77bd60fcu, 0xbedbfc4411068a9cu, 0xf4f1b4d515acb93bu, 0xee92fb5515482d44u,
|
||||
0x991711052d8bf3c5u, 0x751bdd152d4d1c4au, 0xbf5cd54678eef0b6u, 0xd262d45a78a0635du,
|
||||
0xef340a98172aace4u, 0x86fb897116c87c34u, 0x9580869f0e7aac0eu, 0xd45d35e6ae3d4da0u,
|
||||
0xbae0a846d2195712u, 0x8974836059cca109u, 0xe998d258869facd7u, 0x2bd1a438703fc94bu,
|
||||
0x91ff83775423cc06u, 0x7b6306a34627ddcfu, 0xb67f6455292cbf08u, 0x1a3bc84c17b1d542u,
|
||||
0xe41f3d6a7377eecau, 0x20caba5f1d9e4a93u, 0x8e938662882af53eu, 0x547eb47b7282ee9cu,
|
||||
0xb23867fb2a35b28du, 0xe99e619a4f23aa43u, 0xdec681f9f4c31f31u, 0x6405fa00e2ec94d4u,
|
||||
0x8b3c113c38f9f37eu, 0xde83bc408dd3dd04u, 0xae0b158b4738705eu, 0x9624ab50b148d445u,
|
||||
0xd98ddaee19068c76u, 0x3badd624dd9b0957u, 0x87f8a8d4cfa417c9u, 0xe54ca5d70a80e5d6u,
|
||||
0xa9f6d30a038d1dbcu, 0x5e9fcf4ccd211f4cu, 0xd47487cc8470652bu, 0x7647c3200069671fu,
|
||||
0x84c8d4dfd2c63f3bu, 0x29ecd9f40041e073u, 0xa5fb0a17c777cf09u, 0xf468107100525890u,
|
||||
0xcf79cc9db955c2ccu, 0x7182148d4066eeb4u, 0x81ac1fe293d599bfu, 0xc6f14cd848405530u,
|
||||
0xa21727db38cb002fu, 0xb8ada00e5a506a7cu, 0xca9cf1d206fdc03bu, 0xa6d90811f0e4851cu,
|
||||
0xfd442e4688bd304au, 0x908f4a166d1da663u, 0x9e4a9cec15763e2eu, 0x9a598e4e043287feu,
|
||||
0xc5dd44271ad3cdbau, 0x40eff1e1853f29fdu, 0xf7549530e188c128u, 0xd12bee59e68ef47cu,
|
||||
0x9a94dd3e8cf578b9u, 0x82bb74f8301958ceu, 0xc13a148e3032d6e7u, 0xe36a52363c1faf01u,
|
||||
0xf18899b1bc3f8ca1u, 0xdc44e6c3cb279ac1u, 0x96f5600f15a7b7e5u, 0x29ab103a5ef8c0b9u,
|
||||
0xbcb2b812db11a5deu, 0x7415d448f6b6f0e7u, 0xebdf661791d60f56u, 0x111b495b3464ad21u,
|
||||
0x936b9fcebb25c995u, 0xcab10dd900beec34u, 0xb84687c269ef3bfbu, 0x3d5d514f40eea742u,
|
||||
0xe65829b3046b0afau, 0x0cb4a5a3112a5112u, 0x8ff71a0fe2c2e6dcu, 0x47f0e785eaba72abu,
|
||||
0xb3f4e093db73a093u, 0x59ed216765690f56u, 0xe0f218b8d25088b8u, 0x306869c13ec3532cu,
|
||||
0x8c974f7383725573u, 0x1e414218c73a13fbu, 0xafbd2350644eeacfu, 0xe5d1929ef90898fau,
|
||||
0xdbac6c247d62a583u, 0xdf45f746b74abf39u, 0x894bc396ce5da772u, 0x6b8bba8c328eb783u,
|
||||
0xab9eb47c81f5114fu, 0x066ea92f3f326564u, 0xd686619ba27255a2u, 0xc80a537b0efefebdu,
|
||||
0x8613fd0145877585u, 0xbd06742ce95f5f36u, 0xa798fc4196e952e7u, 0x2c48113823b73704u,
|
||||
0xd17f3b51fca3a7a0u, 0xf75a15862ca504c5u, 0x82ef85133de648c4u, 0x9a984d73dbe722fbu,
|
||||
0xa3ab66580d5fdaf5u, 0xc13e60d0d2e0ebbau, 0xcc963fee10b7d1b3u, 0x318df905079926a8u,
|
||||
0xffbbcfe994e5c61fu, 0xfdf17746497f7052u, 0x9fd561f1fd0f9bd3u, 0xfeb6ea8bedefa633u,
|
||||
0xc7caba6e7c5382c8u, 0xfe64a52ee96b8fc0u, 0xf9bd690a1b68637bu, 0x3dfdce7aa3c673b0u,
|
||||
0x9c1661a651213e2du, 0x06bea10ca65c084eu, 0xc31bfa0fe5698db8u, 0x486e494fcff30a62u,
|
||||
0xf3e2f893dec3f126u, 0x5a89dba3c3efccfau, 0x986ddb5c6b3a76b7u, 0xf89629465a75e01cu,
|
||||
0xbe89523386091465u, 0xf6bbb397f1135823u, 0xee2ba6c0678b597fu, 0x746aa07ded582e2cu,
|
||||
0x94db483840b717efu, 0xa8c2a44eb4571cdcu, 0xba121a4650e4ddebu, 0x92f34d62616ce413u,
|
||||
0xe896a0d7e51e1566u, 0x77b020baf9c81d17u, 0x915e2486ef32cd60u, 0x0ace1474dc1d122eu,
|
||||
0xb5b5ada8aaff80b8u, 0x0d819992132456bau, 0xe3231912d5bf60e6u, 0x10e1fff697ed6c69u,
|
||||
0x8df5efabc5979c8fu, 0xca8d3ffa1ef463c1u, 0xb1736b96b6fd83b3u, 0xbd308ff8a6b17cb2u,
|
||||
0xddd0467c64bce4a0u, 0xac7cb3f6d05ddbdeu, 0x8aa22c0dbef60ee4u, 0x6bcdf07a423aa96bu,
|
||||
0xad4ab7112eb3929du, 0x86c16c98d2c953c6u, 0xd89d64d57a607744u, 0xe871c7bf077ba8b7u,
|
||||
0x87625f056c7c4a8bu, 0x11471cd764ad4972u, 0xa93af6c6c79b5d2du, 0xd598e40d3dd89bcfu,
|
||||
0xd389b47879823479u, 0x4aff1d108d4ec2c3u, 0x843610cb4bf160cbu, 0xcedf722a585139bau,
|
||||
0xa54394fe1eedb8feu, 0xc2974eb4ee658828u, 0xce947a3da6a9273eu, 0x733d226229feea32u,
|
||||
0x811ccc668829b887u, 0x0806357d5a3f525fu, 0xa163ff802a3426a8u, 0xca07c2dcb0cf26f7u,
|
||||
0xc9bcff6034c13052u, 0xfc89b393dd02f0b5u, 0xfc2c3f3841f17c67u, 0xbbac2078d443ace2u,
|
||||
0x9d9ba7832936edc0u, 0xd54b944b84aa4c0du, 0xc5029163f384a931u, 0x0a9e795e65d4df11u,
|
||||
0xf64335bcf065d37du, 0x4d4617b5ff4a16d5u, 0x99ea0196163fa42eu, 0x504bced1bf8e4e45u,
|
||||
0xc06481fb9bcf8d39u, 0xe45ec2862f71e1d6u, 0xf07da27a82c37088u, 0x5d767327bb4e5a4cu,
|
||||
0x964e858c91ba2655u, 0x3a6a07f8d510f86fu, 0xbbe226efb628afeau, 0x890489f70a55368bu,
|
||||
0xeadab0aba3b2dbe5u, 0x2b45ac74ccea842eu, 0x92c8ae6b464fc96fu, 0x3b0b8bc90012929du,
|
||||
0xb77ada0617e3bbcbu, 0x09ce6ebb40173744u, 0xe55990879ddcaabdu, 0xcc420a6a101d0515u,
|
||||
0x8f57fa54c2a9eab6u, 0x9fa946824a12232du, 0xb32df8e9f3546564u, 0x47939822dc96abf9u,
|
||||
0xdff9772470297ebdu, 0x59787e2b93bc56f7u, 0x8bfbea76c619ef36u, 0x57eb4edb3c55b65au,
|
||||
0xaefae51477a06b03u, 0xede622920b6b23f1u, 0xdab99e59958885c4u, 0xe95fab368e45ecedu,
|
||||
0x88b402f7fd75539bu, 0x11dbcb0218ebb414u, 0xaae103b5fcd2a881u, 0xd652bdc29f26a119u,
|
||||
0xd59944a37c0752a2u, 0x4be76d3346f0495fu, 0x857fcae62d8493a5u, 0x6f70a4400c562ddbu,
|
||||
0xa6dfbd9fb8e5b88eu, 0xcb4ccd500f6bb952u, 0xd097ad07a71f26b2u, 0x7e2000a41346a7a7u,
|
||||
0x825ecc24c873782fu, 0x8ed400668c0c28c8u, 0xa2f67f2dfa90563bu, 0x728900802f0f32fau,
|
||||
0xcbb41ef979346bcau, 0x4f2b40a03ad2ffb9u, 0xfea126b7d78186bcu, 0xe2f610c84987bfa8u,
|
||||
0x9f24b832e6b0f436u, 0x0dd9ca7d2df4d7c9u, 0xc6ede63fa05d3143u, 0x91503d1c79720dbbu,
|
||||
0xf8a95fcf88747d94u, 0x75a44c6397ce912au, 0x9b69dbe1b548ce7cu, 0xc986afbe3ee11abau,
|
||||
0xc24452da229b021bu, 0xfbe85badce996168u, 0xf2d56790ab41c2a2u, 0xfae27299423fb9c3u,
|
||||
0x97c560ba6b0919a5u, 0xdccd879fc967d41au, 0xbdb6b8e905cb600fu, 0x5400e987bbc1c920u,
|
||||
0xed246723473e3813u, 0x290123e9aab23b68u, 0x9436c0760c86e30bu, 0xf9a0b6720aaf6521u,
|
||||
0xb94470938fa89bceu, 0xf808e40e8d5b3e69u, 0xe7958cb87392c2c2u, 0xb60b1d1230b20e04u,
|
||||
0x90bd77f3483bb9b9u, 0xb1c6f22b5e6f48c2u, 0xb4ecd5f01a4aa828u, 0x1e38aeb6360b1af3u,
|
||||
0xe2280b6c20dd5232u, 0x25c6da63c38de1b0u, 0x8d590723948a535fu, 0x579c487e5a38ad0eu,
|
||||
0xb0af48ec79ace837u, 0x2d835a9df0c6d851u, 0xdcdb1b2798182244u, 0xf8e431456cf88e65u,
|
||||
0x8a08f0f8bf0f156bu, 0x1b8e9ecb641b58ffu, 0xac8b2d36eed2dac5u, 0xe272467e3d222f3fu,
|
||||
0xd7adf884aa879177u, 0x5b0ed81dcc6abb0fu, 0x86ccbb52ea94baeau, 0x98e947129fc2b4e9u,
|
||||
0xa87fea27a539e9a5u, 0x3f2398d747b36224u, 0xd29fe4b18e88640eu, 0x8eec7f0d19a03aadu,
|
||||
0x83a3eeeef9153e89u, 0x1953cf68300424acu, 0xa48ceaaab75a8e2bu, 0x5fa8c3423c052dd7u,
|
||||
0xcdb02555653131b6u, 0x3792f412cb06794du, 0x808e17555f3ebf11u, 0xe2bbd88bbee40bd0u,
|
||||
0xa0b19d2ab70e6ed6u, 0x5b6aceaeae9d0ec4u, 0xc8de047564d20a8bu, 0xf245825a5a445275u,
|
||||
0xfb158592be068d2eu, 0xeed6e2f0f0d56712u, 0x9ced737bb6c4183du, 0x55464dd69685606bu,
|
||||
0xc428d05aa4751e4cu, 0xaa97e14c3c26b886u, 0xf53304714d9265dfu, 0xd53dd99f4b3066a8u,
|
||||
0x993fe2c6d07b7fabu, 0xe546a8038efe4029u, 0xbf8fdb78849a5f96u, 0xde98520472bdd033u,
|
||||
0xef73d256a5c0f77cu, 0x963e66858f6d4440u, 0x95a8637627989aadu, 0xdde7001379a44aa8u,
|
||||
0xbb127c53b17ec159u, 0x5560c018580d5d52u, 0xe9d71b689dde71afu, 0xaab8f01e6e10b4a6u,
|
||||
0x9226712162ab070du, 0xcab3961304ca70e8u, 0xb6b00d69bb55c8d1u, 0x3d607b97c5fd0d22u,
|
||||
0xe45c10c42a2b3b05u, 0x8cb89a7db77c506au, 0x8eb98a7a9a5b04e3u, 0x77f3608e92adb242u,
|
||||
0xb267ed1940f1c61cu, 0x55f038b237591ed3u, 0xdf01e85f912e37a3u, 0x6b6c46dec52f6688u,
|
||||
0x8b61313bbabce2c6u, 0x2323ac4b3b3da015u, 0xae397d8aa96c1b77u, 0xabec975e0a0d081au,
|
||||
0xd9c7dced53c72255u, 0x96e7bd358c904a21u, 0x881cea14545c7575u, 0x7e50d64177da2e54u,
|
||||
0xaa242499697392d2u, 0xdde50bd1d5d0b9e9u, 0xd4ad2dbfc3d07787u, 0x955e4ec64b44e864u,
|
||||
0x84ec3c97da624ab4u, 0xbd5af13bef0b113eu, 0xa6274bbdd0fadd61u, 0xecb1ad8aeacdd58eu,
|
||||
0xcfb11ead453994bau, 0x67de18eda5814af2u, 0x81ceb32c4b43fcf4u, 0x80eacf948770ced7u,
|
||||
0xa2425ff75e14fc31u, 0xa1258379a94d028du, 0xcad2f7f5359a3b3eu, 0x096ee45813a04330u,
|
||||
0xfd87b5f28300ca0du, 0x8bca9d6e188853fcu, 0x9e74d1b791e07e48u, 0x775ea264cf55347eu,
|
||||
0xc612062576589ddau, 0x95364afe032a819eu, 0xf79687aed3eec551u, 0x3a83ddbd83f52205u,
|
||||
0x9abe14cd44753b52u, 0xc4926a9672793543u, 0xc16d9a0095928a27u, 0x75b7053c0f178294u,
|
||||
0xf1c90080baf72cb1u, 0x5324c68b12dd6339u, 0x971da05074da7beeu, 0xd3f6fc16ebca5e04u,
|
||||
0xbce5086492111aeau, 0x88f4bb1ca6bcf585u, 0xec1e4a7db69561a5u, 0x2b31e9e3d06c32e6u,
|
||||
0x9392ee8e921d5d07u, 0x3aff322e62439fd0u, 0xb877aa3236a4b449u, 0x09befeb9fad487c3u,
|
||||
0xe69594bec44de15bu, 0x4c2ebe687989a9b4u, 0x901d7cf73ab0acd9u, 0x0f9d37014bf60a11u,
|
||||
0xb424dc35095cd80fu, 0x538484c19ef38c95u, 0xe12e13424bb40e13u, 0x2865a5f206b06fbau,
|
||||
0x8cbccc096f5088cbu, 0xf93f87b7442e45d4u, 0xafebff0bcb24aafeu, 0xf78f69a51539d749u,
|
||||
0xdbe6fecebdedd5beu, 0xb573440e5a884d1cu, 0x89705f4136b4a597u, 0x31680a88f8953031u,
|
||||
0xabcc77118461cefcu, 0xfdc20d2b36ba7c3eu, 0xd6bf94d5e57a42bcu, 0x3d32907604691b4du,
|
||||
0x8637bd05af6c69b5u, 0xa63f9a49c2c1b110u, 0xa7c5ac471b478423u, 0x0fcf80dc33721d54u,
|
||||
0xd1b71758e219652bu, 0xd3c36113404ea4a9u, 0x83126e978d4fdf3bu, 0x645a1cac083126eau,
|
||||
0xa3d70a3d70a3d70au, 0x3d70a3d70a3d70a4u, 0xccccccccccccccccu, 0xcccccccccccccccdu,
|
||||
0x8000000000000000u, 0x0000000000000000u, 0xa000000000000000u, 0x0000000000000000u,
|
||||
0xc800000000000000u, 0x0000000000000000u, 0xfa00000000000000u, 0x0000000000000000u,
|
||||
0x9c40000000000000u, 0x0000000000000000u, 0xc350000000000000u, 0x0000000000000000u,
|
||||
0xf424000000000000u, 0x0000000000000000u, 0x9896800000000000u, 0x0000000000000000u,
|
||||
0xbebc200000000000u, 0x0000000000000000u, 0xee6b280000000000u, 0x0000000000000000u,
|
||||
0x9502f90000000000u, 0x0000000000000000u, 0xba43b74000000000u, 0x0000000000000000u,
|
||||
0xe8d4a51000000000u, 0x0000000000000000u, 0x9184e72a00000000u, 0x0000000000000000u,
|
||||
0xb5e620f480000000u, 0x0000000000000000u, 0xe35fa931a0000000u, 0x0000000000000000u,
|
||||
0x8e1bc9bf04000000u, 0x0000000000000000u, 0xb1a2bc2ec5000000u, 0x0000000000000000u,
|
||||
0xde0b6b3a76400000u, 0x0000000000000000u, 0x8ac7230489e80000u, 0x0000000000000000u,
|
||||
0xad78ebc5ac620000u, 0x0000000000000000u, 0xd8d726b7177a8000u, 0x0000000000000000u,
|
||||
0x878678326eac9000u, 0x0000000000000000u, 0xa968163f0a57b400u, 0x0000000000000000u,
|
||||
0xd3c21bcecceda100u, 0x0000000000000000u, 0x84595161401484a0u, 0x0000000000000000u,
|
||||
0xa56fa5b99019a5c8u, 0x0000000000000000u, 0xcecb8f27f4200f3au, 0x0000000000000000u,
|
||||
0x813f3978f8940984u, 0x4000000000000000u, 0xa18f07d736b90be5u, 0x5000000000000000u,
|
||||
0xc9f2c9cd04674edeu, 0xa400000000000000u, 0xfc6f7c4045812296u, 0x4d00000000000000u,
|
||||
0x9dc5ada82b70b59du, 0xf020000000000000u, 0xc5371912364ce305u, 0x6c28000000000000u,
|
||||
0xf684df56c3e01bc6u, 0xc732000000000000u, 0x9a130b963a6c115cu, 0x3c7f400000000000u,
|
||||
0xc097ce7bc90715b3u, 0x4b9f100000000000u, 0xf0bdc21abb48db20u, 0x1e86d40000000000u,
|
||||
0x96769950b50d88f4u, 0x1314448000000000u, 0xbc143fa4e250eb31u, 0x17d955a000000000u,
|
||||
0xeb194f8e1ae525fdu, 0x5dcfab0800000000u, 0x92efd1b8d0cf37beu, 0x5aa1cae500000000u,
|
||||
0xb7abc627050305adu, 0xf14a3d9e40000000u, 0xe596b7b0c643c719u, 0x6d9ccd05d0000000u,
|
||||
0x8f7e32ce7bea5c6fu, 0xe4820023a2000000u, 0xb35dbf821ae4f38bu, 0xdda2802c8a800000u,
|
||||
0xe0352f62a19e306eu, 0xd50b2037ad200000u, 0x8c213d9da502de45u, 0x4526f422cc340000u,
|
||||
0xaf298d050e4395d6u, 0x9670b12b7f410000u, 0xdaf3f04651d47b4cu, 0x3c0cdd765f114000u,
|
||||
0x88d8762bf324cd0fu, 0xa5880a69fb6ac800u, 0xab0e93b6efee0053u, 0x8eea0d047a457a00u,
|
||||
0xd5d238a4abe98068u, 0x72a4904598d6d880u, 0x85a36366eb71f041u, 0x47a6da2b7f864750u,
|
||||
0xa70c3c40a64e6c51u, 0x999090b65f67d924u, 0xd0cf4b50cfe20765u, 0xfff4b4e3f741cf6du,
|
||||
0x82818f1281ed449fu, 0xbff8f10e7a8921a4u, 0xa321f2d7226895c7u, 0xaff72d52192b6a0du,
|
||||
0xcbea6f8ceb02bb39u, 0x9bf4f8a69f764490u, 0xfee50b7025c36a08u, 0x02f236d04753d5b4u,
|
||||
0x9f4f2726179a2245u, 0x01d762422c946590u, 0xc722f0ef9d80aad6u, 0x424d3ad2b7b97ef5u,
|
||||
0xf8ebad2b84e0d58bu, 0xd2e0898765a7deb2u, 0x9b934c3b330c8577u, 0x63cc55f49f88eb2fu,
|
||||
0xc2781f49ffcfa6d5u, 0x3cbf6b71c76b25fbu, 0xf316271c7fc3908au, 0x8bef464e3945ef7au,
|
||||
0x97edd871cfda3a56u, 0x97758bf0e3cbb5acu, 0xbde94e8e43d0c8ecu, 0x3d52eeed1cbea317u,
|
||||
0xed63a231d4c4fb27u, 0x4ca7aaa863ee4bddu, 0x945e455f24fb1cf8u, 0x8fe8caa93e74ef6au,
|
||||
0xb975d6b6ee39e436u, 0xb3e2fd538e122b44u, 0xe7d34c64a9c85d44u, 0x60dbbca87196b616u,
|
||||
0x90e40fbeea1d3a4au, 0xbc8955e946fe31cdu, 0xb51d13aea4a488ddu, 0x6babab6398bdbe41u,
|
||||
0xe264589a4dcdab14u, 0xc696963c7eed2dd1u, 0x8d7eb76070a08aecu, 0xfc1e1de5cf543ca2u,
|
||||
0xb0de65388cc8ada8u, 0x3b25a55f43294bcbu, 0xdd15fe86affad912u, 0x49ef0eb713f39ebeu,
|
||||
0x8a2dbf142dfcc7abu, 0x6e3569326c784337u, 0xacb92ed9397bf996u, 0x49c2c37f07965404u,
|
||||
0xd7e77a8f87daf7fbu, 0xdc33745ec97be906u, 0x86f0ac99b4e8dafdu, 0x69a028bb3ded71a3u,
|
||||
0xa8acd7c0222311bcu, 0xc40832ea0d68ce0cu, 0xd2d80db02aabd62bu, 0xf50a3fa490c30190u,
|
||||
0x83c7088e1aab65dbu, 0x792667c6da79e0fau, 0xa4b8cab1a1563f52u, 0x577001b891185938u,
|
||||
0xcde6fd5e09abcf26u, 0xed4c0226b55e6f86u, 0x80b05e5ac60b6178u, 0x544f8158315b05b4u,
|
||||
0xa0dc75f1778e39d6u, 0x696361ae3db1c721u, 0xc913936dd571c84cu, 0x03bc3a19cd1e38e9u,
|
||||
0xfb5878494ace3a5fu, 0x04ab48a04065c723u, 0x9d174b2dcec0e47bu, 0x62eb0d64283f9c76u,
|
||||
0xc45d1df942711d9au, 0x3ba5d0bd324f8394u, 0xf5746577930d6500u, 0xca8f44ec7ee36479u,
|
||||
0x9968bf6abbe85f20u, 0x7e998b13cf4e1ecbu, 0xbfc2ef456ae276e8u, 0x9e3fedd8c321a67eu,
|
||||
0xefb3ab16c59b14a2u, 0xc5cfe94ef3ea101eu, 0x95d04aee3b80ece5u, 0xbba1f1d158724a12u,
|
||||
0xbb445da9ca61281fu, 0x2a8a6e45ae8edc97u, 0xea1575143cf97226u, 0xf52d09d71a3293bdu,
|
||||
0x924d692ca61be758u, 0x593c2626705f9c56u, 0xb6e0c377cfa2e12eu, 0x6f8b2fb00c77836cu,
|
||||
0xe498f455c38b997au, 0x0b6dfb9c0f956447u, 0x8edf98b59a373fecu, 0x4724bd4189bd5eacu,
|
||||
0xb2977ee300c50fe7u, 0x58edec91ec2cb657u, 0xdf3d5e9bc0f653e1u, 0x2f2967b66737e3edu,
|
||||
0x8b865b215899f46cu, 0xbd79e0d20082ee74u, 0xae67f1e9aec07187u, 0xecd8590680a3aa11u,
|
||||
0xda01ee641a708de9u, 0xe80e6f4820cc9495u, 0x884134fe908658b2u, 0x3109058d147fdcddu,
|
||||
0xaa51823e34a7eedeu, 0xbd4b46f0599fd415u, 0xd4e5e2cdc1d1ea96u, 0x6c9e18ac7007c91au,
|
||||
0x850fadc09923329eu, 0x03e2cf6bc604ddb0u, 0xa6539930bf6bff45u, 0x84db8346b786151cu,
|
||||
0xcfe87f7cef46ff16u, 0xe612641865679a63u, 0x81f14fae158c5f6eu, 0x4fcb7e8f3f60c07eu,
|
||||
0xa26da3999aef7749u, 0xe3be5e330f38f09du, 0xcb090c8001ab551cu, 0x5cadf5bfd3072cc5u,
|
||||
0xfdcb4fa002162a63u, 0x73d9732fc7c8f7f6u, 0x9e9f11c4014dda7eu, 0x2867e7fddcdd9afau,
|
||||
0xc646d63501a1511du, 0xb281e1fd541501b8u, 0xf7d88bc24209a565u, 0x1f225a7ca91a4226u,
|
||||
0x9ae757596946075fu, 0x3375788de9b06958u, 0xc1a12d2fc3978937u, 0x0052d6b1641c83aeu,
|
||||
0xf209787bb47d6b84u, 0xc0678c5dbd23a49au, 0x9745eb4d50ce6332u, 0xf840b7ba963646e0u,
|
||||
0xbd176620a501fbffu, 0xb650e5a93bc3d898u, 0xec5d3fa8ce427affu, 0xa3e51f138ab4cebeu,
|
||||
0x93ba47c980e98cdfu, 0xc66f336c36b10137u, 0xb8a8d9bbe123f017u, 0xb80b0047445d4184u,
|
||||
0xe6d3102ad96cec1du, 0xa60dc059157491e5u, 0x9043ea1ac7e41392u, 0x87c89837ad68db2fu,
|
||||
0xb454e4a179dd1877u, 0x29babe4598c311fbu, 0xe16a1dc9d8545e94u, 0xf4296dd6fef3d67au,
|
||||
0x8ce2529e2734bb1du, 0x1899e4a65f58660cu, 0xb01ae745b101e9e4u, 0x5ec05dcff72e7f8fu,
|
||||
0xdc21a1171d42645du, 0x76707543f4fa1f73u, 0x899504ae72497ebau, 0x6a06494a791c53a8u,
|
||||
0xabfa45da0edbde69u, 0x0487db9d17636892u, 0xd6f8d7509292d603u, 0x45a9d2845d3c42b6u,
|
||||
0x865b86925b9bc5c2u, 0x0b8a2392ba45a9b2u, 0xa7f26836f282b732u, 0x8e6cac7768d7141eu,
|
||||
0xd1ef0244af2364ffu, 0x3207d795430cd926u, 0x8335616aed761f1fu, 0x7f44e6bd49e807b8u,
|
||||
0xa402b9c5a8d3a6e7u, 0x5f16206c9c6209a6u, 0xcd036837130890a1u, 0x36dba887c37a8c0fu,
|
||||
0x802221226be55a64u, 0xc2494954da2c9789u, 0xa02aa96b06deb0fdu, 0xf2db9baa10b7bd6cu,
|
||||
0xc83553c5c8965d3du, 0x6f92829494e5acc7u, 0xfa42a8b73abbf48cu, 0xcb772339ba1f17f9u,
|
||||
0x9c69a97284b578d7u, 0xff2a760414536efbu, 0xc38413cf25e2d70du, 0xfef5138519684abau,
|
||||
0xf46518c2ef5b8cd1u, 0x7eb258665fc25d69u, 0x98bf2f79d5993802u, 0xef2f773ffbd97a61u,
|
||||
0xbeeefb584aff8603u, 0xaafb550ffacfd8fau, 0xeeaaba2e5dbf6784u, 0x95ba2a53f983cf38u,
|
||||
0x952ab45cfa97a0b2u, 0xdd945a747bf26183u, 0xba756174393d88dfu, 0x94f971119aeef9e4u,
|
||||
0xe912b9d1478ceb17u, 0x7a37cd5601aab85du, 0x91abb422ccb812eeu, 0xac62e055c10ab33au,
|
||||
0xb616a12b7fe617aau, 0x577b986b314d6009u, 0xe39c49765fdf9d94u, 0xed5a7e85fda0b80bu,
|
||||
0x8e41ade9fbebc27du, 0x14588f13be847307u, 0xb1d219647ae6b31cu, 0x596eb2d8ae258fc8u,
|
||||
0xde469fbd99a05fe3u, 0x6fca5f8ed9aef3bbu, 0x8aec23d680043beeu, 0x25de7bb9480d5854u,
|
||||
0xada72ccc20054ae9u, 0xaf561aa79a10ae6au, 0xd910f7ff28069da4u, 0x1b2ba1518094da04u,
|
||||
0x87aa9aff79042286u, 0x90fb44d2f05d0842u, 0xa99541bf57452b28u, 0x353a1607ac744a53u,
|
||||
0xd3fa922f2d1675f2u, 0x42889b8997915ce8u, 0x847c9b5d7c2e09b7u, 0x69956135febada11u,
|
||||
0xa59bc234db398c25u, 0x43fab9837e699095u, 0xcf02b2c21207ef2eu, 0x94f967e45e03f4bbu,
|
||||
0x8161afb94b44f57du, 0x1d1be0eebac278f5u, 0xa1ba1ba79e1632dcu, 0x6462d92a69731732u,
|
||||
0xca28a291859bbf93u, 0x7d7b8f7503cfdcfeu, 0xfcb2cb35e702af78u, 0x5cda735244c3d43eu,
|
||||
0x9defbf01b061adabu, 0x3a0888136afa64a7u, 0xc56baec21c7a1916u, 0x088aaa1845b8fdd0u,
|
||||
0xf6c69a72a3989f5bu, 0x8aad549e57273d45u, 0x9a3c2087a63f6399u, 0x36ac54e2f678864bu,
|
||||
0xc0cb28a98fcf3c7fu, 0x84576a1bb416a7ddu, 0xf0fdf2d3f3c30b9fu, 0x656d44a2a11c51d5u,
|
||||
0x969eb7c47859e743u, 0x9f644ae5a4b1b325u, 0xbc4665b596706114u, 0x873d5d9f0dde1feeu,
|
||||
0xeb57ff22fc0c7959u, 0xa90cb506d155a7eau, 0x9316ff75dd87cbd8u, 0x09a7f12442d588f2u,
|
||||
0xb7dcbf5354e9beceu, 0x0c11ed6d538aeb2fu, 0xe5d3ef282a242e81u, 0x8f1668c8a86da5fau,
|
||||
0x8fa475791a569d10u, 0xf96e017d694487bcu, 0xb38d92d760ec4455u, 0x37c981dcc395a9acu,
|
||||
0xe070f78d3927556au, 0x85bbe253f47b1417u, 0x8c469ab843b89562u, 0x93956d7478ccec8eu,
|
||||
0xaf58416654a6babbu, 0x387ac8d1970027b2u, 0xdb2e51bfe9d0696au, 0x06997b05fcc0319eu,
|
||||
0x88fcf317f22241e2u, 0x441fece3bdf81f03u, 0xab3c2fddeeaad25au, 0xd527e81cad7626c3u,
|
||||
0xd60b3bd56a5586f1u, 0x8a71e223d8d3b074u, 0x85c7056562757456u, 0xf6872d5667844e49u,
|
||||
0xa738c6bebb12d16cu, 0xb428f8ac016561dbu, 0xd106f86e69d785c7u, 0xe13336d701beba52u,
|
||||
0x82a45b450226b39cu, 0xecc0024661173473u, 0xa34d721642b06084u, 0x27f002d7f95d0190u,
|
||||
0xcc20ce9bd35c78a5u, 0x31ec038df7b441f4u, 0xff290242c83396ceu, 0x7e67047175a15271u,
|
||||
0x9f79a169bd203e41u, 0x0f0062c6e984d386u, 0xc75809c42c684dd1u, 0x52c07b78a3e60868u,
|
||||
0xf92e0c3537826145u, 0xa7709a56ccdf8a82u, 0x9bbcc7a142b17ccbu, 0x88a66076400bb691u,
|
||||
0xc2abf989935ddbfeu, 0x6acff893d00ea435u, 0xf356f7ebf83552feu, 0x0583f6b8c4124d43u,
|
||||
0x98165af37b2153deu, 0xc3727a337a8b704au, 0xbe1bf1b059e9a8d6u, 0x744f18c0592e4c5cu,
|
||||
0xeda2ee1c7064130cu, 0x1162def06f79df73u, 0x9485d4d1c63e8be7u, 0x8addcb5645ac2ba8u,
|
||||
0xb9a74a0637ce2ee1u, 0x6d953e2bd7173692u, 0xe8111c87c5c1ba99u, 0xc8fa8db6ccdd0437u,
|
||||
0x910ab1d4db9914a0u, 0x1d9c9892400a22a2u, 0xb54d5e4a127f59c8u, 0x2503beb6d00cab4bu,
|
||||
0xe2a0b5dc971f303au, 0x2e44ae64840fd61du, 0x8da471a9de737e24u, 0x5ceaecfed289e5d2u,
|
||||
0xb10d8e1456105dadu, 0x7425a83e872c5f47u, 0xdd50f1996b947518u, 0xd12f124e28f77719u,
|
||||
0x8a5296ffe33cc92fu, 0x82bd6b70d99aaa6fu, 0xace73cbfdc0bfb7bu, 0x636cc64d1001550bu,
|
||||
0xd8210befd30efa5au, 0x3c47f7e05401aa4eu, 0x8714a775e3e95c78u, 0x65acfaec34810a71u,
|
||||
0xa8d9d1535ce3b396u, 0x7f1839a741a14d0du, 0xd31045a8341ca07cu, 0x1ede48111209a050u,
|
||||
0x83ea2b892091e44du, 0x934aed0aab460432u, 0xa4e4b66b68b65d60u, 0xf81da84d5617853fu,
|
||||
0xce1de40642e3f4b9u, 0x36251260ab9d668eu, 0x80d2ae83e9ce78f3u, 0xc1d72b7c6b426019u,
|
||||
0xa1075a24e4421730u, 0xb24cf65b8612f81fu, 0xc94930ae1d529cfcu, 0xdee033f26797b627u,
|
||||
0xfb9b7cd9a4a7443cu, 0x169840ef017da3b1u, 0x9d412e0806e88aa5u, 0x8e1f289560ee864eu,
|
||||
0xc491798a08a2ad4eu, 0xf1a6f2bab92a27e2u, 0xf5b5d7ec8acb58a2u, 0xae10af696774b1dbu,
|
||||
0x9991a6f3d6bf1765u, 0xacca6da1e0a8ef29u, 0xbff610b0cc6edd3fu, 0x17fd090a58d32af3u,
|
||||
0xeff394dcff8a948eu, 0xddfc4b4cef07f5b0u, 0x95f83d0a1fb69cd9u, 0x4abdaf101564f98eu,
|
||||
0xbb764c4ca7a4440fu, 0x9d6d1ad41abe37f1u, 0xea53df5fd18d5513u, 0x84c86189216dc5edu,
|
||||
0x92746b9be2f8552cu, 0x32fd3cf5b4e49bb4u, 0xb7118682dbb66a77u, 0x3fbc8c33221dc2a1u,
|
||||
0xe4d5e82392a40515u, 0x0fabaf3feaa5334au, 0x8f05b1163ba6832du, 0x29cb4d87f2a7400eu,
|
||||
0xb2c71d5bca9023f8u, 0x743e20e9ef511012u, 0xdf78e4b2bd342cf6u, 0x914da9246b255416u,
|
||||
0x8bab8eefb6409c1au, 0x1ad089b6c2f7548eu, 0xae9672aba3d0c320u, 0xa184ac2473b529b1u,
|
||||
0xda3c0f568cc4f3e8u, 0xc9e5d72d90a2741eu, 0x8865899617fb1871u, 0x7e2fa67c7a658892u,
|
||||
0xaa7eebfb9df9de8du, 0xddbb901b98feeab7u, 0xd51ea6fa85785631u, 0x552a74227f3ea565u,
|
||||
0x8533285c936b35deu, 0xd53a88958f87275fu, 0xa67ff273b8460356u, 0x8a892abaf368f137u,
|
||||
0xd01fef10a657842cu, 0x2d2b7569b0432d85u, 0x8213f56a67f6b29bu, 0x9c3b29620e29fc73u,
|
||||
0xa298f2c501f45f42u, 0x8349f3ba91b47b8fu, 0xcb3f2f7642717713u, 0x241c70a936219a73u,
|
||||
0xfe0efb53d30dd4d7u, 0xed238cd383aa0110u, 0x9ec95d1463e8a506u, 0xf4363804324a40aau,
|
||||
0xc67bb4597ce2ce48u, 0xb143c6053edcd0d5u, 0xf81aa16fdc1b81dau, 0xdd94b7868e94050au,
|
||||
0x9b10a4e5e9913128u, 0xca7cf2b4191c8326u, 0xc1d4ce1f63f57d72u, 0xfd1c2f611f63a3f0u,
|
||||
0xf24a01a73cf2dccfu, 0xbc633b39673c8cecu, 0x976e41088617ca01u, 0xd5be0503e085d813u,
|
||||
0xbd49d14aa79dbc82u, 0x4b2d8644d8a74e18u, 0xec9c459d51852ba2u, 0xddf8e7d60ed1219eu,
|
||||
0x93e1ab8252f33b45u, 0xcabb90e5c942b503u, 0xb8da1662e7b00a17u, 0x3d6a751f3b936243u,
|
||||
0xe7109bfba19c0c9du, 0x0cc512670a783ad4u, 0x906a617d450187e2u, 0x27fb2b80668b24c5u,
|
||||
0xb484f9dc9641e9dau, 0xb1f9f660802dedf6u, 0xe1a63853bbd26451u, 0x5e7873f8a0396973u,
|
||||
0x8d07e33455637eb2u, 0xdb0b487b6423e1e8u, 0xb049dc016abc5e5fu, 0x91ce1a9a3d2cda62u,
|
||||
0xdc5c5301c56b75f7u, 0x7641a140cc7810fbu, 0x89b9b3e11b6329bau, 0xa9e904c87fcb0a9du,
|
||||
0xac2820d9623bf429u, 0x546345fa9fbdcd44u, 0xd732290fbacaf133u, 0xa97c177947ad4095u,
|
||||
0x867f59a9d4bed6c0u, 0x49ed8eabcccc485du, 0xa81f301449ee8c70u, 0x5c68f256bfff5a74u,
|
||||
0xd226fc195c6a2f8cu, 0x73832eec6fff3111u, 0x83585d8fd9c25db7u, 0xc831fd53c5ff7eabu,
|
||||
0xa42e74f3d032f525u, 0xba3e7ca8b77f5e55u, 0xcd3a1230c43fb26fu, 0x28ce1bd2e55f35ebu,
|
||||
0x80444b5e7aa7cf85u, 0x7980d163cf5b81b3u, 0xa0555e361951c366u, 0xd7e105bcc332621fu,
|
||||
0xc86ab5c39fa63440u, 0x8dd9472bf3fefaa7u, 0xfa856334878fc150u, 0xb14f98f6f0feb951u,
|
||||
0x9c935e00d4b9d8d2u, 0x6ed1bf9a569f33d3u, 0xc3b8358109e84f07u, 0x0a862f80ec4700c8u,
|
||||
0xf4a642e14c6262c8u, 0xcd27bb612758c0fau, 0x98e7e9cccfbd7dbdu, 0x8038d51cb897789cu,
|
||||
0xbf21e44003acdd2cu, 0xe0470a63e6bd56c3u, 0xeeea5d5004981478u, 0x1858ccfce06cac74u,
|
||||
0x95527a5202df0ccbu, 0x0f37801e0c43ebc8u, 0xbaa718e68396cffdu, 0xd30560258f54e6bau,
|
||||
0xe950df20247c83fdu, 0x47c6b82ef32a2069u, 0x91d28b7416cdd27eu, 0x4cdc331d57fa5441u,
|
||||
0xb6472e511c81471du, 0xe0133fe4adf8e952u, 0xe3d8f9e563a198e5u, 0x58180fddd97723a6u,
|
||||
0x8e679c2f5e44ff8fu, 0x570f09eaa7ea7648u,
|
||||
}
|
||||
};
|
||||
return table;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint64_t
|
||||
#include <cstdint> // uint64_t, uint8_t
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#include <nlohmann/detail/bit_ops.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
// Optional SIMD backend for bulk UTF-8 validation. This is an opt-in external
|
||||
@@ -69,18 +71,12 @@ inline std::size_t find_string_special(const unsigned char* data, std::size_t n)
|
||||
std::size_t i = 0;
|
||||
for (; i + 8 <= n; i += 8)
|
||||
{
|
||||
std::uint64_t word = 0;
|
||||
std::memcpy(&word, data + i, sizeof(word));
|
||||
if (swar_string_special(word) != 0)
|
||||
const std::uint64_t special = swar_string_special(read_eight_bytes(data + i));
|
||||
if (special != 0)
|
||||
{
|
||||
// a special byte is in this word; locate it (endian-agnostic)
|
||||
for (std::size_t j = 0; j < 8; ++j)
|
||||
{
|
||||
if (is_string_special(data[i + j]))
|
||||
{
|
||||
return i + j;
|
||||
}
|
||||
}
|
||||
// the lowest flagged byte is the first special one: the borrows of
|
||||
// the subtractions can only flag bytes above a true hit
|
||||
return i + (static_cast<std::size_t>(count_trailing_zeros(special)) / 8);
|
||||
}
|
||||
}
|
||||
for (; i < n; ++i)
|
||||
@@ -114,8 +110,7 @@ inline std::size_t find_ascii_copyable_run(const unsigned char* data, std::size_
|
||||
std::size_t i = 0;
|
||||
for (; i + 8 <= n; i += 8)
|
||||
{
|
||||
std::uint64_t v = 0;
|
||||
std::memcpy(&v, data + i, sizeof(v));
|
||||
const std::uint64_t v = read_eight_bytes(data + i);
|
||||
const std::uint64_t q = v ^ 0x2222222222222222ull; // '"' (0x22)
|
||||
const std::uint64_t b = v ^ 0x5C5C5C5C5C5C5C5Cull; // '\\' (0x5C)
|
||||
const std::uint64_t d = v ^ 0x7F7F7F7F7F7F7F7Full; // DEL (0x7F)
|
||||
@@ -126,7 +121,9 @@ inline std::size_t find_ascii_copyable_run(const unsigned char* data, std::size_
|
||||
| (v & high); // >= 0x80
|
||||
if (stop != 0)
|
||||
{
|
||||
break;
|
||||
// the lowest flagged byte is the first one to stop at (see
|
||||
// find_string_special())
|
||||
return i + (static_cast<std::size_t>(count_trailing_zeros(stop)) / 8);
|
||||
}
|
||||
}
|
||||
for (; i < n; ++i)
|
||||
@@ -253,12 +250,18 @@ inline std::size_t scalar_string_bulk_run(const unsigned char* data, std::size_t
|
||||
{
|
||||
break; // end of buffer, or a quote/escape/control byte
|
||||
}
|
||||
const std::size_t seq = validate_one_utf8(data + pos, n - pos);
|
||||
if (seq == 0)
|
||||
// a run of multi-byte sequences (e.g. CJK text) is validated sequence
|
||||
// by sequence without searching for the next special byte in between
|
||||
do
|
||||
{
|
||||
break; // ill-formed or truncated: let the byte path diagnose it
|
||||
const std::size_t seq = validate_one_utf8(data + pos, n - pos);
|
||||
if (seq == 0)
|
||||
{
|
||||
return pos; // ill-formed or truncated: let the byte path diagnose it
|
||||
}
|
||||
pos += seq;
|
||||
}
|
||||
pos += seq;
|
||||
while (pos < n && data[pos] >= 0x80u);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@@ -273,8 +276,7 @@ inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t
|
||||
std::size_t i = 0;
|
||||
for (; i + 8 <= n; i += 8)
|
||||
{
|
||||
std::uint64_t v = 0;
|
||||
std::memcpy(&v, data + i, sizeof(v));
|
||||
const std::uint64_t v = read_eight_bytes(data + i);
|
||||
const std::uint64_t q = v ^ 0x2222222222222222ull;
|
||||
const std::uint64_t b = v ^ 0x5C5C5C5C5C5C5C5Cull;
|
||||
const std::uint64_t hit = ((q - ones) & ~q & high)
|
||||
@@ -282,14 +284,8 @@ inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t
|
||||
| ((v - 0x2020202020202020ull) & ~v & high);
|
||||
if (hit != 0)
|
||||
{
|
||||
for (std::size_t j = 0; j < 8; ++j)
|
||||
{
|
||||
const unsigned char c = data[i + j];
|
||||
if (c == '\"' || c == '\\' || c < 0x20u)
|
||||
{
|
||||
return i + j;
|
||||
}
|
||||
}
|
||||
// the lowest flagged byte is the first delimiter (see find_string_special())
|
||||
return i + (static_cast<std::size_t>(count_trailing_zeros(hit)) / 8);
|
||||
}
|
||||
}
|
||||
for (; i < n; ++i)
|
||||
@@ -320,5 +316,50 @@ inline std::size_t string_bulk_run(const unsigned char* data, std::size_t n) noe
|
||||
return scalar_string_bulk_run(data, n);
|
||||
}
|
||||
|
||||
// Decode the 4 hex digits at [data, data+4) - the digits following a `\u`
|
||||
// escape - into a codepoint 0x0000..0xFFFF via one table lookup per byte
|
||||
// (after yyjson's read_hex_u16), or return -1 if any of the 4 bytes is not a
|
||||
// hex digit ('0'..'9', 'A'..'F', 'a'..'f'). The caller must already have
|
||||
// checked that 4 bytes are available; used by lexer::get_codepoint()'s
|
||||
// contiguous fast path. On -1 it falls back to the byte-at-a-time loop, which
|
||||
// stops at the first invalid digit, so the reported error and position are
|
||||
// unaffected by this fast path.
|
||||
inline int hex_codepoint(const unsigned char* data) noexcept
|
||||
{
|
||||
static const std::array<std::uint8_t, 256> hex_digit_table = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
{
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 00..0F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 10..1F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 20..2F
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 30..3F ('0'..'9')
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 40..4F ('A'..'F')
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 50..5F
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 60..6F ('a'..'f')
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 70..7F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 80..8F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 90..9F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0..AF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B0..BF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C0..CF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D0..DF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // E0..EF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // F0..FF
|
||||
}
|
||||
};
|
||||
|
||||
const std::uint8_t d0 = hex_digit_table[data[0]];
|
||||
const std::uint8_t d1 = hex_digit_table[data[1]];
|
||||
const std::uint8_t d2 = hex_digit_table[data[2]];
|
||||
const std::uint8_t d3 = hex_digit_table[data[3]];
|
||||
// every valid digit is <= 0xF; the combined OR only exceeds it if at
|
||||
// least one of the four bytes was not a hex digit (looked up as 0xFF)
|
||||
if ((d0 | d1 | d2 | d3) > 0x0F)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (d0 << 12) | (d1 << 8) | (d2 << 4) | d3;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstring> // memcpy
|
||||
#include <new> // operator new, placement new
|
||||
#include <string> // string
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
#include <nlohmann/detail/view/node.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// storage of a parsed document; heap-allocated (header and an initial node
|
||||
/// array in one block) so that views survive moves of the owning document
|
||||
struct document_data
|
||||
{
|
||||
const char* src = nullptr;
|
||||
std::size_t size = 0;
|
||||
node* tape = nullptr;
|
||||
std::size_t tape_size = 0;
|
||||
std::size_t tape_cap = 0;
|
||||
node* inline_tape = nullptr; ///< node array allocated together with this header
|
||||
std::size_t inline_cap = 0;
|
||||
std::string arena{}; ///< decoded strings that contained escapes // NOLINT(readability-redundant-member-init)
|
||||
std::string owned{}; ///< owned copy of the input, if any // NOLINT(readability-redundant-member-init)
|
||||
std::array<const char*, 4> base = {{nullptr, nullptr, nullptr, nullptr}}; ///< string bases: source, arena (indexed by flags & node_flags::storage)
|
||||
bool discarded = true;
|
||||
|
||||
/// one allocation for the header and room for `nodes` nodes; large
|
||||
/// documents get a separate node array instead (so it can be trimmed)
|
||||
static document_data* create(std::size_t nodes)
|
||||
{
|
||||
nodes = nodes <= 256 ? nodes : 0;
|
||||
void* mem = ::operator new (sizeof(document_data) + (nodes * sizeof(node)));
|
||||
auto* d = new (mem) document_data(); // NOLINT(cppcoreguidelines-owning-memory): owned by the returned pointer, freed by deleter
|
||||
// (aligned: sizeof is a multiple of the alignment; through void*, as GCC's -Wcast-align wants)
|
||||
d->inline_tape = static_cast<node*>(static_cast<void*>(static_cast<char*>(mem) + sizeof(document_data))); // NOLINT(bugprone-casting-through-void)
|
||||
d->inline_cap = nodes;
|
||||
d->tape = d->inline_tape;
|
||||
d->tape_cap = nodes;
|
||||
return d;
|
||||
}
|
||||
|
||||
struct deleter
|
||||
{
|
||||
void operator()(document_data* d) const noexcept
|
||||
{
|
||||
d->~document_data();
|
||||
::operator delete (d);
|
||||
}
|
||||
};
|
||||
|
||||
document_data() noexcept = default;
|
||||
document_data(const document_data&) = delete;
|
||||
document_data(document_data&&) = delete;
|
||||
document_data& operator=(const document_data&) = delete;
|
||||
document_data& operator=(document_data&&) = delete;
|
||||
~document_data()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void release() noexcept
|
||||
{
|
||||
if (tape != inline_tape)
|
||||
{
|
||||
::operator delete (tape);
|
||||
}
|
||||
tape = inline_tape;
|
||||
tape_cap = inline_cap;
|
||||
}
|
||||
|
||||
/// make room for n nodes; keeps the first tape_size nodes
|
||||
void reserve(std::size_t n)
|
||||
{
|
||||
if (n <= tape_cap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
node* fresh = static_cast<node*>(::operator new (n * sizeof(node)));
|
||||
if (tape_size != 0)
|
||||
{
|
||||
std::memcpy(fresh, tape, tape_size * sizeof(node));
|
||||
}
|
||||
release();
|
||||
tape = fresh;
|
||||
tape_cap = n;
|
||||
}
|
||||
|
||||
const char* str(const node& n) const noexcept
|
||||
{
|
||||
return base[n.flags & node_flags::storage] + n.off;
|
||||
}
|
||||
|
||||
/// the node after n's subtree (containers span `next` nodes, scalars one)
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE const node* after(const node* n) noexcept
|
||||
{
|
||||
return n + (is_container(*n) ? n->next : 1u);
|
||||
}
|
||||
|
||||
/// first element (array) or first key (object) of a container
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE const node* first_child(const node* n) noexcept
|
||||
{
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/// end of the elements of a container
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE const node* child_end(const node* n) noexcept
|
||||
{
|
||||
return n + n->next;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -0,0 +1,63 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
// Macros of json_view.hpp and its detail headers. json.hpp undefines its own
|
||||
// macros at its end (macro_unscope.hpp), so the view defines the few it needs
|
||||
// under its own prefix; json_view.hpp undefines them all at its end
|
||||
// (detail/view/macro_unscope.hpp). Configuration that json.hpp undefines is
|
||||
// read from detail::abi_config instead.
|
||||
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
#define NLOHMANN_VIEW_HAS_CPP_17 1
|
||||
#else
|
||||
#define NLOHMANN_VIEW_HAS_CPP_17 0
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define NLOHMANN_VIEW_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define NLOHMANN_VIEW_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#define NLOHMANN_VIEW_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#define NLOHMANN_VIEW_NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define NLOHMANN_VIEW_LIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_UNLIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_ALWAYS_INLINE __forceinline
|
||||
#define NLOHMANN_VIEW_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
#define NLOHMANN_VIEW_LIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_UNLIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_ALWAYS_INLINE inline
|
||||
#define NLOHMANN_VIEW_NOINLINE
|
||||
#endif
|
||||
|
||||
// exceptions as in json.hpp (JSON_NOEXCEPTION, JSON_THROW_USER)
|
||||
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
|
||||
#define NLOHMANN_VIEW_THROW(exception) throw exception
|
||||
#else
|
||||
#include <cstdlib>
|
||||
// (the exception is built first, so that the arguments of the throwing
|
||||
// helpers count as used; the program ends anyway)
|
||||
#define NLOHMANN_VIEW_THROW(exception) (static_cast<void>(exception), std::abort())
|
||||
#endif
|
||||
#if defined(JSON_THROW_USER)
|
||||
#undef NLOHMANN_VIEW_THROW
|
||||
#define NLOHMANN_VIEW_THROW JSON_THROW_USER
|
||||
#endif
|
||||
|
||||
// the parser stores a node's first word at once where the layout of `node` is
|
||||
// known to be little-endian (MSVC targets are); elsewhere field by field
|
||||
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || defined(_MSC_VER)
|
||||
#define NLOHMANN_VIEW_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define NLOHMANN_VIEW_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/// sixteen checks at fixed offsets 0..15
|
||||
#define NLOHMANN_VIEW_REPEAT16(X) X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)
|
||||
@@ -0,0 +1,20 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
// undefine the macros of detail/view/macro_scope.hpp (at the end of json_view.hpp)
|
||||
|
||||
#undef NLOHMANN_VIEW_HAS_CPP_17
|
||||
#undef NLOHMANN_VIEW_LIKELY
|
||||
#undef NLOHMANN_VIEW_UNLIKELY
|
||||
#undef NLOHMANN_VIEW_ALWAYS_INLINE
|
||||
#undef NLOHMANN_VIEW_NOINLINE
|
||||
#undef NLOHMANN_VIEW_THROW
|
||||
#undef NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
#undef NLOHMANN_VIEW_REPEAT16
|
||||
@@ -0,0 +1,97 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
// the node kinds are value_t values; the tests of is_container() and of the
|
||||
// number kinds depend on this numbering
|
||||
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
|
||||
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
|
||||
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
|
||||
&& static_cast<std::uint8_t>(value_t::number_unsigned) == 6 && static_cast<std::uint8_t>(value_t::number_float) == 7,
|
||||
"the node format depends on the numbering of value_t");
|
||||
|
||||
/// node flags
|
||||
struct node_flags
|
||||
{
|
||||
static constexpr std::uint8_t escaped = 1; ///< string payload lives in the decode arena, not the source
|
||||
static constexpr std::uint8_t storage = 3; ///< mask: where a string or number token lives (index into document_data::base)
|
||||
static constexpr std::uint8_t is_true = 4; ///< boolean value
|
||||
};
|
||||
|
||||
/// One entry of the flat index, in document order. An object's members are
|
||||
/// stored as key node followed by the value's subtree. Integers keep their
|
||||
/// converted 64-bit value in the len/next bytes (the node after a scalar is
|
||||
/// always the next one, and the token length follows from `extra`).
|
||||
struct node
|
||||
{
|
||||
std::uint8_t kind; ///< value_t
|
||||
std::uint8_t flags; ///< node_flags
|
||||
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; otherwise 0
|
||||
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if node_flags::escaped
|
||||
std::uint32_t len; ///< string: decoded bytes; float: token bytes; array/object: element count
|
||||
std::uint32_t next; ///< array/object: number of nodes of the subtree (its extent in the enclosing sequence)
|
||||
};
|
||||
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool is_container(const node& n) noexcept
|
||||
{
|
||||
return static_cast<unsigned>(n.kind) - 1u <= 1u;
|
||||
}
|
||||
|
||||
/// the converted value of an integer node (stored in len/next)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t integer_bits(const node& n) noexcept
|
||||
{
|
||||
std::uint64_t v = 0;
|
||||
std::memcpy(&v, reinterpret_cast<const unsigned char*>(&n) + 8, 8); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
return v;
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noexcept
|
||||
{
|
||||
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, &v, 8); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
}
|
||||
|
||||
/// token length of a number node
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
|
||||
{
|
||||
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
|
||||
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
|
||||
}
|
||||
|
||||
/// estimated number of nodes for an input of `size` bytes (one node per ~12
|
||||
/// bytes covers typical documents without regrowth)
|
||||
inline std::size_t estimate_nodes(std::size_t size) noexcept
|
||||
{
|
||||
return (size / 12) + 16;
|
||||
}
|
||||
|
||||
/// estimated number of nodes for the input [src, src + size): pretty-printed
|
||||
/// input (whitespace after the first byte) needs about a node per 12 bytes,
|
||||
/// minified input up to one per 4 (yyjson tells the two apart the same way)
|
||||
inline std::size_t estimate_nodes(const char* src, std::size_t size) noexcept
|
||||
{
|
||||
return size >= 2 && (src[1] == ' ' || src[1] == '\n' || src[1] == '\r' || src[1] == '\t') ? estimate_nodes(size) : (size / 4) + 16;
|
||||
}
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -0,0 +1,189 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2020 YaoYuan <https://github.com/ibireme/yyjson>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint8_t, uint16_t, uint64_t
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
// Scanning primitives of the view's parser. The unrolled checks at fixed
|
||||
// offsets follow yyjson (https://github.com/ibireme/yyjson, MIT license): the
|
||||
// loads do not depend on each other, so the CPU can run ahead. Words are read
|
||||
// with read_eight_bytes(), so nothing here depends on the byte order.
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// 1 for bytes that may appear verbatim in a string: 0x20..0x7F except '"' and '\\'
|
||||
inline const std::uint8_t* string_plain() noexcept
|
||||
{
|
||||
static const std::array<std::uint8_t, 256> table =
|
||||
{
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00..0x1F
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20..0x3F ('"')
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 0x40..0x5F ('\\')
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60..0x7F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80..0x9F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0..0xBF
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0..0xDF
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0..0xFF
|
||||
}
|
||||
};
|
||||
return table.data();
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool is_digit(unsigned char c) noexcept
|
||||
{
|
||||
return static_cast<unsigned char>(c - '0') <= 9;
|
||||
}
|
||||
|
||||
/// two bytes as they are in memory (only compared with byte-symmetric patterns)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint16_t load16(const unsigned char* p) noexcept
|
||||
{
|
||||
std::uint16_t w = 0;
|
||||
std::memcpy(&w, p, 2);
|
||||
return w;
|
||||
}
|
||||
|
||||
/// Advance over plain string bytes and well-formed UTF-8. Stops at a quote,
|
||||
/// a backslash, a control character, ill-formed UTF-8, or the end. The first
|
||||
/// 16 bytes are checked one by one, so that the position advances by
|
||||
/// constants in predicted branches (most strings are short); longer runs
|
||||
/// continue eight bytes at a time.
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* scan_string_run(const unsigned char* p, const unsigned char* e) noexcept
|
||||
{
|
||||
const std::uint8_t* plain = string_plain();
|
||||
for (;;)
|
||||
{
|
||||
if (e - p >= 16)
|
||||
{
|
||||
#define NLOHMANN_VIEW_STEP(i) if (NLOHMANN_VIEW_LIKELY(plain[p[i]] != 0)) {} else { p += (i); goto stop; }
|
||||
NLOHMANN_VIEW_REPEAT16(NLOHMANN_VIEW_STEP)
|
||||
#undef NLOHMANN_VIEW_STEP
|
||||
p += 16;
|
||||
while (e - p >= 8)
|
||||
{
|
||||
const std::uint64_t special = swar_string_special(read_eight_bytes(p));
|
||||
if (special != 0)
|
||||
{
|
||||
p += count_trailing_zeros(special) / 8;
|
||||
goto stop;
|
||||
}
|
||||
p += 8;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
while (p != e && plain[*p] != 0)
|
||||
{
|
||||
++p;
|
||||
}
|
||||
if (p == e)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
stop:
|
||||
if (*p < 0x80)
|
||||
{
|
||||
return p; // quote, backslash, or control character
|
||||
}
|
||||
// non-ASCII: a run of well-formed sequences (the library's check, so
|
||||
// that exactly what json::parse accepts is accepted)
|
||||
do
|
||||
{
|
||||
const std::size_t n = validate_one_utf8(p, static_cast<std::size_t>(e - p));
|
||||
if (n == 0)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
p += n;
|
||||
}
|
||||
while (p != e && *p >= 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
/// advance over ASCII digits
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* skip_digits(const unsigned char* p, const unsigned char* e) noexcept
|
||||
{
|
||||
while (e - p >= 16)
|
||||
{
|
||||
#define NLOHMANN_VIEW_STEP(i) if (NLOHMANN_VIEW_LIKELY(is_digit(p[i]))) {} else { return p + (i); }
|
||||
NLOHMANN_VIEW_REPEAT16(NLOHMANN_VIEW_STEP)
|
||||
#undef NLOHMANN_VIEW_STEP
|
||||
p += 16;
|
||||
}
|
||||
while (p != e && is_digit(*p))
|
||||
{
|
||||
++p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/// powers of ten up to 10^19 as integers
|
||||
inline std::uint64_t int_pow10(unsigned k) noexcept
|
||||
{
|
||||
static const std::array<std::uint64_t, 20> table =
|
||||
{
|
||||
{
|
||||
1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 10000000u, 100000000u, 1000000000u,
|
||||
10000000000u, 100000000000u, 1000000000000u, 10000000000000u, 100000000000000u, 1000000000000000u,
|
||||
10000000000000000u, 100000000000000000u, 1000000000000000000u, 10000000000000000000u
|
||||
}
|
||||
};
|
||||
return table[k];
|
||||
}
|
||||
|
||||
/// value of 0 < k < 8 digits at p in one step if [p, p + 8) lies below
|
||||
/// limit, else one digit at a time (whole blocks of eight digits are read by
|
||||
/// parse_upto19() directly)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t parse_upto8(const unsigned char* p, unsigned k, const unsigned char* limit) noexcept
|
||||
{
|
||||
if (NLOHMANN_VIEW_LIKELY(limit - p >= 8))
|
||||
{
|
||||
// move the k digits to the top and pad the vacated low bytes with '0'
|
||||
const unsigned shift = 8 * (8 - k);
|
||||
return parse_eight_digits((read_eight_bytes(p) << shift) | (0x3030303030303030u >> (8 * k)));
|
||||
}
|
||||
std::uint64_t v = 0;
|
||||
for (unsigned i = 0; i < k; ++i)
|
||||
{
|
||||
v = (v * 10) + static_cast<std::uint64_t>(p[i] - '0');
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/// value of k <= 19 digits at p
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t parse_upto19(const unsigned char* p, unsigned k, const unsigned char* limit) noexcept
|
||||
{
|
||||
std::uint64_t w = 0;
|
||||
while (k >= 8)
|
||||
{
|
||||
// (eight digits of the token: they lie below limit)
|
||||
w = (w * 100000000u) + parse_eight_digits(read_eight_bytes(p));
|
||||
p += 8;
|
||||
k -= 8;
|
||||
}
|
||||
if (k != 0)
|
||||
{
|
||||
w = (w * int_pow10(k)) + parse_upto8(p, k, limit);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -0,0 +1,111 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm> // min
|
||||
#include <cstddef> // size_t
|
||||
#include <cstring> // memcmp, strlen
|
||||
#include <string> // basic_string
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
#if NLOHMANN_VIEW_HAS_CPP_17
|
||||
#include <string_view> // string_view
|
||||
#endif
|
||||
#ifndef JSON_NO_IO
|
||||
#include <ostream> // ostream
|
||||
#endif
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
#if NLOHMANN_VIEW_HAS_CPP_17
|
||||
using string_ref = std::string_view;
|
||||
#else
|
||||
/// minimal C++11 stand-in for std::string_view
|
||||
class string_ref
|
||||
{
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
using const_iterator = const char*;
|
||||
|
||||
string_ref() noexcept = default;
|
||||
string_ref(const char* s) : m_data(s), m_size(std::strlen(s)) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
string_ref(const char* s, std::size_t n) noexcept : m_data(s), m_size(n) {}
|
||||
template<typename Traits, typename Alloc>
|
||||
string_ref(const std::basic_string<char, Traits, Alloc>& s) noexcept : m_data(s.data()), m_size(s.size()) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
|
||||
const char* data() const noexcept
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
std::size_t size() const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
std::size_t length() const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
const char* begin() const noexcept
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
const char* end() const noexcept
|
||||
{
|
||||
return m_data + m_size;
|
||||
}
|
||||
char operator[](std::size_t i) const noexcept
|
||||
{
|
||||
return m_data[i];
|
||||
}
|
||||
|
||||
template<typename Traits, typename Alloc>
|
||||
explicit operator std::basic_string<char, Traits, Alloc>() const
|
||||
{
|
||||
return std::basic_string<char, Traits, Alloc>(m_data, m_size);
|
||||
}
|
||||
|
||||
friend bool operator==(string_ref a, string_ref b) noexcept
|
||||
{
|
||||
return a.m_size == b.m_size && (a.m_size == 0 || std::memcmp(a.m_data, b.m_data, a.m_size) == 0);
|
||||
}
|
||||
friend bool operator!=(string_ref a, string_ref b) noexcept
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
friend bool operator<(string_ref a, string_ref b) noexcept
|
||||
{
|
||||
const int c = std::memcmp(a.m_data, b.m_data, (std::min)(a.m_size, b.m_size));
|
||||
return c != 0 ? c < 0 : a.m_size < b.m_size;
|
||||
}
|
||||
#ifndef JSON_NO_IO
|
||||
friend std::ostream& operator<<(std::ostream& o, string_ref s)
|
||||
{
|
||||
return o.write(s.m_data, static_cast<std::streamsize>(s.m_size));
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
const char* m_data = "";
|
||||
std::size_t m_size = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include <nlohmann/adl_serializer.hpp>
|
||||
#include <nlohmann/byte_container_with_subtype.hpp>
|
||||
#include <nlohmann/detail/abi_config.hpp>
|
||||
#include <nlohmann/detail/conversions/from_json.hpp>
|
||||
#include <nlohmann/detail/conversions/to_json.hpp>
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
|
||||
+1058
-182
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,15 @@
|
||||
#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 <random> // mt19937
|
||||
#include <sstream> // stringstream
|
||||
#include <string> // string
|
||||
#include <utility> // pair
|
||||
#include <vector> // vector
|
||||
|
||||
namespace
|
||||
@@ -659,6 +664,184 @@ TEST_CASE("lexer string fast path")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("lexer escape fast path")
|
||||
{
|
||||
// json::accept() never throws, so this section stays covered without
|
||||
// exceptions; it pins which of the cases below are valid/invalid and
|
||||
// checks the contiguous and streaming paths agree on that classification.
|
||||
SECTION("accept() parity")
|
||||
{
|
||||
const std::vector<std::pair<std::string, bool>> cases =
|
||||
{
|
||||
{"\\u0041", true}, {"\\u00e4", true}, {"\\u00E4", true},
|
||||
{"\\uD83D\\uDE00", true},
|
||||
{"\\u12", false}, {"\\u12G4", false}, {"\\uXYZW", false},
|
||||
{"\\uD800", false}, {"\\uD800A", false}, {"\\uD800\\u0041", false},
|
||||
{"\\uDC00", false}, {"\\u", false}
|
||||
};
|
||||
|
||||
for (const auto& c : cases)
|
||||
{
|
||||
for (const std::size_t offset :
|
||||
{
|
||||
std::size_t{0}, std::size_t{9}
|
||||
})
|
||||
{
|
||||
const std::string doc = "[\"" + std::string(offset, 'a') + c.first + "\"]";
|
||||
CAPTURE(doc);
|
||||
CHECK(json::accept(doc) == c.second);
|
||||
std::stringstream ss(doc);
|
||||
CHECK(json::accept(ss) == c.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
// the full outcome of parsing @a doc: the parsed value, or the exact
|
||||
// error message, so a mismatch in either is caught
|
||||
const auto outcome = [](const std::string & doc, bool streaming) -> std::string
|
||||
{
|
||||
try
|
||||
{
|
||||
if (streaming)
|
||||
{
|
||||
std::stringstream ss(doc);
|
||||
const json j = json::parse(ss);
|
||||
return j.dump();
|
||||
}
|
||||
const json j = json::parse(doc);
|
||||
return j.dump();
|
||||
}
|
||||
catch (const json::exception& e)
|
||||
{
|
||||
return {e.what()};
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("contiguous vs streaming parity")
|
||||
{
|
||||
const std::vector<std::string> escapes =
|
||||
{
|
||||
"\\u0041", // "A"
|
||||
"\\u00e4", // "ä" (lowercase hex)
|
||||
"\\u00E4", // "ä" (uppercase hex)
|
||||
"\\uD83D\\uDE00", // valid surrogate pair (an emoji)
|
||||
"\\u12", // truncated: only 2 hex digits before the closing quote
|
||||
"\\u12G4", // invalid hex digit at the 3rd position
|
||||
"\\uXYZW", // all 4 bytes invalid
|
||||
"\\uD800", // lone high surrogate, string ends right after
|
||||
"\\uD800A", // high surrogate not followed by another \u escape
|
||||
"\\uD800\\u0041", // high surrogate followed by \u, but not a low surrogate
|
||||
"\\uDC00", // lone low surrogate
|
||||
"\\u", // '\u' with nothing after (closing quote right away)
|
||||
};
|
||||
|
||||
// once at the start of the string and once past the first 8-byte SWAR
|
||||
// word of the outer string_bulk_run, so the escape is reached both
|
||||
// right after the opening quote and mid-run
|
||||
for (const auto& escape : escapes)
|
||||
{
|
||||
for (const std::size_t offset :
|
||||
{
|
||||
std::size_t{0}, std::size_t{9}
|
||||
})
|
||||
{
|
||||
const std::string doc = "[\"" + std::string(offset, 'a') + escape + "\"]";
|
||||
CAPTURE(doc);
|
||||
CHECK(outcome(doc, false) == outcome(doc, true));
|
||||
}
|
||||
|
||||
// the escape is the last thing before end of input: no closing
|
||||
// quote at all
|
||||
const std::string truncated_doc = "[\"" + escape;
|
||||
CAPTURE(truncated_doc);
|
||||
CHECK(outcome(truncated_doc, false) == outcome(truncated_doc, true));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("truncated \\u escape at every distance from the end of input")
|
||||
{
|
||||
// ia.bulk_remaining() must correctly report fewer than 4 bytes for
|
||||
// every possible count of trailing hex-looking bytes (0, 1, 2, or 3)
|
||||
// before end of input, so the fast path declines and the byte path
|
||||
// alone reports the "must be followed by 4 hex digits" error, at the
|
||||
// same position, in every case
|
||||
for (const std::string& tail :
|
||||
{
|
||||
std::string{}, std::string("1"), std::string("12"), std::string("123")
|
||||
})
|
||||
{
|
||||
const std::string doc = "[\"\\u" + tail;
|
||||
CAPTURE(doc);
|
||||
CHECK(outcome(doc, false) == outcome(doc, true));
|
||||
CHECK(outcome(doc, false).find("must be followed by 4 hex digits") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("invalid hex digit at every position of the 4")
|
||||
{
|
||||
// the fast path must decline for *any* invalid byte among the 4, not
|
||||
// just the first, and the byte path must then stop at exactly that
|
||||
// position - same as it always has
|
||||
for (std::size_t bad_pos = 0; bad_pos < 4; ++bad_pos)
|
||||
{
|
||||
std::string digits = "1234";
|
||||
digits[bad_pos] = 'g'; // not a hex digit
|
||||
const std::string doc = "[\"\\u" + digits + "\"]";
|
||||
CAPTURE(doc);
|
||||
CHECK(outcome(doc, false) == outcome(doc, true));
|
||||
CHECK(outcome(doc, false).find("must be followed by 4 hex digits") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("random escapes")
|
||||
{
|
||||
// A seeded PRNG builds the 4 bytes following `\u` from a mix of hex
|
||||
// digits and non-hex bytes, at varying distances from the start of
|
||||
// the string, to compare the two scanners on many more shapes than
|
||||
// are practical to enumerate by hand.
|
||||
std::mt19937 gen(7654321); // NOLINT(cert-msc32-c,cert-msc51-cpp)
|
||||
const std::string hex_alphabet = "0123456789AaBbCcDdEeFf";
|
||||
std::uniform_int_distribution<std::size_t> pick_hex(0, hex_alphabet.size() - 1);
|
||||
std::uniform_int_distribution<int> pick_byte(1, 255); // never NUL
|
||||
std::uniform_int_distribution<int> pick_is_hex(0, 4); // 4-in-5 chance of a hex digit
|
||||
std::uniform_int_distribution<std::size_t> pick_offset(0, 12);
|
||||
|
||||
std::vector<std::string> mismatches;
|
||||
for (int iter = 0; iter < 3000; ++iter)
|
||||
{
|
||||
std::string digits;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (pick_is_hex(gen) != 0)
|
||||
{
|
||||
digits += hex_alphabet[pick_hex(gen)];
|
||||
}
|
||||
else
|
||||
{
|
||||
char c = static_cast<char>(pick_byte(gen));
|
||||
if (c == '"' || c == '\\')
|
||||
{
|
||||
// keep the string well-formed apart from the escape
|
||||
// itself, so any mismatch is attributable to the \u
|
||||
// handling and not to an unrelated quote/escape
|
||||
c = 'z';
|
||||
}
|
||||
digits += c;
|
||||
}
|
||||
}
|
||||
const std::string doc = "[\"" + std::string(pick_offset(gen), 'a') + "\\u" + digits + "\"]";
|
||||
if (outcome(doc, false) != outcome(doc, true))
|
||||
{
|
||||
mismatches.push_back(doc);
|
||||
}
|
||||
}
|
||||
CAPTURE(mismatches);
|
||||
CHECK(mismatches.empty());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("parse_float_fast declines what it cannot convert exactly")
|
||||
{
|
||||
// The lexer only hands well-formed numbers to parse_float_fast, so the
|
||||
@@ -700,3 +883,706 @@ 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::string extra = longer.find('.') == 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);
|
||||
CHECK_THROWS_WITH_AS(json::parse("1.7976931348623159e308"),
|
||||
"[json.exception.out_of_range.406] number overflow parsing '1.7976931348623159e308'", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("string scanning kernels")
|
||||
{
|
||||
// the word-at-a-time kernels must stop exactly where a byte-by-byte scan
|
||||
// stops, for any content, length, and alignment
|
||||
const auto reference_special = [](const unsigned char* data, std::size_t n)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while (i < n && !nlohmann::detail::is_string_special(data[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
const auto reference_copyable = [](const unsigned char* data, std::size_t n)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while (i < n && nlohmann::detail::is_ascii_copyable(data[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
const auto reference_bulk_run = [](const unsigned char* data, std::size_t n)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while (i < n)
|
||||
{
|
||||
if (data[i] < 0x80u)
|
||||
{
|
||||
if (nlohmann::detail::is_string_special(data[i]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
const std::size_t seq = nlohmann::detail::validate_one_utf8(data + i, n - i);
|
||||
if (seq == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i += seq;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
|
||||
// pieces: ordinary ASCII, stops, DEL, well-formed sequences of every
|
||||
// length, and ill-formed or truncated ones
|
||||
const std::vector<std::string> pieces =
|
||||
{
|
||||
"a", "Z", " ", "~", "0123456789", "\"", "\\", std::string(1, '\0'), "\n", "\x1F", "\x7F",
|
||||
"\xC3\xA4", "\xE2\x82\xAC", "\xE6\x97\xA5\xE6\x9C\xAC", "\xF0\x9F\x98\x80", "\xED\x9F\xBF",
|
||||
"\x80", "\xC0\x80", "\xC3", "\xE2\x82", "\xED\xA0\x80", "\xF4\x90\x80\x80", "\xFF",
|
||||
};
|
||||
std::uint64_t state = 5295;
|
||||
const auto next = [&state]()
|
||||
{
|
||||
state ^= state << 13u;
|
||||
state ^= state >> 7u;
|
||||
state ^= state << 17u;
|
||||
return state;
|
||||
};
|
||||
for (int round = 0; round < 100000; ++round)
|
||||
{
|
||||
// mostly ordinary text, so that runs span several words
|
||||
std::string text(static_cast<std::size_t>(next() % 8), '.');
|
||||
const auto count = static_cast<std::size_t>(next() % 12);
|
||||
for (std::size_t k = 0; k < count; ++k)
|
||||
{
|
||||
const std::size_t p = (next() % 4 == 0) ? static_cast<std::size_t>(next() % pieces.size()) : 0;
|
||||
text += pieces[p];
|
||||
text += std::string(static_cast<std::size_t>(next() % 10), 'x');
|
||||
}
|
||||
const auto* data = reinterpret_cast<const unsigned char*>(text.data()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
for (std::size_t offset = 0; offset < 3 && offset <= text.size(); ++offset)
|
||||
{
|
||||
const std::size_t n = text.size() - offset;
|
||||
CAPTURE(text);
|
||||
CAPTURE(offset);
|
||||
CHECK(nlohmann::detail::find_string_special(data + offset, n) == reference_special(data + offset, n));
|
||||
CHECK(nlohmann::detail::find_ascii_copyable_run(data + offset, n) == reference_copyable(data + offset, n));
|
||||
CHECK(nlohmann::detail::scalar_string_bulk_run(data + offset, n) == reference_bulk_run(data + offset, n));
|
||||
}
|
||||
}
|
||||
|
||||
// the trailing-zero count, whichever implementation the compiler gets
|
||||
for (int k = 0; k < 64; ++k)
|
||||
{
|
||||
const std::uint64_t bit = std::uint64_t{1} << k;
|
||||
CHECK(nlohmann::detail::count_trailing_zeros(bit) == k);
|
||||
CHECK(nlohmann::detail::count_trailing_zeros(bit | (bit << 1u) | 0x8000000000000000u) == k);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/builder.hpp>
|
||||
#include <nlohmann/detail/view/string_ref.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <test_data.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using nlohmann::detail::view::document_data;
|
||||
using nlohmann::detail::view::node;
|
||||
|
||||
// the node index of a text; a vector input has no terminating NUL, so that
|
||||
// AddressSanitizer catches any read past the last byte
|
||||
struct built
|
||||
{
|
||||
std::unique_ptr<document_data, document_data::deleter> data{}; // NOLINT(readability-redundant-member-init)
|
||||
std::vector<char> copy{}; // NOLINT(readability-redundant-member-init)
|
||||
bool ok = false;
|
||||
nlohmann::detail::view::parse_failure failure{};
|
||||
};
|
||||
|
||||
built build(const std::string& text, bool comments, bool trailing_commas, bool sentinel)
|
||||
{
|
||||
built r;
|
||||
r.data.reset(document_data::create(nlohmann::detail::view::estimate_nodes(text.data(), text.size())));
|
||||
const char* src = text.c_str();
|
||||
if (!sentinel)
|
||||
{
|
||||
r.copy.assign(text.begin(), text.end());
|
||||
src = r.copy.data();
|
||||
}
|
||||
r.ok = nlohmann::detail::view::build < !nlohmann::detail::abi_config::strict_nul_handling > (*r.data, src, text.size(), comments, trailing_commas, sentinel, r.failure);
|
||||
r.data->src = src;
|
||||
r.data->base[0] = src;
|
||||
r.data->base[1] = r.data->arena.data();
|
||||
return r;
|
||||
}
|
||||
|
||||
// the value of a subtree, as json::parse would build it
|
||||
json value_of(const document_data& d, const node*& n)
|
||||
{
|
||||
const node& x = *n;
|
||||
++n;
|
||||
switch (static_cast<json::value_t>(x.kind))
|
||||
{
|
||||
case json::value_t::object:
|
||||
{
|
||||
json o = json::object();
|
||||
const node* const end = &x + x.next;
|
||||
while (n != end)
|
||||
{
|
||||
const std::string key(d.str(*n), n->len);
|
||||
++n;
|
||||
o[key] = value_of(d, n);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
case json::value_t::array:
|
||||
{
|
||||
json a = json::array();
|
||||
const node* const end = &x + x.next;
|
||||
while (n != end)
|
||||
{
|
||||
a.push_back(value_of(d, n));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
case json::value_t::string:
|
||||
return std::string(d.str(x), x.len);
|
||||
case json::value_t::boolean:
|
||||
return (x.flags & nlohmann::detail::view::node_flags::is_true) != 0;
|
||||
case json::value_t::number_integer:
|
||||
return static_cast<std::int64_t>(nlohmann::detail::view::integer_bits(x));
|
||||
case json::value_t::number_unsigned:
|
||||
return nlohmann::detail::view::integer_bits(x);
|
||||
case json::value_t::number_float:
|
||||
return json::parse(std::string(d.src + x.off, x.len)).get<double>();
|
||||
case json::value_t::null:
|
||||
case json::value_t::binary:
|
||||
case json::value_t::discarded:
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
json value_of(const built& b)
|
||||
{
|
||||
const node* n = b.data->tape;
|
||||
json v = value_of(*b.data, n);
|
||||
CHECK(n == b.data->tape + b.data->tape_size);
|
||||
return v;
|
||||
}
|
||||
|
||||
// accept/reject and the value must match json::parse, for all options and
|
||||
// with and without a NUL after the text
|
||||
void check_same(const std::string& text)
|
||||
{
|
||||
CAPTURE(text);
|
||||
for (int options = 0; options < 4; ++options)
|
||||
{
|
||||
const bool comments = (options & 1) != 0;
|
||||
const bool trailing_commas = (options & 2) != 0;
|
||||
const bool accepted = json::accept(text, comments, trailing_commas);
|
||||
for (const bool sentinel :
|
||||
{
|
||||
true, false
|
||||
})
|
||||
{
|
||||
const built b = build(text, comments, trailing_commas, sentinel);
|
||||
CHECK(b.ok == accepted);
|
||||
if (b.ok && accepted)
|
||||
{
|
||||
CHECK(value_of(b) == json::parse(text, nullptr, true, comments, trailing_commas));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a small deterministic generator of documents
|
||||
struct generator
|
||||
{
|
||||
std::mt19937 rng{5295}; // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed)
|
||||
|
||||
int r(int n)
|
||||
{
|
||||
return static_cast<int>(rng() % static_cast<unsigned>(n));
|
||||
}
|
||||
|
||||
void ws(std::string& o)
|
||||
{
|
||||
for (int n = r(4) == 0 ? r(12) : r(2); n > 0; --n)
|
||||
{
|
||||
o += " \n\t\r "[r(6)];
|
||||
}
|
||||
}
|
||||
|
||||
void str(std::string& o)
|
||||
{
|
||||
static const char* const pieces[] = {"a", "Z", " ", "~", "\\n", "\\\"", "\\\\", "\\/", "\\u00e9", "\\ud83d\\ude00", "\xc3\xa9", "\xe3\x81\x82", "\xf0\x9f\x98\x80", "\x7f", "\\u001f", "long enough text to leave the first 16 bytes"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
o += '"';
|
||||
for (int n = r(3) == 0 ? r(20) : r(6); n > 0; --n)
|
||||
{
|
||||
o += pieces[r(16)];
|
||||
}
|
||||
o += '"';
|
||||
}
|
||||
|
||||
void num(std::string& o)
|
||||
{
|
||||
static const char* const numbers[] = {"0", "-0", "1", "-1", "12", "123456789", "1234567890123456789", "9223372036854775807", "-9223372036854775808", // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
"9223372036854775808", "18446744073709551615", "18446744073709551616", "-9223372036854775809",
|
||||
"1.5", "-2.25e-3", "1e10", "1E+2", "0.000001", "3.141592653589793238462643", "1e308", "-1e-400", "123.456e7"
|
||||
};
|
||||
o += numbers[r(22)];
|
||||
}
|
||||
|
||||
void value(std::string& o, int depth)
|
||||
{
|
||||
ws(o);
|
||||
const int k = depth > 5 ? 2 + r(6) : r(8);
|
||||
if (k == 0 || k == 1)
|
||||
{
|
||||
const bool object = k == 0;
|
||||
o += object ? '{' : '[';
|
||||
for (int i = r(5); i > 0; --i)
|
||||
{
|
||||
ws(o);
|
||||
if (object)
|
||||
{
|
||||
str(o);
|
||||
ws(o);
|
||||
o += ':';
|
||||
}
|
||||
value(o, depth + 1);
|
||||
o += i > 1 ? "," : "";
|
||||
}
|
||||
ws(o);
|
||||
o += object ? '}' : ']';
|
||||
}
|
||||
else if (k < 4)
|
||||
{
|
||||
str(o);
|
||||
}
|
||||
else if (k < 6)
|
||||
{
|
||||
num(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char* const literals[] = {"true", "false", "null"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
o += literals[r(3)];
|
||||
}
|
||||
ws(o);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("json_view string_ref")
|
||||
{
|
||||
// std::string_view in C++17, a stand-in with the same members before
|
||||
using nlohmann::detail::view::string_ref;
|
||||
const std::string text = "abc";
|
||||
const string_ref r(text);
|
||||
CHECK(r.length() == 3);
|
||||
CHECK(std::string(r.begin(), r.end()) == "abc");
|
||||
CHECK(r[1] == 'b');
|
||||
CHECK(r != string_ref("abd"));
|
||||
CHECK_FALSE(r != string_ref("abcd", 3));
|
||||
std::ostringstream o;
|
||||
o << r;
|
||||
CHECK(o.str() == "abc");
|
||||
}
|
||||
|
||||
TEST_CASE("json_view builder")
|
||||
{
|
||||
SECTION("scalars and containers")
|
||||
{
|
||||
for (const char* text :
|
||||
{
|
||||
"null", "true", "false", "0", "-0", "42", "-42", "1.5", "\"\"", "\"abc\"", "[]", "{}", "[1,2,3]", "{\"a\":1,\"b\":[true,null]}", // NOLINT(modernize-raw-string-literal)
|
||||
" [ 1 , 2 ] ", "{\"a\" : {\"b\" : {}}}", "[[[]]]", "\"\\u00e4\\n\\ud83d\\ude00\"", "{\"a\":1,\"a\":2}", "18446744073709551616", // NOLINT(modernize-raw-string-literal)
|
||||
"-9223372036854775809", "123456789012345678901234567890", "1e400", "-1e400", "1.7976931348623157e308"
|
||||
})
|
||||
{
|
||||
check_same(text);
|
||||
}
|
||||
|
||||
// the midpoint between the largest double and 2^1024 rounds to
|
||||
// infinity (an overflow), one less to the largest double: with more
|
||||
// than 19 digits, the fast conversions cannot decide these, and the
|
||||
// overflow check falls back to strtod
|
||||
const std::string midpoint = "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792";
|
||||
const std::string below = "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791";
|
||||
check_same(midpoint);
|
||||
check_same("-" + midpoint);
|
||||
check_same(below);
|
||||
check_same("[" + below + "," + midpoint + "]");
|
||||
}
|
||||
|
||||
SECTION("malformed input")
|
||||
{
|
||||
for (const char* text :
|
||||
{
|
||||
"", " ", "[", "]", "{", "}", "[1,]", "{\"a\":1,}", "[1 2]", "{\"a\" 1}", "{1:2}", "tru", "nul", "fals", "truex", "-", "01", "1.", ".5", "1e", "1e+",
|
||||
"\"", "\"abc", "\"\\x\"", "\"\\u12\"", "\"\\u12G4\"", "\"\\ud800\"", "\"\\udc00\"", "\"\\ud800\\u0041\"", "\"\x01\"", "\"\xff\"", "\"\xc3\"", // NOLINT(modernize-raw-string-literal)
|
||||
"\"\xe0\x80\x80\"", "\"\xed\xa0\x80\"", "[1]x", "[1] [2]", "/", "/*", "/* */ 1", "// c\n1", "1 // c", "[1,/*c*/2]", "[1,2,]"
|
||||
})
|
||||
{
|
||||
check_same(text);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("NUL, BOM, and whitespace")
|
||||
{
|
||||
// a NUL inside a string is a control character, as for json::parse
|
||||
// (where a NUL ends the input, it does so only between values)
|
||||
for (const bool sentinel :
|
||||
{
|
||||
true, false
|
||||
})
|
||||
{
|
||||
const built b = build(std::string("[\"ab\0cd\"]", 9), false, false, sentinel);
|
||||
CHECK(!b.ok);
|
||||
CHECK(b.failure.code == nlohmann::detail::view::error_code::string_control_character);
|
||||
CHECK(b.failure.offset == 4);
|
||||
}
|
||||
check_same(std::string("[1]\0garbage", 11));
|
||||
check_same(std::string("[1\0]", 4));
|
||||
check_same(std::string("[1, // c\0\n2]", 12));
|
||||
check_same(std::string("[1, /* c\0 */ 2]", 15));
|
||||
check_same("\xEF\xBB\xBF[1]");
|
||||
check_same("\xEF\xBB[1]");
|
||||
check_same(" \t\r\n 7 \n");
|
||||
for (const char* text :
|
||||
{"[1]\r", "[1]\n", "[1]\r\n", "[1,\r2]", "[1,\r\n2]", "7\r", "\"x\"\r", "{\"a\":\r\n1}\r", "[\n 1,\n 2\n]", "{\n \"a\": [\n 1\n ]\n}"
|
||||
})
|
||||
{
|
||||
check_same(text);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("deep nesting")
|
||||
{
|
||||
// the open containers beyond 64 levels live on the heap
|
||||
for (const std::size_t depth :
|
||||
{
|
||||
63u, 64u, 65u, 1000u, 100000u
|
||||
})
|
||||
{
|
||||
const std::string arrays = std::string(depth, '[') + std::string(depth, ']');
|
||||
const built b = build(arrays, false, false, false);
|
||||
REQUIRE(b.ok);
|
||||
CHECK(b.data->tape_size == depth);
|
||||
CHECK(b.data->tape[0].next == depth);
|
||||
std::string objects;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
objects += "{\"a\":";
|
||||
}
|
||||
objects += '1' + std::string(depth, '}');
|
||||
const built o = build(objects, false, false, false);
|
||||
REQUIRE(o.ok);
|
||||
CHECK(o.data->tape_size == (2 * depth) + 1);
|
||||
CHECK(!build(std::string(depth, '[') + std::string(depth - 1, ']'), false, false, false).ok);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("generated documents and damaged copies")
|
||||
{
|
||||
generator g;
|
||||
for (int i = 0; i < 3000; ++i)
|
||||
{
|
||||
std::string text;
|
||||
g.value(text, 0);
|
||||
check_same(text);
|
||||
// damage: flip one byte, or cut the text
|
||||
std::string damaged = text;
|
||||
const auto at = static_cast<std::size_t>(g.r(static_cast<int>(damaged.size())));
|
||||
static const char replacements[] = {'x', '"', '\\', ',', ':', ']', '}', '[', '{', '1', '-', '.', 'e', '\0', '\n', '/'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
damaged[at] = replacements[g.r(16)];
|
||||
check_same(damaged);
|
||||
check_same(text.substr(0, at));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test files")
|
||||
{
|
||||
for (const char* name :
|
||||
{
|
||||
"/json.org/1.json", "/json.org/2.json", "/json.org/3.json", "/json.org/4.json", "/json.org/5.json",
|
||||
"/json_testsuite/sample.json", "/nativejson-benchmark/canada.json", "/nativejson-benchmark/citm_catalog.json",
|
||||
"/nativejson-benchmark/twitter.json", "/json_tests/pass1.json", "/json_tests/pass2.json", "/json_tests/pass3.json"
|
||||
})
|
||||
{
|
||||
CAPTURE(name);
|
||||
std::ifstream f(std::string(TEST_DATA_DIRECTORY) + name, std::ios::binary);
|
||||
std::stringstream ss;
|
||||
ss << f.rdbuf();
|
||||
const std::string text = ss.str();
|
||||
REQUIRE(!text.empty());
|
||||
const built b = build(text, false, false, true);
|
||||
REQUIRE(b.ok);
|
||||
CHECK(value_of(b) == json::parse(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -766,25 +766,6 @@ TEST_CASE("regression tests 2")
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
SECTION("issue #5066 - MSVC converts json to std::variant<json> via the conversion operator")
|
||||
{
|
||||
// std::variant<json> must not be retrievable via get<>(), because otherwise the
|
||||
// implicit conversion operator becomes a candidate that MSVC picks over the variant's
|
||||
// converting constructor, routing a number through the string from_json overload
|
||||
static_assert(!nlohmann::detail::is_detected<nlohmann::detail::get_template_function, const json&, std::variant<json>>::value,
|
||||
"std::variant<json> must not be retrievable via get<>()");
|
||||
|
||||
// clang before 7 cannot instantiate libstdc++'s std::variant<json>
|
||||
#if !(defined(__clang__) && __clang_major__ < 7)
|
||||
// push_back, not emplace_back: #5066 needs the implicit conversion
|
||||
// from json to the vector's value type
|
||||
std::vector<std::variant<json>> v;
|
||||
v.push_back(json(1)); // NOLINT(hicpp-use-emplace,modernize-use-emplace)
|
||||
CHECK(std::get<0>(v[0]) == 1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("regression test - parser callback must not lose a duplicate key's prior value")
|
||||
|
||||
@@ -8,3 +8,6 @@ The following changes have been made to the code with respect to <https://github
|
||||
- membership check
|
||||
- made function from `_is_within`
|
||||
- removed unused variable `actual_path`
|
||||
- Added the optional config key `external`: include paths listed there are kept as
|
||||
`#include` directives instead of being inlined (the first directive per path; the
|
||||
repeated ones are commented out).
|
||||
|
||||
@@ -57,6 +57,11 @@ Python v.2.7.0 or higher is required.
|
||||
amalgamation. Have a look at `test/source.c.json` and `test/include.h.json`
|
||||
to see two examples.
|
||||
|
||||
The optional `external` list names include paths that are kept as `#include`
|
||||
directives instead of being inlined, e.g. `["nlohmann/json.hpp"]` for a header
|
||||
that includes another amalgamated header. Only the first directive for each
|
||||
of these paths is kept; the repeated ones are commented out.
|
||||
|
||||
* The `-s, --source` option should specify the path to the source directory.
|
||||
This is useful for supporting separate source and build directories.
|
||||
|
||||
|
||||
@@ -62,6 +62,10 @@ class Amalgamation(object):
|
||||
return None
|
||||
|
||||
def __init__(self, args):
|
||||
# include paths that are kept as #include directives instead of
|
||||
# being inlined (e.g. a header amalgamated on its own)
|
||||
self.external = []
|
||||
self.included_external = []
|
||||
with open(args.config, 'r') as f:
|
||||
config = json.loads(f.read())
|
||||
for key in config:
|
||||
@@ -220,11 +224,14 @@ class TranslationUnit(object):
|
||||
while include_match:
|
||||
if not _is_within(include_match, skippable_contexts):
|
||||
include_path = include_match.group("path")
|
||||
search_same_dir = include_match.group(1) == '"'
|
||||
found_included_path = self.amalgamation.find_included_file(
|
||||
include_path, self.file_dir if search_same_dir else None)
|
||||
if found_included_path:
|
||||
includes.append((include_match, found_included_path))
|
||||
if include_path in self.amalgamation.external:
|
||||
includes.append((include_match, None))
|
||||
else:
|
||||
search_same_dir = include_match.group(1) == '"'
|
||||
found_included_path = self.amalgamation.find_included_file(
|
||||
include_path, self.file_dir if search_same_dir else None)
|
||||
if found_included_path:
|
||||
includes.append((include_match, found_included_path))
|
||||
|
||||
include_match = self.include_pattern.search(self.content,
|
||||
include_match.end())
|
||||
@@ -235,6 +242,17 @@ class TranslationUnit(object):
|
||||
for include in includes:
|
||||
include_match, found_included_path = include
|
||||
tmp_content += self.content[prev_end:include_match.start()]
|
||||
if found_included_path is None:
|
||||
# an external header: keep the first directive and comment
|
||||
# out the repeated ones
|
||||
include_path = include_match.group("path")
|
||||
if include_path in self.amalgamation.included_external:
|
||||
tmp_content += "// {0}".format(include_match.group(0))
|
||||
else:
|
||||
self.amalgamation.included_external.append(include_path)
|
||||
tmp_content += include_match.group(0)
|
||||
prev_end = include_match.end()
|
||||
continue
|
||||
tmp_content += "// {0}\n".format(include_match.group(0))
|
||||
if found_included_path not in self.amalgamation.included_files:
|
||||
t = TranslationUnit(found_included_path, self.amalgamation, False)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"project": "JSON for Modern C++",
|
||||
"target": "single_include/nlohmann/json_view.hpp",
|
||||
"sources": [
|
||||
"include/nlohmann/json_view.hpp"
|
||||
],
|
||||
"include_paths": ["include"],
|
||||
"external": ["nlohmann/json.hpp"]
|
||||
}
|
||||
Reference in New Issue
Block a user