summaryrefslogtreecommitdiff
path: root/zen/string_tools.h
diff options
context:
space:
mode:
Diffstat (limited to 'zen/string_tools.h')
-rw-r--r--zen/string_tools.h64
1 files changed, 53 insertions, 11 deletions
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 <algorithm>
#include <cassert>
#include <vector>
-#include <sstream> //std::basic_ostringstream
#include "stl_tools.h"
#include "string_traits.h"
+#include "legacy_compiler.h" //<charconv> (without compiler crashes)
//enhance arbitray string class with useful non-member functions:
namespace zen
{
template <class Char> bool isWhiteSpace(Char c);
+template <class Char> bool isLineBreak (Char c);
template <class Char> bool isDigit (Char c); //not exactly the same as "std::isdigit" -> we consider '0'-'9' only!
template <class Char> bool isHexDigit (Char c);
template <class Char> bool isAsciiAlpha(Char c);
@@ -116,6 +117,14 @@ bool isWhiteSpace(Char c)
}
template <class Char> inline
+bool isLineBreak(Char c)
+{
+ static_assert(std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>);
+ return c == static_cast<Char>('\r') || c == static_cast<Char>('\n');
+}
+
+
+template <class Char> inline
bool isDigit(Char c) //similar to implementation of std::isdigit()!
{
static_assert(std::is_same_v<Char, char> || std::is_same_v<Char, wchar_t>);
@@ -552,6 +561,10 @@ int saferPrintf(wchar_t* buffer, size_t bufferSize, const wchar_t* format, const
template <class S, class T, class Num> 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<S>, GetCharTypeT<T>>);
const int BUFFER_SIZE = 128;
@@ -573,22 +586,31 @@ enum class NumberType
};
+template <class S, class Num> S numberTo(const Num& number, std::integral_constant<NumberType, NumberType::OTHER>) = delete;
+#if 0 //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20)
template <class S, class Num> inline
-S numberTo(const Num& number, std::integral_constant<NumberType, NumberType::OTHER>) //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20)
+S numberTo(const Num& number, std::integral_constant<NumberType, NumberType::OTHER>)
{
std::basic_ostringstream<GetCharTypeT<S>> ss;
ss << number;
return copyStringTo<S>(ss.str());
}
+#endif
-template <class S, class Num> inline S floatToString(const Num& number, char ) { return printNumber<S>( "%g", static_cast<double>(number)); }
-template <class S, class Num> inline S floatToString(const Num& number, wchar_t) { return printNumber<S>(L"%g", static_cast<double>(number)); }
-
template <class S, class Num> inline
S numberTo(const Num& number, std::integral_constant<NumberType, NumberType::FLOATING_POINT>)
{
- return floatToString<S>(number, GetCharTypeT<S>());
+ //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<const char*>(buffer), strEnd,
+ [&](char c) { output += static_cast<GetCharTypeT<S>>(c); });
+ return output;
}
@@ -665,25 +687,46 @@ S numberTo(const Num& number, std::integral_constant<NumberType, NumberType::UNS
//--------------------------------------------------------------------------------
+template <class Num, class S> Num stringTo(const S& str, std::integral_constant<NumberType, NumberType::OTHER>) = delete;
+#if 0 //default string to number conversion using streams: convenient, but SLOW
template <class Num, class S> inline
-Num stringTo(const S& str, std::integral_constant<NumberType, NumberType::OTHER>) //default string to number conversion using streams: convenient, but SLOW
+Num stringTo(const S& str, std::integral_constant<NumberType, NumberType::OTHER>)
{
using CharType = GetCharTypeT<S>;
Num number = 0;
std::basic_istringstream<CharType>(copyStringTo<std::basic_string<CharType>>(str)) >> number;
return number;
}
+#endif
-template <class Num> inline Num stringToFloat(const char* str) { return std::strtod(str, nullptr); }
-template <class Num> 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<char>(c); });
+
+ return zen::from_chars(buf.c_str(), buf.c_str() + buf.size());
+}
+
template <class Num, class S> inline
Num stringTo(const S& str, std::integral_constant<NumberType, NumberType::FLOATING_POINT>)
{
- return stringToFloat<Num>(strBegin(str));
+ const auto* const first = strBegin(str);
+ const auto* const last = first + strLength(str);
+ return static_cast<Num>(stringToFloat(first, last));
}
+
template <class Num, class S>
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)
{
bgstack15