bool safe_int_internal()

in src/kudu/gutil/strings/numbers.cc [545:663]


bool safe_int_internal(const char* start, const char* end, int base,
                       IntType* value_p) {
  // Consume whitespace.
  while (start < end && ascii_isspace(start[0])) {
    ++start;
  }
  while (start < end && ascii_isspace(end[-1])) {
    --end;
  }
  if (start >= end) {
    return false;
  }

  // Consume sign.
  const bool negative = (start[0] == '-');
  if (negative || start[0] == '+') {
    ++start;
    if (start >= end) {
      return false;
    }
  }

  // Consume base-dependent prefix.
  //  base 0: "0x" -> base 16, "0" -> base 8, default -> base 10
  //  base 16: "0x" -> base 16
  // Also validate the base.
  if (base == 0) {
    if (end - start >= 2 && start[0] == '0' &&
        (start[1] == 'x' || start[1] == 'X')) {
      base = 16;
      start += 2;
    } else if (end - start >= 1 && start[0] == '0') {
      base = 8;
      start += 1;
    } else {
      base = 10;
    }
  } else if (base == 16) {
    if (end - start >= 2 && start[0] == '0' &&
        (start[1] == 'x' || start[1] == 'X')) {
      start += 2;
    }
  } else if (base >= 2 && base <= 36) {
    // okay
  } else {
    return false;
  }

  // Consume digits.
  //
  // The classic loop:
  //
  //   for each digit
  //     value = value * base + digit
  //   value *= sign
  //
  // The classic loop needs overflow checking.  It also fails on the most
  // negative integer, -2147483648 in 32-bit two's complement representation.
  //
  // My improved loop:
  //
  //  if (!negative)
  //    for each digit
  //      value = value * base
  //      value = value + digit
  //  else
  //    for each digit
  //      value = value * base
  //      value = value - digit
  //
  // Overflow checking becomes simple.
  //
  // I present the positive code first for easier reading.
  IntType value = 0;
  if (!negative) {
    const IntType vmax = std::numeric_limits<IntType>::max();
    assert(vmax > 0);
    assert(vmax >= base);
    const IntType vmax_over_base = vmax / base;
    // loop over digits
    // loop body is interleaved for perf, not readability
    for (; start < end; ++start) {
      unsigned char c = static_cast<unsigned char>(start[0]);
      int digit = kAsciiToInt[c];
      if (value > vmax_over_base) return false;
      value *= base;
      if (digit >= base) return false;
      if (value > vmax - digit) return false;
      value += digit;
    }
  } else {
    const IntType vmin = std::numeric_limits<IntType>::min();
    assert(vmin < 0);
    assert(vmin <= 0 - base);
    IntType vmin_over_base = vmin / base;
    // 2003 c++ standard [expr.mul]
    // "... the sign of the remainder is implementation-defined."
    // Although (vmin/base)*base + vmin%base is always vmin.
    // 2011 c++ standard tightens the spec but we cannot rely on it.
    if (vmin % base > 0) {
      vmin_over_base += 1;
    }
    // loop over digits
    // loop body is interleaved for perf, not readability
    for (; start < end; ++start) {
      unsigned char c = static_cast<unsigned char>(start[0]);
      int digit = kAsciiToInt[c];
      if (value < vmin_over_base) return false;
      value *= base;
      if (digit >= base) return false;
      if (value < vmin + digit) return false;
      value -= digit;
    }
  }

  // Store output.
  *value_p = value;
  return true;
}