Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a80aed8b74 | ||
|
|
bae6216491 | ||
|
|
7503394a30 | ||
|
|
caabb97337 |
No files matched your search
@@ -344,8 +344,8 @@ class binary_reader
|
|||||||
nested document could declare a length that disagrees with where its
|
nested document could declare a length that disagrees with where its
|
||||||
terminator actually falls and quietly hand the bytes in between to the
|
terminator actually falls and quietly hand the bytes in between to the
|
||||||
enclosing document. A well-formed document is at least 5 bytes (the prefix
|
enclosing document. A well-formed document is at least 5 bytes (the prefix
|
||||||
plus the terminator); the equality also rejects those impossible sizes,
|
plus the terminator); open_bson_document() rejects a smaller size before
|
||||||
since at least 5 bytes are always consumed.
|
it is stored, so @a document_size is never negative here.
|
||||||
|
|
||||||
@param[in] document_start value of chars_read before the size prefix
|
@param[in] document_start value of chars_read before the size prefix
|
||||||
@param[in] document_size the declared document size
|
@param[in] document_size the declared document size
|
||||||
@@ -353,7 +353,7 @@ class binary_reader
|
|||||||
*/
|
*/
|
||||||
bool check_bson_document_size(const std::size_t document_start, const std::int32_t document_size)
|
bool check_bson_document_size(const std::size_t document_start, const std::int32_t document_size)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast<std::size_t>(document_size) != chars_read - document_start))
|
if (JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(document_size) != chars_read - document_start))
|
||||||
{
|
{
|
||||||
return bson_document_size_error(document_size, chars_read - document_start);
|
return bson_document_size_error(document_size, chars_read - document_start);
|
||||||
}
|
}
|
||||||
@@ -3091,8 +3091,6 @@ class binary_reader
|
|||||||
if (size_and_type.first != npos)
|
if (size_and_type.first != npos)
|
||||||
{
|
{
|
||||||
if (size_and_type.second != 0)
|
if (size_and_type.second != 0)
|
||||||
{
|
|
||||||
if (size_and_type.second != 'N')
|
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
{
|
{
|
||||||
@@ -3103,7 +3101,6 @@ class binary_reader
|
|||||||
dim.push_back(dimlen);
|
dim.push_back(dimlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
@@ -3303,11 +3300,9 @@ class binary_reader
|
|||||||
// follow the documented _ArrayType_, _ArraySize_, _ArrayData_ order
|
// follow the documented _ArrayType_, _ArraySize_, _ArrayData_ order
|
||||||
if (ndarray_dtype != 0)
|
if (ndarray_dtype != 0)
|
||||||
{
|
{
|
||||||
|
// every optimized type marker is_valid_optimized_type() accepts for BJData has a name
|
||||||
const char* type_name = bjd_type_name(ndarray_dtype);
|
const char* type_name = bjd_type_name(ndarray_dtype);
|
||||||
if (JSON_HEDLEY_UNLIKELY(type_name == nullptr))
|
JSON_ASSERT(type_name != nullptr);
|
||||||
{
|
|
||||||
return unexpected_byte("invalid byte", "type");
|
|
||||||
}
|
|
||||||
|
|
||||||
string_t type_key = "_ArrayType_";
|
string_t type_key = "_ArrayType_";
|
||||||
string_t type = type_name; // sax->string() takes a reference
|
string_t type = type_name; // sax->string() takes a reference
|
||||||
@@ -3390,12 +3385,6 @@ class binary_reader
|
|||||||
if (current == '$')
|
if (current == '$')
|
||||||
{
|
{
|
||||||
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
|
|
||||||
&& JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second)))
|
|
||||||
{
|
|
||||||
return optimized_type_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -3423,7 +3412,7 @@ class binary_reader
|
|||||||
// an ndarray was read here only if the flag flipped; when it was
|
// an ndarray was read here only if the flag flipped; when it was
|
||||||
// seeded true, get_ubjson_size_value() already rejected the nested
|
// seeded true, get_ubjson_size_value() already rejected the nested
|
||||||
// dimension vector
|
// dimension vector
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
if (is_ndarray && !inside_ndarray)
|
||||||
{
|
{
|
||||||
result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
|
result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
|
||||||
}
|
}
|
||||||
@@ -3433,7 +3422,7 @@ class binary_reader
|
|||||||
if (current == '#')
|
if (current == '#')
|
||||||
{
|
{
|
||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
if (is_ndarray && !inside_ndarray)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size");
|
return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size");
|
||||||
}
|
}
|
||||||
@@ -3607,7 +3596,6 @@ class binary_reader
|
|||||||
JSON_HEDLEY_NEVER_INLINE
|
JSON_HEDLEY_NEVER_INLINE
|
||||||
bool parse_ubjson_typed_run(std::size_t& remaining, const char_int_type type, std::true_type /*bulk*/)
|
bool parse_ubjson_typed_run(std::size_t& remaining, const char_int_type type, std::true_type /*bulk*/)
|
||||||
{
|
{
|
||||||
const bool bjdata = input_format == input_format_t::bjdata;
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 'U':
|
case 'U':
|
||||||
@@ -3621,11 +3609,11 @@ class binary_reader
|
|||||||
case 'L':
|
case 'L':
|
||||||
return parse_ubjson_typed_run<std::int64_t>(remaining);
|
return parse_ubjson_typed_run<std::int64_t>(remaining);
|
||||||
case 'u':
|
case 'u':
|
||||||
return !bjdata || parse_ubjson_typed_run<std::uint16_t>(remaining);
|
return parse_ubjson_typed_run<std::uint16_t>(remaining);
|
||||||
case 'm':
|
case 'm':
|
||||||
return !bjdata || parse_ubjson_typed_run<std::uint32_t>(remaining);
|
return parse_ubjson_typed_run<std::uint32_t>(remaining);
|
||||||
case 'M':
|
case 'M':
|
||||||
return !bjdata || parse_ubjson_typed_run<std::uint64_t>(remaining);
|
return parse_ubjson_typed_run<std::uint64_t>(remaining);
|
||||||
case 'd':
|
case 'd':
|
||||||
return parse_ubjson_typed_run<float>(remaining);
|
return parse_ubjson_typed_run<float>(remaining);
|
||||||
case 'D':
|
case 'D':
|
||||||
@@ -3706,7 +3694,7 @@ class binary_reader
|
|||||||
// if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
|
// if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
|
||||||
// {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
|
// {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
|
||||||
|
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
if ((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
|
||||||
|
|
||||||
@@ -3765,7 +3753,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If BJData type marker is 'B' decode as binary
|
// If BJData type marker is 'B' decode as binary
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B')
|
if (size_and_type.first != npos && size_and_type.second == 'B')
|
||||||
{
|
{
|
||||||
binary_t result;
|
binary_t result;
|
||||||
return get_binary(size_and_type.first, result) && sax->binary(result);
|
return get_binary(size_and_type.first, result) && sax->binary(result);
|
||||||
@@ -3814,7 +3802,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do not accept ND-array size in objects in BJData
|
// do not accept ND-array size in objects in BJData
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
if ((size_and_type.second & (1 << 8)) != 0)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object");
|
return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object");
|
||||||
}
|
}
|
||||||
@@ -5095,8 +5083,9 @@ class binary_reader
|
|||||||
JSON_PRIVATE_UNLESS_TESTED:
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
/*!
|
/*!
|
||||||
@brief check whether @a marker is a type marker that may follow '$'
|
@brief check whether @a marker is a type marker that may follow '$'
|
||||||
UBJSON: Z N T F i U I l L d D H C S [ {; BJData: the numeric markers and C
|
UBJSON: Z N T F i U I l L d D H C S [ {; BJData: the numeric markers and C.
|
||||||
(BJData's excluded markers are rejected separately).
|
The markers BJData excludes (F H N S T Z [ {) are the ones
|
||||||
|
binary_writer::is_bjdata_excluded_type_marker() lists; keep the two in sync.
|
||||||
*/
|
*/
|
||||||
bool is_valid_optimized_type(const char_int_type marker) const noexcept
|
bool is_valid_optimized_type(const char_int_type marker) const noexcept
|
||||||
{
|
{
|
||||||
@@ -5131,20 +5120,6 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief whether @a marker is excluded from BJData's optimized ND-array types
|
|
||||||
@return whether @a marker is one of 'F', 'H', 'N', 'S', 'T', 'Z', '[', '{'
|
|
||||||
|
|
||||||
Mirrors binary_writer's @ref binary_writer::is_bjdata_excluded_type_marker
|
|
||||||
"is_bjdata_excluded_type_marker()`, which encodes the same list the other
|
|
||||||
way; keep the two in sync.
|
|
||||||
*/
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief look up the ND-array element type name for a BJData dtype marker
|
@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
|
@return the type name ("uint8", "int8", ...), or nullptr if @a marker does
|
||||||
|
|||||||
@@ -3126,22 +3126,19 @@ class binary_writer
|
|||||||
// negative fixnum
|
// negative fixnum
|
||||||
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
|
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)())
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 8
|
// int 8
|
||||||
oa.write_character(to_char_type(0xD0));
|
oa.write_character(to_char_type(0xD0));
|
||||||
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
|
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)())
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 16
|
// int 16
|
||||||
oa.write_character(to_char_type(0xD1));
|
oa.write_character(to_char_type(0xD1));
|
||||||
write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
|
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)())
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 32
|
// int 32
|
||||||
oa.write_character(to_char_type(0xD2));
|
oa.write_character(to_char_type(0xD2));
|
||||||
@@ -4057,7 +4054,7 @@ class binary_writer
|
|||||||
Containers, strings, high-precision numbers, booleans and null cannot be
|
Containers, strings, high-precision numbers, booleans and null cannot be
|
||||||
declared as the single type of an optimized container in BJData; such a
|
declared as the single type of an optimized container in BJData; such a
|
||||||
container is written unoptimized. The reader rejects them with the same
|
container is written unoptimized. The reader rejects them with the same
|
||||||
list (binary_reader::is_bjd_excluded_optimized_type()).
|
list (binary_reader::is_valid_optimized_type()).
|
||||||
*/
|
*/
|
||||||
static constexpr bool is_bjdata_excluded_type_marker(const CharType marker) noexcept
|
static constexpr bool is_bjdata_excluded_type_marker(const CharType marker) noexcept
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm> // copy, none_of, min, search
|
#include <algorithm> // remove, fill, find, none_of, min
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <clocale> // localeconv, lconv
|
#include <clocale> // localeconv, lconv
|
||||||
#include <cmath> // isfinite
|
#include <cmath> // isfinite
|
||||||
@@ -2080,35 +2080,31 @@ class serializer
|
|||||||
// check if the buffer was large enough
|
// check if the buffer was large enough
|
||||||
JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
|
JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
|
||||||
|
|
||||||
// look up the locale's decimal point now, matching what
|
// look up the locale's thousands separator and decimal point now,
|
||||||
// snprintf_float() just used (see get_decimal_point() in
|
// matching what snprintf_float() just used (see lexer::get_decimal_point())
|
||||||
// number_parse.hpp); it is a string, which can be longer than one
|
|
||||||
// byte (U+066B in ps_AF, #5993).
|
|
||||||
// A thousands separator needs no handling: %g never groups digits.
|
|
||||||
const auto* loc = std::localeconv();
|
const auto* loc = std::localeconv();
|
||||||
JSON_ASSERT(loc != nullptr);
|
JSON_ASSERT(loc != nullptr);
|
||||||
const char* const decimal_point = (loc->decimal_point == nullptr) ? "" : loc->decimal_point;
|
const char thousands_sep = (loc->thousands_sep == nullptr) ? '\0' : *loc->thousands_sep;
|
||||||
const std::size_t decimal_point_len = std::char_traits<char>::length(decimal_point);
|
const char decimal_point = (loc->decimal_point == nullptr) ? '\0' : *loc->decimal_point;
|
||||||
|
|
||||||
|
// erase thousands separators
|
||||||
|
if (thousands_sep != '\0')
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
||||||
|
const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
|
||||||
|
std::fill(end, number_buffer.end(), '\0');
|
||||||
|
JSON_ASSERT((end - number_buffer.begin()) <= len);
|
||||||
|
len = (end - number_buffer.begin());
|
||||||
|
}
|
||||||
|
|
||||||
// convert decimal point to '.'
|
// convert decimal point to '.'
|
||||||
if ((decimal_point_len > 1) || (decimal_point_len == 1 && decimal_point[0] != '.'))
|
if (decimal_point != '\0' && decimal_point != '.')
|
||||||
{
|
{
|
||||||
const auto first = number_buffer.begin();
|
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
||||||
const auto last = first + len;
|
const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
|
||||||
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::search returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
if (dec_pos != number_buffer.end())
|
||||||
const auto dec_pos = std::search(first, last, decimal_point, decimal_point + decimal_point_len);
|
|
||||||
if (dec_pos != last)
|
|
||||||
{
|
{
|
||||||
*dec_pos = '.';
|
*dec_pos = '.';
|
||||||
if (decimal_point_len > 1)
|
|
||||||
{
|
|
||||||
// move the fraction and exponent behind the '.' (std::copy
|
|
||||||
// allows the overlap, as the destination is before the source)
|
|
||||||
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::copy returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
|
||||||
const auto end = std::copy(dec_pos + static_cast<std::ptrdiff_t>(decimal_point_len), last, dec_pos + 1);
|
|
||||||
*end = '\0';
|
|
||||||
len = end - first;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+39
-71
@@ -18359,8 +18359,8 @@ class binary_reader
|
|||||||
nested document could declare a length that disagrees with where its
|
nested document could declare a length that disagrees with where its
|
||||||
terminator actually falls and quietly hand the bytes in between to the
|
terminator actually falls and quietly hand the bytes in between to the
|
||||||
enclosing document. A well-formed document is at least 5 bytes (the prefix
|
enclosing document. A well-formed document is at least 5 bytes (the prefix
|
||||||
plus the terminator); the equality also rejects those impossible sizes,
|
plus the terminator); open_bson_document() rejects a smaller size before
|
||||||
since at least 5 bytes are always consumed.
|
it is stored, so @a document_size is never negative here.
|
||||||
|
|
||||||
@param[in] document_start value of chars_read before the size prefix
|
@param[in] document_start value of chars_read before the size prefix
|
||||||
@param[in] document_size the declared document size
|
@param[in] document_size the declared document size
|
||||||
@@ -18368,7 +18368,7 @@ class binary_reader
|
|||||||
*/
|
*/
|
||||||
bool check_bson_document_size(const std::size_t document_start, const std::int32_t document_size)
|
bool check_bson_document_size(const std::size_t document_start, const std::int32_t document_size)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 0 || static_cast<std::size_t>(document_size) != chars_read - document_start))
|
if (JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(document_size) != chars_read - document_start))
|
||||||
{
|
{
|
||||||
return bson_document_size_error(document_size, chars_read - document_start);
|
return bson_document_size_error(document_size, chars_read - document_start);
|
||||||
}
|
}
|
||||||
@@ -21106,8 +21106,6 @@ class binary_reader
|
|||||||
if (size_and_type.first != npos)
|
if (size_and_type.first != npos)
|
||||||
{
|
{
|
||||||
if (size_and_type.second != 0)
|
if (size_and_type.second != 0)
|
||||||
{
|
|
||||||
if (size_and_type.second != 'N')
|
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
{
|
{
|
||||||
@@ -21118,7 +21116,6 @@ class binary_reader
|
|||||||
dim.push_back(dimlen);
|
dim.push_back(dimlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
for (std::size_t i = 0; i < size_and_type.first; ++i)
|
||||||
@@ -21318,11 +21315,9 @@ class binary_reader
|
|||||||
// follow the documented _ArrayType_, _ArraySize_, _ArrayData_ order
|
// follow the documented _ArrayType_, _ArraySize_, _ArrayData_ order
|
||||||
if (ndarray_dtype != 0)
|
if (ndarray_dtype != 0)
|
||||||
{
|
{
|
||||||
|
// every optimized type marker is_valid_optimized_type() accepts for BJData has a name
|
||||||
const char* type_name = bjd_type_name(ndarray_dtype);
|
const char* type_name = bjd_type_name(ndarray_dtype);
|
||||||
if (JSON_HEDLEY_UNLIKELY(type_name == nullptr))
|
JSON_ASSERT(type_name != nullptr);
|
||||||
{
|
|
||||||
return unexpected_byte("invalid byte", "type");
|
|
||||||
}
|
|
||||||
|
|
||||||
string_t type_key = "_ArrayType_";
|
string_t type_key = "_ArrayType_";
|
||||||
string_t type = type_name; // sax->string() takes a reference
|
string_t type = type_name; // sax->string() takes a reference
|
||||||
@@ -21405,12 +21400,6 @@ class binary_reader
|
|||||||
if (current == '$')
|
if (current == '$')
|
||||||
{
|
{
|
||||||
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
|
|
||||||
&& JSON_HEDLEY_UNLIKELY(is_bjd_excluded_optimized_type(result.second)))
|
|
||||||
{
|
|
||||||
return optimized_type_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof("type")))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -21438,7 +21427,7 @@ class binary_reader
|
|||||||
// an ndarray was read here only if the flag flipped; when it was
|
// an ndarray was read here only if the flag flipped; when it was
|
||||||
// seeded true, get_ubjson_size_value() already rejected the nested
|
// seeded true, get_ubjson_size_value() already rejected the nested
|
||||||
// dimension vector
|
// dimension vector
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
if (is_ndarray && !inside_ndarray)
|
||||||
{
|
{
|
||||||
result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
|
result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
|
||||||
}
|
}
|
||||||
@@ -21448,7 +21437,7 @@ class binary_reader
|
|||||||
if (current == '#')
|
if (current == '#')
|
||||||
{
|
{
|
||||||
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
|
||||||
if (input_format == input_format_t::bjdata && is_ndarray && !inside_ndarray)
|
if (is_ndarray && !inside_ndarray)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size");
|
return last_byte_error(exception_id::unexpected_byte, "ndarray requires both type and size", "size");
|
||||||
}
|
}
|
||||||
@@ -21622,7 +21611,6 @@ class binary_reader
|
|||||||
JSON_HEDLEY_NEVER_INLINE
|
JSON_HEDLEY_NEVER_INLINE
|
||||||
bool parse_ubjson_typed_run(std::size_t& remaining, const char_int_type type, std::true_type /*bulk*/)
|
bool parse_ubjson_typed_run(std::size_t& remaining, const char_int_type type, std::true_type /*bulk*/)
|
||||||
{
|
{
|
||||||
const bool bjdata = input_format == input_format_t::bjdata;
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 'U':
|
case 'U':
|
||||||
@@ -21636,11 +21624,11 @@ class binary_reader
|
|||||||
case 'L':
|
case 'L':
|
||||||
return parse_ubjson_typed_run<std::int64_t>(remaining);
|
return parse_ubjson_typed_run<std::int64_t>(remaining);
|
||||||
case 'u':
|
case 'u':
|
||||||
return !bjdata || parse_ubjson_typed_run<std::uint16_t>(remaining);
|
return parse_ubjson_typed_run<std::uint16_t>(remaining);
|
||||||
case 'm':
|
case 'm':
|
||||||
return !bjdata || parse_ubjson_typed_run<std::uint32_t>(remaining);
|
return parse_ubjson_typed_run<std::uint32_t>(remaining);
|
||||||
case 'M':
|
case 'M':
|
||||||
return !bjdata || parse_ubjson_typed_run<std::uint64_t>(remaining);
|
return parse_ubjson_typed_run<std::uint64_t>(remaining);
|
||||||
case 'd':
|
case 'd':
|
||||||
return parse_ubjson_typed_run<float>(remaining);
|
return parse_ubjson_typed_run<float>(remaining);
|
||||||
case 'D':
|
case 'D':
|
||||||
@@ -21721,7 +21709,7 @@ class binary_reader
|
|||||||
// if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
|
// if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
|
||||||
// {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
|
// {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
|
||||||
|
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
if ((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
|
||||||
|
|
||||||
@@ -21780,7 +21768,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If BJData type marker is 'B' decode as binary
|
// If BJData type marker is 'B' decode as binary
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B')
|
if (size_and_type.first != npos && size_and_type.second == 'B')
|
||||||
{
|
{
|
||||||
binary_t result;
|
binary_t result;
|
||||||
return get_binary(size_and_type.first, result) && sax->binary(result);
|
return get_binary(size_and_type.first, result) && sax->binary(result);
|
||||||
@@ -21829,7 +21817,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
// do not accept ND-array size in objects in BJData
|
// do not accept ND-array size in objects in BJData
|
||||||
if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
|
if ((size_and_type.second & (1 << 8)) != 0)
|
||||||
{
|
{
|
||||||
return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object");
|
return last_byte_error(exception_id::unexpected_byte, "BJData object does not support ND-array size in optimized format", "object");
|
||||||
}
|
}
|
||||||
@@ -23110,8 +23098,9 @@ class binary_reader
|
|||||||
JSON_PRIVATE_UNLESS_TESTED:
|
JSON_PRIVATE_UNLESS_TESTED:
|
||||||
/*!
|
/*!
|
||||||
@brief check whether @a marker is a type marker that may follow '$'
|
@brief check whether @a marker is a type marker that may follow '$'
|
||||||
UBJSON: Z N T F i U I l L d D H C S [ {; BJData: the numeric markers and C
|
UBJSON: Z N T F i U I l L d D H C S [ {; BJData: the numeric markers and C.
|
||||||
(BJData's excluded markers are rejected separately).
|
The markers BJData excludes (F H N S T Z [ {) are the ones
|
||||||
|
binary_writer::is_bjdata_excluded_type_marker() lists; keep the two in sync.
|
||||||
*/
|
*/
|
||||||
bool is_valid_optimized_type(const char_int_type marker) const noexcept
|
bool is_valid_optimized_type(const char_int_type marker) const noexcept
|
||||||
{
|
{
|
||||||
@@ -23146,20 +23135,6 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
@brief whether @a marker is excluded from BJData's optimized ND-array types
|
|
||||||
@return whether @a marker is one of 'F', 'H', 'N', 'S', 'T', 'Z', '[', '{'
|
|
||||||
|
|
||||||
Mirrors binary_writer's @ref binary_writer::is_bjdata_excluded_type_marker
|
|
||||||
"is_bjdata_excluded_type_marker()`, which encodes the same list the other
|
|
||||||
way; keep the two in sync.
|
|
||||||
*/
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief look up the ND-array element type name for a BJData dtype marker
|
@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
|
@return the type name ("uint8", "int8", ...), or nullptr if @a marker does
|
||||||
@@ -31110,22 +31085,19 @@ class binary_writer
|
|||||||
// negative fixnum
|
// negative fixnum
|
||||||
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
|
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)())
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 8
|
// int 8
|
||||||
oa.write_character(to_char_type(0xD0));
|
oa.write_character(to_char_type(0xD0));
|
||||||
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
|
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)())
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 16
|
// int 16
|
||||||
oa.write_character(to_char_type(0xD1));
|
oa.write_character(to_char_type(0xD1));
|
||||||
write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
|
write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
|
||||||
}
|
}
|
||||||
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
|
else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)())
|
||||||
j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
|
|
||||||
{
|
{
|
||||||
// int 32
|
// int 32
|
||||||
oa.write_character(to_char_type(0xD2));
|
oa.write_character(to_char_type(0xD2));
|
||||||
@@ -32041,7 +32013,7 @@ class binary_writer
|
|||||||
Containers, strings, high-precision numbers, booleans and null cannot be
|
Containers, strings, high-precision numbers, booleans and null cannot be
|
||||||
declared as the single type of an optimized container in BJData; such a
|
declared as the single type of an optimized container in BJData; such a
|
||||||
container is written unoptimized. The reader rejects them with the same
|
container is written unoptimized. The reader rejects them with the same
|
||||||
list (binary_reader::is_bjd_excluded_optimized_type()).
|
list (binary_reader::is_valid_optimized_type()).
|
||||||
*/
|
*/
|
||||||
static constexpr bool is_bjdata_excluded_type_marker(const CharType marker) noexcept
|
static constexpr bool is_bjdata_excluded_type_marker(const CharType marker) noexcept
|
||||||
{
|
{
|
||||||
@@ -33446,7 +33418,7 @@ NLOHMANN_JSON_NAMESPACE_END
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm> // copy, none_of, min, search
|
#include <algorithm> // remove, fill, find, none_of, min
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <clocale> // localeconv, lconv
|
#include <clocale> // localeconv, lconv
|
||||||
#include <cmath> // isfinite
|
#include <cmath> // isfinite
|
||||||
@@ -37300,35 +37272,31 @@ class serializer
|
|||||||
// check if the buffer was large enough
|
// check if the buffer was large enough
|
||||||
JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
|
JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
|
||||||
|
|
||||||
// look up the locale's decimal point now, matching what
|
// look up the locale's thousands separator and decimal point now,
|
||||||
// snprintf_float() just used (see get_decimal_point() in
|
// matching what snprintf_float() just used (see lexer::get_decimal_point())
|
||||||
// number_parse.hpp); it is a string, which can be longer than one
|
|
||||||
// byte (U+066B in ps_AF, #5993).
|
|
||||||
// A thousands separator needs no handling: %g never groups digits.
|
|
||||||
const auto* loc = std::localeconv();
|
const auto* loc = std::localeconv();
|
||||||
JSON_ASSERT(loc != nullptr);
|
JSON_ASSERT(loc != nullptr);
|
||||||
const char* const decimal_point = (loc->decimal_point == nullptr) ? "" : loc->decimal_point;
|
const char thousands_sep = (loc->thousands_sep == nullptr) ? '\0' : *loc->thousands_sep;
|
||||||
const std::size_t decimal_point_len = std::char_traits<char>::length(decimal_point);
|
const char decimal_point = (loc->decimal_point == nullptr) ? '\0' : *loc->decimal_point;
|
||||||
|
|
||||||
|
// erase thousands separators
|
||||||
|
if (thousands_sep != '\0')
|
||||||
|
{
|
||||||
|
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
||||||
|
const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
|
||||||
|
std::fill(end, number_buffer.end(), '\0');
|
||||||
|
JSON_ASSERT((end - number_buffer.begin()) <= len);
|
||||||
|
len = (end - number_buffer.begin());
|
||||||
|
}
|
||||||
|
|
||||||
// convert decimal point to '.'
|
// convert decimal point to '.'
|
||||||
if ((decimal_point_len > 1) || (decimal_point_len == 1 && decimal_point[0] != '.'))
|
if (decimal_point != '\0' && decimal_point != '.')
|
||||||
{
|
{
|
||||||
const auto first = number_buffer.begin();
|
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
||||||
const auto last = first + len;
|
const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
|
||||||
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::search returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
if (dec_pos != number_buffer.end())
|
||||||
const auto dec_pos = std::search(first, last, decimal_point, decimal_point + decimal_point_len);
|
|
||||||
if (dec_pos != last)
|
|
||||||
{
|
{
|
||||||
*dec_pos = '.';
|
*dec_pos = '.';
|
||||||
if (decimal_point_len > 1)
|
|
||||||
{
|
|
||||||
// move the fraction and exponent behind the '.' (std::copy
|
|
||||||
// allows the overlap, as the destination is before the source)
|
|
||||||
// NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::copy returns an iterator, see https://github.com/nlohmann/json/issues/3081
|
|
||||||
const auto end = std::copy(dec_pos + static_cast<std::ptrdiff_t>(decimal_point_len), last, dec_pos + 1);
|
|
||||||
*end = '\0';
|
|
||||||
len = end - first;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1038,14 +1038,6 @@ template<class T>
|
|||||||
struct sweep_allocator
|
struct sweep_allocator
|
||||||
{
|
{
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
// GCC 4.8's std::map takes these from the allocator instead of from
|
|
||||||
// std::allocator_traits
|
|
||||||
using pointer = T*;
|
|
||||||
using const_pointer = const T*;
|
|
||||||
using reference = T&;
|
|
||||||
using const_reference = const T&;
|
|
||||||
using size_type = std::size_t;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
|
|
||||||
sweep_allocator() = default;
|
sweep_allocator() = default;
|
||||||
template<class U> sweep_allocator(const sweep_allocator<U>& /*unused*/) noexcept {}
|
template<class U> sweep_allocator(const sweep_allocator<U>& /*unused*/) noexcept {}
|
||||||
@@ -1163,14 +1155,9 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
|
|||||||
|
|
||||||
// With iterator debugging (MSVC STL debug builds, also used by clang-cl),
|
// With iterator debugging (MSVC STL debug builds, also used by clang-cl),
|
||||||
// containers allocate a debug proxy through the allocator inside their
|
// containers allocate a debug proxy through the allocator inside their
|
||||||
// noexcept default and move constructors, so failing that allocation
|
// noexcept move constructors, so failing that allocation terminates the
|
||||||
// terminates the program instead of throwing std::bad_alloc. Nothing to
|
// program instead of throwing std::bad_alloc. Nothing to check there.
|
||||||
// check there.
|
|
||||||
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
||||||
// Clang 3.4 and 3.5 leak memory when an element constructor throws
|
|
||||||
// inside libstdc++'s containers (a std::map copy, a std::vector
|
|
||||||
// reallocation), without any json value involved.
|
|
||||||
#if !(defined(__clang__) && !defined(__apple_build_version__) && __clang_major__ == 3 && __clang_minor__ < 6)
|
|
||||||
SECTION("parser callback")
|
SECTION("parser callback")
|
||||||
{
|
{
|
||||||
const auto keep_all = [](int /*depth*/, sweep_json::parse_event_t /*event*/, sweep_json& /*parsed*/) noexcept
|
const auto keep_all = [](int /*depth*/, sweep_json::parse_event_t /*event*/, sweep_json& /*parsed*/) noexcept
|
||||||
@@ -1191,6 +1178,7 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
|
|||||||
return sweep_json::parse(text, drop_d);
|
return sweep_json::parse(text, drop_d);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SECTION("sax_parse into an existing value")
|
SECTION("sax_parse into an existing value")
|
||||||
{
|
{
|
||||||
@@ -1204,7 +1192,5 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
|
|||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -78,23 +78,25 @@ TEST_CASE("BJData")
|
|||||||
{
|
{
|
||||||
SECTION("binary_reader BJData lookup tables")
|
SECTION("binary_reader BJData lookup tables")
|
||||||
{
|
{
|
||||||
// both lookups are static member functions
|
// bjd_type_name() is static; is_valid_optimized_type() needs a BJData reader
|
||||||
std::vector<std::uint8_t> const data;
|
std::vector<std::uint8_t> const data;
|
||||||
using reader_t = nlohmann::detail::binary_reader<json, decltype(nlohmann::detail::input_adapter(data))>;
|
using reader_t = nlohmann::detail::binary_reader<json, decltype(nlohmann::detail::input_adapter(data))>;
|
||||||
|
|
||||||
// the excluded optimized-type markers must match binary_writer's
|
// the markers BJData excludes as optimized types must match
|
||||||
// is_bjdata_excluded_type_marker(), which encodes the same 8 markers
|
// binary_writer's is_bjdata_excluded_type_marker(), which encodes the
|
||||||
|
// same 8 markers
|
||||||
|
reader_t reader(nlohmann::detail::input_adapter(data), json::input_format_t::bjdata);
|
||||||
for (const char marker :
|
for (const char marker :
|
||||||
{'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'
|
{'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z', 'x'
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
CHECK(reader_t::is_bjd_excluded_optimized_type(static_cast<unsigned char>(marker)));
|
CHECK(!reader.is_valid_optimized_type(static_cast<unsigned char>(marker)));
|
||||||
}
|
}
|
||||||
for (const char marker :
|
for (const char marker :
|
||||||
{'U', 'i', 'u', 'I', 'm', 'l', 'M', 'L', 'd', 'D', 'C', 'B', 'x'
|
{'U', 'i', 'u', 'I', 'm', 'l', 'M', 'L', 'd', 'D', 'C', 'B', 'h'
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
CHECK(!reader_t::is_bjd_excluded_optimized_type(static_cast<unsigned char>(marker)));
|
CHECK(reader.is_valid_optimized_type(static_cast<unsigned char>(marker)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// every dtype marker must round-trip to its ND-array type name
|
// every dtype marker must round-trip to its ND-array type name
|
||||||
|
|||||||
@@ -2222,10 +2222,9 @@ TEST_CASE("serialization of short strings")
|
|||||||
{
|
{
|
||||||
CAPTURE(s)
|
CAPTURE(s)
|
||||||
const json j = s;
|
const json j = s;
|
||||||
const std::string quoted = "\"" + s + "\""; // NOLINT(performance-inefficient-string-concatenation)
|
CHECK(j.dump() == "\"" + s + "\"");
|
||||||
CHECK(j.dump() == quoted);
|
CHECK(j.dump(-1, ' ', true) == "\"" + s + "\"");
|
||||||
CHECK(j.dump(-1, ' ', true) == quoted);
|
CHECK(json({{s, s}}).dump() == "{\"" + s + "\":\"" + s + "\"}");
|
||||||
CHECK(json({{s, s}}).dump() == "{" + quoted + ":" + quoted + "}"); // NOLINT(performance-inefficient-string-concatenation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// a character that needs an escape
|
// a character that needs an escape
|
||||||
|
|||||||
@@ -160,12 +160,12 @@ class strict_key
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_value;
|
std::string m_value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
strict_key make_strict_key(const std::string& key)
|
strict_key make_strict_key(const std::string& key)
|
||||||
{
|
{
|
||||||
return {key.c_str()};
|
return strict_key(key.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Key, class Value, class Compare, class Allocator>
|
template<class Key, class Value, class Compare, class Allocator>
|
||||||
@@ -224,9 +224,7 @@ TEST_CASE("converting a value with keys that cannot be made from a std::string n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// direct-initialization: a copy-initialization makes GCC 4.8 instantiate the
|
const strict_json converted = value;
|
||||||
// copy constructor, which needs a range constructor strict_object lacks
|
|
||||||
const strict_json converted(value);
|
|
||||||
|
|
||||||
// at() needs to make a std::string of a key for its error message
|
// at() needs to make a std::string of a key for its error message
|
||||||
const auto member = [](const strict_json & object, const char* name) -> const strict_json &
|
const auto member = [](const strict_json & object, const char* name) -> const strict_json &
|
||||||
|
|||||||
@@ -105,53 +105,19 @@ template<typename T>
|
|||||||
struct failing_allocator
|
struct failing_allocator
|
||||||
{
|
{
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
// GCC 4.8's std::map takes these from the allocator instead of from
|
|
||||||
// std::allocator_traits
|
|
||||||
using pointer = T*;
|
|
||||||
using const_pointer = const T*;
|
|
||||||
using reference = T&;
|
|
||||||
using const_reference = const T&;
|
|
||||||
using size_type = std::size_t;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
struct rebind
|
|
||||||
{
|
|
||||||
using other = failing_allocator<U>;
|
|
||||||
};
|
|
||||||
|
|
||||||
failing_allocator() = default;
|
failing_allocator() = default;
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
explicit failing_allocator(const failing_allocator<U>& /*other*/) noexcept {}
|
explicit failing_allocator(const failing_allocator<U>& /*other*/) noexcept {}
|
||||||
|
|
||||||
[[noreturn]] T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static)
|
T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||||
{
|
{
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate(T* /*p*/, std::size_t /*n*/) noexcept {} // NOLINT(readability-convert-member-functions-to-static)
|
void deallocate(T* /*p*/, std::size_t /*n*/) noexcept {} // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
|
||||||
// GCC 4.8's std::map calls these on the allocator directly instead of
|
|
||||||
// going through std::allocator_traits
|
|
||||||
std::size_t max_size() const noexcept // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
{
|
|
||||||
return (std::numeric_limits<std::size_t>::max)() / sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename... Args>
|
|
||||||
void construct(U* p, Args&& ... args) // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
{
|
|
||||||
::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
void destroy(U* p) noexcept // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
{
|
|
||||||
static_cast<void>(p); // unused for trivially destructible types
|
|
||||||
p->~U();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
bool operator==(const failing_allocator<U>& /*other*/) const noexcept
|
bool operator==(const failing_allocator<U>& /*other*/) const noexcept
|
||||||
{
|
{
|
||||||
@@ -304,7 +270,7 @@ TEST_CASE("json_view")
|
|||||||
"\"", "\"abc", "\"\\x\"", "\"\\u12\"", "\"\\ud800\"", "\"\\udc00\"", "\"\x01\"", "\"\xff\"", "\"\xc3\"", "[1]x", "/", "/*", "[\n 1,\n x\n]", // NOLINT(modernize-raw-string-literal)
|
"\"", "\"abc", "\"\\x\"", "\"\\u12\"", "\"\\ud800\"", "\"\\udc00\"", "\"\x01\"", "\"\xff\"", "\"\xc3\"", "[1]x", "/", "/*", "[\n 1,\n x\n]", // NOLINT(modernize-raw-string-literal)
|
||||||
"1e400", "-1e400", "[1.7976931348623159e308]", "{\"a\":\n{\"b\": [1, 2,\n 3 x]}}",
|
"1e400", "-1e400", "[1.7976931348623159e308]", "{\"a\":\n{\"b\": [1, 2,\n 3 x]}}",
|
||||||
// (an error after every kind of value: the error is found by replaying the parser)
|
// (an error after every kind of value: the error is found by replaying the parser)
|
||||||
R"([null, true, -1, 1, 1.5, "s", {"a": 1} 2])", R"({"a": null, "b": -1, "c": 1.5, "d": "s", "e": {}, 1})"
|
"[null, true, -1, 1, 1.5, \"s\", {\"a\": 1} 2]", "{\"a\": null, \"b\": -1, \"c\": 1.5, \"d\": \"s\", \"e\": {}, 1}"
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
CAPTURE(text)
|
CAPTURE(text)
|
||||||
@@ -1590,7 +1556,7 @@ TEST_CASE("json_view values")
|
|||||||
CHECK_THROWS_WITH_AS(not_an_object.root().get<view_map>(), json_view_test::message("type_error.302", "", 0, 5, "type must be object, but is array").c_str(), json::type_error&);
|
CHECK_THROWS_WITH_AS(not_an_object.root().get<view_map>(), json_view_test::message("type_error.302", "", 0, 5, "type must be object, but is array").c_str(), json::type_error&);
|
||||||
#if !defined(JSON_NOEXCEPTION)
|
#if !defined(JSON_NOEXCEPTION)
|
||||||
// (and one that cannot allocate its nodes)
|
// (and one that cannot allocate its nodes)
|
||||||
using failing_map = std::map<std::string, json_view, std::less<std::string>, failing_allocator<std::pair<const std::string, json_view>>>; // NOLINT(modernize-use-transparent-functors)
|
using failing_map = std::map<std::string, json_view, std::less<std::string>, failing_allocator<std::pair<const std::string, json_view>>>;
|
||||||
const json_document one_member = json_document::parse(R"({"a":1})");
|
const json_document one_member = json_document::parse(R"({"a":1})");
|
||||||
CHECK_THROWS_AS(one_member.root().get<failing_map>(), std::bad_alloc&);
|
CHECK_THROWS_AS(one_member.root().get<failing_map>(), std::bad_alloc&);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -397,14 +397,6 @@ TEST_CASE("locale with a multi-byte decimal point")
|
|||||||
|
|
||||||
// a value the locale-independent paths convert is not affected
|
// a value the locale-independent paths convert is not affected
|
||||||
CHECK(json::parse("12.5") == 12.5);
|
CHECK(json::parse("12.5") == 12.5);
|
||||||
|
|
||||||
// dump() of a long double that takes the snprintf path replaces the
|
|
||||||
// whole decimal point, not only its first byte (#5993)
|
|
||||||
CHECK(long_double_json(1.5L).dump() == "1.5");
|
|
||||||
CHECK(long_double_json(2.0L).dump() == "2.0");
|
|
||||||
CHECK(long_double_json(-0.25L).dump() == "-0.25");
|
|
||||||
CHECK(long_double_json::parse(long_double_json(1.5e-7L).dump()) == long_double_json(1.5e-7L));
|
|
||||||
CHECK(long_double_json::parse(ld.dump()) == expected_long_double);
|
|
||||||
}
|
}
|
||||||
if (!tested)
|
if (!tested)
|
||||||
{
|
{
|
||||||
@@ -533,7 +525,7 @@ struct locale_switching_token
|
|||||||
{
|
{
|
||||||
switched = std::setlocale(LC_NUMERIC, switch_to.c_str()) != nullptr;
|
switched = std::setlocale(LC_NUMERIC, switch_to.c_str()) != nullptr;
|
||||||
}
|
}
|
||||||
return &text[0]; // NOLINT(readability-container-data-pointer): std::string::data() is const before C++17
|
return &text[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
@@ -655,7 +647,7 @@ TEST_CASE("convert_float_locale_aware")
|
|||||||
|
|
||||||
// "C" -> comma locale: strtod stops at the '.', so the conversion is repeated
|
// "C" -> comma locale: strtod stops at the '.', so the conversion is repeated
|
||||||
{
|
{
|
||||||
locale_switching_token token("1.5", comma_locale);
|
locale_switching_token token("1.5", comma_locale.c_str());
|
||||||
double value = 0;
|
double value = 0;
|
||||||
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
||||||
if (token.switched)
|
if (token.switched)
|
||||||
@@ -668,7 +660,7 @@ TEST_CASE("convert_float_locale_aware")
|
|||||||
// the same for the other floating-point types
|
// the same for the other floating-point types
|
||||||
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
||||||
{
|
{
|
||||||
locale_switching_token token("2.25", comma_locale);
|
locale_switching_token token("2.25", comma_locale.c_str());
|
||||||
float value = 0;
|
float value = 0;
|
||||||
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
||||||
if (token.switched)
|
if (token.switched)
|
||||||
@@ -678,7 +670,7 @@ TEST_CASE("convert_float_locale_aware")
|
|||||||
}
|
}
|
||||||
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
||||||
{
|
{
|
||||||
locale_switching_token token("2.25", comma_locale);
|
locale_switching_token token("2.25", comma_locale.c_str());
|
||||||
long double value = 0;
|
long double value = 0;
|
||||||
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
||||||
if (token.switched)
|
if (token.switched)
|
||||||
|
|||||||
@@ -122,8 +122,7 @@ TEST_CASE("JSON text with std::byte")
|
|||||||
SECTION("invalid text")
|
SECTION("invalid text")
|
||||||
{
|
{
|
||||||
CHECK_FALSE(json::accept(to_bytes("[1,\n2,")));
|
CHECK_FALSE(json::accept(to_bytes("[1,\n2,")));
|
||||||
json _;
|
CHECK_THROWS_WITH_AS(json::parse(to_bytes("[1,\n2,")),
|
||||||
CHECK_THROWS_WITH_AS(_ = json::parse(to_bytes("[1,\n2,")),
|
|
||||||
"[json.exception.parse_error.101] parse error at line 2, column 3: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
|
"[json.exception.parse_error.101] parse error at line 2, column 3: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -541,7 +541,6 @@ TEST_CASE("object_key_index")
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::size_t> hashes;
|
std::vector<std::size_t> hashes;
|
||||||
hashes.reserve(initial);
|
|
||||||
for (std::size_t i = 0; i < initial; ++i)
|
for (std::size_t i = 0; i < initial; ++i)
|
||||||
{
|
{
|
||||||
hashes.push_back(hash_of(i));
|
hashes.push_back(hash_of(i));
|
||||||
|
|||||||
@@ -1533,7 +1533,7 @@ TEST_CASE("regression tests 1")
|
|||||||
{
|
{
|
||||||
my_json::object_t top = orig.get_ref<const my_json::object_t&>();
|
my_json::object_t top = orig.get_ref<const my_json::object_t&>();
|
||||||
top.at("x") = my_json::parse(R"({"a":{"b":1},"n":null,"arr":[10,20],"objs":[{"m":5},{"m":6}]})");
|
top.at("x") = my_json::parse(R"({"a":{"b":1},"n":null,"arr":[10,20],"objs":[{"m":5},{"m":6}]})");
|
||||||
return my_json(std::move(top)); // NOLINT(modernize-return-braced-init-list): {top} would be an array
|
return my_json(std::move(top));
|
||||||
};
|
};
|
||||||
|
|
||||||
SECTION("existing members")
|
SECTION("existing members")
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ class oversized_get_area_streambuf : public std::streambuf
|
|||||||
private:
|
private:
|
||||||
std::array<char, 8> m_data{{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}};
|
std::array<char, 8> m_data{{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// how a test reads from the stream
|
// how a test reads from the stream
|
||||||
@@ -464,18 +463,15 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk")
|
|||||||
CHECK(token.empty());
|
CHECK(token.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SIZE_MAX > UINT32_MAX
|
|
||||||
// a get area larger than an int needs a 64-bit std::size_t (checked by the
|
|
||||||
// preprocessor, as a constant condition triggers MSVC's C4127)
|
|
||||||
SECTION("skipping more characters than gbump() takes at once")
|
SECTION("skipping more characters than gbump() takes at once")
|
||||||
{
|
{
|
||||||
// gbump() takes an int, but a get area can be larger
|
// gbump() takes an int, but a get area can be larger
|
||||||
const std::size_t claimed = std::size_t{3} << 30u;
|
const std::size_t claimed = sizeof(std::size_t) < 8 ? 0 : std::size_t{3} << 30u;
|
||||||
oversized_get_area_streambuf buf(claimed);
|
oversized_get_area_streambuf buf(claimed);
|
||||||
if (static_cast<std::size_t>(buf.in_avail()) != claimed)
|
if (claimed == 0 || static_cast<std::size_t>(buf.in_avail()) != claimed)
|
||||||
{
|
{
|
||||||
// a standard library whose streambuf stores the size of the get
|
// a 32-bit size_t, or a standard library whose streambuf stores
|
||||||
// area in an int (MSVC)
|
// the size of the get area in an int (MSVC)
|
||||||
MESSAGE("a get area larger than an int is not supported");
|
MESSAGE("a get area larger than an int is not supported");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -495,7 +491,6 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk")
|
|||||||
buf.restore_get_area();
|
buf.restore_get_area();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SECTION("SAX parsing from a stream")
|
SECTION("SAX parsing from a stream")
|
||||||
|
|||||||
Reference in new issue
Block a user