Merge pull request #2125 from nlohmann/binary_type
Clean up implementation of binary type
This commit is contained in:
		
						commit
						a82c80e9af
					
				
					 75 changed files with 1425 additions and 780 deletions
				
			
		
							
								
								
									
										167
									
								
								include/nlohmann/byte_container_with_subtype.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								include/nlohmann/byte_container_with_subtype.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,167 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <cstdint> // uint8_t
 | ||||
| #include <tuple> // tie
 | ||||
| #include <utility> // move
 | ||||
| 
 | ||||
| namespace nlohmann | ||||
| { | ||||
| 
 | ||||
| /*!
 | ||||
| @brief an internal type for a backed binary type | ||||
| 
 | ||||
| This type extends the template parameter @a BinaryType provided to `basic_json` | ||||
| with a subtype used by BSON and MessagePack. This type exists so that the user | ||||
| does not have to specify a type themselves with a specific naming scheme in | ||||
| order to override the binary type. | ||||
| 
 | ||||
| @tparam BinaryType container to store bytes (`std::vector<std::uint8_t>` by | ||||
|                    default) | ||||
| 
 | ||||
| @since version 3.8.0 | ||||
| */ | ||||
| template<typename BinaryType> | ||||
| class byte_container_with_subtype : public BinaryType | ||||
| { | ||||
|   public: | ||||
|     /// the type of the underlying container
 | ||||
|     using container_type = BinaryType; | ||||
| 
 | ||||
|     byte_container_with_subtype() noexcept(noexcept(container_type())) | ||||
|         : container_type() | ||||
|     {} | ||||
| 
 | ||||
|     byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) | ||||
|         : container_type(b) | ||||
|     {} | ||||
| 
 | ||||
|     byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) | ||||
|         : container_type(std::move(b)) | ||||
|     {} | ||||
| 
 | ||||
|     byte_container_with_subtype(const container_type& b, | ||||
|                                 std::uint8_t subtype) noexcept(noexcept(container_type(b))) | ||||
|         : container_type(b) | ||||
|         , m_subtype(subtype) | ||||
|         , m_has_subtype(true) | ||||
|     {} | ||||
| 
 | ||||
|     byte_container_with_subtype(container_type&& b, std::uint8_t subtype) noexcept(noexcept(container_type(std::move(b)))) | ||||
|         : container_type(std::move(b)) | ||||
|         , m_subtype(subtype) | ||||
|         , m_has_subtype(true) | ||||
|     {} | ||||
| 
 | ||||
|     bool operator==(const byte_container_with_subtype& rhs) const | ||||
|     { | ||||
|         return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) == | ||||
|                std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype); | ||||
|     } | ||||
| 
 | ||||
|     bool operator!=(const byte_container_with_subtype& rhs) const | ||||
|     { | ||||
|         return !(rhs == *this); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief sets the binary subtype | ||||
| 
 | ||||
|     Sets the binary subtype of the value, also flags a binary JSON value as | ||||
|     having a subtype, which has implications for serialization. | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref subtype() -- return the binary subtype | ||||
|     @sa @ref clear_subtype() -- clears the binary subtype | ||||
|     @sa @ref has_subtype() -- returns whether or not the binary value has a | ||||
|     subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     void set_subtype(std::uint8_t subtype) noexcept | ||||
|     { | ||||
|         m_subtype = subtype; | ||||
|         m_has_subtype = true; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief return the binary subtype | ||||
| 
 | ||||
|     Returns the numerical subtype of the value if it has a subtype. If it does | ||||
|     not have a subtype, this function will return size_t(-1) as a sentinel | ||||
|     value. | ||||
| 
 | ||||
|     @return the numerical subtype of the binary value | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref set_subtype() -- sets the binary subtype | ||||
|     @sa @ref clear_subtype() -- clears the binary subtype | ||||
|     @sa @ref has_subtype() -- returns whether or not the binary value has a | ||||
|     subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     constexpr std::uint8_t subtype() const noexcept | ||||
|     { | ||||
|         return m_subtype; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief return whether the value has a subtype | ||||
| 
 | ||||
|     @return whether the value has a subtype | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref subtype() -- return the binary subtype | ||||
|     @sa @ref set_subtype() -- sets the binary subtype | ||||
|     @sa @ref clear_subtype() -- clears the binary subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     constexpr bool has_subtype() const noexcept | ||||
|     { | ||||
|         return m_has_subtype; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief clears the binary subtype | ||||
| 
 | ||||
|     Clears the binary subtype and flags the value as not having a subtype, which | ||||
|     has implications for serialization; for instance MessagePack will prefer the | ||||
|     bin family over the ext family. | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref subtype() -- return the binary subtype | ||||
|     @sa @ref set_subtype() -- sets the binary subtype | ||||
|     @sa @ref has_subtype() -- returns whether or not the binary value has a | ||||
|     subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     void clear_subtype() noexcept | ||||
|     { | ||||
|         m_subtype = 0; | ||||
|         m_has_subtype = false; | ||||
|     } | ||||
| 
 | ||||
|   private: | ||||
|     std::uint8_t m_subtype = 0; | ||||
|     bool m_has_subtype = false; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace nlohmann
 | ||||
|  | @ -228,9 +228,9 @@ template <typename BasicJsonType, typename ConstructibleArrayType, | |||
|               is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and | ||||
|               not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and | ||||
|               not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and | ||||
|               not std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value and | ||||
|               not is_basic_json<ConstructibleArrayType>::value, | ||||
|               int > = 0 > | ||||
| 
 | ||||
| auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) | ||||
| -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), | ||||
| j.template get<typename ConstructibleArrayType::value_type>(), | ||||
|  | @ -245,6 +245,17 @@ void()) | |||
|     from_json_array_impl(j, arr, priority_tag<3> {}); | ||||
| } | ||||
| 
 | ||||
| template <typename BasicJsonType> | ||||
| void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) | ||||
| { | ||||
|     if (JSON_HEDLEY_UNLIKELY(not j.is_binary())) | ||||
|     { | ||||
|         JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); | ||||
|     } | ||||
| 
 | ||||
|     bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>(); | ||||
| } | ||||
| 
 | ||||
| template<typename BasicJsonType, typename ConstructibleObjectType, | ||||
|          enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0> | ||||
| void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) | ||||
|  |  | |||
|  | @ -74,7 +74,7 @@ struct external_constructor<value_t::binary> | |||
|     static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) | ||||
|     { | ||||
|         j.m_type = value_t::binary; | ||||
|         typename BasicJsonType::internal_binary_t value{b}; | ||||
|         typename BasicJsonType::binary_t value{b}; | ||||
|         j.m_value = value; | ||||
|         j.assert_invariant(); | ||||
|     } | ||||
|  | @ -83,7 +83,7 @@ struct external_constructor<value_t::binary> | |||
|     static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) | ||||
|     { | ||||
|         j.m_type = value_t::binary; | ||||
|         typename BasicJsonType::internal_binary_t value{std::move(b)}; | ||||
|         typename BasicJsonType::binary_t value{std::move(b)}; | ||||
|         j.m_value = value; | ||||
|         j.assert_invariant(); | ||||
|     } | ||||
|  | @ -278,9 +278,9 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e) | |||
| template <typename BasicJsonType, typename CompatibleArrayType, | ||||
|           enable_if_t<is_compatible_array_type<BasicJsonType, | ||||
|                       CompatibleArrayType>::value and | ||||
|                       not is_compatible_object_type< | ||||
|                           BasicJsonType, CompatibleArrayType>::value and | ||||
|                       not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and | ||||
|                       not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and | ||||
|                       not std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value and | ||||
|                       not is_basic_json<CompatibleArrayType>::value, | ||||
|                       int> = 0> | ||||
| void to_json(BasicJsonType& j, const CompatibleArrayType& arr) | ||||
|  | @ -288,6 +288,12 @@ void to_json(BasicJsonType& j, const CompatibleArrayType& arr) | |||
|     external_constructor<value_t::array>::construct(j, arr); | ||||
| } | ||||
| 
 | ||||
