From d6a92bdab579ea967e83f599e6a70628e3686ab9 Mon Sep 17 00:00:00 2001 From: mniip Date: Fri, 4 May 2018 14:45:57 +0300 Subject: [PATCH] Copy the String interface to ByteString --- src/common/String.cpp | 199 ++++++++++++++++++++++++++++++++++++++++-- src/common/String.h | 120 +++++++++++++++++++++++-- 2 files changed, 309 insertions(+), 10 deletions(-) diff --git a/src/common/String.cpp b/src/common/String.cpp index e36003cc9..cdca64827 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -234,7 +234,9 @@ inline wchar_t narrow_wchar(String::value_type ch) return wchar_t(ch); } -String numberChars = "-.+0123456789ABCDEFXabcdefx"; +char const numberChars[] = "-.+0123456789ABCDEFXabcdefx"; +ByteString numberByteString(numberChars); +String numberString(numberChars); static thread_local struct LocaleImpl { @@ -247,19 +249,51 @@ static thread_local struct LocaleImpl wstream.imbue(std::locale::classic()); } + inline void PrepareStream(ByteStringBuilder &b) + { + stream.flags(b.flags); + stream.width(b.width); + stream.precision(b.precision); + stream.fill(b.fill); + stream.clear(); + } + + inline void PrepareStream(ByteString const &str, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) + { + stream.flags((std::ios_base::dec & ~ reset) | set); + std::basic_string bstr; + while(pos < str.size() && numberByteString.Contains(str[pos])) + bstr.push_back(narrow_wchar(str[pos++])); + stream.str(bstr); + stream.clear(); + } + + inline void FlushStream(ByteStringBuilder &b) + { + std::basic_string str = stream.str(); + b.AddChars(str.data(), str.size()); + stream.str(std::basic_string()); + } + + inline void FlushStream() + { + stream.str(std::basic_string()); + } + inline void PrepareWStream(StringBuilder &b) { wstream.flags(b.flags); wstream.width(b.width); wstream.precision(b.precision); wstream.fill(b.fill); + wstream.clear(); } inline void PrepareWStream(String const &str, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) { wstream.flags((std::ios_base::dec & ~ reset) | set); std::basic_string wstr; - while(pos < str.size() && representable_wchar(str[pos]) && numberChars.Contains(str[pos])) + while(pos < str.size() && representable_wchar(str[pos]) && numberString.Contains(str[pos])) wstr.push_back(narrow_wchar(str[pos++])); wstream.str(wstr); wstream.clear(); @@ -283,6 +317,159 @@ static thread_local struct LocaleImpl } LocaleImpl; +ByteString ByteStringBuilder::Build() const +{ + return ByteString(buffer.begin(), buffer.end()); +} + +void ByteStringBuilder::AddChars(ByteString::value_type const *data, size_t count) +{ + buffer.reserve(buffer.size() + count); + buffer.insert(buffer.end(), data, data + count); +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, short int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, long int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, long long int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned short int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, unsigned long long int data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, ByteString::value_type data) +{ + b.AddChars(&data, 1); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, ByteString::value_type const *data) +{ + return b << ByteString(data); +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, ByteString const &data) +{ + b.AddChars(data.data(), data.size()); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, float data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteStringBuilder &operator<<(ByteStringBuilder &b, double data) +{ + LocaleImpl.PrepareStream(b); + LocaleImpl.stream << data; + LocaleImpl.FlushStream(b); + return b; +} + +ByteString::Split ByteString::SplitSigned(long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const +{ + LocaleImpl.PrepareStream(*this, pos, set, reset); + LocaleImpl.stream >> value; + if(LocaleImpl.stream.fail()) + { + LocaleImpl.FlushStream(); + return Split(*this, pos, npos, 0, false); + } + LocaleImpl.stream.clear(); + Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); + LocaleImpl.FlushStream(); + return split; +} + +ByteString::Split ByteString::SplitUnsigned(unsigned long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const +{ + LocaleImpl.PrepareStream(*this, pos, set, reset); + LocaleImpl.stream >> value; + if(LocaleImpl.stream.fail()) + { + LocaleImpl.FlushStream(); + return Split(*this, pos, npos, 0, false); + } + LocaleImpl.stream.clear(); + Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); + LocaleImpl.FlushStream(); + return split; +} + +ByteString::Split ByteString::SplitFloat(double &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const +{ + LocaleImpl.PrepareStream(*this, pos, set, reset); + LocaleImpl.stream >> value; + if(LocaleImpl.stream.fail()) + { + LocaleImpl.FlushStream(); + return Split(*this, pos, npos, 0, false); + } + LocaleImpl.stream.clear(); + Split split(*this, pos, pos + LocaleImpl.stream.tellg(), 0, false); + LocaleImpl.FlushStream(); + return split; +} + String StringBuilder::Build() const { return String(buffer.begin(), buffer.end()); @@ -371,6 +558,11 @@ StringBuilder &operator<<(StringBuilder &b, String::value_type data) return b; } +StringBuilder &operator<<(StringBuilder &b, String::value_type const *data) +{ + return b << String(data); +} + StringBuilder &operator<<(StringBuilder &b, String const &data) { b.AddChars(data.data(), data.size()); @@ -399,7 +591,6 @@ String::Split String::SplitSigned(long long int &value, size_t pos, std::ios_bas LocaleImpl.wstream >> value; if(LocaleImpl.wstream.fail()) { - LocaleImpl.wstream.clear(); LocaleImpl.FlushWStream(); return Split(*this, pos, npos, 0, false); } @@ -415,7 +606,6 @@ String::Split String::SplitUnsigned(unsigned long long int &value, size_t pos, s LocaleImpl.wstream >> value; if(LocaleImpl.wstream.fail()) { - LocaleImpl.wstream.clear(); LocaleImpl.FlushWStream(); return Split(*this, pos, npos, 0, false); } @@ -431,7 +621,6 @@ String::Split String::SplitFloat(double &value, size_t pos, std::ios_base::fmtfl LocaleImpl.wstream >> value; if(LocaleImpl.wstream.fail()) { - LocaleImpl.wstream.clear(); LocaleImpl.FlushWStream(); return Split(*this, pos, npos, 0, false); } diff --git a/src/common/String.h b/src/common/String.h index 05629fc33..bb6be1841 100644 --- a/src/common/String.h +++ b/src/common/String.h @@ -72,10 +72,10 @@ public: inline ByteString Substr(size_t pos = 0, size_t count = npos) const { return super::substr(pos, count); } inline ByteString SubstrFromEnd(size_t rpos = 0, size_t rcount = npos) const { return super::substr(rcount == npos || rcount > rpos ? 0 : rpos - rcount, size() - rpos); } - inline ByteString Between(size_t from, size_t to) const { return from >= to ? ByteString() : super::substr(from, to - from); } + inline ByteString Between(size_t from, size_t to) const { return to == npos ? super::substr(from) : from >= to ? ByteString() : super::substr(from, to - from); } inline bool Contains(value_type ch) const { return super::find(ch) != npos; } - inline bool Contains(ByteString const &other) { return super::find(other) != npos; } + inline bool Contains(ByteString const &other) const { return super::find(other) != npos; } inline bool BeginsWith(ByteString const &other) const { return !super::compare(0, other.size(), other); } inline bool EndsWith(ByteString const &other) const { return !super::compare(size() - other.size(), other.size(), other); } @@ -89,6 +89,71 @@ public: inline Split SplitFromEndBy(ByteString const &str, size_t pos = npos) const { return Split(*this, pos, super::find(str, pos), str.size(), true); } inline Split SplitFromEndByAny(ByteString const &str, size_t pos = npos) const { return Split(*this, pos, super::find_last_of(str, pos), 1, true); } inline Split SplitFromEndByNot(ByteString const &str, size_t pos = npos) const { return Split(*this, pos, super::find_last_not_of(str, pos), 1, true); } +private: + Split SplitSigned(long long int &, size_t, std::ios_base::fmtflags, std::ios_base::fmtflags) const; + Split SplitUnsigned(unsigned long long int &, size_t, std::ios_base::fmtflags, std::ios_base::fmtflags) const; + Split SplitFloat(double &, size_t, std::ios_base::fmtflags, std::ios_base::fmtflags) const; +public: + template inline Split SplitSigned(T &ref, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const + { + long long int value = 0; + Split split = SplitSigned(value, pos, set, reset); + ref = value; + return split; + } + template inline Split SplitUnsigned(T &ref, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const + { + unsigned long long int value = 0; + Split split = SplitUnsigned(value, pos, set, reset); + ref = value; + return split; + } + template inline Split SplitFloat(T &ref, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const + { + double value = 0; + Split split = SplitFloat(value, pos, set, reset); + ref = value; + return split; + } + + inline Split SplitNumber(short int &ref, size_t pos = 0) const { return SplitSigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(int &ref, size_t pos = 0) const { return SplitSigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(long int &ref, size_t pos = 0) const { return SplitSigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(long long int &ref, size_t pos = 0) const { return SplitSigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(unsigned short int &ref, size_t pos = 0) const { return SplitUnsigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(unsigned int &ref, size_t pos = 0) const { return SplitUnsigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(unsigned long int &ref, size_t pos = 0) const { return SplitUnsigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(unsigned long long int &ref, size_t pos = 0) const { return SplitUnsigned(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(float &ref, size_t pos = 0) const { return SplitFloat(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + inline Split SplitNumber(double &ref, size_t pos = 0) const { return SplitFloat(ref, pos, std::ios_base::fmtflags(), std::ios_base::fmtflags()); } + + template inline Split SplitNumber(short int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); } + template inline Split SplitNumber(int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); } + template inline Split SplitNumber(long int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); } + template inline Split SplitNumber(long long int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); } + template inline Split SplitNumber(unsigned short int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); } + template inline Split SplitNumber(unsigned int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); } + template inline Split SplitNumber(unsigned long int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); } + template inline Split SplitNumber(unsigned long long int &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); } + template inline Split SplitNumber(float &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitFloat(ref, pos, set, reset); } + template inline Split SplitNumber(double &ref, Format::FlagsOverride, size_t pos = 0) const { return SplitFloat(ref, pos, set, reset); } + + template T ToNumber(bool noThrow = false) const + { + T value = T(); + Split split = SplitNumber(value); + if(split.PositionBefore() != size()) + return noThrow ? T() : throw std::runtime_error("Not a number"); + return value; + } + template inline T ToNumber(Format::FlagsOverride fmt, bool noThrow = false) const + { + T value = T(); + Split split = SplitNumber(value, fmt); + if(split.PositionBefore() != size()) + return noThrow ? T() : throw std::runtime_error("Not a number"); + return value; + } std::vector PartitionBy(value_type ch, bool includeEmpty = false) const; std::vector PartitionBy(ByteString const &str, bool includeEmpty = false) const; @@ -102,6 +167,7 @@ public: String FromUtf8(bool ignoreError = true) const; inline String FromAscii() const; + template static ByteString Build(Ts&&... args); using Stream = std::basic_stringstream; }; @@ -177,7 +243,7 @@ public: inline Split SplitByAny(String const &str, size_t pos = 0) const { return Split(*this, pos, super::find_first_of(str, pos), 1, false); } inline Split SplitByNot(String const &str, size_t pos = 0) const { return Split(*this, pos, super::find_first_not_of(str, pos), 1, false); } inline Split SplitFromEndBy(value_type ch, size_t pos = npos) const { return Split(*this, pos, super::rfind(ch, pos), 1, true); } - inline Split SplitFromEndBy(String const &str, size_t pos = npos) const { return Split(*this, pos,super::find(str, pos), str.size(), true); } + inline Split SplitFromEndBy(String const &str, size_t pos = npos) const { return Split(*this, pos, super::find(str, pos), str.size(), true); } inline Split SplitFromEndByAny(String const &str, size_t pos = npos) const { return Split(*this, pos, super::find_last_of(str, pos), 1, true); } inline Split SplitFromEndByNot(String const &str, size_t pos = npos) const { return Split(*this, pos, super::find_last_not_of(str, pos), 1, true); } private: @@ -251,7 +317,7 @@ public: std::vector PartitionByAny(String const &str, bool includeEmpty = false) const; String &Substitute(String const &needle, String const &replacement); - + inline String &Insert(size_t pos, String const &str) { super::insert(pos, str); return *this; } inline String &Erase(size_t pos, size_t count) { super::erase(pos, count); return *this; } inline String &EraseBetween(size_t from, size_t to) { if(from < to) super::erase(from, to - from); return *this; } @@ -326,9 +392,52 @@ public: inline ConversionError(bool to): std::runtime_error(to ? "Could not convert to UTF-8" : "Could not convert from UTF-8") {} }; +class ByteStringBuilder +{ + std::vector buffer; +public: + std::ios_base::fmtflags flags; + ByteString::value_type fill; + size_t width, precision; + inline ByteStringBuilder(): flags(std::ios_base::skipws | std::ios_base::dec), fill(' '), width(0), precision(6) {} + + void AddChars(ByteString::value_type const *, size_t); + size_t Size() const { return buffer.size(); } + ByteString Build() const; + + template ByteStringBuilder &operator<<(T) = delete; + + template ByteStringBuilder &Add(T &&arg, Ts&&... args) + { + return (*this << std::forward(arg)).Add(std::forward(args)...); + } + ByteStringBuilder &Add() { return *this; } +}; + +ByteStringBuilder &operator<<(ByteStringBuilder &, short int); +ByteStringBuilder &operator<<(ByteStringBuilder &, int); +ByteStringBuilder &operator<<(ByteStringBuilder &, long int); +ByteStringBuilder &operator<<(ByteStringBuilder &, long long int); +ByteStringBuilder &operator<<(ByteStringBuilder &, unsigned short int); +ByteStringBuilder &operator<<(ByteStringBuilder &, unsigned int); +ByteStringBuilder &operator<<(ByteStringBuilder &, unsigned long int); +ByteStringBuilder &operator<<(ByteStringBuilder &, unsigned long long int); +ByteStringBuilder &operator<<(ByteStringBuilder &, ByteString::value_type); +ByteStringBuilder &operator<<(ByteStringBuilder &, ByteString::value_type const *); +ByteStringBuilder &operator<<(ByteStringBuilder &, ByteString const &); +ByteStringBuilder &operator<<(ByteStringBuilder &, float); +ByteStringBuilder &operator<<(ByteStringBuilder &, double); + +template ByteString ByteString::Build(Ts&&... args) +{ + ByteStringBuilder b; + b.Add(std::forward(args)...); + return b.Build(); +} + class StringBuilder { - std::vector buffer; // TODO: std::list > ? + std::vector buffer; public: std::ios_base::fmtflags flags; String::value_type fill; @@ -358,6 +467,7 @@ StringBuilder &operator<<(StringBuilder &, unsigned long int); StringBuilder &operator<<(StringBuilder &, unsigned long long int); StringBuilder &operator<<(StringBuilder &, ByteString::value_type); StringBuilder &operator<<(StringBuilder &, String::value_type); +StringBuilder &operator<<(StringBuilder &, String::value_type const *); StringBuilder &operator<<(StringBuilder &, String const &); StringBuilder &operator<<(StringBuilder &, float); StringBuilder &operator<<(StringBuilder &, double);