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"
12 #include "daw_json_parse_common.h"
14 
15 #include <daw/daw_uint_buffer.h>
16 
17 #include <ciso646>
18 #include <cstddef>
19 #include <type_traits>
20 
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 ) );
27  }
28 
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 ) );
34  }
35 
36  inline constexpr void skip_to_first8( char const *&first,
37  char const *const last ) {
38  bool keep_going = last - first >= 8;
39  while( keep_going ) {
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;
61  }
62  first -= *( first - 1 ) == '\\' ? 1 : 0;
63  }
64 
65  inline constexpr void skip_to_first4( char const *&first,
66  char const *const last ) {
67  bool keep_going = last - first >= 4;
68  while( keep_going ) {
69  // Need to look for escapes as this is fast path
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;
82  }
83  first -= *( first - 1 ) == '\\' ? 1 : 0;
84  }
85 
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;
93  // This is a logic error to happen.
94  // daw_json_assert_weak( first != '"', "Unexpected quote", rng );
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 );
99  } else {
100  if( last - first >= 8 ) {
101  skip_to_first8( first, last );
102  } else if( last - first >= 4 ) {
103  skip_to_first4( first, last );
104  }
105  while( *first != '"' ) {
106  while( ( *first != '"' ) & ( *first != '\\' ) ) {
107  ++first;
108  }
109  if( DAW_JSON_UNLIKELY( *first == '\\' ) ) {
110  if( need_slow_path < 0 ) {
111  need_slow_path = first - rng.first;
112  }
113  first += 2;
114  } else {
115  break;
116  }
117  }
118  }
119  rng.first = first;
120  return static_cast<std::size_t>( need_slow_path );
121  }
122 
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 );
133  } else {
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 );
138  }
139  while( DAW_JSON_LIKELY( first < last ) and *first != '"' ) {
140  while( DAW_JSON_LIKELY( first < last ) and
141  ( ( *first != '"' ) & ( *first != '\\' ) ) ) {
142  ++first;
143  }
144 
145  if( DAW_JSON_UNLIKELY( first < last and *first == '\\' ) ) {
146  if( need_slow_path < 0 ) {
147  need_slow_path = first - rng.first;
148  }
149  first += 2;
150  } else {
151  break;
152  }
153  }
154  }
155  daw_json_assert_weak( first < last and *first == '"',
156  ErrorReason::InvalidString, rng );
157  rng.first = first;
158  return static_cast<std::size_t>( need_slow_path );
159  }
160  };
161 } // namespace daw::json::json_details::string_quote
daw_not_const_ex_functions.h
daw_json_assert_weak
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:206
DAW_JSON_UNLIKELY
#define DAW_JSON_UNLIKELY(Bool)
Definition: daw_json_assert.h:35
daw_json_parse_common.h
daw_json_assert.h
DAW_JSON_LIKELY
#define DAW_JSON_LIKELY(Bool)
Definition: daw_json_assert.h:34