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