mirror of
https://github.com/nlohmann/json.git
synced 2026-10-11 17:07:15 +00:00
#5795 and #5806 changed binary_writer.hpp but were merged without
updated amalgamated files, so the check_amalgamation run on develop
(c59ad9525) fails. This is the output of 'make amalgamate'; no source
files change.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
c59ad95252
commit
e8b747e4bc
1 file changed
+199
-30
Generated
+199
-30
@@ -4171,6 +4171,10 @@ struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using detect_key_compare = typename T::key_compare;
|
using detect_key_compare = typename T::key_compare;
|
||||||
|
|
||||||
|
// detects whether two values of type T can be compared with operator==
|
||||||
|
template<typename T>
|
||||||
|
using detect_equal_comparable = decltype(static_cast<bool>(std::declval<const T&>() == std::declval<const T&>()));
|
||||||
|
|
||||||
// obtains the actual object key comparator: object_t::key_compare if the
|
// obtains the actual object key comparator: object_t::key_compare if the
|
||||||
// object type defines it, and default_object_comparator_t otherwise
|
// object type defines it, and default_object_comparator_t otherwise
|
||||||
//
|
//
|
||||||
@@ -22042,12 +22046,6 @@ class binary_writer
|
|||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
static_assert(
|
|
||||||
std::is_convertible <
|
|
||||||
typename BasicJsonType::object_t::key_type,
|
|
||||||
string_t >::value,
|
|
||||||
"object_t::key_type must be implicitly convertible to string_t");
|
|
||||||
|
|
||||||
// step 1: write control byte and the object size
|
// step 1: write control byte and the object size
|
||||||
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
write_cbor_head(0xA0, j.m_data.m_value.object->size());
|
||||||
|
|
||||||
@@ -22055,7 +22053,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
// el.first is written directly (not via a temporary
|
// el.first is written directly (not via a temporary
|
||||||
// basic_json), with the object as diagnostics context
|
// basic_json), with the object as diagnostics context
|
||||||
write_cbor_string(el.first, j);
|
write_cbor_key(el.first, j);
|
||||||
write_cbor(el.second, depth + 1);
|
write_cbor(el.second, depth + 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -22320,12 +22318,6 @@ class binary_writer
|
|||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
static_assert(
|
|
||||||
std::is_convertible <
|
|
||||||
typename BasicJsonType::object_t::key_type,
|
|
||||||
string_t >::value,
|
|
||||||
"object_t::key_type must be implicitly convertible to string_t");
|
|
||||||
|
|
||||||
// step 1: write control byte and the object size
|
// step 1: write control byte and the object size
|
||||||
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
write_msgpack_object_prefix(j.m_data.m_value.object->size(), j);
|
||||||
|
|
||||||
@@ -22333,7 +22325,7 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
// as in write_cbor, el.first is written directly with the
|
// as in write_cbor, el.first is written directly with the
|
||||||
// object as diagnostics context
|
// object as diagnostics context
|
||||||
write_msgpack_string(el.first, j);
|
write_msgpack_key(el.first, j);
|
||||||
write_msgpack(el.second, depth + 1);
|
write_msgpack(el.second, depth + 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -22609,9 +22601,9 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief a CBOR or MessagePack array or object whose elements
|
/// @brief a CBOR, MessagePack, or BON8 array or object whose elements
|
||||||
/// @ref write_cbor_iterative or @ref write_msgpack_iterative is
|
/// @ref write_cbor_iterative, @ref write_msgpack_iterative, or
|
||||||
/// still writing
|
/// @ref write_bon8_iterative is still writing
|
||||||
struct binary_container_frame
|
struct binary_container_frame
|
||||||
{
|
{
|
||||||
explicit binary_container_frame(const BasicJsonType* value_) noexcept
|
explicit binary_container_frame(const BasicJsonType* value_) noexcept
|
||||||
@@ -22723,7 +22715,7 @@ class binary_writer
|
|||||||
|
|
||||||
// the key is written directly (not via a temporary basic_json),
|
// the key is written directly (not via a temporary basic_json),
|
||||||
// with the object as diagnostics context, as in write_cbor
|
// with the object as diagnostics context, as in write_cbor
|
||||||
write_cbor_string(current.object_it->first, *current.value);
|
write_cbor_key(current.object_it->first, *current.value);
|
||||||
const BasicJsonType* child = &(current.object_it->second);
|
const BasicJsonType* child = &(current.object_it->second);
|
||||||
++stack.back().object_it;
|
++stack.back().object_it;
|
||||||
write_cbor_value_or_push(*child, stack);
|
write_cbor_value_or_push(*child, stack);
|
||||||
@@ -22800,7 +22792,7 @@ class binary_writer
|
|||||||
|
|
||||||
// as in write_cbor_iterative, the key is written directly with
|
// as in write_cbor_iterative, the key is written directly with
|
||||||
// the object as diagnostics context
|
// the object as diagnostics context
|
||||||
write_msgpack_string(current.object_it->first, *current.value);
|
write_msgpack_key(current.object_it->first, *current.value);
|
||||||
const BasicJsonType* child = &(current.object_it->second);
|
const BasicJsonType* child = &(current.object_it->second);
|
||||||
++stack.back().object_it;
|
++stack.back().object_it;
|
||||||
write_msgpack_value_or_push(*child, stack);
|
write_msgpack_value_or_push(*child, stack);
|
||||||
@@ -23405,6 +23397,21 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief Writes the head of a BSON element with key @a name whose value is
|
||||||
|
the object or array @a j: its type, key, and @a size
|
||||||
|
|
||||||
|
Called while the key is in scope: an object key is a key_type, which
|
||||||
|
may only convert to a temporary string_t, so it cannot be kept by
|
||||||
|
pointer until after the loop over the entries.
|
||||||
|
*/
|
||||||
|
void write_bson_nested_head(const string_t& name, const BasicJsonType& j,
|
||||||
|
const std::size_t size)
|
||||||
|
{
|
||||||
|
write_bson_entry_header(name, j.is_object() ? 0x03 : 0x04);
|
||||||
|
write_number<std::int32_t>(to_bson_length(size), true);
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief an object or array of the BSON document being sized or written
|
/// @brief an object or array of the BSON document being sized or written
|
||||||
struct bson_frame
|
struct bson_frame
|
||||||
{
|
{
|
||||||
@@ -23569,7 +23576,6 @@ class binary_writer
|
|||||||
{
|
{
|
||||||
// write entries until the current object or array is done, or an
|
// write entries until the current object or array is done, or an
|
||||||
// entry is an object or array itself
|
// entry is an object or array itself
|
||||||
const string_t* nested_name = nullptr;
|
|
||||||
const BasicJsonType* nested = nullptr;
|
const BasicJsonType* nested = nullptr;
|
||||||
if (current.value->is_object())
|
if (current.value->is_object())
|
||||||
{
|
{
|
||||||
@@ -23580,7 +23586,7 @@ class binary_writer
|
|||||||
++current.member;
|
++current.member;
|
||||||
if (el.second.is_structured())
|
if (el.second.is_structured())
|
||||||
{
|
{
|
||||||
nested_name = &el.first;
|
write_bson_nested_head(el.first, el.second, nested_sizes[next_size++]);
|
||||||
nested = &el.second;
|
nested = &el.second;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -23599,7 +23605,7 @@ class binary_writer
|
|||||||
++current.index;
|
++current.index;
|
||||||
if (el.is_structured())
|
if (el.is_structured())
|
||||||
{
|
{
|
||||||
nested_name = &index_name;
|
write_bson_nested_head(index_name, el, nested_sizes[next_size++]);
|
||||||
nested = ⪙
|
nested = ⪙
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -23611,8 +23617,6 @@ class binary_writer
|
|||||||
|
|
||||||
if (nested != nullptr)
|
if (nested != nullptr)
|
||||||
{
|
{
|
||||||
write_bson_entry_header(*nested_name, nested->is_object() ? 0x03 : 0x04);
|
|
||||||
write_number<std::int32_t>(to_bson_length(nested_sizes[next_size++]), true);
|
|
||||||
parents.push_back(std::move(current));
|
parents.push_back(std::move(current));
|
||||||
current = bson_frame(nested);
|
current = bson_frame(nested);
|
||||||
continue;
|
continue;
|
||||||
@@ -23680,6 +23684,43 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write an object key as a CBOR text string
|
||||||
|
|
||||||
|
A key convertible to string_t is written directly. Other key types (only
|
||||||
|
an explicit conversion, or only a to_json overload) go through a temporary
|
||||||
|
basic_json, as in version 3.12.0; the temporary is then the diagnostics
|
||||||
|
context for strict UTF-8 checks.
|
||||||
|
*/
|
||||||
|
template<typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t<std::is_convertible<Key, string_t>::value, int> = 0>
|
||||||
|
void write_cbor_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& context)
|
||||||
|
{
|
||||||
|
write_cbor_string(key, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t < !std::is_convertible<Key, string_t>::value, int > = 0 >
|
||||||
|
void write_cbor_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& /*context*/)
|
||||||
|
{
|
||||||
|
write_cbor(BasicJsonType(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief write an object key as a MessagePack str, as in @ref write_cbor_key
|
||||||
|
template<typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t<std::is_convertible<Key, string_t>::value, int> = 0>
|
||||||
|
void write_msgpack_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& context)
|
||||||
|
{
|
||||||
|
write_msgpack_string(key, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename Key = typename BasicJsonType::object_t::key_type,
|
||||||
|
enable_if_t < !std::is_convertible<Key, string_t>::value, int > = 0 >
|
||||||
|
void write_msgpack_key(const typename BasicJsonType::object_t::key_type& key, const BasicJsonType& /*context*/)
|
||||||
|
{
|
||||||
|
write_msgpack(BasicJsonType(key));
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief write a CBOR text string
|
@brief write a CBOR text string
|
||||||
|
|
||||||
@@ -24301,11 +24342,27 @@ class binary_writer
|
|||||||
@param[in] j JSON value to serialize
|
@param[in] j JSON value to serialize
|
||||||
@param[in,out] string_open whether the output ends with a non-empty
|
@param[in,out] string_open whether the output ends with a non-empty
|
||||||
string that has not been terminated with 0xFF
|
string that has not been terminated with 0xFF
|
||||||
|
@param[in] depth nesting level of @a j, counted from the
|
||||||
|
top-level value passed to @ref basic_json::to_bon8
|
||||||
|
@throw type_error.316 if a string value or an object key is not valid
|
||||||
|
UTF-8
|
||||||
|
@throw out_of_range.407 if an unsigned integer does not fit int64
|
||||||
@throw type_error.321 if @a j or a value nested in it is discarded
|
@throw type_error.321 if @a j or a value nested in it is discarded
|
||||||
|
|
||||||
|
Values nested deeper than @ref recursion_depth_limit are written by
|
||||||
|
@ref write_bon8_iterative without the call stack.
|
||||||
|
|
||||||
|
@sa @ref write_cbor
|
||||||
|
@sa https://github.com/nlohmann/json/issues/5392
|
||||||
*/
|
*/
|
||||||
void write_bon8_value(const BasicJsonType& j, bool& string_open)
|
void write_bon8_value(const BasicJsonType& j, bool& string_open, const std::size_t depth = 0)
|
||||||
{
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(depth >= recursion_depth_limit()) && (j.is_array() || j.is_object()))
|
||||||
|
{
|
||||||
|
write_bon8_iterative(j, string_open);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (j.type())
|
switch (j.type())
|
||||||
{
|
{
|
||||||
case value_t::null:
|
case value_t::null:
|
||||||
@@ -24359,7 +24416,7 @@ class binary_writer
|
|||||||
|
|
||||||
for (const auto& el : *j.m_data.m_value.array)
|
for (const auto& el : *j.m_data.m_value.array)
|
||||||
{
|
{
|
||||||
write_bon8_value(el, string_open);
|
write_bon8_value(el, string_open, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (N > 4)
|
if (N > 4)
|
||||||
@@ -24378,7 +24435,7 @@ class binary_writer
|
|||||||
for (const auto& el : *j.m_data.m_value.object)
|
for (const auto& el : *j.m_data.m_value.object)
|
||||||
{
|
{
|
||||||
write_bon8_string(el.first, string_open, j);
|
write_bon8_string(el.first, string_open, j);
|
||||||
write_bon8_value(el.second, string_open);
|
write_bon8_value(el.second, string_open, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (N > 4)
|
if (N > 4)
|
||||||
@@ -24415,6 +24472,83 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write @a j with @ref write_bon8_value, or write its marker and push
|
||||||
|
a frame for @ref write_bon8_iterative to continue with its elements
|
||||||
|
|
||||||
|
A scalar, and an empty array or object, are written out in full and not
|
||||||
|
pushed.
|
||||||
|
|
||||||
|
@sa @ref write_cbor_value_or_push
|
||||||
|
*/
|
||||||
|
void write_bon8_value_or_push(const BasicJsonType& j, bool& string_open, std::vector<binary_container_frame>& stack)
|
||||||
|
{
|
||||||
|
if (j.is_array() || j.is_object())
|
||||||
|
{
|
||||||
|
// arrays use the markers 0x80..0x85, objects 0x86..0x8B; the last
|
||||||
|
// one stands for more than four elements, closed later with 0xFE
|
||||||
|
const auto N = j.size();
|
||||||
|
const std::size_t base = j.is_array() ? 0x80 : 0x86;
|
||||||
|
write_bon8_marker(static_cast<std::uint8_t>(base + (N <= 4 ? N : 5)), string_open);
|
||||||
|
if (N != 0)
|
||||||
|
{
|
||||||
|
stack.emplace_back(&j);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_bon8_value(j, string_open);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief write out @a root and everything below it without the call stack
|
||||||
|
|
||||||
|
A container with more than four elements is closed with 0xFE once its
|
||||||
|
last element is written, as in @ref write_bon8_value.
|
||||||
|
|
||||||
|
@sa @ref write_cbor_iterative
|
||||||
|
*/
|
||||||
|
void write_bon8_iterative(const BasicJsonType& root, bool& string_open)
|
||||||
|
{
|
||||||
|
// only a container with elements is ever pushed; see write_bon8_value_or_push
|
||||||
|
std::vector<binary_container_frame> stack;
|
||||||
|
write_bon8_value_or_push(root, string_open, stack);
|
||||||
|
|
||||||
|
while (!stack.empty())
|
||||||
|
{
|
||||||
|
const binary_container_frame current = stack.back();
|
||||||
|
const bool is_array = current.value->is_array();
|
||||||
|
const bool at_end = is_array
|
||||||
|
? current.array_it == current.value->m_data.m_value.array->cend()
|
||||||
|
: current.object_it == current.value->m_data.m_value.object->cend();
|
||||||
|
|
||||||
|
if (at_end)
|
||||||
|
{
|
||||||
|
if (current.value->size() > 4)
|
||||||
|
{
|
||||||
|
write_bon8_marker(0xFE, string_open);
|
||||||
|
}
|
||||||
|
stack.pop_back();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the child before pushing: entering it can move every frame
|
||||||
|
const BasicJsonType* child = nullptr;
|
||||||
|
if (is_array)
|
||||||
|
{
|
||||||
|
child = &(*current.array_it);
|
||||||
|
++stack.back().array_it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_bon8_string(current.object_it->first, string_open, *current.value);
|
||||||
|
child = &(current.object_it->second);
|
||||||
|
++stack.back().object_it;
|
||||||
|
}
|
||||||
|
write_bon8_value_or_push(*child, string_open, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief write a single byte that is not part of a string
|
@brief write a single byte that is not part of a string
|
||||||
|
|
||||||
@@ -29408,6 +29542,24 @@ public:
|
|||||||
return create<object_t>(first, last);
|
return create<object_t>(first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief compare two object keys for equality, if the key type supports it
|
||||||
|
/// @note object_t only needs operator< for its keys (std::map), so operator==
|
||||||
|
/// may not exist; the keys are then reported as different, which makes
|
||||||
|
/// copy_object_level pair the values via object_t::find()
|
||||||
|
template<typename K = typename object_t::key_type,
|
||||||
|
detail::enable_if_t<detail::is_detected<detail::detect_equal_comparable, K>::value, int> = 0>
|
||||||
|
static bool copy_keys_equal(const K& a, const K& b)
|
||||||
|
{
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename K = typename object_t::key_type,
|
||||||
|
detail::enable_if_t < !detail::is_detected<detail::detect_equal_comparable, K>::value, int > = 0 >
|
||||||
|
static bool copy_keys_equal(const K& /*a*/, const K& /*b*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief create the copy of the object @a src in @a dst
|
/// @brief create the copy of the object @a src in @a dst
|
||||||
/// @note structured values are appended to @a worklist instead
|
/// @note structured values are appended to @a worklist instead
|
||||||
static void copy_object_level(const basic_json& src, basic_json& dst,
|
static void copy_object_level(const basic_json& src, basic_json& dst,
|
||||||
@@ -29440,7 +29592,7 @@ public:
|
|||||||
auto src_it = src_object.cbegin();
|
auto src_it = src_object.cbegin();
|
||||||
for (auto& element : *dst.m_data.m_value.object)
|
for (auto& element : *dst.m_data.m_value.object)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_LIKELY(src_it != src_object.cend() && src_it->first == element.first))
|
if (JSON_HEDLEY_LIKELY(src_it != src_object.cend() && copy_keys_equal(src_it->first, element.first)))
|
||||||
{
|
{
|
||||||
copy_shallow(src_it->second, element.second, worklist);
|
copy_shallow(src_it->second, element.second, worklist);
|
||||||
++src_it;
|
++src_it;
|
||||||
@@ -31317,11 +31469,28 @@ public:
|
|||||||
// std::map or ordered_map) never moves from its argument, so key is still
|
// std::map or ordered_map) never moves from its argument, so key is still
|
||||||
// valid here regardless of whether KeyType was deduced as an rvalue reference
|
// valid here regardless of whether KeyType was deduced as an rvalue reference
|
||||||
// NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved)
|
// NOLINTNEXTLINE(bugprone-use-after-move,hicpp-invalid-access-moved)
|
||||||
JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", string_t(key), "' not found"), &j));
|
JSON_THROW(out_of_range::create(detail::exception_id::key_not_found, detail::concat("key '", key_for_message(key), "' not found"), &j));
|
||||||
}
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief key as it is passed to detail::concat for an error message
|
||||||
|
/// @note keys with data() and size() (such as string_t itself or a string
|
||||||
|
/// view) are passed through unchanged, so a miss does not copy them;
|
||||||
|
/// other keys (such as string literals or key types that only convert
|
||||||
|
/// to string_t) are converted to string_t
|
||||||
|
template < typename KeyType, detail::enable_if_t < detail::detect_string_can_append_data<string_t, KeyType>::value, int > = 0 >
|
||||||
|
static const KeyType & key_for_message(const KeyType& key)
|
||||||
|
{
|
||||||
|
return key; // NOLINT(bugprone-return-const-ref-from-parameter): the result is only passed to concat() within the full-expression that holds key
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename KeyType, detail::enable_if_t < !detail::detect_string_can_append_data<string_t, KeyType>::value, int > = 0 >
|
||||||
|
static string_t key_for_message(const KeyType& key)
|
||||||
|
{
|
||||||
|
return string_t(key);
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief checked array element access used by the at() overloads taking an index
|
/// @brief checked array element access used by the at() overloads taking an index
|
||||||
/// @throw type_error.304 if @a j is not an array
|
/// @throw type_error.304 if @a j is not an array
|
||||||
/// @throw out_of_range.401 if @a idx is out of range
|
/// @throw out_of_range.401 if @a idx is out of range
|
||||||
|
|||||||
Reference in new issue
Block a user