#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/dyadic_float.h"
#include "src/__support/FPUtil/rounding_mode.h"
#include "src/__support/common.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/detailed_powers_of_ten.h"
#include "src/__support/high_precision_decimal.h"
#include "src/__support/macros/config.h"
#include "src/__support/str_to_integer.h"
#include "src/__support/str_to_num_result.h"
#include "src/__support/uint128.h"
#include "src/errno/libc_errno.h"
namespace LIBC_NAMESPACE_DECL {
namespace internal {
template <class T> struct ExpandedFloat {
typename fputil::FPBits<T>::StorageType mantissa;
int32_t exponent;
};
template <class T> struct FloatConvertReturn {
ExpandedFloat<T> num = {0, 0};
int error = 0;
};
LIBC_INLINE uint64_t low64(const UInt128 &num) {
return static_cast<uint64_t>(num & 0xffffffffffffffff);
}
LIBC_INLINE uint64_t high64(const UInt128 &num) {
return static_cast<uint64_t>(num >> 64);
}
template <class T> LIBC_INLINE void set_implicit_bit(fputil::FPBits<T> &) {
return;
}
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
template <>
LIBC_INLINE void
set_implicit_bit<long double>(fputil::FPBits<long double> &result) {
result.set_implicit_bit(result.get_biased_exponent() != 0);
}
#endif
template <class T>
LIBC_INLINE cpp::optional<ExpandedFloat<T>>
eisel_lemire(ExpandedFloat<T> init_num,
RoundDirection round = RoundDirection::Nearest) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
StorageType mantissa = init_num.mantissa;
int32_t exp10 = init_num.exponent;
if (sizeof(T) > 8) {
return cpp::nullopt;
}
if (exp10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 ||
exp10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) {
return cpp::nullopt;
}
uint32_t clz = cpp::countl_zero<StorageType>(mantissa);
mantissa <<= clz;
int32_t exp2 =
exp10_to_exp2(exp10) + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - clz;
const uint64_t *power_of_ten =
DETAILED_POWERS_OF_TEN[exp10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10];
UInt128 first_approx =
static_cast<UInt128>(mantissa) * static_cast<UInt128>(power_of_ten[1]);
UInt128 final_approx;
const uint64_t halfway_constant =
(uint64_t(1) << (FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3))) - 1;
if ((high64(first_approx) & halfway_constant) == halfway_constant &&
low64(first_approx) + mantissa < mantissa) {
UInt128 low_bits =
static_cast<UInt128>(mantissa) * static_cast<UInt128>(power_of_ten[0]);
UInt128 second_approx =
first_approx + static_cast<UInt128>(high64(low_bits));
if ((high64(second_approx) & halfway_constant) == halfway_constant &&
low64(second_approx) + 1 == 0 &&
low64(low_bits) + mantissa < mantissa) {
return cpp::nullopt;
}
final_approx = second_approx;
} else {
final_approx = first_approx;
}
StorageType msb = static_cast<StorageType>(high64(final_approx) >>
(FPBits::STORAGE_LEN - 1));
StorageType final_mantissa = static_cast<StorageType>(
high64(final_approx) >>
(msb + FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3)));
exp2 -= static_cast<uint32_t>(1 ^ msb);
if (round == RoundDirection::Nearest) {
if (low64(final_approx) == 0 &&
(high64(final_approx) & halfway_constant) == 0 &&
(final_mantissa & 3) == 1) {
return cpp::nullopt;
}
final_mantissa += final_mantissa & 1;
} else if (round == RoundDirection::Up) {
if (low64(final_approx) > 0 ||
(high64(final_approx) & halfway_constant) > 0) {
final_mantissa += 2;
}
}
final_mantissa >>= 1;
if ((final_mantissa >> (FPBits::FRACTION_LEN + 1)) > 0) {
final_mantissa >>= 1;
++exp2;
}
if (static_cast<uint32_t>(exp2) - 1 >= (1 << FPBits::EXP_LEN) - 2) {
return cpp::nullopt;
}
ExpandedFloat<T> output;
output.mantissa = final_mantissa;
output.exponent = exp2;
return output;
}
#if !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
template <>
LIBC_INLINE cpp::optional<ExpandedFloat<long double>>
eisel_lemire<long double>(ExpandedFloat<long double> init_num,
RoundDirection round) {
using FPBits = typename fputil::FPBits<long double>;
using StorageType = typename FPBits::StorageType;
StorageType mantissa = init_num.mantissa;
int32_t exp10 = init_num.exponent;
if (exp10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 ||
exp10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) {
return cpp::nullopt;
}
uint32_t clz = cpp::countl_zero<StorageType>(mantissa);
mantissa <<= clz;
int32_t exp2 =
exp10_to_exp2(exp10) + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - clz;
const uint64_t *power_of_ten =
DETAILED_POWERS_OF_TEN[exp10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10];
UInt128 approx_upper = static_cast<UInt128>(high64(mantissa)) *
static_cast<UInt128>(power_of_ten[1]);
UInt128 approx_middle_a = static_cast<UInt128>(high64(mantissa)) *
static_cast<UInt128>(power_of_ten[0]);
UInt128 approx_middle_b = static_cast<UInt128>(low64(mantissa)) *
static_cast<UInt128>(power_of_ten[1]);
UInt128 approx_middle = approx_middle_a + approx_middle_b;
approx_upper += (approx_middle < approx_middle_a) ? UInt128(1) << 64 : 0;
UInt128 approx_lower = static_cast<UInt128>(low64(mantissa)) *
static_cast<UInt128>(power_of_ten[0]);
UInt128 final_approx_lower =
approx_lower + (static_cast<UInt128>(low64(approx_middle)) << 64);
UInt128 final_approx_upper = approx_upper + high64(approx_middle) +
(final_approx_lower < approx_lower ? 1 : 0);
constexpr UInt128 HALFWAY_CONSTANT =
(UInt128(1) << (FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3))) - 1;
if ((final_approx_upper & HALFWAY_CONSTANT) == HALFWAY_CONSTANT &&
final_approx_lower + mantissa < mantissa) {
return cpp::nullopt;
}
uint32_t msb =
static_cast<uint32_t>(final_approx_upper >> (FPBits::STORAGE_LEN - 1));
StorageType final_mantissa =
final_approx_upper >>
(msb + FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3));
exp2 -= static_cast<uint32_t>(1 ^ msb);
if (round == RoundDirection::Nearest) {
if (final_approx_lower == 0 &&
(final_approx_upper & HALFWAY_CONSTANT) == 0 &&
(final_mantissa & 3) == 1) {
return cpp::nullopt;
}
final_mantissa += final_mantissa & 1;
} else if (round == RoundDirection::Up) {
if (final_approx_lower > 0 || (final_approx_upper & HALFWAY_CONSTANT) > 0) {
final_mantissa += 2;
}
}
final_mantissa >>= 1;
if ((final_mantissa >> (FPBits::FRACTION_LEN + 1)) > 0) {
final_mantissa >>= 1;
++exp2;
}
if (exp2 - 1 >= (1 << FPBits::EXP_LEN) - 2) {
return cpp::nullopt;
}
ExpandedFloat<long double> output;
output.mantissa = final_mantissa;
output.exponent = exp2;
return output;
}
#endif
constexpr uint8_t POWERS_OF_TWO[19] = {
0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59,
};
constexpr int32_t NUM_POWERS_OF_TWO =
sizeof(POWERS_OF_TWO) / sizeof(POWERS_OF_TWO[0]);
template <class T>
LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion(
const char *__restrict numStart,
const size_t num_len = cpp::numeric_limits<size_t>::max(),
RoundDirection round = RoundDirection::Nearest) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
int32_t exp2 = 0;
HighPrecisionDecimal hpd = HighPrecisionDecimal(numStart, num_len);
FloatConvertReturn<T> output;
if (hpd.get_num_digits() == 0) {
output.num = {0, 0};
return output;
}
if (hpd.get_decimal_point() > 0 &&
exp10_to_exp2(hpd.get_decimal_point() - 1) > FPBits::EXP_BIAS) {
output.num = {0, fputil::FPBits<T>::MAX_BIASED_EXPONENT};
output.error = ERANGE;
return output;
}
if (hpd.get_decimal_point() < 0 &&
exp10_to_exp2(-hpd.get_decimal_point()) >
(FPBits::EXP_BIAS + static_cast<int32_t>(FPBits::FRACTION_LEN))) {
output.num = {0, 0};
output.error = ERANGE;
return output;
}
while (hpd.get_decimal_point() > 0) {
int32_t shift_amount = 0;
if (hpd.get_decimal_point() >= NUM_POWERS_OF_TWO) {
shift_amount = 60;
} else {
shift_amount = POWERS_OF_TWO[hpd.get_decimal_point()];
}
exp2 += shift_amount;
hpd.shift(-shift_amount);
}
while (hpd.get_decimal_point() < 0 ||
(hpd.get_decimal_point() == 0 && hpd.get_digits()[0] < 5)) {
int32_t shift_amount = 0;
if (-hpd.get_decimal_point() >= NUM_POWERS_OF_TWO) {
shift_amount = 60;
} else if (hpd.get_decimal_point() != 0) {
shift_amount = POWERS_OF_TWO[-hpd.get_decimal_point()];
} else {
shift_amount = 1;
}
exp2 -= shift_amount;
hpd.shift(shift_amount);
}
--exp2;
hpd.shift(1);
exp2 += FPBits::EXP_BIAS;
if (exp2 >= FPBits::MAX_BIASED_EXPONENT) {
output.num = {0, FPBits::MAX_BIASED_EXPONENT};
output.error = ERANGE;
return output;
}
hpd.shift(FPBits::FRACTION_LEN);
StorageType final_mantissa = hpd.round_to_integer_type<StorageType>();
if (exp2 <= 0) {
while (exp2 < 0) {
hpd.shift(-1);
++exp2;
}
hpd.shift(-1);
final_mantissa = hpd.round_to_integer_type<StorageType>(round);
if ((final_mantissa >> FPBits::FRACTION_LEN) != 0) {
++exp2;
}
}
if (final_mantissa == StorageType(2) << FPBits::FRACTION_LEN) {
final_mantissa >>= 1;
++exp2;
if (exp2 >= FPBits::MAX_BIASED_EXPONENT) {
output.error = ERANGE;
}
}
if (exp2 == 0) {
output.error = ERANGE;
}
output.num = {final_mantissa, exp2};
return output;
}
template <class T> class ClingerConsts;
template <> class ClingerConsts<float> {
public:
static constexpr float POWERS_OF_TEN_ARRAY[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5,
1e6, 1e7, 1e8, 1e9, 1e10};
static constexpr int32_t EXACT_POWERS_OF_TEN = 10;
static constexpr int32_t DIGITS_IN_MANTISSA = 7;
static constexpr float MAX_EXACT_INT = 16777215.0;
};
template <> class ClingerConsts<double> {
public:
static constexpr double POWERS_OF_TEN_ARRAY[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
static constexpr int32_t EXACT_POWERS_OF_TEN = 22;
static constexpr int32_t DIGITS_IN_MANTISSA = 15;
static constexpr double MAX_EXACT_INT = 9007199254740991.0;
};
#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64)
template <> class ClingerConsts<long double> {
public:
static constexpr long double POWERS_OF_TEN_ARRAY[] = {
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
static constexpr int32_t EXACT_POWERS_OF_TEN =
ClingerConsts<double>::EXACT_POWERS_OF_TEN;
static constexpr int32_t DIGITS_IN_MANTISSA =
ClingerConsts<double>::DIGITS_IN_MANTISSA;
static constexpr long double MAX_EXACT_INT =
ClingerConsts<double>::MAX_EXACT_INT;
};
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80)
template <> class ClingerConsts<long double> {
public:
static constexpr long double POWERS_OF_TEN_ARRAY[] = {
1e0L, 1e1L, 1e2L, 1e3L, 1e4L, 1e5L, 1e6L, 1e7L, 1e8L, 1e9L,
1e10L, 1e11L, 1e12L, 1e13L, 1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L,
1e20L, 1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L};
static constexpr int32_t EXACT_POWERS_OF_TEN = 27;
static constexpr int32_t DIGITS_IN_MANTISSA = 21;
static constexpr long double MAX_EXACT_INT = 18446744073709551615.0L;
};
#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128)
template <> class ClingerConsts<long double> {
public:
static constexpr long double POWERS_OF_TEN_ARRAY[] = {
1e0L, 1e1L, 1e2L, 1e3L, 1e4L, 1e5L, 1e6L, 1e7L, 1e8L, 1e9L,
1e10L, 1e11L, 1e12L, 1e13L, 1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L,
1e20L, 1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L, 1e28L, 1e29L,
1e30L, 1e31L, 1e32L, 1e33L, 1e34L, 1e35L, 1e36L, 1e37L, 1e38L, 1e39L,
1e40L, 1e41L, 1e42L, 1e43L, 1e44L, 1e45L, 1e46L, 1e47L, 1e48L};
static constexpr int32_t EXACT_POWERS_OF_TEN = 48;
static constexpr int32_t DIGITS_IN_MANTISSA = 33;
static constexpr long double MAX_EXACT_INT =
10384593717069655257060992658440191.0L;
};
#else
#error "Unknown long double type"
#endif
template <class T>
LIBC_INLINE cpp::optional<ExpandedFloat<T>>
clinger_fast_path(ExpandedFloat<T> init_num,
RoundDirection round = RoundDirection::Nearest) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
StorageType mantissa = init_num.mantissa;
int32_t exp10 = init_num.exponent;
if ((mantissa >> FPBits::FRACTION_LEN) > 0) {
return cpp::nullopt;
}
FPBits result;
T float_mantissa;
if constexpr (cpp::is_same_v<StorageType, UInt<128>>) {
float_mantissa = static_cast<T>(fputil::DyadicFloat<128>(
Sign::POS, 0,
fputil::DyadicFloat<128>::MantissaType(
{uint64_t(mantissa), uint64_t(mantissa >> 64)})));
} else {
float_mantissa = static_cast<T>(mantissa);
}
if (exp10 == 0) {
result = FPBits(float_mantissa);
}
if (exp10 > 0) {
if (exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN +
ClingerConsts<T>::DIGITS_IN_MANTISSA) {
return cpp::nullopt;
}
if (exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN) {
float_mantissa = float_mantissa *
ClingerConsts<T>::POWERS_OF_TEN_ARRAY
[exp10 - ClingerConsts<T>::EXACT_POWERS_OF_TEN];
exp10 = ClingerConsts<T>::EXACT_POWERS_OF_TEN;
}
if (float_mantissa > ClingerConsts<T>::MAX_EXACT_INT) {
return cpp::nullopt;
}
result =
FPBits(float_mantissa * ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp10]);
} else if (exp10 < 0) {
if (-exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN) {
return cpp::nullopt;
}
result =
FPBits(float_mantissa / ClingerConsts<T>::POWERS_OF_TEN_ARRAY[-exp10]);
}
if (round != RoundDirection::Nearest) {
FPBits negative_result;
negative_result = FPBits((-float_mantissa) *
ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp10]);
if (result.get_val() != -negative_result.get_val()) {
FPBits lower_result;
FPBits higher_result;
if (result.get_val() < -negative_result.get_val()) {
lower_result = result;
higher_result = negative_result;
} else {
lower_result = negative_result;
higher_result = result;
}
if (round == RoundDirection::Up) {
result = higher_result;
} else {
result = lower_result;
}
}
}
ExpandedFloat<T> output;
output.mantissa = result.get_mantissa();
output.exponent = result.get_biased_exponent();
return output;
}
template <typename T> LIBC_INLINE constexpr int32_t get_upper_bound() {
return fputil::FPBits<T>::EXP_BIAS / 3;
}
template <> LIBC_INLINE constexpr int32_t get_upper_bound<float>() {
return 39;
}
template <> LIBC_INLINE constexpr int32_t get_upper_bound<double>() {
return 309;
}
template <typename T> LIBC_INLINE constexpr int32_t get_lower_bound() {
using FPBits = typename fputil::FPBits<T>;
return -((FPBits::EXP_BIAS +
static_cast<int32_t>(FPBits::FRACTION_LEN + FPBits::STORAGE_LEN)) /
3);
}
template <> LIBC_INLINE constexpr int32_t get_lower_bound<float>() {
return -(39 + 6 + 10);
}
template <> LIBC_INLINE constexpr int32_t get_lower_bound<double>() {
return -(309 + 15 + 20);
}
template <class T>
LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float(
ExpandedFloat<T> init_num, bool truncated, RoundDirection round,
const char *__restrict numStart,
const size_t num_len = cpp::numeric_limits<size_t>::max()) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
StorageType mantissa = init_num.mantissa;
int32_t exp10 = init_num.exponent;
FloatConvertReturn<T> output;
cpp::optional<ExpandedFloat<T>> opt_output;
if (exp10 > get_upper_bound<T>()) {
output.num = {0, FPBits::MAX_BIASED_EXPONENT};
output.error = ERANGE;
return output;
}
if (exp10 < get_lower_bound<T>()) {
output.num = {0, 0};
output.error = ERANGE;
return output;
}
#ifndef LIBC_COPT_STRTOFLOAT_DISABLE_CLINGER_FAST_PATH
if (!truncated) {
opt_output = clinger_fast_path<T>(init_num, round);
if (opt_output.has_value()) {
return {opt_output.value(), 0};
}
}
#endif
#ifndef LIBC_COPT_STRTOFLOAT_DISABLE_EISEL_LEMIRE
opt_output = eisel_lemire<T>(init_num, round);
if (opt_output.has_value()) {
if (!truncated) {
return {opt_output.value(), 0};
}
auto second_output = eisel_lemire<T>({mantissa + 1, exp10}, round);
if (second_output.has_value()) {
if (opt_output->mantissa == second_output->mantissa &&
opt_output->exponent == second_output->exponent) {
return {opt_output.value(), 0};
}
}
}
#endif
#ifndef LIBC_COPT_STRTOFLOAT_DISABLE_SIMPLE_DECIMAL_CONVERSION
output = simple_decimal_conversion<T>(numStart, num_len, round);
#else
#warning "Simple decimal conversion is disabled, result may not be correct."
#endif
return output;
}
template <class T>
LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num,
bool truncated,
RoundDirection round) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
StorageType mantissa = init_num.mantissa;
int32_t exp2 = init_num.exponent;
FloatConvertReturn<T> output;
constexpr int32_t INF_EXP = (1 << FPBits::EXP_LEN) - 1;
uint32_t amount_to_shift_left = cpp::countl_zero<StorageType>(mantissa);
mantissa <<= amount_to_shift_left;
exp2 -= amount_to_shift_left;
int32_t biased_exponent = exp2 + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - 1;
if (biased_exponent >= INF_EXP) {
output.num = {0, (1 << FPBits::EXP_LEN) - 1};
output.error = ERANGE;
return output;
}
uint32_t amount_to_shift_right =
FPBits::STORAGE_LEN - FPBits::FRACTION_LEN - 1;
if (biased_exponent <= 0) {
amount_to_shift_right += 1 - biased_exponent;
biased_exponent = 0;
if (amount_to_shift_right > FPBits::STORAGE_LEN) {
output.num = {0, 0};
output.error = ERANGE;
return output;
}
}
StorageType round_bit_mask = StorageType(1) << (amount_to_shift_right - 1);
StorageType sticky_mask = round_bit_mask - 1;
bool round_bit = static_cast<bool>(mantissa & round_bit_mask);
bool sticky_bit = static_cast<bool>(mantissa & sticky_mask) || truncated;
if (amount_to_shift_right < FPBits::STORAGE_LEN) {
mantissa >>= amount_to_shift_right;
mantissa &= FPBits::FRACTION_MASK;
} else {
mantissa = 0;
}
bool least_significant_bit = static_cast<bool>(mantissa & StorageType(1));
if (round == RoundDirection::Nearest) {
if (round_bit && (least_significant_bit || sticky_bit)) {
++mantissa;
}
} else if (round == RoundDirection::Up) {
if (round_bit || sticky_bit) {
++mantissa;
}
} else {
if (round_bit && sticky_bit) {
++mantissa;
}
}
if (mantissa > FPBits::FRACTION_MASK) {
++biased_exponent;
if (biased_exponent == INF_EXP) {
output.error = ERANGE;
}
}
if (biased_exponent == 0) {
output.error = ERANGE;
}
output.num = {mantissa & FPBits::FRACTION_MASK, biased_exponent};
return output;
}
LIBC_INLINE bool is_float_hex_start(const char *__restrict src,
const char decimalPoint) {
if (!(src[0] == '0' && tolower(src[1]) == 'x')) {
return false;
}
size_t first_digit = 2;
if (src[2] == decimalPoint) {
++first_digit;
}
return isalnum(src[first_digit]) && b36_char_to_int(src[first_digit]) < 16;
}
template <class T>
LIBC_INLINE StrToNumResult<ExpandedFloat<T>>
decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
RoundDirection round) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
constexpr uint32_t BASE = 10;
constexpr char EXPONENT_MARKER = 'e';
bool truncated = false;
bool seen_digit = false;
bool after_decimal = false;
StorageType mantissa = 0;
int32_t exponent = 0;
size_t index = 0;
StrToNumResult<ExpandedFloat<T>> output({0, 0});
const StorageType bitstype_max_div_by_base =
cpp::numeric_limits<StorageType>::max() / BASE;
while (true) {
if (isdigit(src[index])) {
uint32_t digit = src[index] - '0';
seen_digit = true;
if (mantissa < bitstype_max_div_by_base) {
mantissa = (mantissa * BASE) + digit;
if (after_decimal) {
--exponent;
}
} else {
if (digit > 0)
truncated = true;
if (!after_decimal)
++exponent;
}
++index;
continue;
}
if (src[index] == DECIMAL_POINT) {
if (after_decimal) {
break;
}
after_decimal = true;
++index;
continue;
}
break;
}
if (!seen_digit)
return output;
if (tolower(src[index]) == EXPONENT_MARKER) {
bool has_sign = false;
if (src[index + 1] == '+' || src[index + 1] == '-') {
has_sign = true;
}
if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) {
++index;
auto result = strtointeger<int32_t>(src + index, 10);
if (result.has_error())
output.error = result.error;
int32_t add_to_exponent = result.value;
index += result.parsed_len;
int64_t temp_exponent = static_cast<int64_t>(exponent) +
static_cast<int64_t>(add_to_exponent);
if (temp_exponent > FPBits::MAX_BIASED_EXPONENT) {
exponent = FPBits::MAX_BIASED_EXPONENT;
} else if (temp_exponent < -FPBits::MAX_BIASED_EXPONENT) {
exponent = -FPBits::MAX_BIASED_EXPONENT;
} else {
exponent = static_cast<int32_t>(temp_exponent);
}
}
}
output.parsed_len = index;
if (mantissa == 0) {
output.value = {0, 0};
} else {
auto temp =
decimal_exp_to_float<T>({mantissa, exponent}, truncated, round, src);
output.value = temp.num;
output.error = temp.error;
}
return output;
}
template <class T>
LIBC_INLINE StrToNumResult<ExpandedFloat<T>>
hexadecimal_string_to_float(const char *__restrict src,
const char DECIMAL_POINT, RoundDirection round) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
constexpr uint32_t BASE = 16;
constexpr char EXPONENT_MARKER = 'p';
bool truncated = false;
bool seen_digit = false;
bool after_decimal = false;
StorageType mantissa = 0;
int32_t exponent = 0;
size_t index = 0;
StrToNumResult<ExpandedFloat<T>> output({0, 0});
const StorageType bitstype_max_div_by_base =
cpp::numeric_limits<StorageType>::max() / BASE;
while (true) {
if (isalnum(src[index])) {
uint32_t digit = b36_char_to_int(src[index]);
if (digit < BASE)
seen_digit = true;
else
break;
if (mantissa < bitstype_max_div_by_base) {
mantissa = (mantissa * BASE) + digit;
if (after_decimal)
--exponent;
} else {
if (digit > 0)
truncated = true;
if (!after_decimal)
++exponent;
}
++index;
continue;
}
if (src[index] == DECIMAL_POINT) {
if (after_decimal) {
break;
}
after_decimal = true;
++index;
continue;
}
break;
}
if (!seen_digit)
return output;
exponent *= 4;
if (tolower(src[index]) == EXPONENT_MARKER) {
bool has_sign = false;
if (src[index + 1] == '+' || src[index + 1] == '-') {
has_sign = true;
}
if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) {
++index;
auto result = strtointeger<int32_t>(src + index, 10);
if (result.has_error())
output.error = result.error;
int32_t add_to_exponent = result.value;
index += result.parsed_len;
int64_t temp_exponent = static_cast<int64_t>(exponent) +
static_cast<int64_t>(add_to_exponent);
if (temp_exponent > FPBits::MAX_BIASED_EXPONENT) {
exponent = FPBits::MAX_BIASED_EXPONENT;
} else if (temp_exponent < -FPBits::MAX_BIASED_EXPONENT) {
exponent = -FPBits::MAX_BIASED_EXPONENT;
} else {
exponent = static_cast<int32_t>(temp_exponent);
}
}
}
output.parsed_len = index;
if (mantissa == 0) {
output.value.exponent = 0;
output.value.mantissa = 0;
} else {
auto temp = binary_exp_to_float<T>({mantissa, exponent}, truncated, round);
output.error = temp.error;
output.value = temp.num;
}
return output;
}
template <class T>
LIBC_INLINE typename fputil::FPBits<T>::StorageType
nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
StorageType nan_mantissa = 0;
if (ncharseq.data() != nullptr && isdigit(ncharseq[0])) {
StrToNumResult<StorageType> strtoint_result =
strtointeger<StorageType>(ncharseq.data(), 0);
if (!strtoint_result.has_error())
nan_mantissa = strtoint_result.value;
if (strtoint_result.parsed_len != static_cast<ptrdiff_t>(ncharseq.size()))
nan_mantissa = 0;
}
return nan_mantissa;
}
template <class T>
LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
FPBits result = FPBits();
bool seen_digit = false;
char sign = '+';
int error = 0;
ptrdiff_t index = first_non_whitespace(src) - src;
if (src[index] == '+' || src[index] == '-') {
sign = src[index];
++index;
}
if (sign == '-') {
result.set_sign(Sign::NEG);
}
static constexpr char DECIMAL_POINT = '.';
static const char *inf_string = "infinity";
static const char *nan_string = "nan";
if (isdigit(src[index]) || src[index] == DECIMAL_POINT) {
int base = 10;
if (is_float_hex_start(src + index, DECIMAL_POINT)) {
base = 16;
index += 2;
seen_digit = true;
}
RoundDirection round_direction = RoundDirection::Nearest;
switch (fputil::quick_get_round()) {
case FE_TONEAREST:
round_direction = RoundDirection::Nearest;
break;
case FE_UPWARD:
if (sign == '+') {
round_direction = RoundDirection::Up;
} else {
round_direction = RoundDirection::Down;
}
break;
case FE_DOWNWARD:
if (sign == '+') {
round_direction = RoundDirection::Down;
} else {
round_direction = RoundDirection::Up;
}
break;
case FE_TOWARDZERO:
round_direction = RoundDirection::Down;
break;
}
StrToNumResult<ExpandedFloat<T>> parse_result({0, 0});
if (base == 16) {
parse_result = hexadecimal_string_to_float<T>(src + index, DECIMAL_POINT,
round_direction);
} else {
parse_result = decimal_string_to_float<T>(src + index, DECIMAL_POINT,
round_direction);
}
seen_digit = parse_result.parsed_len != 0;
result.set_mantissa(parse_result.value.mantissa);
result.set_biased_exponent(parse_result.value.exponent);
index += parse_result.parsed_len;
error = parse_result.error;
} else if (tolower(src[index]) == 'n') {
if (tolower(src[index + 1]) == nan_string[1] &&
tolower(src[index + 2]) == nan_string[2]) {
seen_digit = true;
index += 3;
StorageType nan_mantissa = 0;
if (src[index] == '(') {
size_t left_paren = index;
++index;
while (isalnum(src[index]) || src[index] == '_')
++index;
if (src[index] == ')') {
++index;
nan_mantissa = nan_mantissa_from_ncharseq<T>(
cpp::string_view(src + (left_paren + 1), index - left_paren - 2));
} else {
index = left_paren;
}
}
result = FPBits(result.quiet_nan(result.sign(), nan_mantissa));
}
} else if (tolower(src[index]) == 'i') {
if (tolower(src[index + 1]) == inf_string[1] &&
tolower(src[index + 2]) == inf_string[2]) {
seen_digit = true;
result = FPBits(result.inf(result.sign()));
if (tolower(src[index + 3]) == inf_string[3] &&
tolower(src[index + 4]) == inf_string[4] &&
tolower(src[index + 5]) == inf_string[5] &&
tolower(src[index + 6]) == inf_string[6] &&
tolower(src[index + 7]) == inf_string[7]) {
index += 8;
} else {
index += 3;
}
}
}
if (!seen_digit) {
return {T(0), 0, error};
}
set_implicit_bit<T>(result);
return {result.get_val(), index, error};
}
template <class T> LIBC_INLINE StrToNumResult<T> strtonan(const char *arg) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
FPBits result;
int error = 0;
StorageType nan_mantissa = 0;
ptrdiff_t index = 0;
while (isalnum(arg[index]) || arg[index] == '_')
++index;
if (arg[index] == '\0')
nan_mantissa = nan_mantissa_from_ncharseq<T>(cpp::string_view(arg, index));
result = FPBits::quiet_nan(Sign::POS, nan_mantissa);
return {result.get_val(), 0, error};
}
}
}
#endif