| template <typename BasicJsonType> | ||||
| void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) | ||||
| { | ||||
|     external_constructor<value_t::binary>::construct(j, bin); | ||||
| } | ||||
| 
 | ||||
| template<typename BasicJsonType, typename T, | ||||
|          enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> | ||||
| void to_json(BasicJsonType& j, const std::valarray<T>& arr) | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ class binary_reader | |||
|     using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | ||||
|     using number_float_t = typename BasicJsonType::number_float_t; | ||||
|     using string_t = typename BasicJsonType::string_t; | ||||
|     using internal_binary_t = typename BasicJsonType::internal_binary_t; | ||||
|     using binary_t = typename BasicJsonType::binary_t; | ||||
|     using json_sax_t = SAX; | ||||
| 
 | ||||
|   public: | ||||
|  | @ -219,7 +219,7 @@ class binary_reader | |||
|     @return `true` if the byte array was successfully parsed | ||||
|     */ | ||||
|     template<typename NumberType> | ||||
|     bool get_bson_binary(const NumberType len, internal_binary_t& result) | ||||
|     bool get_bson_binary(const NumberType len, binary_t& result) | ||||
|     { | ||||
|         if (JSON_HEDLEY_UNLIKELY(len < 0)) | ||||
|         { | ||||
|  | @ -227,8 +227,10 @@ 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"))); | ||||
|         } | ||||
| 
 | ||||
|         result.has_subtype = true; // All BSON binary values have a subtype
 | ||||
|         get_number<std::uint8_t>(input_format_t::bson, result.subtype); | ||||
|         // All BSON binary values have a subtype
 | ||||
|         std::uint8_t subtype; | ||||
|         get_number<std::uint8_t>(input_format_t::bson, subtype); | ||||
|         result.set_subtype(subtype); | ||||
| 
 | ||||
|         return get_binary(input_format_t::bson, len, result); | ||||
|     } | ||||
|  | @ -274,7 +276,7 @@ class binary_reader | |||
|             case 0x05: // binary
 | ||||
|             { | ||||
|                 std::int32_t len; | ||||
|                 internal_binary_t value; | ||||
|                 binary_t value; | ||||
|                 return get_number<std::int32_t, true>(input_format_t::bson, len) and get_bson_binary(len, value) and sax->binary(value); | ||||
|             } | ||||
| 
 | ||||
|  | @ -530,7 +532,7 @@ class binary_reader | |||
|             case 0x5B: // Binary data (eight-byte uint64_t for n follow)
 | ||||
|             case 0x5F: // Binary data (indefinite length)
 | ||||
|             { | ||||
|                 internal_binary_t b; | ||||
|                 binary_t b; | ||||
|                 return get_cbor_binary(b) and sax->binary(b); | ||||
|             } | ||||
| 
 | ||||
|  | @ -860,7 +862,7 @@ class binary_reader | |||
| 
 | ||||
|     @return whether byte array creation completed | ||||
|     */ | ||||
|     bool get_cbor_binary(internal_binary_t& result) | ||||
|     bool get_cbor_binary(binary_t& result) | ||||
|     { | ||||
|         if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "binary"))) | ||||
|         { | ||||
|  | @ -901,32 +903,36 @@ class binary_reader | |||
|             case 0x58: // Binary data (one-byte uint8_t for n follows)
 | ||||
|             { | ||||
|                 std::uint8_t len; | ||||
|                 return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); | ||||
|                 return get_number(input_format_t::cbor, len) and | ||||
|                        get_binary(input_format_t::cbor, len, result); | ||||
|             } | ||||
| 
 | ||||
|             case 0x59: // Binary data (two-byte uint16_t for n follow)
 | ||||
|             { | ||||
|                 std::uint16_t len; | ||||
|                 return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); | ||||
|                 return get_number(input_format_t::cbor, len) and | ||||
|                        get_binary(input_format_t::cbor, len, result); | ||||
|             } | ||||
| 
 | ||||
|             case 0x5A: // Binary data (four-byte uint32_t for n follow)
 | ||||
|             { | ||||
|                 std::uint32_t len; | ||||
|                 return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); | ||||
|                 return get_number(input_format_t::cbor, len) and | ||||
|                        get_binary(input_format_t::cbor, len, result); | ||||
|             } | ||||
| 
 | ||||
|             case 0x5B: // Binary data (eight-byte uint64_t for n follow)
 | ||||
|             { | ||||
|                 std::uint64_t len; | ||||
|                 return get_number(input_format_t::cbor, len) and get_binary(input_format_t::cbor, len, result); | ||||
|                 return get_number(input_format_t::cbor, len) and | ||||
|                        get_binary(input_format_t::cbor, len, result); | ||||
|             } | ||||
| 
 | ||||
|             case 0x5F: // Binary data (indefinite length)
 | ||||
