#include <Eina.h>
#include <eina_error.hh>
#include <eina_throw.hh>
+#include <eina_eo_base_fwd.hh>
#include <memory>
#include <iterator>
* Wraps an native Eina_Accessor and provide random access to data structures.
*/
template <typename T>
-struct accessor
+struct accessor_common_base
{
typedef unsigned int key_type; /**< Type for accessor key. */
typedef T mapped_type; /**< Type for accessor mapped elements. */
/**
* @brief Default constructor. Creates an empty accessor.
*/
- accessor() : _impl(0) {}
+ accessor_common_base() : _impl(0) {}
/**
* @brief Create an accessor object that wraps the given Eina accessor.
* gains ownership of the given handle, deallocating it at destruction
* time.
*/
- explicit accessor(Eina_Accessor* impl)
+ explicit accessor_common_base(Eina_Accessor* impl)
: _impl(impl)
{
assert(_impl != 0);
* accessor object, so that the newly created object can be used
* freely.
*/
- accessor(accessor<T> const& other)
+ accessor_common_base(accessor_common_base<T> const& other)
: _impl(eina_accessor_clone(other._impl))
{}
* This operator replaces the current native Eina accessor by a copy
* of the native accessor inside the given object.
*/
- accessor<T>& operator=(accessor<T> const& other)
+ accessor_common_base<T>& operator=(accessor_common_base<T> const& other)
{
eina_accessor_free(_impl);
_impl = eina_accessor_clone(other._impl);
/**
* @brief Destructor. Free the internal @c Eina_Acessor.
*/
- ~accessor()
+ ~accessor_common_base()
{
eina_accessor_free(_impl);
}
/**
+ * @brief Get the handle for the wrapped @c Eina_Accessor.
+ * @return Internal handle for the native Eina accessor.
+ *
+ * This member function returns the native @c Eina_Accessor handle
+ * that is wrapped inside this object.
+ *
+ * @warning It is important to take care when using it, since the
+ * handle will be automatically release upon object destruction.
+ */
+ Eina_Accessor* native_handle() const;
+
+ /**
+ * @brief Swap content between both objects.
+ * @param other Other accessor object.
+ *
+ * This member function swaps the internal @c Eina_Acessor with the
+ * given accessor object.
+ */
+ void swap(accessor_common_base<T>& other)
+ {
+ std::swap(_impl, other._impl);
+ }
+ /**
+ * @brief Cast to @c boolean based on the wrapped @c Eina_Accessor.
+ * @return @c true if the wrapped handle is not @c NULL, @c false otherwise.
+ *
+ * Boolean typecast overload for easy validation of the accessor
+ * object. Returns @c false if it does not have an internal
+ * @c Eina_Accessor, i.e. if the current handle is not @c NULL.
+ */
+ explicit operator bool() const
+ {
+ return native_handle() ? &accessor_common_base<T>::native_handle : 0 ;
+ }
+
+ /**
+ * @internal
+ * Member variable for storing the native Eina_Accessor pointer.
+ */
+ Eina_Accessor* _impl;
+};
+
+template <typename T, typename Enable = T>
+struct accessor;
+
+template <typename T>
+struct accessor<T, typename std::enable_if< ! std::is_base_of<efl::eo::base, T>::value, T>::type>
+ : accessor_common_base<T>
+{
+ typedef accessor_common_base<T> _base_type;
+ typedef accessor<T> _self_type;
+
+ typedef typename _base_type::key_type key_type;
+ typedef typename _base_type::mapped_type mapped_type;
+ typedef typename _base_type::value_type value_type;
+ typedef typename _base_type::size_type size_type;
+
+ /**
+ * @brief Default constructor. Creates an empty accessor.
+ */
+ accessor() : _base_type() {}
+
+ /**
+ * @brief Create an accessor object that wraps the given Eina accessor.
+ * @param impl Native @c Eina_Accessor to be wrapped.
+ *
+ * This constructor creates an accessor object that wraps the given
+ * Eina_Accessor and provides access to the data pointed by it.
+ *
+ * @warning It is important to note that the created accessor object
+ * gains ownership of the given handle, deallocating it at destruction
+ * time.
+ */
+ explicit accessor(Eina_Accessor* impl) : _base_type(impl) {}
+
+ /**
+ * @brief Copy constructor. Creates a copy of the given accessor object.
+ * @param other Other accessor object.
+ *
+ * This constructor clones the internal @c Eina_Accessor of the given
+ * accessor object, so that the newly created object can be used
+ * freely.
+ */
+ accessor(_self_type const& other) : _base_type(other) {}
+
+ /**
+ * @brief Assignment Operator. Replace the current content.
+ * @param other Other accessor object.
+ * @throw <tt>eina::system_error</tt> if the Eina accessor could not be cloned.
+ *
+ * This operator replaces the current native Eina accessor by a copy
+ * of the native accessor inside the given object.
+ */
+ _self_type& operator=(_self_type const& other)
+ {
+ _base_type::operator=(other);
+ }
+
+ /**
+ * @brief Destructor. Free the internal @c Eina_Acessor.
+ */
+ ~accessor()
+ {
+ // Cleanup is already done in the base class.
+ }
+
+ /**
* @brief Retrieve the data of the accessor at a given position.
* @param i The position of the element.
* @return Constant reference to the retrieved data.
*/
mapped_type& operator[](size_type i) const
{
- assert(_impl != 0);
+ assert(this->_impl != 0);
void* p;
- if(!eina_accessor_data_get(_impl, i, &p))
+ if(!eina_accessor_data_get(this->_impl, i, &p))
{
eina::error_code ec = efl::eina::get_error_code();
EFL_CXX_THROW(eina::system_error(ec, "EFL Eina Error"));
return *static_cast<mapped_type*>(p);
}
+ using _base_type::native_handle;
+
/**
- * @brief Get the handle for the wrapped @c Eina_Accessor.
- * @return Internal handle for the native Eina accessor.
+ * @brief Swap content between both objects.
+ * @param other Other accessor object.
*
- * This member function returns the native @c Eina_Accessor handle
- * that is wrapped inside this object.
+ * This member function swaps the internal @c Eina_Acessor with the
+ * given accessor object.
+ */
+ void swap(_self_type& other)
+ {
+ _base_type::swap(other);
+ }
+
+ /**
+ * @brief Cast to @c boolean based on the wrapped @c Eina_Accessor.
+ * @return @c true if the wrapped handle is not @c NULL, @c false otherwise.
*
- * @warning It is important to take care when using it, since the
- * handle will be automatically release upon object destruction.
+ * Boolean typecast overload for easy validation of the accessor
+ * object. Returns @c false if it does not have an internal
+ * @c Eina_Accessor, i.e. if the current handle is not @c NULL.
*/
- Eina_Accessor* native_handle() const;
+ explicit operator bool() const
+ {
+ return native_handle() ? &_self_type::native_handle : 0 ;
+ }
+};
+
+template <typename T>
+struct accessor<T, typename std::enable_if<std::is_base_of<efl::eo::base, T>::value, T>::type>
+ : accessor_common_base<T>
+{
+ typedef accessor_common_base<T> _base_type;
+ typedef accessor<T> _self_type;
+
+ typedef typename _base_type::key_type key_type;
+ typedef typename _base_type::mapped_type mapped_type;
+ typedef typename _base_type::value_type value_type;
+ typedef typename _base_type::size_type size_type;
+
+ /**
+ * @brief Default constructor. Creates an empty accessor.
+ */
+ accessor() : _base_type() {}
+
+ /**
+ * @brief Create an accessor object that wraps the given Eina accessor.
+ * @param impl Native @c Eina_Accessor to be wrapped.
+ *
+ * This constructor creates an accessor object that wraps the given
+ * Eina_Accessor and provides access to the data pointed by it.
+ *
+ * @warning It is important to note that the created accessor object
+ * gains ownership of the given handle, deallocating it at destruction
+ * time.
+ */
+ explicit accessor(Eina_Accessor* impl) : _base_type(impl) {}
+
+ /**
+ * @brief Copy constructor. Creates a copy of the given accessor object.
+ * @param other Other accessor object.
+ *
+ * This constructor clones the internal @c Eina_Accessor of the given
+ * accessor object, so that the newly created object can be used
+ * freely.
+ */
+ accessor(_self_type const& other) : _base_type(other) {}
+
+ /**
+ * @brief Assignment Operator. Replace the current content.
+ * @param other Other accessor object.
+ * @throw <tt>eina::system_error</tt> if the Eina accessor could not be cloned.
+ *
+ * This operator replaces the current native Eina accessor by a copy
+ * of the native accessor inside the given object.
+ */
+ _self_type& operator=(_self_type const& other)
+ {
+ _base_type::operator=(other);
+ }
+
+ /**
+ * @brief Destructor. Free the internal @c Eina_Acessor.
+ */
+ ~accessor()
+ {
+ // Cleanup is already done in the base class.
+ }
+
+ /**
+ * @brief Retrieve the data of the accessor at a given position.
+ * @param i The position of the element.
+ * @return Constant reference to the retrieved data.
+ * @throw <tt>eina::system_error</tt> if the given element could not be retrieved.
+ *
+ * This operator retrieves a constant reference to the element at the
+ * given position. If the element could not be retrieved an
+ * <tt>eina::system_error</tt> is thrown.
+ */
+ mapped_type operator[](size_type i) const
+ {
+ assert(this->_impl != 0);
+ void* p;
+ if(!eina_accessor_data_get(this->_impl, i, &p))
+ {
+ eina::error_code ec = efl::eina::get_error_code();
+ EFL_CXX_THROW(eina::system_error(ec, "EFL Eina Error"));
+ }
+
+ // TODO Do we need to ref this Eo* instance ?
+
+ return mapped_type(::eo_ref(static_cast<Eo*>(p)));
+ }
+
+ using _base_type::native_handle;
/**
* @brief Swap content between both objects.
* This member function swaps the internal @c Eina_Acessor with the
* given accessor object.
*/
- void swap(accessor<T>& other)
+ void swap(_self_type& other)
{
- std::swap(_impl, other._impl);
+ _base_type::swap(other);
}
+
/**
* @brief Cast to @c boolean based on the wrapped @c Eina_Accessor.
* @return @c true if the wrapped handle is not @c NULL, @c false otherwise.
*/
explicit operator bool() const
{
- return native_handle() ? &accessor<T>::native_handle : 0 ;
+ return native_handle() ? &_self_type::native_handle : 0 ;
}
-private:
-
- /**
- * @internal
- * Member variable for storing the native Eina_Accessor pointer.
- */
- Eina_Accessor* _impl;
};
/**
* @{
*/
+template <typename T, class Enable = T>
+struct accessor_iterator;
+
/**
* Random access iterator for <tt>eina::accessor</tt>.
*/
template <typename T>
-struct accessor_iterator
+struct accessor_iterator<T, typename std::enable_if< ! std::is_base_of<efl::eo::base, T>::value, T>::type>
{
typedef T value_type; /**< Type of the elements. */
typedef value_type* pointer; /**< Pointer to element type. */
std::swap(_accessor, other._accessor);
}
-private:
accessor<T> _accessor; /**< @internal */
unsigned int _index; /**< @internal */
+};
+
+/**
+ * Specialization for all data types that are not derivated from efl::eo::base.
+ */
+template <typename T>
+struct accessor_iterator<T, typename std::enable_if<std::is_base_of<efl::eo::base, T>::value, T>::type>
+{
+ typedef T value_type; /**< Type of the elements. */
+ typedef value_type* pointer; /**< Pointer to element type. */
+ typedef value_type& reference; /**< Reference to element type. */
+ typedef std::ptrdiff_t difference_type; /**< Type to represent the distance between two @ref accessor_iterators */
+ typedef std::input_iterator_tag iterator_category; /**< Defines the iterator as being a random access iterator. */
+
/**
- * @brief Check if @p lhs and @p rhs point to the same position.
- * @param lhs @c accessor_iterator at the left side of the expression.
- * @param rhs @c accessor_iterator at the right side of the expression.
- * @return @c true if both @p lhs and @p rhs point to the same position.
+ * @brief Creates an @c accessor_iterator to the given <tt>eina::accessor</tt>.
+ * @param a <tt>eina::accessor</tt> object.
+ * @param pos Initial position of the iterator (Default = @c 0).
+ *
+ * This constructor creates an @c accessor_iterator for the given
+ * <tt>eina::accessor</tt> object. The position initially pointed by
+ * the iterator can be supplied via the @p pos argument, by default
+ * it is the first position (index @c 0).
+ */
+ accessor_iterator(accessor<T> const& a, unsigned int pos = 0u)
+ : _accessor(a), _index(pos), _tmp_value(0)
+ {}
+
+ ~accessor_iterator()
+ {
+ if(_tmp_value) {
+ delete _tmp_value;
+ }
+ }
+
+ /**
+ * @brief Move the iterator forward by @p i positions.
+ * @param i Number of positions to move.
+ * @return The @c accessor_iterator itself.
+ */
+ accessor_iterator<T>& operator+=(difference_type i)
+ {
+ _index += i;
+ return *this;
+ }
+
+ /**
+ * @brief Move the iterator back by @p i positions.
+ * @param i Number of positions to move.
+ * @return The @c accessor_iterator itself.
*/
- template <typename U>
- friend bool operator==(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+ accessor_iterator<T>& operator-=(difference_type i)
{
- return lhs._index == rhs._index;
+ _index -= i;
+ return *this;
}
/**
- * @brief Get the distance between two <tt>accessor_iterator</tt>s.
- * @param lhs @c accessor_iterator at the left side of the expression.
- * @param rhs @c accessor_iterator at the right side of the expression.
- * @return The number of elements between @p lhs and @p rhs.
+ * @brief Get the element @p i positions away from the current element.
+ * @param i Position relative to the current element.
+ * @return Copy of the element @p i positions away from the
+ * element currently pointed by the @c accessor_iterator.
*/
- template <typename U>
- friend typename accessor_iterator<U>::difference_type
- operator-(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+ value_type operator[](difference_type i)
{
- return lhs._index - rhs._index;
+ return _accessor[_index + i];
}
/**
- * @brief Get an @c accessor_iterator moved @p rhs positions forward.
- * @param lhs @c accessor_iterator object.
- * @param rhs Number of positions relative to the current element.
- * @return Copy of @p lhs moved @p rhs positions forward.
+ * @brief Move the iterator to the next position.
+ * @return The @c accessor_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.
*/
- template <typename U>
- friend
- accessor_iterator<U> operator+(accessor_iterator<U> lhs
- , typename accessor_iterator<U>::difference_type rhs)
+ accessor_iterator<T>& operator++()
{
- lhs._index += rhs;
- return lhs;
+ ++_index;
+ return *this;
}
/**
- * @brief Get an @c accessor_iterator moved @p lhs positions forward.
- * @param lhs Number of positions relative to the current element.
- * @param rhs @c accessor_iterator object.
- * @return Copy of @p rhs moved @p lhs positions forward.
+ * @brief Move the iterator to the previous position.
+ * @return The @c accessor_iterator itself.
+ *
+ * This operator decrements the iterator, making it point to the
+ * position right before the current one.
+ * At the end, it returns a reference to itself.
*/
- template <typename U>
- friend
- accessor_iterator<U> operator+(typename accessor_iterator<U>::difference_type lhs
- , accessor_iterator<U> rhs)
+ accessor_iterator<T>& operator--()
{
- return rhs + lhs;
+ --_index;
+ return *this;
}
/**
- * @brief Check if @p lhs points to a position before the position pointed by @p rhs.
- * @param lhs @c accessor_iterator at the left side of the expression.
- * @param rhs @c accessor_iterator at the right side of the expression.
- * @return @c true if @p lhs points to a position before the position
- * pointed by @p rhs, @c false otherwise.
+ * @brief Move the iterator to the next position.
+ * @return A copy of the @c accessor_iterator before the change.
+ *
+ * This operator increments the iterator, making it point to the
+ * position right after the current one.
+ * At the end, it returns a copy of the @c accessor_iterator before
+ * the change.
*/
- template <typename U>
- friend bool operator<(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+ accessor_iterator<T>& operator++(int)
{
- return lhs._index < rhs._index;
+ accessor_iterator<T> tmp(*this);
+ ++*this;
+ return tmp;
}
/**
- * @brief Check if the position pointed by @p lhs is the same or is before the one pointed by @p rhs.
- * @param lhs @c accessor_iterator at the left side of the expression.
- * @param rhs @c accessor_iterator at the right side of the expression.
- * @return @c true if the position pointed by @p lhs is the same or is
- * before the position pointed by @p rhs, @c false otherwise.
+ * @brief Move the iterator to the previous position.
+ * @return A copy of the @c accessor_iterator before the change.
+ *
+ * This operator decrements the iterator, making it point to the
+ * position right before the current one.
+ * At the end, it returns a copy of the @c accessor_iterator before
+ * the change.
*/
- template <typename U>
- friend bool operator<=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+ accessor_iterator<T>& operator--(int)
{
- return lhs._index <= rhs._index;
+ accessor_iterator<T> tmp(*this);
+ --*this;
+ return tmp;
}
+
+ /**
+ * @brief Get a reference to the element currently pointed by the @c accessor_iterator.
+ * @return Copy of the current element.
+ */
+ value_type operator*() const
+ {
+ return _accessor[_index];
+ }
+
+ /**
+ * @brief Return a pointer to a copy of the current element, which member will be accessed.
+ * @return Pointer a copy of the element currently pointed by the @c accessor_iterator.
+ */
+ pointer operator->() const
+ {
+ if(!_tmp_value)
+ {
+ _tmp_value = new value_type(_accessor[_index]);
+ }
+ else
+ {
+ *_tmp_value = _accessor[_index];
+ }
+ return _tmp_value;
+ }
+
+ /**
+ * @brief Swap content with the given @c accessor_iterator.
+ * @param other Another @c accessor_iterator of the same type.
+ */
+ void swap(accessor_iterator<T>& other)
+ {
+ std::swap(_index, other._index);
+ std::swap(_accessor, other._accessor);
+ std::swap(_tmp_value, other._tmp_value);
+ }
+
+ accessor<T> _accessor; /**< @internal */
+ unsigned int _index; /**< @internal */
+ pointer _tmp_value; /**< @internal */
};
/**
- * @brief Check if the position pointed by @p lhs is the same or is after the one pointed by @p rhs.
+ * @brief Check if @p lhs and @p rhs point to the same position.
* @param lhs @c accessor_iterator at the left side of the expression.
* @param rhs @c accessor_iterator at the right side of the expression.
- * @return @c true if the position pointed by @p lhs is the same or is
- * after the position pointed by @p rhs, @c false otherwise.
+ * @return @c true if both @p lhs and @p rhs point to the same position.
*/
template <typename U>
-bool operator>=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+bool operator==(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
{
- return !(lhs < rhs);
+ return lhs._index == rhs._index;
+}
+
+/**
+ * @brief Check if @p lhs and @p rhs point to different positions.
+ * @param lhs @c accessor_iterator at the left side of the expression.
+ * @param rhs @c accessor_iterator at the right side of the expression.
+ * @return @c true if @p lhs and @p rhs point to different positions.
+ */
+template <typename U>
+bool operator!=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+{
+ return !(lhs == rhs);
+}
+
+/**
+ * @brief Get the distance between two <tt>accessor_iterator</tt>s.
+ * @param lhs @c accessor_iterator at the left side of the expression.
+ * @param rhs @c accessor_iterator at the right side of the expression.
+ * @return The number of elements between @p lhs and @p rhs.
+ */
+template <typename U>
+typename accessor_iterator<U>::difference_type
+operator-(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+{
+ return lhs._index - rhs._index;
+}
+
+/**
+ * @brief Get an @c accessor_iterator moved @p rhs positions forward.
+ * @param lhs @c accessor_iterator object.
+ * @param rhs Number of positions relative to the current element.
+ * @return Copy of @p lhs moved @p rhs positions forward.
+ */
+template <typename U>
+accessor_iterator<U> operator+(accessor_iterator<U> lhs
+ , typename accessor_iterator<U>::difference_type rhs)
+{
+ lhs += rhs;
+ return lhs;
+}
+
+/**
+ * @brief Get an @c accessor_iterator moved @p lhs positions forward.
+ * @param lhs Number of positions relative to the current element.
+ * @param rhs @c accessor_iterator object.
+ * @return Copy of @p rhs moved @p lhs positions forward.
+ */
+template <typename U>
+accessor_iterator<U> operator+(typename accessor_iterator<U>::difference_type lhs
+ , accessor_iterator<U> const& rhs)
+{
+ return rhs + lhs;
+}
+
+/**
+ * @brief Check if @p lhs points to a position before the position pointed by @p rhs.
+ * @param lhs @c accessor_iterator at the left side of the expression.
+ * @param rhs @c accessor_iterator at the right side of the expression.
+ * @return @c true if @p lhs points to a position before the position
+ * pointed by @p rhs, @c false otherwise.
+ */
+template <typename U>
+bool operator<(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+{
+ return lhs._index < rhs._index;
}
/**
template <typename U>
bool operator>(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
{
- return !(lhs <= rhs);
+ return rhs < lhs;
}
/**
- * @brief Check if @p lhs and @p rhs point to different positions.
+ * @brief Check if the position pointed by @p lhs is the same or is before the one pointed by @p rhs.
* @param lhs @c accessor_iterator at the left side of the expression.
* @param rhs @c accessor_iterator at the right side of the expression.
- * @return @c true if @p lhs and @p rhs point to different positions.
+ * @return @c true if the position pointed by @p lhs is the same or is
+ * before the position pointed by @p rhs, @c false otherwise.
*/
template <typename U>
-bool operator!=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+bool operator<=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
{
- return !(lhs == rhs);
+ return !(rhs < lhs);
+}
+
+/**
+ * @brief Check if the position pointed by @p lhs is the same or is after the one pointed by @p rhs.
+ * @param lhs @c accessor_iterator at the left side of the expression.
+ * @param rhs @c accessor_iterator at the right side of the expression.
+ * @return @c true if the position pointed by @p lhs is the same or is
+ * after the position pointed by @p rhs, @c false otherwise.
+ */
+template <typename U>
+bool operator>=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
+{
+ return !(lhs < rhs);
}
/**