16 #include <daw/daw_attributes.h>
17 #include <daw/daw_cpp_feature_check.h>
18 #include <daw/daw_cxmath.h>
19 #include <daw/daw_do_n.h>
20 #include <daw/daw_likely.h>
21 #include <daw/daw_uint_buffer.h>
22 #include <daw/daw_unreachable.h>
24 #if defined( DAW_ALLOW_SSE42 )
25 #include <emmintrin.h>
26 #include <nmmintrin.h>
27 #include <smmintrin.h>
28 #include <tmmintrin.h>
29 #include <wmmintrin.h>
30 #include <xmmintrin.h>
31 #if defined( DAW_HAS_MSVC_LIKE )
41 namespace json_details {
44 constexpr
bool is_escaped(
char const *ptr,
char const *min_ptr ) {
45 if( *( ptr - 1 ) !=
'\\' ) {
48 if( ( ptr - min_ptr ) < 2 ) {
51 return *( ptr - 2 ) !=
'\\';
54 #if defined( DAW_ALLOW_SSE42 )
56 alignas( 16 )
bool values[256] = { };
58 constexpr
bool operator[](
char idx )
const {
59 return values[
static_cast<unsigned char>( idx )];
63 template<
char... keys>
64 static constexpr
inline key_table_t key_table = [] {
65 auto result = key_table_t{ };
66 (void)( ( result.values[
static_cast<unsigned char>( keys )] = true ) |
73 #if DAW_HAS_BUILTIN( __builtin_ffs )
74 return __builtin_ffs(
static_cast<int>( value ) ) - 1;
75 #elif defined( DAW_HAS_MSVC_LIKE )
77 _BitScanForward( &index,
static_cast<int>( value ) );
78 return static_cast<std::ptrdiff_t
>( index );
80 std::ptrdiff_t result = 0;
84 while( ( value & 1 ) == 0 ) {
92 #if defined( DAW_ALLOW_SSE42 )
93 DAW_ATTRIB_INLINE __m128i
94 set_reverse(
char c0,
char c1 = 0,
char c2 = 0,
char c3 = 0,
char c4 = 0,
95 char c5 = 0,
char c6 = 0,
char c7 = 0,
char c8 = 0,
96 char c9 = 0,
char c10 = 0,
char c11 = 0,
char c12 = 0,
97 char c13 = 0,
char c14 = 0,
char c15 = 0 ) {
98 return _mm_set_epi8( c15, c14, c13, c12, c11, c10, c9, c8, c7, c6, c5,
102 DAW_ATTRIB_INLINE __m128i uload16_char_data( sse42_exec_tag,
104 return _mm_loadu_si128(
reinterpret_cast<__m128i
const *
>( ptr ) );
107 DAW_ATTRIB_INLINE __m128i load16_char_data( sse42_exec_tag,
109 return _mm_load_si128(
reinterpret_cast<__m128i
const *
>( ptr ) );
113 DAW_ATTRIB_INLINE UInt32 mem_find_eq( sse42_exec_tag, __m128i block ) {
114 __m128i
const keys = _mm_set1_epi8( k );
115 __m128i
const found = _mm_cmpeq_epi8( block, keys );
116 return to_uint32( _mm_movemask_epi8( found ) );
119 template<
unsigned char k>
120 DAW_ATTRIB_INLINE UInt32 mem_find_gt( sse42_exec_tag, __m128i block ) {
121 static __m128i
const keys = _mm_set1_epi8( k );
122 __m128i
const found = _mm_cmpgt_epi8( block, keys );
123 return to_uint32( _mm_movemask_epi8( found ) );
126 template<
bool is_unchecked_input,
char... keys,
typename CharT>
127 DAW_ATTRIB_INLINE CharT *mem_move_to_next_of( sse42_exec_tag tag,
129 CharT *
const last ) {
131 while( last - first >= 16 ) {
132 auto const val0 = uload16_char_data( tag, first );
133 auto const key_positions = ( mem_find_eq<keys>( tag, val0 ) | ... );
134 if( key_positions != 0 ) {
135 return first + find_lsb_set( tag, key_positions );
140 auto const max_pos = last - first;
141 memcpy( &val1, first,
static_cast<std::size_t
>( max_pos ) );
142 auto const key_positions = ( mem_find_eq<keys>( tag, val1 ) | ... );
143 if( key_positions != 0 ) {
144 auto const offset = find_lsb_set( tag, key_positions );
145 if( offset >= max_pos ) {
148 return first + offset;
153 template<
bool is_unchecked_input,
char... keys,
typename CharT>
154 DAW_ATTRIB_INLINE CharT *
155 mem_move_to_next_not_of( sse42_exec_tag tag, CharT *first, CharT *last ) {
156 using keys_len = daw::constant<static_cast<int>(
sizeof...( keys ) )>;
157 using compare_mode = daw::constant<static_cast<int>(
158 _SIDD_SBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_NEGATIVE_POLARITY )>;
159 static_assert( keys_len::value <= 16 );
161 __m128i
const a = set_reverse( keys... );
163 while( last - first >= 16 ) {
164 auto const b = uload16_char_data( tag, first );
166 _mm_cmpestri( a, keys_len::value, b, 16, compare_mode::value );
173 auto const max_pos = last - first;
175 _mm_cmpestri( a, keys_len::vlaue, b, 16, compare_mode::value );
176 if( result < max_pos ) {
177 return first + result;
182 template<
typename U32>
183 DAW_ATTRIB_INLINE
bool add_overflow( U32 value1, U32 value2,
185 static_assert(
sizeof( U32 ) <=
sizeof(
unsigned long long ) );
186 static_assert(
sizeof( U32 ) == 4 );
187 #if defined( DAW_JSON_HAS_BUILTIN_UADD )
188 if constexpr(
sizeof(
unsigned ) ==
sizeof( U32 ) ) {
189 return __builtin_uadd_overflow(
190 static_cast<unsigned>( value1 ),
static_cast<unsigned>( value2 ),
191 reinterpret_cast<unsigned *
>( &result ) );
192 }
else if constexpr(
sizeof(
unsigned long ) ==
sizeof( U32 ) ) {
193 return __builtin_uaddl_overflow(
194 static_cast<unsigned long>( value1 ),
195 static_cast<unsigned long>( value2 ),
196 reinterpret_cast<unsigned long *
>( &result ) );
198 return __builtin_uaddll_overflow(
199 static_cast<unsigned long long>( value1 ),
200 static_cast<unsigned long long>( value2 ),
201 reinterpret_cast<unsigned long long *
>( &result ) );
204 return _addcarry_u32( 0,
static_cast<std::uint32_t
>( value1 ),
205 static_cast<std::uint32_t
>( value2 ),
206 reinterpret_cast<std::uint32_t *
>( &result ) );
212 DAW_ATTRIB_INLINE constexpr UInt32
214 UInt32 backslashes ) {
215 backslashes &= ~prev_escaped;
216 UInt32 follow_escape = ( backslashes << 1 ) | prev_escaped;
217 using even_bits = daw::constant<0x5555'5555_u32>;
219 UInt32
const odd_seq_start =
220 backslashes & ( ~even_bits::value ) & ( ~follow_escape );
221 UInt32 seq_start_on_even_bits = 0_u32;
223 auto r = odd_seq_start + backslashes;
224 seq_start_on_even_bits = 0x0000'FFFF_u32 & r;
228 UInt32 invert_mask = seq_start_on_even_bits << 1U;
230 return ( even_bits::value ^ invert_mask ) & follow_escape;
233 DAW_ATTRIB_INLINE UInt32 prefix_xor( sse42_exec_tag, UInt32 bitmask ) {
234 __m128i
const all_ones = _mm_set1_epi8(
'\xFF' );
235 __m128i
const result = _mm_clmulepi64_si128(
236 _mm_set_epi32( 0, 0, 0,
static_cast<std::int32_t
>( bitmask ) ),
238 return to_uint32( _mm_cvtsi128_si32( result ) );
241 template<
bool is_unchecked_input,
typename CharT>
242 DAW_ATTRIB_NONNULL( )
243 DAW_ATTRIB_RET_NONNULL
244 inline CharT *mem_skip_until_end_of_string(
simd_exec_tag tag,
246 CharT *
const last ) {
247 UInt32 prev_escapes = 0_u32;
248 while( last - first >= 16 ) {
249 auto const val0 = uload16_char_data( tag, first );
250 UInt32
const backslashes = mem_find_eq<'\\'>( tag, val0 );
251 UInt32
const escaped =
252 find_escaped_branchless( tag, prev_escapes, backslashes );
253 UInt32
const quotes = mem_find_eq<
'"'>( tag, val0 ) & ( ~escaped );
254 UInt32
const in_string = prefix_xor( tag, quotes );
255 if( in_string != 0 ) {
256 first += find_lsb_set( tag, in_string );
261 if constexpr( is_unchecked_input ) {
262 while( *first !=
'"' ) {
263 while( not key_table<'"', '\\'>[*first] ) {
266 if( *first ==
'"' ) {
272 while( DAW_LIKELY( first < last ) and *first !=
'"' ) {
273 while( DAW_LIKELY( first < last ) and
274 not key_table<'"', '\\'>[*first] ) {
277 if( first >= last ) {
280 if( *first ==
'"' ) {
286 return ( is_unchecked_input or DAW_LIKELY( first < last ) ) ? first
290 template<
bool is_unchecked_input,
typename CharT>
291 DAW_ATTRIB_NONNULL( )
292 DAW_ATTRIB_RET_NONNULL
inline CharT *mem_skip_until_end_of_string(
294 std::ptrdiff_t &first_escape ) {
295 CharT *
const first_first = first;
296 UInt32 prev_escapes = 0_u32;
297 while( last - first >= 16 ) {
298 auto const val0 = uload16_char_data( tag, first );
299 UInt32
const backslashes = mem_find_eq<'\\'>( tag, val0 );
300 if( ( backslashes != 0 ) & ( first_escape < 0 ) ) {
301 first_escape = find_lsb_set( tag, backslashes );
303 UInt32
const escaped =
304 find_escaped_branchless( tag, prev_escapes, backslashes );
305 UInt32
const quotes = mem_find_eq<
'"'>( tag, val0 ) & ( ~escaped );
306 UInt32
const in_string = prefix_xor( tag, quotes );
307 if( in_string != 0 ) {
308 first += find_lsb_set( tag, in_string );
313 if constexpr( is_unchecked_input ) {
314 while( *first !=
'"' ) {
315 while( not key_table<'"', '\\'>[*first] ) {
318 if( *first ==
'"' ) {
321 if( first_escape < 0 ) {
322 first_escape = first_first - first;
327 while( DAW_LIKELY( first < last ) and *first !=
'"' ) {
328 while( DAW_LIKELY( first < last ) and
329 not key_table<'"', '\\'>[*first] ) {
332 if( first >= last ) {
335 if( *first ==
'"' ) {
338 if( first_escape < 0 ) {
339 first_escape = first_first - first;
344 return ( is_unchecked_input or DAW_LIKELY( first < last ) ) ? first
349 template<
bool is_unchecked_input,
char... keys,
typename CharT>
350 DAW_ATTRIB_NONNULL( )
351 DAW_ATTRIB_RET_NONNULL DAW_ATTRIB_INLINE CharT *mem_move_to_next_of(
353 if constexpr(
sizeof...( keys ) == 1 ) {
354 char const key[]{ keys... };
355 auto *ptr =
reinterpret_cast<CharT *
>( std::memchr(
356 first, key[0],
static_cast<std::size_t
>( last - first ) ) );
357 if( ptr ==
nullptr ) {
362 constexpr
auto eq = [](
char l,
char r )
366 while( is_unchecked_input or first < last ) {
367 char const c = *first;
368 if( nsc_or( eq( c, keys )... ) ) {
377 template<
bool is_unchecked_input,
typename CharT>
378 DAW_ATTRIB_NONNULL( )
379 DAW_ATTRIB_RET_NONNULL DAW_ATTRIB_INLINE CharT *mem_skip_string(
381 return mem_move_to_next_of<is_unchecked_input,
'"',
'\\'>( tag, first,
385 template<
bool is_unchecked_input,
typename CharT>
386 DAW_ATTRIB_NONNULL( )
387 DAW_ATTRIB_RET_NONNULL DAW_ATTRIB_INLINE
389 CharT *
const last ) {
390 if constexpr( not is_unchecked_input ) {
393 first = mem_move_to_next_of<is_unchecked_input,
'\\',
'"'>( tag, first,
395 while( is_unchecked_input or first < last ) {
404 first = mem_move_to_next_of<is_unchecked_input,
'\\',
'"'>(
410 template<
bool is_unchecked_input,
typename CharT>
411 DAW_ATTRIB_NONNULL( )
412 DAW_ATTRIB_RET_NONNULL DAW_ATTRIB_INLINE
415 CharT *
const last ) {
416 if( first == last ) {
419 using char_t = std::remove_const_t<CharT>;
422 if( is_unchecked_input or
423 DAW_LIKELY( *( last - 1 ) != char_t{
'\\' } ) ) {
424 while( is_unchecked_input or DAW_UNLIKELY( first < last ) ) {
425 char const c = *first;
426 if( c == char_t{
'"' } ) {
429 if( c == char_t{
'\\' } ) {
438 while( is_unchecked_input or DAW_UNLIKELY( first < last ) ) {
439 char const c = *first;
440 if( c == char_t{
'"' } ) {
443 if( c == char_t{
'\\' } ) {
444 if( DAW_LIKELY( first + 1 < last ) ) {
458 template<
bool is_unchecked_input,
typename CharT>
459 DAW_ATTRIB_NONNULL( )
460 DAW_ATTRIB_RET_NONNULL DAW_ATTRIB_INLINE
463 std::ptrdiff_t &first_escape ) {
464 CharT *
const first_first = first;
465 if constexpr( not is_unchecked_input ) {
468 first = mem_move_to_next_of<is_unchecked_input,
'\\',
'"'>( tag, first,
470 while( is_unchecked_input or first < last ) {
475 if( first_escape < 0 ) {
476 first_escape = first_first - first;
478 if constexpr( is_unchecked_input ) {
481 first +=
static_cast<int>(
static_cast<bool>( last - first ) );
486 first = mem_move_to_next_of<is_unchecked_input,
'\\',
'"'>(
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
#define DAW_JSON_CPP23_STATIC_CALL_OP
This is in addition to the parse policy. Always do a full name match instead of sometimes relying on ...
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.