|             { | ||||
|                 while (get() != 0xFF) | ||||
|                 { | ||||
|                     internal_binary_t chunk; | ||||
|                     binary_t chunk; | ||||
|                     if (not get_cbor_binary(chunk)) | ||||
|                     { | ||||
|                         return false; | ||||
|  | @ -1276,7 +1282,7 @@ class binary_reader | |||
|             case 0xD7: // fixext 8
 | ||||
|             case 0xD8: // fixext 16
 | ||||
|             { | ||||
|                 internal_binary_t b; | ||||
|                 binary_t b; | ||||
|                 return get_msgpack_binary(b) and sax->binary(b); | ||||
|             } | ||||
| 
 | ||||
|  | @ -1499,83 +1505,106 @@ class binary_reader | |||
| 
 | ||||
|     @return whether byte array creation completed | ||||
|     */ | ||||
|     bool get_msgpack_binary(internal_binary_t& result) | ||||
|     bool get_msgpack_binary(binary_t& result) | ||||
|     { | ||||
|         // helper function to set the subtype
 | ||||
|         auto assign_and_return_true = [&result](std::int8_t subtype) | ||||
|         { | ||||
|             result.set_subtype(static_cast<std::uint8_t>(subtype)); | ||||
|             return true; | ||||
|         }; | ||||
| 
 | ||||
|         switch (current) | ||||
|         { | ||||
|             case 0xC4: // bin 8
 | ||||
|             { | ||||
|                 std::uint8_t len; | ||||
|                 return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); | ||||
|                 return get_number(input_format_t::msgpack, len) and | ||||
|                        get_binary(input_format_t::msgpack, len, result); | ||||
|             } | ||||
| 
 | ||||
|             case 0xC5: // bin 16
 | ||||
|             { | ||||
|                 std::uint16_t len; | ||||
|                 return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); | ||||
|                 return get_number(input_format_t::msgpack, len) and | ||||
|                        get_binary(input_format_t::msgpack, len, result); | ||||
|             } | ||||
| 
 | ||||
|             case 0xC6: // bin 32
 | ||||
|             { | ||||
|                 std::uint32_t len; | ||||
|                 return get_number(input_format_t::msgpack, len) and get_binary(input_format_t::msgpack, len, result); | ||||
|                 return get_number(input_format_t::msgpack, len) and | ||||
|                        get_binary(input_format_t::msgpack, len, result); | ||||
|             } | ||||
| 
 | ||||
|             case 0xC7: // ext 8
 | ||||
|             { | ||||
|                 std::uint8_t len; | ||||
|                 result.has_subtype = true; | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, len) and | ||||
|                        get_number(input_format_t::msgpack, result.subtype) and | ||||
|                        get_binary(input_format_t::msgpack, len, result); | ||||
|                        get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, len, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             case 0xC8: // ext 16
 | ||||
|             { | ||||
|                 std::uint16_t len; | ||||
|                 result.has_subtype = true; | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, len) and | ||||
|                        get_number(input_format_t::msgpack, result.subtype) and | ||||
|                        get_binary(input_format_t::msgpack, len, result); | ||||
|                        get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, len, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             case 0xC9: // ext 32
 | ||||
|             { | ||||
|                 std::uint32_t len; | ||||
|                 result.has_subtype = true; | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, len) and | ||||
|                        get_number(input_format_t::msgpack, result.subtype) and | ||||
|                        get_binary(input_format_t::msgpack, len, result); | ||||
|                        get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, len, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             case 0xD4: // fixext 1
 | ||||
|             { | ||||
|                 result.has_subtype = true; | ||||
|                 return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 1, result); | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, 1, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             case 0xD5: // fixext 2
 | ||||
|             { | ||||
|                 result.has_subtype = true; | ||||
|                 return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 2, result); | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, 2, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             case 0xD6: // fixext 4
 | ||||
|             { | ||||
|                 result.has_subtype = true; | ||||
|                 return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 4, result); | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, 4, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             case 0xD7: // fixext 8
 | ||||
|             { | ||||
|                 result.has_subtype = true; | ||||
|                 return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 8, result); | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, 8, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             case 0xD8: // fixext 16
 | ||||
|             { | ||||
|                 result.has_subtype = true; | ||||
|                 return get_number(input_format_t::msgpack, result.subtype) and get_binary(input_format_t::msgpack, 16, result); | ||||
|                 std::int8_t subtype; | ||||
|                 return get_number(input_format_t::msgpack, subtype) and | ||||
|                        get_binary(input_format_t::msgpack, 16, result) and | ||||
|                        assign_and_return_true(subtype); | ||||
|             } | ||||
| 
 | ||||
|             default:           // LCOV_EXCL_LINE
 | ||||
|  | @ -2194,7 +2223,7 @@ class binary_reader | |||
|     template<typename NumberType> | ||||
|     bool get_binary(const input_format_t format, | ||||
|                     const NumberType len, | ||||
|                     internal_binary_t& result) | ||||
|                     binary_t& result) | ||||
|     { | ||||
|         bool success = true; | ||||
|         std::generate_n(std::back_inserter(result), len, [this, &success, &format]() | ||||
|  |  | |||
|  | @ -23,13 +23,9 @@ input. | |||
| template<typename BasicJsonType> | ||||
| struct json_sax | ||||
| { | ||||
|     /// type for (signed) integers
 | ||||
|     using number_integer_t = typename BasicJsonType::number_integer_t; | ||||
|     /// type for unsigned integers
 | ||||
|     using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | ||||
|     /// type for floating-point numbers
 | ||||
|     using number_float_t = typename BasicJsonType::number_float_t; | ||||
|     /// type for strings
 | ||||
|     using string_t = typename BasicJsonType::string_t; | ||||
|     using binary_t = typename BasicJsonType::binary_t; | ||||
| 
 | ||||
|  | @ -214,7 +210,7 @@ class json_sax_dom_parser | |||
| 
 | ||||
|     bool binary(binary_t& val) | ||||
|     { | ||||
|         handle_value(BasicJsonType::binary_array(std::move(val))); | ||||
|         handle_value(std::move(val)); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|  | @ -404,7 +400,7 @@ class json_sax_dom_callback_parser | |||
| 
 | ||||
|     bool binary(binary_t& val) | ||||
|     { | ||||
|         handle_value(BasicJsonType::binary_array(val)); | ||||
|         handle_value(std::move(val)); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ template<typename BasicJsonType> struct internal_iterator | |||
|     /// iterator for JSON arrays
 | ||||
|     typename BasicJsonType::array_t::iterator array_iterator {}; | ||||
|     /// iterator for JSON binary arrays
 | ||||
|     typename BasicJsonType::binary_t::iterator binary_iterator {}; | ||||
|     typename BasicJsonType::binary_t::container_type::iterator binary_iterator {}; | ||||
|     /// generic iterator for all other types
 | ||||
|     primitive_iterator_t primitive_iterator {}; | ||||
| }; | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ template<typename BasicJsonType, typename CharType> | |||
| class binary_writer | ||||
| { | ||||
|     using string_t = typename BasicJsonType::string_t; | ||||
|     using internal_binary_t = typename BasicJsonType::internal_binary_t; | ||||
|     using binary_t = typename BasicJsonType::binary_t; | ||||
| 
 | ||||
|   public: | ||||
|     /*!
 | ||||
|  | @ -578,7 +578,7 @@ class binary_writer | |||
|             { | ||||
|                 // step 0: determine if the binary type has a set subtype to
 | ||||
|                 // 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
 | ||||
|                 const auto N = j.m_value.binary->size(); | ||||
|  | @ -658,7 +658,7 @@ class binary_writer | |||
|                 // step 1.5: if this is an ext type, write the subtype
 | ||||
|                 if (use_ext) | ||||
|                 { | ||||
|                     write_number(j.m_value.binary->subtype); | ||||
|                     write_number(static_cast<std::int8_t>(j.m_value.binary->subtype())); | ||||
|                 } | ||||
| 
 | ||||
|                 // step 2: write the byte string
 | ||||
|  | @ -1080,7 +1080,7 @@ class binary_writer | |||
|     /*!
 | ||||
|     @return The size of the BSON-encoded binary array @a value | ||||
|     */ | ||||
|     static std::size_t calc_bson_binary_size(const typename BasicJsonType::internal_binary_t& value) | ||||
|     static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) | ||||
|     { | ||||
|         return sizeof(std::int32_t) + value.size() + 1ul; | ||||
|     } | ||||
|  | @ -1108,17 +1108,12 @@ class binary_writer | |||
|     @brief Writes a BSON element with key @a name and binary value @a value | ||||
|     */ | ||||
|     void write_bson_binary(const string_t& name, | ||||
|                            const internal_binary_t& value) | ||||
|                            const binary_t& value) | ||||
|     { | ||||
|         write_bson_entry_header(name, 0x05); | ||||
| 
 | ||||
|         write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size())); | ||||
|         std::uint8_t subtype = 0x00; // Generic Binary Subtype
 | ||||
|         if (value.has_subtype) | ||||
|         { | ||||
|             subtype = value.subtype; | ||||
|         } | ||||
|         write_number(subtype); | ||||
|         write_number(value.has_subtype() ? value.subtype() : std::uint8_t(0x00)); | ||||
| 
 | ||||
|         oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size()); | ||||
|     } | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ class serializer | |||
|     using number_float_t = typename BasicJsonType::number_float_t; | ||||
|     using number_integer_t = typename BasicJsonType::number_integer_t; | ||||
|     using number_unsigned_t = typename BasicJsonType::number_unsigned_t; | ||||
|     using binary_t = typename BasicJsonType::binary_t; | ||||
|     using binary_char_t = typename BasicJsonType::binary_t::value_type; | ||||
|     static constexpr std::uint8_t UTF8_ACCEPT = 0; | ||||
|     static constexpr std::uint8_t UTF8_REJECT = 1; | ||||
| 
 | ||||
|  | @ -84,19 +84,22 @@ class serializer | |||
|     - strings and object keys are escaped using `escape_string()` | ||||
|     - integer numbers are converted implicitly via `operator<<` | ||||
|     - floating-point numbers are converted to a string using `"%g"` format | ||||
|     - if specified to, binary values are output using the syntax `b[]`, otherwise an exception is thrown | ||||
|     - binary values are serialized as objects containing the subtype and the | ||||
|       byte array | ||||
| 
 | ||||
|     @param[in] val               value to serialize | ||||
|     @param[in] pretty_print      whether the output shall be pretty-printed | ||||
|     @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters | ||||
|     in the output are escaped with `\uXXXX` sequences, and the result consists | ||||
|     of ASCII characters only. | ||||
|     @param[in] indent_step       the indent level | ||||
|     @param[in] current_indent    the current indent level (only used internally) | ||||
|     @param[in] serialize_binary  whether the output shall include non-standard binary output | ||||
|     */ | ||||
|     void dump(const BasicJsonType& val, const bool pretty_print, | ||||
|     void dump(const BasicJsonType& val, | ||||
|               const bool pretty_print, | ||||
|               const bool ensure_ascii, | ||||
|               const unsigned int indent_step, | ||||
|               const unsigned int current_indent = 0, | ||||
|               const bool serialize_binary = false) | ||||
|               const unsigned int current_indent = 0) | ||||
|     { | ||||
|         switch (val.m_type) | ||||
|         { | ||||
|  | @ -127,7 +130,7 @@ class serializer | |||
|                         o->write_character('\"'); | ||||
|                         dump_escaped(i->first, ensure_ascii); | ||||
|                         o->write_characters("\": ", 3); | ||||
|                         dump(i->second, true, ensure_ascii, indent_step, new_indent, serialize_binary); | ||||
|                         dump(i->second, true, ensure_ascii, indent_step, new_indent); | ||||
|                         o->write_characters(",\n", 2); | ||||
|                     } | ||||
| 
 | ||||
|  | @ -138,7 +141,7 @@ class serializer | |||
|                     o->write_character('\"'); | ||||
|                     dump_escaped(i->first, ensure_ascii); | ||||
|                     o->write_characters("\": ", 3); | ||||
|                     dump(i->second, true, ensure_ascii, indent_step, new_indent, serialize_binary); | ||||
|                     dump(i->second, true, ensure_ascii, indent_step, new_indent); | ||||
| 
 | ||||
|                     o->write_character('\n'); | ||||
|                     o->write_characters(indent_string.c_str(), current_indent); | ||||
|  | @ -155,7 +158,7 @@ class serializer | |||
|                         o->write_character('\"'); | ||||
|                         dump_escaped(i->first, ensure_ascii); | ||||
|                         o->write_characters("\":", 2); | ||||
|                         dump(i->second, false, ensure_ascii, indent_step, current_indent, serialize_binary); | ||||
|                         dump(i->second, false, ensure_ascii, indent_step, current_indent); | ||||
|                         o->write_character(','); | ||||
|                     } | ||||
| 
 | ||||
|  | @ -165,7 +168,7 @@ class serializer | |||
|                     o->write_character('\"'); | ||||
|                     dump_escaped(i->first, ensure_ascii); | ||||
|                     o->write_characters("\":", 2); | ||||
|                     dump(i->second, false, ensure_ascii, indent_step, current_indent, serialize_binary); | ||||
|                     dump(i->second, false, ensure_ascii, indent_step, current_indent); | ||||
| 
 | ||||
|                     o->write_character('}'); | ||||
|                 } | ||||
|  | @ -197,14 +200,14 @@ class serializer | |||
|                             i != val.m_value.array->cend() - 1; ++i) | ||||
|                     { | ||||
|                         o->write_characters(indent_string.c_str(), new_indent); | ||||
|                         dump(*i, true, ensure_ascii, indent_step, new_indent, serialize_binary); | ||||
|                         dump(*i, true, ensure_ascii, indent_step, new_indent); | ||||
|                         o->write_characters(",\n", 2); | ||||
|                     } | ||||
| 
 | ||||
