15 #include <daw/daw_uint_buffer.h>
19 #include <type_traits>
21 namespace daw::json::json_details::string_quote {
22 template<std::
size_t N,
char c>
23 inline constexpr UInt8 test_at_byte( UInt64 b ) {
24 auto const lhs = b & ( 0xFF_u64 << ( N * 8U ) );
25 auto const rhs = to_uint64(
static_cast<unsigned char>( c ) ) << ( N * 8U );
26 return to_uint8( not( lhs - rhs ) );
29 template<std::
size_t N,
char c>
30 inline constexpr UInt8 test_at_byte( UInt32 b ) {
31 auto const lhs = b & ( 0xFF_u32 << ( N * 8U ) );
32 auto const rhs = to_uint32(
static_cast<unsigned char>( c ) ) << ( N * 8U );
33 return to_uint8( not( lhs - rhs ) );
36 inline constexpr
void skip_to_first8(
char const *&first,
37 char const *
const last ) {
38 bool keep_going = last - first >= 8;
40 auto buff = daw::to_uint64_buffer( first );
41 auto const q7 = test_at_byte<7U,
'"'>( buff );
42 auto const q6 = test_at_byte<6U,
'"'>( buff );
43 auto const q5 = test_at_byte<5U,
'"'>( buff );
44 auto const q4 = test_at_byte<4U,
'"'>( buff );
45 auto const q3 = test_at_byte<3U,
'"'>( buff );
46 auto const q2 = test_at_byte<2U,
'"'>( buff );
47 auto const q1 = test_at_byte<1U,
'"'>( buff );
48 auto const q0 = test_at_byte<0U,
'"'>( buff );
49 auto const s7 = test_at_byte<7U, '\\'>( buff );
50 auto const s6 = test_at_byte<6U, '\\'>( buff );
51 auto const s5 = test_at_byte<5U, '\\'>( buff );
52 auto const s4 = test_at_byte<4U, '\\'>( buff );
53 auto const s3 = test_at_byte<3U, '\\'>( buff );
54 auto const s2 = test_at_byte<2U, '\\'>( buff );
55 auto const s1 = test_at_byte<1U, '\\'>( buff );
56 auto const s0 = test_at_byte<0U, '\\'>( buff );
57 keep_going = not( q0 | q1 | q2 | q3 | q4 | q5 | q6 | q7 | s0 | s1 | s2 |
58 s3 | s4 | s5 | s6 | s7 );
59 keep_going = keep_going &
static_cast<bool>( last - ( first + 8 ) >= 8 );
60 first +=
static_cast<int>( keep_going ) * 8;
62 first -= *( first - 1 ) ==
'\\' ? 1 : 0;
65 inline constexpr
void skip_to_first4(
char const *&first,
66 char const *
const last ) {
67 bool keep_going = last - first >= 4;
70 auto buff = daw::to_uint32_buffer( first );
71 auto const q3 = test_at_byte<3U,
'"'>( buff );
72 auto const q2 = test_at_byte<2U,
'"'>( buff );
73 auto const q1 = test_at_byte<1U,
'"'>( buff );
74 auto const q0 = test_at_byte<0U,
'"'>( buff );
75 auto const s3 = test_at_byte<3U, '\\'>( buff );
76 auto const s2 = test_at_byte<2U, '\\'>( buff );
77 auto const s1 = test_at_byte<1U, '\\'>( buff );
78 auto const s0 = test_at_byte<0U, '\\'>( buff );
79 keep_going = not( q0 | q1 | q2 | q3 | s0 | s1 | s2 | s3 );
80 keep_going = keep_going &
static_cast<bool>( last - ( first + 4 ) >= 4 );
81 first +=
static_cast<int>( keep_going ) * 4;
83 first -= *( first - 1 ) ==
'\\' ? 1 : 0;
86 struct string_quote_parser {
87 template<
typename Range>
88 [[nodiscard]]
static constexpr
auto parse_nq( Range &rng )
89 -> std::enable_if_t<Range::is_unchecked_input, std::size_t> {
90 std::ptrdiff_t need_slow_path = -1;
91 char const *first = rng.first;
92 char const *
const last = rng.last;
95 if constexpr( not std::is_same_v<
typename Range::exec_tag_t,
96 constexpr_exec_tag> ) {
97 first = mem_skip_until_end_of_string<true>( Range::exec_tag, first,
98 last, need_slow_path );
100 if( last - first >= 8 ) {
101 skip_to_first8( first, last );
102 }
else if( last - first >= 4 ) {
103 skip_to_first4( first, last );
105 while( *first !=
'"' ) {
106 while( ( *first !=
'"' ) & ( *first !=
'\\' ) ) {
110 if( need_slow_path < 0 ) {
111 need_slow_path = first - rng.first;
120 return static_cast<std::size_t
>( need_slow_path );
123 template<
typename Range>
124 [[nodiscard]]
static constexpr
auto parse_nq( Range &rng )
125 -> std::enable_if_t<not Range::is_unchecked_input, std::size_t> {
126 std::ptrdiff_t need_slow_path = -1;
127 char const *first = rng.first;
128 char const *
const last = rng.class_last;
129 if constexpr( not std::is_same_v<
typename Range::exec_tag_t,
130 constexpr_exec_tag> ) {
131 first = mem_skip_until_end_of_string<false>( Range::exec_tag, first,
132 last, need_slow_path );
134 if(
char const *
const l = rng.last; l - first >= 8 ) {
135 skip_to_first8( first, l );
136 }
else if( last - first >= 4 ) {
137 skip_to_first4( first, l );
141 ( ( *first !=
'"' ) & ( *first !=
'\\' ) ) ) {
146 if( need_slow_path < 0 ) {
147 need_slow_path = first - rng.first;
156 ErrorReason::InvalidString, rng );
158 return static_cast<std::size_t
>( need_slow_path );