♻️ refine interface of wrapped_binary_t

This commit is contained in:
Niels Lohmann 2020-05-15 23:21:49 +02:00
parent a452e8a0a1
commit bc1886fb60
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
5 changed files with 186 additions and 86 deletions

View file

@ -227,8 +227,8 @@ class binary_reader
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary")));
} }
result.has_subtype = true; // All BSON binary values have a subtype result.m_has_subtype = true; // All BSON binary values have a subtype
get_number<std::uint8_t>(input_format_t::bson, result.subtype); get_number<std::uint8_t>(input_format_t::bson, result.m_subtype);
return get_binary(input_format_t::bson, len, result); return get_binary(input_format_t::bson, len, result);
} }
@ -1524,58 +1524,58 @@ class binary_reader
case 0xC7: // ext 8 case 0xC7: // ext 8
{ {
std::uint8_t len; std::uint8_t len;
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, len) and return get_number(input_format_t::msgpack, len) and
get_number(input_format_t::msgpack, result.subtype) and get_number(input_format_t::msgpack, result.m_subtype) and
get_binary(input_format_t::msgpack, len, result); get_binary(input_format_t::msgpack, len, result);
} }
case 0xC8: // ext 16 case 0xC8: // ext 16
{ {
std::uint16_t len; std::uint16_t len;
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, len) and return get_number(input_format_t::msgpack, len) and
get_number(input_format_t::msgpack, result.subtype) and get_number(input_format_t::msgpack, result.m_subtype) and
get_binary(input_format_t::msgpack, len, result); get_binary(input_format_t::msgpack, len, result);
} }
case 0xC9: // ext 32 case 0xC9: // ext 32
{ {
std::uint32_t len; std::uint32_t len;
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, len) and return get_number(input_format_t::msgpack, len) and
get_number(input_format_t::msgpack, result.subtype) and get_number(input_format_t::msgpack, result.m_subtype) and
get_binary(input_format_t::msgpack, len, result); get_binary(input_format_t::msgpack, len, result);
} }
case 0xD4: // fixext 1 case 0xD4: // fixext 1
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 1, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result);
} }
case 0xD5: // fixext 2 case 0xD5: // fixext 2
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 2, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result);
} }
case 0xD6: // fixext 4 case 0xD6: // fixext 4
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 4, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result);
} }
case 0xD7: // fixext 8 case 0xD7: // fixext 8
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 8, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result);
} }
case 0xD8: // fixext 16 case 0xD8: // fixext 16
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 16, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result);
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE

View file

@ -550,7 +550,7 @@ class binary_writer
{ {
// step 0: determine if the binary type has a set subtype to // step 0: determine if the binary type has a set subtype to
// determine whether or not to use the ext or fixext types // determine whether or not to use the ext or fixext types
const bool use_ext = j.m_value.binary->has_subtype; const bool use_ext = j.m_value.binary->has_subtype();
// step 1: write control byte and the byte string length // step 1: write control byte and the byte string length
const auto N = j.m_value.binary->size(); const auto N = j.m_value.binary->size();
@ -630,7 +630,9 @@ class binary_writer
// step 1.5: if this is an ext type, write the subtype // step 1.5: if this is an ext type, write the subtype
if (use_ext) if (use_ext)
{ {
write_number(j.m_value.binary->subtype); std::uint8_t subtype;
write_number(subtype);
j.m_value.binary->set_subtype(subtype);
} }
// step 2: write the byte string // step 2: write the byte string
@ -1085,12 +1087,7 @@ class binary_writer
write_bson_entry_header(name, 0x05); write_bson_entry_header(name, 0x05);
write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size())); write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size()));
std::uint8_t subtype = 0x00; // Generic Binary Subtype write_number(value.has_subtype() ? value.subtype() : 0x00);
if (value.has_subtype)
{
subtype = value.subtype;
}
write_number(subtype);
oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size()); oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
} }

View file

