DAW JSON Link
Loading...
Searching...
No Matches
daw_json_skip_class_simd.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
12
16
17#include <daw/daw_attributes.h>
18#include <daw/daw_cxmath.h>
19#include <daw/daw_is_constant_evaluated.h>
20#include <daw/daw_span.h>
21
22#include <cstddef>
23#include <cstdint>
24#include <type_traits>
25
26#if defined( DAW_JSON_HAS_SIMD )
27namespace daw::json {
28 inline namespace DAW_JSON_VER {
29 namespace json_details {
30 namespace skip_bracketed_item_simd_details {
31 using simd_type = daw::simd::vec<char>;
32 static constexpr std::size_t block_size =
33 static_cast<std::size_t>( simd_type::size( ) );
34 static_assert( block_size <= 64 );
35
36 [[nodiscard]] constexpr std::uint64_t
37 low_bits( std::size_t count ) noexcept {
38 return count == 64 ? ~std::uint64_t{ 0 }
39 : ( std::uint64_t{ 1 } << count ) - 1;
40 }
41
42 [[nodiscard]] constexpr std::uint64_t
43 prefix_xor( std::uint64_t bits ) noexcept {
44 bits ^= bits << 1U;
45 bits ^= bits << 2U;
46 bits ^= bits << 4U;
47 bits ^= bits << 8U;
48 bits ^= bits << 16U;
49 bits ^= bits << 32U;
50 return bits;
51 }
52
53 [[nodiscard]] constexpr bool last_bit( std::uint64_t bits,
54 std::size_t count ) noexcept {
55 return count != 0 and
56 ( ( bits >> ( count - 1U ) ) & std::uint64_t{ 1 } ) != 0;
57 }
58
59 [[nodiscard]]
60#if defined( DAW_JSON_HAS_STD_SIMD )
61 consteval
62#else
63 DAW_ATTRIB_INLINE
64#endif
65 simd_type splat( char value ) noexcept {
66 return simd_type( value );
67 }
68
69 template<char... Values>
70 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR auto one_of( simd_type value ) {
71 return ( ( value == splat( Values ) ) | ... );
72 }
73
74 [[nodiscard]] DAW_JSON_SIMD_CONSTEXPR simd_type
75 load( char const *first, std::size_t count ) {
76 if( count == block_size ) {
77 return daw::simd::unchecked_load<simd_type>(
78 daw::span( first, block_size ) );
79 }
80 return daw::simd::partial_load<simd_type>(
81 daw::span( first, count ) );
82 }
83 } // namespace skip_bracketed_item_simd_details
84
87 template<SkipBracketedType BracketedType, typename ParseState>
88 [[nodiscard]] DAW_ATTRIB_FLATTEN DAW_JSON_SIMD_CONSTEXPR ParseState
89 skip_bracketed_item_simd( ParseState &parse_state ) {
90 DAW_CPP23_STATIC_LOCAL constexpr char primary_left =
91 BracketedType == SkipBracketedType::Class ? '{' : '[';
92 DAW_CPP23_STATIC_LOCAL constexpr char primary_right =
93 BracketedType == SkipBracketedType::Class ? '}' : ']';
94 DAW_CPP23_STATIC_LOCAL constexpr char secondary_left =
95 BracketedType == SkipBracketedType::Class ? '[' : '{';
96 DAW_CPP23_STATIC_LOCAL constexpr char secondary_right =
97 BracketedType == SkipBracketedType::Class ? ']' : '}';
98
99 using namespace skip_bracketed_item_simd_details;
100 auto ptr_first = parse_state.first;
101 auto const ptr_last = parse_state.last;
102 if( DAW_UNLIKELY( ptr_first >= ptr_last ) ) {
103 return parse_state;
104 }
105
106 auto result = parse_state;
107 std::size_t count = 0;
108 std::uint32_t primary_depth = 1;
109 std::uint32_t secondary_depth = 0;
110 bool in_string = false;
111 bool escaped = false;
112
113 if( *ptr_first == primary_left ) {
114 ++ptr_first;
115 }
116
117 while( ptr_first < ptr_last ) {
118 auto const remaining =
119 static_cast<std::size_t>( ptr_last - ptr_first );
120 auto const lane_count =
121 remaining < block_size ? remaining : block_size;
122 auto const input = load( ptr_first, lane_count );
123 auto const valid_bits = low_bits( lane_count );
124 auto const backslash_bits =
125 ( input == splat( '\\' ) ).to_ullong( ) & valid_bits;
126
127 DAW_CPP23_STATIC_LOCAL constexpr std::uint64_t odd_bits =
128 0xAAAAAAAAAAAAAAAAULL;
129 auto const previous_escaped = escaped ? std::uint64_t{ 1 } : 0;
130 auto const potential_escape = backslash_bits & ~previous_escaped;
131 auto const maybe_escaped = potential_escape << 1U;
132 auto const escape_and_terminal =
133 ( ( maybe_escaped | odd_bits ) - potential_escape ) ^ odd_bits;
134 auto const escaped_bits =
135 ( escape_and_terminal ^ ( backslash_bits | previous_escaped ) ) &
136 valid_bits;
137 auto const escape_bits = escape_and_terminal & backslash_bits;
138 escaped = last_bit( escape_bits, lane_count );
139
140 auto const quote_bits =
141 ( input == splat( '"' ) ).to_ullong( ) & ~escaped_bits & valid_bits;
142 auto const in_string_bits =
143 ( prefix_xor( quote_bits ) ^
144 ( in_string ? valid_bits : std::uint64_t{ 0 } ) ) &
145 valid_bits;
146 in_string = last_bit( in_string_bits, lane_count );
147
148 auto events = one_of<'{', '}', '[', ']', ','>( input ).to_ullong( ) &
149 ~( in_string_bits ^ quote_bits ) & ~escaped_bits &
150 valid_bits;
151 while( events != 0 ) {
152 auto const lane =
153 static_cast<std::size_t>(
154 daw::cxmath::count_trailing_zeros( static_cast<std::uint64_t>( events ) ) );
155 switch( ptr_first[lane] ) {
156 case ',':
157 if( ( primary_depth == 1 ) & ( secondary_depth == 0 ) ) {
158 ++count;
159 }
160 break;
161 case primary_left:
162 ++primary_depth;
163 break;
164 case primary_right:
165 --primary_depth;
166 if( primary_depth == 0 ) {
167 auto const end = ptr_first + lane + 1;
168 if constexpr( not ParseState::is_unchecked_input ) {
169 daw_json_ensure( secondary_depth == 0,
170 ErrorReason::InvalidBracketing,
171 parse_state );
172 }
173 result.last = end;
174 result.counter = count;
175 parse_state.first = end;
176 return result;
177 }
178 break;
179 case secondary_left:
180 ++secondary_depth;
181 break;
182 case secondary_right:
183 --secondary_depth;
184 break;
185 default:
186 DAW_UNREACHABLE( );
187 }
188 events &= events - 1U;
189 }
190 ptr_first += lane_count;
191 }
192
193 if constexpr( not ParseState::is_unchecked_input ) {
195 not in_string, ErrorReason::UnexpectedEndOfData, parse_state );
196 daw_json_ensure( ( primary_depth == 0 ) & ( secondary_depth == 0 ),
197 ErrorReason::InvalidBracketing,
198 parse_state );
199 }
200 result.last = ptr_first;
201 result.counter = count;
202 parse_state.first = ptr_first;
203 return result;
204 }
205 } // namespace json_details
206 } // namespace DAW_JSON_VER
207} // namespace daw::json
208#endif
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20