32 namespace json_details {
33 [[nodiscard]]
static constexpr UInt8 to_nibble(
unsigned char chr ) {
34 int const b =
static_cast<int>( chr );
35 int const maskLetter = ( (
'9' - b ) >> 31 );
36 int const maskSmall = ( (
'Z' - b ) >> 31 );
37 int const offset =
'0' + ( maskLetter & int(
'A' -
'0' - 10 ) ) +
38 ( maskSmall &
int(
'a' -
'A' ) );
39 auto const result =
static_cast<unsigned>( b - offset );
40 return to_uint8( result );
43 template<
bool is_unchecked_input>
44 [[nodiscard]]
static constexpr UInt16
45 byte_from_nibbles( daw::not_null<char const *> &first ) {
46 auto const n0 = to_nibble(
static_cast<unsigned char>( *first++ ) );
47 auto const n1 = to_nibble(
static_cast<unsigned char>( *first++ ) );
48 if constexpr( not is_unchecked_input ) {
51 return to_uint16( ( n0 << 4U ) | n1 );
54 static constexpr char u32toC( UInt32 value ) {
55 return static_cast<char>(
static_cast<unsigned char>( value ) );
58 template<
typename ParseState>
59 [[nodiscard]]
static constexpr daw::not_null<char *>
60 decode_utf16( ParseState &parse_state, daw::not_null<char *> it ) {
62 ErrorReason::UnexpectedEndOfData,
64 auto first = daw::not_null<char const *>( parse_state.first );
68 byte_from_nibbles<ParseState::is_unchecked_input>( first ) )
70 cp |= byte_from_nibbles<ParseState::is_unchecked_input>( first );
72 *it++ =
static_cast<char>(
static_cast<unsigned char>( cp ) );
73 parse_state.first = input_pointer( parse_state.first, first.get( ) );
79 cp < 0xDC00U or cp > 0xDFFFU, ErrorReason::InvalidUTFEscape,
81 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
82 cp = ( cp - 0xD800U ) * 0x400U;
84 *first ==
'\\', ErrorReason::InvalidUTFEscape,
88 ( parse_state.last - first >= 5 ) and *first ==
'u',
89 ErrorReason::InvalidUTFEscape,
94 byte_from_nibbles<ParseState::is_unchecked_input>( first ) )
97 byte_from_nibbles<ParseState::is_unchecked_input>( first );
99 0xDC00U <= trailing and trailing <= 0xDFFFU,
100 ErrorReason::InvalidUTFEscape,
107 if( cp >= 0x10000U ) {
109 char const enc3 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
111 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
113 u32toC( ( ( cp >> 12U ) & 0b0011'1111U ) | 0b1000'0000U );
114 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111'0000U );
119 parse_state.first = input_pointer( parse_state.first, first.get( ) );
125 char const enc2 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
127 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
128 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110'0000U );
132 parse_state.first = input_pointer( parse_state.first, first.get( ) );
138 char const enc1 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
139 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100'0000U );
142 parse_state.first = input_pointer( parse_state.first, first.get( ) );
146 template<
typename ParseState,
typename Appender>
147 static constexpr void decode_utf16( ParseState &parse_state,
149 auto first = daw::not_null<char const *>( parse_state.first );
153 byte_from_nibbles<ParseState::is_unchecked_input>( first ) )
155 cp |= byte_from_nibbles<ParseState::is_unchecked_input>( first );
158 parse_state.first = input_pointer( parse_state.first, first.get( ) );
162 cp < 0xDC00U or cp > 0xDFFFU, ErrorReason::InvalidUTFEscape,
164 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
165 cp = ( cp - 0xD800U ) * 0x400U;
167 *first ==
'\\', ErrorReason::InvalidUTFEscape,
171 *first ==
'u', ErrorReason::InvalidUTFEscape, parse_state );
175 byte_from_nibbles<ParseState::is_unchecked_input>( first ) )
178 byte_from_nibbles<ParseState::is_unchecked_input>( first );
180 0xDC00U <= trailing and trailing <= 0xDFFFU,
181 ErrorReason::InvalidUTFEscape,
188 if( cp >= 0x10000U ) {
190 char const enc3 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
192 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
194 u32toC( ( ( cp >> 12U ) & 0b0011'1111U ) | 0b1000'0000U );
195 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111'0000U );
200 parse_state.first = input_pointer( parse_state.first, first.get( ) );
205 char const enc2 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
207 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
208 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110'0000U );
212 parse_state.first = input_pointer( parse_state.first, first.get( ) );
217 char const enc1 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
218 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100'0000U );
221 parse_state.first = input_pointer( parse_state.first, first.get( ) );
224 namespace parse_tokens {
225 inline constexpr char escape_quotes[] =
"\\\"";
230 template<
bool AllowHighEight,
typename JsonMember,
bool KnownBounds,
232 [[nodiscard]]
constexpr json_result_t<JsonMember>
233 parse_string_known_stdstring( ParseState &parse_state ) {
234 DAW_CPP23_STATIC_LOCAL
constexpr bool is_insitu =
235 JsonMember::expected_type == JsonParseTypes::StringInsitu;
238 not is_insitu or ParseState::allow_string_mutation,
239 "In-situ strings can only be parsed from writable input documents" );
240 static_assert( not is_insitu or
241 std::is_same_v<typename ParseState::iterator, char *>,
242 "In-situ strings require a mutable character buffer" );
244 bool const has_quote = parse_state.front( ) ==
'"';
246 parse_state.remove_prefix( );
249 using string_type = json_base_type_t<JsonMember>;
251 std::conditional_t<is_insitu, daw::span<char>, string_type>;
252 result_t result = [&] {
253 if constexpr( is_insitu ) {
254 return daw::span( std::data( parse_state ),
255 std::size( parse_state ) );
258 std::size( parse_state ) + 1U +
259 static_cast<unsigned>( has_quote ),
261 parse_state.template get_allocator_for<char>( ) );
264 daw::not_null<char *> it = std::data( result );
266 if(
auto const first_slash =
267 static_cast<std::ptrdiff_t
>( parse_state.counter ) - 1;
269 if constexpr( is_insitu ) {
273 daw::algorithm::copy_n( parse_state.first,
275 static_cast<std::size_t
>( first_slash ) )
278 parse_state.first += first_slash;
281 DAW_CPP23_STATIC_LOCAL
constexpr auto in_json_string =
283 if constexpr( KnownBounds or not ParseState::is_unchecked_input ) {
284 if( not DAW_LIKELY( r.has_more( ) ) ) {
288 return DAW_LIKELY( r.front( ) !=
'"' );
291 while( in_json_string( parse_state ) ) {
293 daw::not_null<char const *> first = parse_state.first;
294 daw::not_null<char const *>
const last = parse_state.last;
296 if( not json_details::use_constexpr_exec_mode<
297 typename ParseState::exec_tag_t>( ) ) {
298 first = mem_move_to_next_of<
299 ( not KnownBounds and
300 ( ParseState::is_unchecked_input or
301 ParseState::is_zero_terminated_string ) ),
302 typename ParseState::exec_tag_t,
304 '\\'>( first, last );
306 while( first < last and *first !=
'"' and *first !=
'\\' ) {
310 ErrorReason::UnexpectedEndOfData,
314 auto const run_size = first.get( ) - parse_state.first;
316 static_cast<std::ptrdiff_t
>( result.size( ) ) -
317 ( it.get( ) - result.data( ) ) >=
319 ErrorReason::UnexpectedEndOfData );
321 if( it.get( ) == parse_state.first ) {
324 it = daw::algorithm::copy(
325 parse_state.first, first.get( ), it.get( ) );
328 input_pointer( parse_state.first, first.get( ) );
330 if( parse_state.front( ) ==
'\\' ) {
331 parse_state.remove_prefix( );
333 ErrorReason::InvalidUTFCodepoint,
335 switch( parse_state.front( ) ) {
338 parse_state.remove_prefix( );
342 parse_state.remove_prefix( );
346 parse_state.remove_prefix( );
350 parse_state.remove_prefix( );
354 parse_state.remove_prefix( );
357 it = decode_utf16( parse_state, it );
362 *it++ = parse_state.front( );
363 parse_state.remove_prefix( );
371 *it++ = parse_state.front( );
372 parse_state.remove_prefix( );
376 parse_state.is_quotes_checked( ),
377 ErrorReason::InvalidString,
381 ErrorReason::UnexpectedEndOfData,
384 auto const sz =
static_cast<std::size_t
>(
385 std::distance( std::data( result ), it.get( ) ) );
387 std::size( result ) >= sz, ErrorReason::InvalidString, parse_state );
389 if constexpr( is_insitu ) {
392 while( it != ( parse_state.last + 1 ) ) {
396 result = result.subspan( 0, sz );
401 if constexpr( not is_insitu and
402 std::is_convertible_v<result_t,
403 json_result_t<JsonMember>> ) {
406 using constructor_t = json_constructor_t<JsonMember>;
407 return construct_value<json_result_t<JsonMember>, constructor_t>(
408 parse_state, std::data( result ), std::size( result ) );