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 ErrorReason::InvalidUTFEscape,
81 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
82 cp = ( cp - 0xD800U ) * 0x400U;
85 ErrorReason::InvalidUTFEscape,
89 ( parse_state.last - first >= 5 ) and *first ==
'u',
90 ErrorReason::InvalidUTFEscape,
95 byte_from_nibbles<ParseState::is_unchecked_input>( first ) )
98 byte_from_nibbles<ParseState::is_unchecked_input>( first );
100 0xDC00U <= trailing and trailing <= 0xDFFFU,
101 ErrorReason::InvalidUTFEscape,
108 if( cp >= 0x10000U ) {
110 char const enc3 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
112 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
114 u32toC( ( ( cp >> 12U ) & 0b0011'1111U ) | 0b1000'0000U );
115 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111'0000U );
120 parse_state.first = input_pointer( parse_state.first, first.get( ) );
126 char const enc2 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
128 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
129 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110'0000U );
133 parse_state.first = input_pointer( parse_state.first, first.get( ) );
139 char const enc1 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
140 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100'0000U );
143 parse_state.first = input_pointer( parse_state.first, first.get( ) );
147 template<
typename ParseState,
typename Appender>
148 static constexpr void decode_utf16( ParseState &parse_state,
150 auto first = daw::not_null<char const *>( parse_state.first );
154 byte_from_nibbles<ParseState::is_unchecked_input>( first ) )
156 cp |= byte_from_nibbles<ParseState::is_unchecked_input>( first );
159 parse_state.first = input_pointer( parse_state.first, first.get( ) );
163 ErrorReason::InvalidUTFEscape,
165 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
166 cp = ( cp - 0xD800U ) * 0x400U;
169 ErrorReason::InvalidUTFEscape,
173 *first ==
'u', ErrorReason::InvalidUTFEscape, parse_state );
177 byte_from_nibbles<ParseState::is_unchecked_input>( first ) )
180 byte_from_nibbles<ParseState::is_unchecked_input>( first );
182 0xDC00U <= trailing and trailing <= 0xDFFFU,
183 ErrorReason::InvalidUTFEscape,
190 if( cp >= 0x10000U ) {
192 char const enc3 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
194 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
196 u32toC( ( ( cp >> 12U ) & 0b0011'1111U ) | 0b1000'0000U );
197 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111'0000U );
202 parse_state.first = input_pointer( parse_state.first, first.get( ) );
207 char const enc2 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
209 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
210 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110'0000U );
214 parse_state.first = input_pointer( parse_state.first, first.get( ) );
219 char const enc1 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
220 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100'0000U );
223 parse_state.first = input_pointer( parse_state.first, first.get( ) );
226 namespace parse_tokens {
227 inline constexpr char escape_quotes[] =
"\\\"";
232 template<
bool AllowHighEight,
typename JsonMember,
bool KnownBounds,
234 [[nodiscard]]
constexpr json_result_t<JsonMember>
235 parse_string_known_stdstring( ParseState &parse_state ) {
236 DAW_CPP23_STATIC_LOCAL
constexpr bool is_insitu =
237 JsonMember::expected_type == JsonParseTypes::StringInsitu;
240 not is_insitu or ParseState::allow_string_mutation,
241 "In-situ strings can only be parsed from writable input documents" );
242 static_assert( not is_insitu or
243 std::is_same_v<typename ParseState::iterator, char *>,
244 "In-situ strings require a mutable character buffer" );
246 bool const has_quote = parse_state.front( ) ==
'"';
248 parse_state.remove_prefix( );
251 using string_type = json_base_type_t<JsonMember>;
253 std::conditional_t<is_insitu, daw::span<char>, string_type>;
254 result_t result = [&] {
255 if constexpr( is_insitu ) {
256 return daw::span( std::data( parse_state ),
257 std::size( parse_state ) );
260 std::size( parse_state ) + 1U +
261 static_cast<unsigned>( has_quote ),
263 parse_state.template get_allocator_for<char>( ) );
266 daw::not_null<char *> it = std::data( result );
268 if(
auto const first_slash =
269 static_cast<std::ptrdiff_t
>( parse_state.counter ) - 1;
271 if constexpr( is_insitu ) {
275 daw::algorithm::copy_n( parse_state.first,
277 static_cast<std::size_t
>( first_slash ) )
280 parse_state.first += first_slash;
283 DAW_CPP23_STATIC_LOCAL
constexpr auto in_json_string =
285 if constexpr( KnownBounds or not ParseState::is_unchecked_input ) {
286 if( not DAW_LIKELY( r.has_more( ) ) ) {
290 return DAW_LIKELY( r.front( ) !=
'"' );
293 while( in_json_string( parse_state ) ) {
295 daw::not_null<char const *> first = parse_state.first;
296 daw::not_null<char const *>
const last = parse_state.last;
298 if( not json_details::use_constexpr_exec_mode<
299 typename ParseState::exec_tag_t>( ) ) {
300 first = mem_move_to_next_of<
301 ( not KnownBounds and
302 ( ParseState::is_unchecked_input or
303 ParseState::is_zero_terminated_string ) ),
304 typename ParseState::exec_tag_t,
306 '\\'>( first, last );
308 while( first < last and *first !=
'"' and *first !=
'\\' ) {
312 ErrorReason::UnexpectedEndOfData,
316 auto const run_size = first.get( ) - parse_state.first;
318 static_cast<std::ptrdiff_t
>( result.size( ) ) -
319 ( it.get( ) - result.data( ) ) >=
321 ErrorReason::UnexpectedEndOfData );
323 if( it.get( ) == parse_state.first ) {
326 it = daw::algorithm::copy(
327 parse_state.first, first.get( ), it.get( ) );
330 input_pointer( parse_state.first, first.get( ) );
332 if( parse_state.front( ) ==
'\\' ) {
333 parse_state.remove_prefix( );
335 ErrorReason::InvalidUTFCodepoint,
337 switch( parse_state.front( ) ) {
340 parse_state.remove_prefix( );
344 parse_state.remove_prefix( );
348 parse_state.remove_prefix( );
352 parse_state.remove_prefix( );
356 parse_state.remove_prefix( );
359 it = decode_utf16( parse_state, it );
364 *it++ = parse_state.front( );
365 parse_state.remove_prefix( );
372 ErrorReason::InvalidString,
374 *it++ = parse_state.front( );
375 parse_state.remove_prefix( );
379 parse_state.is_quotes_checked( ),
380 ErrorReason::InvalidString,
384 ErrorReason::UnexpectedEndOfData,
387 auto const sz =
static_cast<std::size_t
>(
388 std::distance( std::data( result ), it.get( ) ) );
390 std::size( result ) >= sz, ErrorReason::InvalidString, parse_state );
392 if constexpr( is_insitu ) {
395 while( it != ( parse_state.last + 1 ) ) {
399 result = result.subspan( 0, sz );
404 if constexpr( not is_insitu and
405 std::is_convertible_v<result_t,
406 json_result_t<JsonMember>> ) {
409 using constructor_t = json_constructor_t<JsonMember>;
410 return construct_value<json_result_t<JsonMember>, constructor_t>(
411 parse_state, std::data( result ), std::size( result ) );