@ -17,8 +17,13 @@ his- or herself with a specific naming scheme in order to override the
binary type. I.e. it's for ease of use. binary type. I.e. it's for ease of use.
*/ */
template<typename BinaryType> template<typename BinaryType>
struct wrapped_binary_t : public BinaryType class wrapped_binary_t : public BinaryType
{ {
public:
// to simplify code in binary_reader
template<typename BasicJsonType, typename InputAdapterType, typename SAX>
friend class binary_reader;
using binary_t = BinaryType; using binary_t = BinaryType;
wrapped_binary_t() noexcept(noexcept(binary_t())) wrapped_binary_t() noexcept(noexcept(binary_t()))
@ -36,18 +41,56 @@ struct wrapped_binary_t : public BinaryType
wrapped_binary_t(const binary_t& bint, wrapped_binary_t(const binary_t& bint,
std::uint8_t st) noexcept(noexcept(binary_t(bint))) std::uint8_t st) noexcept(noexcept(binary_t(bint)))
: binary_t(bint) : binary_t(bint)
, subtype(st) , m_subtype(st)
, has_subtype(true) , m_has_subtype(true)
{} {}
wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint))))
: binary_t(std::move(bint)) : binary_t(std::move(bint))
, subtype(st) , m_subtype(st)
, has_subtype(true) , m_has_subtype(true)
{} {}
std::uint8_t subtype = 0; /*!
bool has_subtype = false; @brief set the subtype
@param subtype subtype to set (implementation specific)
*/
void set_subtype(std::uint8_t subtype) noexcept
{
m_subtype = subtype;
m_has_subtype = true;
}
/*!
@brief get the subtype
@return subtype (implementation specific)
*/
constexpr std::uint8_t subtype() const noexcept
{
return m_subtype;
}
/*!
@brief get whether a subtype was set
@return whether a subtype was set
*/
constexpr bool has_subtype() const noexcept
{
return m_has_subtype;
}
/*!
@brief clear the subtype
*/
void clear_subtype() noexcept
{
m_subtype = 0;
m_has_subtype = false;
}
private:
std::uint8_t m_subtype = 0;
bool m_has_subtype = false;
}; };
} // namespace detail } // namespace detail

View file

