summaryrefslogtreecommitdiff
path: root/zen/string_tools.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2016-03-16 21:31:24 +0100
committerDaniel Wilhelm <daniel@wili.li>2016-03-16 21:31:24 +0100
commit89621addb4a7c87d2e3f3e7462e3c690cf71de71 (patch)
tree008b5dea7624ee1eeb57ff82c45fdf1afcab3b08 /zen/string_tools.h
parent7.5 (diff)
downloadFreeFileSync-89621addb4a7c87d2e3f3e7462e3c690cf71de71.tar.gz
FreeFileSync-89621addb4a7c87d2e3f3e7462e3c690cf71de71.tar.bz2
FreeFileSync-89621addb4a7c87d2e3f3e7462e3c690cf71de71.zip
7.6
Diffstat (limited to 'zen/string_tools.h')
-rw-r--r--zen/string_tools.h95
1 files changed, 49 insertions, 46 deletions
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 8f83b9cd..fc9fe806 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef STRING_TOOLS_HEADER_213458973046
-#define STRING_TOOLS_HEADER_213458973046
+#ifndef STRING_TOOLS_H_213458973046
+#define STRING_TOOLS_H_213458973046
#include <cctype> //isspace
#include <cwctype> //iswspace
@@ -42,8 +42,8 @@ template <class S, class T> S afterFirst (const S& str, const T& term, FailureRe
template <class S, class T> S beforeFirst(const S& str, const T& term, FailureReturnVal rv);
template <class S, class T> std::vector<S> split(const S& str, const T& delimiter);
-template <class S> void trim ( S& str, bool fromLeft = true, bool fromRight = true);
-template <class S> S trimCpy(const S& str, bool fromLeft = true, bool fromRight = true);
+template <class S> void trim (S& str, bool fromLeft = true, bool fromRight = true);
+template <class S> S trimCpy(S str, bool fromLeft = true, bool fromRight = true);
template <class S, class T, class U> void replace ( S& str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
template <class S, class T, class U> S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll = true);
@@ -54,7 +54,7 @@ template <class Num, class S > Num stringTo(const S& str);
template <class S, class T, class Num> S printNumber(const T& format, const Num& number); //format a single number using std::snprintf()
//string to string conversion: converts string-like type into char-compatible target string class
-template <class T, class S> T copyStringTo(const S& str);
+template <class T, class S> T copyStringTo(S&& str);
@@ -94,6 +94,7 @@ bool isDigit(Char ch) //similar to implmenetation of std::::isdigit()!
return static_cast<Char>('0') <= ch && ch <= static_cast<Char>('9');
}
+
template <> bool isAlpha(char ch) = delete; //probably not a good idea with UTF-8 anyway...
template <> inline bool isAlpha(wchar_t ch) { return std::iswalpha(ch) != 0; }
@@ -252,7 +253,7 @@ std::vector<S> split(const S& str, const T& delimiter)
}
-namespace implementation
+namespace impl
{
ZEN_INIT_DETECT_MEMBER(append);
@@ -295,8 +296,8 @@ S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll)
for (;;)
{
- implementation::stringAppend(output, strPos, strMatch - strPos);
- implementation::stringAppend(output, newBegin, newLen);
+ impl::stringAppend(output, strPos, strMatch - strPos);
+ impl::stringAppend(output, newBegin, newLen);
strPos = strMatch + oldLen;
@@ -308,7 +309,7 @@ S replaceCpy(const S& str, const T& oldTerm, const U& newTerm, bool replaceAll)
if (strMatch == strEnd)
break;
}
- implementation::stringAppend(output, strPos, strEnd - strPos);
+ impl::stringAppend(output, strPos, strEnd - strPos);
return output;
}
@@ -346,16 +347,15 @@ void trim(S& str, bool fromLeft, bool fromRight)
template <class S> inline
-S trimCpy(const S& str, bool fromLeft, bool fromRight)
+S trimCpy(S str, bool fromLeft, bool fromRight)
{
//implementing trimCpy() in terms of trim(), instead of the other way round, avoids memory allocations when trimming from right!
- S tmp = str;
- trim(tmp, fromLeft, fromRight);
- return tmp;
+ trim(str, fromLeft, fromRight);
+ return std::move(str); //"str" is an l-value parameter => no copy elision!
}
-namespace implementation
+namespace impl
{
template <class S, class T>
struct CopyStringToString
@@ -363,18 +363,19 @@ struct CopyStringToString
T copy(const S& src) const { return T(strBegin(src), strLength(src)); }
};
-template <class S>
-struct CopyStringToString<S, S> //perf: we don't need a deep copy if string types match
+template <class T>
+struct CopyStringToString<T, T> //perf: we don't need a deep copy if string types match
{
- const S& copy(const S& src) const { return src; }
+ template <class S>
+ T copy(S&& str) const { return std::forward<S>(str); }
};
}
template <class T, class S> inline
-T copyStringTo(const S& str) { return implementation::CopyStringToString<S, T>().copy(str); }
+T copyStringTo(S&& str) { return impl::CopyStringToString<std::decay_t<S>, T>().copy(std::forward<S>(str)); }
-namespace implementation
+namespace impl
{
template <class Num> inline
int saferPrintf(char* buffer, size_t bufferSize, const char* format, const Num& number) //there is no such thing as a "safe" printf ;)
@@ -400,17 +401,18 @@ 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
{
- typedef typename GetCharType<S>::Type CharType;
+ static_assert(IsSameType<typename GetCharType<S>::Type, typename GetCharType<T>::Type>::value, "");
+ using CharType = typename GetCharType<S>::Type;
const int BUFFER_SIZE = 128;
- CharType buffer[BUFFER_SIZE];
- const int charsWritten = implementation::saferPrintf(buffer, BUFFER_SIZE, strBegin(format), number);
+ CharType buffer[BUFFER_SIZE]; //zero-initialize?
+ const int charsWritten = impl::saferPrintf(buffer, BUFFER_SIZE, strBegin(format), number);
return charsWritten > 0 ? S(buffer, charsWritten) : S();
}
-namespace implementation
+namespace impl
{
enum NumberType
{
@@ -424,7 +426,7 @@ enum NumberType
template <class S, class Num> inline
S numberTo(const Num& number, Int2Type<NUM_TYPE_OTHER>) //default number to string conversion using streams: convenient, but SLOW, SLOW, SLOW!!!! (~ factor of 20)
{
- typedef typename GetCharType<S>::Type CharType;
+ using CharType = typename GetCharType<S>::Type;
std::basic_ostringstream<CharType> ss;
ss << number;
@@ -453,7 +455,7 @@ template <class OutputIterator, class Num> inline
void formatNegativeInteger(Num n, OutputIterator& it)
{
assert(n < 0);
- typedef typename std::iterator_traits<OutputIterator>::value_type CharType;
+ using CharType = typename std::iterator_traits<OutputIterator>::value_type;
do
{
const Num tmp = n / 10;
@@ -469,7 +471,7 @@ template <class OutputIterator, class Num> inline
void formatPositiveInteger(Num n, OutputIterator& it)
{
assert(n >= 0);
- typedef typename std::iterator_traits<OutputIterator>::value_type CharType;
+ using CharType = typename std::iterator_traits<OutputIterator>::value_type;
do
{
const Num tmp = n / 10;
@@ -483,8 +485,9 @@ void formatPositiveInteger(Num n, OutputIterator& it)
template <class S, class Num> inline
S numberTo(const Num& number, Int2Type<NUM_TYPE_SIGNED_INT>)
{
- typedef typename GetCharType<S>::Type CharType;
- CharType buffer[2 + sizeof(Num) * 241 / 100]; //it's generally faster to use a buffer than to rely on String::operator+=() (in)efficiency
+ using CharType = typename GetCharType<S>::Type;
+ CharType buffer[2 + sizeof(Num) * 241 / 100]; //zero-initialize?
+ //it's generally faster to use a buffer than to rely on String::operator+=() (in)efficiency
//required chars (+ sign char): 1 + ceil(ln_10(256^sizeof(n) / 2 + 1)) -> divide by 2 for signed half-range; second +1 since one half starts with 1!
// <= 1 + ceil(ln_10(256^sizeof(n))) =~ 1 + ceil(sizeof(n) * 2.4082) <= 2 + floor(sizeof(n) * 2.41)
@@ -503,8 +506,8 @@ S numberTo(const Num& number, Int2Type<NUM_TYPE_SIGNED_INT>)
template <class S, class Num> inline
S numberTo(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
{
- typedef typename GetCharType<S>::Type CharType;
- CharType buffer[1 + sizeof(Num) * 241 / 100];
+ using CharType = typename GetCharType<S>::Type;
+ CharType buffer[1 + sizeof(Num) * 241 / 100]; //zero-initialize?
//required chars: ceil(ln_10(256^sizeof(n))) =~ ceil(sizeof(n) * 2.4082) <= 1 + floor(sizeof(n) * 2.41)
auto it = std::end(buffer);
@@ -519,7 +522,7 @@ S numberTo(const Num& number, Int2Type<NUM_TYPE_UNSIGNED_INT>)
template <class Num, class S> inline
Num stringTo(const S& str, Int2Type<NUM_TYPE_OTHER>) //default string to number conversion using streams: convenient, but SLOW
{
- typedef typename GetCharType<S>::Type CharType;
+ using CharType = typename GetCharType<S>::Type;
Num number = 0;
std::basic_istringstream<CharType>(copyStringTo<std::basic_string<CharType>>(str)) >> number;
return number;
@@ -538,8 +541,8 @@ Num stringTo(const S& str, Int2Type<NUM_TYPE_FLOATING_POINT>)
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
{
- typedef typename GetCharType<S>::Type CharType;
-
+ using CharType = typename GetCharType<S>::Type;
+
const CharType* first = strBegin(str);
const CharType* last = first + strLength(str);
@@ -606,28 +609,28 @@ Num stringTo(const S& str, Int2Type<NUM_TYPE_UNSIGNED_INT>) //very fast conversi
template <class S, class Num> inline
S numberTo(const Num& number)
{
- typedef Int2Type<
- IsSignedInt <Num>::value ? implementation::NUM_TYPE_SIGNED_INT :
- IsUnsignedInt<Num>::value ? implementation::NUM_TYPE_UNSIGNED_INT :
- IsFloat <Num>::value ? implementation::NUM_TYPE_FLOATING_POINT :
- implementation::NUM_TYPE_OTHER> TypeTag;
+ using TypeTag = Int2Type<
+ IsSignedInt <Num>::value ? impl::NUM_TYPE_SIGNED_INT :
+ IsUnsignedInt<Num>::value ? impl::NUM_TYPE_UNSIGNED_INT :
+ IsFloat <Num>::value ? impl::NUM_TYPE_FLOATING_POINT :
+ impl::NUM_TYPE_OTHER>;
- return implementation::numberTo<S>(number, TypeTag());
+ return impl::numberTo<S>(number, TypeTag());
}
template <class Num, class S> inline
Num stringTo(const S& str)
{
- typedef Int2Type<
- IsSignedInt <Num>::value ? implementation::NUM_TYPE_SIGNED_INT :
- IsUnsignedInt<Num>::value ? implementation::NUM_TYPE_UNSIGNED_INT :
- IsFloat <Num>::value ? implementation::NUM_TYPE_FLOATING_POINT :
- implementation::NUM_TYPE_OTHER> TypeTag;
+ using TypeTag = Int2Type<
+ IsSignedInt <Num>::value ? impl::NUM_TYPE_SIGNED_INT :
+ IsUnsignedInt<Num>::value ? impl::NUM_TYPE_UNSIGNED_INT :
+ IsFloat <Num>::value ? impl::NUM_TYPE_FLOATING_POINT :
+ impl::NUM_TYPE_OTHER>;
- return implementation::stringTo<Num>(str, TypeTag());
+ return impl::stringTo<Num>(str, TypeTag());
}
}
-#endif //STRING_TOOLS_HEADER_213458973046
+#endif //STRING_TOOLS_H_213458973046
bgstack15