From 1ea7a035d1c7e23180f992c16a8fc29ed450c916 Mon Sep 17 00:00:00 2001 From: mniip Date: Thu, 3 May 2018 02:48:05 +0300 Subject: [PATCH] Add Number parsing facilities --- src/common/Format.h | 2 ++ src/common/String.cpp | 61 +++++++++++++++++++++++++++++++++++++++ src/common/String.h | 66 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/src/common/Format.h b/src/common/Format.h index cd454b362..c2db70752 100644 --- a/src/common/Format.h +++ b/src/common/Format.h @@ -62,8 +62,10 @@ namespace Format template inline FlagsOverride NoShowPoint(T value) { return FlagsOverride(value); } inline FlagsOverride Uppercase() { return FlagsOverride(); } inline FlagsOverride ShowPoint() { return FlagsOverride(); } + inline FlagsOverride SkipWS() { return FlagsOverride(); } inline FlagsOverride NoUppercase() { return FlagsOverride(); } inline FlagsOverride NoShowPoint() { return FlagsOverride(); } + inline FlagsOverride NoSkipWS() { return FlagsOverride(); } template inline FlagsOverride Fixed(T value) { return FlagsOverride(value); } template inline FlagsOverride Scientific(T value) { return FlagsOverride(value); } diff --git a/src/common/String.cpp b/src/common/String.cpp index efa4fea49..a3e1788d9 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -234,6 +234,8 @@ inline wchar_t narrow_wchar(String::value_type ch) return wchar_t(ch); } +String numberChars = "-.+0123456789ABCDEFXabcdefx"; + static thread_local struct LocaleImpl { std::basic_stringstream stream; @@ -253,6 +255,16 @@ static thread_local struct LocaleImpl wstream.fill(b.fill); } + 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])) + wstr.push_back(narrow_wchar(str[pos++])); + wstream.str(wstr); + wstream.clear(); + } + inline void FlushWStream(StringBuilder &b) { std::basic_string wstr = wstream.str(); @@ -263,6 +275,11 @@ static thread_local struct LocaleImpl b.AddChars(chars.data(), chars.size()); wstream.str(std::basic_string()); } + + inline void FlushWStream() + { + wstream.str(std::basic_string()); + } } LocaleImpl; @@ -376,6 +393,50 @@ StringBuilder &operator<<(StringBuilder &b, double data) return b; } +String::Split String::SplitSigned(long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const +{ + LocaleImpl.PrepareWStream(*this, pos, set, reset); + LocaleImpl.wstream >> value; + if(LocaleImpl.wstream.fail()) + { + LocaleImpl.FlushWStream(); + return Split(*this, pos, npos, 0, false); + } + LocaleImpl.wstream.clear(); + Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); + LocaleImpl.FlushWStream(); + return split; +} + +String::Split String::SplitUnsigned(unsigned long long int &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const +{ + LocaleImpl.PrepareWStream(*this, pos, set, reset); + LocaleImpl.wstream >> value; + if(LocaleImpl.wstream.fail()) + { + LocaleImpl.FlushWStream(); + return Split(*this, pos, npos, 0, false); + } + LocaleImpl.wstream.clear(); + Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); + LocaleImpl.FlushWStream(); + return split; +} + +String::Split String::SplitFloat(double &value, size_t pos, std::ios_base::fmtflags set, std::ios_base::fmtflags reset) const +{ + LocaleImpl.PrepareWStream(*this, pos, set, reset); + LocaleImpl.wstream >> value; + if(LocaleImpl.wstream.fail()) + { + LocaleImpl.FlushWStream(); + return Split(*this, pos, npos, 0, false); + } + LocaleImpl.wstream.clear(); + Split split(*this, pos, pos + LocaleImpl.wstream.tellg(), 0, false); + LocaleImpl.FlushWStream(); + return split; +} template<> std::ctype::~ctype() { diff --git a/src/common/String.h b/src/common/String.h index 306bc9313..c13e5d385 100644 --- a/src/common/String.h +++ b/src/common/String.h @@ -9,6 +9,7 @@ class ByteStringBuilder; class String; class StringBuilder; +namespace Format { template struct FlagsOverride; } template class SplitBase { @@ -179,6 +180,71 @@ public: 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: + 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() const + { + T value = T(); + Split split = SplitNumber(value); + if(split.PositionBefore() != size()) + return T(); + return value; + } + template inline T ToNumber(Format::FlagsOverride fmt) const + { + T value = T(); + Split split = SplitNumber(value, fmt); + if(split.PositionBefore() != size()) + return T(); + return value; + } std::vector PartitionBy(value_type ch, bool includeEmpty = false) const; std::vector PartitionBy(String const &str, bool includeEmpty = false) const;