AK+Everywhere: Replace custom number parsers with fast_float
Some checks failed
CI / macOS, arm64, Sanitizer_CI, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers_CI, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, Clang (push) Waiting to run
Package the js repl as a binary artifact / Linux, arm64 (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
Build Dev Container Image / build (push) Has been cancelled

Our floating point number parser was based on the fast_float library:
https://github.com/fastfloat/fast_float

However, our implementation only supports 8-bit characters. To support
UTF-16, we will need to be able to convert char16_t-based strings to
numbers as well. This works out-of-the-box with fast_float.

We can also use fast_float for integer parsing.
This commit is contained in:
Timothy Flynn 2025-06-26 19:06:46 -04:00 committed by Tim Flynn
commit 62d9a84b8d
Notes: github-actions[bot] 2025-07-03 13:53:10 +00:00
30 changed files with 413 additions and 3034 deletions

View file

@ -111,217 +111,6 @@ TEST_CASE(match_trailing_backslash)
EXPECT(AK::StringUtils::matches("x\\"sv, "x\\\\"sv));
}
TEST_CASE(convert_to_int)
{
auto value = AK::StringUtils::convert_to_int(StringView());
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_int(""sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_int("a"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_int("+"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_int("-"sv);
EXPECT(!value.has_value());
auto actual = AK::StringUtils::convert_to_int("0"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 0);
actual = AK::StringUtils::convert_to_int("1"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 1);
actual = AK::StringUtils::convert_to_int("+1"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 1);
actual = AK::StringUtils::convert_to_int("-1"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), -1);
actual = AK::StringUtils::convert_to_int("01"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 1);
actual = AK::StringUtils::convert_to_int("12345"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 12345);
actual = AK::StringUtils::convert_to_int("-12345"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), -12345);
actual = AK::StringUtils::convert_to_int(" \t-12345 \n\n"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), -12345);
auto actual_i8 = AK::StringUtils::convert_to_int<i8>("-1"sv);
EXPECT(actual_i8.has_value());
EXPECT_EQ(actual_i8.value(), -1);
EXPECT_EQ(sizeof(actual_i8.value()), (size_t)1);
actual_i8 = AK::StringUtils::convert_to_int<i8>("128"sv);
EXPECT(!actual_i8.has_value());
auto actual_i16 = AK::StringUtils::convert_to_int<i16>("-1"sv);
EXPECT(actual_i16.has_value());
EXPECT_EQ(actual_i16.value(), -1);
EXPECT_EQ(sizeof(actual_i16.value()), (size_t)2);
actual_i16 = AK::StringUtils::convert_to_int<i16>("32768"sv);
EXPECT(!actual_i16.has_value());
auto actual_i32 = AK::StringUtils::convert_to_int<i32>("-1"sv);
EXPECT(actual_i32.has_value());
EXPECT_EQ(actual_i32.value(), -1);
EXPECT_EQ(sizeof(actual_i32.value()), (size_t)4);
actual_i32 = AK::StringUtils::convert_to_int<i32>("2147483648"sv);
EXPECT(!actual_i32.has_value());
auto actual_i64 = AK::StringUtils::convert_to_int<i64>("-1"sv);
EXPECT(actual_i64.has_value());
EXPECT_EQ(actual_i64.value(), -1);
EXPECT_EQ(sizeof(actual_i64.value()), (size_t)8);
actual_i64 = AK::StringUtils::convert_to_int<i64>("9223372036854775808"sv);
EXPECT(!actual_i64.has_value());
}
TEST_CASE(convert_to_uint)
{
auto value = AK::StringUtils::convert_to_uint(StringView());
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint(""sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint("a"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint("+"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint("-"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint("+1"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint("-1"sv);
EXPECT(!value.has_value());
auto actual = AK::StringUtils::convert_to_uint("0"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 0u);
actual = AK::StringUtils::convert_to_uint("1"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 1u);
actual = AK::StringUtils::convert_to_uint("01"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 1u);
actual = AK::StringUtils::convert_to_uint("12345"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 12345u);
actual = AK::StringUtils::convert_to_uint(" \t12345 \n\n"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 12345u);
auto actual_u8 = AK::StringUtils::convert_to_uint<u8>("255"sv);
EXPECT(actual_u8.has_value());
EXPECT_EQ(actual_u8.value(), 255u);
EXPECT_EQ(sizeof(actual_u8.value()), (size_t)1);
actual_u8 = AK::StringUtils::convert_to_uint<u8>("256"sv);
EXPECT(!actual_u8.has_value());
auto actual_u16 = AK::StringUtils::convert_to_uint<u16>("65535"sv);
EXPECT(actual_u16.has_value());
EXPECT_EQ(actual_u16.value(), 65535u);
EXPECT_EQ(sizeof(actual_u16.value()), (size_t)2);
actual_u16 = AK::StringUtils::convert_to_uint<u16>("65536"sv);
EXPECT(!actual_u16.has_value());
auto actual_u32 = AK::StringUtils::convert_to_uint<u32>("4294967295"sv);
EXPECT(actual_u32.has_value());
EXPECT_EQ(actual_u32.value(), 4294967295ul);
EXPECT_EQ(sizeof(actual_u32.value()), (size_t)4);
actual_u32 = AK::StringUtils::convert_to_uint<u32>("4294967296"sv);
EXPECT(!actual_u32.has_value());
auto actual_u64 = AK::StringUtils::convert_to_uint<u64>("18446744073709551615"sv);
EXPECT(actual_u64.has_value());
EXPECT_EQ(actual_u64.value(), 18446744073709551615ull);
EXPECT_EQ(sizeof(actual_u64.value()), (size_t)8);
actual_u64 = AK::StringUtils::convert_to_uint<u64>("18446744073709551616"sv);
EXPECT(!actual_u64.has_value());
}
TEST_CASE(convert_to_uint_from_octal)
{
auto value = AK::StringUtils::convert_to_uint_from_octal<u16>(StringView());
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint_from_octal<u16>(""sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint_from_octal<u16>("a"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint_from_octal<u16>("+"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint_from_octal<u16>("-"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint_from_octal<u16>("+1"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint_from_octal<u16>("-1"sv);
EXPECT(!value.has_value());
value = AK::StringUtils::convert_to_uint_from_octal<u16>("8"sv);
EXPECT(!value.has_value());
auto actual = AK::StringUtils::convert_to_uint_from_octal<u16>("77777777"sv);
EXPECT(!actual.has_value());
actual = AK::StringUtils::convert_to_uint_from_octal<u16>("0"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 0u);
actual = AK::StringUtils::convert_to_uint_from_octal<u16>("1"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 1u);
actual = AK::StringUtils::convert_to_uint_from_octal<u16>("0755"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 0755u);
actual = AK::StringUtils::convert_to_uint_from_octal<u16>("755"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 0755u);
actual = AK::StringUtils::convert_to_uint_from_octal<u16>(" \t644 \n\n"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 0644u);
actual = AK::StringUtils::convert_to_uint_from_octal<u16>("177777"sv);
EXPECT_EQ(actual.has_value(), true);
EXPECT_EQ(actual.value(), 0177777u);
}
TEST_CASE(convert_to_floating_point)
{
auto number_string = " 123.45 "sv;
auto maybe_number = AK::StringUtils::convert_to_floating_point<float>(number_string, TrimWhitespace::Yes);
EXPECT_APPROXIMATE(maybe_number.value(), 123.45f);
}
TEST_CASE(ends_with)
{
ByteString test_string = "ABCDEF";