update nlohmann:json to v3.12.0

This commit is contained in:
Green Sky
2025-05-21 11:51:08 +02:00
parent 2ea7a1529a
commit 7e76d6116f
50 changed files with 4863 additions and 2641 deletions

View File

@ -1,9 +1,9 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.2
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#pragma once
@ -20,6 +20,9 @@
#include <string> // char_traits, string
#include <utility> // make_pair, move
#include <vector> // vector
#ifdef __cpp_lib_byteswap
#include <bit> //byteswap
#endif
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/input/input_adapters.hpp>
@ -55,7 +58,6 @@ static inline bool little_endianness(int num = 1) noexcept
return *reinterpret_cast<char*>(&num) == 1;
}
///////////////////
// binary reader //
///////////////////
@ -63,7 +65,7 @@ static inline bool little_endianness(int num = 1) noexcept
/*!
@brief deserialization of CBOR, MessagePack, and UBJSON values
*/
template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType, InputAdapterType>>
class binary_reader
{
using number_integer_t = typename BasicJsonType::number_integer_t;
@ -73,7 +75,7 @@ class binary_reader
using binary_t = typename BasicJsonType::binary_t;
using json_sax_t = SAX;
using char_type = typename InputAdapterType::char_type;
using char_int_type = typename std::char_traits<char_type>::int_type;
using char_int_type = typename char_traits<char_type>::int_type;
public:
/*!
@ -146,7 +148,7 @@ class binary_reader
get();
}
if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
@ -170,7 +172,7 @@ class binary_reader
std::int32_t document_size{};
get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
{
return false;
}
@ -229,7 +231,7 @@ class binary_reader
exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
}
return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();
return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();
}
/*!
@ -326,11 +328,17 @@ class binary_reader
return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
}
case 0x11: // uint64
{
std::uint64_t value{};
return get_number<std::uint64_t, true>(input_format_t::bson, value) && sax->number_unsigned(value);
}
default: // anything else not supported (yet)
{
std::array<char, 3> cr{{}};
static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
std::string cr_str{cr.data()};
const std::string cr_str{cr.data()};
return sax->parse_error(element_type_parse_position, cr_str,
parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
}
@ -392,7 +400,7 @@ class binary_reader
std::int32_t document_size{};
get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
{
return false;
}
@ -423,7 +431,7 @@ class binary_reader
switch (get_char ? get() : current)
{
// EOF
case std::char_traits<char_type>::eof():
case char_traits<char_type>::eof():
return unexpect_eof(input_format_t::cbor, "value");
// Integer 0x00..0x17 (0..23)
@ -652,7 +660,7 @@ class binary_reader
}
case 0x9F: // array (indefinite length)
return get_cbor_array(static_cast<std::size_t>(-1), tag_handler);
return get_cbor_array(detail::unknown_size(), tag_handler);
// map (0x00..0x17 pairs of data items follow)
case 0xA0:
@ -706,7 +714,7 @@ class binary_reader
}
case 0xBF: // map (indefinite length)
return get_cbor_object(static_cast<std::size_t>(-1), tag_handler);
return get_cbor_object(detail::unknown_size(), tag_handler);
case 0xC6: // tagged item
case 0xC7:
@ -1094,7 +1102,7 @@ class binary_reader
}
/*!
@param[in] len the length of the array or static_cast<std::size_t>(-1) for an
@param[in] len the length of the array or detail::unknown_size() for an
array of indefinite size
@param[in] tag_handler how CBOR tags should be treated
@return whether array creation completed
@ -1107,7 +1115,7 @@ class binary_reader
return false;
}
if (len != static_cast<std::size_t>(-1))
if (len != detail::unknown_size())
{
for (std::size_t i = 0; i < len; ++i)
{
@ -1132,7 +1140,7 @@ class binary_reader
}
/*!
@param[in] len the length of the object or static_cast<std::size_t>(-1) for an
@param[in] len the length of the object or detail::unknown_size() for an
object of indefinite size
@param[in] tag_handler how CBOR tags should be treated
@return whether object creation completed
@ -1148,7 +1156,7 @@ class binary_reader
if (len != 0)
{
string_t key;
if (len != static_cast<std::size_t>(-1))
if (len != detail::unknown_size())
{
for (std::size_t i = 0; i < len; ++i)
{
@ -1198,7 +1206,7 @@ class binary_reader
switch (get())
{
// EOF
case std::char_traits<char_type>::eof():
case char_traits<char_type>::eof():
return unexpect_eof(input_format_t::msgpack, "value");
// positive fixint
@ -2153,7 +2161,7 @@ class binary_reader
}
if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimentional vector is not allowed", "size"), nullptr));
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr));
}
std::vector<size_t> dim;
if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
@ -2265,7 +2273,7 @@ class binary_reader
exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
}
bool is_error = get_ubjson_size_value(result.first, is_ndarray);
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray)
{
if (inside_ndarray)
@ -2280,7 +2288,7 @@ class binary_reader
if (current == '#')
{
bool is_error = get_ubjson_size_value(result.first, is_ndarray);
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
if (input_format == input_format_t::bjdata && is_ndarray)
{
return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
@ -2300,7 +2308,7 @@ class binary_reader
{
switch (prefix)
{
case std::char_traits<char_type>::eof(): // EOF
case char_traits<char_type>::eof(): // EOF
return unexpect_eof(input_format, "value");
case 'T': // true
@ -2311,6 +2319,16 @@ class binary_reader
case 'Z': // null
return sax->null();
case 'B': // byte
{
if (input_format != input_format_t::bjdata)
{
break;
}
std::uint8_t number{};
return get_number(input_format, number) && sax->number_unsigned(number);
}
case 'U':
{
std::uint8_t number{};
@ -2511,7 +2529,7 @@ class binary_reader
return false;
}
if (size_and_type.second == 'C')
if (size_and_type.second == 'C' || size_and_type.second == 'B')
{
size_and_type.second = 'U';
}
@ -2533,6 +2551,13 @@ class binary_reader
return (sax->end_array() && sax->end_object());
}
// If BJData type marker is 'B' decode as binary
if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B')
{
binary_t result;
return get_binary(input_format, size_and_type.first, result) && sax->binary(result);
}
if (size_and_type.first != npos)
{
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
@ -2566,7 +2591,7 @@ class binary_reader
}
else
{
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
{
return false;
}
@ -2644,7 +2669,7 @@ class binary_reader
}
else
{
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
{
return false;
}
@ -2745,7 +2770,7 @@ class binary_reader
This function provides the interface to the used input adapter. It does
not throw in case the input reached EOF, but returns a -'ve valued
`std::char_traits<char_type>::eof()` in that case.
`char_traits<char_type>::eof()` in that case.
@return character read from the input
*/
@ -2755,6 +2780,29 @@ class binary_reader
return current = ia.get_character();
}
/*!
@brief get_to read into a primitive type
This function provides the interface to the used input adapter. It does
not throw in case the input reached EOF, but returns false instead
@return bool, whether the read was successful
*/
template<class T>
bool get_to(T& dest, const input_format_t format, const char* context)
{
auto new_chars_read = ia.get_elements(&dest);
chars_read += new_chars_read;
if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T)))
{
// in case of failure, advance position by 1 to report failing location
++chars_read;
sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
return false;
}
return true;
}
/*!
@return character read from the input after ignoring all 'N' entries
*/
@ -2769,6 +2817,28 @@ class binary_reader
return current;
}
template<class NumberType>
static void byte_swap(NumberType& number)
{
constexpr std::size_t sz = sizeof(number);
#ifdef __cpp_lib_byteswap
if constexpr (sz == 1)
{
return;
}
if constexpr(std::is_integral_v<NumberType>)
{
number = std::byteswap(number);
return;
}
#endif
auto* ptr = reinterpret_cast<std::uint8_t*>(&number);
for (std::size_t i = 0; i < sz / 2; ++i)
{
std::swap(ptr[i], ptr[sz - i - 1]);
}
}
/*
@brief read a number from the input
@ -2787,29 +2857,16 @@ class binary_reader
template<typename NumberType, bool InputIsLittleEndian = false>
bool get_number(const input_format_t format, NumberType& result)
{
// step 1: read input into array with system's byte order
std::array<std::uint8_t, sizeof(NumberType)> vec{};
for (std::size_t i = 0; i < sizeof(NumberType); ++i)
// read in the original format
if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number")))
{
get();
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
{
return false;
}
// reverse byte order prior to conversion if necessary
if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
{
vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
}
else
{
vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
}
return false;
}
if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
{
byte_swap(result);
}
// step 2: convert array into number of type T and return
std::memcpy(&result, vec.data(), sizeof(NumberType));
return true;
}
@ -2887,7 +2944,7 @@ class binary_reader
JSON_HEDLEY_NON_NULL(3)
bool unexpect_eof(const input_format_t format, const char* context) const
{
if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char_type>::eof()))
if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
{
return sax->parse_error(chars_read, "<end of file>",
parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
@ -2948,13 +3005,13 @@ class binary_reader
}
private:
static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1);
static JSON_INLINE_VARIABLE constexpr std::size_t npos = detail::unknown_size();
/// input adapter
InputAdapterType ia;
/// the current character
char_int_type current = std::char_traits<char_type>::eof();
char_int_type current = char_traits<char_type>::eof();
/// the number of characters read
std::size_t chars_read = 0;
@ -2974,6 +3031,7 @@ class binary_reader
#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \
make_array<bjd_type>( \
bjd_type{'B', "byte"}, \
bjd_type{'C', "char"}, \
bjd_type{'D', "double"}, \
bjd_type{'I', "int16"}, \