eina_cxx: Add specialized eina::iterator for Eo* wrappers
authorVitor Sousa <vitorsousasilva@gmail.com>
Tue, 1 Dec 2015 19:25:11 +0000 (17:25 -0200)
committerVitor Sousa <vitorsousasilva@gmail.com>
Fri, 18 Mar 2016 20:47:09 +0000 (17:47 -0300)
Add specialization of eina::iterator for Eo* C++ wrappers.

Specialize ibegin/iend methods in eina::list and eina::array of
Eo* wrappers to use the new eina::iterator.

Add unit test.

src/bindings/eina_cxx/eina_array.hh
src/bindings/eina_cxx/eina_iterator.hh
src/bindings/eina_cxx/eina_list.hh
src/tests/eina_cxx/eina_cxx_test_iterator.cc

index d352de5..7c8e798 100644 (file)
@@ -415,6 +415,32 @@ public:
   {
     return rend();
   }
+  eina::iterator<value_type> ibegin()
+  {
+    return _eo_array_access_traits::ibegin<value_type>(this->_impl._array);
+  }
+  eina::iterator<value_type> iend()
+  {
+    return _eo_array_access_traits::iend<value_type>(this->_impl._array);
+  }
+
+  eina::iterator<value_type const> ibegin() const
+  {
+    return _eo_array_access_traits::ibegin<value_type>(this->_impl._array);
+  }
+
+  eina::iterator<value_type const> iend() const
+  {
+    return _eo_array_access_traits::iend<value_type>(this->_impl._array);
+  }
+  eina::iterator<value_type const> cibegin() const
+  {
+    return _eo_array_access_traits::cibegin<value_type>(this->_impl._array);
+  }
+  eina::iterator<value_type const> ciend() const
+  {
+    return _eo_array_access_traits::ciend<value_type>(this->_impl._array);
+  }
   
   using _base_type::swap;
   using _base_type::max_size;
index 9518cf4..81eb2ee 100644 (file)
@@ -3,6 +3,8 @@
 
 #include <Eina.h>
 
+#include <eina_eo_concrete_fwd.hh>
+
 #include <cstdlib>
 #include <iterator>
 
@@ -128,8 +130,9 @@ protected:
  * automatically take care of allocating a deallocating resources using
  * the RAII programming idiom.
  */
-template <typename T>
-struct iterator : _common_iterator_base<T const>
+template <typename T, typename Enable = void>
+struct iterator
+  : _common_iterator_base<typename std::enable_if<!std::is_convertible<T*, ::efl::eo::concrete const* const>::value, T const>::type>
 {
 private:
   typedef _common_iterator_base<T const> base_type; /**< Type for the base class. */
@@ -204,6 +207,85 @@ public:
   }
 };
 
