🔨 small improvements

This commit is contained in:
Niels Lohmann 2018-10-27 18:31:03 +02:00
parent 037e93f5c0
commit 4e765596f7
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
6 changed files with 339 additions and 309 deletions

View file

@ -68,6 +68,10 @@ class binary_reader
switch (format)
{
case input_format_t::bson:
result = parse_bson_internal();
break;
case input_format_t::cbor:
result = parse_cbor_internal();
break;
@ -80,10 +84,6 @@ class binary_reader
result = parse_ubjson_internal();
break;
case input_format_t::bson:
result = parse_bson_internal();
break;
// LCOV_EXCL_START
default:
assert(false);
@ -135,8 +135,8 @@ class binary_reader
*/
bool parse_bson_internal()
{
std::int32_t documentSize;
get_number<std::int32_t, true>(input_format_t::bson, documentSize);
std::int32_t document_size;
get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
{
@ -315,8 +315,8 @@ class binary_reader
*/
bool parse_bson_array()
{
std::int32_t documentSize;
get_number<std::int32_t, true>(input_format_t::bson, documentSize);
std::int32_t document_size;
get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
{

View file

@ -92,7 +92,7 @@ class input_stream_adapter : public input_adapter_protocol
class input_buffer_adapter : public input_adapter_protocol
{
public:
input_buffer_adapter(const char* b, const std::size_t l)
input_buffer_adapter(const char* b, const std::size_t l) noexcept
: cursor(b), limit(b + l)
{}
@ -240,7 +240,9 @@ template<typename WideStringType>
class wide_string_input_adapter : public input_adapter_protocol
{
public:
explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
explicit wide_string_input_adapter(const WideStringType& w) noexcept
: str(w)
{}
std::char_traits<char>::int_type get_character() noexcept override
{

View file

@ -23,6 +23,8 @@ namespace detail
template<typename BasicJsonType, typename CharType>
class binary_writer
{
using string_t = typename BasicJsonType::string_t;
public:
/*!
@brief create a binary writer
@ -48,11 +50,6 @@ class binary_writer
break;
}
case value_t::discarded:
{
break;
}
default:
{
JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name())));
@ -69,15 +66,15 @@ class binary_writer
{
case value_t::null:
{
oa->write_character(static_cast<CharType>(0xF6));
oa->write_character(to_char_type(0xF6));
break;
}
case value_t::boolean:
{
oa->write_character(j.m_value.boolean
? static_cast<CharType>(0xF5)
: static_cast<CharType>(0xF4));
? to_char_type(0xF5)
: to_char_type(0xF4));
break;
}
@ -94,22 +91,22 @@ class binary_writer
}
else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x18));
oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x19));
oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x1A));
oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_integer));
}
else
{
oa->write_character(static_cast<CharType>(0x1B));
oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_integer));
}
}
@ -124,22 +121,22 @@ class binary_writer
}
else if (positive_number <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x38));
oa->write_character(to_char_type(0x38));
write_number(static_cast<uint8_t>(positive_number));
}
else if (positive_number <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x39));
oa->write_character(to_char_type(0x39));
write_number(static_cast<uint16_t>(positive_number));
}
else if (positive_number <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x3A));
oa->write_character(to_char_type(0x3A));
write_number(static_cast<uint32_t>(positive_number));
}
else
{
oa->write_character(static_cast<CharType>(0x3B));
oa->write_character(to_char_type(0x3B));
write_number(static_cast<uint64_t>(positive_number));
}
}
@ -154,22 +151,22 @@ class binary_writer
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x18));
oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x19));
oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x1A));
oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
}
else
{
oa->write_character(static_cast<CharType>(0x1B));
oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_unsigned));
}
break;
@ -192,23 +189,23 @@ class binary_writer
}
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x78));
oa->write_character(to_char_type(0x78));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x79));
oa->write_character(to_char_type(0x79));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x7A));
oa->write_character(to_char_type(0x7A));
write_number(static_cast<uint32_t>(N));
}
// LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)())
{
oa->write_character(static_cast<CharType>(0x7B));
oa->write_character(to_char_type(0x7B));
write_number(static_cast<uint64_t>(N));
}
// LCOV_EXCL_STOP
@ -230,23 +227,23 @@ class binary_writer
}
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x98));
oa->write_character(to_char_type(0x98));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x99));
oa->write_character(to_char_type(0x99));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x9A));
oa->write_character(to_char_type(0x9A));
write_number(static_cast<uint32_t>(N));
}
// LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)())
{
oa->write_character(static_cast<CharType>(0x9B));
oa->write_character(to_char_type(0x9B));
write_number(static_cast<uint64_t>(N));
}
// LCOV_EXCL_STOP
@ -269,23 +266,23 @@ class binary_writer
}
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0xB8));
oa->write_character(to_char_type(0xB8));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0xB9));
oa->write_character(to_char_type(0xB9));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0xBA));
oa->write_character(to_char_type(0xBA));
write_number(static_cast<uint32_t>(N));
}
// LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)())
{
oa->write_character(static_cast<CharType>(0xBB));
oa->write_character(to_char_type(0xBB));
write_number(static_cast<uint64_t>(N));
}
// LCOV_EXCL_STOP
@ -313,15 +310,15 @@ class binary_writer
{
case value_t::null: // nil
{
oa->write_character(static_cast<CharType>(0xC0));
oa->write_character(to_char_type(0xC0));
break;
}
case value_t::boolean: // true and false
{
oa->write_character(j.m_value.boolean
? static_cast<CharType>(0xC3)
: static_cast<CharType>(0xC2));
? to_char_type(0xC3)
: to_char_type(0xC2));
break;
}
@ -340,25 +337,25 @@ class binary_writer
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
{
// uint 8
oa->write_character(static_cast<CharType>(0xCC));
oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
{
// uint 16
oa->write_character(static_cast<CharType>(0xCD));
oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
{
// uint 32
oa->write_character(static_cast<CharType>(0xCE));
oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
{
// uint 64
oa->write_character(static_cast<CharType>(0xCF));
oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer));
}
}
@ -373,28 +370,28 @@ class binary_writer
j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
{
// int 8
oa->write_character(static_cast<CharType>(0xD0));
oa->write_character(to_char_type(0xD0));
write_number(static_cast<int8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
{
// int 16
oa->write_character(static_cast<CharType>(0xD1));
oa->write_character(to_char_type(0xD1));
write_number(static_cast<int16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
{
// int 32
oa->write_character(static_cast<CharType>(0xD2));
oa->write_character(to_char_type(0xD2));
write_number(static_cast<int32_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
{
// int 64
oa->write_character(static_cast<CharType>(0xD3));
oa->write_character(to_char_type(0xD3));
write_number(static_cast<int64_t>(j.m_value.number_integer));
}
}
@ -411,25 +408,25 @@ class binary_writer
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
{
// uint 8
oa->write_character(static_cast<CharType>(0xCC));
oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
{
// uint 16
oa->write_character(static_cast<CharType>(0xCD));
oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
{
// uint 32
oa->write_character(static_cast<CharType>(0xCE));
oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
{
// uint 64
oa->write_character(static_cast<CharType>(0xCF));
oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer));
}
break;
@ -454,19 +451,19 @@ class binary_writer
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
// str 8
oa->write_character(static_cast<CharType>(0xD9));
oa->write_character(to_char_type(0xD9));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
// str 16
oa->write_character(static_cast<CharType>(0xDA));
oa->write_character(to_char_type(0xDA));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
// str 32
oa->write_character(static_cast<CharType>(0xDB));
oa->write_character(to_char_type(0xDB));
write_number(static_cast<uint32_t>(N));
}
@ -489,13 +486,13 @@ class binary_writer
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
// array 16
oa->write_character(static_cast<CharType>(0xDC));
oa->write_character(to_char_type(0xDC));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
// array 32
oa->write_character(static_cast<CharType>(0xDD));
oa->write_character(to_char_type(0xDD));
write_number(static_cast<uint32_t>(N));
}
@ -519,13 +516,13 @@ class binary_writer
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
// map 16
oa->write_character(static_cast<CharType>(0xDE));
oa->write_character(to_char_type(0xDE));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
// map 32
oa->write_character(static_cast<CharType>(0xDF));
oa->write_character(to_char_type(0xDF));
write_number(static_cast<uint32_t>(N));
}
@ -558,7 +555,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('Z'));
oa->write_character(to_char_type('Z'));
}
break;
}
@ -568,8 +565,8 @@ class binary_writer
if (add_prefix)
{
oa->write_character(j.m_value.boolean
? static_cast<CharType>('T')
: static_cast<CharType>('F'));
? to_char_type('T')
: to_char_type('F'));
}
break;
}
@ -596,7 +593,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('S'));
oa->write_character(to_char_type('S'));
}
write_number_with_ubjson_prefix(j.m_value.string->size(), true);
oa->write_characters(
@ -609,7 +606,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('['));
oa->write_character(to_char_type('['));
}
bool prefix_required = true;
@ -626,14 +623,14 @@ class binary_writer
if (same_prefix)
{
prefix_required = false;
oa->write_character(static_cast<CharType>('$'));
oa->write_character(to_char_type('$'));
oa->write_character(first_prefix);
}
}
if (use_count)
{
oa->write_character(static_cast<CharType>('#'));
oa->write_character(to_char_type('#'));
write_number_with_ubjson_prefix(j.m_value.array->size(), true);
}
@ -644,7 +641,7 @@ class binary_writer
if (not use_count)
{
oa->write_character(static_cast<CharType>(']'));
oa->write_character(to_char_type(']'));
}
break;
@ -654,7 +651,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('{'));
oa->write_character(to_char_type('{'));
}
bool prefix_required = true;
@ -671,14 +668,14 @@ class binary_writer
if (same_prefix)
{
prefix_required = false;
oa->write_character(static_cast<CharType>('$'));
oa->write_character(to_char_type('$'));
oa->write_character(first_prefix);
}
}
if (use_count)
{
oa->write_character(static_cast<CharType>('#'));
oa->write_character(to_char_type('#'));
write_number_with_ubjson_prefix(j.m_value.object->size(), true);
}
@ -693,7 +690,7 @@ class binary_writer
if (not use_count)
{
oa->write_character(static_cast<CharType>('}'));
oa->write_character(to_char_type('}'));
}
break;
@ -713,9 +710,9 @@ class binary_writer
@return The size of a BSON document entry header, including the id marker
and the entry name size (and its null-terminator).
*/
static std::size_t calc_bson_entry_header_size(const typename BasicJsonType::string_t& name)
static std::size_t calc_bson_entry_header_size(const string_t& name)
{
const auto it = name.find(static_cast<typename BasicJsonType::string_t::value_type>(0));
const auto it = name.find(static_cast<typename string_t::value_type>(0));
if (JSON_UNLIKELY(it != BasicJsonType::string_t::npos))
{
JSON_THROW(out_of_range::create(409,
@ -728,10 +725,10 @@ class binary_writer
/*!
@brief Writes the given @a element_type and @a name to the output adapter
*/
void write_bson_entry_header(const typename BasicJsonType::string_t& name,
std::uint8_t element_type)
void write_bson_entry_header(const string_t& name,
const std::uint8_t element_type)
{
oa->write_character(static_cast<CharType>(element_type)); // boolean
oa->write_character(to_char_type(element_type)); // boolean
oa->write_characters(
reinterpret_cast<const CharType*>(name.c_str()),
name.size() + 1u);
@ -740,17 +737,17 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and boolean value @a value
*/
void write_bson_boolean(const typename BasicJsonType::string_t& name,
void write_bson_boolean(const string_t& name,
const bool value)
{
write_bson_entry_header(name, 0x08);
oa->write_character(value ? static_cast<CharType>(0x01) : static_cast<CharType>(0x00));
oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
}
/*!
@brief Writes a BSON element with key @a name and double value @a value
*/
void write_bson_double(const typename BasicJsonType::string_t& name,
void write_bson_double(const string_t& name,
const double value)
{
write_bson_entry_header(name, 0x01);
@ -760,7 +757,7 @@ class binary_writer
/*!
@return The size of the BSON-encoded string in @a value
*/
static std::size_t calc_bson_string_size(const typename BasicJsonType::string_t& value)
static std::size_t calc_bson_string_size(const string_t& value)
{
return sizeof(std::int32_t) + value.size() + 1ul;
}
@ -768,8 +765,8 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and string value @a value
*/
void write_bson_string(const typename BasicJsonType::string_t& name,
const typename BasicJsonType::string_t& value)
void write_bson_string(const string_t& name,
const string_t& value)
{
write_bson_entry_header(name, 0x02);
@ -782,7 +779,7 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and null value
*/
void write_bson_null(const typename BasicJsonType::string_t& name)
void write_bson_null(const string_t& name)
{
write_bson_entry_header(name, 0x0A);
}
@ -805,7 +802,7 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and integer @a value
*/
void write_bson_integer(const typename BasicJsonType::string_t& name,
void write_bson_integer(const string_t& name,
const std::int64_t value)
{
if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
@ -823,45 +820,39 @@ class binary_writer
/*!
@return The size of the BSON-encoded unsigned integer in @a j
*/
static std::size_t calc_bson_unsigned_size(const std::uint64_t value)
static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
{
if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{
return sizeof(std::int32_t);
}
else
{
return sizeof(std::int64_t);
}
return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
? sizeof(std::int32_t)
: sizeof(std::int64_t);
}
/*!
@brief Writes a BSON element with key @a name and unsigned @a value
*/
void write_bson_unsigned(const typename BasicJsonType::string_t& name,
void write_bson_unsigned(const string_t& name,
const std::uint64_t value)
{
if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{
write_bson_entry_header(name, 0x10); // int32
write_bson_entry_header(name, 0x10 /* int32 */);
write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
}
else if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
{
write_bson_entry_header(name, 0x12); // int64
write_bson_entry_header(name, 0x12 /* int64 */);
write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
}
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(value)));
JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(value) + " cannot be represented by BSON as it does not fit int64"));
}
}
/*!
@brief Writes a BSON element with key @a name and object @a value
*/
void write_bson_object_entry(const typename BasicJsonType::string_t& name,
void write_bson_object_entry(const string_t& name,
const typename BasicJsonType::object_t& value)
{
write_bson_entry_header(name, 0x03); // object
@ -887,7 +878,7 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and array @a value
*/
void write_bson_array(const typename BasicJsonType::string_t& name,
void write_bson_array(const string_t& name,
const typename BasicJsonType::array_t& value)
{
write_bson_entry_header(name, 0x04); // array
@ -900,22 +891,19 @@ class binary_writer
write_bson_element(std::to_string(array_index++), el);
}
oa->write_character(static_cast<CharType>(0x00));
oa->write_character(to_char_type(0x00));
}
/*!
@brief Calculates the size necessary to serialize the JSON value @a j with its @a name
@return The calculated size for the BSON document entry for @a j with the given @a name.
*/
static std::size_t calc_bson_element_size(const typename BasicJsonType::string_t& name,
static std::size_t calc_bson_element_size(const string_t& name,
const BasicJsonType& j)
{
const auto header_size = calc_bson_entry_header_size(name);
switch (j.type())
{
case value_t::discarded:
return 0ul;
case value_t::object:
return header_size + calc_bson_object_size(*j.m_value.object);
@ -955,14 +943,11 @@ class binary_writer
current BSON document
@return The size of the BSON entry
*/
void write_bson_element(const typename BasicJsonType::string_t& name,
void write_bson_element(const string_t& name,
const BasicJsonType& j)
{
switch (j.type())
{
case value_t::discarded:
return;
case value_t::object:
return write_bson_object_entry(name, *j.m_value.object);
@ -1003,12 +988,11 @@ class binary_writer
*/
static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
{
std::size_t document_size = 0;
for (const auto& el : value)
std::size_t document_size = std::accumulate(value.begin(), value.end(), 0,
[](size_t result, const typename BasicJsonType::object_t::value_type & el)
{
document_size += calc_bson_element_size(el.first, el.second);
}
return result += calc_bson_element_size(el.first, el.second);
});
return sizeof(std::int32_t) + document_size + 1ul;
}
@ -1026,7 +1010,7 @@ class binary_writer
write_bson_element(el.first, el.second);
}
oa->write_character(static_cast<CharType>(0x00));
oa->write_character(to_char_type(0x00));
}
//////////
@ -1035,12 +1019,12 @@ class binary_writer
static constexpr CharType get_cbor_float_prefix(float /*unused*/)
{
return static_cast<CharType>(0xFA); // Single-Precision Float
return to_char_type(0xFA); // Single-Precision Float
}
static constexpr CharType get_cbor_float_prefix(double /*unused*/)
{
return static_cast<CharType>(0xFB); // Double-Precision Float
return to_char_type(0xFB); // Double-Precision Float
}
/////////////
@ -1049,12 +1033,12 @@ class binary_writer
static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
{
return static_cast<CharType>(0xCA); // float 32
return to_char_type(0xCA); // float 32
}
static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
{
return static_cast<CharType>(0xCB); // float 64
return to_char_type(0xCB); // float 64
}
////////////
@ -1084,7 +1068,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
oa->write_character(to_char_type('i')); // int8
}
write_number(static_cast<uint8_t>(n));
}
@ -1092,7 +1076,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
oa->write_character(to_char_type('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
@ -1100,7 +1084,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
oa->write_character(to_char_type('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
@ -1108,7 +1092,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
oa->write_character(to_char_type('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
@ -1116,7 +1100,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
oa->write_character(to_char_type('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
@ -1137,7 +1121,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
oa->write_character(to_char_type('i')); // int8
}
write_number(static_cast<int8_t>(n));
}
@ -1145,7 +1129,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
oa->write_character(to_char_type('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
@ -1153,7 +1137,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
oa->write_character(to_char_type('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
@ -1161,7 +1145,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
oa->write_character(to_char_type('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
@ -1169,7 +1153,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
oa->write_character(to_char_type('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
@ -1304,6 +1288,46 @@ class binary_writer
oa->write_characters(vec.data(), sizeof(NumberType));
}
// The following to_char_type functions are implement the conversion
// between uint8_t and CharType. In case CharType is not unsigned,
// such a conversion is required to allow values greater than 128.
// See <https://github.com/nlohmann/json/issues/1286> for a discussion.
template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >
static constexpr CharType to_char_type(std::uint8_t x) noexcept
{
return *reinterpret_cast<char*>(&x);
}
template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >
static CharType to_char_type(std::uint8_t x) noexcept
{
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
static_assert(std::is_pod<CharType>::value, "CharType must be POD");
CharType result;
std::memcpy(&result, &x, sizeof(x));
return result;
}
template<typename C = CharType,
enable_if_t<std::is_unsigned<C>::value>* = nullptr>
static constexpr CharType to_char_type(std::uint8_t x) noexcept
{
return x;
}
template < typename InputCharType, typename C = CharType,
enable_if_t <
std::is_signed<C>::value and
std::is_signed<char>::value and
std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
> * = nullptr >
static constexpr CharType to_char_type(InputCharType x) noexcept
{
return x;
}
private:
/// whether we can assume little endianess
const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();

View file

@ -30,7 +30,9 @@ template<typename CharType>
class output_vector_adapter : public output_adapter_protocol<CharType>
{
public:
explicit output_vector_adapter(std::vector<CharType>& vec) : v(vec) {}
explicit output_vector_adapter(std::vector<CharType>& vec) noexcept
: v(vec)
{}
void write_character(CharType c) override
{
@ -51,7 +53,9 @@ template<typename CharType>
class output_stream_adapter : public output_adapter_protocol<CharType>
{
public:
explicit output_stream_adapter(std::basic_ostream<CharType>& s) : stream(s) {}
explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
: stream(s)
{}
void write_character(CharType c) override
{
@ -72,7 +76,9 @@ template<typename CharType, typename StringType = std::basic_string<CharType>>
class output_string_adapter : public output_adapter_protocol<CharType>
{
public:
explicit output_string_adapter(StringType& s) : str(s) {}
explicit output_string_adapter(StringType& s) noexcept
: str(s)
{}
void write_character(CharType c) override
{

View file

@ -2115,7 +2115,7 @@ class input_stream_adapter : public input_adapter_protocol
class input_buffer_adapter : public input_adapter_protocol
{
public:
input_buffer_adapter(const char* b, const std::size_t l)
input_buffer_adapter(const char* b, const std::size_t l) noexcept
: cursor(b), limit(b + l)
{}
@ -2263,7 +2263,9 @@ template<typename WideStringType>
class wide_string_input_adapter : public input_adapter_protocol
{
public:
explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
explicit wide_string_input_adapter(const WideStringType& w) noexcept
: str(w)
{}
std::char_traits<char>::int_type get_character() noexcept override
{
@ -6210,7 +6212,9 @@ template<typename CharType>
class output_vector_adapter : public output_adapter_protocol<CharType>
{
public:
explicit output_vector_adapter(std::vector<CharType>& vec) : v(vec) {}
explicit output_vector_adapter(std::vector<CharType>& vec) noexcept
: v(vec)
{}
void write_character(CharType c) override
{
@ -6231,7 +6235,9 @@ template<typename CharType>
class output_stream_adapter : public output_adapter_protocol<CharType>
{
public:
explicit output_stream_adapter(std::basic_ostream<CharType>& s) : stream(s) {}
explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
: stream(s)
{}
void write_character(CharType c) override
{
@ -6252,7 +6258,9 @@ template<typename CharType, typename StringType = std::basic_string<CharType>>
class output_string_adapter : public output_adapter_protocol<CharType>
{
public:
explicit output_string_adapter(StringType& s) : str(s) {}
explicit output_string_adapter(StringType& s) noexcept
: str(s)
{}
void write_character(CharType c) override
{
@ -6369,6 +6377,10 @@ class binary_reader
switch (format)
{
case input_format_t::bson:
result = parse_bson_internal();
break;
case input_format_t::cbor:
result = parse_cbor_internal();
break;
@ -6381,10 +6393,6 @@ class binary_reader
result = parse_ubjson_internal();
break;
case input_format_t::bson:
result = parse_bson_internal();
break;
// LCOV_EXCL_START
default:
assert(false);
@ -6436,8 +6444,8 @@ class binary_reader
*/
bool parse_bson_internal()
{
std::int32_t documentSize;
get_number<std::int32_t, true>(input_format_t::bson, documentSize);
std::int32_t document_size;
get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
{
@ -6616,8 +6624,8 @@ class binary_reader
*/
bool parse_bson_array()
{
std::int32_t documentSize;
get_number<std::int32_t, true>(input_format_t::bson, documentSize);
std::int32_t document_size;
get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
{
@ -8303,6 +8311,8 @@ namespace detail
template<typename BasicJsonType, typename CharType>
class binary_writer
{
using string_t = typename BasicJsonType::string_t;
public:
/*!
@brief create a binary writer
@ -8328,11 +8338,6 @@ class binary_writer
break;
}
case value_t::discarded:
{
break;
}
default:
{
JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name())));
@ -8349,15 +8354,15 @@ class binary_writer
{
case value_t::null:
{
oa->write_character(static_cast<CharType>(0xF6));
oa->write_character(to_char_type(0xF6));
break;
}
case value_t::boolean:
{
oa->write_character(j.m_value.boolean
? static_cast<CharType>(0xF5)
: static_cast<CharType>(0xF4));
? to_char_type(0xF5)
: to_char_type(0xF4));
break;
}
@ -8374,22 +8379,22 @@ class binary_writer
}
else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x18));
oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x19));
oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x1A));
oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_integer));
}
else
{
oa->write_character(static_cast<CharType>(0x1B));
oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_integer));
}
}
@ -8404,22 +8409,22 @@ class binary_writer
}
else if (positive_number <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x38));
oa->write_character(to_char_type(0x38));
write_number(static_cast<uint8_t>(positive_number));
}
else if (positive_number <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x39));
oa->write_character(to_char_type(0x39));
write_number(static_cast<uint16_t>(positive_number));
}
else if (positive_number <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x3A));
oa->write_character(to_char_type(0x3A));
write_number(static_cast<uint32_t>(positive_number));
}
else
{
oa->write_character(static_cast<CharType>(0x3B));
oa->write_character(to_char_type(0x3B));
write_number(static_cast<uint64_t>(positive_number));
}
}
@ -8434,22 +8439,22 @@ class binary_writer
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x18));
oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_unsigned));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x19));
oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_unsigned));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x1A));
oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_unsigned));
}
else
{
oa->write_character(static_cast<CharType>(0x1B));
oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_unsigned));
}
break;
@ -8472,23 +8477,23 @@ class binary_writer
}
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x78));
oa->write_character(to_char_type(0x78));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x79));
oa->write_character(to_char_type(0x79));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x7A));
oa->write_character(to_char_type(0x7A));
write_number(static_cast<uint32_t>(N));
}
// LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)())
{
oa->write_character(static_cast<CharType>(0x7B));
oa->write_character(to_char_type(0x7B));
write_number(static_cast<uint64_t>(N));
}
// LCOV_EXCL_STOP
@ -8510,23 +8515,23 @@ class binary_writer
}
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0x98));
oa->write_character(to_char_type(0x98));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0x99));
oa->write_character(to_char_type(0x99));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0x9A));
oa->write_character(to_char_type(0x9A));
write_number(static_cast<uint32_t>(N));
}
// LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)())
{
oa->write_character(static_cast<CharType>(0x9B));
oa->write_character(to_char_type(0x9B));
write_number(static_cast<uint64_t>(N));
}
// LCOV_EXCL_STOP
@ -8549,23 +8554,23 @@ class binary_writer
}
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
oa->write_character(static_cast<CharType>(0xB8));
oa->write_character(to_char_type(0xB8));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
oa->write_character(static_cast<CharType>(0xB9));
oa->write_character(to_char_type(0xB9));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
oa->write_character(static_cast<CharType>(0xBA));
oa->write_character(to_char_type(0xBA));
write_number(static_cast<uint32_t>(N));
}
// LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)())
{
oa->write_character(static_cast<CharType>(0xBB));
oa->write_character(to_char_type(0xBB));
write_number(static_cast<uint64_t>(N));
}
// LCOV_EXCL_STOP
@ -8593,15 +8598,15 @@ class binary_writer
{
case value_t::null: // nil
{
oa->write_character(static_cast<CharType>(0xC0));
oa->write_character(to_char_type(0xC0));
break;
}
case value_t::boolean: // true and false
{
oa->write_character(j.m_value.boolean
? static_cast<CharType>(0xC3)
: static_cast<CharType>(0xC2));
? to_char_type(0xC3)
: to_char_type(0xC2));
break;
}
@ -8620,25 +8625,25 @@ class binary_writer
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
{
// uint 8
oa->write_character(static_cast<CharType>(0xCC));
oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
{
// uint 16
oa->write_character(static_cast<CharType>(0xCD));
oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
{
// uint 32
oa->write_character(static_cast<CharType>(0xCE));
oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
{
// uint 64
oa->write_character(static_cast<CharType>(0xCF));
oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer));
}
}
@ -8653,28 +8658,28 @@ class binary_writer
j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())
{
// int 8
oa->write_character(static_cast<CharType>(0xD0));
oa->write_character(to_char_type(0xD0));
write_number(static_cast<int8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())
{
// int 16
oa->write_character(static_cast<CharType>(0xD1));
oa->write_character(to_char_type(0xD1));
write_number(static_cast<int16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())
{
// int 32
oa->write_character(static_cast<CharType>(0xD2));
oa->write_character(to_char_type(0xD2));
write_number(static_cast<int32_t>(j.m_value.number_integer));
}
else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())
{
// int 64
oa->write_character(static_cast<CharType>(0xD3));
oa->write_character(to_char_type(0xD3));
write_number(static_cast<int64_t>(j.m_value.number_integer));
}
}
@ -8691,25 +8696,25 @@ class binary_writer
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())
{
// uint 8
oa->write_character(static_cast<CharType>(0xCC));
oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())
{
// uint 16
oa->write_character(static_cast<CharType>(0xCD));
oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())
{
// uint 32
oa->write_character(static_cast<CharType>(0xCE));
oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer));
}
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())
{
// uint 64
oa->write_character(static_cast<CharType>(0xCF));
oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer));
}
break;
@ -8734,19 +8739,19 @@ class binary_writer
else if (N <= (std::numeric_limits<uint8_t>::max)())
{
// str 8
oa->write_character(static_cast<CharType>(0xD9));
oa->write_character(to_char_type(0xD9));
write_number(static_cast<uint8_t>(N));
}
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
// str 16
oa->write_character(static_cast<CharType>(0xDA));
oa->write_character(to_char_type(0xDA));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
// str 32
oa->write_character(static_cast<CharType>(0xDB));
oa->write_character(to_char_type(0xDB));
write_number(static_cast<uint32_t>(N));
}
@ -8769,13 +8774,13 @@ class binary_writer
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
// array 16
oa->write_character(static_cast<CharType>(0xDC));
oa->write_character(to_char_type(0xDC));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
// array 32
oa->write_character(static_cast<CharType>(0xDD));
oa->write_character(to_char_type(0xDD));
write_number(static_cast<uint32_t>(N));
}
@ -8799,13 +8804,13 @@ class binary_writer
else if (N <= (std::numeric_limits<uint16_t>::max)())
{
// map 16
oa->write_character(static_cast<CharType>(0xDE));
oa->write_character(to_char_type(0xDE));
write_number(static_cast<uint16_t>(N));
}
else if (N <= (std::numeric_limits<uint32_t>::max)())
{
// map 32
oa->write_character(static_cast<CharType>(0xDF));
oa->write_character(to_char_type(0xDF));
write_number(static_cast<uint32_t>(N));
}
@ -8838,7 +8843,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('Z'));
oa->write_character(to_char_type('Z'));
}
break;
}
@ -8848,8 +8853,8 @@ class binary_writer
if (add_prefix)
{
oa->write_character(j.m_value.boolean
? static_cast<CharType>('T')
: static_cast<CharType>('F'));
? to_char_type('T')
: to_char_type('F'));
}
break;
}
@ -8876,7 +8881,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('S'));
oa->write_character(to_char_type('S'));
}
write_number_with_ubjson_prefix(j.m_value.string->size(), true);
oa->write_characters(
@ -8889,7 +8894,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('['));
oa->write_character(to_char_type('['));
}
bool prefix_required = true;
@ -8906,14 +8911,14 @@ class binary_writer
if (same_prefix)
{
prefix_required = false;
oa->write_character(static_cast<CharType>('$'));
oa->write_character(to_char_type('$'));
oa->write_character(first_prefix);
}
}
if (use_count)
{
oa->write_character(static_cast<CharType>('#'));
oa->write_character(to_char_type('#'));
write_number_with_ubjson_prefix(j.m_value.array->size(), true);
}
@ -8924,7 +8929,7 @@ class binary_writer
if (not use_count)
{
oa->write_character(static_cast<CharType>(']'));
oa->write_character(to_char_type(']'));
}
break;
@ -8934,7 +8939,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('{'));
oa->write_character(to_char_type('{'));
}
bool prefix_required = true;
@ -8951,14 +8956,14 @@ class binary_writer
if (same_prefix)
{
prefix_required = false;
oa->write_character(static_cast<CharType>('$'));
oa->write_character(to_char_type('$'));
oa->write_character(first_prefix);
}
}
if (use_count)
{
oa->write_character(static_cast<CharType>('#'));
oa->write_character(to_char_type('#'));
write_number_with_ubjson_prefix(j.m_value.object->size(), true);
}
@ -8973,7 +8978,7 @@ class binary_writer
if (not use_count)
{
oa->write_character(static_cast<CharType>('}'));
oa->write_character(to_char_type('}'));
}
break;
@ -8993,9 +8998,9 @@ class binary_writer
@return The size of a BSON document entry header, including the id marker
and the entry name size (and its null-terminator).
*/
static std::size_t calc_bson_entry_header_size(const typename BasicJsonType::string_t& name)
static std::size_t calc_bson_entry_header_size(const string_t& name)
{
const auto it = name.find(static_cast<typename BasicJsonType::string_t::value_type>(0));
const auto it = name.find(static_cast<typename string_t::value_type>(0));
if (JSON_UNLIKELY(it != BasicJsonType::string_t::npos))
{
JSON_THROW(out_of_range::create(409,
@ -9008,10 +9013,10 @@ class binary_writer
/*!
@brief Writes the given @a element_type and @a name to the output adapter
*/
void write_bson_entry_header(const typename BasicJsonType::string_t& name,
std::uint8_t element_type)
void write_bson_entry_header(const string_t& name,
const std::uint8_t element_type)
{
oa->write_character(static_cast<CharType>(element_type)); // boolean
oa->write_character(to_char_type(element_type)); // boolean
oa->write_characters(
reinterpret_cast<const CharType*>(name.c_str()),
name.size() + 1u);
@ -9020,17 +9025,17 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and boolean value @a value
*/
void write_bson_boolean(const typename BasicJsonType::string_t& name,
void write_bson_boolean(const string_t& name,
const bool value)
{
write_bson_entry_header(name, 0x08);
oa->write_character(value ? static_cast<CharType>(0x01) : static_cast<CharType>(0x00));
oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
}
/*!
@brief Writes a BSON element with key @a name and double value @a value
*/
void write_bson_double(const typename BasicJsonType::string_t& name,
void write_bson_double(const string_t& name,
const double value)
{
write_bson_entry_header(name, 0x01);
@ -9040,7 +9045,7 @@ class binary_writer
/*!
@return The size of the BSON-encoded string in @a value
*/
static std::size_t calc_bson_string_size(const typename BasicJsonType::string_t& value)
static std::size_t calc_bson_string_size(const string_t& value)
{
return sizeof(std::int32_t) + value.size() + 1ul;
}
@ -9048,8 +9053,8 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and string value @a value
*/
void write_bson_string(const typename BasicJsonType::string_t& name,
const typename BasicJsonType::string_t& value)
void write_bson_string(const string_t& name,
const string_t& value)
{
write_bson_entry_header(name, 0x02);
@ -9062,7 +9067,7 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and null value
*/
void write_bson_null(const typename BasicJsonType::string_t& name)
void write_bson_null(const string_t& name)
{
write_bson_entry_header(name, 0x0A);
}
@ -9085,7 +9090,7 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and integer @a value
*/
void write_bson_integer(const typename BasicJsonType::string_t& name,
void write_bson_integer(const string_t& name,
const std::int64_t value)
{
if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
@ -9103,45 +9108,39 @@ class binary_writer
/*!
@return The size of the BSON-encoded unsigned integer in @a j
*/
static std::size_t calc_bson_unsigned_size(const std::uint64_t value)
static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
{
if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{
return sizeof(std::int32_t);
}
else
{
return sizeof(std::int64_t);
}
return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
? sizeof(std::int32_t)
: sizeof(std::int64_t);
}
/*!
@brief Writes a BSON element with key @a name and unsigned @a value
*/
void write_bson_unsigned(const typename BasicJsonType::string_t& name,
void write_bson_unsigned(const string_t& name,
const std::uint64_t value)
{
if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{
write_bson_entry_header(name, 0x10); // int32
write_bson_entry_header(name, 0x10 /* int32 */);
write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
}
else if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
{
write_bson_entry_header(name, 0x12); // int64
write_bson_entry_header(name, 0x12 /* int64 */);
write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
}
else
{
JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(value)));
JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(value) + " cannot be represented by BSON as it does not fit int64"));
}
}
/*!
@brief Writes a BSON element with key @a name and object @a value
*/
void write_bson_object_entry(const typename BasicJsonType::string_t& name,
void write_bson_object_entry(const string_t& name,
const typename BasicJsonType::object_t& value)
{
write_bson_entry_header(name, 0x03); // object
@ -9167,7 +9166,7 @@ class binary_writer
/*!
@brief Writes a BSON element with key @a name and array @a value
*/
void write_bson_array(const typename BasicJsonType::string_t& name,
void write_bson_array(const string_t& name,
const typename BasicJsonType::array_t& value)
{
write_bson_entry_header(name, 0x04); // array
@ -9180,22 +9179,19 @@ class binary_writer
write_bson_element(std::to_string(array_index++), el);
}
oa->write_character(static_cast<CharType>(0x00));
oa->write_character(to_char_type(0x00));
}
/*!
@brief Calculates the size necessary to serialize the JSON value @a j with its @a name
@return The calculated size for the BSON document entry for @a j with the given @a name.
*/
static std::size_t calc_bson_element_size(const typename BasicJsonType::string_t& name,
static std::size_t calc_bson_element_size(const string_t& name,
const BasicJsonType& j)
{
const auto header_size = calc_bson_entry_header_size(name);
switch (j.type())
{
case value_t::discarded:
return 0ul;
case value_t::object:
return header_size + calc_bson_object_size(*j.m_value.object);
@ -9235,14 +9231,11 @@ class binary_writer
current BSON document
@return The size of the BSON entry
*/
void write_bson_element(const typename BasicJsonType::string_t& name,
void write_bson_element(const string_t& name,
const BasicJsonType& j)
{
switch (j.type())
{
case value_t::discarded:
return;
case value_t::object:
return write_bson_object_entry(name, *j.m_value.object);
@ -9283,12 +9276,11 @@ class binary_writer
*/
static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
{
std::size_t document_size = 0;
for (const auto& el : value)
std::size_t document_size = std::accumulate(value.begin(), value.end(), 0,
[](size_t result, const typename BasicJsonType::object_t::value_type & el)
{
document_size += calc_bson_element_size(el.first, el.second);
}
return result += calc_bson_element_size(el.first, el.second);
});
return sizeof(std::int32_t) + document_size + 1ul;
}
@ -9306,7 +9298,7 @@ class binary_writer
write_bson_element(el.first, el.second);
}
oa->write_character(static_cast<CharType>(0x00));
oa->write_character(to_char_type(0x00));
}
//////////
@ -9315,12 +9307,12 @@ class binary_writer
static constexpr CharType get_cbor_float_prefix(float /*unused*/)
{
return static_cast<CharType>(0xFA); // Single-Precision Float
return to_char_type(0xFA); // Single-Precision Float
}
static constexpr CharType get_cbor_float_prefix(double /*unused*/)
{
return static_cast<CharType>(0xFB); // Double-Precision Float
return to_char_type(0xFB); // Double-Precision Float
}
/////////////
@ -9329,12 +9321,12 @@ class binary_writer
static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
{
return static_cast<CharType>(0xCA); // float 32
return to_char_type(0xCA); // float 32
}
static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
{
return static_cast<CharType>(0xCB); // float 64
return to_char_type(0xCB); // float 64
}
////////////
@ -9364,7 +9356,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
oa->write_character(to_char_type('i')); // int8
}
write_number(static_cast<uint8_t>(n));
}
@ -9372,7 +9364,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
oa->write_character(to_char_type('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
@ -9380,7 +9372,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
oa->write_character(to_char_type('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
@ -9388,7 +9380,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
oa->write_character(to_char_type('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
@ -9396,7 +9388,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
oa->write_character(to_char_type('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
@ -9417,7 +9409,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('i')); // int8
oa->write_character(to_char_type('i')); // int8
}
write_number(static_cast<int8_t>(n));
}
@ -9425,7 +9417,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('U')); // uint8
oa->write_character(to_char_type('U')); // uint8
}
write_number(static_cast<uint8_t>(n));
}
@ -9433,7 +9425,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('I')); // int16
oa->write_character(to_char_type('I')); // int16
}
write_number(static_cast<int16_t>(n));
}
@ -9441,7 +9433,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('l')); // int32
oa->write_character(to_char_type('l')); // int32
}
write_number(static_cast<int32_t>(n));
}
@ -9449,7 +9441,7 @@ class binary_writer
{
if (add_prefix)
{
oa->write_character(static_cast<CharType>('L')); // int64
oa->write_character(to_char_type('L')); // int64
}
write_number(static_cast<int64_t>(n));
}
@ -9584,6 +9576,46 @@ class binary_writer
oa->write_characters(vec.data(), sizeof(NumberType));
}
// The following to_char_type functions are implement the conversion
// between uint8_t and CharType. In case CharType is not unsigned,
// such a conversion is required to allow values greater than 128.
// See <https://github.com/nlohmann/json/issues/1286> for a discussion.
template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >
static constexpr CharType to_char_type(std::uint8_t x) noexcept
{
return *reinterpret_cast<char*>(&x);
}
template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >
static CharType to_char_type(std::uint8_t x) noexcept
{
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
static_assert(std::is_pod<CharType>::value, "CharType must be POD");
CharType result;
std::memcpy(&result, &x, sizeof(x));
return result;
}
template<typename C = CharType,
enable_if_t<std::is_unsigned<C>::value>* = nullptr>
static constexpr CharType to_char_type(std::uint8_t x) noexcept
{
return x;
}
template < typename InputCharType, typename C = CharType,
enable_if_t <
std::is_signed<C>::value and
std::is_signed<char>::value and
std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
> * = nullptr >
static constexpr CharType to_char_type(InputCharType x) noexcept
{
return x;
}
private:
/// whether we can assume little endianess
const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();

View file

@ -37,14 +37,6 @@ TEST_CASE("BSON")
{
SECTION("individual values not supported")
{
SECTION("discarded")
{
// discarded values are not serialized
json j = json::value_t::discarded;
const auto result = json::to_bson(j);
CHECK(result.empty());
}
SECTION("null")
{
json j = nullptr;
@ -392,32 +384,6 @@ TEST_CASE("BSON")
CHECK(json::from_bson(result, true, false) == j);
}
SECTION("discarded values are not serialized")
{
json j = json::value_t::discarded;
const auto result = json::to_bson(j);
CHECK(result.empty());
}
SECTION("discarded members are not serialized")
{
json j =
{
{ "entry", json::value_t::discarded }
};
std::vector<uint8_t> expected =
{
0x05, 0x00, 0x00, 0x00, // size (little endian)
// no entries
0x00 // end marker
};
const auto result = json::to_bson(j);
CHECK(result == expected);
}
SECTION("non-empty object with object member")
{
json j =
@ -1136,7 +1102,7 @@ TEST_CASE("BSON numerical data")
};
CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.out_of_range.407] number overflow serializing " + std::to_string(i));
CHECK_THROWS_WITH(json::to_bson(j), "[json.exception.out_of_range.407] integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64");
}
}