33 namespace json_details {
34 template<
typename Signed,
typename Un
signed>
35 DAW_ATTRIB_INLINE
constexpr Signed to_signed( Unsigned &&u,
37 if( sign <= Signed{ 0 } ) {
38 return static_cast<Signed
>( -u );
40 return static_cast<Signed
>( u );
45 is_made_of_eight_digits_cx( daw::not_null<char const *>
const ptr ) {
49 auto const val = daw::to_uint64_buffer( ptr.get( ) );
50 return ( ( ( val & daw::UInt64{0xF0F0'F0F0'F0F0'F0F0ULL} ) |
51 ( ( ( val + daw::UInt64{0x0606'0606'0606'0606ULL} ) &
52 daw::UInt64{0xF0F0'F0F0'F0F0'F0F0ULL} ) >>
53 4U ) ) == daw::UInt64{0x3333'3333'3333'3333ULL} );
56 template<options::JsonRangeCheck RangeCheck,
typename Unsigned,
57 typename MaxArithUnsigned>
58 using max_unsigned_t = daw::conditional_t<
59 daw::is_integral_v<Unsigned> or std::is_enum_v<Unsigned>,
60 daw::conditional_t<(
sizeof( Unsigned ) >
sizeof( MaxArithUnsigned ) ),
61 Unsigned, MaxArithUnsigned>,
66 constexpr UInt64 parse_8_digits( daw::not_null<char const *>
const str ) {
67 auto const chunk = daw::to_uint64_buffer( str.get( ) );
69 auto const lower_digits =
70 ( chunk & daw::UInt64{0x0F'00'0F'00'0F'00'0F'00ULL} ) >> 8U;
71 auto const upper_digits =
72 ( chunk & daw::UInt64{0x00'0F'00'0F'00'0F'00'0FULL} ) * 10U;
73 auto const chunk2 = lower_digits + upper_digits;
76 auto const lower_digits2 =
77 ( chunk2 & daw::UInt64{0x00'FF'00'00'00'FF'00'00ULL} ) >> 16U;
78 auto const upper_digits2 =
79 ( chunk2 & daw::UInt64{0x00'00'00'FF'00'00'00'FFULL} ) * 100U;
80 auto const chunk3 = lower_digits2 + upper_digits2;
83 auto const lower_digits3 =
84 ( chunk3 & daw::UInt64{0x00'00'FF'FF'00'00'00'00ULL} ) >> 32U;
85 auto const upper_digits3 =
86 ( chunk3 & daw::UInt64{0x00'00'00'00'00'00'FF'FFULL} ) * 10000U;
87 auto const chunk4 = lower_digits3 + upper_digits3;
89 return chunk4 & daw::UInt64{0xFFFF'FFFFULL};
92 static_assert( parse_8_digits(
"12345678" ) == daw::UInt64{1234'5678},
93 "8 digit parser does not work on this platform" );
96 parse_16_digits( daw::not_null<char const *>
const str ) {
97 auto const upper = parse_8_digits( str );
98 auto const lower = parse_8_digits( str + 8 );
99 return upper * daw::UInt64{100'000'000ULL} + lower;
102 static_assert( parse_16_digits(
"1234567890123456" ) ==
103 daw::UInt64{1234567890123456ULL},
104 "16 digit parser does not work on this platform" );
107 struct make_unsigned_with_bool : daw::make_unsigned<T> {};
110 struct make_unsigned_with_bool<bool> {
114 template<
typename Integer,
typename T,
typename ParseState>
115 [[nodiscard]]
constexpr Integer
116 narrow_cast( T value, ParseState
const &parse_state ) {
117 if constexpr( std::is_signed_v<T> ) {
118 if constexpr( std::is_signed_v<Integer> ) {
119 if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
121 }
else if( value <=
static_cast<T
>( daw::max_value<Integer> ) ) {
122 return static_cast<Integer
>( value );
125 true, ErrorReason::NumberOutOfRange, parse_state );
127 }
else if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
131 daw_json_error(
true, ErrorReason::NumberOutOfRange, parse_state );
134 value <=
static_cast<T
>( daw::max_value<Integer> ) ) {
137 daw_json_error(
true, ErrorReason::NumberOutOfRange, parse_state );
139 }
else if constexpr( std::is_signed_v<Integer> ) {
140 if constexpr(
sizeof( T ) <
sizeof( Integer ) ) {
141 return static_cast<Integer
>( value );
143 if( value >
static_cast<T
>( daw::max_value<Integer> ) ) {
145 true, ErrorReason::NumberOutOfRange, parse_state );
147 return static_cast<Integer
>( value );
149 }
else if constexpr(
sizeof( T ) <=
sizeof( Integer ) ) {
150 return static_cast<Integer
>( value );
152 if( value <=
static_cast<T
>( daw::max_value<Integer> ) ) {
153 return static_cast<Integer
>( value );
155 daw_json_error(
true, ErrorReason::NumberOutOfRange, parse_state );
160 using make_unsigned_with_bool_t =
161 typename make_unsigned_with_bool<T>::type;
163 template<
typename Unsigned, options::JsonRangeCheck RangeChecked,
165 [[nodiscard]]
static constexpr Unsigned
166 unsigned_parser_known( ParseState &parse_state ) {
168 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
169 using uresult_t = max_unsigned_t<RangeChecked,
170 make_unsigned_with_bool_t<Unsigned>,
173 not
static_cast<bool>( RangeChecked ) or
174 std::is_same_v<uresult_t, UInt64>,
175 "Range checking is only supported for std integral types" );
177 daw::not_null<char const *> first = parse_state.first;
178 daw::not_null<char const *>
const last = parse_state.last;
179 uresult_t result = uresult_t( );
181 while( last - first >= 16 ) {
182 result *=
static_cast<uresult_t
>( 10'000'000'000'000'000ULL );
183 result +=
static_cast<uresult_t
>( parse_16_digits( first ) );
186 if( last - first >= 8 ) {
187 result *=
static_cast<uresult_t
>( 100'000'000ULL );
188 result +=
static_cast<uresult_t
>( parse_8_digits( first ) );
191 if constexpr( ParseState::is_zero_terminated_string ) {
192 auto dig = parse_digit( *first );
197 dig = parse_digit( *first );
200 while( first < last ) {
202 result += parse_digit( *first );
206 if constexpr( RangeChecked != options::JsonRangeCheck::Never ) {
208 ( daw::digits10<result_t> + 1U ) - std::size( parse_state );
210 ( ( result <=
static_cast<uresult_t
>( daw::max_value<result_t> ) ) &
212 ErrorReason::NumberOutOfRange,
215 if constexpr( std::is_same_v<
char const *,
216 typename ParseState::iterator> ) {
217 parse_state.first = first;
219 parse_state.first += first.get( ) - parse_state.first;
221 if constexpr( RangeChecked == options::JsonRangeCheck::Never ) {
222 return daw::construct_a<Unsigned>(
static_cast<Unsigned
>( result ) );
224 return daw::construct_a<Unsigned>(
225 narrow_cast<Unsigned>( result, parse_state ) );
230 template<
typename Unsigned, options::JsonRangeCheck RangeChecked,
232 [[nodiscard]]
static constexpr Unsigned
233 unsigned_parser_not_known( ParseState &parse_state ) {
235 using result_t = max_unsigned_t<RangeChecked, Unsigned, UInt64>;
236 using uresult_t = max_unsigned_t<RangeChecked,
237 make_unsigned_with_bool_t<Unsigned>,
240 not
static_cast<bool>( RangeChecked ) or
241 std::is_same_v<uresult_t, UInt64>,
242 "Range checking is only supported for std integral types" );
244 ErrorReason::UnexpectedEndOfData,
246 daw::not_null<char const *> first = parse_state.first;
247 auto const orig_first = first;
249 daw::not_null<char const *>
const last = parse_state.last;
250 uresult_t result = uresult_t( );
252 last - first >= 8 ? is_made_of_eight_digits_cx( first ) :
false;
253 if( has_eight & ( last - first >= 16 ) ) {
254 bool has_sixteen = is_made_of_eight_digits_cx( first + 8 );
255 while( has_sixteen ) {
256 result *=
static_cast<uresult_t
>( 10'000'000'000'000'000ULL );
257 result +=
static_cast<uresult_t
>( parse_16_digits( first ) );
260 last - first >= 8 ? is_made_of_eight_digits_cx( first ) :
false;
263 ( last - first >= 16 ? is_made_of_eight_digits_cx( first + 8 )
268 result *=
static_cast<uresult_t
>( 100'000'000ULL );
269 result +=
static_cast<uresult_t
>( parse_8_digits( first ) );
272 if constexpr( ParseState::is_zero_terminated_string ) {
273 auto dig = parse_digit( *first );
278 dig = parse_digit( *first );
281 while( first < last ) {
282 auto const dig = parse_digit( *first );
292 if constexpr( RangeChecked != options::JsonRangeCheck::Never ) {
294 static_cast<std::ptrdiff_t
>( daw::digits10<result_t> + 1 ) -
295 ( first - orig_first );
297 count >= 0, ErrorReason::NumberOutOfRange, parse_state );
300 if constexpr( std::is_same_v<
char const *,
301 typename ParseState::iterator> ) {
302 parse_state.first = first;
304 parse_state.first += first.get( ) - parse_state.first;
306 if constexpr( RangeChecked == options::JsonRangeCheck::Never ) {
307 return daw::construct_a<Unsigned>(
308 static_cast<Unsigned
>(
static_cast<result_t
>( result ) ) );
310 return daw::construct_a<Unsigned>(
311 narrow_cast<Unsigned>( result, parse_state ) );
315 template<
typename Unsigned, options::JsonRangeCheck RangeChecked,
316 bool KnownBounds,
typename ParseState>
317 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr Unsigned
318 unsigned_parser( ParseState &parse_state ) {
319 if constexpr( KnownBounds ) {
320 return unsigned_parser_known<Unsigned, RangeChecked>( parse_state );
322 return unsigned_parser_not_known<Unsigned, RangeChecked>(