mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 19:50:34 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0b82e5af7 | ||
|
|
2610d176ef | ||
|
|
c9a2143c78 | ||
|
|
a8b078ea37 | ||
|
|
391bc271b2 | ||
|
|
afef548ea1 | ||
|
|
70380a8de6 | ||
|
|
1841b4f671 | ||
|
|
edd18d071e | ||
|
|
35a3b0f3de | ||
|
|
e072480872 | ||
|
|
a3a94bb7eb | ||
|
|
0ffe9ab4a8 | ||
|
|
e158b080bd |
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm> // generate_n
|
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <cmath> // ldexp
|
#include <cmath> // ldexp
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
@@ -123,7 +122,26 @@ class binary_reader
|
|||||||
~binary_reader() = default;
|
~binary_reader() = default;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@param[in] format the binary format to parse
|
@brief parse in the format the constructor was given
|
||||||
|
|
||||||
|
@param[in] sax_ a SAX event processor
|
||||||
|
@param[in] strict whether to expect the input to be consumed completed
|
||||||
|
@param[in] tag_handler how to treat CBOR tags
|
||||||
|
|
||||||
|
@return whether parsing was successful
|
||||||
|
*/
|
||||||
|
JSON_HEDLEY_NON_NULL(2)
|
||||||
|
bool sax_parse(json_sax_t* sax_,
|
||||||
|
const bool strict = true,
|
||||||
|
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
|
||||||
|
{
|
||||||
|
return sax_parse(input_format, sax_, strict, tag_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@param[in] format the binary format to parse; must equal the format the
|
||||||
|
constructor was given, since that format is what
|
||||||
|
every reader function below actually dispatches on
|
||||||
@param[in] sax_ a SAX event processor
|
@param[in] sax_ a SAX event processor
|
||||||
@param[in] strict whether to expect the input to be consumed completed
|
@param[in] strict whether to expect the input to be consumed completed
|
||||||
@param[in] tag_handler how to treat CBOR tags
|
@param[in] tag_handler how to treat CBOR tags
|
||||||
@@ -136,6 +154,7 @@ class binary_reader
|
|||||||
const bool strict = true,
|
const bool strict = true,
|
||||||
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
|
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
|
||||||
{
|
{
|
||||||
|
JSON_ASSERT(format == input_format);
|
||||||
sax = sax_;
|
sax = sax_;
|
||||||
container_stack.clear();
|
container_stack.clear();
|
||||||
bon8_pushback_size = 0;
|
bon8_pushback_size = 0;
|
||||||
@@ -148,7 +167,7 @@ class binary_reader
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case input_format_t::cbor:
|
case input_format_t::cbor:
|
||||||
result = parse_cbor_internal(true, tag_handler);
|
result = parse_cbor_internal(tag_handler);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case input_format_t::msgpack:
|
case input_format_t::msgpack:
|
||||||
@@ -271,6 +290,22 @@ class binary_reader
|
|||||||
return enter_container(/*is_object*/true, len, type_marker);
|
return enter_container(/*is_object*/true, len, type_marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief close the innermost open array or object
|
||||||
|
|
||||||
|
Pops the container opened by the matching @ref enter_container call and
|
||||||
|
emits the SAX end event. Every format-specific driver otherwise repeated
|
||||||
|
the same pop-then-dispatch sequence at its own close site.
|
||||||
|
|
||||||
|
@return whether the SAX parser accepted the end event
|
||||||
|
*/
|
||||||
|
bool leave_container()
|
||||||
|
{
|
||||||
|
const bool is_object = container_stack.back().is_object;
|
||||||
|
container_stack.pop_back();
|
||||||
|
return is_object ? sax->end_object() : sax->end_array();
|
||||||
|
}
|
||||||
|
|
||||||
//////////
|
//////////
|
||||||
// BSON //
|
// BSON //
|
||||||
//////////
|
//////////
|
||||||
@@ -355,8 +390,8 @@ class binary_reader
|
|||||||
if (element_type == 0) // end of the innermost document
|
if (element_type == 0) // end of the innermost document
|
||||||
{
|
{
|
||||||
// a copy, not a reference: it must stay valid across the
|
// a copy, not a reference: it must stay valid across the
|
||||||
// pop_back() below, which destroys the container_stack
|
// pop_back() inside leave_container() below, which destroys
|
||||||
// element it would otherwise alias
|
// the container_stack element it would otherwise alias
|
||||||
const container_frame top = container_stack.back();
|
const container_frame top = container_stack.back();
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!check_bson_document_size(top.start_position, top.declared_size)))
|
if (JSON_HEDLEY_UNLIKELY(!check_bson_document_size(top.start_position, top.declared_size)))
|
||||||
@@ -364,8 +399,7 @@ class binary_reader
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
container_stack.pop_back();
|
if (JSON_HEDLEY_UNLIKELY(!leave_container()))
|
||||||
if (JSON_HEDLEY_UNLIKELY(top.is_object ? !sax->end_object() : !sax->end_array()))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -860,29 +894,13 @@ class binary_reader
|
|||||||
return enter_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
|
return enter_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
|
||||||
|
|
||||||
case 0x98: // array (one-byte uint8_t for n follows)
|
case 0x98: // array (one-byte uint8_t for n follows)
|
||||||
{
|
|
||||||
std::uint8_t len{};
|
|
||||||
return get_number(input_format_t::cbor, len) && enter_array(static_cast<std::size_t>(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x99: // array (two-byte uint16_t for n follow)
|
case 0x99: // array (two-byte uint16_t for n follow)
|
||||||
{
|
|
||||||
std::uint16_t len{};
|
|
||||||
return get_number(input_format_t::cbor, len) && enter_array(static_cast<std::size_t>(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x9A: // array (four-byte uint32_t for n follow)
|
case 0x9A: // array (four-byte uint32_t for n follow)
|
||||||
{
|
|
||||||
std::uint32_t len{};
|
|
||||||
std::size_t size{};
|
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_container_size(len, size, "array") && enter_array(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x9B: // array (eight-byte uint64_t for n follow)
|
case 0x9B: // array (eight-byte uint64_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_container_size(len, size, "array") && enter_array(size);
|
return get_cbor_argument(len) && get_cbor_container_size(len, size, "array") && enter_array(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9F: // array (indefinite length)
|
case 0x9F: // array (indefinite length)
|
||||||
@@ -916,35 +934,19 @@ class binary_reader
|
|||||||
return enter_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
|
return enter_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
|
||||||
|
|
||||||
case 0xB8: // map (one-byte uint8_t for n follows)
|
case 0xB8: // map (one-byte uint8_t for n follows)
|
||||||
{
|
|
||||||
std::uint8_t len{};
|
|
||||||
return get_number(input_format_t::cbor, len) && enter_object(static_cast<std::size_t>(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0xB9: // map (two-byte uint16_t for n follow)
|
case 0xB9: // map (two-byte uint16_t for n follow)
|
||||||
{
|
|
||||||
std::uint16_t len{};
|
|
||||||
return get_number(input_format_t::cbor, len) && enter_object(static_cast<std::size_t>(len));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0xBA: // map (four-byte uint32_t for n follow)
|
case 0xBA: // map (four-byte uint32_t for n follow)
|
||||||
{
|
|
||||||
std::uint32_t len{};
|
|
||||||
std::size_t size{};
|
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_container_size(len, size, "map") && enter_object(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0xBB: // map (eight-byte uint64_t for n follow)
|
case 0xBB: // map (eight-byte uint64_t for n follow)
|
||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
return get_number(input_format_t::cbor, len) && get_cbor_container_size(len, size, "map") && enter_object(size);
|
return get_cbor_argument(len) && get_cbor_container_size(len, size, "map") && enter_object(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xBF: // map (indefinite length)
|
case 0xBF: // map (indefinite length)
|
||||||
return enter_object(detail::unknown_size());
|
return enter_object(detail::unknown_size());
|
||||||
|
|
||||||
case 0xC0: // tagged item
|
case 0xC0: // tagged item (tag value 0-23, in the head itself)
|
||||||
case 0xC1:
|
case 0xC1:
|
||||||
case 0xC2:
|
case 0xC2:
|
||||||
case 0xC3:
|
case 0xC3:
|
||||||
@@ -968,6 +970,22 @@ class binary_reader
|
|||||||
case 0xD5:
|
case 0xD5:
|
||||||
case 0xD6:
|
case 0xD6:
|
||||||
case 0xD7:
|
case 0xD7:
|
||||||
|
{
|
||||||
|
if (tag_handler == 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, concat("invalid byte: 0x", last_token), "value"), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore and store: the tag value is already in the head, so
|
||||||
|
// there is nothing left to read here; the tagged value that
|
||||||
|
// follows is read by the loop in parse_cbor_internal() rather
|
||||||
|
// than by recursing here
|
||||||
|
tag_pending = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case 0xD8: // tagged item (1 byte follows)
|
case 0xD8: // tagged item (1 byte follows)
|
||||||
case 0xD9: // tagged item (2 bytes follow)
|
case 0xD9: // tagged item (2 bytes follow)
|
||||||
case 0xDA: // tagged item (4 bytes follow)
|
case 0xDA: // tagged item (4 bytes follow)
|
||||||
@@ -984,47 +1002,11 @@ class binary_reader
|
|||||||
|
|
||||||
case cbor_tag_handler_t::ignore:
|
case cbor_tag_handler_t::ignore:
|
||||||
{
|
{
|
||||||
// ignore binary subtype
|
// ignore the tag's binary subtype argument
|
||||||
switch (current)
|
std::uint64_t subtype_to_ignore{};
|
||||||
|
if (!get_cbor_argument(subtype_to_ignore))
|
||||||
{
|
{
|
||||||
case 0xD8:
|
return false;
|
||||||
{
|
|
||||||
std::uint8_t subtype_to_ignore{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype_to_ignore))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xD9:
|
|
||||||
{
|
|
||||||
std::uint16_t subtype_to_ignore{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype_to_ignore))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xDA:
|
|
||||||
{
|
|
||||||
std::uint32_t subtype_to_ignore{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype_to_ignore))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xDB:
|
|
||||||
{
|
|
||||||
std::uint64_t subtype_to_ignore{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype_to_ignore))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
// the tagged value follows; it is read by the loop in
|
// the tagged value follows; it is read by the loop in
|
||||||
// parse_cbor_internal() rather than by recursing here
|
// parse_cbor_internal() rather than by recursing here
|
||||||
@@ -1034,57 +1016,15 @@ class binary_reader
|
|||||||
|
|
||||||
case cbor_tag_handler_t::store:
|
case cbor_tag_handler_t::store:
|
||||||
{
|
{
|
||||||
binary_t b;
|
|
||||||
// use binary subtype and store in a binary container
|
// use binary subtype and store in a binary container
|
||||||
switch (current)
|
std::uint64_t subtype{};
|
||||||
|
if (!get_cbor_argument(subtype))
|
||||||
{
|
{
|
||||||
case 0xD8:
|
return false;
|
||||||
{
|
|
||||||
std::uint8_t subtype{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xD9:
|
|
||||||
{
|
|
||||||
std::uint16_t subtype{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xDA:
|
|
||||||
{
|
|
||||||
std::uint32_t subtype{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0xDB:
|
|
||||||
{
|
|
||||||
std::uint64_t subtype{};
|
|
||||||
if (!get_number(input_format_t::cbor, subtype))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
// as above, the tagged value is read by the caller
|
|
||||||
tag_pending = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
binary_t b;
|
||||||
|
b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
|
||||||
|
|
||||||
get();
|
get();
|
||||||
// a byte string (the heads accepted by get_cbor_binary) keeps the tag as subtype
|
// a byte string (the heads accepted by get_cbor_binary) keeps the tag as subtype
|
||||||
if ((current >= 0x40 && current <= 0x5B) || current == 0x5F)
|
if ((current >= 0x40 && current <= 0x5B) || current == 0x5F)
|
||||||
@@ -1115,52 +1055,7 @@ class binary_reader
|
|||||||
return sax->null();
|
return sax->null();
|
||||||
|
|
||||||
case 0xF9: // Half-Precision Float (two-byte IEEE 754)
|
case 0xF9: // Half-Precision Float (two-byte IEEE 754)
|
||||||
{
|
return get_half_float(input_format_t::cbor, false);
|
||||||
const auto byte1_raw = get();
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto byte2_raw = get();
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto byte1 = static_cast<unsigned char>(byte1_raw);
|
|
||||||
const auto byte2 = static_cast<unsigned char>(byte2_raw);
|
|
||||||
|
|
||||||
// Code from RFC 8949, Appendix D, Figure 3:
|
|
||||||
// As half-precision floating-point numbers were only added
|
|
||||||
// to IEEE 754 in 2008, today's programming platforms often
|
|
||||||
// still only have limited support for them. It is very
|
|
||||||
// easy to include at least decoding support for them even
|
|
||||||
// without such support. An example of a small decoder for
|
|
||||||
// half-precision floating-point numbers in the C language
|
|
||||||
// is shown in Fig. 3.
|
|
||||||
const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
|
|
||||||
const double val = [&half]
|
|
||||||
{
|
|
||||||
const int exp = (half >> 10u) & 0x1Fu;
|
|
||||||
const unsigned int mant = half & 0x3FFu;
|
|
||||||
JSON_ASSERT(exp <= 31);
|
|
||||||
JSON_ASSERT(mant <= 1023);
|
|
||||||
switch (exp)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return std::ldexp(mant, -24);
|
|
||||||
case 31:
|
|
||||||
return (mant == 0)
|
|
||||||
? std::numeric_limits<double>::infinity()
|
|
||||||
: std::numeric_limits<double>::quiet_NaN();
|
|
||||||
default:
|
|
||||||
return std::ldexp(mant + 1024, exp - 25);
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
return sax->number_float((half & 0x8000u) != 0
|
|
||||||
? static_cast<number_float_t>(-val)
|
|
||||||
: static_cast<number_float_t>(val), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0xFA: // Single-Precision Float (four-byte IEEE 754)
|
case 0xFA: // Single-Precision Float (four-byte IEEE 754)
|
||||||
{
|
{
|
||||||
@@ -1539,6 +1434,73 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief read a CBOR argument (additional information 24-27) of the width
|
||||||
|
@ref current announces
|
||||||
|
|
||||||
|
The lower 5 bits of @a current (0x18-0x1B) select a 1/2/4/8-byte
|
||||||
|
big-endian unsigned integer that follows the head byte; this is shared by
|
||||||
|
every major type that uses this encoding (unsigned/negative integers,
|
||||||
|
strings, arrays, maps, tags). Reading always goes through @ref get_number,
|
||||||
|
so EOF is reported the same way as before this helper existed.
|
||||||
|
|
||||||
|
@param[out] value the decoded argument
|
||||||
|
@return whether reading succeeded
|
||||||
|
*/
|
||||||
|
bool get_cbor_argument(std::uint64_t& value)
|
||||||
|
{
|
||||||
|
switch (current & 0x1F)
|
||||||
|
{
|
||||||
|
case 0x18: // 1 byte
|
||||||
|
{
|
||||||
|
std::uint8_t n{};
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = n;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x19: // 2 bytes
|
||||||
|
{
|
||||||
|
std::uint16_t n{};
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = n;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x1A: // 4 bytes
|
||||||
|
{
|
||||||
|
std::uint32_t n{};
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = n;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x1B: // 8 bytes
|
||||||
|
{
|
||||||
|
std::uint64_t n{};
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::cbor, n)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = n;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief narrow a definite CBOR array/map length to std::size_t
|
@brief narrow a definite CBOR array/map length to std::size_t
|
||||||
|
|
||||||
@@ -1571,19 +1533,15 @@ class binary_reader
|
|||||||
enclosing container after each element, so that the nesting depth of the
|
enclosing container after each element, so that the nesting depth of the
|
||||||
input costs heap rather than native stack (see #5104).
|
input costs heap rather than native stack (see #5104).
|
||||||
|
|
||||||
@param[in] get_char whether a new character should be retrieved from the
|
|
||||||
input (true) or whether the last read character
|
|
||||||
@a current should be considered instead
|
|
||||||
@param[in] tag_handler how CBOR tags should be treated
|
@param[in] tag_handler how CBOR tags should be treated
|
||||||
|
|
||||||
@return whether reading the value succeeded
|
@return whether reading the value succeeded
|
||||||
*/
|
*/
|
||||||
bool parse_cbor_internal(const bool get_char,
|
bool parse_cbor_internal(const cbor_tag_handler_t tag_handler)
|
||||||
const cbor_tag_handler_t tag_handler)
|
|
||||||
{
|
{
|
||||||
// whether the next value starts at a fresh byte or at the one already
|
// whether the next value starts at a fresh byte or at the one already
|
||||||
// read into `current`
|
// read into `current`
|
||||||
bool fetch = get_char;
|
bool fetch = true;
|
||||||
|
|
||||||
// the key currently being read; hoisted out of the loop so that its
|
// the key currently being read; hoisted out of the loop so that its
|
||||||
// capacity is reused across elements and across nesting levels
|
// capacity is reused across elements and across nesting levels
|
||||||
@@ -1626,8 +1584,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (at_end)
|
if (at_end)
|
||||||
{
|
{
|
||||||
container_stack.pop_back();
|
if (JSON_HEDLEY_UNLIKELY(!leave_container()))
|
||||||
if (JSON_HEDLEY_UNLIKELY(top.is_object ? !sax->end_object() : !sax->end_array()))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1676,9 +1633,6 @@ class binary_reader
|
|||||||
// MsgPack //
|
// MsgPack //
|
||||||
/////////////
|
/////////////
|
||||||
|
|
||||||
/*!
|
|
||||||
@return whether a valid MessagePack value was passed to the SAX parser
|
|
||||||
*/
|
|
||||||
/*!
|
/*!
|
||||||
@brief read one MessagePack value
|
@brief read one MessagePack value
|
||||||
|
|
||||||
@@ -2377,8 +2331,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (container_stack.back().remaining == 0)
|
if (container_stack.back().remaining == 0)
|
||||||
{
|
{
|
||||||
container_stack.pop_back();
|
if (JSON_HEDLEY_UNLIKELY(!leave_container()))
|
||||||
if (JSON_HEDLEY_UNLIKELY(is_object ? !sax->end_object() : !sax->end_array()))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2423,20 +2376,16 @@ class binary_reader
|
|||||||
////////////
|
////////////
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@param[in] get_char whether a new character should be retrieved from the
|
|
||||||
input (true, default) or whether the last read
|
|
||||||
character should be considered instead
|
|
||||||
|
|
||||||
@return whether a valid UBJSON value was passed to the SAX parser
|
@return whether a valid UBJSON value was passed to the SAX parser
|
||||||
*/
|
*/
|
||||||
bool parse_ubjson_internal(const bool get_char = true)
|
bool parse_ubjson_internal()
|
||||||
{
|
{
|
||||||
// the key currently being read; hoisted out of the loop so that its
|
// the key currently being read; hoisted out of the loop so that its
|
||||||
// capacity is reused across elements and across nesting levels
|
// capacity is reused across elements and across nesting levels
|
||||||
string_t key;
|
string_t key;
|
||||||
|
|
||||||
// the type marker of the value to read next
|
// the type marker of the value to read next
|
||||||
char_int_type prefix = get_char ? get_ignore_noop() : current;
|
char_int_type prefix = get_ignore_noop();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -2511,8 +2460,7 @@ class binary_reader
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
container_stack.pop_back();
|
if (JSON_HEDLEY_UNLIKELY(!leave_container()))
|
||||||
if (JSON_HEDLEY_UNLIKELY(top.is_object ? !sax->end_object() : !sax->end_array()))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2720,6 +2668,42 @@ class binary_reader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief read a UBJSON/BJData optimized-container count of a signed marker
|
||||||
|
type ('i', 'I', 'l', 'L') and narrow it to std::size_t
|
||||||
|
|
||||||
|
Every signed count marker rejects a negative value the same way (error
|
||||||
|
113); the value_in_range_of check additionally needed for 'L' is only
|
||||||
|
ever live when @a SignedType is std::int64_t on a target where
|
||||||
|
std::size_t is narrower (e.g. 32-bit), since 'i'/'I'/'l' can never exceed
|
||||||
|
std::size_t there.
|
||||||
|
|
||||||
|
@tparam SignedType std::int8_t, std::int16_t, std::int32_t or std::int64_t
|
||||||
|
@param[out] result the count narrowed to std::size_t
|
||||||
|
@return whether reading and validating succeeded
|
||||||
|
*/
|
||||||
|
template<typename SignedType>
|
||||||
|
bool get_ubjson_signed_count(std::size_t& result)
|
||||||
|
{
|
||||||
|
SignedType number{};
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(number < 0))
|
||||||
|
{
|
||||||
|
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
||||||
|
exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
|
||||||
|
}
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(number)))
|
||||||
|
{
|
||||||
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
|
||||||
|
exception_message(input_format, "integer value overflow", "size"), nullptr));
|
||||||
|
}
|
||||||
|
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@param[out] result determined size
|
@param[out] result determined size
|
||||||
@param[in,out] is_ndarray for input, `true` means already inside an ndarray vector
|
@param[in,out] is_ndarray for input, `true` means already inside an ndarray vector
|
||||||
@@ -2752,73 +2736,16 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
return get_ubjson_signed_count<std::int8_t>(result);
|
||||||
std::int8_t number{};
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (number < 0)
|
|
||||||
{
|
|
||||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
|
||||||
exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
|
|
||||||
}
|
|
||||||
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
{
|
return get_ubjson_signed_count<std::int16_t>(result);
|
||||||
std::int16_t number{};
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (number < 0)
|
|
||||||
{
|
|
||||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
|
||||||
exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
|
|
||||||
}
|
|
||||||
result = static_cast<std::size_t>(number);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
{
|
return get_ubjson_signed_count<std::int32_t>(result);
|
||||||
std::int32_t number{};
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (number < 0)
|
|
||||||
{
|
|
||||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
|
||||||
exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
|
|
||||||
}
|
|
||||||
result = static_cast<std::size_t>(number);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
{
|
return get_ubjson_signed_count<std::int64_t>(result);
|
||||||
std::int64_t number{};
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (number < 0)
|
|
||||||
{
|
|
||||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
|
||||||
exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
|
|
||||||
}
|
|
||||||
if (!value_in_range_of<std::size_t>(number))
|
|
||||||
{
|
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
|
|
||||||
exception_message(input_format, "integer value overflow", "size"), nullptr));
|
|
||||||
}
|
|
||||||
result = static_cast<std::size_t>(number);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
{
|
{
|
||||||
@@ -2909,16 +2836,23 @@ class binary_reader
|
|||||||
result = 1;
|
result = 1;
|
||||||
for (auto i : dim)
|
for (auto i : dim)
|
||||||
{
|
{
|
||||||
// Pre-multiplication overflow check: if i > 0 and result > SIZE_MAX/i, then result*i would overflow.
|
// Pre-multiplication overflow check: since the loop above
|
||||||
// This check must happen before multiplication since overflow detection after the fact is unreliable
|
// already rejected any zero dimension, i is always > 0
|
||||||
// as modular arithmetic can produce any value, not just 0 or SIZE_MAX.
|
// here, so result > SIZE_MAX/i means result*i would
|
||||||
if (JSON_HEDLEY_UNLIKELY(i > 0 && result > (std::numeric_limits<std::size_t>::max)() / i))
|
// overflow. This check must happen before multiplication
|
||||||
|
// since overflow detection after the fact is unreliable,
|
||||||
|
// as modular arithmetic can produce any value, not just 0
|
||||||
|
// or SIZE_MAX.
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(result > (std::numeric_limits<std::size_t>::max)() / i))
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
result *= i;
|
result *= i;
|
||||||
// Additional post-multiplication check to catch any edge cases the pre-check might miss
|
// the pre-check above already rules out result becoming 0
|
||||||
if (result == 0 || result == npos)
|
// by overflow; the only value it cannot rule out is an
|
||||||
|
// exact match with npos, the sentinel reserved for an
|
||||||
|
// unknown-size container (see get_ubjson_size_type())
|
||||||
|
if (result == npos)
|
||||||
{
|
{
|
||||||
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
|
return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
|
||||||
}
|
}
|
||||||
@@ -2979,7 +2913,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
result.second = get(); // must not ignore 'N', because 'N' maybe the type
|
result.second = get(); // must not ignore 'N', because 'N' maybe the type
|
||||||
if (input_format == input_format_t::bjdata
|
if (input_format == input_format_t::bjdata
|
||||||
&& JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second)))
|
&& JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second)))
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
auto last_token = get_token_string();
|
||||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
@@ -3123,50 +3057,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const auto byte1_raw = get();
|
return get_half_float(input_format, true);
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto byte2_raw = get();
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto byte1 = static_cast<unsigned char>(byte1_raw);
|
|
||||||
const auto byte2 = static_cast<unsigned char>(byte2_raw);
|
|
||||||
|
|
||||||
// Code from RFC 8949, Appendix D, Figure 3:
|
|
||||||
// As half-precision floating-point numbers were only added
|
|
||||||
// to IEEE 754 in 2008, today's programming platforms often
|
|
||||||
// still only have limited support for them. It is very
|
|
||||||
// easy to include at least decoding support for them even
|
|
||||||
// without such support. An example of a small decoder for
|
|
||||||
// half-precision floating-point numbers in the C language
|
|
||||||
// is shown in Fig. 3.
|
|
||||||
const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1);
|
|
||||||
const double val = [&half]
|
|
||||||
{
|
|
||||||
const int exp = (half >> 10u) & 0x1Fu;
|
|
||||||
const unsigned int mant = half & 0x3FFu;
|
|
||||||
JSON_ASSERT(exp <= 31);
|
|
||||||
JSON_ASSERT(mant <= 1023);
|
|
||||||
switch (exp)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return std::ldexp(mant, -24);
|
|
||||||
case 31:
|
|
||||||
return (mant == 0)
|
|
||||||
? std::numeric_limits<double>::infinity()
|
|
||||||
: std::numeric_limits<double>::quiet_NaN();
|
|
||||||
default:
|
|
||||||
return std::ldexp(mant + 1024, exp - 25);
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
return sax->number_float((half & 0x8000u) != 0
|
|
||||||
? static_cast<number_float_t>(-val)
|
|
||||||
: static_cast<number_float_t>(val), "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
@@ -3239,19 +3130,16 @@ class binary_reader
|
|||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
||||||
{
|
{
|
||||||
size_and_type.second &= ~(static_cast<char_int_type>(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker
|
size_and_type.second &= ~(static_cast<char_int_type>(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker
|
||||||
auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t)
|
const char* type_name = bjd_type_name(size_and_type.second);
|
||||||
{
|
|
||||||
return p.first < t;
|
|
||||||
});
|
|
||||||
string_t key = "_ArrayType_";
|
string_t key = "_ArrayType_";
|
||||||
if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second))
|
if (JSON_HEDLEY_UNLIKELY(type_name == nullptr))
|
||||||
{
|
{
|
||||||
auto last_token = get_token_string();
|
auto last_token = get_token_string();
|
||||||
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
|
||||||
exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
|
exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
string_t type = it->second; // sax->string() takes a reference
|
string_t type = type_name; // sax->string() takes a reference
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
|
if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -3543,8 +3431,7 @@ class binary_reader
|
|||||||
|
|
||||||
if (at_end)
|
if (at_end)
|
||||||
{
|
{
|
||||||
container_stack.pop_back();
|
if (JSON_HEDLEY_UNLIKELY(!leave_container()))
|
||||||
if (JSON_HEDLEY_UNLIKELY(top.is_object ? !sax->end_object() : !sax->end_array()))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -4083,6 +3970,68 @@ class binary_reader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief read and decode an IEEE 754 half-precision (16-bit) float
|
||||||
|
|
||||||
|
Used by CBOR (big endian) and BJData (little endian); the two formats
|
||||||
|
only differ in the byte order of the two bytes that make up the half.
|
||||||
|
|
||||||
|
@param[in] format the current format (for diagnostics)
|
||||||
|
@param[in] little_endian whether the two bytes are little endian (BJData)
|
||||||
|
or big endian (CBOR)
|
||||||
|
|
||||||
|
@return whether reading and decoding succeeded
|
||||||
|
*/
|
||||||
|
bool get_half_float(const input_format_t format, const bool little_endian)
|
||||||
|
{
|
||||||
|
const auto byte1_raw = get();
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto byte2_raw = get();
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto byte1 = static_cast<unsigned char>(byte1_raw);
|
||||||
|
const auto byte2 = static_cast<unsigned char>(byte2_raw);
|
||||||
|
|
||||||
|
// Code from RFC 8949, Appendix D, Figure 3:
|
||||||
|
// As half-precision floating-point numbers were only added
|
||||||
|
// to IEEE 754 in 2008, today's programming platforms often
|
||||||
|
// still only have limited support for them. It is very
|
||||||
|
// easy to include at least decoding support for them even
|
||||||
|
// without such support. An example of a small decoder for
|
||||||
|
// half-precision floating-point numbers in the C language
|
||||||
|
// is shown in Fig. 3.
|
||||||
|
const auto half = little_endian
|
||||||
|
? static_cast<unsigned int>((byte2 << 8u) + byte1)
|
||||||
|
: static_cast<unsigned int>((byte1 << 8u) + byte2);
|
||||||
|
const double val = [&half]
|
||||||
|
{
|
||||||
|
const int exp = (half >> 10u) & 0x1Fu;
|
||||||
|
const unsigned int mant = half & 0x3FFu;
|
||||||
|
JSON_ASSERT(exp <= 31);
|
||||||
|
JSON_ASSERT(mant <= 1023);
|
||||||
|
switch (exp)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return std::ldexp(mant, -24);
|
||||||
|
case 31:
|
||||||
|
return (mant == 0)
|
||||||
|
? std::numeric_limits<double>::infinity()
|
||||||
|
: std::numeric_limits<double>::quiet_NaN();
|
||||||
|
default:
|
||||||
|
return std::ldexp(mant + 1024, exp - 25);
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
return sax->number_float((half & 0x8000u) != 0
|
||||||
|
? static_cast<number_float_t>(-val)
|
||||||
|
: static_cast<number_float_t>(val), "");
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief create a string by reading characters from the input
|
@brief create a string by reading characters from the input
|
||||||
|
|
||||||
@@ -4308,38 +4257,61 @@ class binary_reader
|
|||||||
/// BON8: number of bytes in @ref bon8_pushback
|
/// BON8: number of bytes in @ref bon8_pushback
|
||||||
std::size_t bon8_pushback_size = 0;
|
std::size_t bon8_pushback_size = 0;
|
||||||
|
|
||||||
// excluded markers in bjdata optimized type
|
|
||||||
#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \
|
|
||||||
make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{')
|
|
||||||
|
|
||||||
#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"}, \
|
|
||||||
bjd_type{'L', "int64"}, \
|
|
||||||
bjd_type{'M', "uint64"}, \
|
|
||||||
bjd_type{'U', "uint8"}, \
|
|
||||||
bjd_type{'d', "single"}, \
|
|
||||||
bjd_type{'i', "int8"}, \
|
|
||||||
bjd_type{'l', "int32"}, \
|
|
||||||
bjd_type{'m', "uint32"}, \
|
|
||||||
bjd_type{'u', "uint16"})
|
|
||||||
|
|
||||||
JSON_PRIVATE_UNLESS_TESTED:
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
// lookup tables
|
/*!
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
|
@brief whether @a marker is excluded from BJData's optimized ND-array types
|
||||||
const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers =
|
@return whether @a marker is one of 'F', 'H', 'N', 'S', 'T', 'Z', '[', '{'
|
||||||
JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_;
|
|
||||||
|
|
||||||
using bjd_type = std::pair<char_int_type, string_t>;
|
Mirrors binary_writer's @ref binary_writer::is_bjdata_excluded_type_marker
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
|
"is_bjdata_excluded_type_marker()`, which encodes the same list the other
|
||||||
const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map =
|
way; keep the two in sync.
|
||||||
JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_;
|
*/
|
||||||
|
static constexpr bool is_bjd_excluded_optimized_type(const char_int_type marker) noexcept
|
||||||
|
{
|
||||||
|
return marker == '[' || marker == '{' || marker == 'S' || marker == 'H'
|
||||||
|
|| marker == 'T' || marker == 'F' || marker == 'N' || marker == 'Z';
|
||||||
|
}
|
||||||
|
|
||||||
#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_
|
/*!
|
||||||
#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_
|
@brief look up the ND-array element type name for a BJData dtype marker
|
||||||
|
@return the type name ("uint8", "int8", ...), or nullptr if @a marker does
|
||||||
|
not name a known dtype
|
||||||
|
|
||||||
|
A C++11 `constexpr` function cannot contain a `switch`, so this is a
|
||||||
|
plain (non-constexpr) switch instead.
|
||||||
|
*/
|
||||||
|
static const char* bjd_type_name(const char_int_type marker)
|
||||||
|
{
|
||||||
|
switch (marker)
|
||||||
|
{
|
||||||
|
case 'B':
|
||||||
|
return "byte";
|
||||||
|
case 'C':
|
||||||
|
return "char";
|
||||||
|
case 'D':
|
||||||
|
return "double";
|
||||||
|
case 'I':
|
||||||
|
return "int16";
|
||||||
|
case 'L':
|
||||||
|
return "int64";
|
||||||
|
case 'M':
|
||||||
|
return "uint64";
|
||||||
|
case 'U':
|
||||||
|
return "uint8";
|
||||||
|
case 'd':
|
||||||
|
return "single";
|
||||||
|
case 'i':
|
||||||
|
return "int8";
|
||||||
|
case 'l':
|
||||||
|
return "int32";
|
||||||
|
case 'm':
|
||||||
|
return "uint32";
|
||||||
|
case 'u':
|
||||||
|
return "uint16";
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef JSON_HAS_CPP_17
|
#ifndef JSON_HAS_CPP_17
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array> // array
|
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
|
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
|
||||||
#include <utility> // index_sequence, make_index_sequence, index_sequence_for
|
#include <utility> // index_sequence, make_index_sequence, index_sequence_for
|
||||||
@@ -161,11 +160,5 @@ struct static_const
|
|||||||
constexpr T static_const<T>::value;
|
constexpr T static_const<T>::value;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args)
|
|
||||||
{
|
|
||||||
return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+19
-19
@@ -5034,7 +5034,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief generate SAX events (iterator pair, or iterator+sentinel pair for C++20 ranges support)
|
/// @brief generate SAX events (iterator pair, or iterator+sentinel pair for C++20 ranges support)
|
||||||
@@ -5051,7 +5051,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
return format == input_format_t::json
|
return format == input_format_t::json
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief generate SAX events
|
/// @brief generate SAX events
|
||||||
@@ -5073,7 +5073,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
? parser(std::move(ia), nullptr, true, ignore_comments, ignore_trailing_commas).sax_parse(sax, strict)
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
|
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(sax, strict);
|
||||||
}
|
}
|
||||||
#ifndef JSON_NO_IO
|
#ifndef JSON_NO_IO
|
||||||
/// @brief deserialize from stream
|
/// @brief deserialize from stream
|
||||||
@@ -5371,7 +5371,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(&sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5391,7 +5391,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(&sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5420,7 +5420,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
auto ia = i.get();
|
auto ia = i.get();
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(&sdp, strict, tag_handler)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5438,7 +5438,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5457,7 +5457,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5484,7 +5484,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
auto ia = i.get();
|
auto ia = i.get();
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5502,7 +5502,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5521,7 +5521,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5548,7 +5548,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
auto ia = i.get();
|
auto ia = i.get();
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5566,7 +5566,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5585,7 +5585,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5603,7 +5603,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bon8).sax_parse(input_format_t::bon8, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bon8).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5622,7 +5622,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bon8).sax_parse(input_format_t::bon8, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bon8).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5640,7 +5640,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
auto ia = detail::input_adapter(std::forward<InputType>(i));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5659,7 +5659,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
basic_json result;
|
basic_json result;
|
||||||
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
auto ia = detail::input_adapter(std::move(first), std::move(last));
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
@@ -5686,7 +5686,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
auto ia = i.get();
|
auto ia = i.get();
|
||||||
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict)) // cppcheck-suppress[accessMoved]
|
if (!binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(&sdp, strict)) // cppcheck-suppress[accessMoved]
|
||||||
{
|
{
|
||||||
result = value_t::discarded;
|
result = value_t::discarded;
|
||||||
}
|
}
|
||||||
|
|||||||
+700
-887
File diff suppressed because it is too large
Load Diff
@@ -210,15 +210,42 @@ TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
|||||||
|
|
||||||
TEST_CASE("BJData")
|
TEST_CASE("BJData")
|
||||||
{
|
{
|
||||||
SECTION("binary_reader BJData LUT arrays are sorted")
|
SECTION("binary_reader BJData lookup tables")
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> const data;
|
std::vector<std::uint8_t> const data;
|
||||||
auto ia = nlohmann::detail::input_adapter(data);
|
auto ia = nlohmann::detail::input_adapter(data);
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
|
||||||
nlohmann::detail::binary_reader<json, decltype(ia)> const br{std::move(ia), json::input_format_t::bjdata};
|
nlohmann::detail::binary_reader<json, decltype(ia)> const br{std::move(ia), json::input_format_t::bjdata};
|
||||||
|
|
||||||
CHECK(std::is_sorted(br.bjd_optimized_type_markers.begin(), br.bjd_optimized_type_markers.end()));
|
// the excluded optimized-type markers must match binary_writer's
|
||||||
CHECK(std::is_sorted(br.bjd_types_map.begin(), br.bjd_types_map.end()));
|
// is_bjdata_excluded_type_marker(), which encodes the same 8 markers
|
||||||
|
for (const char marker :
|
||||||
|
{'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'
|
||||||
|
})
|
||||||
|
{
|
||||||
|
CHECK(br.is_bjd_excluded_optimized_type(marker));
|
||||||
|
}
|
||||||
|
for (const char marker :
|
||||||
|
{'U', 'i', 'u', 'I', 'm', 'l', 'M', 'L', 'd', 'D', 'C', 'B', 'x'
|
||||||
|
})
|
||||||
|
{
|
||||||
|
CHECK(!br.is_bjd_excluded_optimized_type(marker));
|
||||||
|
}
|
||||||
|
|
||||||
|
// every dtype marker must round-trip to its ND-array type name
|
||||||
|
const std::vector<std::pair<char, std::string>> types
|
||||||
|
{
|
||||||
|
{'B', "byte"}, {'C', "char"}, {'D', "double"}, {'I', "int16"},
|
||||||
|
{'L', "int64"}, {'M', "uint64"}, {'U', "uint8"}, {'d', "single"},
|
||||||
|
{'i', "int8"}, {'l', "int32"}, {'m', "uint32"}, {'u', "uint16"}
|
||||||
|
};
|
||||||
|
for (const auto& type : types)
|
||||||
|
{
|
||||||
|
const char* name = br.bjd_type_name(type.first);
|
||||||
|
REQUIRE(name != nullptr);
|
||||||
|
CHECK(std::string(name) == type.second);
|
||||||
|
}
|
||||||
|
CHECK(br.bjd_type_name('x') == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("individual values")
|
SECTION("individual values")
|
||||||
|
|||||||
@@ -3033,3 +3033,224 @@ TEST_CASE("UBJSON optimized array of unsigned integers beyond int64")
|
|||||||
CHECK(json::to_ubjson(j, true, true) == expected);
|
CHECK(json::to_ubjson(j, true, true) == expected);
|
||||||
CHECK(json::from_ubjson(expected) == j);
|
CHECK(json::from_ubjson(expected) == j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// the bytes that follow the marker of an integer: the value in the width of
|
||||||
|
// the marker (big endian for UBJSON, little endian for BJData), or, for a
|
||||||
|
// high-precision number, the length and the decimal digits
|
||||||
|
std::vector<std::uint8_t> integer_payload(const char marker, const json& value, const bool little_endian)
|
||||||
|
{
|
||||||
|
std::size_t width = 0;
|
||||||
|
switch (marker)
|
||||||
|
{
|
||||||
|
case 'i':
|
||||||
|
case 'U':
|
||||||
|
width = 1;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
case 'u':
|
||||||
|
width = 2;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
case 'm':
|
||||||
|
width = 4;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
case 'M':
|
||||||
|
width = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
const std::string digits = value.dump();
|
||||||
|
std::vector<std::uint8_t> result = {'i', static_cast<std::uint8_t>(digits.size())};
|
||||||
|
for (const char c : digits)
|
||||||
|
{
|
||||||
|
result.push_back(static_cast<std::uint8_t>(c));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::uint64_t bits = value.is_number_unsigned()
|
||||||
|
? value.get<std::uint64_t>()
|
||||||
|
: static_cast<std::uint64_t>(value.get<std::int64_t>());
|
||||||
|
std::vector<std::uint8_t> result(width);
|
||||||
|
for (std::size_t i = 0; i < width; ++i)
|
||||||
|
{
|
||||||
|
result[little_endian ? i : width - 1 - i] = static_cast<std::uint8_t>(bits >> (8 * i));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
json i64(const std::int64_t v)
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
json u64(const std::uint64_t v)
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST_CASE("UBJSON and BJData integer markers at every range edge")
|
||||||
|
{
|
||||||
|
// An optimized container announces the marker of its values after `$` and
|
||||||
|
// then writes every value without a marker, so the marker the writer
|
||||||
|
// announces and the width it writes must match for every value. This
|
||||||
|
// checks both for the values around each edge of the integer types, as
|
||||||
|
// scalars and as the values of optimized arrays and objects.
|
||||||
|
struct integer_case
|
||||||
|
{
|
||||||
|
json value;
|
||||||
|
char ubjson; // expected UBJSON marker
|
||||||
|
char bjdata; // expected BJData marker
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::int64_t int64_min = (std::numeric_limits<std::int64_t>::min)();
|
||||||
|
const std::int64_t int64_max = (std::numeric_limits<std::int64_t>::max)();
|
||||||
|
const std::uint64_t uint64_max = (std::numeric_limits<std::uint64_t>::max)();
|
||||||
|
|
||||||
|
const std::vector<integer_case> cases =
|
||||||
|
{
|
||||||
|
// int8
|
||||||
|
{i64(-129), 'I', 'I'},
|
||||||
|
{i64(-128), 'i', 'i'},
|
||||||
|
{i64(-127), 'i', 'i'},
|
||||||
|
{i64(-1), 'i', 'i'},
|
||||||
|
{i64(0), 'i', 'i'},
|
||||||
|
{u64(0), 'i', 'i'},
|
||||||
|
{i64(126), 'i', 'i'},
|
||||||
|
{i64(127), 'i', 'i'},
|
||||||
|
{u64(127), 'i', 'i'},
|
||||||
|
{i64(128), 'U', 'U'},
|
||||||
|
{u64(128), 'U', 'U'},
|
||||||
|
// uint8
|
||||||
|
{i64(254), 'U', 'U'},
|
||||||
|
{i64(255), 'U', 'U'},
|
||||||
|
{u64(255), 'U', 'U'},
|
||||||
|
{i64(256), 'I', 'I'},
|
||||||
|
{u64(256), 'I', 'I'},
|
||||||
|
// int16
|
||||||
|
{i64(-32769), 'l', 'l'},
|
||||||
|
{i64(-32768), 'I', 'I'},
|
||||||
|
{i64(-32767), 'I', 'I'},
|
||||||
|
{i64(32766), 'I', 'I'},
|
||||||
|
{i64(32767), 'I', 'I'},
|
||||||
|
{u64(32767), 'I', 'I'},
|
||||||
|
{i64(32768), 'l', 'u'},
|
||||||
|
{u64(32768), 'l', 'u'},
|
||||||
|
// uint16 (BJData only)
|
||||||
|
{i64(65534), 'l', 'u'},
|
||||||
|
{i64(65535), 'l', 'u'},
|
||||||
|
{u64(65535), 'l', 'u'},
|
||||||
|
{i64(65536), 'l', 'l'},
|
||||||
|
{u64(65536), 'l', 'l'},
|
||||||
|
// int32
|
||||||
|
{i64(-2147483649LL), 'L', 'L'},
|
||||||
|
{i64(-2147483648LL), 'l', 'l'},
|
||||||
|
{i64(-2147483647LL), 'l', 'l'},
|
||||||
|
{i64(2147483646LL), 'l', 'l'},
|
||||||
|
{i64(2147483647LL), 'l', 'l'},
|
||||||
|
{u64(2147483647ULL), 'l', 'l'},
|
||||||
|
{i64(2147483648LL), 'L', 'm'},
|
||||||
|
{u64(2147483648ULL), 'L', 'm'},
|
||||||
|
// uint32 (BJData only)
|
||||||
|
{i64(4294967294LL), 'L', 'm'},
|
||||||
|
{i64(4294967295LL), 'L', 'm'},
|
||||||
|
{u64(4294967295ULL), 'L', 'm'},
|
||||||
|
{i64(4294967296LL), 'L', 'L'},
|
||||||
|
{u64(4294967296ULL), 'L', 'L'},
|
||||||
|
// int64
|
||||||
|
{i64(int64_min), 'L', 'L'},
|
||||||
|
{i64(int64_min + 1), 'L', 'L'},
|
||||||
|
{i64(int64_max - 1), 'L', 'L'},
|
||||||
|
{i64(int64_max), 'L', 'L'},
|
||||||
|
{u64(static_cast<std::uint64_t>(int64_max)), 'L', 'L'},
|
||||||
|
// uint64 (BJData only; UBJSON writes a high-precision number)
|
||||||
|
{u64(static_cast<std::uint64_t>(int64_max) + 1), 'H', 'M'},
|
||||||
|
{u64(uint64_max - 1), 'H', 'M'},
|
||||||
|
{u64(uint64_max), 'H', 'M'},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& c : cases)
|
||||||
|
{
|
||||||
|
for (const bool bjdata :
|
||||||
|
{
|
||||||
|
false, true
|
||||||
|
})
|
||||||
|
{
|
||||||
|
const char marker = bjdata ? c.bjdata : c.ubjson;
|
||||||
|
const std::vector<std::uint8_t> payload = integer_payload(marker, c.value, bjdata);
|
||||||
|
const auto to_binary = [bjdata](const json & j, const bool use_size, const bool use_type)
|
||||||
|
{
|
||||||
|
return bjdata ? json::to_bjdata(j, use_size, use_type) : json::to_ubjson(j, use_size, use_type);
|
||||||
|
};
|
||||||
|
const auto from_binary = [bjdata](const std::vector<std::uint8_t>& v)
|
||||||
|
{
|
||||||
|
return bjdata ? json::from_bjdata(v) : json::from_ubjson(v);
|
||||||
|
};
|
||||||
|
INFO("value = " << c.value.dump() << (c.value.is_number_unsigned() ? " (unsigned)" : "") << ", format = " << (bjdata ? "BJData" : "UBJSON"));
|
||||||
|
|
||||||
|
// scalar
|
||||||
|
std::vector<std::uint8_t> expected = {static_cast<std::uint8_t>(marker)};
|
||||||
|
expected.insert(expected.end(), payload.begin(), payload.end());
|
||||||
|
for (const bool use_size :
|
||||||
|
{
|
||||||
|
false, true
|
||||||
|
})
|
||||||
|
{
|
||||||
|
CHECK(to_binary(c.value, use_size, false) == expected);
|
||||||
|
}
|
||||||
|
CHECK(from_binary(expected) == c.value);
|
||||||
|
|
||||||
|
const json arr = {c.value, c.value, c.value};
|
||||||
|
|
||||||
|
// array without count or type: every value has its marker
|
||||||
|
expected = {'['};
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
expected.push_back(static_cast<std::uint8_t>(marker));
|
||||||
|
expected.insert(expected.end(), payload.begin(), payload.end());
|
||||||
|
}
|
||||||
|
expected.push_back(']');
|
||||||
|
CHECK(to_binary(arr, false, false) == expected);
|
||||||
|
CHECK(from_binary(expected) == arr);
|
||||||
|
|
||||||
|
// array with count: every value has its marker
|
||||||
|
expected = {'[', '#', 'i', 3};
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
expected.push_back(static_cast<std::uint8_t>(marker));
|
||||||
|
expected.insert(expected.end(), payload.begin(), payload.end());
|
||||||
|
}
|
||||||
|
CHECK(to_binary(arr, true, false) == expected);
|
||||||
|
CHECK(from_binary(expected) == arr);
|
||||||
|
|
||||||
|
// array with type and count: the marker once, then the payloads
|
||||||
|
expected = {'[', '$', static_cast<std::uint8_t>(marker), '#', 'i', 3};
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
expected.insert(expected.end(), payload.begin(), payload.end());
|
||||||
|
}
|
||||||
|
CHECK(to_binary(arr, true, true) == expected);
|
||||||
|
CHECK(from_binary(expected) == arr);
|
||||||
|
|
||||||
|
// object with type and count: the marker once, then key and payload
|
||||||
|
const json obj = {{"a", c.value}, {"b", c.value}};
|
||||||
|
expected = {'{', '$', static_cast<std::uint8_t>(marker), '#', 'i', 2};
|
||||||
|
for (const char key :
|
||||||
|
{'a', 'b'
|
||||||
|
})
|
||||||
|
{
|
||||||
|
expected.push_back('i');
|
||||||
|
expected.push_back(1);
|
||||||
|
expected.push_back(static_cast<std::uint8_t>(key));
|
||||||
|
expected.insert(expected.end(), payload.begin(), payload.end());
|
||||||
|
}
|
||||||
|
CHECK(to_binary(obj, true, true) == expected);
|
||||||
|
CHECK(from_binary(expected) == obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user