18 #include <daw/algorithms/daw_algorithm_copy.h>
19 #include <daw/algorithms/daw_algorithm_copy_n.h>
20 #include <daw/daw_data_end.h>
21 #include <daw/daw_likely.h>
24 #include <daw/stdinc/data_access.h>
25 #include <daw/stdinc/range_access.h>
26 #include <type_traits>
30 namespace json_details {
31 [[nodiscard]]
static inline constexpr UInt8
32 to_nibble(
unsigned char chr ) {
33 int const b =
static_cast<int>( chr );
34 int const maskLetter = ( (
'9' - b ) >> 31 );
35 int const maskSmall = ( (
'Z' - b ) >> 31 );
36 int const offset =
'0' + ( maskLetter & int(
'A' -
'0' - 10 ) ) +
37 ( maskSmall &
int(
'a' -
'A' ) );
38 auto const result =
static_cast<unsigned>( b - offset );
39 return to_uint8( result );
42 template<
bool is_unchecked_input>
44 [[nodiscard]]
static inline constexpr UInt16
45 byte_from_nibbles(
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( 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>
60 DAW_ATTRIB_RET_NONNULL [[nodiscard]]
static constexpr
char *decode_utf16(
61 ParseState &parse_state,
char *it ) {
62 constexpr
bool is_unchecked_input = ParseState::is_unchecked_input;
64 ErrorReason::UnexpectedEndOfData, parse_state );
65 char const *first = parse_state.first;
67 UInt32 cp = to_uint32( byte_from_nibbles<is_unchecked_input>( first ) )
69 cp |= byte_from_nibbles<is_unchecked_input>( first );
71 *it++ =
static_cast<char>(
static_cast<unsigned char>( cp ) );
72 parse_state.first = first;
77 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
78 cp = ( cp - 0xD800U ) * 0x400U;
81 ( parse_state.last - first >= 5 ) and *first ==
'u',
82 ErrorReason::InvalidUTFEscape,
86 to_uint32( byte_from_nibbles<is_unchecked_input>( first ) ) << 8U;
87 trailing |= byte_from_nibbles<is_unchecked_input>( first );
93 if( cp >= 0x10000U ) {
95 char const enc3 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
97 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
99 u32toC( ( ( cp >> 12U ) & 0b0011'1111U ) | 0b1000'0000U );
100 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111'0000U );
105 parse_state.first = first;
111 char const enc2 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
113 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
114 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110'0000U );
118 parse_state.first = first;
124 char const enc1 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
125 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100'0000U );
128 parse_state.first = first;
132 template<
typename ParseState,
typename Appender>
133 static constexpr
void decode_utf16( ParseState &parse_state,
135 constexpr
bool is_unchecked_input = ParseState::is_unchecked_input;
136 char const *first = parse_state.first;
138 UInt32 cp = to_uint32( byte_from_nibbles<is_unchecked_input>( first ) )
140 cp |= byte_from_nibbles<is_unchecked_input>( first );
143 parse_state.first = first;
146 if( 0xD800U <= cp and cp <= 0xDBFFU ) {
147 cp = ( cp - 0xD800U ) * 0x400U;
153 to_uint32( byte_from_nibbles<is_unchecked_input>( first ) ) << 8U;
154 trailing |= byte_from_nibbles<is_unchecked_input>( first );
160 if( cp >= 0x10000U ) {
162 char const enc3 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
164 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
166 u32toC( ( ( cp >> 12U ) & 0b0011'1111U ) | 0b1000'0000U );
167 char const enc0 = u32toC( ( cp >> 18U ) | 0b1111'0000U );
172 parse_state.first = first;
177 char const enc2 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
179 u32toC( ( ( cp >> 6U ) & 0b0011'1111U ) | 0b1000'0000U );
180 char const enc0 = u32toC( ( cp >> 12U ) | 0b1110'0000U );
184 parse_state.first = first;
189 char const enc1 = u32toC( ( cp & 0b0011'1111U ) | 0b1000'0000U );
190 char const enc0 = u32toC( ( cp >> 6U ) | 0b1100'0000U );
193 parse_state.first = first;
196 namespace parse_tokens {
197 inline constexpr
char const escape_quotes[] =
"\\\"";
202 template<
bool AllowHighEight,
typename JsonMember,
bool KnownBounds,
204 [[nodiscard]]
static constexpr
auto
205 parse_string_known_stdstring( ParseState &parse_state ) {
206 using string_type = json_base_type_t<JsonMember>;
208 string_type( std::size( parse_state ) + 1,
'\0',
209 parse_state.template get_allocator_for<char>( ) );
210 char *it = std::data( result );
212 bool const has_quote = parse_state.front( ) ==
'"';
214 parse_state.remove_prefix( );
217 if(
auto const first_slash =
218 static_cast<std::ptrdiff_t
>( parse_state.counter ) - 1;
220 it = daw::algorithm::copy_n( parse_state.first, it,
221 static_cast<std::size_t
>( first_slash ) )
223 parse_state.first += first_slash;
225 constexpr
auto pred =
227 if constexpr( ParseState::is_unchecked_input ) {
228 return DAW_LIKELY( r.front( ) !=
'"' );
230 return DAW_LIKELY( r.has_more( ) ) and ( r.front( ) !=
'"' );
234 while( pred( parse_state ) ) {
236 char const *first = parse_state.first;
237 char const *
const last = parse_state.last;
238 if constexpr( std::is_same_v<
typename ParseState::exec_tag_t,
242 ErrorReason::UnexpectedEndOfData,
244 while( *first !=
'"' and *first !=
'\\' ) {
247 ErrorReason::UnexpectedEndOfData,
252 mem_move_to_next_of<( ParseState::is_unchecked_input or
254 '"',
'\\'>( ParseState::exec_tag, first,
258 static_cast<std::ptrdiff_t
>( result.size( ) ) -
259 std::distance( result.data( ), it ) >=
260 std::distance( parse_state.first, first ),
261 ErrorReason::UnexpectedEndOfData );
262 it = daw::algorithm::copy( parse_state.first, first, it );
263 parse_state.first = first;
265 if( parse_state.front( ) ==
'\\' ) {
266 parse_state.remove_prefix( );
268 ErrorReason::InvalidUTFCodepoint,
270 switch( parse_state.front( ) ) {
273 parse_state.remove_prefix( );
277 parse_state.remove_prefix( );
281 parse_state.remove_prefix( );
285 parse_state.remove_prefix( );
289 parse_state.remove_prefix( );
292 it = decode_utf16( parse_state, it );
297 *it++ = parse_state.front( );
298 parse_state.remove_prefix( );
301 if constexpr( not AllowHighEight ) {
303 ( not parse_state.is_space_unchecked( ) ) &
304 (
static_cast<unsigned char>( parse_state.front( ) ) <=
306 ErrorReason::InvalidStringHighASCII, parse_state );
308 *it++ = parse_state.front( );
309 parse_state.remove_prefix( );
313 parse_state.is_quotes_checked( ),
314 ErrorReason::InvalidString, parse_state );
317 ErrorReason::UnexpectedEndOfData, parse_state );
320 static_cast<std::size_t
>( std::distance( std::data( result ), it ) );
322 ErrorReason::InvalidString, parse_state );
324 if constexpr( std::is_convertible_v<string_type,
325 json_result_t<JsonMember>> ) {
328 using constructor_t = json_constructor_t<JsonMember>;
329 construct_value<json_result_t<JsonMember>, constructor_t>(
330 parse_state, std::data( result ), daw::data_end( result ) );
#define daw_json_assert_weak(Bool,...)
Assert that Bool is true when in Checked Input mode If false pass rest of args to daw_json_error.
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
#define DAW_JSON_CPP23_STATIC_CALL_OP
This is in addition to the parse policy. Always do a full name match instead of sometimes relying on ...
std::bool_constant< is_zero_terminated_string_v< T > > is_zero_terminated_string
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.