14 #include <daw/daw_arith_traits.h>
15 #include <daw/daw_cxmath.h>
16 #include <daw/daw_uint_buffer.h>
23 #ifdef DAW_ALLOW_SSE42
24 #include <emmintrin.h>
25 #include <smmintrin.h>
26 #include <tmmintrin.h>
27 #include <xmmintrin.h>
33 namespace daw::json::json_details {
34 [[nodiscard]]
static inline constexpr
bool
35 is_made_of_eight_digits_cx(
const char *ptr ) {
39 for( std::size_t n = 0; n < 8; ++n ) {
40 buff[n] =
static_cast<std::byte
>( ptr[n] );
42 UInt64 val = UInt64( );
44 for( std::size_t n = 0; n < 8; ++n ) {
45 val |= to_uint64( buff[n] ) << ( 8 * n );
48 ( ( val & 0xF0F0
'F0F0'F0F0
'F0F0_u64 ) |
49 ( ( ( val + 0x0606'0606
'0606'0606_u64 ) & 0xF0F0
'F0F0'F0F0
'F0F0_u64 ) >>
50 4U ) ) == 0x3333'3333
'3333'3333_u64 );
54 typename MaxArithUnsigned>
55 using max_unsigned_t = std::conditional_t<
56 (daw::is_integral_v<Unsigned> or std::is_enum_v<Unsigned>),
57 std::conditional_t<(
sizeof( Unsigned ) >
sizeof( MaxArithUnsigned ) ),
58 Unsigned, MaxArithUnsigned>,
63 inline constexpr UInt64 parse_8_digits(
const char *
const str ) {
64 auto const chunk = daw::to_uint64_buffer( str );
66 auto const lower_digits = ( chunk & 0x0f
'00'0f
'00'0f
'00'0f
'00_u64 ) >> 8U;
67 auto const upper_digits = ( chunk & 0x00'0f
'00'0f
'00'0f
'00'0f_u64 ) * 10U;
68 auto const chunk2 = lower_digits + upper_digits;
71 auto const lower_digits2 =
72 ( chunk2 & 0x00
'ff'00
'00'00
'ff'00
'00_u64 ) >> 16U;
73 auto const upper_digits2 =
74 ( chunk2 & 0x00'00
'00'ff
'00'00
'00'ff_u64 ) * 100U;
75 auto const chunk3 = lower_digits2 + upper_digits2;
78 auto const lower_digits3 =
79 ( chunk3 & 0x00
'00'ff
'ff'00
'00'00
'00_u64 ) >> 32U;
80 auto const upper_digits3 =
81 ( chunk3 & 0x00'00
'00'00
'00'00
'ff'ff_u64 ) * 10000U;
82 auto const chunk4 = lower_digits3 + upper_digits3;
84 return chunk4 & 0xFFFF
'FFFF_u64;
86 static_assert( parse_8_digits( "12345678" ) == 1234'5678_u64,
87 "8 digit parser does not work on this platform" );
88 inline constexpr UInt64 parse_16_digits(
const char *
const str ) {
89 auto const upper = parse_8_digits( str );
90 auto const lower = parse_8_digits( str + 8 );
91 return upper * 100
'000'000_u64 + lower;
93 static_assert( parse_16_digits(
"1234567890123456" ) == 1234567890123456_u64,
94 "16 digit parser does not work on this platform" );
96 template<
typename Unsigned,
JsonRangeCheck RangeChecked,
bool KnownBounds,
98 std::enable_if_t<KnownBounds, std::nullptr_t> =
nullptr>
99 [[nodiscard]]
static constexpr Unsigned
100 unsigned_parser( constexpr_exec_tag
const &, Range &rng ) {
102 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
103 static_assert( not
static_cast<bool>( RangeChecked ) or
104 std::is_same_v<result_t, UInt64>,
105 "Range checking is only supported for std integral types" );
107 char const *first = rng.first;
108 char const *
const last = rng.last;
109 result_t result = result_t( );
111 while( last - first >= 16 ) {
112 result *=
static_cast<result_t
>( 10
'000'000
'000'000
'000ULL );
113 result += static_cast<result_t>( parse_16_digits( first ) );
116 if( last - first >= 8 ) {
117 result *= static_cast<result_t>( 100'000
'000ULL );
118 result += static_cast<result_t>( parse_8_digits( first ) );
121 while( first < last ) {
123 result += parse_digit( *first );
126 if constexpr( RangeChecked != JsonRangeCheck::Never ) {
128 ( daw::numeric_limits<result_t>::digits10 + 1U ) - rng.size( );
129 daw_json_assert( ( ( result <= daw::numeric_limits<result_t>::max( ) ) &
131 ErrorReason::NumberOutOfRange, rng );
134 if constexpr( RangeChecked == JsonRangeCheck::Never ) {
135 return daw::construct_a<Unsigned>( static_cast<Unsigned>( result ) );
137 return daw::construct_a<Unsigned>( daw::narrow_cast<Unsigned>( result ) );
141 //**************************
142 template<typename Unsigned, JsonRangeCheck RangeChecked, bool KnownBounds,
144 std::enable_if_t<not KnownBounds, std::nullptr_t> = nullptr>
145 [[nodiscard]] static constexpr Unsigned
146 unsigned_parser( constexpr_exec_tag const &, Range &rng ) {
147 // We do not know how long the string is
148 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
149 static_assert( not static_cast<bool>( RangeChecked ) or
150 std::is_same_v<result_t, UInt64>,
151 "Range checking is only supported for std integral types" );
152 daw_json_assert_weak( rng.has_more( ), ErrorReason::UnexpectedEndOfData,
154 char const *first = rng.first;
155 char const *const orig_first = first;
156 char const *const last = rng.last;
157 result_t result = result_t( );
159 last - first >= 8 ? is_made_of_eight_digits_cx( first ) : false;
160 if( has_eight & ( last - first >= 16 ) ) {
161 bool has_sixteen = is_made_of_eight_digits_cx( first + 8 );
162 while( has_sixteen ) {
163 result *= static_cast<result_t>( 10'000
'000'000
'000'000ULL );
164 result +=
static_cast<result_t
>( parse_16_digits( first ) );
167 last - first >= 8 ? is_made_of_eight_digits_cx( first ) : false;
170 ( last - first >= 16 ? is_made_of_eight_digits_cx( first + 8 )
175 result *=
static_cast<result_t
>( 100
'000'000ULL );
176 result +=
static_cast<result_t
>( parse_8_digits( first ) );
179 auto dig = parse_digit( *first );
185 dig = parse_digit( *first );
188 if constexpr( RangeChecked != JsonRangeCheck::Never ) {
189 auto const count =
static_cast<std::ptrdiff_t
>(
190 daw::numeric_limits<Unsigned>::digits10 + 1 ) -
191 ( first - orig_first );
196 if constexpr( RangeChecked == JsonRangeCheck::Never ) {
197 return daw::construct_a<Unsigned>(
static_cast<Unsigned
>( result ) );
199 return daw::construct_a<Unsigned>( daw::narrow_cast<Unsigned>( result ) );
203 #ifdef DAW_ALLOW_SSE42