/* * Copyright (c) 2022, David Tuin * Copyright (c) 2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include namespace AK { #define ENUMERATE_INTEGRAL_TYPES \ __ENUMERATE_TYPE(i8) \ __ENUMERATE_TYPE(i16) \ __ENUMERATE_TYPE(i32) \ __ENUMERATE_TYPE(long) \ __ENUMERATE_TYPE(long long) \ __ENUMERATE_TYPE(u8) \ __ENUMERATE_TYPE(u16) \ __ENUMERATE_TYPE(u32) \ __ENUMERATE_TYPE(unsigned long) \ __ENUMERATE_TYPE(unsigned long long) #define ENUMERATE_ARITHMETIC_TYPES \ ENUMERATE_INTEGRAL_TYPES \ __ENUMERATE_TYPE(float) \ __ENUMERATE_TYPE(double) template static constexpr Optional> from_chars(CharType const* string, size_t length, int base) { ValueType value { 0 }; fast_float::parse_options_t options; options.base = base; options.format |= fast_float::chars_format::no_infnan; if constexpr (IsSigned || IsFloatingPoint) { options.format |= fast_float::chars_format::allow_leading_plus; } auto result = fast_float::from_chars_advanced(string, string + length, value, options); if constexpr (IsFloatingPoint) { if (result.ec == std::errc::result_out_of_range && (__builtin_isinf(value) || value == 0)) result.ec = {}; } if (result.ec != std::errc {}) return {}; return ParseFirstNumberResult { value, static_cast(result.ptr - string) }; } template Optional> parse_first_number(StringView string, TrimWhitespace trim_whitespace, int base) { if (trim_whitespace == TrimWhitespace::Yes) string = StringUtils::trim_whitespace(string, TrimMode::Both); return from_chars(string.characters_without_null_termination(), string.length(), base); } template Optional> parse_first_number(Utf16View const& string, TrimWhitespace trim_whitespace, int base) { if (string.has_ascii_storage()) return parse_first_number(string.bytes(), trim_whitespace, base); auto trimmed_string = trim_whitespace == TrimWhitespace::Yes ? string.trim_whitespace() : string; return from_chars(trimmed_string.utf16_span().data(), trimmed_string.length_in_code_units(), base); } #define __ENUMERATE_TYPE(type) \ template Optional> parse_first_number(StringView, TrimWhitespace, int); ENUMERATE_ARITHMETIC_TYPES #undef __ENUMERATE_TYPE #define __ENUMERATE_TYPE(type) \ template Optional> parse_first_number(Utf16View const&, TrimWhitespace, int); ENUMERATE_ARITHMETIC_TYPES #undef __ENUMERATE_TYPE template Optional parse_number(StringView string, TrimWhitespace trim_whitespace, int base) { if (trim_whitespace == TrimWhitespace::Yes) string = StringUtils::trim_whitespace(string, TrimMode::Both); auto result = parse_first_number(string, TrimWhitespace::No, base); if (!result.has_value()) return {}; if (result->characters_parsed != string.length()) return {}; return result->value; } template Optional parse_number(Utf16View const& string, TrimWhitespace trim_whitespace, int base) { if (string.has_ascii_storage()) return parse_number(string.bytes(), trim_whitespace, base); auto trimmed_string = trim_whitespace == TrimWhitespace::Yes ? string.trim_whitespace() : string; auto result = parse_first_number(trimmed_string, TrimWhitespace::No, base); if (!result.has_value()) return {}; if (result->characters_parsed != trimmed_string.length_in_code_units()) return {}; return result->value; } #define __ENUMERATE_TYPE(type) \ template Optional parse_number(StringView, TrimWhitespace, int); ENUMERATE_ARITHMETIC_TYPES #undef __ENUMERATE_TYPE #define __ENUMERATE_TYPE(type) \ template Optional parse_number(Utf16View const&, TrimWhitespace, int); ENUMERATE_ARITHMETIC_TYPES #undef __ENUMERATE_TYPE template Optional parse_hexadecimal_number(StringView string, TrimWhitespace trim_whitespace) { return parse_number(string, trim_whitespace, 16); } template Optional parse_hexadecimal_number(Utf16View const& string, TrimWhitespace trim_whitespace) { return parse_number(string, trim_whitespace, 16); } #define __ENUMERATE_TYPE(type) \ template Optional parse_hexadecimal_number(StringView, TrimWhitespace); ENUMERATE_INTEGRAL_TYPES #undef __ENUMERATE_TYPE #define __ENUMERATE_TYPE(type) \ template Optional parse_hexadecimal_number(Utf16View const&, TrimWhitespace); ENUMERATE_INTEGRAL_TYPES #undef __ENUMERATE_TYPE }