@ -844,10 +844,10 @@ class basic_json
simply defined as an ordered sequence of zero or more byte values. simply defined as an ordered sequence of zero or more byte values.
Additionally, as an implementation detail, the subtype of the binary data is Additionally, as an implementation detail, the subtype of the binary data is
carried around as a `unint8_t`, which is compatible with both of the binary carried around as a `std::uint8_t`, which is compatible with both of the
data formats that use binary subtyping, (though the specific numbering is binary data formats that use binary subtyping, (though the specific
incompatible with each other, and it is up to the user to translate between numbering is incompatible with each other, and it is up to the user to
them). translate between them).
[CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type
as: as:
@ -890,6 +890,18 @@ class basic_json
*/ */
using binary_t = BinaryType; using binary_t = BinaryType;
/*!
@brief binary array with a binary type
This type is used to store binary types internally. It wrapps the template
type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish
different binary types from different formats.
While @ref binary_t is used to define how binary values are stored, this
type is used to access binary values once they are parsed.
@sa @ref binary_array -- create a binary array
*/
using internal_binary_t = nlohmann::detail::wrapped_binary_t<BinaryType>; using internal_binary_t = nlohmann::detail::wrapped_binary_t<BinaryType>;
/// @} /// @}
@ -3882,8 +3894,7 @@ class basic_json
{ {
if (is_binary()) if (is_binary())
{ {
m_value.binary->has_subtype = true; m_value.binary->set_subtype(subtype);
m_value.binary->subtype = subtype;
} }
} }
@ -3911,8 +3922,7 @@ class basic_json
{ {
if (is_binary()) if (is_binary())
{ {
m_value.binary->has_subtype = false; m_value.binary->clear_subtype();
m_value.binary->subtype = 0;
} }
} }
@ -3936,7 +3946,7 @@ class basic_json
*/ */
bool has_subtype() const noexcept bool has_subtype() const noexcept
{ {
return is_binary() and m_value.binary->has_subtype; return is_binary() and m_value.binary->has_subtype();
} }
/*! /*!

View file

@ -5804,8 +5804,8 @@ class binary_reader
return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"))); return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary")));
} }
result.has_subtype = true; // All BSON binary values have a subtype result.m_has_subtype = true; // All BSON binary values have a subtype
get_number<std::uint8_t>(input_format_t::bson, result.subtype); get_number<std::uint8_t>(input_format_t::bson, result.m_subtype);
return get_binary(input_format_t::bson, len, result); return get_binary(input_format_t::bson, len, result);
} }
@ -7101,58 +7101,58 @@ class binary_reader
case 0xC7: // ext 8 case 0xC7: // ext 8
{ {
std::uint8_t len; std::uint8_t len;
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, len) and return get_number(input_format_t::msgpack, len) and
get_number(input_format_t::msgpack, result.subtype) and get_number(input_format_t::msgpack, result.m_subtype) and
get_binary(input_format_t::msgpack, len, result); get_binary(input_format_t::msgpack, len, result);
} }
case 0xC8: // ext 16 case 0xC8: // ext 16
{ {
std::uint16_t len; std::uint16_t len;
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, len) and return get_number(input_format_t::msgpack, len) and
get_number(input_format_t::msgpack, result.subtype) and get_number(input_format_t::msgpack, result.m_subtype) and
get_binary(input_format_t::msgpack, len, result); get_binary(input_format_t::msgpack, len, result);
} }
case 0xC9: // ext 32 case 0xC9: // ext 32
{ {
std::uint32_t len; std::uint32_t len;
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, len) and return get_number(input_format_t::msgpack, len) and
get_number(input_format_t::msgpack, result.subtype) and get_number(input_format_t::msgpack, result.m_subtype) and
get_binary(input_format_t::msgpack, len, result); get_binary(input_format_t::msgpack, len, result);
} }
case 0xD4: // fixext 1 case 0xD4: // fixext 1
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 1, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 1, result);
} }
case 0xD5: // fixext 2 case 0xD5: // fixext 2
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 2, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 2, result);
} }
case 0xD6: // fixext 4 case 0xD6: // fixext 4
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 4, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 4, result);
} }
case 0xD7: // fixext 8 case 0xD7: // fixext 8
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 8, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 8, result);
} }
case 0xD8: // fixext 16 case 0xD8: // fixext 16
{ {
result.has_subtype = true; result.m_has_subtype = true;
return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 16, result); return get_number(input_format_t::msgpack, result.m_subtype) and get_binary(input_format_t::msgpack, 16, result);
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
@ -12557,7 +12557,7 @@ class binary_writer
{ {
// step 0: determine if the binary type has a set subtype to // step 0: determine if the binary type has a set subtype to
// determine whether or not to use the ext or fixext types // determine whether or not to use the ext or fixext types
const bool use_ext = j.m_value.binary->has_subtype; const bool use_ext = j.m_value.binary->has_subtype();
// step 1: write control byte and the byte string length // step 1: write control byte and the byte string length
const auto N = j.m_value.binary->size(); const auto N = j.m_value.binary->size();
@ -12637,7 +12637,9 @@ class binary_writer
// step 1.5: if this is an ext type, write the subtype // step 1.5: if this is an ext type, write the subtype
if (use_ext) if (use_ext)
{ {
write_number(j.m_value.binary->subtype); std::uint8_t subtype;
write_number(subtype);
j.m_value.binary->set_subtype(subtype);
} }
// step 2: write the byte string // step 2: write the byte string
@ -13092,12 +13094,7 @@ class binary_writer
write_bson_entry_header(name, 0x05); write_bson_entry_header(name, 0x05);
write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size())); write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size()));
std::uint8_t subtype = 0x00; // Generic Binary Subtype write_number(value.has_subtype() ? value.subtype() : 0x00);
if (value.has_subtype)
{
subtype = value.subtype;
}
write_number(subtype);
oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size()); oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
} }
@ -15593,8 +15590,13 @@ his- or herself with a specific naming scheme in order to override the
binary type. I.e. it's for ease of use. binary type. I.e. it's for ease of use.
*/ */
template<typename BinaryType> template<typename BinaryType>
struct wrapped_binary_t : public BinaryType class wrapped_binary_t : public BinaryType
{ {
public:
// to simplify code in binary_reader
template<typename BasicJsonType, typename InputAdapterType, typename SAX>
friend class binary_reader;
using binary_t = BinaryType; using binary_t = BinaryType;
wrapped_binary_t() noexcept(noexcept(binary_t())) wrapped_binary_t() noexcept(noexcept(binary_t()))
@ -15612,18 +15614,56 @@ struct wrapped_binary_t : public BinaryType
wrapped_binary_t(const binary_t& bint, wrapped_binary_t(const binary_t& bint,
std::uint8_t st) noexcept(noexcept(binary_t(bint))) std::uint8_t st) noexcept(noexcept(binary_t(bint)))
: binary_t(bint) : binary_t(bint)
, subtype(st) , m_subtype(st)
, has_subtype(true) , m_has_subtype(true)
{} {}
wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint)))) wrapped_binary_t(binary_t&& bint, std::uint8_t st) noexcept(noexcept(binary_t(std::move(bint))))
: binary_t(std::move(bint)) : binary_t(std::move(bint))
, subtype(st) , m_subtype(st)
, has_subtype(true) , m_has_subtype(true)
{} {}
std::uint8_t subtype = 0; /*!
bool has_subtype = false; @brief set the subtype
@param subtype subtype to set (implementation specific)
*/
void set_subtype(std::uint8_t subtype) noexcept
{
m_subtype = subtype;
m_has_subtype = true;
}
/*!
@brief get the subtype
@return subtype (implementation specific)
*/
constexpr std::uint8_t subtype() const noexcept
{
return m_subtype;
}
/*!
@brief get whether a subtype was set
@return whether a subtype was set
*/
constexpr bool has_subtype() const noexcept
{
return m_has_subtype;
}
/*!
@brief clear the subtype
*/
void clear_subtype() noexcept
{
m_subtype = 0;
m_has_subtype = false;
}
private:
std::uint8_t m_subtype = 0;
bool m_has_subtype = false;
}; };
} // namespace detail } // namespace detail
@ -16403,10 +16443,10 @@ class basic_json
simply defined as an ordered sequence of zero or more byte values. simply defined as an ordered sequence of zero or more byte values.
Additionally, as an implementation detail, the subtype of the binary data is Additionally, as an implementation detail, the subtype of the binary data is
carried around as a `unint8_t`, which is compatible with both of the binary carried around as a `std::uint8_t`, which is compatible with both of the
data formats that use binary subtyping, (though the specific numbering is binary data formats that use binary subtyping, (though the specific
incompatible with each other, and it is up to the user to translate between numbering is incompatible with each other, and it is up to the user to
them). translate between them).
[CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type
as: as:
@ -16449,6 +16489,18 @@ class basic_json
*/ */
using binary_t = BinaryType; using binary_t = BinaryType;
/*!
@brief binary array with a binary type
This type is used to store binary types internally. It wrapps the template
type `BinaryType` (@ref binary_t) and adds a subtype to allow to distinguish
different binary types from different formats.
While @ref binary_t is used to define how binary values are stored, this
type is used to access binary values once they are parsed.
@sa @ref binary_array -- create a binary array
*/
using internal_binary_t = nlohmann::detail::wrapped_binary_t<BinaryType>; using internal_binary_t = nlohmann::detail::wrapped_binary_t<BinaryType>;
/// @} /// @}
@ -19441,8 +19493,7 @@ class basic_json
{ {
if (is_binary()) if (is_binary())
{ {
m_value.binary->has_subtype = true; m_value.binary->set_subtype(subtype);
m_value.binary->subtype = subtype;
} }
} }
@ -19470,8 +19521,7 @@ class basic_json
{ {
if (is_binary()) if (is_binary())
{ {
m_value.binary->has_subtype = false; m_value.binary->clear_subtype();
m_value.binary->subtype = 0;
} }
} }
@ -19495,7 +19545,7 @@ class basic_json
*/ */
bool has_subtype() const noexcept bool has_subtype() const noexcept
{ {
return is_binary() and m_value.binary->has_subtype; return is_binary() and m_value.binary->has_subtype();
} }
/*! /*!