10 namespace daw::json::json_details {
11 [[nodiscard]]
inline constexpr UInt8 to_nibble(
unsigned char chr ) {
12 int const b =
static_cast<int>( chr );
13 int const maskLetter = ( (
'9' - b ) >> 31 );
14 int const maskSmall = ( (
'Z' - b ) >> 31 );
15 int const offset =
'0' + ( maskLetter & int(
'A' -
'0' - 10 ) ) +
16 ( maskSmall &
int(
'a' -
'A' ) );
17 auto const result =
static_cast<unsigned>( b - offset );
18 return to_uint8( result );
21 template<
bool is_unchecked_input>
22 [[nodiscard]]
inline constexpr UInt16
23 byte_from_nibbles(
char const *&first ) {
24 auto const n0 = to_nibble(
static_cast<unsigned char>( *first++ ) );
25 auto const n1 = to_nibble(
static_cast<unsigned char>( *first++ ) );
26 if constexpr( is_unchecked_input ) {
29 return to_uint16( ( n0 << 4U ) | n1 );
32 constexpr
char u32toC( UInt32 value ) {
33 return static_cast<char>(
static_cast<unsigned char>( value ) );
36 template<
typename Range>
37 [[nodiscard]]
static constexpr
char *decode_utf16( Range &rng,
char *it ) {
38 constexpr
bool is_unchecked_input = Range::is_unchecked_input;
39 char const *first = rng.first;
41 UInt32 cp = to_uint32( byte_from_nibbles<is_unchecked_input>( first ) )
43 cp |= byte_from_nibbles<is_unchecked_input>( first );
45 *it++ =
static_cast<char>(
static_cast<unsigned char>( cp ) );
51 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
52 cp = ( cp - 0xD800U ) * 0x400U;
58 to_uint32( byte_from_nibbles<is_unchecked_input>( first ) ) << 8U;
59 trailing |= byte_from_nibbles<is_unchecked_input>( first );
65 if( cp >= 0x10000U ) {
67 char const enc3 = u32toC( ( cp & 0b0011
'1111U ) | 0b1000'0000U );
69 u32toC( ( ( cp >> 6U ) & 0b0011
'1111U ) | 0b1000'0000U );
71 u32toC( ( ( cp >> 12U ) & 0b0011
'1111U ) | 0b1000'0000U );
72 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111
'0000U );
80 //******************************
83 char const enc2 = u32toC( ( cp & 0b0011'1111U ) | 0b1000
'0000U );
85 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000
'0000U );
86 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110'0000U );
96 char const enc1 = u32toC( ( cp & 0b0011
'1111U ) | 0b1000'0000U );
97 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100
'0000U );
104 template<typename Range, typename Appender>
105 static constexpr void decode_utf16( Range &rng, Appender &app ) {
106 constexpr bool is_unchecked_input = Range::is_unchecked_input;
107 char const *first = rng.first;
109 UInt32 cp = to_uint32( byte_from_nibbles<is_unchecked_input>( first ) )
111 cp |= byte_from_nibbles<is_unchecked_input>( first );
117 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
118 cp = ( cp - 0xD800U ) * 0x400U;
120 daw_json_assert_weak( *first == 'u
', ErrorReason::InvalidUTFEscape, rng );
123 to_uint32( byte_from_nibbles<is_unchecked_input>( first ) ) << 8U;
124 trailing |= byte_from_nibbles<is_unchecked_input>( first );
130 if( cp >= 0x10000U ) {
132 char const enc3 = u32toC( ( cp & 0b0011'1111U ) | 0b1000
'0000U );
134 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000
'0000U );
136 u32toC( ( ( cp >> 12U ) & 0b0011'1111U ) | 0b1000
'0000U );
137 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111'0000U );
147 char const enc2 = u32toC( ( cp & 0b0011
'1111U ) | 0b1000'0000U );
149 u32toC( ( ( cp >> 6U ) & 0b0011
'1111U ) | 0b1000'0000U );
150 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110
'0000U );
159 char const enc1 = u32toC( ( cp & 0b0011'1111U ) | 0b1000
'0000U );
160 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100'0000U );
166 namespace parse_tokens {
167 inline constexpr
char const escape_quotes[] =
"\\\"";
172 template<
bool AllowHighEight,
typename JsonMember,
bool KnownBounds,
174 [[nodiscard, maybe_unused]] constexpr json_result<JsonMember>
175 parse_string_known_stdstring( Range &rng ) {
177 std::basic_string<char, std::char_traits<char>,
178 typename Range::template allocator_type_as<char>>;
180 string_type( rng.size( ),
'\0', rng.template get_allocator_for<char>( ) );
182 char *it = result.data( );
184 bool const has_quote = rng.front( ) ==
'"';
186 rng.remove_prefix( );
189 if(
auto const first_slash =
static_cast<std::ptrdiff_t
>( rng.counter ) - 1;
191 it = std::copy_n( rng.first, first_slash, it );
192 rng.first += first_slash;
195 ( Range::is_unchecked_input or
DAW_JSON_LIKELY( rng.has_more( ) ) ) and
196 rng.front( ) !=
'"' ) {
198 char const *first = rng.first;
199 char const *
const last = rng.last;
200 if constexpr( std::is_same_v<
typename Range::exec_tag_t,
201 constexpr_exec_tag> ) {
202 while( not key_table<'"', '\\'>[*first] ) {
205 ErrorReason::UnexpectedEndOfData, rng );
208 first = mem_move_to_next_of<Range::is_unchecked_input,
'"',
'\\'>(
209 Range::exec_tag, first, last );
211 it = std::copy( rng.first, first, it );
214 if( rng.front( ) ==
'\\' ) {
216 ErrorReason::InvalidUTFCodepoint, rng );
217 rng.remove_prefix( );
218 switch( rng.front( ) ) {
221 rng.remove_prefix( );
225 rng.remove_prefix( );
229 rng.remove_prefix( );
233 rng.remove_prefix( );
237 rng.remove_prefix( );
240 it = decode_utf16( rng, it );
245 *it++ = rng.front( );
246 rng.remove_prefix( );
249 if constexpr( not AllowHighEight ) {
251 ( not rng.is_space_unchecked( ) ) &
252 (
static_cast<unsigned char>( rng.front( ) ) <= 0x7FU ),
253 ErrorReason::InvalidStringHighASCII, rng );
255 *it++ = rng.front( );
256 rng.remove_prefix( );
260 ErrorReason::InvalidString, rng );
263 ErrorReason::UnexpectedEndOfData, rng );
266 static_cast<std::size_t
>( std::distance( result.data( ), it ) );
270 if constexpr( std::is_convertible_v<string_type,
271 json_result<JsonMember>> ) {
274 using constructor_t =
typename JsonMember::constructor_t;
275 construct_value<json_result<JsonMember>>(
276 constructor_t{ }, rng, result.data( ),
277 result.data( ) +
static_cast<std::ptrdiff_t
>( result.size( ) ) );