|                     // last element
 | ||||
|                     assert(not val.m_value.array->empty()); | ||||
|                     o->write_characters(indent_string.c_str(), new_indent); | ||||
|                     dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent, serialize_binary); | ||||
|                     dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); | ||||
| 
 | ||||
|                     o->write_character('\n'); | ||||
|                     o->write_characters(indent_string.c_str(), current_indent); | ||||
|  | @ -218,13 +221,13 @@ class serializer | |||
|                     for (auto i = val.m_value.array->cbegin(); | ||||
|                             i != val.m_value.array->cend() - 1; ++i) | ||||
|                     { | ||||
|                         dump(*i, false, ensure_ascii, indent_step, current_indent, serialize_binary); | ||||
|                         dump(*i, false, ensure_ascii, indent_step, current_indent); | ||||
|                         o->write_character(','); | ||||
|                     } | ||||
| 
 | ||||
|                     // last element
 | ||||
|                     assert(not val.m_value.array->empty()); | ||||
|                     dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent, serialize_binary); | ||||
|                     dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); | ||||
| 
 | ||||
|                     o->write_character(']'); | ||||
|                 } | ||||
|  | @ -242,27 +245,73 @@ class serializer | |||
| 
 | ||||
|             case value_t::binary: | ||||
|             { | ||||
|                 if (not serialize_binary) | ||||
|                 if (pretty_print) | ||||
|                 { | ||||
|                     JSON_THROW(type_error::create(317, "cannot serialize binary data to text JSON")); | ||||
|                 } | ||||
|                     o->write_characters("{\n", 2); | ||||
| 
 | ||||
|                 if (val.m_value.binary->empty()) | ||||
|                 { | ||||
|                     o->write_characters("b[]", 3); | ||||
|                     // variable to hold indentation for recursive calls
 | ||||
|                     const auto new_indent = current_indent + indent_step; | ||||
|                     if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) | ||||
|                     { | ||||
|                         indent_string.resize(indent_string.size() * 2, ' '); | ||||
|                     } | ||||
| 
 | ||||
|                     o->write_characters(indent_string.c_str(), new_indent); | ||||
| 
 | ||||
|                     o->write_characters("\"bytes\": [", 10); | ||||
| 
 | ||||
|                     if (not val.m_value.binary->empty()) | ||||
|                     { | ||||
|                         for (auto i = val.m_value.binary->cbegin(); | ||||
|                                 i != val.m_value.binary->cend() - 1; ++i) | ||||
|                         { | ||||
|                             dump_integer(*i); | ||||
|                             o->write_characters(", ", 2); | ||||
|                         } | ||||
|                         dump_integer(val.m_value.binary->back()); | ||||
|                     } | ||||
| 
 | ||||
|                     o->write_characters("],\n", 3); | ||||
|                     o->write_characters(indent_string.c_str(), new_indent); | ||||
| 
 | ||||
|                     o->write_characters("\"subtype\": ", 11); | ||||
|                     if (val.m_value.binary->has_subtype()) | ||||
|                     { | ||||
|                         dump_integer(val.m_value.binary->subtype()); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         o->write_characters("null", 4); | ||||
|                     } | ||||
|                     o->write_character('\n'); | ||||
|                     o->write_characters(indent_string.c_str(), current_indent); | ||||
|                     o->write_character('}'); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     o->write_characters("b[", 2); | ||||
|                     for (auto i = val.m_value.binary->cbegin(); | ||||
|                             i != val.m_value.binary->cend() - 1; ++i) | ||||
|                     o->write_characters("{\"bytes\":[", 10); | ||||
| 
 | ||||
|                     if (not val.m_value.binary->empty()) | ||||
|                     { | ||||
|                         dump_integer(*i); | ||||
|                         o->write_character(','); | ||||
|                         for (auto i = val.m_value.binary->cbegin(); | ||||
|                                 i != val.m_value.binary->cend() - 1; ++i) | ||||
|                         { | ||||
|                             dump_integer(*i); | ||||
|                             o->write_character(','); | ||||
|                         } | ||||
|                         dump_integer(val.m_value.binary->back()); | ||||
|                     } | ||||
| 
 | ||||
|                     dump_integer(val.m_value.binary->back()); | ||||
|                     o->write_character(']'); | ||||
|                     o->write_characters("],\"subtype\":", 12); | ||||
|                     if (val.m_value.binary->has_subtype()) | ||||
|                     { | ||||
|                         dump_integer(val.m_value.binary->subtype()); | ||||
|                         o->write_character('}'); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         o->write_characters("null}", 5); | ||||
|                     } | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|  | @ -624,7 +673,7 @@ class serializer | |||
|     template<typename NumberType, detail::enable_if_t< | ||||
|                  std::is_same<NumberType, number_unsigned_t>::value or | ||||
|                  std::is_same<NumberType, number_integer_t>::value or | ||||
|                  std::is_same<NumberType, typename binary_t::value_type>::value, | ||||
|                  std::is_same<NumberType, binary_char_t>::value, | ||||
|                  int> = 0> | ||||
|     void dump_integer(NumberType x) | ||||
|     { | ||||
|  |  | |||
|  | @ -48,6 +48,7 @@ SOFTWARE. | |||
| #include <vector> // vector
 | ||||
| 
 | ||||
| #include <nlohmann/adl_serializer.hpp> | ||||
| #include <nlohmann/byte_container_with_subtype.hpp> | ||||
| #include <nlohmann/detail/boolean_operators.hpp> | ||||
| #include <nlohmann/detail/conversions/from_json.hpp> | ||||
| #include <nlohmann/detail/conversions/to_json.hpp> | ||||
|  | @ -838,21 +839,20 @@ class basic_json | |||
| 
 | ||||
|     This type is a type designed to carry binary data that appears in various | ||||
|     serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and | ||||
|     BSON's generic binary subtype.  This type is NOT a part of standard JSON and | ||||
|     exists solely for compatibility with these binary types.  As such, it is | ||||
|     BSON's generic binary subtype. This type is NOT a part of standard JSON and | ||||
|     exists solely for compatibility with these binary types. As such, it is | ||||
|     simply defined as an ordered sequence of zero or more byte values. | ||||
| 
 | ||||
|     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 | ||||
|     data formats that use binary subtyping, (though the specific numbering is | ||||
|     incompatible with each other, and it is up to the user to translate between | ||||
|     them). | ||||
|     carried around as a `std::uint8_t`, which is compatible with both of the | ||||
|     binary data formats that use binary subtyping, (though the specific | ||||
|     numbering is incompatible with each other, and it is up to the user to | ||||
|     translate between them). | ||||
| 
 | ||||
|     [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type
 | ||||
|     as: | ||||
|     > Major type 2:  a byte string.  The string's length in bytes is | ||||
|     > represented following the rules for positive integers (major type | ||||
|     > 0). | ||||
|     > Major type 2: a byte string. The string's length in bytes is represented | ||||
|     > following the rules for positive integers (major type 0). | ||||
| 
 | ||||
|     [MessagePack's documentation on the bin type | ||||
|     family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family)
 | ||||
|  | @ -868,7 +868,7 @@ class basic_json | |||
| 
 | ||||
|     None of these impose any limitations on the internal representation other | ||||
|     than the basic unit of storage be some type of array whose parts are | ||||
|     decomposible into bytes. | ||||
|     decomposable into bytes. | ||||
| 
 | ||||
|     The default representation of this binary format is a | ||||
|     `std::vector<std::uint8_t>`, which is a very common way to represent a byte | ||||
|  | @ -880,53 +880,30 @@ class basic_json | |||
| 
 | ||||
|     #### Storage | ||||
| 
 | ||||
|     Binary Arrays are stored as pointers in a @ref basic_json type.  That is, | ||||
|     Binary Arrays are stored as pointers in a @ref basic_json type. That is, | ||||
|     for any access to array values, a pointer of the type `binary_t*` must be | ||||
|     dereferenced. | ||||
| 
 | ||||
|     @sa @ref array_t -- type for an array value | ||||
|     #### Notes on subtypes | ||||
| 
 | ||||
|     - CBOR | ||||
|        - Binary values are represented as byte strings. No subtypes are | ||||
|          supported and will be ignored when CBOR is written. | ||||
|     - MessagePack | ||||
|        - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, | ||||
|          or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) | ||||
|          is used. For other sizes, the ext family (ext8, ext16, ext32) is used. | ||||
|          The subtype is then added as singed 8-bit integer. | ||||
|        - If no subtype is given, the bin family (bin8, bin16, bin32) is used. | ||||
|     - BSON | ||||
|        - If a subtype is given, it is used and added as unsigned 8-bit integer. | ||||
|        - If no subtype is given, the generic binary subtype 0x00 is used. | ||||
| 
 | ||||
|     @sa @ref binary -- create a binary array | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     using binary_t = BinaryType; | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief an internal type for a backed binary type | ||||
| 
 | ||||
|     This type is designed to be `binary_t` but with the subtype implementation | ||||
|     detail.  This type exists so that the user does not have to specify a struct | ||||
|     his- or herself with a specific naming scheme in order to override the | ||||
|     binary type.  I.e. it's for ease of use. | ||||
|     */ | ||||
|     struct internal_binary_t : public BinaryType | ||||
|     { | ||||
|         using BinaryType::BinaryType; | ||||
|         internal_binary_t() noexcept(noexcept(BinaryType())) | ||||
|             : BinaryType() | ||||
|         {} | ||||
|         internal_binary_t(const BinaryType& bint) noexcept(noexcept(BinaryType(bint))) | ||||
|             : BinaryType(bint) | ||||
|         {} | ||||
|         internal_binary_t(BinaryType&& bint) noexcept(noexcept(BinaryType(std::move(bint)))) | ||||
|             : BinaryType(std::move(bint)) | ||||
|         {} | ||||
|         internal_binary_t(const BinaryType& bint, std::uint8_t st) noexcept(noexcept(BinaryType(bint))) | ||||
|             : BinaryType(bint) | ||||
|             , subtype(st) | ||||
|             , has_subtype(true) | ||||
|         {} | ||||
|         internal_binary_t(BinaryType&& bint, std::uint8_t st) noexcept(noexcept(BinaryType(std::move(bint)))) | ||||
|             : BinaryType(std::move(bint)) | ||||
|             , subtype(st) | ||||
|             , has_subtype(true) | ||||
|         {} | ||||
| 
 | ||||
|         // TOOD: If minimum C++ version is ever bumped to C++17, this field
 | ||||
|         // deserves to be a std::optional
 | ||||
|         std::uint8_t subtype = 0; | ||||
|         bool has_subtype = false; | ||||
|     }; | ||||
| 
 | ||||
|     using binary_t = nlohmann::byte_container_with_subtype<BinaryType>; | ||||
|     /// @}
 | ||||
| 
 | ||||
|   private: | ||||
|  | @ -969,7 +946,7 @@ class basic_json | |||
|     number    | number_integer  | @ref number_integer_t | ||||
|     number    | number_unsigned | @ref number_unsigned_t | ||||
|     number    | number_float    | @ref number_float_t | ||||
|     binary    | binary          | pointer to @ref internal_binary_t | ||||
|     binary    | binary          | pointer to @ref binary_t | ||||
|     null      | null            | *no value is stored* | ||||
| 
 | ||||
|     @note Variable-length types (objects, arrays, and strings) are stored as | ||||
|  | @ -987,7 +964,7 @@ class basic_json | |||
|         /// string (stored with pointer to save storage)
 | ||||
|         string_t* string; | ||||
|         /// binary (stored with pointer to save storage)
 | ||||
|         internal_binary_t* binary; | ||||
|         binary_t* binary; | ||||
|         /// boolean
 | ||||
|         boolean_t boolean; | ||||
|         /// number (integer)
 | ||||
|  | @ -1032,7 +1009,7 @@ class basic_json | |||
| 
 | ||||
|                 case value_t::binary: | ||||
|                 { | ||||
|                     binary = create<internal_binary_t>(); | ||||
|                     binary = create<binary_t>(); | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|  | @ -1115,27 +1092,27 @@ class basic_json | |||
|         } | ||||
| 
 | ||||
|         /// constructor for binary arrays
 | ||||
|         json_value(const binary_t& value) | ||||
|         json_value(const typename binary_t::container_type& value) | ||||
|         { | ||||
|             binary = create<internal_binary_t>(value); | ||||
|             binary = create<binary_t>(value); | ||||
|         } | ||||
| 
 | ||||
|         /// constructor for rvalue binary arrays
 | ||||
|         json_value(binary_t&& value) | ||||
|         json_value(typename binary_t::container_type&& value) | ||||
|         { | ||||
|             binary = create<internal_binary_t>(std::move(value)); | ||||
|             binary = create<binary_t>(std::move(value)); | ||||
|         } | ||||
| 
 | ||||
|         /// constructor for binary arrays (internal type)
 | ||||
|         json_value(const internal_binary_t& value) | ||||
|         json_value(const binary_t& value) | ||||
|         { | ||||
|             binary = create<internal_binary_t>(value); | ||||
|             binary = create<binary_t>(value); | ||||
|         } | ||||
| 
 | ||||
|         /// constructor for rvalue binary arrays (internal type)
 | ||||
|         json_value(internal_binary_t&& value) | ||||
|         json_value(binary_t&& value) | ||||
|         { | ||||
|             binary = create<internal_binary_t>(std::move(value)); | ||||
|             binary = create<binary_t>(std::move(value)); | ||||
|         } | ||||
| 
 | ||||
|         void destroy(value_t t) noexcept | ||||
|  | @ -1215,7 +1192,7 @@ class basic_json | |||
| 
 | ||||
|                 case value_t::binary: | ||||
|                 { | ||||
|                     AllocatorType<internal_binary_t> alloc; | ||||
|                     AllocatorType<binary_t> alloc; | ||||
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, binary); | ||||
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1); | ||||
|                     break; | ||||
|  | @ -1501,7 +1478,7 @@ class basic_json | |||
|         using other_string_t = typename BasicJsonType::string_t; | ||||
|         using other_object_t = typename BasicJsonType::object_t; | ||||
|         using other_array_t = typename BasicJsonType::array_t; | ||||
|         using other_binary_t = typename BasicJsonType::internal_binary_t; | ||||
|         using other_binary_t = typename BasicJsonType::binary_t; | ||||
| 
 | ||||
|         switch (val.type()) | ||||
|         { | ||||
|  | @ -1668,22 +1645,22 @@ class basic_json | |||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief explicitly create a binary array from an already constructed copy of | ||||
|     its base type | ||||
|     @brief explicitly create a binary array (without subtype) | ||||
| 
 | ||||
|     Creates a JSON binary array value from a given `binary_t`. Binary values are | ||||
|     part of various binary formats, such as CBOR, MsgPack, and BSON.  And this | ||||
|     constructor is used to create a value for serialization to those formats. | ||||
|     Creates a JSON binary array value from a given binary container. Binary | ||||
|     values are part of various binary formats, such as CBOR, MessagePack, and | ||||
|     BSON. This constructor is used to create a value for serialization to those | ||||
|     formats. | ||||
| 
 | ||||
|     @note Note, this function exists because of the difficulty in correctly | ||||
|     specifying the correct template overload in the standard value ctor, as both | ||||
|     JSON arrays and JSON binary arrays are backed with some form of a | ||||
|     `std::vector`.  Because JSON binary arrays are a non-standard extension it | ||||
|     `std::vector`. Because JSON binary arrays are a non-standard extension it | ||||
|     was decided that it would be best to prevent automatic initialization of a | ||||
|     binary array type, for backwards compatibility and so it does not happen on | ||||
|     accident. | ||||
| 
 | ||||
|     @param[in] init  `binary_t` with JSON values to create a binary array from | ||||
|     @param[in] init container containing bytes to use as binary type | ||||
| 
 | ||||
|     @return JSON binary array value | ||||
| 
 | ||||
|  | @ -1695,7 +1672,7 @@ class basic_json | |||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     JSON_HEDLEY_WARN_UNUSED_RESULT | ||||
|     static basic_json binary_array(const binary_t& init) | ||||
|     static basic_json binary(const typename binary_t::container_type& init) | ||||
|     { | ||||
|         auto res = basic_json(); | ||||
|         res.m_type = value_t::binary; | ||||
|  | @ -1703,32 +1680,24 @@ class basic_json | |||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     JSON_HEDLEY_WARN_UNUSED_RESULT | ||||
|     static basic_json binary_array(const binary_t& init, std::uint8_t subtype) | ||||
|     { | ||||
|         auto res = basic_json(); | ||||
|         res.m_type = value_t::binary; | ||||
|         res.m_value = internal_binary_t(init, subtype); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief explicitly create a binary array from an already constructed rvalue | ||||
|     copy of its base type | ||||
|     @brief explicitly create a binary array (with subtype) | ||||
| 
 | ||||
|     Creates a JSON binary array value from a given `binary_t`. Binary values are | ||||
|     part of various binary formats, such as CBOR, MsgPack, and BSON.  And this | ||||
|     constructor is used to create a value for serialization to those formats. | ||||
|     Creates a JSON binary array value from a given binary container. Binary | ||||
|     values are part of various binary formats, such as CBOR, MessagePack, and | ||||
|     BSON. This constructor is used to create a value for serialization to those | ||||
|     formats. | ||||
| 
 | ||||
|     @note Note, this function exists because of the difficulty in correctly | ||||
|     specifying the correct template overload in the standard value ctor, as both | ||||
|     JSON arrays and JSON binary arrays are backed with some form of a | ||||
|     `std::vector`.  Because JSON binary arrays are a non-standard extension it | ||||
|     `std::vector`. Because JSON binary arrays are a non-standard extension it | ||||
|     was decided that it would be best to prevent automatic initialization of a | ||||
|     binary array type, for backwards compatibility and so it doesn't happen on | ||||
|     binary array type, for backwards compatibility and so it does not happen on | ||||
|     accident. | ||||
| 
 | ||||
|     @param[in] init  `binary_t` with JSON values to create a binary array from | ||||
|     @param[in] init container containing bytes to use as binary type | ||||
|     @param[in] subtype subtype to use in MessagePack and BSON | ||||
| 
 | ||||
|     @return JSON binary array value | ||||
| 
 | ||||
|  | @ -1740,7 +1709,17 @@ class basic_json | |||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     JSON_HEDLEY_WARN_UNUSED_RESULT | ||||
|     static basic_json binary_array(binary_t&& init) | ||||
|     static basic_json binary(const typename binary_t::container_type& init, std::uint8_t subtype) | ||||
|     { | ||||
|         auto res = basic_json(); | ||||
|         res.m_type = value_t::binary; | ||||
|         res.m_value = binary_t(init, subtype); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     /// @copydoc binary(const typename binary_t::container_type&)
 | ||||
|     JSON_HEDLEY_WARN_UNUSED_RESULT | ||||
|     static basic_json binary(typename binary_t::container_type&& init) | ||||
|     { | ||||
|         auto res = basic_json(); | ||||
|         res.m_type = value_t::binary; | ||||
|  | @ -1748,12 +1727,13 @@ class basic_json | |||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|     /// @copydoc binary(const typename binary_t::container_type&, std::uint8_t)
 | ||||
|     JSON_HEDLEY_WARN_UNUSED_RESULT | ||||
|     static basic_json binary_array(binary_t&& init, std::uint8_t subtype) | ||||
|     static basic_json binary(typename binary_t::container_type&& init, std::uint8_t subtype) | ||||
|     { | ||||
|         auto res = basic_json(); | ||||
|         res.m_type = value_t::binary; | ||||
|         res.m_value = internal_binary_t(std::move(init), subtype); | ||||
|         res.m_value = binary_t(std::move(init), subtype); | ||||
|         return res; | ||||
|     } | ||||
| 
 | ||||
|  | @ -2257,16 +2237,15 @@ class basic_json | |||
|     possible values: `strict` (throws and exception in case a decoding error | ||||
|     occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), | ||||
|     and `ignore` (ignore invalid UTF-8 sequences during serialization). | ||||
|     @param[in] serialize_binary Whether or not to allow serialization of binary | ||||
|     types to JSON.  Because binary types are non-standard, this will produce | ||||
|     non-conformant JSON, and is disabled by default.  This flag is primarily | ||||
|     useful for debugging.  Will output the binary value as a list of 8-bit | ||||
|     numbers prefixed by "b" (e.g. "bindata" = b[3, 0, 42, 255]). | ||||
| 
 | ||||
|     @return string containing the serialization of the JSON value | ||||
| 
 | ||||
|     @throw type_error.316 if a string stored inside the JSON value is not | ||||
|                           UTF-8 encoded | ||||
|                           UTF-8 encoded and @a error_handler is set to strict | ||||
| 
 | ||||
|     @note Binary values are serialized as object containing two keys: | ||||
|       - "bytes": an array of bytes as integers | ||||
|       - "subtype": the subtype as integer or "null" if the binary has no subtype | ||||
| 
 | ||||
|     @complexity Linear. | ||||
| 
 | ||||
|  | @ -2281,24 +2260,24 @@ class basic_json | |||
| 
 | ||||
|     @since version 1.0.0; indentation character @a indent_char, option | ||||
|            @a ensure_ascii and exceptions added in version 3.0.0; error | ||||
|            handlers added in version 3.4.0. | ||||
|            handlers added in version 3.4.0; serialization of binary values added | ||||
|            in version 3.8.0. | ||||
|     */ | ||||
|     string_t dump(const int indent = -1, | ||||
|                   const char indent_char = ' ', | ||||
|                   const bool ensure_ascii = false, | ||||
|                   const error_handler_t error_handler = error_handler_t::strict, | ||||
|                   const bool serialize_binary = false) const | ||||
|                   const error_handler_t error_handler = error_handler_t::strict) const | ||||
|     { | ||||
|         string_t result; | ||||
|         serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler); | ||||
| 
 | ||||
|         if (indent >= 0) | ||||
|         { | ||||
|             s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent), 0, serialize_binary); | ||||
|             s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent)); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             s.dump(*this, false, ensure_ascii, 0, 0, serialize_binary); | ||||
|             s.dump(*this, false, ensure_ascii, 0); | ||||
|         } | ||||
| 
 | ||||
|         return result; | ||||
|  | @ -2805,7 +2784,7 @@ class basic_json | |||
|     /// get a pointer to the value (binary)
 | ||||
|     binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept | ||||
|     { | ||||
|         return is_binary() ? reinterpret_cast<binary_t*>(m_value.binary) : nullptr; | ||||
|         return is_binary() ? m_value.binary : nullptr; | ||||
|     } | ||||
| 
 | ||||
|     /// get a pointer to the value (binary)
 | ||||
|  | @ -2814,18 +2793,6 @@ class basic_json | |||
|         return is_binary() ? m_value.binary : nullptr; | ||||
|     } | ||||
| 
 | ||||
