update nlohmann::json to 3.10.4

This commit is contained in:
2021-12-11 23:32:21 +01:00
parent 4a1dde26ce
commit 42ff7c8099
39 changed files with 5323 additions and 2710 deletions

View File

@ -11,6 +11,7 @@
#include <limits> // numeric_limits
#include <string> // char_traits, string
#include <utility> // make_pair, move
#include <vector> // vector
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/input/input_adapters.hpp>
@ -18,6 +19,7 @@
#include <nlohmann/detail/input/lexer.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/is_sax.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/value_t.hpp>
namespace nlohmann
@ -28,8 +30,9 @@ namespace detail
/// how to treat CBOR tags
enum class cbor_tag_handler_t
{
error, ///< throw a parse_error exception in case of a tag
ignore ///< ignore tags
error, ///< throw a parse_error exception in case of a tag
ignore, ///< ignore tags
store ///< store tags as binary type
};
/*!
@ -70,16 +73,16 @@ class binary_reader
@param[in] adapter input adapter to read from
*/
explicit binary_reader(InputAdapterType&& adapter) : ia(std::move(adapter))
explicit binary_reader(InputAdapterType&& adapter) noexcept : ia(std::move(adapter))
{
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
}
// make class move-only
binary_reader(const binary_reader&) = delete;
binary_reader(binary_reader&&) = default;
binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
binary_reader& operator=(const binary_reader&) = delete;
binary_reader& operator=(binary_reader&&) = default;
binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~binary_reader() = default;
/*!
@ -88,7 +91,7 @@ class binary_reader
@param[in] strict whether to expect the input to be consumed completed
@param[in] tag_handler how to treat CBOR tags
@return
@return whether parsing was successful
*/
JSON_HEDLEY_NON_NULL(3)
bool sax_parse(const input_format_t format,
@ -117,8 +120,9 @@ class binary_reader
result = parse_ubjson_internal();
break;
case input_format_t::json: // LCOV_EXCL_LINE
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
}
// strict mode: next byte must be EOF
@ -136,7 +140,7 @@ class binary_reader
if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
{
return sax->parse_error(chars_read, get_token_string(),
parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value")));
parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"), BasicJsonType()));
}
}
@ -172,7 +176,7 @@ class binary_reader
/*!
@brief Parses a C-style string from the BSON input.
@param[in, out] result A reference to the string variable where the read
@param[in,out] result A reference to the string variable where the read
string is to be stored.
@return `true` if the \x00-byte indicating the end of the string was
encountered before the EOF; false` indicates an unexpected EOF.
@ -200,7 +204,7 @@ class binary_reader
input.
@param[in] len The length (including the zero-byte at the end) of the
string to be read.
@param[in, out] result A reference to the string variable where the read
@param[in,out] result A reference to the string variable where the read
string is to be stored.
@tparam NumberType The type of the length @a len
@pre len >= 1
@ -212,7 +216,7 @@ class binary_reader
if (JSON_HEDLEY_UNLIKELY(len < 1))
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string")));
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"), BasicJsonType()));
}
return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != std::char_traits<char_type>::eof();
@ -221,7 +225,7 @@ class binary_reader
/*!
@brief Parses a byte array input of length @a len from the BSON input.
@param[in] len The length of the byte array to be read.
@param[in, out] result A reference to the binary variable where the read
@param[in,out] result A reference to the binary variable where the read
array is to be stored.
@tparam NumberType The type of the length @a len
@pre len >= 0
@ -233,7 +237,7 @@ class binary_reader
if (JSON_HEDLEY_UNLIKELY(len < 0))
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary")));
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"), BasicJsonType()));
}
// All BSON binary values have a subtype
@ -314,8 +318,8 @@ class binary_reader
default: // anything else not supported (yet)
{
std::array<char, 3> cr{{}};
(std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type));
return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data())));
(std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()), BasicJsonType()));
}
}
}
@ -630,7 +634,7 @@ class binary_reader
case 0x9B: // array (eight-byte uint64_t for n follow)
{
std::uint64_t len{};
return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
return get_number(input_format_t::cbor, len) && get_cbor_array(detail::conditional_static_cast<std::size_t>(len), tag_handler);
}
case 0x9F: // array (indefinite length)
@ -684,7 +688,7 @@ class binary_reader
case 0xBB: // map (eight-byte uint64_t for n follow)
{
std::uint64_t len{};
return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
return get_number(input_format_t::cbor, len) && get_cbor_object(detail::conditional_static_cast<std::size_t>(len), tag_handler);
}
case 0xBF: // map (indefinite length)
@ -715,35 +719,36 @@ class binary_reader
case cbor_tag_handler_t::error:
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value")));
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType()));
}
case cbor_tag_handler_t::ignore:
{
// ignore binary subtype
switch (current)
{
case 0xD8:
{
std::uint8_t len{};
get_number(input_format_t::cbor, len);
std::uint8_t subtype_to_ignore{};
get_number(input_format_t::cbor, subtype_to_ignore);
break;
}
case 0xD9:
{
std::uint16_t len{};
get_number(input_format_t::cbor, len);
std::uint16_t subtype_to_ignore{};
get_number(input_format_t::cbor, subtype_to_ignore);
break;
}
case 0xDA:
{
std::uint32_t len{};
get_number(input_format_t::cbor, len);
std::uint32_t subtype_to_ignore{};
get_number(input_format_t::cbor, subtype_to_ignore);
break;
}
case 0xDB:
{
std::uint64_t len{};
get_number(input_format_t::cbor, len);
std::uint64_t subtype_to_ignore{};
get_number(input_format_t::cbor, subtype_to_ignore);
break;
}
default:
@ -752,8 +757,50 @@ class binary_reader
return parse_cbor_internal(true, tag_handler);
}
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
case cbor_tag_handler_t::store:
{
binary_t b;
// use binary subtype and store in binary container
switch (current)
{
case 0xD8:
{
std::uint8_t subtype{};
get_number(input_format_t::cbor, subtype);
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
break;
}
case 0xD9:
{
std::uint16_t subtype{};
get_number(input_format_t::cbor, subtype);
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
break;
}
case 0xDA:
{
std::uint32_t subtype{};
get_number(input_format_t::cbor, subtype);
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
break;
}
case 0xDB:
{
std::uint64_t subtype{};
get_number(input_format_t::cbor, subtype);
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
break;
}
default:
return parse_cbor_internal(true, tag_handler);
}
get();
return get_cbor_binary(b) && sax->binary(b);
}
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
return false; // LCOV_EXCL_LINE
}
}
@ -829,7 +876,7 @@ class binary_reader
default: // anything else (0xFF is handled inside the other types)
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value")));
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType()));
}
}
}
@ -924,7 +971,7 @@ class binary_reader
default:
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string")));
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"), BasicJsonType()));
}
}
}
@ -1023,7 +1070,7 @@ class binary_reader
default:
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary")));
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"), BasicJsonType()));
}
}
}
@ -1080,38 +1127,41 @@ class binary_reader
return false;
}
string_t key;
if (len != std::size_t(-1))
if (len != 0)
{
for (std::size_t i = 0; i < len; ++i)
string_t key;
if (len != std::size_t(-1))
{
get();
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
for (std::size_t i = 0; i < len; ++i)
{
return false;
}
get();
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
{
return false;
}
if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
{
return false;
if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
{
return false;
}
key.clear();
}
key.clear();
}
}
else
{
while (get() != 0xFF)
else
{
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
while (get() != 0xFF)
{
return false;
}
if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
{
return false;
}
if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
{
return false;
if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
{
return false;
}
key.clear();
}
key.clear();
}
}
@ -1490,7 +1540,7 @@ class binary_reader
default: // anything else
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value")));
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"), BasicJsonType()));
}
}
}
@ -1572,7 +1622,7 @@ class binary_reader
default:
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string")));
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"), BasicJsonType()));
}
}
}
@ -1822,7 +1872,7 @@ class binary_reader
default:
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string")));
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"), BasicJsonType()));
}
}
@ -1852,7 +1902,7 @@ class binary_reader
{
return false;
}
result = static_cast<std::size_t>(number);
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
return true;
}
@ -1892,7 +1942,7 @@ class binary_reader
default:
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size")));
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"), BasicJsonType()));
}
}
}
@ -1930,7 +1980,7 @@ class binary_reader
return false;
}
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size")));
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"), BasicJsonType()));
}
return get_ubjson_size_value(result.first);
@ -2020,7 +2070,7 @@ class binary_reader
if (JSON_HEDLEY_UNLIKELY(current > 127))
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char")));
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"), BasicJsonType()));
}
string_t s(1, static_cast<typename string_t::value_type>(current));
return sax->string(s);
@ -2041,7 +2091,7 @@ class binary_reader
default: // anything else
{
auto last_token = get_token_string();
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value")));
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"), BasicJsonType()));
}
}
}
@ -2209,8 +2259,8 @@ class binary_reader
}
// parse number string
auto number_ia = detail::input_adapter(std::forward<decltype(number_vector)>(number_vector));
auto number_lexer = detail::lexer<BasicJsonType, decltype(number_ia)>(std::move(number_ia), false);
using ia_type = decltype(detail::input_adapter(number_vector));
auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);
const auto result_number = number_lexer.scan();
const auto number_string = number_lexer.get_token_string();
const auto result_remainder = number_lexer.scan();
@ -2219,7 +2269,7 @@ class binary_reader
if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
{
return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number")));
return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType()));
}
switch (result_number)
@ -2230,8 +2280,22 @@ class binary_reader
return sax->number_unsigned(number_lexer.get_number_unsigned());
case token_type::value_float:
return sax->number_float(number_lexer.get_number_float(), std::move(number_string));
case token_type::uninitialized:
case token_type::literal_true:
case token_type::literal_false:
case token_type::literal_null:
case token_type::value_string:
case token_type::begin_array:
case token_type::begin_object:
case token_type::end_array:
case token_type::end_object:
case token_type::name_separator:
case token_type::value_separator:
case token_type::parse_error:
case token_type::end_of_input:
case token_type::literal_or_value:
default:
return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number")));
return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType()));
}
}
@ -2285,7 +2349,7 @@ class binary_reader
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;
std::array<std::uint8_t, sizeof(NumberType)> vec{};
for (std::size_t i = 0; i < sizeof(NumberType); ++i)
{
get();
@ -2339,7 +2403,7 @@ class binary_reader
break;
}
result.push_back(static_cast<typename string_t::value_type>(current));
};
}
return success;
}
@ -2387,7 +2451,7 @@ class binary_reader
if (JSON_HEDLEY_UNLIKELY(current == std::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)));
parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), BasicJsonType()));
}
return true;
}
@ -2398,7 +2462,7 @@ class binary_reader
std::string get_token_string() const
{
std::array<char, 3> cr{{}};
(std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current));
(std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
return std::string{cr.data()};
}
@ -2432,8 +2496,9 @@ class binary_reader
error_msg += "BSON";
break;
case input_format_t::json: // LCOV_EXCL_LINE
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
}
return error_msg + " " + context + ": " + detail;

View File

@ -2,9 +2,7 @@
#include <array> // array
#include <cstddef> // size_t
#include <cstdio> //FILE *
#include <cstring> // strlen
#include <istream> // istream
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
#include <memory> // shared_ptr, make_shared, addressof
#include <numeric> // accumulate
@ -12,6 +10,11 @@
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
#include <utility> // pair, declval
#ifndef JSON_NO_IO
#include <cstdio> // FILE *
#include <istream> // istream
#endif // JSON_NO_IO
#include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/macro_scope.hpp>
@ -26,6 +29,7 @@ enum class input_format_t { json, cbor, msgpack, ubjson, bson };
// input adapters //
////////////////////
#ifndef JSON_NO_IO
/*!
Input adapter for stdio file access. This adapter read only 1 byte and do not use any
buffer. This adapter is a very low level adapter.
@ -42,9 +46,10 @@ class file_input_adapter
// make class move-only
file_input_adapter(const file_input_adapter&) = delete;
file_input_adapter(file_input_adapter&&) = default;
file_input_adapter(file_input_adapter&&) noexcept = default;
file_input_adapter& operator=(const file_input_adapter&) = delete;
file_input_adapter& operator=(file_input_adapter&&) = delete;
~file_input_adapter() = default;
std::char_traits<char>::int_type get_character() noexcept
{
@ -88,9 +93,10 @@ class input_stream_adapter
// delete because of pointer members
input_stream_adapter(const input_stream_adapter&) = delete;
input_stream_adapter& operator=(input_stream_adapter&) = delete;
input_stream_adapter& operator=(input_stream_adapter&& rhs) = delete;
input_stream_adapter& operator=(input_stream_adapter&&) = delete;
input_stream_adapter(input_stream_adapter&& rhs) noexcept : is(rhs.is), sb(rhs.sb)
input_stream_adapter(input_stream_adapter&& rhs) noexcept
: is(rhs.is), sb(rhs.sb)
{
rhs.is = nullptr;
rhs.sb = nullptr;
@ -103,7 +109,7 @@ class input_stream_adapter
{
auto res = sb->sbumpc();
// set eof manually, as we don't use the istream interface.
if (JSON_HEDLEY_UNLIKELY(res == EOF))
if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
{
is->clear(is->rdstate() | std::ios::eofbit);
}
@ -115,6 +121,7 @@ class input_stream_adapter
std::istream* is = nullptr;
std::streambuf* sb = nullptr;
};
#endif // JSON_NO_IO
// General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile.
@ -125,7 +132,8 @@ class iterator_input_adapter
using char_type = typename std::iterator_traits<IteratorType>::value_type;
iterator_input_adapter(IteratorType first, IteratorType last)
: current(std::move(first)), end(std::move(last)) {}
: current(std::move(first)), end(std::move(last))
{}
typename std::char_traits<char_type>::int_type get_character()
{
@ -135,10 +143,8 @@ class iterator_input_adapter
std::advance(current, 1);
return result;
}
else
{
return std::char_traits<char_type>::eof();
}
return std::char_traits<char_type>::eof();
}
private:
@ -152,7 +158,6 @@ class iterator_input_adapter
{
return current == end;
}
};
@ -371,16 +376,39 @@ typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapte
}
// Convenience shorthand from container to iterator
template<typename ContainerType>
auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
{
// Enable ADL
using std::begin;
using std::end;
// Enables ADL on begin(container) and end(container)
// Encloses the using declarations in namespace for not to leak them to outside scope
namespace container_input_adapter_factory_impl
{
using std::begin;
using std::end;
template<typename ContainerType, typename Enable = void>
struct container_input_adapter_factory {};
template<typename ContainerType>
struct container_input_adapter_factory< ContainerType,
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
{
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
static adapter_type create(const ContainerType& container)
{
return input_adapter(begin(container), end(container));
}
};
} // namespace container_input_adapter_factory_impl
template<typename ContainerType>
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
{
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
}
#ifndef JSON_NO_IO
// Special cases with fast paths
inline file_input_adapter input_adapter(std::FILE* file)
{
@ -396,6 +424,7 @@ inline input_stream_adapter input_adapter(std::istream&& stream)
{
return input_stream_adapter(stream);
}
#endif // JSON_NO_IO
using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
@ -415,7 +444,7 @@ contiguous_bytes_input_adapter input_adapter(CharT b)
}
template<typename T, std::size_t N>
auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N))
auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
{
return input_adapter(array, array + N);
}
@ -444,7 +473,7 @@ class span_input_adapter
contiguous_bytes_input_adapter&& get()
{
return std::move(ia);
return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
}
private:

View File

@ -126,6 +126,11 @@ struct json_sax
const std::string& last_token,
const detail::exception& ex) = 0;
json_sax() = default;
json_sax(const json_sax&) = default;
json_sax(json_sax&&) noexcept = default;
json_sax& operator=(const json_sax&) = default;
json_sax& operator=(json_sax&&) noexcept = default;
virtual ~json_sax() = default;
};
@ -156,7 +161,7 @@ class json_sax_dom_parser
using binary_t = typename BasicJsonType::binary_t;
/*!
@param[in, out] r reference to a JSON value that is manipulated while
@param[in,out] r reference to a JSON value that is manipulated while
parsing
@param[in] allow_exceptions_ whether parse errors yield exceptions
*/
@ -166,9 +171,9 @@ class json_sax_dom_parser
// make class move-only
json_sax_dom_parser(const json_sax_dom_parser&) = delete;
json_sax_dom_parser(json_sax_dom_parser&&) = default;
json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default;
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~json_sax_dom_parser() = default;
bool null()
@ -219,8 +224,7 @@ class json_sax_dom_parser
if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive object size: " + std::to_string(len)));
JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back()));
}
return true;
@ -235,6 +239,7 @@ class json_sax_dom_parser
bool end_object()
{
ref_stack.back()->set_parents();
ref_stack.pop_back();
return true;
}
@ -245,8 +250,7 @@ class json_sax_dom_parser
if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408,
"excessive array size: " + std::to_string(len)));
JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back()));
}
return true;
@ -254,6 +258,7 @@ class json_sax_dom_parser
bool end_array()
{
ref_stack.back()->set_parents();
ref_stack.pop_back();
return true;
}
@ -341,9 +346,9 @@ class json_sax_dom_callback_parser
// make class move-only
json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default;
json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default;
json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~json_sax_dom_callback_parser() = default;
bool null()
@ -400,7 +405,7 @@ class json_sax_dom_callback_parser
// check object limit
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len)));
JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back()));
}
return true;
@ -425,10 +430,17 @@ class json_sax_dom_callback_parser
bool end_object()
{
if (ref_stack.back() && !callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
if (ref_stack.back())
{
// discard object
*ref_stack.back() = discarded;
if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
{
// discard object
*ref_stack.back() = discarded;
}
else
{
ref_stack.back()->set_parents();
}
}
JSON_ASSERT(!ref_stack.empty());
@ -463,7 +475,7 @@ class json_sax_dom_callback_parser
// check array limit
if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{
JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len)));
JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back()));
}
return true;
@ -476,7 +488,11 @@ class json_sax_dom_callback_parser
if (ref_stack.back())
{
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
if (!keep)
if (keep)
{
ref_stack.back()->set_parents();
}
else
{
// discard array
*ref_stack.back() = discarded;
@ -574,7 +590,7 @@ class json_sax_dom_callback_parser
// array
if (ref_stack.back()->is_array())
{
ref_stack.back()->m_value.array->push_back(std::move(value));
ref_stack.back()->m_value.array->emplace_back(std::move(value));
return {true, &(ref_stack.back()->m_value.array->back())};
}

View File

@ -112,7 +112,7 @@ class lexer : public lexer_base<BasicJsonType>
public:
using token_type = typename lexer_base<BasicJsonType>::token_type;
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false)
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
: ia(std::move(adapter))
, ignore_comments(ignore_comments_)
, decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
@ -120,9 +120,9 @@ class lexer : public lexer_base<BasicJsonType>
// delete because of pointer members
lexer(const lexer&) = delete;
lexer(lexer&&) = default;
lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
lexer& operator=(lexer&) = delete;
lexer& operator=(lexer&&) = default;
lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~lexer() = default;
private:
@ -231,7 +231,7 @@ class lexer : public lexer_base<BasicJsonType>
/*!
@brief scan a string literal
This function scans a string according to Sect. 7 of RFC 7159. While
This function scans a string according to Sect. 7 of RFC 8259. While
scanning, bytes are escaped and copied into buffer token_buffer. Then the
function returns successfully, token_buffer is *not* null-terminated (as it
may contain \0 bytes), and token_buffer.size() is the number of bytes in the
@ -921,10 +921,10 @@ class lexer : public lexer_base<BasicJsonType>
/*!
@brief scan a number literal
This function scans a string according to Sect. 6 of RFC 7159.
This function scans a string according to Sect. 6 of RFC 8259.
The function is realized with a deterministic finite state machine derived
from the grammar described in RFC 7159. Starting in state "init", the
from the grammar described in RFC 8259. Starting in state "init", the
input is read and used to determined the next state. Only state "done"
accepts the number. State "error" is a trap state to model errors. In the
table below, "anything" means any character but the ones listed before.
@ -998,7 +998,7 @@ class lexer : public lexer_base<BasicJsonType>
// all other characters are rejected outside scan_number()
default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
}
scan_number_minus:
@ -1236,7 +1236,7 @@ scan_number_done:
// we are done scanning a number)
unget();
char* endptr = nullptr;
char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
errno = 0;
// try to parse integers first and fall back to floats
@ -1447,7 +1447,7 @@ scan_number_done:
{
// escape control characters
std::array<char, 9> cs{{}};
(std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c));
(std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
result += cs.data();
}
else
@ -1541,17 +1541,17 @@ scan_number_done:
// literals
case 't':
{
std::array<char_type, 4> true_literal = {{'t', 'r', 'u', 'e'}};
std::array<char_type, 4> true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}};
return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);
}
case 'f':
{
std::array<char_type, 5> false_literal = {{'f', 'a', 'l', 's', 'e'}};
std::array<char_type, 5> false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}};
return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);
}
case 'n':
{
std::array<char_type, 4> null_literal = {{'n', 'u', 'l', 'l'}};
std::array<char_type, 4> null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}};
return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);
}

View File

@ -23,7 +23,7 @@ namespace detail
// parser //
////////////
enum class parse_event_t : uint8_t
enum class parse_event_t : std::uint8_t
{
/// the parser read `{` and started to process a JSON object
object_start,
@ -41,7 +41,7 @@ enum class parse_event_t : uint8_t
template<typename BasicJsonType>
using parser_callback_t =
std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;
/*!
@brief syntax analysis
@ -88,7 +88,6 @@ class parser
{
json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
sax_parse_internal(&sdp);
result.assert_invariant();
// in strict mode, input must be completely read
if (strict && (get_token() != token_type::end_of_input))
@ -96,7 +95,7 @@ class parser
sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_of_input, "value")));
exception_message(token_type::end_of_input, "value"), BasicJsonType()));
}
// in case of an error, return discarded value
@ -117,15 +116,13 @@ class parser
{
json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
sax_parse_internal(&sdp);
result.assert_invariant();
// in strict mode, input must be completely read
if (strict && (get_token() != token_type::end_of_input))
{
sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_of_input, "value")));
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType()));
}
// in case of an error, return discarded value
@ -135,6 +132,8 @@ class parser
return;
}
}
result.assert_invariant();
}
/*!
@ -161,8 +160,7 @@ class parser
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_of_input, "value")));
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType()));
}
return result;
@ -208,8 +206,7 @@ class parser
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::value_string, "object key")));
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType()));
}
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
{
@ -221,8 +218,7 @@ class parser
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::name_separator, "object separator")));
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType()));
}
// remember we are now inside an object
@ -265,7 +261,7 @@ class parser
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'", BasicJsonType()));
}
if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
@ -335,16 +331,21 @@ class parser
// using "uninitialized" to avoid "expected" message
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::uninitialized, "value")));
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), BasicJsonType()));
}
case token_type::uninitialized:
case token_type::end_array:
case token_type::end_object:
case token_type::name_separator:
case token_type::value_separator:
case token_type::end_of_input:
case token_type::literal_or_value:
default: // the last token was unexpected
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::literal_or_value, "value")));
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), BasicJsonType()));
}
}
}
@ -390,65 +391,61 @@ class parser
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_array, "array")));
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), BasicJsonType()));
}
else // object
// states.back() is false -> object
// comma -> next value
if (get_token() == token_type::value_separator)
{
// comma -> next value
if (get_token() == token_type::value_separator)
// parse key
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
{
// parse key
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::value_string, "object key")));
}
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
{
return false;
}
// parse separator (:)
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::name_separator, "object separator")));
}
// parse values
get_token();
continue;
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType()));
}
// closing }
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
{
if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
{
return false;
}
// We are done with this object. Before we can parse a
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
JSON_ASSERT(!states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
return false;
}
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::end_object, "object")));
// parse separator (:)
if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType()));
}
// parse values
get_token();
continue;
}
// closing }
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
{
if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
{
return false;
}
// We are done with this object. Before we can parse a
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
JSON_ASSERT(!states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
}
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), BasicJsonType()));
}
}
@ -497,5 +494,6 @@ class parser
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true;
};
} // namespace detail
} // namespace nlohmann