2018-01-10 17:18:31 +08:00
# pragma once
2017-08-14 23:55:06 +08:00
2017-08-15 01:28:01 +08:00
# include <algorithm> // reverse
# include <array> // array
# include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
# include <cstring> // memcpy
# include <limits> // numeric_limits
2017-08-14 23:55:06 +08:00
2018-01-29 18:21:11 +08:00
# include <nlohmann/detail/input/binary_reader.hpp>
# include <nlohmann/detail/output/output_adapters.hpp>
2017-08-14 23:55:06 +08:00
namespace nlohmann
{
namespace detail
{
///////////////////
// binary writer //
///////////////////
/*!
@ brief serialization to CBOR and MessagePack values
*/
template < typename BasicJsonType , typename CharType >
class binary_writer
{
public :
/*!
@ brief create a binary writer
@ param [ in ] adapter output adapter to write to
*/
explicit binary_writer ( output_adapter_t < CharType > adapter ) : oa ( adapter )
{
assert ( oa ) ;
}
/*!
@ brief [ in ] j JSON value to serialize
*/
void write_cbor ( const BasicJsonType & j )
{
switch ( j . type ( ) )
{
case value_t : : null :
{
oa - > write_character ( static_cast < CharType > ( 0xF6 ) ) ;
break ;
}
case value_t : : boolean :
{
oa - > write_character ( j . m_value . boolean
? static_cast < CharType > ( 0xF5 )
: static_cast < CharType > ( 0xF4 ) ) ;
break ;
}
case value_t : : number_integer :
{
if ( j . m_value . number_integer > = 0 )
{
// CBOR does not differentiate between positive signed
// integers and unsigned integers. Therefore, we used the
// code from the value_t::number_unsigned case here.
if ( j . m_value . number_integer < = 0x17 )
{
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x18 ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x19 ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x1A ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_integer ) ) ;
}
else
{
oa - > write_character ( static_cast < CharType > ( 0x1B ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_integer ) ) ;
}
}
else
{
// The conversions below encode the sign in the first
// byte, and the value is converted to a positive number.
const auto positive_number = - 1 - j . m_value . number_integer ;
if ( j . m_value . number_integer > = - 24 )
{
write_number ( static_cast < uint8_t > ( 0x20 + positive_number ) ) ;
}
else if ( positive_number < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x38 ) ) ;
write_number ( static_cast < uint8_t > ( positive_number ) ) ;
}
else if ( positive_number < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x39 ) ) ;
write_number ( static_cast < uint16_t > ( positive_number ) ) ;
}
else if ( positive_number < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x3A ) ) ;
write_number ( static_cast < uint32_t > ( positive_number ) ) ;
}
else
{
oa - > write_character ( static_cast < CharType > ( 0x3B ) ) ;
write_number ( static_cast < uint64_t > ( positive_number ) ) ;
}
}
break ;
}
case value_t : : number_unsigned :
{
if ( j . m_value . number_unsigned < = 0x17 )
{
write_number ( static_cast < uint8_t > ( j . m_value . number_unsigned ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x18 ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_unsigned ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x19 ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_unsigned ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
oa - > write_character ( static_cast < CharType > ( 0x1A ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_unsigned ) ) ;
}
else
{
oa - > write_character ( static_cast < CharType > ( 0x1B ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_unsigned ) ) ;
}
break ;
}
2018-03-29 00:20:55 +08:00
case value_t : : number_float :
2017-08-14 23:55:06 +08:00
{
2018-03-29 01:37:21 +08:00
oa - > write_character ( get_cbor_float_prefix ( j . m_value . number_float ) ) ;
2017-08-14 23:55:06 +08:00
write_number ( j . m_value . number_float ) ;
break ;
}
case value_t : : string :
{
// step 1: write control byte and the string length
const auto N = j . m_value . string - > size ( ) ;
if ( N < = 0x17 )
{
write_number ( static_cast < uint8_t > ( 0x60 + N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x78 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x79 ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x7A ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// LCOV_EXCL_START
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x7B ) ) ;
write_number ( static_cast < uint64_t > ( N ) ) ;
}
// LCOV_EXCL_STOP
// step 2: write the string
oa - > write_characters (
reinterpret_cast < const CharType * > ( j . m_value . string - > c_str ( ) ) ,
j . m_value . string - > size ( ) ) ;
break ;
}
case value_t : : array :
{
// step 1: write control byte and the array size
const auto N = j . m_value . array - > size ( ) ;
if ( N < = 0x17 )
{
write_number ( static_cast < uint8_t > ( 0x80 + N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x98 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x99 ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x9A ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// LCOV_EXCL_START
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0x9B ) ) ;
write_number ( static_cast < uint64_t > ( N ) ) ;
}
// LCOV_EXCL_STOP
// step 2: write each element
for ( const auto & el : * j . m_value . array )
{
write_cbor ( el ) ;
}
break ;
}
case value_t : : object :
{
// step 1: write control byte and the object size
const auto N = j . m_value . object - > size ( ) ;
if ( N < = 0x17 )
{
write_number ( static_cast < uint8_t > ( 0xA0 + N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0xB8 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0xB9 ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0xBA ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// LCOV_EXCL_START
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
oa - > write_character ( static_cast < CharType > ( 0xBB ) ) ;
write_number ( static_cast < uint64_t > ( N ) ) ;
}
// LCOV_EXCL_STOP
// step 2: write each element
for ( const auto & el : * j . m_value . object )
{
write_cbor ( el . first ) ;
write_cbor ( el . second ) ;
}
break ;
}
default :
break ;
}
}
/*!
@ brief [ in ] j JSON value to serialize
*/
void write_msgpack ( const BasicJsonType & j )
{
switch ( j . type ( ) )
{
case value_t : : null : // nil
{
oa - > write_character ( static_cast < CharType > ( 0xC0 ) ) ;
break ;
}
case value_t : : boolean : // true and false
{
oa - > write_character ( j . m_value . boolean
? static_cast < CharType > ( 0xC3 )
: static_cast < CharType > ( 0xC2 ) ) ;
break ;
}
case value_t : : number_integer :
{
if ( j . m_value . number_integer > = 0 )
{
// MessagePack does not differentiate between positive
// signed integers and unsigned integers. Therefore, we used
// the code from the value_t::number_unsigned case here.
if ( j . m_value . number_unsigned < 128 )
{
// positive fixnum
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
// uint 8
oa - > write_character ( static_cast < CharType > ( 0xCC ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
// uint 16
oa - > write_character ( static_cast < CharType > ( 0xCD ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
// uint 32
oa - > write_character ( static_cast < CharType > ( 0xCE ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
{
// uint 64
oa - > write_character ( static_cast < CharType > ( 0xCF ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_integer ) ) ;
}
}
else
{
if ( j . m_value . number_integer > = - 32 )
{
// negative fixnum
write_number ( static_cast < int8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int8_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
{
// int 8
oa - > write_character ( static_cast < CharType > ( 0xD0 ) ) ;
write_number ( static_cast < int8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int16_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
{
// int 16
oa - > write_character ( static_cast < CharType > ( 0xD1 ) ) ;
write_number ( static_cast < int16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int32_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
{
// int 32
oa - > write_character ( static_cast < CharType > ( 0xD2 ) ) ;
write_number ( static_cast < int32_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_integer > = ( std : : numeric_limits < int64_t > : : min ) ( ) and
j . m_value . number_integer < = ( std : : numeric_limits < int64_t > : : max ) ( ) )
{
// int 64
oa - > write_character ( static_cast < CharType > ( 0xD3 ) ) ;
write_number ( static_cast < int64_t > ( j . m_value . number_integer ) ) ;
}
}
break ;
}
case value_t : : number_unsigned :
{
if ( j . m_value . number_unsigned < 128 )
{
// positive fixnum
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
{
// uint 8
oa - > write_character ( static_cast < CharType > ( 0xCC ) ) ;
write_number ( static_cast < uint8_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
{
// uint 16
oa - > write_character ( static_cast < CharType > ( 0xCD ) ) ;
write_number ( static_cast < uint16_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
{
// uint 32
oa - > write_character ( static_cast < CharType > ( 0xCE ) ) ;
write_number ( static_cast < uint32_t > ( j . m_value . number_integer ) ) ;
}
else if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint64_t > : : max ) ( ) )
{
// uint 64
oa - > write_character ( static_cast < CharType > ( 0xCF ) ) ;
write_number ( static_cast < uint64_t > ( j . m_value . number_integer ) ) ;
}
break ;
}
2018-03-29 00:20:55 +08:00
case value_t : : number_float :
2017-08-14 23:55:06 +08:00
{
2018-03-29 01:37:21 +08:00
oa - > write_character ( get_msgpack_float_prefix ( j . m_value . number_float ) ) ;
2017-08-14 23:55:06 +08:00
write_number ( j . m_value . number_float ) ;
break ;
}
case value_t : : string :
{
// step 1: write control byte and the string length
const auto N = j . m_value . string - > size ( ) ;
if ( N < = 31 )
{
// fixstr
write_number ( static_cast < uint8_t > ( 0xA0 | N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
// str 8
oa - > write_character ( static_cast < CharType > ( 0xD9 ) ) ;
write_number ( static_cast < uint8_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
// str 16
oa - > write_character ( static_cast < CharType > ( 0xDA ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
// str 32
oa - > write_character ( static_cast < CharType > ( 0xDB ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// step 2: write the string
oa - > write_characters (
reinterpret_cast < const CharType * > ( j . m_value . string - > c_str ( ) ) ,
j . m_value . string - > size ( ) ) ;
break ;
}
case value_t : : array :
{
// step 1: write control byte and the array size
const auto N = j . m_value . array - > size ( ) ;
if ( N < = 15 )
{
// fixarray
write_number ( static_cast < uint8_t > ( 0x90 | N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
// array 16
oa - > write_character ( static_cast < CharType > ( 0xDC ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
// array 32
oa - > write_character ( static_cast < CharType > ( 0xDD ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// step 2: write each element
for ( const auto & el : * j . m_value . array )
{
write_msgpack ( el ) ;
}
break ;
}
case value_t : : object :
{
// step 1: write control byte and the object size
const auto N = j . m_value . object - > size ( ) ;
if ( N < = 15 )
{
// fixmap
write_number ( static_cast < uint8_t > ( 0x80 | ( N & 0xF ) ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint16_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
// map 16
oa - > write_character ( static_cast < CharType > ( 0xDE ) ) ;
write_number ( static_cast < uint16_t > ( N ) ) ;
}
2018-01-14 17:27:30 +08:00
else if ( N < = ( std : : numeric_limits < uint32_t > : : max ) ( ) )
2017-08-14 23:55:06 +08:00
{
// map 32
oa - > write_character ( static_cast < CharType > ( 0xDF ) ) ;
write_number ( static_cast < uint32_t > ( N ) ) ;
}
// step 2: write each element
for ( const auto & el : * j . m_value . object )
{
write_msgpack ( el . first ) ;
write_msgpack ( el . second ) ;
}
break ;
}
default :
break ;
}
}
2018-01-14 17:27:30 +08:00
/*!
@ param [ in ] j JSON value to serialize
@ param [ in ] use_count whether to use ' # ' prefixes ( optimized format )
@ param [ in ] use_type whether to use ' $ ' prefixes ( optimized format )
@ param [ in ] add_prefix whether prefixes need to be used for this value
*/
void write_ubjson ( const BasicJsonType & j , const bool use_count ,
const bool use_type , const bool add_prefix = true )
{
switch ( j . type ( ) )
{
case value_t : : null :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' Z ' ) ) ;
}
break ;
}
case value_t : : boolean :
{
if ( add_prefix )
2018-10-08 00:39:18 +08:00
{
2018-01-14 17:27:30 +08:00
oa - > write_character ( j . m_value . boolean
? static_cast < CharType > ( ' T ' )
: static_cast < CharType > ( ' F ' ) ) ;
2018-10-08 00:39:18 +08:00
}
2018-01-14 17:27:30 +08:00
break ;
}
case value_t : : number_integer :
{
write_number_with_ubjson_prefix ( j . m_value . number_integer , add_prefix ) ;
break ;
}
case value_t : : number_unsigned :
{
write_number_with_ubjson_prefix ( j . m_value . number_unsigned , add_prefix ) ;
break ;
}
case value_t : : number_float :
{
write_number_with_ubjson_prefix ( j . m_value . number_float , add_prefix ) ;
break ;
}
case value_t : : string :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' S ' ) ) ;
}
write_number_with_ubjson_prefix ( j . m_value . string - > size ( ) , true ) ;
oa - > write_characters (
reinterpret_cast < const CharType * > ( j . m_value . string - > c_str ( ) ) ,
j . m_value . string - > size ( ) ) ;
break ;
}
case value_t : : array :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' [ ' ) ) ;
}
bool prefix_required = true ;
if ( use_type and not j . m_value . array - > empty ( ) )
{
assert ( use_count ) ;
2018-03-29 01:37:21 +08:00
const CharType first_prefix = ubjson_prefix ( j . front ( ) ) ;
2018-01-14 17:27:30 +08:00
const bool same_prefix = std : : all_of ( j . begin ( ) + 1 , j . end ( ) ,
[ this , first_prefix ] ( const BasicJsonType & v )
{
return ubjson_prefix ( v ) = = first_prefix ;
} ) ;
if ( same_prefix )
{
prefix_required = false ;
oa - > write_character ( static_cast < CharType > ( ' $ ' ) ) ;
2018-03-29 01:37:21 +08:00
oa - > write_character ( first_prefix ) ;
2018-01-14 17:27:30 +08:00
}
}
if ( use_count )
{
oa - > write_character ( static_cast < CharType > ( ' # ' ) ) ;
write_number_with_ubjson_prefix ( j . m_value . array - > size ( ) , true ) ;
}
for ( const auto & el : * j . m_value . array )
{
write_ubjson ( el , use_count , use_type , prefix_required ) ;
}
if ( not use_count )
{
oa - > write_character ( static_cast < CharType > ( ' ] ' ) ) ;
}
break ;
}
case value_t : : object :
{
if ( add_prefix )
{
oa - > write_character ( static_cast < CharType > ( ' { ' ) ) ;
}
bool prefix_required = true ;
if ( use_type and not j . m_value . object - > empty ( ) )
{
assert ( use_count ) ;
2018-03-29 01:37:21 +08:00
const CharType first_prefix = ubjson_prefix ( j . front ( ) ) ;
2018-01-14 17:27:30 +08:00
const bool same_prefix = std : : all_of ( j . begin ( ) , j . end ( ) ,
[ this , first_prefix ] ( const BasicJsonType & v )
{
return ubjson_prefix ( v ) = = first_prefix ;
} ) ;
if ( same_prefix )
{
prefix_required = false ;
oa - > write_character ( static_cast < CharType > ( ' $ ' ) ) ;
2018-03-29 01:37:21 +08:00
oa - > write_character ( first_prefix ) ;
2018-01-14 17:27:30 +08:00
}
}
if ( use_count )
{
oa - > write_character ( static_cast < CharType > ( ' # ' ) ) ;
write_number_with_ubjson_prefix ( j . m_value . object - > size ( ) , true ) ;
}
for ( const auto & el : * j . m_value . object )
{
write_number_with_ubjson_prefix ( el . first . size ( ) , true ) ;
oa - > write_characters (
reinterpret_cast < const CharType * > ( el . first . c_str ( ) ) ,
el . first . size ( ) ) ;
write_ubjson ( el . second , use_count , use_type , prefix_required ) ;
}
if ( not use_count )
{
oa - > write_character ( static_cast < CharType > ( ' } ' ) ) ;
}
break ;
}
default :
break ;
}
}
2018-10-07 23:57:13 +08:00
/*!
@ return The size of a BSON document entry header , including the id marker and the entry name size ( and its null - terminator ) .
*/
static std : : size_t calc_bson_entry_header_size ( const typename BasicJsonType : : string_t & name )
2018-09-15 09:08:50 +08:00
{
2018-10-18 03:47:01 +08:00
if ( name . find ( static_cast < typename BasicJsonType : : string_t : : value_type > ( 0 ) ) ! = BasicJsonType : : string_t : : npos )
2018-10-17 02:42:00 +08:00
{
JSON_THROW ( out_of_range : : create ( 409 , " BSON key cannot contain code point U+0000 " ) ) ;
}
2018-10-07 23:57:13 +08:00
return /*id*/ 1ul + name . size ( ) + /*zero-terminator*/ 1u ;
2018-09-15 09:08:50 +08:00
}
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes the given @ a element_type and @ a name to the output adapter
*/
void write_bson_entry_header ( const typename BasicJsonType : : string_t & name , std : : uint8_t element_type )
2018-09-15 09:23:54 +08:00
{
2018-10-07 23:57:13 +08:00
oa - > write_character ( static_cast < CharType > ( element_type ) ) ; // boolean
2018-09-15 09:23:54 +08:00
oa - > write_characters (
reinterpret_cast < const CharType * > ( name . c_str ( ) ) ,
name . size ( ) + 1u ) ;
}
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and boolean value @ a value
*/
void write_bson_boolean ( const typename BasicJsonType : : string_t & name , const bool value )
2018-09-15 17:33:24 +08:00
{
2018-10-07 23:57:13 +08:00
write_bson_entry_header ( name , 0x08 ) ;
oa - > write_character ( value ? static_cast < CharType > ( 0x01 ) : static_cast < CharType > ( 0x00 ) ) ;
}
2018-09-15 17:33:24 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and double value @ a value
*/
void write_bson_double ( const typename BasicJsonType : : string_t & name , const double value )
{
write_bson_entry_header ( name , 0x01 ) ;
write_number < double , true > ( value ) ;
}
2018-09-15 17:33:24 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ return The size of the BSON - encoded string in @ a value
*/
static std : : size_t calc_bson_string_size ( const typename BasicJsonType : : string_t & value )
{
return sizeof ( std : : int32_t ) + value . size ( ) + 1ul ;
2018-09-15 17:33:24 +08:00
}
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and string value @ a value
*/
void write_bson_string ( const typename BasicJsonType : : string_t & name , const typename BasicJsonType : : string_t & value )
2018-09-15 17:38:26 +08:00
{
2018-10-07 23:57:13 +08:00
write_bson_entry_header ( name , 0x02 ) ;
write_number < std : : int32_t , true > ( static_cast < std : : int32_t > ( value . size ( ) + 1ul ) ) ;
2018-09-15 17:38:26 +08:00
oa - > write_characters (
2018-10-07 23:57:13 +08:00
reinterpret_cast < const CharType * > ( value . c_str ( ) ) ,
value . size ( ) + 1 ) ;
}
2018-09-15 17:38:26 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and null value
*/
void write_bson_null ( const typename BasicJsonType : : string_t & name )
{
write_bson_entry_header ( name , 0x0A ) ;
2018-09-15 17:38:26 +08:00
}
2018-10-07 23:57:13 +08:00
/*!
@ return The size of the BSON - encoded integer @ a value
*/
static std : : size_t calc_bson_integer_size ( const std : : int64_t value )
2018-09-15 17:54:17 +08:00
{
2018-10-07 23:57:13 +08:00
if ( ( std : : numeric_limits < std : : int32_t > : : min ) ( ) < = value and value < = ( std : : numeric_limits < std : : int32_t > : : max ) ( ) )
2018-09-15 18:00:53 +08:00
{
2018-10-07 23:57:13 +08:00
return sizeof ( std : : int32_t ) ;
2018-09-15 18:11:21 +08:00
}
else
{
2018-10-07 23:57:13 +08:00
return sizeof ( std : : int64_t ) ;
2018-09-15 18:11:21 +08:00
}
}
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and integer @ a value
*/
void write_bson_integer ( const typename BasicJsonType : : string_t & name , const std : : int64_t value )
2018-09-15 18:11:21 +08:00
{
2018-10-07 23:57:13 +08:00
if ( ( std : : numeric_limits < std : : int32_t > : : min ) ( ) < = value and value < = ( std : : numeric_limits < std : : int32_t > : : max ) ( ) )
2018-09-15 18:11:21 +08:00
{
2018-10-07 23:57:13 +08:00
write_bson_entry_header ( name , 0x10 ) ; // int32
write_number < std : : int32_t , true > ( static_cast < std : : int32_t > ( value ) ) ;
2018-09-15 18:00:53 +08:00
}
else
{
2018-10-07 23:57:13 +08:00
write_bson_entry_header ( name , 0x12 ) ; // int64
write_number < std : : int64_t , true > ( static_cast < std : : int64_t > ( value ) ) ;
}
}
2018-09-15 18:00:53 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ return The size of the BSON - encoded unsigned integer in @ a j
*/
static std : : size_t calc_bson_unsigned_size ( const std : : uint64_t value )
{
if ( value < = static_cast < std : : uint64_t > ( ( std : : numeric_limits < std : : int32_t > : : max ) ( ) ) )
{
return sizeof ( std : : int32_t ) ;
}
else
{
return sizeof ( std : : int64_t ) ;
2018-09-15 18:00:53 +08:00
}
2018-09-15 17:54:17 +08:00
}
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and unsigned @ a value
*/
void write_bson_unsigned ( const typename BasicJsonType : : string_t & name , const std : : uint64_t value )
2018-09-15 19:03:42 +08:00
{
2018-10-07 23:57:13 +08:00
if ( value < = static_cast < std : : uint64_t > ( ( std : : numeric_limits < std : : int32_t > : : max ) ( ) ) )
{
write_bson_entry_header ( name , 0x10 ) ; // int32
write_number < std : : int32_t , true > ( static_cast < std : : int32_t > ( value ) ) ;
}
2018-10-17 01:13:07 +08:00
else if ( value < = static_cast < std : : uint64_t > ( ( std : : numeric_limits < std : : int64_t > : : max ) ( ) ) )
2018-10-07 23:57:13 +08:00
{
write_bson_entry_header ( name , 0x12 ) ; // int64
write_number < std : : int64_t , true > ( static_cast < std : : int64_t > ( value ) ) ;
}
2018-10-17 01:13:07 +08:00
else
{
JSON_THROW ( out_of_range : : create ( 407 , " number overflow serializing " + std : : to_string ( value ) ) ) ;
}
2018-10-07 23:57:13 +08:00
}
2018-09-15 19:03:42 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and object @ a value
*/
void write_bson_object_entry ( const typename BasicJsonType : : string_t & name , const typename BasicJsonType : : object_t & value )
{
write_bson_entry_header ( name , 0x03 ) ; // object
write_bson_object ( value ) ;
2018-09-15 19:03:42 +08:00
}
2018-10-07 23:57:13 +08:00
/*!
@ return The size of the BSON - encoded array @ a value
*/
static std : : size_t calc_bson_array_size ( const typename BasicJsonType : : array_t & value )
2018-09-15 19:54:08 +08:00
{
2018-10-07 23:57:13 +08:00
std : : size_t embedded_document_size = 0ul ;
2018-09-15 19:54:08 +08:00
2018-10-07 23:57:13 +08:00
for ( const auto & el : value )
{
embedded_document_size + = calc_bson_element_size ( " " , el ) ;
}
2018-09-15 19:54:08 +08:00
2018-10-07 23:57:13 +08:00
return sizeof ( std : : int32_t ) + embedded_document_size + 1ul ;
}
2018-09-15 19:54:08 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ brief Writes a BSON element with key @ a name and array @ a value
*/
void write_bson_array ( const typename BasicJsonType : : string_t & name , const typename BasicJsonType : : array_t & value )
{
write_bson_entry_header ( name , 0x04 ) ; // array
write_number < std : : int32_t , true > ( calc_bson_array_size ( value ) ) ;
for ( const auto & el : value )
2018-09-15 19:54:08 +08:00
{
2018-10-07 23:57:13 +08:00
write_bson_element ( " " , el ) ;
2018-09-15 19:54:08 +08:00
}
oa - > write_character ( static_cast < CharType > ( 0x00 ) ) ;
2018-10-07 23:57:13 +08:00
}
2018-09-15 19:54:08 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ brief Calculates the size necessary to serialize the JSON value @ a j with its @ a name
@ return The calculated size for the BSON document entry for @ a j with the given @ a name .
*/
static std : : size_t calc_bson_element_size ( const typename BasicJsonType : : string_t & name , const BasicJsonType & j )
{
const auto header_size = calc_bson_entry_header_size ( name ) ;
switch ( j . type ( ) )
{
// LCOV_EXCL_START
default :
assert ( false ) ;
return 0ul ;
// LCOV_EXCL_STOP
2018-10-08 02:08:05 +08:00
case value_t : : discarded :
return 0ul ;
2018-10-07 23:57:13 +08:00
case value_t : : object :
return header_size + calc_bson_object_size ( * j . m_value . object ) ;
case value_t : : array :
return header_size + calc_bson_array_size ( * j . m_value . array ) ;
case value_t : : boolean :
return header_size + 1ul ;
case value_t : : number_float :
return header_size + 8ul ;
case value_t : : number_integer :
return header_size + calc_bson_integer_size ( j . m_value . number_integer ) ;
case value_t : : number_unsigned :
return header_size + calc_bson_unsigned_size ( j . m_value . number_unsigned ) ;
case value_t : : string :
return header_size + calc_bson_string_size ( * j . m_value . string ) ;
case value_t : : null :
return header_size + 0ul ;
} ;
2018-09-15 19:54:08 +08:00
}
2018-10-07 23:57:13 +08:00
/*!
@ brief Serializes the JSON value @ a j to BSON and associates it with the key @ a name .
@ param name The name to associate with the JSON entity @ a j within the current BSON document
@ return The size of the bson entry
*/
void write_bson_element ( const typename BasicJsonType : : string_t & name , const BasicJsonType & j )
2018-09-15 09:23:54 +08:00
{
switch ( j . type ( ) )
{
2018-09-26 02:34:25 +08:00
// LCOV_EXCL_START
2018-09-15 09:23:54 +08:00
default :
2018-09-26 02:34:25 +08:00
assert ( false ) ;
2018-10-07 23:57:13 +08:00
return ;
2018-09-26 02:34:25 +08:00
// LCOV_EXCL_STOP
2018-10-08 02:08:05 +08:00
case value_t : : discarded :
return ;
2018-09-15 19:03:42 +08:00
case value_t : : object :
2018-10-07 23:57:13 +08:00
return write_bson_object_entry ( name , * j . m_value . object ) ;
2018-09-15 19:54:08 +08:00
case value_t : : array :
2018-10-07 23:57:13 +08:00
return write_bson_array ( name , * j . m_value . array ) ;
2018-09-15 09:23:54 +08:00
case value_t : : boolean :
2018-10-07 23:57:13 +08:00
return write_bson_boolean ( name , j . m_value . boolean ) ;
2018-09-15 09:23:54 +08:00
case value_t : : number_float :
2018-10-07 23:57:13 +08:00
return write_bson_double ( name , j . m_value . number_float ) ;
2018-09-15 17:54:17 +08:00
case value_t : : number_integer :
2018-10-07 23:57:13 +08:00
return write_bson_integer ( name , j . m_value . number_integer ) ;
2018-09-15 18:11:21 +08:00
case value_t : : number_unsigned :
2018-10-07 23:57:13 +08:00
return write_bson_unsigned ( name , j . m_value . number_unsigned ) ;
2018-09-15 17:33:24 +08:00
case value_t : : string :
2018-10-07 23:57:13 +08:00
return write_bson_string ( name , * j . m_value . string ) ;
2018-09-15 17:38:26 +08:00
case value_t : : null :
2018-10-07 23:57:13 +08:00
return write_bson_null ( name ) ;
2018-09-15 09:23:54 +08:00
} ;
2018-10-07 23:57:13 +08:00
}
2018-09-15 09:23:54 +08:00
2018-10-07 23:57:13 +08:00
/*!
@ brief Calculates the size of the BSON serialization of the given
JSON - object @ a j .
@ param [ in ] j JSON value to serialize
@ pre j . type ( ) = = value_t : : object
*/
static std : : size_t calc_bson_object_size ( const typename BasicJsonType : : object_t & value )
{
std : : size_t document_size = 0 ;
for ( const auto & el : value )
{
document_size + = calc_bson_element_size ( el . first , el . second ) ;
}
return sizeof ( std : : int32_t ) + document_size + 1ul ;
2018-09-15 09:23:54 +08:00
}
2018-09-15 04:58:22 +08:00
/*!
@ param [ in ] j JSON value to serialize
@ pre j . type ( ) = = value_t : : object
*/
2018-10-07 23:57:13 +08:00
void write_bson_object ( const typename BasicJsonType : : object_t & value )
2018-09-15 04:58:22 +08:00
{
2018-10-07 23:57:13 +08:00
write_number < std : : int32_t , true > ( calc_bson_object_size ( value ) ) ;
2018-09-15 09:08:50 +08:00
2018-10-07 23:57:13 +08:00
for ( const auto & el : value )
2018-09-15 09:08:50 +08:00
{
2018-10-07 23:57:13 +08:00
write_bson_element ( el . first , el . second ) ;
2018-09-15 09:08:50 +08:00
}
2018-09-15 06:43:39 +08:00
oa - > write_character ( static_cast < CharType > ( 0x00 ) ) ;
2018-09-15 04:58:22 +08:00
}
/*!
@ param [ in ] j JSON value to serialize
@ pre j . type ( ) = = value_t : : object
*/
void write_bson ( const BasicJsonType & j )
{
switch ( j . type ( ) )
{
default :
2018-10-07 13:52:12 +08:00
JSON_THROW ( type_error : : create ( 317 , " JSON value of type " + std : : to_string ( static_cast < std : : uint8_t > ( j . type ( ) ) ) + " cannot be serialized to requested format " ) ) ;
2018-09-15 04:58:22 +08:00
break ;
case value_t : : discarded :
break ;
case value_t : : object :
2018-10-07 23:57:13 +08:00
write_bson_object ( * j . m_value . object ) ;
2018-09-15 04:58:22 +08:00
break ;
}
}
2017-08-14 23:55:06 +08:00
private :
/*
@ brief write a number to output input
@ param [ in ] n number of type @ a NumberType
@ tparam NumberType the type of the number
2018-09-26 02:34:25 +08:00
@ tparam OutputIsLittleEndian Set to true if output data is
required to be little endian
2017-08-14 23:55:06 +08:00
@ note This function needs to respect the system ' s endianess , because bytes
2018-01-28 21:13:02 +08:00
in CBOR , MessagePack , and UBJSON are stored in network order ( big
endian ) and therefore need reordering on little endian systems .
2017-08-14 23:55:06 +08:00
*/
2018-09-26 02:34:25 +08:00
template < typename NumberType , bool OutputIsLittleEndian = false >
2018-01-28 21:13:02 +08:00
void write_number ( const NumberType n )
2017-08-14 23:55:06 +08:00
{
// step 1: write number to array of length NumberType
std : : array < CharType , sizeof ( NumberType ) > vec ;
std : : memcpy ( vec . data ( ) , & n , sizeof ( NumberType ) ) ;
// step 2: write array to output (with possible reordering)
2018-09-26 02:34:25 +08:00
if ( is_little_endian & & ! OutputIsLittleEndian )
2018-09-15 04:58:22 +08:00
{
// reverse byte order prior to conversion if necessary
std : : reverse ( vec . begin ( ) , vec . end ( ) ) ;
}
oa - > write_characters ( vec . data ( ) , sizeof ( NumberType ) ) ;
}
2018-03-08 05:01:44 +08:00
// UBJSON: write number (floating point)
template < typename NumberType , typename std : : enable_if <
std : : is_floating_point < NumberType > : : value , int > : : type = 0 >
void write_number_with_ubjson_prefix ( const NumberType n ,
const bool add_prefix )
{
if ( add_prefix )
{
2018-03-29 01:37:21 +08:00
oa - > write_character ( get_ubjson_float_prefix ( n ) ) ;
2018-03-08 05:01:44 +08:00
}
write_number ( n ) ;
}
// UBJSON: write number (unsigned integer)
template < typename NumberType , typename std : : enable_if <
std : : is_unsigned < NumberType > : : value , int > : : type = 0 >
2018-01-14 17:27:30 +08:00
void write_number_with_ubjson_prefix ( const NumberType n ,
const bool add_prefix )
{
2018-03-08 05:01:44 +08:00
if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int8_t > : : max ) ( ) ) )
2018-01-14 17:27:30 +08:00
{
if ( add_prefix )
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' i ' ) ) ; // int8
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < uint8_t > ( n ) ) ;
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
else if ( n < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' U ' ) ) ; // uint8
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < uint8_t > ( n ) ) ;
}
else if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int16_t > : : max ) ( ) ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' I ' ) ) ; // int16
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < int16_t > ( n ) ) ;
}
else if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int32_t > : : max ) ( ) ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' l ' ) ) ; // int32
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < int32_t > ( n ) ) ;
}
else if ( n < = static_cast < uint64_t > ( ( std : : numeric_limits < int64_t > : : max ) ( ) ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' L ' ) ) ; // int64
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < int64_t > ( n ) ) ;
2018-01-14 17:27:30 +08:00
}
else
{
2018-10-17 18:15:58 +08:00
JSON_THROW ( out_of_range : : create ( 407 , " integer number " + std : : to_string ( n ) + " cannot be represented by UBJSON as it does not fit int64 " ) ) ;
2018-03-08 05:01:44 +08:00
}
}
// UBJSON: write number (signed integer)
template < typename NumberType , typename std : : enable_if <
std : : is_signed < NumberType > : : value and
not std : : is_floating_point < NumberType > : : value , int > : : type = 0 >
void write_number_with_ubjson_prefix ( const NumberType n ,
const bool add_prefix )
{
if ( ( std : : numeric_limits < int8_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' i ' ) ) ; // int8
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < int8_t > ( n ) ) ;
}
else if ( static_cast < int64_t > ( ( std : : numeric_limits < uint8_t > : : min ) ( ) ) < = n and n < = static_cast < int64_t > ( ( std : : numeric_limits < uint8_t > : : max ) ( ) ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' U ' ) ) ; // uint8
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < uint8_t > ( n ) ) ;
}
else if ( ( std : : numeric_limits < int16_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' I ' ) ) ; // int16
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < int16_t > ( n ) ) ;
}
else if ( ( std : : numeric_limits < int32_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' l ' ) ) ; // int32
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < int32_t > ( n ) ) ;
}
else if ( ( std : : numeric_limits < int64_t > : : min ) ( ) < = n and n < = ( std : : numeric_limits < int64_t > : : max ) ( ) )
{
if ( add_prefix )
2018-01-14 17:27:30 +08:00
{
2018-03-08 05:01:44 +08:00
oa - > write_character ( static_cast < CharType > ( ' L ' ) ) ; // int64
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
write_number ( static_cast < int64_t > ( n ) ) ;
}
// LCOV_EXCL_START
else
{
2018-10-17 18:15:58 +08:00
JSON_THROW ( out_of_range : : create ( 407 , " integer number " + std : : to_string ( n ) + " cannot be represented by UBJSON as it does not fit int64 " ) ) ;
2018-01-14 17:27:30 +08:00
}
2018-03-08 05:01:44 +08:00
// LCOV_EXCL_STOP
2018-01-14 17:27:30 +08:00
}
2018-01-15 03:07:38 +08:00
/*!
@ brief determine the type prefix of container values
@ note This function does not need to be 100 % accurate when it comes to
integer limits . In case a number exceeds the limits of int64_t ,
this will be detected by a later call to function
write_number_with_ubjson_prefix . Therefore , we return ' L ' for any
value that does not fit the previous limits .
*/
2018-03-29 01:37:21 +08:00
CharType ubjson_prefix ( const BasicJsonType & j ) const noexcept
2018-01-14 17:27:30 +08:00
{
switch ( j . type ( ) )
{
case value_t : : null :
return ' Z ' ;
case value_t : : boolean :
return j . m_value . boolean ? ' T ' : ' F ' ;
case value_t : : number_integer :
{
if ( ( std : : numeric_limits < int8_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
{
return ' i ' ;
}
2018-10-08 01:07:58 +08:00
if ( ( std : : numeric_limits < uint8_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
2018-01-14 17:27:30 +08:00
{
return ' U ' ;
}
2018-10-08 01:07:58 +08:00
if ( ( std : : numeric_limits < int16_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
2018-01-14 17:27:30 +08:00
{
return ' I ' ;
}
2018-10-08 01:07:58 +08:00
if ( ( std : : numeric_limits < int32_t > : : min ) ( ) < = j . m_value . number_integer and j . m_value . number_integer < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
2018-01-14 17:27:30 +08:00
{
return ' l ' ;
}
2018-10-08 01:07:58 +08:00
// no check and assume int64_t (see note above)
return ' L ' ;
2018-01-14 17:27:30 +08:00
}
case value_t : : number_unsigned :
{
if ( j . m_value . number_unsigned < = ( std : : numeric_limits < int8_t > : : max ) ( ) )
{
return ' i ' ;
}
2018-10-08 01:07:58 +08:00
if ( j . m_value . number_unsigned < = ( std : : numeric_limits < uint8_t > : : max ) ( ) )
2018-01-14 17:27:30 +08:00
{
return ' U ' ;
}
2018-10-08 01:07:58 +08:00
if ( j . m_value . number_unsigned < = ( std : : numeric_limits < int16_t > : : max ) ( ) )
2018-01-14 17:27:30 +08:00
{
return ' I ' ;
}
2018-10-08 01:07:58 +08:00
if ( j . m_value . number_unsigned < = ( std : : numeric_limits < int32_t > : : max ) ( ) )
2018-01-14 17:27:30 +08:00
{
return ' l ' ;
}
2018-10-08 01:07:58 +08:00
// no check and assume int64_t (see note above)
return ' L ' ;
2018-01-14 17:27:30 +08:00
}
case value_t : : number_float :
2018-03-29 01:37:21 +08:00
return get_ubjson_float_prefix ( j . m_value . number_float ) ;
2018-01-14 17:27:30 +08:00
case value_t : : string :
return ' S ' ;
case value_t : : array :
return ' [ ' ;
case value_t : : object :
return ' { ' ;
2018-01-15 03:07:38 +08:00
default : // discarded values
return ' N ' ;
2018-01-14 17:27:30 +08:00
}
}
2018-10-08 00:39:18 +08:00
static constexpr CharType get_cbor_float_prefix ( float /*unused*/ )
2018-03-29 01:37:21 +08:00
{
return static_cast < CharType > ( 0xFA ) ; // Single-Precision Float
}
2018-10-08 00:39:18 +08:00
static constexpr CharType get_cbor_float_prefix ( double /*unused*/ )
2018-03-29 01:37:21 +08:00
{
return static_cast < CharType > ( 0xFB ) ; // Double-Precision Float
}
2018-10-08 00:39:18 +08:00
static constexpr CharType get_msgpack_float_prefix ( float /*unused*/ )
2018-03-29 01:37:21 +08:00
{
return static_cast < CharType > ( 0xCA ) ; // float 32
}
2018-10-08 00:39:18 +08:00
static constexpr CharType get_msgpack_float_prefix ( double /*unused*/ )
2018-03-29 01:37:21 +08:00
{
return static_cast < CharType > ( 0xCB ) ; // float 64
}
2018-10-08 00:39:18 +08:00
static constexpr CharType get_ubjson_float_prefix ( float /*unused*/ )
2018-03-29 01:37:21 +08:00
{
return ' d ' ; // float 32
}
2018-10-08 00:39:18 +08:00
static constexpr CharType get_ubjson_float_prefix ( double /*unused*/ )
2018-03-29 01:37:21 +08:00
{
return ' D ' ; // float 64
}
2017-08-14 23:55:06 +08:00
private :
/// whether we can assume little endianess
const bool is_little_endian = binary_reader < BasicJsonType > : : little_endianess ( ) ;
/// the output
output_adapter_t < CharType > oa = nullptr ;
} ;
2018-10-08 00:39:18 +08:00
} // namespace detail
} // namespace nlohmann