DAW JSON Link
daw_json_parse_string_quote.h
Go to the documentation of this file.
1// Copyright (c) Darrell Wright
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// Official repository: https://github.com/beached/daw_json_link
7//
8
9#pragma once
10
11#include "daw_json_assert.h"
13#include "version.h"
14
15#include <daw/daw_traits.h>
16#include <daw/daw_uint_buffer.h>
17
18#include <ciso646>
19#include <cstddef>
20#include <type_traits>
21
22namespace daw::json {
23 inline namespace DAW_JSON_VER {
24 namespace json_details::string_quote {
25 template<std::size_t N, char c>
26 inline constexpr UInt8 test_at_byte( UInt64 b ) {
27 auto const lhs = b & ( 0xFF_u64 << ( N * 8U ) );
28 using rhs = daw::constant<to_uint64( static_cast<unsigned char>( c ) )
29 << ( N * 8U )>;
30 return to_uint8( not( lhs - rhs::value ) );
31 }
32
33 template<std::size_t N, char c>
34 DAW_ATTRIB_INLINE inline constexpr UInt8 test_at_byte( UInt32 b ) {
35 auto const lhs = b & ( 0xFF_u32 << ( N * 8U ) );
36 using rhs = daw::constant<to_uint32( static_cast<unsigned char>( c ) )
37 << ( N * 8U )>;
38 return to_uint8( not( lhs - rhs::value ) );
39 }
40
41 template<typename CharT>
42 inline constexpr void skip_to_first8( CharT *&first, CharT *const last ) {
43 bool keep_going = last - first >= 8;
44 while( keep_going ) {
45 auto buff = daw::to_uint64_buffer( first );
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 );
62
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;
67 }
68 first -= *( first - 1 ) == '\\' ? 1 : 0;
69 }
70
71 template<typename CharT>
72 inline constexpr void skip_to_first4( CharT *&first, CharT *const last ) {
73 bool keep_going = last - first >= 4;
74 while( keep_going ) {
75 // Need to look for escapes as this is fast path
76 auto buff = daw::to_uint32_buffer( first );
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;
88 }
89 first -= *( first - 1 ) == '\\' ? 1 : 0;
90 }
91
93 template<typename ParseState>
94 [[nodiscard]] static constexpr auto parse_nq( ParseState &parse_state )
95 -> std::enable_if_t<ParseState::is_unchecked_input, std::size_t> {
96
97 using CharT = typename ParseState::CharT;
98 std::ptrdiff_t need_slow_path = -1;
99 CharT *first = parse_state.first;
100 CharT *const last = parse_state.last;
101 // This is a logic error to happen.
102 // daw_json_assert_weak( first != '"', "Unexpected quote", parse_state
103 // );
104 if constexpr( traits::not_same_v<typename ParseState::exec_tag_t,
106 first = mem_skip_until_end_of_string<true>(
107 ParseState::exec_tag, first, last, need_slow_path );
108 } else {
109
110 {
111 auto const sz = last - first;
112 if( sz >= 8 ) {
113 skip_to_first8( first, last );
114 } else if( sz >= 4 ) {
115 skip_to_first4( first, last );
116 }
117 }
118 while( *first != '"' ) {
119 while( []( char c ) {
120 return ( c != '"' ) & ( c != '\\' );
121 }( *first ) ) {
122 ++first;
123 }
124 if( *first == '\\' ) {
125 if( need_slow_path < 0 ) {
126 need_slow_path = first - parse_state.first;
127 }
128 first += 2;
129 } else {
130 break;
131 }
132 }
133 }
134 parse_state.first = first;
135 return static_cast<std::size_t>( need_slow_path );
136 }
137
138 template<typename ParseState>
139 [[nodiscard]] static constexpr auto parse_nq( ParseState &parse_state )
140 -> std::enable_if_t<not ParseState::is_unchecked_input, std::size_t> {
141
142 using CharT = typename ParseState::CharT;
143 std::ptrdiff_t need_slow_path = -1;
144 CharT *first = parse_state.first;
145 CharT *const last = parse_state.class_last;
146 if constexpr( traits::not_same_v<typename ParseState::exec_tag_t,
148 first = mem_skip_until_end_of_string<false>(
149 ParseState::exec_tag, first, last, need_slow_path );
150 } else {
151 if constexpr( not ParseState::exclude_special_escapes ) {
152 if( CharT *const l = parse_state.last; l - first >= 8 ) {
153 skip_to_first8( first, l );
154 } else if( last - first >= 4 ) {
155 skip_to_first4( first, l );
156 }
157 }
158 if constexpr( ParseState::is_zero_terminated_string ) {
159 if constexpr( ParseState::exclude_special_escapes ) {
160 while( *first != '\0' ) {
161 char c = *first;
162 daw_json_assert( static_cast<unsigned char>( c ) >= 0x20U,
163 ErrorReason::InvalidString, parse_state );
164 if( c == '\\' ) {
165 daw_json_assert( last - first > 1,
166 ErrorReason::InvalidString, parse_state );
167 if( need_slow_path < 0 ) {
168 need_slow_path = first - parse_state.first;
169 }
170 ++first;
171 c = *first;
172 switch( c ) {
173 case '"':
174 case '\\':
175 case '/':
176 case 'b':
177 case 'f':
178 case 'n':
179 case 'r':
180 case 't':
181 case 'u':
182 break;
183 default:
184 daw_json_error( ErrorReason::InvalidString, parse_state );
185 }
186 } else if( c == '"' ) {
187 break;
188 }
189 ++first;
190 }
191 } else {
192 while( ( *first != 0 ) & ( *first != '"' ) ) {
193 while( ( *first != 0 ) & ( *first != '"' ) &
194 ( *first != '\\' ) ) {
195 ++first;
196 }
197
198 if( ( ( *first != 0 ) & ( *first == '\\' ) ) ) {
199 if( need_slow_path < 0 ) {
200 need_slow_path = first - parse_state.first;
201 }
202 first += 2;
203 } else {
204 break;
205 }
206 }
207 }
208 } else {
209 if constexpr( ParseState::exclude_special_escapes ) {
210 while( first < last ) {
211 char c = *first;
212 daw_json_assert( static_cast<unsigned char>( c ) >= 0x20U,
213 ErrorReason::InvalidString, parse_state );
214 if( c == '\\' ) {
215 daw_json_assert( last - first > 1,
216 ErrorReason::InvalidString, parse_state );
217 if( need_slow_path < 0 ) {
218 need_slow_path = first - parse_state.first;
219 }
220 ++first;
221 c = *first;
222 switch( c ) {
223 case '"':
224 case '\\':
225 case '/':
226 case 'b':
227 case 'f':
228 case 'n':
229 case 'r':
230 case 't':
231 case 'u':
232 break;
233 default:
234 daw_json_error( ErrorReason::InvalidString, parse_state );
235 }
236 } else if( c == '"' ) {
237 break;
238 }
239 ++first;
240 }
241 } else {
242 while( first < last and *first != '"' ) {
243 while( first < last and
244 ( ( *first != '"' ) & ( *first != '\\' ) ) ) {
245 ++first;
246 }
247
248 if( first < last and *first == '\\' ) {
249 if( need_slow_path < 0 ) {
250 need_slow_path = first - parse_state.first;
251 }
252 first += 2;
253 } else {
254 break;
255 }
256 }
257 }
258 }
259 }
260 if constexpr( ParseState::is_zero_terminated_string ) {
261 daw_json_assert_weak( *first == '"', ErrorReason::InvalidString,
262 parse_state );
263 } else {
264 daw_json_assert_weak( first < last and *first == '"',
265 ErrorReason::InvalidString, parse_state );
266 }
267 parse_state.first = first;
268 return static_cast<std::size_t>( need_slow_path );
269 }
270 };
271 } // namespace json_details::string_quote
272 } // namespace DAW_JSON_VER
273} // namespace daw::json
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:190
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:179
ParseState & parse_state
Definition: daw_json_parse_class.h:182
constexpr void skip_to_first4(CharT *&first, CharT *const last)
Definition: daw_json_parse_string_quote.h:72
constexpr void skip_to_first8(CharT *&first, CharT *const last)
Definition: daw_json_parse_string_quote.h:42
constexpr UInt8 test_at_byte(UInt64 b)
Definition: daw_json_parse_string_quote.h:26
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
Definition: daw_json_assert.h:39
Definition: daw_from_json.h:22
Definition: daw_json_exec_modes.h:19
static constexpr auto parse_nq(ParseState &parse_state) -> std::enable_if_t< not ParseState::is_unchecked_input, std::size_t >
Definition: daw_json_parse_string_quote.h:139
static constexpr auto parse_nq(ParseState &parse_state) -> std::enable_if_t< ParseState::is_unchecked_input, std::size_t >
Definition: daw_json_parse_string_quote.h:94
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16