eina_cxx: Add eina::string_view class (non owning reference to string)
authorVitor Sousa <vitorsousasilva@gmail.com>
Mon, 12 Jan 2015 13:57:19 +0000 (11:57 -0200)
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>
Tue, 14 Apr 2015 04:06:57 +0000 (01:06 -0300)
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
src/bindings/eina_cxx/Eina.hh
src/bindings/eina_cxx/eina_string_view.hh [new file with mode: 0644]

index 77cf577..4607ece 100644 (file)
@@ -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 \
index c1d755f..18a4a8d 100644 (file)
@@ -13,6 +13,7 @@
 #include <eina_array.hh>
 #include <eina_list.hh>
 #include <eina_stringshare.hh>
+#include <eina_string_view.hh>
 #include <eina_error.hh>
 #include <eina_accessor.hh>
 #include <eina_thread.hh>
diff --git a/src/bindings/eina_cxx/eina_string_view.hh b/src/bindings/eina_cxx/eina_string_view.hh
new file mode 100644 (file)
index 0000000..cfa3ba0
--- /dev/null
@@ -0,0 +1,358 @@
+#ifndef EINA_STRING_VIEW_HH_
+#define EINA_STRING_VIEW_HH_
+
+#include <string>
+#include <iterator>
+#include <stdexcept>
+#include <algorithm>
+
+#include <eina_throw.hh>
+
+namespace efl { namespace eina {
+
+template <typename CharT, typename Traits = std::char_traits<CharT> >
+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<iterator> reverse_iterator;
+   typedef std::reverse_iterator<const_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<CharT, Traits> const& other) noexcept = default;
+   basic_string_view(basic_string_view<CharT, Traits>&& other) noexcept = default;
+
+   template<typename Allocator>
+   basic_string_view(std::basic_string<CharT, Traits, Allocator> 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<CharT, Traits>& operator=(basic_string_view<CharT, Traits> const& other) noexcept = default;
+   basic_string_view<CharT, Traits>& operator=(basic_string_view<CharT, Traits>&& 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> const& s) const
+   {
+      return _len >= s._len && Traits::compare(_str + _len - s._len, s._str, s._len) == 0;
+   }
+
+   size_type find(basic_string_view<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits> 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<CharT, Traits>(data() + pos, len);
+   }
+
+   // Conversions:
+   std::basic_string<CharT, Traits> to_string() const
+   {
+      return std::basic_string<CharT, Traits>(_str, _len);
+   }
+
+   std::basic_string<CharT, Traits> str() const
+   {
+      return to_string();
+   }
+
+   template<typename Allocator>
+   operator std::basic_string<CharT, Traits, Allocator>() const
+   {
+      return std::basic_string<CharT, Traits, Allocator>(_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<CharT, Traits>& s)
+   {
+      std::swap(_str, s._str);
+      std::swap(_len, s._len);
+   }
+
+   //  Comparison operators:
+   friend inline bool operator==(basic_string_view<CharT, Traits> const& s1, basic_string_view<CharT, Traits> const& s2)
+   {
+      if (s1.size() != s2.size())
+        return false;
+      return s1.compare(s2) == 0;
+   }
+
+   friend inline bool operator!=(basic_string_view<CharT, Traits> const& s1, basic_string_view<CharT, Traits> const& s2)
+   {
+      return !(s1 == s2);
+   }
+
+   friend inline bool operator<(basic_string_view<CharT, Traits> const& s1, basic_string_view<CharT, Traits> const& s2)
+   {
+      return s1.compare(s2) < 0;
+   }
+
+   friend inline bool operator>(basic_string_view<CharT, Traits> const& s1, basic_string_view<CharT, Traits> const& s2)
+   {
+      return s2 < s1;
+   }
+
+   friend inline bool operator<=(basic_string_view<CharT, Traits> const& s1, basic_string_view<CharT, Traits> const& s2)
+   {
+       return !(s2 < s1);
+   }
+
+   friend inline bool operator>=(basic_string_view<CharT, Traits> const& s1, basic_string_view<CharT, Traits> const& s2)
+   {
+       return !(s1 < s2);
+   }
+
+private:
+   template <typename Iterator>
+   size_type reverse_distance(Iterator first, Iterator last) const
+   {
+     return _len - 1 - std::distance(first, last);
+   }
+
+   template <typename Iterator>
+   Iterator find_not_of(Iterator first, Iterator last, basic_string_view<CharT, Traits>& 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<class CharT, class Traits>
+inline std::basic_ostream<CharT, Traits>&
+operator<<(std::basic_ostream<CharT, Traits>& os, basic_string_view<CharT,Traits> const& s)
+{
+   return os << s.data();
+}
+
+template <typename CharT, typename Traits>
+void swap(basic_string_view<CharT, Traits>& s1, basic_string_view<CharT, Traits>& s2)
+{
+   s1.swap(s2);
+}
+
+// Instantiations:
+typedef basic_string_view<char> string_view;
+typedef basic_string_view<wchar_t> wstring_view;
+typedef basic_string_view<char16_t> u16string_view;
+typedef basic_string_view<char32_t> u32string_view;
+
+} }
+
+#endif