43 namespace json_details {
44 template<
typename Signed,
typename Un
signed>
45 DAW_ATTRIB_INLINE
constexpr Signed to_signed( Unsigned &&u,
47 if( sign <= Signed{ 0 } ) {
48 return static_cast<Signed
>( -u );
50 return static_cast<Signed
>( u );
55 is_made_of_eight_digits_cx( daw::not_null<char const *>
const ptr ) {
59 std::byte
const buff[8]{
static_cast<std::byte
>( ptr[0] ),
60 static_cast<std::byte
>( ptr[1] ),
61 static_cast<std::byte
>( ptr[2] ),
62 static_cast<std::byte
>( ptr[3] ),
63 static_cast<std::byte
>( ptr[4] ),
64 static_cast<std::byte
>( ptr[5] ),
65 static_cast<std::byte
>( ptr[6] ),
66 static_cast<std::byte
>( ptr[7] ) };
69 for( std::size_t n = 0; n < 8; ++n ) {
70 val |= to_uint64( buff[n] ) << ( 8 * n );
72 return ( ( ( val & 0xF0F0'F0F0'F0F0'F0F0_u64 ) |
73 ( ( ( val + 0x0606'0606'0606'0606_u64 ) &
74 0xF0F0'F0F0'F0F0'F0F0_u64 ) >>
75 4U ) ) == 0x3333'3333'3333'3333_u64 );
78 template<options::JsonRangeCheck RangeCheck,
typename Unsigned,
79 typename MaxArithUnsigned>
80 using max_unsigned_t = daw::conditional_t<
81 daw::is_integral_v<Unsigned> or std::is_enum_v<Unsigned>,
82 daw::conditional_t<(
sizeof( Unsigned ) >
sizeof( MaxArithUnsigned ) ),
83 Unsigned, MaxArithUnsigned>,
88 constexpr UInt64 parse_8_digits( daw::not_null<char const *>
const str ) {
89 auto const chunk = daw::to_uint64_buffer( str.get( ) );
91 auto const lower_digits =
92 ( chunk & 0x0F'00'0F'00'0F'00'0F'00_u64 ) >> 8U;
93 auto const upper_digits =
94 ( chunk & 0x00'0F'00'0F'00'0F'00'0F_u64 ) * 10U;
95 auto const chunk2 = lower_digits + upper_digits;
98 auto const lower_digits2 =
99 ( chunk2 & 0x00'FF'00'00'00'FF'00'00_u64 ) >> 16U;
100 auto const upper_digits2 =
101 ( chunk2 & 0x00'00'00'FF'00'00'00'FF_u64 ) * 100U;
102 auto const chunk3 = lower_digits2 + upper_digits2;
105 auto const lower_digits3 =
106 ( chunk3 & 0x00'00'FF'FF'00'00'00'00_u64 ) >> 32U;
107 auto const upper_digits3 =
108 ( chunk3 & 0x00'00'00'00'00'00'FF'FF_u64 ) * 10000U;
109 auto const chunk4 = lower_digits3 + upper_digits3;
111 return chunk4 & 0xFFFF'FFFF_u64;
114 static_assert( parse_8_digits(
"12345678" ) == 1234'5678_u64,
115 "8 digit parser does not work on this platform" );
118 parse_16_digits( daw::not_null<char const *>
const str ) {
119 auto const upper = parse_8_digits( str );
120 auto const lower = parse_8_digits( str + 8 );
121 return upper * 100'000'000_u64 + lower;
124 static_assert( parse_16_digits(
"1234567890123456" ) ==
125 1234567890123456_u64,
126 "16 digit parser does not work on this platform" );
129 struct make_unsigned_with_bool : daw::make_unsigned<T> {};
132 struct make_unsigned_with_bool<bool> {
136 template<
typename Integer,
typename T,
typename ParseState>
137 [[nodiscard]]
constexpr Integer
138 narrow_cast( T value, ParseState
const &parse_state ) {
139 if constexpr( std::is_signed_v<T> ) {
140 if constexpr( std::is_signed_v<Integer> ) {
141 if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
143 }
else if( value <=
static_cast<T
>( daw::max_value<Integer> ) ) {
144 return static_cast<Integer
>( value );
148 }
else if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
155 value <=
static_cast<T
>( daw::max_value<Integer> ) ) {
160 }
else if constexpr( std::is_signed_v<Integer> ) {
161 if constexpr(
sizeof( T ) <
sizeof( Integer ) ) {
162 return static_cast<Integer
>( value );
164 if( value >
static_cast<T
>( daw::max_value<Integer> ) ) {
167 return static_cast<Integer
>( value );
169 }
else if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
170 return static_cast<Integer
>( value );
172 if( value <=
static_cast<T
>( daw::max_value<Integer> ) ) {
173 return static_cast<Integer
>( value );
180 using make_unsigned_with_bool_t =
181 typename make_unsigned_with_bool<T>::type;
183 template<
typename Unsigned, options::JsonRangeCheck RangeChecked,
185 [[nodiscard]]
static constexpr Unsigned
186 unsigned_parser_known( ParseState &parse_state ) {
188 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
189 using uresult_t = max_unsigned_t<RangeChecked,
190 make_unsigned_with_bool_t<Unsigned>,
193 not
static_cast<bool>( RangeChecked ) or
194 std::is_same_v<uresult_t, UInt64>,
195 "Range checking is only supported for std integral types" );
197 daw::not_null<char const *> first = parse_state.first;
198 daw::not_null<char const *>
const last = parse_state.last;
199 uresult_t result = uresult_t( );
201 while( last - first >= 16 ) {
202 result *=
static_cast<uresult_t
>( 10'000'000'000'000'000ULL );
203 result +=
static_cast<uresult_t
>( parse_16_digits( first ) );
206 if( last - first >= 8 ) {
207 result *=
static_cast<uresult_t
>( 100'000'000ULL );
208 result +=
static_cast<uresult_t
>( parse_8_digits( first ) );
211 if constexpr( ParseState::is_zero_terminated_string ) {
212 auto dig = parse_digit( *first );
217 dig = parse_digit( *first );
220 while( first < last ) {
222 result += parse_digit( *first );
226 if constexpr( RangeChecked != options::JsonRangeCheck::Never ) {
227 auto const count = ( daw::numeric_limits<result_t>::digits10 + 1U ) -
228 std::size( parse_state );
230 ( ( result <=
static_cast<uresult_t
>(
231 ( daw::numeric_limits<result_t>::max )( ) ) ) &
233 ErrorReason::NumberOutOfRange,
236 parse_state.first = first;
237 if constexpr( RangeChecked == options::JsonRangeCheck::Never ) {
238 return daw::construct_a<Unsigned>(
static_cast<Unsigned
>( result ) );
240 return daw::construct_a<Unsigned>(
241 narrow_cast<Unsigned>( result, parse_state ) );
246 template<
typename Unsigned, options::JsonRangeCheck RangeChecked,
248 [[nodiscard]]
static constexpr Unsigned
249 unsigned_parser_not_known( ParseState &parse_state ) {
251 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
252 using uresult_t = max_unsigned_t<RangeChecked,
253 make_unsigned_with_bool_t<Unsigned>,
256 not
static_cast<bool>( RangeChecked ) or
257 std::is_same_v<uresult_t, UInt64>,
258 "Range checking is only supported for std integral types" );
260 ErrorReason::UnexpectedEndOfData,
262 daw::not_null<char const *> first = parse_state.first;
263 auto const orig_first = first;
265 daw::not_null<char const *>
const last = parse_state.last;
266 uresult_t result = uresult_t( );
268 last - first >= 8 ? is_made_of_eight_digits_cx( first ) :
false;
269 if( has_eight & ( last - first >= 16 ) ) {
270 bool has_sixteen = is_made_of_eight_digits_cx( first + 8 );
271 while( has_sixteen ) {
272 result *=
static_cast<uresult_t
>( 10'000'000'000'000'000ULL );
273 result +=
static_cast<uresult_t
>( parse_16_digits( first ) );
276 last - first >= 8 ? is_made_of_eight_digits_cx( first ) :
false;
279 ( last - first >= 16 ? is_made_of_eight_digits_cx( first + 8 )
284 result *=
static_cast<uresult_t
>( 100'000'000ULL );
285 result +=
static_cast<uresult_t
>( parse_8_digits( first ) );
288 if constexpr( ParseState::is_zero_terminated_string ) {
289 auto dig = parse_digit( *first );
294 dig = parse_digit( *first );
297 while( first < last ) {
298 auto const dig = parse_digit( *first );
308 if constexpr( RangeChecked != options::JsonRangeCheck::Never ) {
309 auto const count =
static_cast<std::ptrdiff_t
>(
310 daw::numeric_limits<result_t>::digits10 + 1 ) -
311 ( first - orig_first );
313 count >= 0, ErrorReason::NumberOutOfRange, parse_state );
316 parse_state.first = first;
317 if constexpr( RangeChecked == options::JsonRangeCheck::Never ) {
318 return daw::construct_a<Unsigned>(
319 static_cast<Unsigned
>(
static_cast<result_t
>( result ) ) );
321 return daw::construct_a<Unsigned>(
322 narrow_cast<Unsigned>( result, parse_state ) );
326#if false and defined( DAW_ALLOW_SSE42 )
441 template<
typename Unsigned, options::JsonRangeCheck RangeChecked,
442 bool KnownBounds,
typename ParseState>
443 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Unsigned
444 unsigned_parser( ParseState &parse_state ) {
445 if constexpr( KnownBounds ) {
446 return unsigned_parser_known<Unsigned, RangeChecked>( parse_state );
448 return unsigned_parser_not_known<Unsigned, RangeChecked>(