Skip to content

Commit 2b208cd

Browse files
committed
uint8_t parsing
Signed-off-by: Shikhar <[email protected]>
1 parent 62fb615 commit 2b208cd

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

include/fast_float/ascii_number.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,92 @@ parse_int_string(UC const *p, UC const *pend, T &value,
509509

510510
UC const *const start_digits = p;
511511

512+
if constexpr (std::is_same_v<T, std::uint8_t>) {
513+
const size_t len = (size_t)(pend - p);
514+
if (len == 0) {
515+
if (has_leading_zeros) {
516+
value = 0;
517+
answer.ec = std::errc();
518+
answer.ptr = p;
519+
} else {
520+
answer.ec = std::errc::invalid_argument;
521+
answer.ptr = first;
522+
}
523+
return answer;
524+
}
525+
526+
union {
527+
uint8_t as_str[4];
528+
uint32_t as_int;
529+
} digits;
530+
531+
if (cpp20_and_in_constexpr()) {
532+
digits.as_int = 0;
533+
for (size_t j = 0; j < 4 && j < len; ++j) {
534+
digits.as_str[j] = static_cast<uint8_t>(p[j]);
535+
}
536+
} else if (len >= 4) {
537+
memcpy(&digits.as_int, p, 4);
538+
} else {
539+
uint32_t b0 = static_cast<uint8_t>(p[0]);
540+
uint32_t b1 = (len > 1) ? static_cast<uint8_t>(p[1]) : 0xFFu;
541+
uint32_t b2 = (len > 2) ? static_cast<uint8_t>(p[2]) : 0xFFu;
542+
uint32_t b3 = 0xFFu;
543+
#if FASTFLOAT_IS_BIG_ENDIAN
544+
digits.as_int = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
545+
#else
546+
digits.as_int = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
547+
#endif
548+
}
549+
550+
uint32_t magic =
551+
((digits.as_int + 0x46464646u) | (digits.as_int - 0x30303030u)) &
552+
0x80808080u;
553+
uint32_t tz = (uint32_t)std::__countr_zero(magic); // 7, 15, 23, 31, or 32
554+
uint32_t nd = (tz == 32) ? 4 : (tz >> 3);
555+
nd = (uint32_t)std::min((size_t)nd, len);
556+
if (nd == 0) {
557+
if (has_leading_zeros) {
558+
value = 0;
559+
answer.ec = std::errc();
560+
answer.ptr = p;
561+
return answer;
562+
}
563+
answer.ec = std::errc::invalid_argument;
564+
answer.ptr = first;
565+
return answer;
566+
}
567+
if (nd > 3) {
568+
const UC *q = p + nd;
569+
size_t rem = len - nd;
570+
while (rem) {
571+
if (*q < UC('0') || *q > UC('9'))
572+
break;
573+
++q;
574+
--rem;
575+
}
576+
answer.ec = std::errc::result_out_of_range;
577+
answer.ptr = q;
578+
return answer;
579+
}
580+
581+
digits.as_int ^= 0x30303030u;
582+
digits.as_int <<= ((4 - nd) * 8);
583+
584+
uint32_t check = ((digits.as_int >> 24) & 0xff) |
585+
((digits.as_int >> 8) & 0xff00) |
586+
((digits.as_int << 8) & 0xff0000);
587+
if (check > 0x00020505) {
588+
answer.ec = std::errc::result_out_of_range;
589+
answer.ptr = p + nd;
590+
return answer;
591+
}
592+
value = (uint8_t)((0x640a01 * digits.as_int) >> 24);
593+
answer.ec = std::errc();
594+
answer.ptr = p + nd;
595+
return answer;
596+
}
597+
512598
uint64_t i = 0;
513599
if (base == 10) {
514600
loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible

0 commit comments

Comments
 (0)