inline Expected digits_to()

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);
}