|     /// get a pointer to the value (binary)
 | ||||
|     internal_binary_t* get_impl_ptr(internal_binary_t* /*unused*/) noexcept | ||||
|     { | ||||
|         return is_binary() ? m_value.binary : nullptr; | ||||
|     } | ||||
| 
 | ||||
|     /// get a pointer to the value (binary)
 | ||||
|     constexpr const internal_binary_t* get_impl_ptr(const internal_binary_t* /*unused*/) const noexcept | ||||
|     { | ||||
|         return is_binary() ? m_value.binary : nullptr; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief helper function to implement get_ref() | ||||
| 
 | ||||
|  | @ -3251,6 +3218,36 @@ class basic_json | |||
|         return get<ValueType>(); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @return reference to the binary value | ||||
| 
 | ||||
|     @throw type_error.302 if the value is not binary | ||||
| 
 | ||||
|     @sa @ref is_binary() to check if the value is binary | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     binary_t& get_binary() | ||||
|     { | ||||
|         if (not is_binary()) | ||||
|         { | ||||
|             JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); | ||||
|         } | ||||
| 
 | ||||
|         return *get_ptr<binary_t*>(); | ||||
|     } | ||||
| 
 | ||||
|     /// @copydoc get_binary()
 | ||||
|     const binary_t& get_binary() const | ||||
|     { | ||||
|         if (not is_binary()) | ||||
|         { | ||||
|             JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); | ||||
|         } | ||||
| 
 | ||||
