From af2d82dfc17ccd0c32b0955b1588e3bca379ccab Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 18 Apr 2014 13:45:33 +0100 Subject: [PATCH] Add StringView class for non owning string --- src/string.cc | 4 +- src/string.hh | 146 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/src/string.cc b/src/string.cc index 23457413..46d492f1 100644 --- a/src/string.cc +++ b/src/string.cc @@ -83,7 +83,7 @@ void option_from_string(const String& str, Regex& re) } } -bool prefix_match(const String& str, const String& prefix) +bool prefix_match(StringView str, StringView prefix) { auto it = str.begin(); for (auto& c : prefix) @@ -94,7 +94,7 @@ bool prefix_match(const String& str, const String& prefix) return true; } -bool subsequence_match(const String& str, const String& subseq) +bool subsequence_match(StringView str, StringView subseq) { auto it = str.begin(); for (auto& c : subseq) diff --git a/src/string.hh b/src/string.hh index 57a2666a..8dd51404 100644 --- a/src/string.hh +++ b/src/string.hh @@ -61,6 +61,114 @@ public: } }; +class StringView +{ +public: + constexpr StringView() : m_data{nullptr}, m_length{0} {} + constexpr StringView(const char* data, ByteCount length) + : m_data{data}, m_length{length} {} + constexpr StringView(const char* data) : m_data{data}, m_length{(int)strlen(data)} {} + constexpr StringView(const char* begin, const char* end) : m_data{begin}, m_length{(int)(end - begin)} {} + StringView(const String& str) : m_data{str.data().pointer()}, m_length{str.length()} {} + + bool operator==(StringView other) const; + bool operator!=(StringView other) const; + + const char* data() const { return m_data; } + + using iterator = const char*; + using reverse_iterator = std::reverse_iterator; + + iterator begin() const { return m_data; } + iterator end() const { return m_data + (int)m_length; } + + reverse_iterator rbegin() const { return reverse_iterator{m_data + (int)m_length}; } + reverse_iterator rend() const { return reverse_iterator{m_data}; } + + char front() const { return *m_data; } + char back() const { return m_data[(int)m_length - 1]; } + + char operator[](ByteCount pos) const { return m_data[(int)pos]; } + + ByteCount length() const { return m_length; } + CharCount char_length() const { return utf8::distance(begin(), end()); } + bool empty() { return m_length == 0_byte; } + + ByteCount byte_count_to(CharCount count) const; + CharCount char_count_to(ByteCount count) const; + + StringView substr(ByteCount from, ByteCount length = INT_MAX) const; + StringView substr(CharCount from, CharCount length = INT_MAX) const; + + String str() const { return String{begin(), end()}; } + + operator String() const { return str(); } // to remove + +private: + const char* m_data; + ByteCount m_length; +}; + +inline bool StringView::operator==(StringView other) const +{ + return m_length == other.m_length and memcmp(m_data, other.m_data, (int)m_length) == 0; +} + +inline bool StringView::operator!=(StringView other) const +{ + return !this->operator==(other); +} + +inline bool operator==(const char* lhs, StringView rhs) +{ + return StringView{lhs} == rhs; +} + +inline bool operator!=(const char* lhs, StringView rhs) +{ + return StringView{lhs} != rhs; +} + +inline bool operator==(const std::string& lhs, StringView rhs) +{ + return StringView{lhs} == rhs; +} + +inline bool operator!=(const std::string& lhs, StringView rhs) +{ + return StringView{lhs} != rhs; +} + +inline ByteCount StringView::byte_count_to(CharCount count) const +{ + return utf8::advance(begin(), end(), (int)count) - begin(); +} +inline CharCount StringView::char_count_to(ByteCount count) const +{ + return utf8::distance(begin(), begin() + (int)count); +} + +inline StringView StringView::substr(ByteCount from, ByteCount length) const +{ + return StringView{ m_data + (int)from, std::min(m_length - from, length) }; +} + +inline StringView StringView::substr(CharCount from, CharCount length) const +{ + auto beg = utf8::advance(begin(), end(), (int)from); + return StringView{ beg, utf8::advance(beg, end(), length) }; +} + +inline const char* begin(StringView str) +{ + return str.begin(); +} + +inline const char* end(StringView str) +{ + return str.end(); +} + inline String operator+(const char* lhs, const String& rhs) { return String(lhs) + rhs; @@ -76,6 +184,40 @@ inline String operator+(const String& lhs, const std::string& rhs) return lhs + String(rhs); } +inline String& operator+=(String& lhs, StringView rhs) +{ + lhs.append(rhs.data(), (size_t)(int)rhs.length()); + return lhs; +} + +inline String operator+(const char* lhs, StringView rhs) +{ + String res = lhs; + res += rhs; + return res; +} + +inline String operator+(const String& lhs, StringView rhs) +{ + String res = lhs; + res += rhs; + return res; +} + +inline String operator+(StringView lhs, const String& rhs) +{ + String res{lhs.begin(), lhs.end()}; + res.append(rhs); + return res; +} + +inline String operator+(StringView lhs, const char* rhs) +{ + String res{lhs.begin(), lhs.end()}; + res.append(rhs); + return res; +} + inline String operator+(char lhs, const String& rhs) { return String(lhs) + rhs; @@ -114,8 +256,8 @@ String to_string(const StronglyTypedNumber& val) return to_string((ValueType)val); } -bool prefix_match(const String& str, const String& prefix); -bool subsequence_match(const String& str, const String& subseq); +bool prefix_match(StringView str, StringView prefix); +bool subsequence_match(StringView str, StringView subseq); }