AZ_NODISCARD az_result az_span_atoi64()

in sdk/src/azure/core/az_span.c [209:277]


AZ_NODISCARD az_result az_span_atoi64(az_span source, int64_t* out_number)
{
  _az_PRECONDITION_VALID_SPAN(source, 1, false);
  _az_PRECONDITION_NOT_NULL(out_number);

  int32_t const span_size = az_span_size(source);

  if (span_size < 1)
  {
    return AZ_ERROR_UNEXPECTED_CHAR;
  }

  // If the first character is not a digit, - sign, or an optional + sign, return error.
  int32_t starting_index = 0;
  uint8_t* source_ptr = az_span_ptr(source);
  uint8_t next_byte = source_ptr[0];
  int64_t sign = 1;

  if (!isdigit(next_byte))
  {
    // There must be another byte after a sign.
    // The loop below checks that it must be a digit.
    if (next_byte != '+')
    {
      if (next_byte != '-')
      {
        return AZ_ERROR_UNEXPECTED_CHAR;
      }
      sign = -1;
    }
    if (span_size < 2)
    {
      return AZ_ERROR_UNEXPECTED_CHAR;
    }
    starting_index++;
  }

  // if sign < 0, (-1 * sign + 1) / 2 = 1
  // else, (-1 * sign + 1) / 2 = 0
  // This is necessary to correctly account for the fact that the absolute value of INT64_MIN is 1
  // more than than the absolute value of INT64_MAX.
  uint64_t sign_factor = (uint64_t)(-1 * sign + 1) / 2;

  // Using unsigned int while parsing to account for potential overflow.
  uint64_t value = 0;

  for (int32_t i = starting_index; i < span_size; ++i)
  {
    next_byte = source_ptr[i];
    if (!isdigit(next_byte))
    {
      return AZ_ERROR_UNEXPECTED_CHAR;
    }
    uint64_t const d = (uint64_t)next_byte - '0';

    // Check whether the next digit will cause an integer overflow.
    // Before actually doing the math below, this is checking whether value * 10 + d > INT64_MAX, or
    // in the case of negative numbers, checking whether value * 10 + d > INT64_MAX + 1.
    if ((uint64_t)(INT64_MAX - d + sign_factor) / _az_NUMBER_OF_DECIMAL_VALUES < value)
    {
      return AZ_ERROR_UNEXPECTED_CHAR;
    }

    value = value * _az_NUMBER_OF_DECIMAL_VALUES + d;
  }

  *out_number = (int64_t)value * sign;
  return AZ_OK;
}