|         return *get_ptr<const binary_t*>(); | ||||
|     } | ||||
| 
 | ||||
|     /// @}
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -3873,120 +3870,6 @@ class basic_json | |||
|         return value(ptr, string_t(default_value)); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief return the binary subtype | ||||
| 
 | ||||
|     Returns the numerical subtype of the JSON value, if the JSON value is of | ||||
|     type "binary", and it has a subtype.  If it does not have a subtype (or the | ||||
|     object is not of type binary) this function will return size_t(-1) as a | ||||
|     sentinel value. | ||||
| 
 | ||||
|     @return the numerical subtype of the binary JSON value | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref set_subtype() -- sets the binary subtype | ||||
|     @sa @ref clear_subtype() -- clears the binary subtype | ||||
|     @sa @ref has_subtype() -- returns whether or not the binary value has a | ||||
|     subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     std::size_t get_subtype() const noexcept | ||||
|     { | ||||
|         if (is_binary() and m_value.binary->has_subtype) | ||||
|         { | ||||
|             return m_value.binary->subtype; | ||||
|         } | ||||
| 
 | ||||
|         return std::size_t(-1); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief sets the binary subtype | ||||
| 
 | ||||
|     Sets the binary subtype of the JSON value, also flags a binary JSON value as | ||||
|     having a subtype, which has implications for serialization to msgpack (will | ||||
|     prefer ext file formats over bin).  If the JSON value is not a binary value, | ||||
|     this function does nothing. | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref get_subtype() -- return the binary subtype | ||||
|     @sa @ref clear_subtype() -- clears the binary subtype | ||||
|     @sa @ref has_subtype() -- returns whether or not the binary value has a | ||||
|     subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
| 
 | ||||
|     void set_subtype(std::uint8_t subtype) noexcept | ||||
|     { | ||||
|         if (is_binary()) | ||||
|         { | ||||
|             m_value.binary->has_subtype = true; | ||||
|             m_value.binary->subtype = subtype; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief clears the binary subtype | ||||
| 
 | ||||
|     Clears the binary subtype of the JSON value, also flags a binary JSON value | ||||
|     as not having a subtype, which has implications for serialization to msgpack | ||||
|     (will prefer bin file formats over ext).  If the JSON value is not a binary | ||||
|     value, this function does nothing. | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref get_subtype() -- return the binary subtype | ||||
|     @sa @ref set_subtype() -- sets the binary subtype | ||||
|     @sa @ref has_subtype() -- returns whether or not the binary value has a | ||||
|     subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     void clear_subtype() noexcept | ||||
|     { | ||||
|         if (is_binary()) | ||||
|         { | ||||
|             m_value.binary->has_subtype = false; | ||||
|             m_value.binary->subtype = 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief return whether or not the binary subtype has a value | ||||
| 
 | ||||
|     Returns whether or not the binary subtype has a value. | ||||
| 
 | ||||
|     @return whether or not the binary subtype has a value. | ||||
| 
 | ||||
|     @complexity Constant. | ||||
| 
 | ||||
|     @exceptionsafety No-throw guarantee: this member function never throws | ||||
|     exceptions. | ||||
| 
 | ||||
|     @sa @ref get_subtype() -- return the binary subtype | ||||
|     @sa @ref set_subtype() -- sets the binary subtype | ||||
|     @sa @ref clear_subtype() -- clears the binary subtype | ||||
| 
 | ||||
|     @since version 3.8.0 | ||||
|     */ | ||||
|     bool has_subtype() const noexcept | ||||
|     { | ||||
|         return is_binary() and m_value.binary->has_subtype; | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief access the first element | ||||
| 
 | ||||
|  | @ -4156,7 +4039,7 @@ class basic_json | |||
|                 } | ||||
|                 else if (is_binary()) | ||||
|                 { | ||||
|                     AllocatorType<internal_binary_t> alloc; | ||||
|                     AllocatorType<binary_t> alloc; | ||||
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary); | ||||
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1); | ||||
|                     m_value.binary = nullptr; | ||||
|  | @ -4270,7 +4153,7 @@ class basic_json | |||
|                 } | ||||
|                 else if (is_binary()) | ||||
|                 { | ||||
|                     AllocatorType<internal_binary_t> alloc; | ||||
|                     AllocatorType<binary_t> alloc; | ||||
|                     std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.binary); | ||||
|                     std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.binary, 1); | ||||
|                     m_value.binary = nullptr; | ||||
|  | @ -6110,6 +5993,20 @@ class basic_json | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// @copydoc swap(binary_t)
 | ||||
|     void swap(typename binary_t::container_type& other) | ||||
|     { | ||||
|         // swap only works for strings
 | ||||
|         if (JSON_HEDLEY_LIKELY(is_binary())) | ||||
|         { | ||||
|             std::swap(*(m_value.binary), other); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()))); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// @}
 | ||||
| 
 | ||||
|   public: | ||||
|  | @ -7065,7 +6962,8 @@ class basic_json | |||
|     number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19 | ||||
|     number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A | ||||
|     number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B | ||||
|     number_float    | *any value*                                | Double-Precision Float             | 0xFB | ||||
|     number_float    | *any value representable by a float*       | Single-Precision Float             | 0xFA | ||||
|     number_float    | *any value NOT representable by a float*   | Double-Precision Float             | 0xFB | ||||
|     string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77 | ||||
|     string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78 | ||||
|     string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79 | ||||
|  | @ -7107,7 +7005,7 @@ class basic_json | |||
|           - expected conversions (0xD5..0xD7) | ||||
|           - simple values (0xE0..0xF3, 0xF8) | ||||
|           - undefined (0xF7) | ||||
|           - half and single-precision floats (0xF9-0xFA) | ||||
|           - half-precision floats (0xF9) | ||||
|           - break (0xFF) | ||||
| 
 | ||||
|     @param[in] j  JSON value to serialize | ||||
|  | @ -7125,7 +7023,8 @@ class basic_json | |||
|     @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the | ||||
|              related UBJSON format | ||||
| 
 | ||||
|     @since version 2.0.9 | ||||
|     @since version 2.0.9; compact representation of floating-point numbers | ||||
|            since version 3.8.0 | ||||
|     */ | ||||
|     static std::vector<uint8_t> to_cbor(const basic_json& j) | ||||
|     { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue