diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-09-16 23:02:22 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-09-16 23:02:22 +1000 |
commit | 090441b80aed3c7df45ff1a6d40ed56ee895ad28 (patch) | |
tree | 3a4a8137941aa60f0674d9ed9308a45266c96e4e /source/core | |
parent | 40299558dd4585adb6066cdade5703be7cf10b76 (diff) |
make lexical casts (string -> int/float) faster
Diffstat (limited to 'source/core')
-rw-r--r-- | source/core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/core/StarLexicalCast.cpp | 13 | ||||
-rw-r--r-- | source/core/StarLexicalCast.hpp | 58 |
3 files changed, 52 insertions, 20 deletions
diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index 2f0c858..fa1d246 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -160,6 +160,7 @@ SET (star_core_SOURCES StarJsonPatch.cpp StarJsonRpc.cpp StarFormattedJson.cpp + StarLexicalCast.cpp StarListener.cpp StarLogging.cpp StarLua.cpp diff --git a/source/core/StarLexicalCast.cpp b/source/core/StarLexicalCast.cpp new file mode 100644 index 0000000..1387b2e --- /dev/null +++ b/source/core/StarLexicalCast.cpp @@ -0,0 +1,13 @@ +#include "StarLexicalCast.hpp" + +namespace Star { + +void throwLexicalCastError(std::errc ec, const char* first, const char* last) { + StringView str(first, last - first); + if (ec == std::errc::invalid_argument) + throw BadLexicalCast(strf("Lexical cast failed on '{}' (invalid argument)", str)); + else + throw BadLexicalCast(strf("Lexical cast failed on '{}'", str)); +} + +}
\ No newline at end of file diff --git a/source/core/StarLexicalCast.hpp b/source/core/StarLexicalCast.hpp index 9c671e9..13c0521 100644 --- a/source/core/StarLexicalCast.hpp +++ b/source/core/StarLexicalCast.hpp @@ -5,40 +5,58 @@ #include "StarStringView.hpp" #include "StarMaybe.hpp" -#include <sstream> -#include <locale> +#include "fast_float.h" namespace Star { STAR_EXCEPTION(BadLexicalCast, StarException); -// Very simple basic lexical cast using stream input. Always operates in the -// "C" locale. +void throwLexicalCastError(std::errc ec, const char* first, const char* last); + template <typename Type> -Maybe<Type> maybeLexicalCast(StringView s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) { - Type result; - std::istringstream stream(std::string(s.utf8())); - stream.flags(flags); - stream.imbue(std::locale::classic()); +bool tryLexicalCast(Type& result, const char* first, const char* last) { + auto res = fast_float::from_chars(first, last, result); + return res.ptr == last && (res.ec == std::errc() || res.ec == std::errc::result_out_of_range); +} - if (!(stream >> result)) - return {}; +template <typename Type> +bool tryLexicalCast(Type& result, String const& s) { + return tryLexicalCast<Type>(s.utf8Ptr(), s.utf8Ptr() + s.utf8Size()); +} - // Confirm that we read everything out of the stream - char ch; - if (stream >> ch) +template <typename Type> +bool tryLexicalCast(Type& result, StringView s) { + return tryLexicalCast<Type>(s.utf8Ptr(), s.utf8Ptr() + s.utf8Size()); +} + +template <typename Type> +Maybe<Type> maybeLexicalCast(const char* first, const char* last) { + Type result{}; + if (tryLexicalCast(result, first, last)) + return result; + else return {}; +} + +template <typename Type> +Maybe<Type> maybeLexicalCast(StringView s) { + return maybeLexicalCast<Type>(s.utf8Ptr(), s.utf8Ptr() + s.utf8Size()); +} + +template <typename Type> +Type lexicalCast(const char* first, const char* last) { + Type result{}; + auto res = fast_float::from_chars(first, last, result); + if ((res.ec != std::errc() && res.ec != std::errc::result_out_of_range) || res.ptr != last) + throwLexicalCastError(res.ec, first, last); + return result; } template <typename Type> -Type lexicalCast(StringView s, std::ios_base::fmtflags flags = std::ios_base::boolalpha) { - auto m = maybeLexicalCast<Type>(s, flags); - if (m) - return m.take(); - else - throw BadLexicalCast(strf("Lexical cast failed on '{}'", s)); +Type lexicalCast(StringView s) { + return lexicalCast<Type>(s.utf8Ptr(), s.utf8Ptr() + s.utf8Size()); } } |