in folly/Conv.cpp [540:637]
inline Expected<Tgt, ConversionCode> digits_to(
const char* b, const char* const e) noexcept {
using UT = make_unsigned_t<Tgt>;
assert(b <= e);
SignedValueHandler<Tgt> sgn;
auto err = sgn.init(b);
if (UNLIKELY(err != ConversionCode::SUCCESS)) {
return makeUnexpected(err);
}
auto size = size_t(e - b);
/* Although the string is entirely made of digits, we still need to
* check for overflow.
*/
if (size > std::numeric_limits<UT>::digits10) {
// Leading zeros?
if (b < e && *b == '0') {
for (++b;; ++b) {
if (b == e) {
return Tgt(0); // just zeros, e.g. "0000"
}
if (*b != '0') {
size = size_t(e - b);
break;
}
}
}
if (size > std::numeric_limits<UT>::digits10 &&
(size != std::numeric_limits<UT>::digits10 + 1 ||
strncmp(b, MaxString<UT>::value, size) > 0)) {
return makeUnexpected(sgn.overflow());
}
}
// Here we know that the number won't overflow when
// converted. Proceed without checks.
UT result = 0;
for (; e - b >= 4; b += 4) {
result *= UT(10000);
const int32_t r0 = shift1000[static_cast<size_t>(b[0])];
const int32_t r1 = shift100[static_cast<size_t>(b[1])];
const int32_t r2 = shift10[static_cast<size_t>(b[2])];
const int32_t r3 = shift1[static_cast<size_t>(b[3])];
const auto sum = r0 + r1 + r2 + r3;
if (sum >= OOR) {
goto outOfRange;
}
result += UT(sum);
}
switch (e - b) {
case 3: {
const int32_t r0 = shift100[static_cast<size_t>(b[0])];
const int32_t r1 = shift10[static_cast<size_t>(b[1])];
const int32_t r2 = shift1[static_cast<size_t>(b[2])];
const auto sum = r0 + r1 + r2;
if (sum >= OOR) {
goto outOfRange;
}
result = UT(1000 * result + sum);
break;
}
case 2: {
const int32_t r0 = shift10[static_cast<size_t>(b[0])];
const int32_t r1 = shift1[static_cast<size_t>(b[1])];
const auto sum = r0 + r1;
if (sum >= OOR) {
goto outOfRange;
}
result = UT(100 * result + sum);
break;
}
case 1: {
const int32_t sum = shift1[static_cast<size_t>(b[0])];
if (sum >= OOR) {
goto outOfRange;
}
result = UT(10 * result + sum);
break;
}
default:
assert(b == e);
if (size == 0) {
return makeUnexpected(ConversionCode::NO_DIGITS);
}
break;
}
return sgn.finalize(result);
outOfRange:
return makeUnexpected(ConversionCode::NON_DIGIT_CHAR);
}