19 #include <daw/daw_arith_traits.h>
20 #include <daw/daw_construct_a.h>
21 #include <daw/daw_cxmath.h>
22 #include <daw/daw_remove_cvref.h>
23 #include <daw/daw_uint_buffer.h>
26 #include <daw/stdinc/data_access.h>
29 #if defined( DAW_ALLOW_SSE42 )
30 #include <emmintrin.h>
31 #include <smmintrin.h>
32 #include <tmmintrin.h>
33 #include <xmmintrin.h>
34 #if defined( DAW_HAS_MSVC_LIKE )
41 namespace json_details {
42 template<
typename Signed,
typename Un
signed>
43 DAW_ATTRIB_INLINE constexpr Signed to_signed( Unsigned &&u,
45 if( sign <= Signed{ 0 } ) {
46 return static_cast<Signed
>( -u );
48 return static_cast<Signed
>( u );
52 DAW_ATTRIB_NONNULL( )
inline constexpr
bool is_made_of_eight_digits_cx(
57 std::byte
const buff[8]{
58 static_cast<std::byte
>( ptr[0] ),
static_cast<std::byte
>( ptr[1] ),
59 static_cast<std::byte
>( ptr[2] ),
static_cast<std::byte
>( ptr[3] ),
60 static_cast<std::byte
>( ptr[4] ),
static_cast<std::byte
>( ptr[5] ),
61 static_cast<std::byte
>( ptr[6] ),
static_cast<std::byte
>( ptr[7] ) };
63 UInt64 val = UInt64( );
64 for( std::size_t n = 0; n < 8; ++n ) {
65 val |= to_uint64( buff[n] ) << ( 8 * n );
67 return ( ( ( val & 0xF0F0'F0F0'F0F0'F0F0_u64 ) |
68 ( ( ( val + 0x0606'0606'0606'0606_u64 ) &
69 0xF0F0'F0F0'F0F0'F0F0_u64 ) >>
70 4U ) ) == 0x3333'3333'3333'3333_u64 );
74 typename MaxArithUnsigned>
75 using max_unsigned_t = daw::conditional_t<
76 daw::is_integral_v<Unsigned> or std::is_enum_v<Unsigned>,
77 daw::conditional_t<(
sizeof( Unsigned ) >
sizeof( MaxArithUnsigned ) ),
78 Unsigned, MaxArithUnsigned>,
84 inline constexpr UInt64 parse_8_digits(
char const *
const str ) {
85 auto const chunk = daw::to_uint64_buffer( str );
87 auto const lower_digits =
88 ( chunk & 0x0F'00'0F'00'0F'00'0F'00_u64 ) >> 8U;
89 auto const upper_digits =
90 ( chunk & 0x00'0F'00'0F'00'0F'00'0F_u64 ) * 10U;
91 auto const chunk2 = lower_digits + upper_digits;
94 auto const lower_digits2 =
95 ( chunk2 & 0x00'FF'00'00'00'FF'00'00_u64 ) >> 16U;
96 auto const upper_digits2 =
97 ( chunk2 & 0x00'00'00'FF'00'00'00'FF_u64 ) * 100U;
98 auto const chunk3 = lower_digits2 + upper_digits2;
101 auto const lower_digits3 =
102 ( chunk3 & 0x00'00'FF'FF'00'00'00'00_u64 ) >> 32U;
103 auto const upper_digits3 =
104 ( chunk3 & 0x00'00'00'00'00'00'FF'FF_u64 ) * 10000U;
105 auto const chunk4 = lower_digits3 + upper_digits3;
107 return chunk4 & 0xFFFF'FFFF_u64;
110 static_assert( parse_8_digits(
"12345678" ) == 1234'5678_u64,
111 "8 digit parser does not work on this platform" );
113 DAW_ATTRIB_NONNULL( )
114 inline constexpr UInt64 parse_16_digits(
char const *
const str ) {
115 auto const upper = parse_8_digits( str );
116 auto const lower = parse_8_digits( str + 8 );
117 return upper * 100'000'000_u64 + lower;
120 static_assert( parse_16_digits(
"1234567890123456" ) ==
121 1234567890123456_u64,
122 "16 digit parser does not work on this platform" );
125 struct make_unsigned_with_bool : daw::make_unsigned<T> {};
128 struct make_unsigned_with_bool<bool> {
132 template<
typename Integer,
typename T,
typename ParseState>
133 [[nodiscard]] constexpr Integer
134 narrow_cast( T value, ParseState
const &parse_state ) {
135 if constexpr( std::is_signed_v<T> ) {
136 if constexpr( std::is_signed_v<Integer> ) {
137 if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
139 }
else if( value <=
static_cast<T
>(
140 ( std::numeric_limits<Integer>::max )( ) ) ) {
141 return static_cast<Integer
>( value );
145 }
else if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
153 static_cast<T
>( ( std::numeric_limits<Integer>::max )( ) ) ) {
158 }
else if constexpr( std::is_signed_v<Integer> ) {
159 if constexpr(
sizeof( T ) <
sizeof( Integer ) ) {
160 return static_cast<Integer
>( value );
163 static_cast<T
>( ( std::numeric_limits<Integer>::max )( ) ) ) {
166 return static_cast<Integer
>( value );
168 }
else if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
169 return static_cast<Integer
>( value );
172 static_cast<T
>( ( std::numeric_limits<Integer>::max )( ) ) ) {
173 return static_cast<Integer
>( value );
180 using make_unsigned_with_bool_t =
181 typename make_unsigned_with_bool<T>::type;
185 [[nodiscard]]
static constexpr Unsigned
187 ParseState &parse_state ) {
188 using CharT =
typename ParseState::CharT;
190 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
192 max_unsigned_t<RangeChecked, make_unsigned_with_bool_t<Unsigned>,
195 not
static_cast<bool>( RangeChecked ) or
196 std::is_same_v<uresult_t, UInt64>,
197 "Range checking is only supported for std integral types" );
199 CharT *first = parse_state.first;
200 CharT *
const last = parse_state.last;
201 uresult_t result = uresult_t( );
203 while( last - first >= 16 ) {
204 result *=
static_cast<uresult_t
>( 10'000'000'000'000'000ULL );
205 result +=
static_cast<uresult_t
>( parse_16_digits( first ) );
208 if( last - first >= 8 ) {
209 result *=
static_cast<uresult_t
>( 100'000'000ULL );
210 result +=
static_cast<uresult_t
>( parse_8_digits( first ) );
214 auto dig = parse_digit( *first );
219 dig = parse_digit( *first );
222 while( first < last ) {
224 result += parse_digit( *first );
228 if constexpr( RangeChecked != options::JsonRangeCheck::Never ) {
229 auto const count = ( daw::numeric_limits<result_t>::digits10 + 1U ) -
230 std::size( parse_state );
232 ( ( result <=
static_cast<uresult_t
>(
233 ( daw::numeric_limits<result_t>::max )( ) ) ) &
235 ErrorReason::NumberOutOfRange, parse_state );
237 parse_state.first = first;
238 if constexpr( RangeChecked == options::JsonRangeCheck::Never ) {
239 return daw::construct_a<Unsigned>(
static_cast<Unsigned
>( result ) );
241 return daw::construct_a<Unsigned>(
242 narrow_cast<Unsigned>( result, parse_state ) );
249 [[nodiscard]]
static constexpr Unsigned
251 ParseState &parse_state ) {
252 using CharT =
typename ParseState::CharT;
254 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
256 max_unsigned_t<RangeChecked, make_unsigned_with_bool_t<Unsigned>,
259 not
static_cast<bool>( RangeChecked ) or
260 std::is_same_v<uresult_t, UInt64>,
261 "Range checking is only supported for std integral types" );
263 ErrorReason::UnexpectedEndOfData, parse_state );
264 CharT *first = parse_state.first;
265 CharT *
const orig_first = first;
267 CharT *
const last = parse_state.last;
268 uresult_t result = uresult_t( );
270 last - first >= 8 ? is_made_of_eight_digits_cx( first ) :
false;
271 if( has_eight & ( last - first >= 16 ) ) {
272 bool has_sixteen = is_made_of_eight_digits_cx( first + 8 );
273 while( has_sixteen ) {
274 result *=
static_cast<uresult_t
>( 10'000'000'000'000'000ULL );
275 result +=
static_cast<uresult_t
>( parse_16_digits( first ) );
278 last - first >= 8 ? is_made_of_eight_digits_cx( first ) :
false;
281 ( last - first >= 16 ? is_made_of_eight_digits_cx( first + 8 )
286 result *=
static_cast<uresult_t
>( 100'000'000ULL );
287 result +=
static_cast<uresult_t
>( parse_8_digits( first ) );
291 auto dig = parse_digit( *first );
296 dig = parse_digit( *first );
299 while( first < last ) {
300 auto const dig = parse_digit( *first );
310 if constexpr( RangeChecked != options::JsonRangeCheck::Never ) {
311 auto const count =
static_cast<std::ptrdiff_t
>(
312 daw::numeric_limits<result_t>::digits10 + 1 ) -
313 ( first - orig_first );
318 parse_state.first = first;
319 if constexpr( RangeChecked == options::JsonRangeCheck::Never ) {
320 return daw::construct_a<Unsigned>(
321 static_cast<Unsigned
>(
static_cast<result_t
>( result ) ) );
323 return daw::construct_a<Unsigned>(
324 narrow_cast<Unsigned>( result, parse_state ) );
328 #if false and defined( DAW_ALLOW_SSE42 )
444 bool KnownBounds,
typename ParseState>
445 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Unsigned
447 ParseState &parse_state ) {
448 if constexpr( KnownBounds ) {
449 return unsigned_parser_known<Unsigned, RangeChecked>( tag,
452 return unsigned_parser_not_known<Unsigned, RangeChecked>(
#define daw_json_assert_weak(Bool,...)
Assert that Bool is true when in Checked Input mode If false pass rest of args to daw_json_error.
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
std::bool_constant< is_zero_terminated_string_v< T > > is_zero_terminated_string
JsonRangeCheck
Control if narrowing checks are performed.
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.