24 namespace json_details::string_quote {
25 template<std::
size_t N,
char c>
26 constexpr UInt8 test_at_byte( UInt64 b ) {
27 auto const lhs = b & ( daw::UInt64{0xFF} << ( N * 8U ) );
28 using rhs = daw::constant<to_uint64( static_cast<unsigned char>( c ) )
30 return to_uint8( not( lhs - rhs::value ) );
33 template<std::
size_t N,
char c>
34 DAW_ATTRIB_INLINE
constexpr UInt8 test_at_byte( UInt32 b ) {
35 auto const lhs = b & ( daw::UInt32{0xFF} << ( N * 8U ) );
36 using rhs = daw::constant<to_uint32( static_cast<unsigned char>( c ) )
38 return to_uint8( not( lhs - rhs::value ) );
41 constexpr void skip_to_first8( daw::not_null<char const *> &first,
42 daw::not_null<char const *>
const last ) {
43 bool keep_going = last - first >= 8;
45 auto buff = daw::to_uint64_buffer( first.get( ) );
46 auto const q7 = test_at_byte<7U,
'"'>( buff );
47 auto const q6 = test_at_byte<6U,
'"'>( buff );
48 auto const q5 = test_at_byte<5U,
'"'>( buff );
49 auto const q4 = test_at_byte<4U,
'"'>( buff );
50 auto const q3 = test_at_byte<3U,
'"'>( buff );
51 auto const q2 = test_at_byte<2U,
'"'>( buff );
52 auto const q1 = test_at_byte<1U,
'"'>( buff );
53 auto const q0 = test_at_byte<0U,
'"'>( buff );
54 auto const s7 = test_at_byte<7U, '\\'>( buff );
55 auto const s6 = test_at_byte<6U, '\\'>( buff );
56 auto const s5 = test_at_byte<5U, '\\'>( buff );
57 auto const s4 = test_at_byte<4U, '\\'>( buff );
58 auto const s3 = test_at_byte<3U, '\\'>( buff );
59 auto const s2 = test_at_byte<2U, '\\'>( buff );
60 auto const s1 = test_at_byte<1U, '\\'>( buff );
61 auto const s0 = test_at_byte<0U, '\\'>( buff );
63 keep_going = not( q0 | q1 | q2 | q3 | q4 | q5 | q6 | q7 | s0 | s1 |
64 s2 | s3 | s4 | s5 | s6 | s7 );
65 keep_going = keep_going &
static_cast<bool>( last - first >= 16 );
66 first +=
static_cast<int>( keep_going ) * 8;
68 first -= *( first - 1 ) ==
'\\' ? 1 : 0;
71 constexpr void skip_to_first4( daw::not_null<char const *> &first,
72 daw::not_null<char const *>
const last ) {
73 bool keep_going = last - first >= 4;
76 auto buff = daw::to_uint32_buffer( first.get( ) );
77 auto const q3 = test_at_byte<3U,
'"'>( buff );
78 auto const q2 = test_at_byte<2U,
'"'>( buff );
79 auto const q1 = test_at_byte<1U,
'"'>( buff );
80 auto const q0 = test_at_byte<0U,
'"'>( buff );
81 auto const s3 = test_at_byte<3U, '\\'>( buff );
82 auto const s2 = test_at_byte<2U, '\\'>( buff );
83 auto const s1 = test_at_byte<1U, '\\'>( buff );
84 auto const s0 = test_at_byte<0U, '\\'>( buff );
85 keep_going = not( q0 | q1 | q2 | q3 | s0 | s1 | s2 | s3 );
86 keep_going = keep_going &
static_cast<bool>( last - first >= 8 );
87 first +=
static_cast<int>( keep_going ) * 4;
89 first -= *( first - 1 ) ==
'\\' ? 1 : 0;
92 namespace string_quote_parser {
93 template<
typename ParseState>
94 [[nodiscard]]
static constexpr std::size_t
95 parse_nq_uncheck( ParseState &parse_state ) {
96 std::ptrdiff_t need_slow_path = -1;
98 daw::not_null<char const *>( daw::never_null, parse_state.first );
100 daw::not_null<char const *>( daw::never_null, parse_state.last );
104 if( not json_details::use_constexpr_exec_mode<
105 typename ParseState::exec_tag_t>( ) ) {
107 mem_skip_until_end_of_string<
true,
108 typename ParseState::exec_tag_t>(
109 first, last, need_slow_path );
112 auto const sz = last - first;
114 skip_to_first8( first, last );
115 }
else if( sz >= 4 ) {
116 skip_to_first4( first, last );
119 while( *first !=
'"' ) {
121 return daw::nsc_and( c !=
'"', c !=
'\\' );
125 if( *first ==
'\\' ) {
126 if( need_slow_path < 0 ) {
127 need_slow_path = first - parse_state.first;
135 if constexpr( std::is_same_v<char const *, typename ParseState::iterator> ) {
136 parse_state.first = first;
138 parse_state.first += first.get( ) - parse_state.first;
140 return static_cast<std::size_t
>( need_slow_path );
143 template<
typename ParseState>
144 [[nodiscard]]
static constexpr std::size_t
145 parse_nq_check( ParseState &parse_state ) {
147 std::ptrdiff_t need_slow_path = -1;
148 auto first = daw::not_null<char const *>( parse_state.first );
150 daw::not_null<char const *>( parse_state.class_last );
154 if( not ParseState::exclude_special_escapes and
155 not json_details::use_constexpr_exec_mode<
156 typename ParseState::exec_tag_t>( ) ) {
158 mem_skip_until_end_of_string<
false,
159 typename ParseState::exec_tag_t>(
160 first, last, need_slow_path );
162 if constexpr( not ParseState::exclude_special_escapes ) {
164 daw::not_null<char const *>( parse_state.last );
166 skip_to_first8( first, l );
167 }
else if( last - first >= 4 ) {
168 skip_to_first4( first, l );
171 if constexpr( ParseState::is_zero_terminated_string ) {
172 if constexpr( ParseState::exclude_special_escapes ) {
173 while( *first !=
'\0' ) {
176 ErrorReason::InvalidString,
180 ErrorReason::InvalidString,
182 if( need_slow_path < 0 ) {
183 need_slow_path = first - parse_state.first;
201 }
else if( c ==
'"' ) {
207 while( daw::nsc_and( *first != 0, *first !=
'"' ) ) {
209 *first != 0, *first !=
'"', *first !=
'\\' ) ) {
213 if( daw::nsc_and( *first != 0, *first ==
'\\' ) ) {
214 if( need_slow_path < 0 ) {
215 need_slow_path = first - parse_state.first;
224 if constexpr( ParseState::exclude_special_escapes ) {
225 while( first < last ) {
228 ErrorReason::InvalidString,
232 ErrorReason::InvalidString,
234 if( need_slow_path < 0 ) {
235 need_slow_path = first - parse_state.first;
253 }
else if( c ==
'"' ) {
259 while( first < last and *first !=
'"' ) {
260 while( first < last and
261 daw::nsc_and( *first !=
'"', *first !=
'\\' ) ) {
265 if( first < last and *first ==
'\\' ) {
266 if( need_slow_path < 0 ) {
267 need_slow_path = first - parse_state.first;
277 if constexpr( ParseState::is_zero_terminated_string ) {
279 *first ==
'"', ErrorReason::InvalidString, parse_state );
282 ErrorReason::InvalidString,
285 if constexpr( std::is_same_v<char const *, typename ParseState::iterator> ) {
286 parse_state.first = first;
288 parse_state.first += first.get( ) - parse_state.first;
290 return static_cast<std::size_t
>( need_slow_path );
293 template<
typename ParseState>
294 [[nodiscard]] DAW_ATTRIB_FLATTEN
static constexpr std::size_t
295 parse_nq( ParseState &parse_state ) {
296 if constexpr( ParseState::is_unchecked_input ) {
297 return parse_nq_uncheck( parse_state );
299 return parse_nq_check( parse_state );