From 43285bf1374c68b9703e002702e14dc1c186c358 Mon Sep 17 00:00:00 2001 From: Yuqian Yang Date: Tue, 4 Nov 2025 17:15:56 +0800 Subject: Use strto* to impl float from_chars. --- include/cru/base/StringUtil.h | 68 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 10 deletions(-) (limited to 'include/cru/base') diff --git a/include/cru/base/StringUtil.h b/include/cru/base/StringUtil.h index 1496f9cd..159f34c3 100644 --- a/include/cru/base/StringUtil.h +++ b/include/cru/base/StringUtil.h @@ -5,8 +5,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -36,6 +38,52 @@ std::vector CRU_BASE_API Split(std::string_view str, std::string_view sep, SplitOption options = {}); +namespace details { +template +std::enable_if_t, std::from_chars_result> from_chars( + const char* first, const char* last, T& value, int base = 10) { + return std::from_chars(first, last, value, base); +} + +template +std::enable_if_t, std::from_chars_result> +float_from_chars_impl(const char* first, const char* last, T& value, + std::chars_format fmt = std::chars_format::general) { + if (std::isspace(*first)) { + return std::from_chars_result{first, std::errc::invalid_argument}; + } + + std::string str(first, last); + auto c_str = str.c_str(); + char* c_str_end; + auto parsed_value = StrToFunc(c_str, &c_str_end); + if (c_str == c_str_end) { + return std::from_chars_result{first, std::errc::invalid_argument}; + } + if (IsOverflow(parsed_value)) { + return std::from_chars_result{first, std::errc::result_out_of_range}; + } + value = parsed_value; + return std::from_chars_result{first + (c_str_end - c_str), {}}; +} + +#define CRU_DEFINE_FLOAT_FROM_CHARS(type, str_to_func, overflow_value) \ + inline std::from_chars_result from_chars( \ + const char* first, const char* last, type& value, \ + std::chars_format fmt = std::chars_format::general) { \ + return float_from_chars_impl(first, last, value, fmt); \ + } + +CRU_DEFINE_FLOAT_FROM_CHARS(float, strtof, HUGE_VALF) +CRU_DEFINE_FLOAT_FROM_CHARS(double, strtod, HUGE_VAL) +CRU_DEFINE_FLOAT_FROM_CHARS(long double, strtold, HUGE_VALL) + +#undef CRU_DEFINE_FLOAT_FROM_CHARS +} // namespace details + namespace details { struct ParseToNumberFlagTag {}; } // namespace details @@ -80,8 +128,8 @@ ParseToNumberResult ParseToNumber(std::string_view str, return result; } - auto parse_result = - std::from_chars(ptr, str.data() + str.size(), result.value); + auto parse_result = ::cru::string::details::from_chars( + ptr, str.data() + str.size(), result.value); if (parse_result.ec == std::errc::invalid_argument) { result.valid = false; result.message = "Not a valid number."; @@ -377,14 +425,14 @@ using Utf8CodePointIterator = CodePointIterator; using Utf16CodePointIterator = CodePointIterator; -Index CRU_BASE_API Utf8IndexCodeUnitToCodePoint(const Utf8CodeUnit* ptr, Index size, - Index position); -Index CRU_BASE_API Utf8IndexCodePointToCodeUnit(const Utf8CodeUnit* ptr, Index size, - Index position); -Index CRU_BASE_API Utf16IndexCodeUnitToCodePoint(const Utf16CodeUnit* ptr, Index size, - Index position); -Index CRU_BASE_API Utf16IndexCodePointToCodeUnit(const Utf16CodeUnit* ptr, Index size, - Index position); +Index CRU_BASE_API Utf8IndexCodeUnitToCodePoint(const Utf8CodeUnit* ptr, + Index size, Index position); +Index CRU_BASE_API Utf8IndexCodePointToCodeUnit(const Utf8CodeUnit* ptr, + Index size, Index position); +Index CRU_BASE_API Utf16IndexCodeUnitToCodePoint(const Utf16CodeUnit* ptr, + Index size, Index position); +Index CRU_BASE_API Utf16IndexCodePointToCodeUnit(const Utf16CodeUnit* ptr, + Index size, Index position); #ifdef _WIN32 std::wstring CRU_BASE_API ToUtf16(std::string_view str); -- cgit v1.2.3