From be58d02cb655c244a659abbcdb9ab44e8a5459ce Mon Sep 17 00:00:00 2001 From: Vitor Sousa Date: Mon, 12 Jan 2015 11:57:19 -0200 Subject: [PATCH] eina_cxx: Add eina::string_view class (non owning reference to string) Add an implementation of string_view to Eina C++. It is a non owning reference to a string that allows lightweight argument passing of both C++ std::string and C strings (const char*) on interfaces. --- src/Makefile_Eina_Cxx.am | 1 + src/bindings/eina_cxx/Eina.hh | 1 + src/bindings/eina_cxx/eina_string_view.hh | 358 ++++++++++++++++++++++ 3 files changed, 360 insertions(+) create mode 100644 src/bindings/eina_cxx/eina_string_view.hh diff --git a/src/Makefile_Eina_Cxx.am b/src/Makefile_Eina_Cxx.am index 77cf577fb0..4607ecef1c 100644 --- a/src/Makefile_Eina_Cxx.am +++ b/src/Makefile_Eina_Cxx.am @@ -27,6 +27,7 @@ bindings/eina_cxx/eina_ptrlist.hh \ bindings/eina_cxx/eina_range_types.hh \ bindings/eina_cxx/eina_ref.hh \ bindings/eina_cxx/eina_stringshare.hh \ +bindings/eina_cxx/eina_string_view.hh \ bindings/eina_cxx/eina_thread.hh \ bindings/eina_cxx/eina_throw.hh \ bindings/eina_cxx/eina_tuple.hh \ diff --git a/src/bindings/eina_cxx/Eina.hh b/src/bindings/eina_cxx/Eina.hh index c1d755f9b7..18a4a8d46f 100644 --- a/src/bindings/eina_cxx/Eina.hh +++ b/src/bindings/eina_cxx/Eina.hh @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bindings/eina_cxx/eina_string_view.hh b/src/bindings/eina_cxx/eina_string_view.hh new file mode 100644 index 0000000000..cfa3ba0d85 --- /dev/null +++ b/src/bindings/eina_cxx/eina_string_view.hh @@ -0,0 +1,358 @@ +#ifndef EINA_STRING_VIEW_HH_ +#define EINA_STRING_VIEW_HH_ + +#include +#include +#include +#include + +#include + +namespace efl { namespace eina { + +template > +class basic_string_view +{ +public: + // Types: + typedef Traits traits_type; + typedef CharT value_type; + typedef CharT& reference; + typedef CharT const& const_reference; + typedef CharT* pointer; + typedef CharT const* const_pointer; + typedef const_pointer const_iterator; + typedef const_iterator iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + + // Constants: + static constexpr size_type npos = size_type(-1); + + // Constructors: + constexpr basic_string_view() noexcept + : _str(nullptr), _len(0) + {} + + basic_string_view(basic_string_view const& other) noexcept = default; + basic_string_view(basic_string_view&& other) noexcept = default; + + template + basic_string_view(std::basic_string const& str) noexcept + : _str(str.data()), _len(str.length()) + {} + + basic_string_view(CharT const* c_str) + : _str(c_str), _len(Traits::length(c_str)) + {} + +// basic_string_view(CharT const* c_str, size_type len) noexcept +// : _str(c_str), _len(len) +// {} + + // Assignment: + basic_string_view& operator=(basic_string_view const& other) noexcept = default; + basic_string_view& operator=(basic_string_view&& other) noexcept = default; + + // Iterators + const_iterator begin() const noexcept { return _str; } + const_iterator cbegin() const noexcept { return _str; } + const_iterator end() const noexcept { return _str + _len; } + const_iterator cend() const noexcept { return _str + _len; } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } + + // Capacity: + size_type size() const noexcept { return _len; } + size_type length() const noexcept { return _len; } + bool empty() const noexcept { return _len == 0; } + + // Element access: + const_reference operator[](size_type pos) const { return _str[pos]; } + + const_reference at(size_type pos) const + { + if (pos >= _len) + EFL_CXX_THROW(std::out_of_range("efl::eina::basic_string_view::at")); + return _str[pos]; + } + + const_reference front() const { return _str[0]; } + const_reference back() const { return _str[_len-1]; } + + // Operations: + CharT const* data() const noexcept { return _str; } + + size_type copy(CharT* s, size_type len, size_type pos = 0) const + { + Traits::copy(s, _str+pos, len); + return len; + } + + int compare(basic_string_view const& s) const + { + const int cmp = Traits::compare(_str, s._str, (std::min)(_len, s._len)); + return cmp != 0 ? cmp : ( _len == s._len ? 0 : _len < s._len ? -1 : 1 ); + } + + int compare(size_type pos, size_type len, basic_string_view const& s) const + { + const int cmp = Traits::compare(_str+pos, s._str, (std::min)(len, s._len)); + return cmp != 0 ? cmp : ( len == s._len ? 0 : len < s._len ? -1 : 1 ); + } + + int compare(size_type pos1, size_type len1, basic_string_view const& s, size_type pos2, size_type len2) const + { + const int cmp = Traits::compare(_str+pos1, s._str+pos2, (std::min)(len1, len2)); + return cmp != 0 ? cmp : ( len1 == len2 ? 0 : len1 < len2 ? -1 : 1 ); + } + + bool starts_with(CharT c) const + { + return !empty() && Traits::eq(c, front()); + } + + bool starts_with(basic_string_view const& s) const + { + return _len >= s._len && Traits::compare(_str, s._str, s._len) == 0; + } + + bool ends_with(CharT c) const + { + return !empty() && Traits::eq(c, back()); + } + + bool ends_with(basic_string_view const& s) const + { + return _len >= s._len && Traits::compare(_str + _len - s._len, s._str, s._len) == 0; + } + + size_type find(basic_string_view const& s) const + { + const_iterator iter = std::search(cbegin(), cend(), s.cbegin(), s.cend(), Traits::eq); + return iter == cend () ? npos : std::distance(cbegin(), iter); + } + + size_type find(basic_string_view const& s, size_type pos) const + { + if (pos >= _len) + return npos; + const_iterator iter = std::search(cbegin()+pos, cend(), s.cbegin(), s.cend(), Traits::eq); + return iter == cend () ? npos : std::distance(cbegin(), iter); + } + + size_type find(CharT c) const + { + const_iterator iter = std::find_if(cbegin(), cend(), [=](CharT val) { return Traits::eq(c, val); }); + return iter == cend() ? npos : std::distance(cbegin(), iter); + } + + size_type find(CharT c, size_type pos) const + { + if (pos >= _len) + return npos; + const_iterator iter = std::find_if(cbegin()+pos, cend(), [=](CharT val) { return Traits::eq(c, val); }); + return iter == cend() ? npos : std::distance(cbegin(), iter); + } + + size_type rfind(basic_string_view const& s) const + { + const_reverse_iterator iter = std::search(crbegin(), crend(), s.crbegin(), s.crend(), Traits::eq); + return iter == crend() ? npos : reverse_distance(crbegin(), iter) - s.lenght(); + } + + size_type rfind(basic_string_view const& s, size_type pos) const + { + if (pos >= _len) + return npos; + const_reverse_iterator iter = std::search(crbegin()+pos, crend(), s.crbegin(), s.crend(), Traits::eq); + return iter == crend() ? npos : reverse_distance(crbegin(), iter) - s.lenght(); + } + + size_type rfind(CharT c) const + { + const_reverse_iterator iter = std::find_if(crbegin(), crend(), [&](CharT val) { return Traits::eq(c, val); }); + return iter == crend() ? npos : reverse_distance(crbegin(), iter); + } + + size_type rfind(CharT c, size_type pos) const + { + pos = (pos >= _len) ? 0 : _len - pos - 1; + const_reverse_iterator iter = std::find_if(crbegin()+pos, crend(), [&](CharT val) { return Traits::eq(c, val); }); + return iter == crend() ? npos : reverse_distance(crbegin(), iter); + } + + size_type find_first_of(CharT c) const { return find(c); } + size_type find_last_of (CharT c) const { return rfind(c); } + + size_type find_first_of(basic_string_view const& s) const + { + const_iterator iter = std::find_first_of(cbegin(), cend(), s.cbegin(), s.cend(), Traits::eq); + return iter == cend() ? npos : std::distance(cbegin(), iter); + } + + size_type find_last_of(basic_string_view const& s) const + { + const_reverse_iterator iter = std::find_first_of(crbegin(), crend(), s.cbegin(), s.cend(), Traits::eq); + return iter == crend () ? npos : reverse_distance(crbegin(), iter); + } + + size_type find_first_not_of(basic_string_view const& s) const + { + const_iterator iter = find_not_of(cbegin(), cend(), s); + return iter == cend() ? npos : std::distance(cbegin(), iter); + } + + size_type find_first_not_of(CharT c) const + { + for (const_iterator iter = cbegin(); iter != cend(); ++iter) + if (!Traits::eq(c, *iter)) + return std::distance(cbegin(), iter); + return npos; + } + + size_type find_last_not_of(basic_string_view const& s) const + { + const_reverse_iterator iter = find_not_of(crbegin(), crend(), s); + return iter == crend() ? npos : reverse_distance(crbegin(), iter); + } + + size_type find_last_not_of(CharT c) const + { + for (const_reverse_iterator iter = crbegin(); iter != crend(); ++iter) + if (!Traits::eq(c, *iter)) + return reverse_distance(crbegin(), iter); + return npos; + } + + // XXX: returning std::string instead of eina::string_view + std::basic_string substr(size_type pos, size_type len=npos) const + { + if (pos > size()) + EFL_CXX_THROW(std::out_of_range("efl::eina::string_view::substr")); + if (len == npos || pos + len > size()) + len = size () - pos; + return std::basic_string(data() + pos, len); + } + + // Conversions: + std::basic_string to_string() const + { + return std::basic_string(_str, _len); + } + + std::basic_string str() const + { + return to_string(); + } + + template + operator std::basic_string() const + { + return std::basic_string(_str, _len); + } + + // Modifiers: +// void clear() noexcept { _len = 0; } +// +// void remove_prefix(size_type n) noexcept +// { +// if (n > _len) +// n = _len; +// _str += n; +// _len -= n; +// } +// +// void remove_suffix(size_type n) noexcept +// { +// if (n > _len) +// n = _len; +// _len -= n; +// } + + void swap(basic_string_view& s) + { + std::swap(_str, s._str); + std::swap(_len, s._len); + } + + // Comparison operators: + friend inline bool operator==(basic_string_view const& s1, basic_string_view const& s2) + { + if (s1.size() != s2.size()) + return false; + return s1.compare(s2) == 0; + } + + friend inline bool operator!=(basic_string_view const& s1, basic_string_view const& s2) + { + return !(s1 == s2); + } + + friend inline bool operator<(basic_string_view const& s1, basic_string_view const& s2) + { + return s1.compare(s2) < 0; + } + + friend inline bool operator>(basic_string_view const& s1, basic_string_view const& s2) + { + return s2 < s1; + } + + friend inline bool operator<=(basic_string_view const& s1, basic_string_view const& s2) + { + return !(s2 < s1); + } + + friend inline bool operator>=(basic_string_view const& s1, basic_string_view const& s2) + { + return !(s1 < s2); + } + +private: + template + size_type reverse_distance(Iterator first, Iterator last) const + { + return _len - 1 - std::distance(first, last); + } + + template + Iterator find_not_of(Iterator first, Iterator last, basic_string_view& s) const + { + for (; first != last; ++first) + if (0 == Traits::find(s._str, s._len, *first)) + return first; + return last; + } + + const CharT* _str; + size_type _len; +}; + +// Stream operation +template +inline std::basic_ostream& +operator<<(std::basic_ostream& os, basic_string_view const& s) +{ + return os << s.data(); +} + +template +void swap(basic_string_view& s1, basic_string_view& s2) +{ + s1.swap(s2); +} + +// Instantiations: +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; +typedef basic_string_view u16string_view; +typedef basic_string_view u32string_view; + +} } + +#endif