From 5b604dd360ffc162f163962ccb2b1af109a5f93f Mon Sep 17 00:00:00 2001 From: B Stack Date: Thu, 17 Oct 2019 15:59:39 -0400 Subject: add upstream 10.17 --- zen/string_tools.h | 64 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 11 deletions(-) (limited to 'zen/string_tools.h') diff --git a/zen/string_tools.h b/zen/string_tools.h index c3970d05..dcb5a54a 100644 --- a/zen/string_tools.h +++ b/zen/string_tools.h @@ -14,15 +14,16 @@ #include #include #include -#include //std::basic_ostringstream #include "stl_tools.h" #include "string_traits.h" +#include "legacy_compiler.h" // (without compiler crashes) //enhance arbitray string class with useful non-member functions: namespace zen { template bool isWhiteSpace(Char c); +template bool isLineBreak (Char c); template bool isDigit (Char c); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only! template bool isHexDigit (Char c); template bool isAsciiAlpha(Char c); @@ -115,6 +116,14 @@ bool isWhiteSpace(Char c) // - some parts of UTF-8 chars are erroneously seen as whitespace, e.g. the a0 from "\xec\x8b\xa0" (MSVC) } +template inline +bool isLineBreak(Char c) +{ + static_assert(std::is_same_v || std::is_same_v); + return c == static_cast('\r') || c == static_cast('\n'); +} + + template inline bool isDigit(Char c) //similar to implementation of std::isdigit()! { @@ -552,6 +561,10 @@ int saferPrintf(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const template inline S printNumber(const T& format, const Num& number) //format a single number using ::sprintf { +#if __cpp_lib_format +#error refactor +#endif + static_assert(std::is_same_v, GetCharTypeT>); const int BUFFER_SIZE = 128; @@ -573,22 +586,31 @@ enum class NumberType }; +template S numberTo(const Num& number, std::integral_constant) = delete; +#if 0 //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20) template inline -S numberTo(const Num& number, std::integral_constant) //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20) +S numberTo(const Num& number, std::integral_constant) { std::basic_ostringstream> ss; ss << number; return copyStringTo(ss.str()); } +#endif -template inline S floatToString(const Num& number, char ) { return printNumber( "%g", static_cast(number)); } -template inline S floatToString(const Num& number, wchar_t) { return printNumber(L"%g", static_cast(number)); } - template inline S numberTo(const Num& number, std::integral_constant) { - return floatToString(number, GetCharTypeT()); + //don't use sprintf("%g"): way SLOWWWWWWER than std::to_chars() + + char buffer[128]; //zero-initialize? + //let's give some leeway, but 24 chars should suffice: https://www.reddit.com/r/cpp/comments/dgj89g/cppcon_2019_stephan_t_lavavej_floatingpoint/f3j7d3q/ + const char* strEnd = zen::to_chars(std::begin(buffer), std::end(buffer), number); + + S output; + std::for_each(static_cast(buffer), strEnd, + [&](char c) { output += static_cast>(c); }); + return output; } @@ -665,25 +687,46 @@ S numberTo(const Num& number, std::integral_constant Num stringTo(const S& str, std::integral_constant) = delete; +#if 0 //default string to number conversion using streams: convenient, but SLOW template inline -Num stringTo(const S& str, std::integral_constant) //default string to number conversion using streams: convenient, but SLOW +Num stringTo(const S& str, std::integral_constant) { using CharType = GetCharTypeT; Num number = 0; std::basic_istringstream(copyStringTo>(str)) >> number; return number; } +#endif -template inline Num stringToFloat(const char* str) { return std::strtod(str, nullptr); } -template inline Num stringToFloat(const wchar_t* str) { return std::wcstod(str, nullptr); } +inline +double stringToFloat(const char* first, const char* last) +{ + //don't use std::strtod(): 1. requires null-terminated string 2. SLOWER than std::from_chars() + return zen::from_chars(first, last); +} + + +inline +double stringToFloat(const wchar_t* first, const wchar_t* last) +{ + std::string buf(last - first, '\0'); + std::transform(first, last, buf.begin(), [](wchar_t c) { return static_cast(c); }); + + return zen::from_chars(buf.c_str(), buf.c_str() + buf.size()); +} + template inline Num stringTo(const S& str, std::integral_constant) { - return stringToFloat(strBegin(str)); + const auto* const first = strBegin(str); + const auto* const last = first + strLength(str); + return static_cast(stringToFloat(first, last)); } + template Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to integers: slightly faster than std::atoi, but more importantly: generic { @@ -695,7 +738,6 @@ Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to i while (first != last && isWhiteSpace(*first)) //skip leading whitespace ++first; - //handle minus sign hasMinusSign = false; if (first != last) { -- cgit