Copy the String interface to ByteString

This commit is contained in:
mniip 2018-05-04 14:45:57 +03:00
parent 7f5c164d22
commit d6a92bdab5
2 changed files with 309 additions and 10 deletions

View File

@ -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<char> 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<char> str = stream.str();
b.AddChars(str.data(), str.size());
stream.str(std::basic_string<char>());
}
inline void FlushStream()
{
stream.str(std::basic_string<char>());
}
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<wchar_t> 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);
}

View File

@ -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<typename T> 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<typename T> 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<typename T> 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<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(short int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(long int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(long long int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitSigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(unsigned short int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(unsigned int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(unsigned long int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(unsigned long long int &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitUnsigned(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(float &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitFloat(ref, pos, set, reset); }
template<std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline Split SplitNumber(double &ref, Format::FlagsOverride<void, set, reset>, size_t pos = 0) const { return SplitFloat(ref, pos, set, reset); }
template<typename T> 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<typename T, std::ios_base::fmtflags set, std::ios_base::fmtflags reset> inline T ToNumber(Format::FlagsOverride<void, set, reset> 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<ByteString> PartitionBy(value_type ch, bool includeEmpty = false) const;
std::vector<ByteString> PartitionBy(ByteString const &str, bool includeEmpty = false) const;
@ -102,6 +167,7 @@ public:
String FromUtf8(bool ignoreError = true) const;
inline String FromAscii() const;
template<typename... Ts> static ByteString Build(Ts&&... args);
using Stream = std::basic_stringstream<value_type>;
};
@ -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<String> 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<ByteString::value_type> 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<typename T> ByteStringBuilder &operator<<(T) = delete;
template<typename T, typename... Ts> ByteStringBuilder &Add(T &&arg, Ts&&... args)
{
return (*this << std::forward<T>(arg)).Add(std::forward<Ts>(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<typename... Ts> ByteString ByteString::Build(Ts&&... args)
{
ByteStringBuilder b;
b.Add(std::forward<Ts>(args)...);
return b.Build();
}
class StringBuilder
{
std::vector<String::value_type> buffer; // TODO: std::list<std::vector<String::value_type> > ?
std::vector<String::value_type> 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);