+template <typename T>
+struct iterator<T, typename std::enable_if<std::is_convertible<T*, ::efl::eo::concrete const* const>::value, void>::type>
+  : _common_iterator_base<Eo const>
+{
+private:
+  typedef _common_iterator_base<Eo const> base_type; /**< Type for the base class. */
+  typename base_type::pointer _value; /**< @internal */
+  typedef iterator<T> self_type; /**< Type for the specialized iterator itself. */
+public:
+  typedef typename base_type::value_type value_type; /**< Type for elements returned by the iterator. */
+  typedef typename base_type::pointer pointer; /**< Type for a pointer to an element. */
+  typedef typename base_type::reference reference; /**< Type for a reference to an element. */
+  typedef typename base_type::difference_type difference_type; /**< Type to represent the distance between two iterators. */
+  typedef typename base_type::iterator_category iterator_category; /**< Defines the iterator category as the same of the base class. */
+
+  /**
+   * @brief Creates a iterator wrapping the given native @c Eina_Iterator handle.
+   *
+   * This constructor creates an iterator that wraps the given native
+   * @c Eina_Iterator handle, providing an OOP interface to it.
+   */
+  explicit iterator(Eina_Iterator* iterator_ = 0)
+    : base_type(iterator_)
+  {
+    if(this->_iterator)
+      ++*this;
+  }
+
+
+  /**
+   * @brief Move the iterator to the next position.
+   * @return The iterator itself.
+   *
+   * This operator increments the iterator, making it point to the
+   * position right after the current one.
+   * At the end, it returns a reference to itself.
+   */
+  self_type& operator++()
+  {
+    void* data;
+    Eina_Bool r = ::eina_iterator_next(this->_iterator, &data);
+    if(!r)
+      this->_iterator = 0;
+    _value = static_cast<pointer>(data);
+    return *this;
+  }
+
+  /**
+   * @brief Move the iterator to the next position.
+   * @return The iterator itself.
+   *
+   * Works exactly like @ref operator++().
+   */
+  self_type& operator++(int)
+  {
+    return ++**this;
+  }
+
+  /**
+   * @brief Get a reference to the element currently pointed by the iterator.
+   * @return Reference to the current element.
+   */
+  T const& operator*() const
+  {
+    // relies on layout compatibility between eo::concrete and Eo*
+    return *reinterpret_cast<T const*>(&_value);
+  }
+
+  /**
+   * @brief Return a pointer to the current element, which member will be accessed.
+   * @return Pointer to the element currently pointed by the iterator.
+   */
+  T const* operator->() const
+  {
+    // relies on layout compatibility between eo::concrete and Eo*
+    return reinterpret_cast<T const*>(&_value);
+  }
+};
+
 /**
  * @}
  */
index c1a02b5..ae140b2 100644 (file)
@@ -415,6 +415,30 @@ public:
   {
     return rend();
   }
+  eina::iterator<value_type> ibegin()
+  {
+    return _eo_list_access_traits::ibegin<value_type>(this->_impl._list);
+  }
+  eina::iterator<value_type> iend()
+  {
+    return _eo_list_access_traits::iend<value_type>(this->_impl._list);
+  }
+  eina::iterator<value_type const> ibegin() const
+  {
+    return _eo_list_access_traits::ibegin<value_type>(this->_impl._list);
+  }
+  eina::iterator<value_type const> iend() const
+  {
+    return _eo_list_access_traits::iend<value_type>(this->_impl._list);
+  }
+  eina::iterator<value_type const> cibegin() const
+  {
+    return _eo_list_access_traits::cibegin<value_type>(this->_impl._list);
+  }
+  eina::iterator<value_type const> ciend() const
+  {
+    return _eo_list_access_traits::ciend<value_type>(this->_impl._list);
+  }
   using _base_type::swap;
   using _base_type::max_size;
   using _base_type::native_handle;
index 8f7136a..3fe4c9d 100644 (file)
@@ -3,8 +3,12 @@
 #endif
 
 #include <Eina.hh>
+#include <Eo.hh>
+
+#include <algorithm>
 
 #include "eina_cxx_suite.h"
+#include "simple.eo.hh"
 
 START_TEST(eina_cxx_iterator_equal)
 {
@@ -28,8 +32,35 @@ START_TEST(eina_cxx_iterator_equal)
 }
 END_TEST
 
+START_TEST(eina_cxx_eo_iterator_equal)
+{
+  efl::eina::eina_init eina_init;
+  efl::eo::eo_init eo_init;
+
+  efl::eina::list<simple> list;
+
+  simple const w1;
+  simple const w2;
+  simple const w3;
+  simple const w4;
+
+  list.push_back(w1);
+  list.push_back(w2);
+  list.push_back(w3);
+  list.push_back(w4);
+
+  efl::eina::iterator<simple> iterator = list.ibegin()
+    , last_iterator = list.iend();
+
+  simple const result[] = {w1, w2, w3, w4};
+
+  ck_assert(std::equal(iterator, last_iterator, result));
+}
+END_TEST
+
 void
 eina_test_iterator(TCase *tc)
 {
   tcase_add_test(tc, eina_cxx_iterator_equal);
+  tcase_add_test(tc, eina_cxx_eo_iterator_equal);
 }