2.1.3, 2.1.8: one UBJSON container start helper, shared frame base (#5891)
write_ubjson_start_array/_object are now write_ubjson_start_container<IsArray>, keeping the array-only begin()+1 scan and excessive_valueless rule. ubjson_frame derives from binary_container_frame instead of duplicating it. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 file changed
+32
-72
@@ -626,7 +626,7 @@ class binary_writer
|
|||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
bool prefix_required = true;
|
bool prefix_required = true;
|
||||||
const bool write_closer = write_ubjson_start_array(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
const bool write_closer = write_ubjson_start_container<true>(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto& array = *j.m_data.m_value.array;
|
const auto& array = *j.m_data.m_value.array;
|
||||||
@@ -704,7 +704,7 @@ class binary_writer
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool prefix_required = true;
|
bool prefix_required = true;
|
||||||
const bool write_closer = write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
const bool write_closer = write_ubjson_start_container<false>(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
||||||
|
|
||||||
write_ubjson_members(j, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth);
|
write_ubjson_members(j, use_count, use_type, prefix_required, use_bjdata, bjdata_version, depth);
|
||||||
|
|
||||||
@@ -967,9 +967,10 @@ class binary_writer
|
|||||||
write_msgpack_container_prefix(N, j, 0x80, 0xDE, 0xDF);
|
write_msgpack_container_prefix(N, j, 0x80, 0xDE, 0xDF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief a CBOR, MessagePack, or BON8 array or object whose elements
|
/// @brief a CBOR, MessagePack, BON8, or (as the base of @ref ubjson_frame)
|
||||||
/// @ref write_cbor_iterative, @ref write_msgpack_iterative, or
|
/// UBJSON array or object whose elements @ref write_container_iterative,
|
||||||
/// @ref write_bon8_iterative is still writing
|
/// @ref write_bon8_iterative, or @ref write_ubjson_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
|
||||||
@@ -1156,24 +1157,34 @@ class binary_writer
|
|||||||
write_container_iterative<msgpack_walk>(root);
|
write_container_iterative<msgpack_walk>(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return true when a closing ']' still has to be written after the elements
|
/*!
|
||||||
bool write_ubjson_start_array(const BasicJsonType& j, const bool use_count, const bool use_type,
|
@brief write the start of an array (@a IsArray) or object: its opening
|
||||||
const bool add_prefix, const bool use_bjdata, bool& prefix_required)
|
marker, the optimized type, and the count
|
||||||
|
|
||||||
|
@return true when a closing ']' or '}' still has to be written after the
|
||||||
|
elements
|
||||||
|
*/
|
||||||
|
template<bool IsArray>
|
||||||
|
bool write_ubjson_start_container(const BasicJsonType& j, const bool use_count, const bool use_type,
|
||||||
|
const bool add_prefix, const bool use_bjdata, bool& prefix_required)
|
||||||
{
|
{
|
||||||
prefix_required = true;
|
prefix_required = true;
|
||||||
if (add_prefix)
|
if (add_prefix)
|
||||||
{
|
{
|
||||||
oa.write_character(to_char_type('['));
|
oa.write_character(to_char_type(IsArray ? '[' : '{'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_type && !j.m_data.m_value.array->empty())
|
const std::size_t size = IsArray ? j.m_data.m_value.array->size() : j.m_data.m_value.object->size();
|
||||||
|
|
||||||
|
if (use_type && size != 0)
|
||||||
{
|
{
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
{
|
{
|
||||||
throw_size_marker_required(j);
|
throw_size_marker_required(j);
|
||||||
}
|
}
|
||||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
||||||
const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
|
// the first element of an array has been compared with itself
|
||||||
|
const bool same_prefix = std::all_of(IsArray ? j.begin() + 1 : j.begin(), j.end(),
|
||||||
[this, first_prefix, use_bjdata](const BasicJsonType & v)
|
[this, first_prefix, use_bjdata](const BasicJsonType & v)
|
||||||
{
|
{
|
||||||
return ubjson_prefix(v, use_bjdata) == first_prefix;
|
return ubjson_prefix(v, use_bjdata) == first_prefix;
|
||||||
@@ -1185,8 +1196,9 @@ class binary_writer
|
|||||||
// those, at one byte per element, so the result can be read back.
|
// those, at one byte per element, so the result can be read back.
|
||||||
// Objects are not affected: every element is preceded by its key.
|
// Objects are not affected: every element is preceded by its key.
|
||||||
const bool valueless_type = (first_prefix == 'Z' || first_prefix == 'T' || first_prefix == 'F');
|
const bool valueless_type = (first_prefix == 'Z' || first_prefix == 'T' || first_prefix == 'F');
|
||||||
const bool excessive_valueless = valueless_type
|
const bool excessive_valueless = IsArray
|
||||||
&& j.m_data.m_value.array->size() > detail::max_valueless_container_size;
|
&& valueless_type
|
||||||
|
&& size > detail::max_valueless_container_size;
|
||||||
|
|
||||||
if (same_prefix && !excessive_valueless
|
if (same_prefix && !excessive_valueless
|
||||||
&& !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix)))
|
&& !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix)))
|
||||||
@@ -1199,46 +1211,7 @@ class binary_writer
|
|||||||
|
|
||||||
if (use_count)
|
if (use_count)
|
||||||
{
|
{
|
||||||
write_ubjson_count(j.m_data.m_value.array->size(), use_bjdata);
|
write_ubjson_count(size, use_bjdata);
|
||||||
}
|
|
||||||
|
|
||||||
return !use_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @return true when a closing '}' still has to be written after the elements
|
|
||||||
bool write_ubjson_start_object(const BasicJsonType& j, const bool use_count, const bool use_type,
|
|
||||||
const bool add_prefix, const bool use_bjdata, bool& prefix_required)
|
|
||||||
{
|
|
||||||
prefix_required = true;
|
|
||||||
if (add_prefix)
|
|
||||||
{
|
|
||||||
oa.write_character(to_char_type('{'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_type && !j.m_data.m_value.object->empty())
|
|
||||||
{
|
|
||||||
if (!use_count)
|
|
||||||
{
|
|
||||||
throw_size_marker_required(j);
|
|
||||||
}
|
|
||||||
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
|
|
||||||
const bool same_prefix = std::all_of(j.begin(), j.end(),
|
|
||||||
[this, first_prefix, use_bjdata](const BasicJsonType & v)
|
|
||||||
{
|
|
||||||
return ubjson_prefix(v, use_bjdata) == first_prefix;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (same_prefix && !(use_bjdata && is_bjdata_excluded_type_marker(first_prefix)))
|
|
||||||
{
|
|
||||||
prefix_required = false;
|
|
||||||
oa.write_character(to_char_type('$'));
|
|
||||||
oa.write_character(first_prefix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_count)
|
|
||||||
{
|
|
||||||
write_ubjson_count(j.m_data.m_value.object->size(), use_bjdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return !use_count;
|
return !use_count;
|
||||||
@@ -1266,21 +1239,12 @@ class binary_writer
|
|||||||
|
|
||||||
/// @brief an object or array @ref write_ubjson_iterative is still writing
|
/// @brief an object or array @ref write_ubjson_iterative is still writing
|
||||||
/// the elements of
|
/// the elements of
|
||||||
struct ubjson_frame
|
struct ubjson_frame : binary_container_frame
|
||||||
{
|
{
|
||||||
ubjson_frame(const BasicJsonType* value_, const bool prefix_required_) noexcept
|
ubjson_frame(const BasicJsonType* value_, const bool prefix_required_) noexcept
|
||||||
: value(value_)
|
: binary_container_frame(value_)
|
||||||
, prefix_required(prefix_required_)
|
, prefix_required(prefix_required_)
|
||||||
{
|
{}
|
||||||
if (value->is_object())
|
|
||||||
{
|
|
||||||
object_it = value->m_data.m_value.object->cbegin();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
array_it = value->m_data.m_value.array->cbegin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// declared for GCC's -Weffc++, which asks for them in a class with
|
// declared for GCC's -Weffc++, which asks for them in a class with
|
||||||
// pointer members and a non-trivial destructor; the exception
|
// pointer members and a non-trivial destructor; the exception
|
||||||
@@ -1292,13 +1256,9 @@ class binary_writer
|
|||||||
ubjson_frame& operator=(ubjson_frame&&) = default;
|
ubjson_frame& operator=(ubjson_frame&&) = default;
|
||||||
~ubjson_frame() = default;
|
~ubjson_frame() = default;
|
||||||
|
|
||||||
/// the array or object being written
|
|
||||||
const BasicJsonType* value;
|
|
||||||
/// whether value's elements each carry their own type marker; an
|
/// whether value's elements each carry their own type marker; an
|
||||||
/// optimized ($type) container writes it once for all of them instead
|
/// optimized ($type) container writes it once for all of them instead
|
||||||
bool prefix_required;
|
bool prefix_required;
|
||||||
typename BasicJsonType::object_t::const_iterator object_it{};
|
|
||||||
typename BasicJsonType::array_t::const_iterator array_it{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1332,11 +1292,11 @@ class binary_writer
|
|||||||
bool prefix_required = true;
|
bool prefix_required = true;
|
||||||
if (is_array)
|
if (is_array)
|
||||||
{
|
{
|
||||||
write_ubjson_start_array(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
write_ubjson_start_container<true>(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_ubjson_start_object(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
write_ubjson_start_container<false>(j, use_count, use_type, add_prefix, use_bjdata, prefix_required);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool empty = is_array ? j.m_data.m_value.array->empty() : j.m_data.m_value.object->empty();
|
const bool empty = is_array ? j.m_data.m_value.array->empty() : j.m_data.m_value.object->empty();
|
||||||
@@ -1346,7 +1306,7 @@ class binary_writer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_ubjson_start_array/_object return !use_count, i.e. whether a
|
// write_ubjson_start_container returns !use_count, i.e. whether a
|
||||||
// closer still has to be written; use_count is constant for the whole
|
// closer still has to be written; use_count is constant for the whole
|
||||||
// document, so that is recomputed here instead of being carried along
|
// document, so that is recomputed here instead of being carried along
|
||||||
if (!use_count)
|
if (!use_count)
|
||||||
|
|||||||
Reference in new issue
Block a user