eina_cxx: add documentation to the Eina C++ header files.

Summary:
Added documentation to almost all classes that are intended for direct use by the library users.
Marked classes/functions used by the library itself as @internal.
Modified the Doxyfile.in to enable the generation of documentation to the bindings.

Reviewers: felipealmeida, cedric, woohyun, smohanty, raster

CC: savio, cedric

Differential Revision: https://phab.enlightenment.org/D947

Signed-off-by: Cedric BAIL <c.bail@partner.samsung.com>
This commit is contained in:
vitor.sousa 2014-06-04 22:34:42 +02:00 committed by Cedric BAIL
parent 5e7a9b1225
commit 0902b6a6f8
20 changed files with 5539 additions and 190 deletions

View File

@ -594,6 +594,7 @@ WARN_LOGFILE =
# with spaces. # with spaces.
INPUT = @top_srcdir@/src/lib \ INPUT = @top_srcdir@/src/lib \
@top_srcdir@/src/bindings \
@srcdir@/main.dox \ @srcdir@/main.dox \
@srcdir@/pkgconfig.dox \ @srcdir@/pkgconfig.dox \
@srcdir@/eina_examples.dox \ @srcdir@/eina_examples.dox \
@ -626,7 +627,8 @@ INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.c \ FILE_PATTERNS = *.c \
*.h \ *.h \
*.x *.x \
*.hh
# The RECURSIVE tag can be used to turn specify whether or not subdirectories # The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO. # should be searched for input files as well. Possible values are YES and NO.

View File

@ -1,6 +1,11 @@
#ifndef EINA_HH_ #ifndef EINA_HH_
#define EINA_HH_ #define EINA_HH_
/**
* @file
* @brief Eina C++
*/
#include <eina_iterator.hh> #include <eina_iterator.hh>
#include <eina_ptrarray.hh> #include <eina_ptrarray.hh>
#include <eina_ptrlist.hh> #include <eina_ptrlist.hh>
@ -16,8 +21,37 @@
#include <eina_optional.hh> #include <eina_optional.hh>
#include <eina_integer_sequence.hh> #include <eina_integer_sequence.hh>
/**
* @defgroup Eina_Cxx Eina C++
*
* @defgroup Eina_Cxx_Data_Types_Group Data Types
* @ingroup Eina_Cxx
*
* @defgroup Eina_Cxx_Content_Access_Group Content Access
* @ingroup Eina_Cxx_Data_Types_Group
*
* @defgroup Eina_Cxx_Containers_Group Containers
* @ingroup Eina_Cxx_Data_Types_Group
*
* @defgroup Eina_Cxx_Tools_Group Tools
* @ingroup Eina_Cxx
*
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @addtogroup Eina_Cxx
*
* @{
*/
/**
* @brief Initialize the Eina library.
*
* Initialize all the Eina modules upon construction and finalize them
* upon destruction, using the RAII programming idiom.
*/
struct eina_init struct eina_init
{ {
eina_init() eina_init()
@ -30,6 +64,12 @@ struct eina_init
} }
}; };
/**
* @brief Initialize the mutexes of the Eina library.
*
* Set up all the mutexes in all Eina modules upon construction and
* shut them down upon destruction, using the RAII programming idiom.
*/
struct eina_threads_init struct eina_threads_init
{ {
eina_threads_init() eina_threads_init()
@ -42,6 +82,10 @@ struct eina_threads_init
} }
}; };
/**
* @}
*/
} } } }
#endif #endif

View File

@ -9,25 +9,82 @@
#include <cstdlib> #include <cstdlib>
#include <cassert> #include <cassert>
/**
* @addtogroup Eina_Cxx_Content_Access_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Accessor_Group Accessor
* @ingroup Eina_Cxx_Content_Access_Group
*
* @brief These classes manage accessor on containers.
*
* These classes allow to access elements of a container in a
* generic way, without knowing which container is used (like
* iterators in the C++ STL). Accessors allows random access (that is, any
* element in the container). For sequential access, see
* @ref Eina_Cxx_Iterator_Group.
*
* @{
*/
/**
* Wraps an native Eina_Accessor and provide random access to data structures.
*/
template <typename T> template <typename T>
struct accessor struct accessor
{ {
typedef unsigned int key_type; typedef unsigned int key_type; /**< Type for accessor key. */
typedef T mapped_type; typedef T mapped_type; /**< Type for accessor mapped elements. */
typedef T value_type; typedef T value_type; /**< Type for accessor elements. Same as @ref mapped_type. */
typedef std::size_t size_type; typedef std::size_t size_type; /**< Type for size information used in the accessor. */
/**
* @brief Default constructor. Creates an empty accessor.
*/
accessor() : _impl(0) {} accessor() : _impl(0) {}
/**
* @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) explicit accessor(Eina_Accessor* impl)
: _impl(impl) : _impl(impl)
{ {
assert(_impl != 0); assert(_impl != 0);
} }
/**
* @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(accessor<T> const& other) accessor(accessor<T> const& other)
: _impl(eina_accessor_clone(other._impl)) : _impl(eina_accessor_clone(other._impl))
{} {}
/**
* @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.
*/
accessor<T>& operator=(accessor<T> const& other) accessor<T>& operator=(accessor<T> const& other)
{ {
eina_accessor_free(_impl); eina_accessor_free(_impl);
@ -36,11 +93,25 @@ struct accessor
throw eina::system_error(efl::eina::get_error_code(), "Error cloning accessor"); throw eina::system_error(efl::eina::get_error_code(), "Error cloning accessor");
return *this; return *this;
} }
/**
* @brief Destructor. Free the internal @c Eina_Acessor.
*/
~accessor() ~accessor()
{ {
eina_accessor_free(_impl); eina_accessor_free(_impl);
} }
/**
* @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 mapped_type& operator[](size_type i) const
{ {
assert(_impl != 0); assert(_impl != 0);
@ -53,98 +124,242 @@ struct accessor
return *static_cast<mapped_type*>(p); return *static_cast<mapped_type*>(p);
} }
/**
* @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; 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<T>& other) void swap(accessor<T>& other)
{ {
std::swap(_impl, other._impl); 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 explicit operator bool() const
{ {
return native_handle() ? &accessor<T>::native_handle : 0 ; return native_handle() ? &accessor<T>::native_handle : 0 ;
} }
private: private:
/**
* @internal
* Member variable for storing the native Eina_Accessor pointer.
*/
Eina_Accessor* _impl; Eina_Accessor* _impl;
}; };
/**
* @brief Swap the contents of the two accessor objects.
* @param lhs First accessor object.
* @param rhs Second accessor object.
*/
template <typename U> template <typename U>
void swap(accessor<U>& lhs, accessor<U>& rhs) void swap(accessor<U>& lhs, accessor<U>& rhs)
{ {
lhs.swap(rhs); lhs.swap(rhs);
} }
/**
* @}
*/
/**
* @defgroup Eina_Cxx_Accessor_Iterator_Group Accessor Iterator
* @ingroup Eina_Cxx_Content_Access_Group
*
* @{
*/
/**
* Random access iterator for <tt>eina::accessor</tt>.
*/
template <typename T> template <typename T>
struct accessor_iterator struct accessor_iterator
{ {
typedef T value_type; typedef T value_type; /**< Type of the elements. */
typedef value_type* pointer; typedef value_type* pointer; /**< Pointer to element type. */
typedef value_type& reference; typedef value_type& reference; /**< Reference to element type. */
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type; /**< Type to represent the distance between two @ref accessor_iterators */
typedef std::random_access_iterator_tag iterator_category; typedef std::random_access_iterator_tag iterator_category; /**< Defines the iterator as being a random access iterator. */
/**
* @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_iterator(accessor<T> const& a, unsigned int pos = 0u)
: _accessor(a), _index(pos) : _accessor(a), _index(pos)
{} {}
/**
* @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) accessor_iterator<T>& operator+=(difference_type i)
{ {
_index += i; _index += i;
return *this; return *this;
} }
/**
* @brief Move the iterator back by @p i positions.
* @param i Number of positions to move.
* @return The @c accessor_iterator itself.
*/
accessor_iterator<T>& operator-=(difference_type i) accessor_iterator<T>& operator-=(difference_type i)
{ {
_index -= i; _index -= i;
return *this; return *this;
} }
/**
* @brief Get the element @p i positions away from the current element.
* @param i Position relative to the current element.
* @return Reference to the element @p i positions away from the
* element currently pointed by the @c accessor_iterator.
*/
value_type& operator[](difference_type i) value_type& operator[](difference_type i)
{ {
return _accessor[_index + i]; return _accessor[_index + i];
} }
/**
* @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.
*/
accessor_iterator<T>& operator++() accessor_iterator<T>& operator++()
{ {
++_index; ++_index;
return *this; return *this;
} }
/**
* @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.
*/
accessor_iterator<T>& operator--() accessor_iterator<T>& operator--()
{ {
--_index; --_index;
return *this; return *this;
} }
/**
* @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.
*/
accessor_iterator<T>& operator++(int) accessor_iterator<T>& operator++(int)
{ {
accessor_iterator<T> tmp(*this); accessor_iterator<T> tmp(*this);
++*this; ++*this;
return tmp; return tmp;
} }
/**
* @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.
*/
accessor_iterator<T>& operator--(int) accessor_iterator<T>& operator--(int)
{ {
accessor_iterator<T> tmp(*this); accessor_iterator<T> tmp(*this);
--*this; --*this;
return tmp; return tmp;
} }
/**
* @brief Get a reference to the element currently pointed by the @c accessor_iterator.
* @return Reference to the current element.
*/
value_type& operator*() const value_type& operator*() const
{ {
return _accessor[_index]; return _accessor[_index];
} }
/**
* @brief Return a pointer to the current element, which member will be accessed.
* @return Pointer to the element currently pointed by the @c accessor_iterator.
*/
pointer operator->() const pointer operator->() const
{ {
return &**this; return &**this;
} }
/**
* @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) void swap(accessor_iterator<T>& other)
{ {
std::swap(_index, other._index); std::swap(_index, other._index);
std::swap(_accessor, other._accessor); std::swap(_accessor, other._accessor);
} }
private:
accessor<T> _accessor;
unsigned int _index;
private:
accessor<T> _accessor; /**< @internal */
unsigned int _index; /**< @internal */
/**
* @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.
*/
template <typename U> template <typename U>
friend bool operator==(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs) friend bool operator==(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
{ {
return lhs._index == rhs._index; return lhs._index == rhs._index;
} }
/**
* @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> template <typename U>
friend typename accessor_iterator<U>::difference_type friend typename accessor_iterator<U>::difference_type
operator-(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs) operator-(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
@ -152,6 +367,12 @@ private:
return lhs._index - rhs._index; 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> template <typename U>
friend friend
accessor_iterator<U> operator+(accessor_iterator<U> lhs accessor_iterator<U> operator+(accessor_iterator<U> lhs
@ -161,6 +382,12 @@ private:
return lhs; 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> template <typename U>
friend friend
accessor_iterator<U> operator+(typename accessor_iterator<U>::difference_type lhs accessor_iterator<U> operator+(typename accessor_iterator<U>::difference_type lhs
@ -169,12 +396,26 @@ private:
return rhs + lhs; 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> template <typename U>
friend bool operator<(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs) friend bool operator<(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
{ {
return lhs._index < rhs._index; return lhs._index < rhs._index;
} }
/**
* @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.
*/
template <typename U> template <typename U>
friend bool operator<=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs) friend bool operator<=(accessor_iterator<U> const& lhs, accessor_iterator<U> const& rhs)
{ {
@ -182,30 +423,63 @@ private:
} }
}; };
/**
* @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> 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 < rhs);
} }
/**
* @brief Check if @p lhs points to a position after 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 after the position
* pointed by @p rhs, @c false otherwise.
*/
template <typename U> 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 <= rhs);
} }
/**
* @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> 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 == rhs);
} }
/**
* @brief Swap content between two <tt>accessor_iterator</tt>s.
* @param lhs First @c accessor_iterator.
* @param rhs Second @c accessor_iterator.
*/
template <typename U> template <typename U>
void swap(accessor_iterator<U>& lhs, accessor_iterator<U>& rhs) void swap(accessor_iterator<U>& lhs, accessor_iterator<U>& rhs)
{ {
lhs.swap(rhs); lhs.swap(rhs);
} }
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -6,8 +6,31 @@
#include <cstdlib> #include <cstdlib>
#include <type_traits> #include <type_traits>
/**
* @addtogroup Eina_Cxx_Containers_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Clone_Allocators_Group Clone Allocators
* @ingroup Eina_Cxx_Containers_Group
*
* Clone allocators is a formalized way to pointer containers control
* the memory of the stored objects, allowing users to apply custom
* allocators/deallocators for the cloned objects.
*
* @{
*/
/**
* This allocator creates copies of objects on the heap, calling their
* copy constructor to make then equivalent to the given reference.
*
* The created objects are released with the default delete.
*/
struct heap_copy_allocator struct heap_copy_allocator
{ {
template <typename T> template <typename T>
@ -27,6 +50,11 @@ struct heap_copy_allocator
} }
}; };
/**
* This allocator allows users to create custom allocation schemes by
* overloading the <tt>new_clone(T const& v)</tt> and
* <tt>delete_clone(T* p)</tt> functions.
*/
struct heap_clone_allocator struct heap_clone_allocator
{ {
template <typename T> template <typename T>
@ -41,6 +69,14 @@ struct heap_clone_allocator
} }
}; };
/**
* This allocator does not allocate or deallocate anything. It simple
* gets non-const-qualified pointers for objects, which allow
* containers to hold elements without having ownership on them.
*
* It is commonly used to create a pointer container that is a view into
* another existing container.
*/
struct view_clone_allocator struct view_clone_allocator
{ {
template <typename T> template <typename T>
@ -54,6 +90,11 @@ struct view_clone_allocator
} }
}; };
/**
* This allocator does not define an @c allocate_clone member function,
* so it should be used to disable operations that require elements to
* be cloned.
*/
struct heap_no_copy_allocator struct heap_no_copy_allocator
{ {
template <typename T> template <typename T>
@ -65,8 +106,15 @@ struct heap_no_copy_allocator
delete p; delete p;
#endif #endif
} }
}; };
/**
* Manages allocation and deallocation of memory using the function
* @c malloc and @c free. This allocator does not calls constructors,
* the content of the newly allocated objects are assigned using
* @c memcpy, so it is likely only plausible with types that have
* <em>standard-layout</em>.
*/
struct malloc_clone_allocator struct malloc_clone_allocator
{ {
template <typename T> template <typename T>
@ -86,6 +134,14 @@ struct malloc_clone_allocator
} }
}; };
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -5,48 +5,129 @@
#include <system_error> #include <system_error>
/**
* @addtogroup Eina_Cxx_Tools_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Error_Group Error Handling
* @ingroup Eina_Cxx_Tools_Group
*
* @brief Functions for handling Eina errors.
*
* Integrates the Eina errors with the standard error representation
* defined in the @c system_error library.
*
* @{
*/
/** <tt>std::errc</tt> for Eina errors. */
using std::errc; using std::errc;
/** <tt>std::system_error</tt> for Eina errors. */
using std::system_error; using std::system_error;
/** <tt>std::error_code</tt> for Eina errors. */
using std::error_code; using std::error_code;
/** <tt>std::error_condition</tt> for Eina errors. */
using std::error_condition; using std::error_condition;
/** <tt>std::error_category</tt> for Eina errors. */
typedef std::error_category system_error_category; typedef std::error_category system_error_category;
/**
* @brief Return a @c Eina_Error for an unknown error.
* @return @c Eina_Error indicating a unknown/external error condition.
*
* This function returns an @c Eina_Error indicating a unknown/external
* error condition. When first called, this function will register the
* said error within the other Eina errors, together with a error
* message.
*/
inline Eina_Error unknown_error() inline Eina_Error unknown_error()
{ {
static Eina_Error error = eina_error_msg_static_register("Error from C++ from another value category error"); static Eina_Error error = eina_error_msg_static_register("Error from C++ from another value category error");
return error; return error;
} }
/**
* @brief Gets a <tt>std::generic_category</tt> instance as a <tt>eina::system_error_category</tt>.
* @return a <tt>std::generic_category</tt> instance as a <tt>eina::system_error_category</tt>.
*/
inline system_error_category const& get_generic_category() inline system_error_category const& get_generic_category()
{ {
return ::std::generic_category(); return ::std::generic_category();
} }
/**
* @brief Gets a <tt>std::system_category</tt> instance as a <tt>eina::system_error_category</tt>.
* @return <tt>std::system_category</tt> instance as a <tt>eina::system_error_category</tt>.
*/
inline system_error_category const& get_system_category() inline system_error_category const& get_system_category()
{ {
return ::std::system_category(); return ::std::system_category();
} }
/**
* @brief Typesafe representation of an @c Eina_Error.
*
* Used for improved compatibility with @e system_error library.
*/
enum error_type {}; enum error_type {};
/**
* @brief Specialized error category for Eina errors.
*/
struct error_category : system_error_category struct error_category : system_error_category
{ {
/**
* @brief Name of the error category.
* @return String containing the word "eina"
*/
const char* name() const throw() const char* name() const throw()
{ {
return "eina"; return "eina";
} }
/**
* @brief Check if the given error code is equivalent to the given error condition.
* @param code Integer representing the error code.
* @param condition <tt>eina::error_condition</tt> object.
* @return @c true if @c code is equivalent to @c condition.
*/
bool equivalent(int code, eina::error_condition const& condition) const throw() bool equivalent(int code, eina::error_condition const& condition) const throw()
{ {
return code == condition.value(); return code == condition.value();
} }
/**
* @brief Check if the given error code is equivalent to the given error condition.
* @param code <tt>eina::error_code</tt> object.
* @param condition Integer representing the error condition.
* @return @c true if @c code is equivalent to @c condition.
*/
bool equivalent(eina::error_code const& code, int condition) const throw() bool equivalent(eina::error_code const& code, int condition) const throw()
{ {
return code.value() == condition; return code.value() == condition;
} }
/**
* @brief Get the message related with the given error condition.
* @param condition Eina error condition.
* @return String containing the message related with the given error condition.
*
* This member function returns the error message related with the
* given error condition code.
*
* @note When the given condition code is not registered within the
* Eina errors it will return a string indicating that an error
* message is not available.
*/
std::string message(int condition) const std::string message(int condition) const
{ {
const char* e = ::eina_error_msg_get(condition); const char* e = ::eina_error_msg_get(condition);
@ -54,12 +135,29 @@ struct error_category : system_error_category
} }
}; };
/**
* @brief Get a default <tt>eina::error_category</tt> object.
* @return Reference to a static instance of an <tt>eina::error_category</tt>.
*/
inline eina::system_error_category& eina_error_category() inline eina::system_error_category& eina_error_category()
{ {
static error_category _error_category; static error_category _error_category;
return _error_category; return _error_category;
} }
/**
* @brief Gets the error code for the last Eina error.
* @return <tt>eina::error_code</tt> for the last Eina error.
*
* This function gets the error code for the last Eina error and
* consumes it. The category of the returned <tt>eina::error_code</tt>
* is @c eina_error_category.
*
* @note If no errors have been occurred or if this functions have
* already been called after the last error occurrence a call to this
* function will return a default <tt>eina::error_code</tt> to indicates
* that there is no unconsumed error.
*/
inline eina::error_code get_error_code() inline eina::error_code get_error_code()
{ {
Eina_Error error = eina_error_get(); Eina_Error error = eina_error_get();
@ -72,6 +170,14 @@ inline eina::error_code get_error_code()
return eina::error_code(); return eina::error_code();
} }
/**
* @brief Sets an error code in the Eina library.
* @param e Error code. Should be an @c eina_error_category error.
*
* This function sets an error code in the Eina library. If the category
* of the given error code is not @c eina_error_category it will
* register an unknown error instead.
*/
inline void set_error_code(eina::error_code const& e) inline void set_error_code(eina::error_code const& e)
{ {
if(e.category() == eina_error_category()) if(e.category() == eina_error_category())
@ -80,6 +186,13 @@ inline void set_error_code(eina::error_code const& e)
eina_error_set(unknown_error()); eina_error_set(unknown_error());
} }
/**
* @brief Gets the error condition for the last Eina error.
* @return <tt>eina::error_condition</tt> for the last Eina error.
*
* This function works exactly like @ref get_error_code but returns an
* <tt>eina::error_condition</tt> object instead.
*/
inline eina::error_condition get_error_condition() inline eina::error_condition get_error_condition()
{ {
Eina_Error error = eina_error_get(); Eina_Error error = eina_error_get();
@ -92,12 +205,35 @@ inline eina::error_condition get_error_condition()
return eina::error_condition(); return eina::error_condition();
} }
/**
* @brief Gets the enum value of the last Eina error.
* @return Value of the last Eina error as an @c error_type.
*
* This function returns the error code for the last Eina error.
*
* Differently from @ref get_error_code and @ref get_error_condition,
* this function does not consume the last error.
*/
inline error_type get_error_code_enum() inline error_type get_error_code_enum()
{ {
return static_cast<error_type>( ::eina_error_get() ); return static_cast<error_type>( ::eina_error_get() );
} }
/**
* @brief Throw an exception if there is a error set in Eina library.
* @throw <tt>eina::system_error</tt> containing the error identifier.
*
* This function is meant to be used after executing a operation that
* may set an Eina error. If an error code has been set this function
* will throw an exception.
*
* The thrown exception holds an <tt>eina::error_code</tt> equivalent to
* the one returned by @ref get_error_code.
*
* Like the @ref get_error_code function, this one consumes the last
* error code.
*/
inline void throw_on_error() inline void throw_on_error()
{ {
eina::error_code ec = get_error_code(); eina::error_code ec = get_error_code();
@ -107,13 +243,28 @@ inline void throw_on_error()
} }
} }
/**
* @}
*/
} } } }
/**
* @internal
* Template specialization for interoperability with the @e system_error
* standard library.
* @{
*/
namespace std { namespace std {
template <> struct is_error_condition_enum< ::efl::eina::error_type> : true_type {}; template <> struct is_error_condition_enum< ::efl::eina::error_type> : true_type {};
template <> struct is_error_code_enum< ::efl::eina::error_type> : true_type {}; template <> struct is_error_code_enum< ::efl::eina::error_type> : true_type {};
} }
/**
* @}
*/
/**
* @}
*/
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,24 @@
#include <iterator> #include <iterator>
#include <algorithm> #include <algorithm>
/**
* @addtogroup Eina_Cxx_Containers_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Inline_List_Group Inline List
* @ingroup Eina_Cxx_Containers_Group
*
* @{
*/
/**
* @internal
*/
template <typename T> template <typename T>
struct _inlist_node struct _inlist_node
{ {
@ -19,18 +35,27 @@ struct _inlist_node
T object; T object;
}; };
/**
* @internal
*/
template <typename T> template <typename T>
_inlist_node<T>* _get_node(Eina_Inlist* l) _inlist_node<T>* _get_node(Eina_Inlist* l)
{ {
return static_cast<_inlist_node<T>*>(static_cast<void*>(l)); return static_cast<_inlist_node<T>*>(static_cast<void*>(l));
} }
/**
* @internal
*/
template <typename T> template <typename T>
_inlist_node<T> const* _get_node(Eina_Inlist const* l) _inlist_node<T> const* _get_node(Eina_Inlist const* l)
{ {
return const_cast<Eina_Inlist*>(l); return const_cast<Eina_Inlist*>(l);
} }
/**
* @internal
*/
template <typename T> template <typename T>
Eina_Inlist* _get_list(_inlist_node<T>* n) Eina_Inlist* _get_list(_inlist_node<T>* n)
{ {
@ -40,38 +65,85 @@ Eina_Inlist* _get_list(_inlist_node<T>* n)
return 0; return 0;
} }
/**
* @internal
*/
template <typename T> template <typename T>
Eina_Inlist const* _get_list(_inlist_node<T> const* n) Eina_Inlist const* _get_list(_inlist_node<T> const* n)
{ {
return _get_list(const_cast<_inlist_node<T>*>(n)); return _get_list(const_cast<_inlist_node<T>*>(n));
} }
/**
* @internal
* Iterator for Inline List
*/
template <typename T> template <typename T>
struct _inlist_iterator struct _inlist_iterator
{ {
typedef typename std::remove_const<T>::type value_type; typedef typename std::remove_const<T>::type value_type; /**< Type for the list elements. */
typedef value_type* pointer; typedef value_type* pointer; /**< Type for a pointer to an element. */
typedef value_type& reference; typedef value_type& reference; /**< Type for a reference to an element. */
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type; /**< Type to represent the distance between two iterators. */
typedef std::bidirectional_iterator_tag iterator_category; typedef std::bidirectional_iterator_tag iterator_category; /**< Defines the iterator as being a bidirectional iterator. */
/**
* @brief Default constructor. Creates an uninitialized iterator.
*/
_inlist_iterator() {} _inlist_iterator() {}
/**
* @brief Creates an iterator from a inline list and a node.
* @param list Pointer to the inline list.
* @param node Pointer to the node.
*/
explicit _inlist_iterator(_inlist_node<value_type>* list, _inlist_node<value_type>* node) explicit _inlist_iterator(_inlist_node<value_type>* list, _inlist_node<value_type>* node)
: _list(list), _node(node) {} : _list(list), _node(node) {}
/**
* @brief Copy constructor. Creates a copy of the given iterator.
* @param other Other iterator.
*/
_inlist_iterator(_inlist_iterator<typename std::remove_const<T>::type> const& other) _inlist_iterator(_inlist_iterator<typename std::remove_const<T>::type> const& other)
: _list(other._list), _node(other._node) {} : _list(other._list), _node(other._node) {}
/**
* @brief Move the iterator to the next position in the list.
* @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.
*/
_inlist_iterator<T>& operator++() _inlist_iterator<T>& operator++()
{ {
_node = _get_node<value_type>(_node->__in_list.next); _node = _get_node<value_type>(_node->__in_list.next);
return *this; return *this;
} }
/**
* @brief Move the iterator to the next position in the list.
* @return Copy of the iterator before the increment.
*
* This operator increments the iterator, making it point to the next
* position right after the current one.
* At the end, it returns a copy of the iterator before the increment.
*/
_inlist_iterator<T> operator++(int) _inlist_iterator<T> operator++(int)
{ {
_inlist_iterator<T> tmp(*this); _inlist_iterator<T> tmp(*this);
++*this; ++*this;
return tmp; return tmp;
} }
/**
* @brief Move the iterator to the previous position in the list.
* @return The 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.
*/
_inlist_iterator<T>& operator--() _inlist_iterator<T>& operator--()
{ {
if(_node) if(_node)
@ -80,32 +152,65 @@ struct _inlist_iterator
_node = _get_node<value_type>(_list->__in_list.last); _node = _get_node<value_type>(_list->__in_list.last);
return *this; return *this;
} }
/**
* @brief Move the iterator to the previous position in the list.
* @return Copy of the iterator before the decrement.
*
* 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 iterator before the decrement.
*/
_inlist_iterator<T> operator--(int) _inlist_iterator<T> operator--(int)
{ {
_inlist_iterator<T> tmp(*this); _inlist_iterator<T> tmp(*this);
--*this; --*this;
return tmp; return tmp;
} }
/**
* @brief Get a reference to the element currently pointed by the iterator.
* @return Reference to the current element.
*/
T& operator*() const T& operator*() const
{ {
return _node->object; return _node->object;
} }
/**
* @brief Return a pointer to the current element, which member will be accessed.
* @return Pointer to the element currently pointed by the iterator.
*/
T* operator->() const T* operator->() const
{ {
return &_node->object; return &_node->object;
} }
/**
* @internal
*/
_inlist_node<value_type>* native_handle() _inlist_node<value_type>* native_handle()
{ {
return _node; return _node;
} }
/**
* @internal
*/
_inlist_node<value_type> const* native_handle() const _inlist_node<value_type> const* native_handle() const
{ {
return _node; return _node;
} }
private: private:
_inlist_node<value_type>* _list; _inlist_node<value_type>* _list; /**< Handle to the original list. */
_inlist_node<value_type>* _node; _inlist_node<value_type>* _node; /**< Handle to the current node. */
/**
* @brief Check if both iterators are pointing to the same node.
* @param lhs First iterator to be compared.
* @param rhs Second iterator to be compared.
* @return @c true if both iterators are pointing to the same node, @c false otherwise.
*/
template <typename U> template <typename U>
friend struct _inlist_iterator; friend struct _inlist_iterator;
friend bool operator==(_inlist_iterator<T> lhs, _inlist_iterator<T> rhs) friend bool operator==(_inlist_iterator<T> lhs, _inlist_iterator<T> rhs)
@ -114,12 +219,21 @@ private:
} }
}; };
/**
* @brief Check if iterators are not pointing to the same node.
* @param lhs First iterator to be compared.
* @param rhs Second iterator to be compared.
* @return @c true if iterators are not pointing to the same node, @c false otherwise.
*/
template <typename T> template <typename T>
bool operator!=(_inlist_iterator<T> lhs, _inlist_iterator<T> rhs) bool operator!=(_inlist_iterator<T> lhs, _inlist_iterator<T> rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @internal
*/
struct _inlist_access_traits { struct _inlist_access_traits {
template <typename T> template <typename T>
struct const_iterator struct const_iterator
@ -242,49 +356,93 @@ struct _inlist_access_traits {
template <typename T, typename Allocator> template <typename T, typename Allocator>
class inlist; class inlist;
/**
* @ingroup Eina_Cxx_Range_Group
*
* Range for inline list elements.
*/
template <typename T> template <typename T>
struct range_inlist : _range_template<T, _inlist_access_traits> struct range_inlist : _range_template<T, _inlist_access_traits>
{ {
typedef _range_template<T, _inlist_access_traits> _base_type; typedef _range_template<T, _inlist_access_traits> _base_type; /**< Type for the base class. */
typedef typename _base_type::value_type value_type; typedef typename _base_type::value_type value_type; /**< The type of each element. */
typedef typename _base_type::native_handle_type native_handle_type; typedef typename _base_type::native_handle_type native_handle_type; /** Type for the native Eina inline list handle. */
/**
* @brief Creates a range from a native Eina inline list handle.
*/
range_inlist(native_handle_type list) range_inlist(native_handle_type list)
: _base_type(list) {} : _base_type(list) {}
/**
* @brief Creates a range from a inline list object.
*/
template <typename Allocator> template <typename Allocator>
range_inlist(inlist<value_type, Allocator>& list) range_inlist(inlist<value_type, Allocator>& list)
: _base_type(list.native_handle()) : _base_type(list.native_handle())
{} {}
}; };
/**
* @brief Check the given ranges are equal to each other.
* @param lhs Range object at the left side of the expression.
* @param rhs Range object at the right side of the expression.
* @return @c true if the ranges are equal, @c false otherwise.
*
* This operator checks if the given ranges are equal to each other. To
* be considered equal both ranges need to have the same size, and each
* element in one range must be equal to the element at the same
* position in the other.
*/
template <typename T> template <typename T>
bool operator==(range_inlist<T>const& lhs, range_inlist<T>const& rhs) bool operator==(range_inlist<T>const& lhs, range_inlist<T>const& rhs)
{ {
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
} }
/**
* @brief Returns the opposite of @ref operator==(range_inlist<T>const& lhs, range_inlist<T>const& rhs).
*/
template <typename U> template <typename U>
bool operator!=(range_inlist<U> const& lhs, range_inlist<U>const& rhs) bool operator!=(range_inlist<U> const& lhs, range_inlist<U>const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* Common implementations for inline list.
*/
template <typename T, typename Allocator> template <typename T, typename Allocator>
struct _inlist_common_base struct _inlist_common_base
{ {
typedef typename Allocator::template rebind<_inlist_node<T> >::other node_allocator_type; typedef typename Allocator::template rebind<_inlist_node<T> >::other node_allocator_type; /**< Type for the allocator of the node. */
typedef Allocator allocator_type; typedef Allocator allocator_type; /**< Type for the allocator. */
typedef _inlist_node<T> node_type; typedef _inlist_node<T> node_type; /**< Type for the list node. */
/**
* @brief Creates a list with the given allocator.
* @param allocator Allocator object.
*/
_inlist_common_base(Allocator allocator) _inlist_common_base(Allocator allocator)
: _impl(allocator) {} : _impl(allocator) {}
/**
* @brief Creates an empty inline list.
*/
_inlist_common_base() _inlist_common_base()
{} {}
/**
* @brief Destructor. Deallocate all nodes of the list.
*/
~_inlist_common_base() ~_inlist_common_base()
{ {
clear(); clear();
} }
/**
* @brief Deallocate all nodes of the list.
*/
void clear() void clear()
{ {
Eina_Inlist* p = _impl._list; Eina_Inlist* p = _impl._list;
@ -301,11 +459,18 @@ struct _inlist_common_base
} }
_impl._list = 0; _impl._list = 0;
} }
/**
* @brief Get the allocator used by the list.
*/
node_allocator_type& get_node_allocator() node_allocator_type& get_node_allocator()
{ {
return _impl; return _impl;
} }
/**
* @internal
*/
// For EBO // For EBO
struct _inlist_impl : node_allocator_type struct _inlist_impl : node_allocator_type
{ {
@ -317,40 +482,77 @@ struct _inlist_common_base
Eina_Inlist* _list; Eina_Inlist* _list;
}; };
_inlist_impl _impl; _inlist_impl _impl; /**< @internal */
private: private:
/** Disabled copy constructor. */
_inlist_common_base(_inlist_common_base const& other); _inlist_common_base(_inlist_common_base const& other);
/** Disabled assignment operator. */
_inlist_common_base& operator=(_inlist_common_base const& other); _inlist_common_base& operator=(_inlist_common_base const& other);
}; };
/**
* C++ wrapper for the native Eina inline list.
*
* It provides an OOP interface to the @c Eina_Inlist functions, and
* automatically take care of allocating and deallocating resources using
* the RAII programming idiom.
*
* It also provides additional member functions to facilitate the access
* to the list content, much like a STL list.
*/
template <typename T, typename Allocator = std::allocator<T> > template <typename T, typename Allocator = std::allocator<T> >
class inlist : protected _inlist_common_base<T, Allocator> class inlist : protected _inlist_common_base<T, Allocator>
{ {
typedef _inlist_common_base<T, Allocator> _base_type; typedef _inlist_common_base<T, Allocator> _base_type; /**< Type for the base class. */
typedef typename _base_type::node_type _node_type; typedef typename _base_type::node_type _node_type; /**< Type for each node */
public: public:
typedef typename _base_type::allocator_type allocator_type; typedef typename _base_type::allocator_type allocator_type; /**< Type for the allocator. */
typedef typename allocator_type::value_type value_type; typedef typename allocator_type::value_type value_type; /**< The type of each element. */
typedef typename allocator_type::reference reference; typedef typename allocator_type::reference reference; /**< Type for a reference to an element. */
typedef typename allocator_type::const_reference const_reference; typedef typename allocator_type::const_reference const_reference; /**< Type for a constant reference to an element. */
typedef _inlist_iterator<T const> const_iterator; typedef _inlist_iterator<T const> const_iterator; /**< Type for constant iterator for this kind of container. */
typedef _inlist_iterator<T> iterator; typedef _inlist_iterator<T> iterator; /**< Type for iterator for this kind of container. */
typedef typename allocator_type::pointer pointer; typedef typename allocator_type::pointer pointer; /**< Type for a pointer to an element. */
typedef typename allocator_type::const_pointer const_pointer; typedef typename allocator_type::const_pointer const_pointer; /**< Type for a constant pointer for an element. */
typedef std::size_t size_type; typedef std::size_t size_type; /**< Type for size information. */
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type; /**< Type to represent the distance between two iterators. */
typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; /**< Type for reverse iterator for this kind of container. */
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; /**< Type for constant reverse iterator for this kind of container. */
using _base_type::clear; using _base_type::clear;
/**
* @brief Default constructor. Creates an empty inline list.
*/
inlist() {} inlist() {}
/**
* @brief Construct an inline list object with @p n copies of @p t.
* @param n Number of elements.
* @param t Value to be copied to each element.
*
* This constructor creates an inline list with @p n elements, each
* one as a copy of @p t.
*/
inlist(size_type n, value_type const& t) inlist(size_type n, value_type const& t)
{ {
while(n--) while(n--)
push_back(t); push_back(t);
} }
/**
* @brief Create a inline list coping the elements from the given range.
* @param i Iterator to the initial position. The element pointed by this iterator will be copied.
* @param j Iterator to the final position. The element pointed by this iterator will NOT be copied.
*
* This constructor creates a inline list with copies of the elements
* between @p i and @p j in the same order.
*
* @note The ending element (pointed by @p j) is not copied.
*/
template <typename InputIterator> template <typename InputIterator>
inlist(InputIterator i, InputIterator const& j inlist(InputIterator i, InputIterator const& j
, allocator_type const& alloc = allocator_type() , allocator_type const& alloc = allocator_type()
@ -363,29 +565,74 @@ public:
++i; ++i;
} }
} }
/**
* @brief Copy constructor. Creates a copy of the given inline list.
* @param other Another inline list of the same type.
*
* This constructor creates an inline list containing a copy of each
* element inside @p other in the same order.
*/
inlist(inlist<T, Allocator>const& other) inlist(inlist<T, Allocator>const& other)
: _base_type() : _base_type()
{ {
insert(end(), other.begin(), other.end()); insert(end(), other.begin(), other.end());
} }
/**
* @brief Replace current content with the content of another inline list.
* @param other Another inline list of the same type.
*
* This assignment operator replaces the content of the list by a copy
* of the content of @p other. The list size is adjusted accordingly
* and the newly copied elements keep their original order.
*/
inlist<T, Allocator>& operator=(inlist<T, Allocator>const& other) inlist<T, Allocator>& operator=(inlist<T, Allocator>const& other)
{ {
clear(); clear();
insert(end(), other.begin(), other.end()); insert(end(), other.begin(), other.end());
return *this; return *this;
} }
/**
* @brief Get the current size of the inline list.
* @return Number of elements in the inline list.
*
* This member function returns the current number of elements inside
* the inline list.
*/
size_type size() const size_type size() const
{ {
return _inlist_access_traits::size<T>(native_handle()); return _inlist_access_traits::size<T>(native_handle());
} }
/**
* @brief Check if the inline list is empty.
* @return @c true if the inline list is empty, @c false otherwise.
*
* This member function returns @c true if the inline list does not
* contain any elements, otherwise it returns @c false.
*/
bool empty() const bool empty() const
{ {
return _inlist_access_traits::empty<T>(native_handle()); return _inlist_access_traits::empty<T>(native_handle());
} }
/**
* @brief Get the allocator used in this inline list.
*/
allocator_type get_allocator() const allocator_type get_allocator() const
{ {
return allocator_type(this->get_node_allocator()); return allocator_type(this->get_node_allocator());
} }
/**
* @brief Add a copy of the given element at the end of the inline list.
* @param value Element to be added at the end of the inline list.
*
* This member function allocates a new element at the end of the
* inline list, the content of @p value is copied to the new element.
*/
void push_back(T const& value) void push_back(T const& value)
{ {
_node_type* node ( this->get_node_allocator().allocate(1) ); _node_type* node ( this->get_node_allocator().allocate(1) );
@ -401,6 +648,15 @@ public:
throw; throw;
} }
} }
/**
* @brief Add a copy of the given element at the beginning of the inline list.
* @param value Element to be added at the beginning of the inline list.
*
* This member function allocates a new element at the beginning of
* the inline list, the content of @p value is copied to the new
* element.
*/
void push_front(T const& value) void push_front(T const& value)
{ {
_node_type* node ( this->get_node_allocator().allocate(1) ); _node_type* node ( this->get_node_allocator().allocate(1) );
@ -416,14 +672,36 @@ public:
throw; throw;
} }
} }
/**
* @brief Remove the last element of the inline list.
*/
void pop_back() void pop_back()
{ {
this->_impl._list = eina_inlist_remove(this->_impl._list, this->_impl._list->last); this->_impl._list = eina_inlist_remove(this->_impl._list, this->_impl._list->last);
} }
/**
* @brief Remove the first element of the inline list.
*/
void pop_front() void pop_front()
{ {
this->_impl._list = eina_inlist_remove(this->_impl._list, this->_impl._list); this->_impl._list = eina_inlist_remove(this->_impl._list, this->_impl._list);
} }
/**
* @brief Insert a new element at the given position.
* @param i Iterator pointing to the position where the new element will be inserted.
* @param t Value to be copied to the new element.
* @return Iterator pointing to the new element inserted.
*
* This member function inserts a copy of the element @p t at the
* position @p i. The new element comes right before the element
* originally pointed by @p i.
*
* At the end, a valid iterator pointing to the element just inserted
* is returned.
*/
iterator insert(iterator i, value_type const& t) iterator insert(iterator i, value_type const& t)
{ {
_node_type* node ( this->get_node_allocator().allocate(1) ); _node_type* node ( this->get_node_allocator().allocate(1) );
@ -442,6 +720,21 @@ public:
throw; throw;
} }
} }
/**
* @brief Insert @p n copies of @p t at the given position.
* @param i Iterator pointing to the position where the new elements will be inserted.
* @param n Number of elements to be inserted.
* @param t Value to be copied to each new inserted element.
* @return Iterator pointing to the first inserted element.
*
* This member function inserts @p n new elements at position @p i
* in the inline list, each one as a copy of @p t. The new elements
* come right before the element originally pointed by @p i.
*
* At the end, a valid iterator pointing to the first element inserted
* is returned.
*/
iterator insert(iterator i, size_t n, value_type const& t) iterator insert(iterator i, size_t n, value_type const& t)
{ {
iterator r = i; iterator r = i;
@ -452,6 +745,18 @@ public:
return r; return r;
} }
/**
* @brief Insert the elements between the given range at the given position.
* @param p Iterator pointing to the position where the new elements will be inserted.
* @param i Iterator to the initial position. The element pointed by this iterator will be copied.
* @param j Iterator to the final position. The element pointed by this iterator will NOT be copied.
* @return Iterator pointing to the first inserted element.
*
* This member function inserts a copy of the elements between @p i
* and @p j at the position @p p. The new elements come right before
* the element originally pointed by @p p. Note that the element
* pointed by @p j is not copied.
*/
template <typename InputIterator> template <typename InputIterator>
iterator insert(iterator p, InputIterator i, InputIterator j iterator insert(iterator p, InputIterator i, InputIterator j
, typename eina::enable_if<!eina::is_integral<InputIterator>::value>::type* = 0) , typename eina::enable_if<!eina::is_integral<InputIterator>::value>::type* = 0)
@ -471,6 +776,15 @@ public:
return r; return r;
} }
/**
* @brief Remove the element at the given position.
* @param q Iterator pointing to the element to be removed.
* @return Iterator pointing to the element after the removed one.
*
* This member function removes the element pointed by the iterator
* @p q, reducing the list size by one. At the end, a valid iterator
* pointing to the element right after the removed one is returned.
*/
iterator erase(iterator q) iterator erase(iterator q)
{ {
if(q.native_handle()) if(q.native_handle())
@ -483,6 +797,20 @@ public:
return q; return q;
} }
/**
* @brief Remove the elements between the given range.
* @param i Iterator pointing to the starting position to be removed.
* @param j Iterator pointing to the ending position to be removed.
* The element pointed by this iterator is not removed.
* @return Iterator pointing to the new position of the first
* non-removed element after the removed ones (i.e. the one
* originally pointed by @p j).
*
* This member function removes the elements between the iterators
* @p i and @p j, including the element pointed by @p i but not the
* element pointed by @j.
*/
iterator erase(iterator i, iterator j) iterator erase(iterator i, iterator j)
{ {
while(i != j) while(i != j)
@ -493,6 +821,18 @@ public:
return end(); return end();
} }
/**
* @brief Replace the content of the inline list by the elements in the given range.
* @param i Iterator pointing to the beginning of the elements to be copied.
* @param j Iterator pointing to the end of the elements to be copied.
* Note that the element pointed by j will NOT be copied.
*
* This member function replaces the current elements by copies of the
* elements between the iterators @p i and @p j, including the element
* pointed by @p i but not the one pointed by @p j. The size of the
* list is adjusted accordingly and the newly copied elements remain
* in their original order.
*/
template <typename InputIterator> template <typename InputIterator>
void assign(InputIterator i, InputIterator j void assign(InputIterator i, InputIterator j
, typename eina::enable_if<!eina::is_integral<InputIterator>::value>::type* = 0) , typename eina::enable_if<!eina::is_integral<InputIterator>::value>::type* = 0)
@ -501,99 +841,296 @@ public:
insert(end(), i, j); insert(end(), i, j);
} }
/**
* @brief Replace the content of the inline list by @p n copies @p t.
* @param n Number of elements.
* @param t Value to be copied to each element.
*/
void assign(size_type n, value_type const& t) void assign(size_type n, value_type const& t)
{ {
clear(); clear();
insert(end(), n, t); insert(end(), n, t);
} }
/**
* @brief Get a reference to the last element.
* @return Reference to the last element in the inline list.
*/
value_type& back() value_type& back()
{ {
return _inlist_access_traits::back<T>(native_handle()); return _inlist_access_traits::back<T>(native_handle());
} }
/**
* @brief Get a constant reference to the last element.
* @return Constant reference to the last element in the inline list.
*
* Version of @ref back() for const-qualified inline list objects.
* Returns a constant reference instead.
*/
value_type const& back() const value_type const& back() const
{ {
return _inlist_access_traits::back<T>(native_handle()); return _inlist_access_traits::back<T>(native_handle());
} }
/**
* @brief Get a reference to the first element.
* @return Reference to the first element of the inline list.
*/
value_type& front() value_type& front()
{ {
return _inlist_access_traits::front<T>(native_handle()); return _inlist_access_traits::front<T>(native_handle());
} }
/**
* @brief Get a constant reference to the first element.
* @return Constant reference to the first element of the inline list.
*
* Version of @ref front() for const-qualified inline list objects.
* Returns a constant reference instead.
*/
value_type const& front() const value_type const& front() const
{ {
return _inlist_access_traits::front<T>(native_handle()); return _inlist_access_traits::front<T>(native_handle());
} }
/**
* @brief Get a constant iterator pointing to the first element of the inline list.
* @return Constant iterator to the initial position of the inline list.
*
* Version of @ref begin() for const-qualified inline list objects.
* Returns a constant iterator instead.
*/
const_iterator begin() const const_iterator begin() const
{ {
return _inlist_access_traits::begin<T>(native_handle()); return _inlist_access_traits::begin<T>(native_handle());
} }
/**
* @brief Get a constant iterator to the position following the last element of the inline list.
* @return Constant iterator to the final position of the inline list.
*
* Version of @ref end() for const-qualified inline list objects.
* Returns a constant iterator instead.
*/
const_iterator end() const const_iterator end() const
{ {
return _inlist_access_traits::end<T>(native_handle()); return _inlist_access_traits::end<T>(native_handle());
} }
/**
* @brief Get an iterator pointing to the first element of the inline list.
* @return Iterator to the initial position of the inline list.
*
* This member function returns an iterator pointing to the first
* element of the inline list. If the list is empty the returned
* iterator is the same as the one returned by @ref end().
*/
iterator begin() iterator begin()
{ {
return _inlist_access_traits::begin<T>(native_handle()); return _inlist_access_traits::begin<T>(native_handle());
} }
/**
* @brief Get an iterator to the position following the last element of the inline list.
* @return Iterator to the final position of the inline list.
*
* This member function returns an iterator to the position following
* the last element in the inline list. If the list is empty the
* returned iterator is the same as the one returned by @ref begin().
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
iterator end() iterator end()
{ {
return _inlist_access_traits::end<T>(native_handle()); return _inlist_access_traits::end<T>(native_handle());
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse begin of the inline list.
* @return Constant reverse iterator pointing to the reverse begin of the inline list.
*
* Version of @ref rbegin() for const-qualified inline list objects.
* Returns a constant reverse iterator instead.
*/
const_reverse_iterator rbegin() const const_reverse_iterator rbegin() const
{ {
return reverse_iterator(end()); return reverse_iterator(end());
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse end of the inline list.
* @return Constant reverse iterator pointing to the reverse end of the inline list.
*
* Version of @ref rend() for const-qualified inline list objects.
* Returns a constant reverse iterator instead.
*/
const_reverse_iterator rend() const const_reverse_iterator rend() const
{ {
return const_reverse_iterator(begin()); return const_reverse_iterator(begin());
} }
/**
* @brief Get a reverse iterator pointing to the reverse begin of the inline list.
* @return Reverse iterator pointing to the reverse begin of the inline list.
*
* This member function returns a reverse iterator pointing to the
* last element of the inline list. If the list is empty the returned
* reverse iterator is the same as the one returned by @ref rend().
*/
reverse_iterator rbegin() reverse_iterator rbegin()
{ {
return reverse_iterator(end()); return reverse_iterator(end());
} }
/**
* @brief Get a reverse iterator pointing to the reverse end of the inline list.
* @return Reverse iterator pointing to the reverse end of the inline list.
*
* This member function returns a reverse iterator pointing to the
* position before the first element of the inline list. If the list
* is empty the returned iterator is the same as the one returned by
* @ref rbegin().
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
reverse_iterator rend() reverse_iterator rend()
{ {
return reverse_iterator(begin()); return reverse_iterator(begin());
} }
/**
* @brief Get a constant iterator pointing to the first element of the inline list.
* @return Constant iterator to the initial position of the inline list.
*
* This member function works like @ref begin() const but is granted
* to return a constant iterator even for lists that are not
* const-qualified.
*/
const_iterator cbegin() const const_iterator cbegin() const
{ {
return begin(); return begin();
} }
/**
* @brief Get a constant iterator to the position following the last element of the inline list.
* @return Constant iterator to the final position of the inline list.
*
* This member function works like @ref end() const but is granted to
* return a constant iterator even for lists that are not
* const-qualified.
*/
const_iterator cend() const const_iterator cend() const
{ {
return end(); return end();
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse begin of the inline list.
* @return Constant reverse iterator pointing to the reverse begin of the inline list.
*
* This member function works like @ref rbegin() const but is granted
* to return a constant reverse iterator even for lists that are not
* const-qualified.
*/
const_reverse_iterator crbegin() const const_reverse_iterator crbegin() const
{ {
return rbegin(); return rbegin();
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse end of the inline list.
* @return Constant reverse iterator pointing to the reverse end of the inline list.
*
* This member function works like @ref rend() const but is granted to
* return a constant reverse iterator even for lists that are not
* const-qualified.
*/
const_reverse_iterator crend() const const_reverse_iterator crend() const
{ {
return rend(); return rend();
} }
/**
* @brief Swap content between two inline lists.
* @param other Other inline list of the same type.
*/
void swap(inlist<T, Allocator>& other) void swap(inlist<T, Allocator>& other)
{ {
std::swap(this->_impl._list, other._impl._list); std::swap(this->_impl._list, other._impl._list);
} }
/**
* @brief Get the maximum number of elements a inline list can hold.
* @return Maximum number of elements a inline list can hold.
*/
size_type max_size() const { return -1; } size_type max_size() const { return -1; }
/**
* @brief Get the handle for the wrapped Eina_Inlist.
* @return Internal handle for the native Eina inline list.
*
* This member function returns the native Eina_Inlist 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_Inlist* native_handle() Eina_Inlist* native_handle()
{ {
return this->_impl._list; return this->_impl._list;
} }
/**
* @brief Get the handle for the wrapped Eina_Inlist.
* @return Internal handle for the native Eina inline list.
*
* This member function returns the native Eina_Inlist 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_Inlist const* native_handle() const Eina_Inlist const* native_handle() const
{ {
return this->_impl._list; return this->_impl._list;
} }
/**
* @brief Get a constant @ref eina::accessor for the list.
* @return Constant <tt>eina::accessor</tt> to the list.
*
* Version of @ref accessor() to const-qualified inline lists. Returns
* a const-qualified <tt>eina::accessor</tt> instead.
*/
eina::accessor<T const> accessor() const eina::accessor<T const> accessor() const
{ {
return eina::accessor<T const>(eina_inlist_accessor_new(this->_impl._list)); return eina::accessor<T const>(eina_inlist_accessor_new(this->_impl._list));
} }
/**
* @brief Get a @ref eina::accessor for the list.
* @return <tt>eina::accessor</tt> to the list.
*/
eina::accessor<T> accessor() eina::accessor<T> accessor()
{ {
return eina::accessor<T>(eina_inlist_accessor_new(this->_impl._list)); return eina::accessor<T>(eina_inlist_accessor_new(this->_impl._list));
} }
}; };
/**
* @brief Check if two inline lists are equal.
* @param lhs Inline list at the left side of the expression.
* @param rhs Inline list at the right side of the expression.
* @return @c true if the lists are equals, @c false otherwise.
*
* This operator checks if the given inline lists are equal. To be
* considered equal both lists need to have the same number of elements,
* and each element in one list must be equal to the element at the same
* position in the other list.
*/
template <typename T, typename Allocator1, typename Allocator2> template <typename T, typename Allocator1, typename Allocator2>
bool operator==(inlist<T, Allocator1> const& lhs, inlist<T, Allocator2> const& rhs) bool operator==(inlist<T, Allocator1> const& lhs, inlist<T, Allocator2> const& rhs)
{ {
@ -601,18 +1138,33 @@ bool operator==(inlist<T, Allocator1> const& lhs, inlist<T, Allocator2> const& r
std::equal(lhs.begin(), lhs.end(), rhs.begin()); std::equal(lhs.begin(), lhs.end(), rhs.begin());
} }
/**
* @brief Return the opposite of @ref operator==(inlist<T, Allocator1> const& lhs, inlist<T, Allocator2> const& rhs).
*/
template <typename T, typename Allocator1, typename Allocator2> template <typename T, typename Allocator1, typename Allocator2>
bool operator!=(inlist<T, Allocator1> const& lhs, inlist<T, Allocator2> const& rhs) bool operator!=(inlist<T, Allocator1> const& lhs, inlist<T, Allocator2> const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @brief Swap content between two inline lists.
* @param other Other inline list of the same type.
*/
template <typename T, typename Allocator> template <typename T, typename Allocator>
void swap(inlist<T, Allocator>& lhs, inlist<T, Allocator>& rhs) void swap(inlist<T, Allocator>& lhs, inlist<T, Allocator>& rhs)
{ {
lhs.swap(rhs); lhs.swap(rhs);
} }
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -1,18 +1,42 @@
#ifndef EINA_CXX_EINA_INTEGER_SEQUENCE_HH #ifndef EINA_CXX_EINA_INTEGER_SEQUENCE_HH
#define EINA_CXX_EINA_INTEGER_SEQUENCE_HH #define EINA_CXX_EINA_INTEGER_SEQUENCE_HH
/**
* @addtogroup Eina_Cxx_Data_Types_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Integer_Sequence_Group Integer Sequence
* @ingroup Eina_Cxx_Data_Types_Group
*
* @{
*/
/**
* Compile-time sequence of integers.
*/
template <typename T, T... Ints> template <typename T, T... Ints>
struct integer_sequence struct integer_sequence
{ {
typedef T value_type; typedef T value_type; /**< Type of the integers. */
/**
* @brief Get the number of elements in the sequence.
* @return <tt>std::size_t</tt> representing the sequence size.
*/
static constexpr std::size_t size() { return sizeof...(Ints); } static constexpr std::size_t size() { return sizeof...(Ints); }
typedef integer_sequence<T, Ints...> type; typedef integer_sequence<T, Ints...> type; /**< Type for the sequence instantiation. */
}; };
template<class S1, class S2> struct concat; template<class S1, class S2> struct concat;
/**
* Compile-time concatenation of two integer sequences.
*/
template<typename T, T... I1, T... I2> template<typename T, T... I1, T... I2>
struct concat<integer_sequence<T, I1...>, integer_sequence<T, I2...> > struct concat<integer_sequence<T, I1...>, integer_sequence<T, I2...> >
: integer_sequence<T, I1..., (sizeof...(I1)+I2)...> {}; : integer_sequence<T, I1..., (sizeof...(I1)+I2)...> {};
@ -21,6 +45,10 @@ template<class S1, class S2>
using Concat = typename concat<S1, S2>::type; using Concat = typename concat<S1, S2>::type;
template<typename T, T N> struct gen_seq; template<typename T, T N> struct gen_seq;
/**
* Make a compile time sequence of integers from @c 0 to <tt>N-1</tt>.
*/
template<typename T, T N> using make_integer_sequence = typename gen_seq<T, N>::type; template<typename T, T N> using make_integer_sequence = typename gen_seq<T, N>::type;
template<typename T, T N> template<typename T, T N>
@ -30,12 +58,26 @@ struct gen_seq : Concat<make_integer_sequence<T, N/2>
template<> struct gen_seq<std::size_t, 0> : integer_sequence<std::size_t>{}; template<> struct gen_seq<std::size_t, 0> : integer_sequence<std::size_t>{};
template<> struct gen_seq<std::size_t, 1> : integer_sequence<std::size_t, 0>{}; template<> struct gen_seq<std::size_t, 1> : integer_sequence<std::size_t, 0>{};
/**
* Compile time sequence of indexes.
*/
template <std::size_t... I> template <std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>; using index_sequence = integer_sequence<std::size_t, I...>;
/**
* Make a compile time sequence of indexes from @c 0 to <tt>N-1</tt>.
*/
template <std::size_t I> template <std::size_t I>
using make_index_sequence = make_integer_sequence<std::size_t, I>; using make_index_sequence = make_integer_sequence<std::size_t, I>;
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -6,33 +6,86 @@
#include <cstdlib> #include <cstdlib>
#include <iterator> #include <iterator>
/**
* @addtogroup Eina_Cxx_Content_Access_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Iterator_Group Iterator
* @ingroup Eina_Cxx_Content_Access_Group
*
* @{
*/
/**
* Common implementations for iterators.
*/
template <typename T> template <typename T>
struct _common_iterator_base struct _common_iterator_base
{ {
private: private:
typedef _common_iterator_base<T> self_type; typedef _common_iterator_base<T> self_type; /**< Type for the iterator instantiation itself. */
public: public:
typedef T const value_type; typedef T const value_type; /**< Type for elements returned by the iterator. */
typedef value_type* pointer; typedef value_type* pointer; /**< Type for a pointer to an element. */
typedef value_type& reference; typedef value_type& reference; /**< Type for a reference to an element. */
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type; /**< Type to represent the distance between two iterators. */
typedef std::input_iterator_tag iterator_category; typedef std::input_iterator_tag iterator_category; /**< Defines the iterator as being an input iterator. */
/**
* @brief Default constructor. Creates an iterator that points to nothing.
*/
_common_iterator_base() {} _common_iterator_base() {}
/**
* @brief Creates a iterator wrapping the given native @c Eina_Iterator handle.
* @param iterator Handle to a native @c Eina_Iterator.
*
* This constructor creates an iterator that wraps the given native
* @c Eina_Iterator handle, providing an OOP interface to it.
*
* @warning The created iterator object gains ownership of the handle
* and will deallocate it at destruction time.
*/
explicit _common_iterator_base(Eina_Iterator* iterator) explicit _common_iterator_base(Eina_Iterator* iterator)
: _iterator(iterator) {} : _iterator(iterator) {}
/**
* @brief Release the internal native Eina iterator handle.
*/
~_common_iterator_base() ~_common_iterator_base()
{ {
if(_iterator) if(_iterator)
eina_iterator_free(_iterator); eina_iterator_free(_iterator);
} }
/**
* @brief Creates an iterator from another iterator of the same type.
* @param other Another iterator of the same type.
*
* @warning The supplied iterator transfer its internal handle to the
* new iterator, thus @p other will point to nothing after the call
* of this constructor.
*/
_common_iterator_base(self_type const& other) _common_iterator_base(self_type const& other)
: _iterator(other._iterator) : _iterator(other._iterator)
{ {
other._iterator = 0; other._iterator = 0;
} }
/**
* @brief Acquire the internal handle of the given iterator.
* @param other Another iterator of the same type.
* @return Reference for itself.
*
* @warning The supplied iterator transfer its internal handle to the
* new iterator, thus @p other will point to nothing after the call
* of this constructor.
*/
_common_iterator_base& operator=(self_type const& other) _common_iterator_base& operator=(self_type const& other)
{ {
_iterator = other._iterator; _iterator = other._iterator;
@ -41,38 +94,76 @@ public:
} }
protected: protected:
/**
* @internal
*/
mutable Eina_Iterator* _iterator; mutable Eina_Iterator* _iterator;
/**
* @brief Check if the iterators wrap the same handle.
* @param lhs Iterator at the left side of the expression.
* @param lhs Iterator at the right side of the expression.
* @return @c true if both iterators wrap the same handle, @c false otherwise.
*/
friend inline bool operator==(_common_iterator_base<T> const& lhs, _common_iterator_base<T> const& rhs) friend inline bool operator==(_common_iterator_base<T> const& lhs, _common_iterator_base<T> const& rhs)
{ {
return lhs._iterator == rhs._iterator; return lhs._iterator == rhs._iterator;
} }
/**
* @brief Check if the iterators wrap the different handles.
* @param lhs Iterator at the left side of the expression.
* @param lhs Iterator at the right side of the expression.
* @return @c true if the iterators wrap different handles, @c false otherwise.
*/
friend inline bool operator!=(_common_iterator_base<T> const& lhs, _common_iterator_base<T> const& rhs) friend inline bool operator!=(_common_iterator_base<T> const& lhs, _common_iterator_base<T> const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
}; };
/**
* C++ wrappers to the native @c Eina_Iterator.
* It provides an OOP interface to the @c Eina_Iterator functions, and
* automatically take care of allocating a deallocating resources using
* the RAII programming idiom.
*/
template <typename T> template <typename T>
struct iterator : _common_iterator_base<T const> struct iterator : _common_iterator_base<T const>
{ {
private: private:
typedef _common_iterator_base<T const> base_type; typedef _common_iterator_base<T const> base_type; /**< Type for the base class. */
typename base_type::pointer _value; typename base_type::pointer _value; /**< @internal */
typedef iterator<T> self_type; typedef iterator<T> self_type; /**< Type for the specialized iterator itself. */
public: public:
typedef typename base_type::value_type value_type; typedef typename base_type::value_type value_type; /**< Type for elements returned by the iterator. */
typedef typename base_type::pointer pointer; typedef typename base_type::pointer pointer; /**< Type for a pointer to an element. */
typedef typename base_type::reference reference; typedef typename base_type::reference reference; /**< Type for a reference to an element. */
typedef typename base_type::difference_type difference_type; typedef typename base_type::difference_type difference_type; /**< Type to represent the distance between two iterators. */
typedef typename base_type::iterator_category iterator_category; 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) explicit iterator(Eina_Iterator* iterator = 0)
: base_type(iterator) : base_type(iterator)
{ {
if(this->_iterator) if(this->_iterator)
++*this; ++*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++() self_type& operator++()
{ {
void* data; void* data;
@ -82,20 +173,45 @@ public:
_value = static_cast<pointer>(data); _value = static_cast<pointer>(data);
return *this; return *this;
} }
/**
* @brief Move the iterator to the next position.
* @return The iterator itself.
*
* Works exactly like @ref operator++().
*/
self_type& operator++(int) self_type& operator++(int)
{ {
return ++**this; return ++**this;
} }
/**
* @brief Get a reference to the element currently pointed by the iterator.
* @return Reference to the current element.
*/
value_type& operator*() const value_type& operator*() const
{ {
return *_value; return *_value;
} }
/**
* @brief Return a pointer to the current element, which member will be accessed.
* @return Pointer to the element currently pointed by the iterator.
*/
pointer operator->() const pointer operator->() const
{ {
return _value; return _value;
} }
}; };
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -3,8 +3,17 @@
#include <Eina.h> #include <Eina.h>
/**
* @addtogroup Eina_Cxx_Containers_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @internal
*/
inline Eina_List* _eina_list_prepend_relative_list(Eina_List* list, const void* data, Eina_List* relative) EINA_ARG_NONNULL(2) inline Eina_List* _eina_list_prepend_relative_list(Eina_List* list, const void* data, Eina_List* relative) EINA_ARG_NONNULL(2)
{ {
if(relative) if(relative)
@ -13,6 +22,9 @@ inline Eina_List* _eina_list_prepend_relative_list(Eina_List* list, const void*
return ::eina_list_append(list, data); return ::eina_list_append(list, data);
} }
/**
* @internal
*/
inline Eina_Inlist *_eina_inlist_prepend_relative(Eina_Inlist *in_list, inline Eina_Inlist *_eina_inlist_prepend_relative(Eina_Inlist *in_list,
Eina_Inlist *in_item, Eina_Inlist *in_item,
Eina_Inlist *in_relative) EINA_ARG_NONNULL(2) Eina_Inlist *in_relative) EINA_ARG_NONNULL(2)
@ -25,4 +37,8 @@ inline Eina_Inlist *_eina_inlist_prepend_relative(Eina_Inlist *in_list,
} } } }
/**
* @}
*/
#endif #endif

View File

@ -3,39 +3,102 @@
#include <sstream> #include <sstream>
/**
* @addtogroup Eina_Cxx_Tools_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Log_Group Log
* @ingroup Eina_Cxx_Tools_Group
*
* @{
*/
/**
* Types to represent each log level.
*
* @{
*/
namespace log_level { namespace log_level {
/**
* Type for representing a critical log level.
*/
struct critical_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_CRITICAL; }; struct critical_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_CRITICAL; };
/** Critical log level */
critical_t const critical = {}; critical_t const critical = {};
/**
* Type for representing an error log level.
*/
struct error_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_ERR; }; struct error_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_ERR; };
/** Error log level */
error_t const error = {}; error_t const error = {};
/**
* Type for representing an information log level.
*/
struct info_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_INFO; }; struct info_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_INFO; };
/** Information log level */
info_t const info = {}; info_t const info = {};
/**
* Type for representing a debug log level.
*/
struct debug_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_DBG; }; struct debug_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_DBG; };
/** Debug log level */
debug_t const debug = {}; debug_t const debug = {};
/**
* Type for representing a warning log level.
*/
struct warn_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_WARN; }; struct warn_t { static constexpr ::Eina_Log_Level value = ::EINA_LOG_LEVEL_WARN; };
/** Warning log level */
warn_t const warning = {}; warn_t const warning = {};
} }
/**
* @}
*/
/**
* Base implementation for log domains.
*/
template <typename D> template <typename D>
struct _domain_base struct _domain_base
{ {
/**
* @brief Set the domain log level based on the given log level type.
*
* @{
*/
void set_level(log_level::critical_t l) { set_level(l.value); } void set_level(log_level::critical_t l) { set_level(l.value); }
void set_level(log_level::error_t l) { set_level(l.value); } void set_level(log_level::error_t l) { set_level(l.value); }
void set_level(log_level::info_t l) { set_level(l.value); } void set_level(log_level::info_t l) { set_level(l.value); }
void set_level(log_level::debug_t l) { set_level(l.value); } void set_level(log_level::debug_t l) { set_level(l.value); }
void set_level(log_level::warn_t l) { set_level(l.value); } void set_level(log_level::warn_t l) { set_level(l.value); }
/**
* @}
*/
/**
* @brief Set the domain log level to the level specified by the given identifier.
* @param l Eina native identifier to a log level.
*/
void set_level( ::Eina_Log_Level l) void set_level( ::Eina_Log_Level l)
{ {
::eina_log_domain_registered_level_set(static_cast<D&>(*this).domain_raw(), l); ::eina_log_domain_registered_level_set(static_cast<D&>(*this).domain_raw(), l);
} }
/**
* @brief Get the domain log level.
* @return Eina native identifier representing the current log level of the domain.
*/
::Eina_Log_Level get_level() const ::Eina_Log_Level get_level() const
{ {
return static_cast< ::Eina_Log_Level> return static_cast< ::Eina_Log_Level>
@ -43,35 +106,72 @@ struct _domain_base
} }
}; };
/**
* @internal
*/
struct global_domain : _domain_base<global_domain> struct global_domain : _domain_base<global_domain>
{ {
int domain_raw() const { return EINA_LOG_DOMAIN_GLOBAL; } int domain_raw() const { return EINA_LOG_DOMAIN_GLOBAL; }
}; };
/**
* General purpose log domain.
* It is always registered and available everywhere.
*/
struct global_domain const global_domain = {}; struct global_domain const global_domain = {};
/**
* @internal
*/
struct default_domain : _domain_base<default_domain> struct default_domain : _domain_base<default_domain>
{ {
int domain_raw() const { return EINA_LOG_DOMAIN_DEFAULT; } int domain_raw() const { return EINA_LOG_DOMAIN_DEFAULT; }
}; };
/**
* Default log domain.
* If the macro @c EINA_LOG_DOMAIN_DEFAULT is not defined to anything
* different it will be equivalent to @c global_domain.
*/
struct default_domain const default_domain = {}; struct default_domain const default_domain = {};
/**
* Class for creating log domains. It register a new domain upon
* construction and unregister it upon destruction, following the RAII
* programming idiom.
*/
struct log_domain : _domain_base<log_domain> struct log_domain : _domain_base<log_domain>
{ {
/**
* @brief Creates a new log domain.
* @param name Name of the domain.
* @param color Color of the domain name.
*/
log_domain(char const* name, char const* color = "black") log_domain(char const* name, char const* color = "black")
: _domain( ::eina_log_domain_register(name, color)) : _domain( ::eina_log_domain_register(name, color))
{ {
} }
/**
* @brief Unregister the domain.
*/
~log_domain() ~log_domain()
{ {
::eina_log_domain_unregister(_domain); ::eina_log_domain_unregister(_domain);
} }
int domain_raw() const { return _domain; } int domain_raw() const { return _domain; }
private: private:
/**
* @internal
*
* Member variable that holds the domain identifier.
*/
int _domain; int _domain;
}; };
/**
* @internal
*/
inline void _log(std::stringstream const& stream, int domain, ::Eina_Log_Level level inline void _log(std::stringstream const& stream, int domain, ::Eina_Log_Level level
, const char* file, const char* function, int line) , const char* file, const char* function, int line)
{ {
@ -79,6 +179,17 @@ inline void _log(std::stringstream const& stream, int domain, ::Eina_Log_Level l
, "%s", stream.str().c_str()); , "%s", stream.str().c_str());
} }
/**
* @def EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*
* Logs a message with level %p LEVEL on the domain %p DOMAIN.
*
* It works like a STL output stream and should be used with the left
* shift operator. Example:
* \code{.py}
* EINA_CXX_DOM_LOG(my_domain, my_log_level) << "My log message.";
* \endcode
*/
#define EINA_CXX_DOM_LOG(DOMAIN, LEVEL) \ #define EINA_CXX_DOM_LOG(DOMAIN, LEVEL) \
for( bool run = ::eina_log_domain_level_check((DOMAIN), LEVEL); run;) \ for( bool run = ::eina_log_domain_level_check((DOMAIN), LEVEL); run;) \
for(std::stringstream stream; run ; \ for(std::stringstream stream; run ; \
@ -86,39 +197,157 @@ inline void _log(std::stringstream const& stream, int domain, ::Eina_Log_Level l
, __FILE__, __FUNCTION__, __LINE__), run = false) \ , __FILE__, __FUNCTION__, __LINE__), run = false) \
stream stream
/**
* @def EINA_CXX_DOM_LOG_CRIT(DOMAIN)
*
* Logs a message with level %c EINA_LOG_LEVEL_CRITICAL on the domain
* %p DOMAIN.
*
* It is a short for EINA_CXX_DOM_LOG(DOMAIN, ::EINA_LOG_LEVEL_CRITICAL).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_DOM_LOG_CRIT(DOMAIN) \ #define EINA_CXX_DOM_LOG_CRIT(DOMAIN) \
EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_CRITICAL) EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_CRITICAL)
/**
* @def EINA_CXX_DOM_LOG_ERR(DOMAIN)
*
* Logs a message with level %c EINA_LOG_LEVEL_ERR on the domain
* %p DOMAIN.
*
* It is a short for EINA_CXX_DOM_LOG(DOMAIN, ::EINA_LOG_LEVEL_ERR).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_DOM_LOG_ERR(DOMAIN) \ #define EINA_CXX_DOM_LOG_ERR(DOMAIN) \
EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_ERR) EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_ERR)
/**
* @def EINA_CXX_DOM_LOG_INFO(DOMAIN)
*
* Logs a message with level %c EINA_LOG_LEVEL_INFO on the domain
* %p DOMAIN.
*
* It is a short for EINA_CXX_DOM_LOG(DOMAIN, ::EINA_LOG_LEVEL_INFO).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_DOM_LOG_INFO(DOMAIN) \ #define EINA_CXX_DOM_LOG_INFO(DOMAIN) \
EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_INFO) EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_INFO)
/**
* @def EINA_CXX_DOM_LOG_DBG(DOMAIN)
*
* Logs a message with level %c EINA_LOG_LEVEL_DBG on the domain
* %p DOMAIN.
*
* It is a short for EINA_CXX_DOM_LOG(DOMAIN, ::EINA_LOG_LEVEL_DBG).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_DOM_LOG_DBG(DOMAIN) \ #define EINA_CXX_DOM_LOG_DBG(DOMAIN) \
EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_DBG) EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_DBG)
/**
* @def EINA_CXX_DOM_LOG_WARN(DOMAIN)
*
* Logs a message with level %c EINA_LOG_LEVEL_WARN on the domain
* %p DOMAIN.
*
* It is a short for EINA_CXX_DOM_LOG(DOMAIN, ::EINA_LOG_LEVEL_WARN).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_DOM_LOG_WARN(DOMAIN) \ #define EINA_CXX_DOM_LOG_WARN(DOMAIN) \
EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_WARN) EINA_CXX_DOM_LOG(DOMAIN.domain_raw(), ::EINA_LOG_LEVEL_WARN)
/**
* @def EINA_CXX_LOG(LEVEL)
*
* Logs a message with level %p LEVEL on the default domain
* %c EINA_LOG_DOMAIN_DEFAULT.
*
* It is a short for EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, LEVEL).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_LOG(LEVEL) \ #define EINA_CXX_LOG(LEVEL) \
EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, LEVEL) EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, LEVEL)
/**
* @def EINA_CXX_LOG_CRIT()
*
* Logs a message with level %c EINA_LOG_LEVEL_CRITICAL on the default
* domain %c EINA_LOG_DOMAIN_DEFAULT.
*
* It is a short for EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, ::EINA_LOG_LEVEL_CRITICAL).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_LOG_CRIT() \ #define EINA_CXX_LOG_CRIT() \
EINA_CXX_LOG(EINA_LOG_LEVEL_CRITICAL) EINA_CXX_LOG(EINA_LOG_LEVEL_CRITICAL)
/**
* @def EINA_CXX_LOG_ERR()
*
* Logs a message with level %c EINA_LOG_LEVEL_ERR on the default
* domain %c EINA_LOG_DOMAIN_DEFAULT.
*
* It is a short for EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, ::EINA_LOG_LEVEL_ERR).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_LOG_ERR() \ #define EINA_CXX_LOG_ERR() \
EINA_CXX_LOG(EINA_LOG_LEVEL_ERR) EINA_CXX_LOG(EINA_LOG_LEVEL_ERR)
/**
* @def EINA_CXX_LOG_INFO()
*
* Logs a message with level %c EINA_LOG_LEVEL_INFO on the default
* domain %c EINA_LOG_DOMAIN_DEFAULT.
*
* It is a short for EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, ::EINA_LOG_LEVEL_INFO).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_LOG_INFO() \ #define EINA_CXX_LOG_INFO() \
EINA_CXX_LOG(EINA_LOG_LEVEL_INFO) EINA_CXX_LOG(EINA_LOG_LEVEL_INFO)
/**
* @def EINA_CXX_LOG_DBG()
*
* Logs a message with level %c EINA_LOG_LEVEL_DBG on the default
* domain %c EINA_LOG_DOMAIN_DEFAULT.
*
* It is a short for EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, ::EINA_LOG_LEVEL_DBG).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_LOG_DBG() \ #define EINA_CXX_LOG_DBG() \
EINA_CXX_LOG(EINA_LOG_LEVEL_DBG) EINA_CXX_LOG(EINA_LOG_LEVEL_DBG)
/**
* @def EINA_CXX_LOG_WARN()
*
* Logs a message with level %c EINA_LOG_LEVEL_WARN on the default
* domain %c EINA_LOG_DOMAIN_DEFAULT.
*
* It is a short for EINA_CXX_DOM_LOG(EINA_LOG_DOMAIN_DEFAULT, ::EINA_LOG_LEVEL_WARN).
*
* @see EINA_CXX_DOM_LOG(DOMAIN, LEVEL)
*/
#define EINA_CXX_LOG_WARN() \ #define EINA_CXX_LOG_WARN() \
EINA_CXX_LOG(EINA_LOG_LEVEL_WARN) EINA_CXX_LOG(EINA_LOG_LEVEL_WARN)
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -5,8 +5,17 @@
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
/**
* @addtogroup Eina_Cxx_Data_Types_Group
*
* @{
*/
namespace efl_eina_swap_adl { namespace efl_eina_swap_adl {
/**
* @internal
*/
template <typename T> template <typename T>
void swap_impl(T& lhs, T& rhs) void swap_impl(T& lhs, T& rhs)
{ {
@ -18,34 +27,105 @@ void swap_impl(T& lhs, T& rhs)
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Optional_Group Optional Value
* @ingroup Eina_Cxx_Data_Types_Group
*
* @{
*/
/**
* @internal
*/
template <typename T> template <typename T>
void adl_swap(T& lhs, T& rhs) void adl_swap(T& lhs, T& rhs)
{ {
::efl_eina_swap_adl::swap_impl<T>(lhs, rhs); ::efl_eina_swap_adl::swap_impl<T>(lhs, rhs);
} }
/**
* This class manages an optional contained value, i.e. a value that
* semantically may not be present.
*
* A common use case for optional is the return value of a function that
* may fail. As opposed to other approaches, such as
* <tt>std::pair<T,bool></tt>, optional handles expensive to construct
* objects well and is more readable, as the intent is expressed
* explicitly.
*
* An optional object holding a semantically present value is considered
* to be @em engaged, otherwise it is considered to be @em disengaged.
*/
template <typename T> template <typename T>
struct optional struct optional
{ {
typedef optional<T> _self_type; typedef optional<T> _self_type; /**< Type for the optional class itself. */
/**
* @brief Create a disengaged object.
*
* This constructor creates a disengaged <tt>eina::optional</tt>
* object, since null pointer is meant to be a valid object type.
*/
optional(std::nullptr_t) : engaged(false) optional(std::nullptr_t) : engaged(false)
{} {}
/**
* @brief Default constructor. Create a disengaged object.
*/
optional() : engaged(false) optional() : engaged(false)
{} {}
/**
* @brief Create an engaged object by moving @p other content.
* @param other R-value reference to the desired type.
*
* This constructor creates an <tt>eina::optional</tt> object in an
* engaged state. The contained value is initialized by moving
* @p other.
*/
optional(T&& other) : engaged(false) optional(T&& other) : engaged(false)
{ {
_construct(std::move(other)); _construct(std::move(other));
} }
/**
* @brief Create an engaged object by copying @p other content.
* @param other Constant reference to the desired type.
*
* This constructor creates an <tt>eina::optional</tt> object in an
* engaged state. The contained value is initialized by copying
* @p other.
*/
optional(T const& other) : engaged(false) optional(T const& other) : engaged(false)
{ {
_construct(std::move(other)); _construct(std::move(other));
} }
/**
* @brief Copy constructor. Create an object containing the same value as @p other and in the same state.
* @param other Constant reference to another <tt>eina::optional</tt> object that holds the same value type.
*
* This constructor creates an <tt>eina::optional</tt> object with
* the same engagement state of @p other. If @p other is engaged then
* the contained value of the newly created object is initialized by
* copying the contained value of @p other.
*/
optional(optional<T> const& other) optional(optional<T> const& other)
: engaged(false) : engaged(false)
{ {
if(other.engaged) _construct(*other); if(other.engaged) _construct(*other);
} }
/**
* @brief Move constructor. Create an object containing the same value as @p other and in the same state.
* @param other R-value reference to another <tt>eina::optional</tt> object that holds the same value type.
*
* This constructor creates an <tt>eina::optional</tt> object with
* the same engagement state of @p other. If @p other is engaged then
* the contained value of the newly created object is initialized by
* moving the contained value of @p other.
*/
optional(optional<T>&& other) optional(optional<T>&& other)
: engaged(false) : engaged(false)
{ {
@ -53,6 +133,16 @@ struct optional
other._destroy(); other._destroy();
} }
/**
* @brief Assign new content to the object.
* @param other R-value reference to another <tt>eina::optional</tt> object that holds the same value type.
*
* This operator replaces the current content of the object. If
* @p other is engaged its contained value is moved to this object,
* making <tt>*this</tt> be considered engaged too. If @p other is
* disengaged <tt>*this</tt> is also made disengaged and its
* contained value, if any, is simple destroyed.
*/
_self_type& operator=(optional<T>&& other) _self_type& operator=(optional<T>&& other)
{ {
_destroy(); _destroy();
@ -62,6 +152,17 @@ struct optional
other._destroy(); other._destroy();
return *this; return *this;
} }
/**
* @brief Assign new content to the object.
* @param other Constant reference to another <tt>eina::optional</tt> object that holds the same value type.
*
* This operator replaces the current content of the object. If
* @p other is engaged its contained value is copied to this object,
* making <tt>*this</tt> be considered engaged too. If @p other is
* disengaged <tt>*this</tt> is also made disengaged and its
* contained value, if any, is simple destroyed.
*/
_self_type& operator=(optional<T>const& other) _self_type& operator=(optional<T>const& other)
{ {
optional<T> tmp(other); optional<T> tmp(other);
@ -69,37 +170,80 @@ struct optional
return *this; return *this;
} }
/**
* @brief Releases the contained value if the object is engaged.
*/
~optional() ~optional()
{ {
_destroy(); _destroy();
} }
/**
* @brief Convert to @c bool based on whether the object is engaged or not.
* @return @c true if the object is engaged, @c false otherwise.
*/
explicit operator bool() const explicit operator bool() const
{ {
return is_engaged(); return is_engaged();
} }
/**
* @brief Convert to @c bool based on whether the object is engaged or not.
* @return @c true if the object is disengaged, @c false otherwise.
*/
bool operator!() const bool operator!() const
{ {
bool b ( *this ); bool b ( *this );
return !b; return !b;
} }
/**
* @brief Access member of the contained value.
* @return Pointer to the contained value, whose member will be accessed.
*/
T* operator->() T* operator->()
{ {
assert(is_engaged()); assert(is_engaged());
return static_cast<T*>(static_cast<void*>(&buffer)); return static_cast<T*>(static_cast<void*>(&buffer));
} }
/**
* @brief Access constant member of the contained value.
* @return Constant pointer to the contained value, whose member will be accessed.
*/
T const* operator->() const T const* operator->() const
{ {
return const_cast<_self_type&>(*this).operator->(); return const_cast<_self_type&>(*this).operator->();
} }
/**
* @brief Get the contained value.
* @return Reference to the contained value.
*/
T& operator*() { return get(); } T& operator*() { return get(); }
/**
* @brief Get the contained value.
* @return Constant reference to the contained value.
*/
T const& operator*() const { return get(); } T const& operator*() const { return get(); }
/**
* @brief Get the contained value.
* @return Reference to the contained value.
*/
T& get() { return *this->operator->(); } T& get() { return *this->operator->(); }
/**
* @brief Get the contained value.
* @return Constant reference to the contained value.
*/
T const& get() const { return *this->operator->(); } T const& get() const { return *this->operator->(); }
/**
* @brief Swap content with another <tt>eina::optional</tt> object.
* @param other Another <tt>eina::optional</tt> object.
*/
void swap(optional<T>& other) void swap(optional<T>& other)
{ {
if(is_engaged() && other.is_engaged()) if(is_engaged() && other.is_engaged())
@ -118,11 +262,19 @@ struct optional
} }
} }
/**
* @brief Check if the object is engaged.
* @return @c true if the object is currently engaged, @c false otherwise.
*/
bool is_engaged() const bool is_engaged() const
{ {
return engaged; return engaged;
} }
private: private:
/**
* @internal
*/
template <typename U> template <typename U>
void _construct(U&& object) void _construct(U&& object)
{ {
@ -130,6 +282,10 @@ private:
new (&buffer) T(std::move(object)); new (&buffer) T(std::move(object));
engaged = true; engaged = true;
} }
/**
* @internal
*/
void _destroy() void _destroy()
{ {
if(is_engaged()) if(is_engaged())
@ -141,16 +297,36 @@ private:
typedef typename std::aligned_storage typedef typename std::aligned_storage
<sizeof(T),std::alignment_of<T>::value>::type buffer_type; <sizeof(T),std::alignment_of<T>::value>::type buffer_type;
/**
* Member variable for holding the contained value.
*/
buffer_type buffer; buffer_type buffer;
/**
* Flag to tell whether the object is engaged or not.
*/
bool engaged; bool engaged;
}; };
/**
* @brief Swap content with another <tt>eina::optional</tt> object.
*
*/
template <typename T> template <typename T>
void swap(optional<T>& lhs, optional<T>& rhs) void swap(optional<T>& lhs, optional<T>& rhs)
{ {
lhs.swap(rhs); lhs.swap(rhs);
} }
/**
* @brief Check if both <tt>eina::optional</tt> object are equal.
* @param lhs <tt>eina::optional</tt> object at the left side of the expression.
* @param rhs <tt>eina::optional</tt> object at the right side of the expression.
* @return @c true if both are objects are disengaged of if both objects
* are engaged and contain the same value, @c false in all
* other cases.
*/
template <typename T> template <typename T>
bool operator==(optional<T> const& lhs, optional<T> const& rhs) bool operator==(optional<T> const& lhs, optional<T> const& rhs)
{ {
@ -161,11 +337,28 @@ bool operator==(optional<T> const& lhs, optional<T> const& rhs)
else else
return *lhs == *rhs; return *lhs == *rhs;
} }
/**
* @brief Check if the <tt>eina::optional</tt> objects are different.
* @param lhs <tt>eina::optional</tt> object at the left side of the expression.
* @param rhs <tt>eina::optional</tt> object at the right side of the expression.
* @return The opposite of @ref operator==(optional<T> const& lhs, optional<T> const& rhs).
*/
template <typename T> template <typename T>
bool operator!=(optional<T> const& lhs, optional<T> const& rhs) bool operator!=(optional<T> const& lhs, optional<T> const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @brief Less than comparison between <tt>eina::optional</tt> objects.
* @param lhs <tt>eina::optional</tt> object at the left side of the expression.
* @param rhs <tt>eina::optional</tt> object at the right side of the expression.
* @return @c true if both objects are engaged and the contained value
* of @p lhs is less than the contained value of @p rhs, or if
* only @p lhs is disengaged. In all other cases returns
* @c false.
*/
template <typename T> template <typename T>
bool operator<(optional<T> const& lhs, optional<T> const& rhs) bool operator<(optional<T> const& lhs, optional<T> const& rhs)
{ {
@ -178,22 +371,60 @@ bool operator<(optional<T> const& lhs, optional<T> const& rhs)
else else
return *lhs < *rhs; return *lhs < *rhs;
} }
/**
* @brief Less than or equal comparison between <tt>eina::optional</tt> objects.
* @param lhs <tt>eina::optional</tt> object at the left side of the expression.
* @param rhs <tt>eina::optional</tt> object at the right side of the expression.
* @return @c true if @p lhs is disengaged or if both objects are
* engaged and the contained value of @p lhs is less than or
* equal to the contained value of @p rhs. In all other cases
* returns @c false.
*/
template <typename T> template <typename T>
bool operator<=(optional<T> const& lhs, optional<T> const& rhs) bool operator<=(optional<T> const& lhs, optional<T> const& rhs)
{ {
return lhs < rhs || lhs == rhs; return lhs < rhs || lhs == rhs;
} }
/**
* @brief More than comparison between <tt>eina::optional</tt> objects.
* @param lhs <tt>eina::optional</tt> object at the left side of the expression.
* @param rhs <tt>eina::optional</tt> object at the right side of the expression.
* @return @c true if both objects are engaged and the contained value
* of @p lhs is more than the contained value of @p rhs, or if
* only @p rhs is disengaged. In all other cases returns
* @c false.
*/
template <typename T> template <typename T>
bool operator>(optional<T> const& lhs, optional<T> const& rhs) bool operator>(optional<T> const& lhs, optional<T> const& rhs)
{ {
return !(lhs <= rhs); return !(lhs <= rhs);
} }
/**
* @brief More than or equal comparison between <tt>eina::optional</tt> objects.
* @param lhs <tt>eina::optional</tt> object at the left side of the expression.
* @param rhs <tt>eina::optional</tt> object at the right side of the expression.
* @return @c true if @p rhs is disengaged or if both objects are
* engaged and the contained value of @p lhs is more than or
* equal to the contained value of @p rhs. In all other
* cases returns @c false.
*/
template <typename T> template <typename T>
bool operator>=(optional<T> const& lhs, optional<T> const& rhs) bool operator>=(optional<T> const& lhs, optional<T> const& rhs)
{ {
return !(lhs < rhs); return !(lhs < rhs);
} }
/**
* @}
*/
} } // efl::eina } } // efl::eina
/**
* @}
*/
#endif // EINA_OPTIONAL_HH_ #endif // EINA_OPTIONAL_HH_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,159 +1,377 @@
#ifndef EINA_RANGE_TYPES_HH_ #ifndef EINA_RANGE_TYPES_HH_
#define EINA_RANGE_TYPES_HH_ #define EINA_RANGE_TYPES_HH_
/**
* @addtogroup Eina_Cxx_Content_Access_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Range_Group Range
* @ingroup Eina_Cxx_Content_Access_Group
*
* @{
*/
/**
* @brief Range implementation for immutable collections.
*/
template <typename T, typename Traits> template <typename T, typename Traits>
struct _const_range_template struct _const_range_template
{ {
typedef typename Traits::template const_iterator<T>::type const_iterator; typedef typename Traits::template const_iterator<T>::type const_iterator; /**< Type for constant iterator to the range. */
typedef typename Traits::template iterator<T>::type iterator; typedef typename Traits::template iterator<T>::type iterator; /**< Type for iterator to the range. */
typedef T value_type; typedef T value_type; /**< The type of each element. */
typedef T& reference; typedef T& reference; /**< Type for a reference to an element. */
typedef T const& const_reference; typedef T const& const_reference; /**< Type for a constant reference to an element. */
typedef T* pointer; typedef T* pointer; /**< Type for a pointer to an element. */
typedef T const* const_pointer; typedef T const* const_pointer; /**< Type for a constant pointer to an element. */
typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; /**< Type for reverse iterator to the range. */
typedef std::reverse_iterator<const_iterator> const_reverse_iterator; typedef std::reverse_iterator<const_iterator> const_reverse_iterator; /**< Type for constant reverse iterator to the range. */
typedef std::size_t size_type; typedef std::size_t size_type; /**< Type for size information. */
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type; /**< Type to represent the distance between two iterators. */
typedef typename Traits::template const_native_handle<T>::type native_handle_type; typedef typename Traits::template const_native_handle<T>::type native_handle_type; /**< Type for the native handle of the container. */
typedef _const_range_template<T, Traits> _self_type; typedef _const_range_template<T, Traits> _self_type; /**< Type of the range itself. */
/**
* @brief Creates a range object wrapping the given native container handle.
*/
_const_range_template(native_handle_type handle) _const_range_template(native_handle_type handle)
: _handle(handle) {} : _handle(handle) {}
/**
* @brief Get a constant handle for the native Eina container.
* @return Constant handle for the native Eina container.
*/
native_handle_type native_handle() const { return _handle; } native_handle_type native_handle() const { return _handle; }
/**
* @brief Get a constant reference to the last element.
* @return Constant reference to the last element of the range.
*/
value_type const& back() const value_type const& back() const
{ {
return Traits::template back<value_type>(_handle); return Traits::template back<value_type>(_handle);
} }
/**
* @brief Get a constant reference to the first element.
* @return Constant reference to the first element of the range.
*/
value_type const& front() const value_type const& front() const
{ {
return Traits::template front<value_type>(_handle); return Traits::template front<value_type>(_handle);
} }
/**
* @brief Get a constant iterator pointing to the first element of the range.
* @return Constant iterator to the initial position of the range.
*
* This member function returns a constant iterator pointing to the
* first element of the range. If the range contains no elements the
* returned iterator is the same as the one returned by @ref end() const.
*/
const_iterator begin() const const_iterator begin() const
{ {
return cbegin(); return cbegin();
} }
/**
* @brief Get a constant iterator to the position following the last element of the range.
* @return Constant iterator to the final position of the range.
*
* This member function returns a constant iterator to the position
* following the last element in the range. If the range contains no
* elements the returned iterator is the same as the one returned by
* @ref begin() const.
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
const_iterator end() const const_iterator end() const
{ {
return cend(); return cend();
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse begin of the range.
* @return Constant reverse iterator pointing to the reverse begin of the range.
*
* This member function works like @ref rbegin() const but is granted
* to return a constant reverse iterator even for a range to a mutable
* collection.
*/
const_reverse_iterator crbegin() const const_reverse_iterator crbegin() const
{ {
return const_reverse_iterator(Traits::template rbegin<value_type>(_handle)); return const_reverse_iterator(Traits::template rbegin<value_type>(_handle));
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse end of the range.
* @return Constant reverse iterator pointing to the reverse end of the range.
*
* This member function works like @ref rend() const but is granted to
* return a constant reverse iterator even for range to a mutable
* collection.
*/
const_reverse_iterator crend() const const_reverse_iterator crend() const
{ {
return const_reverse_iterator(Traits::template rend<value_type>(_handle)); return const_reverse_iterator(Traits::template rend<value_type>(_handle));
} }
/**
* @brief Get a constant iterator pointing to the first element of the range.
* @return Constant iterator to the initial position of the range.
*
* This member function works like @ref begin() const but is granted
* to return a constant iterator even for a range to a mutable
* collection.
*/
const_iterator cbegin() const const_iterator cbegin() const
{ {
return Traits::template cbegin<value_type>(_handle); return Traits::template cbegin<value_type>(_handle);
} }
/**
* @brief Get a constant iterator to the position following the last element of the range.
* @return Constant iterator to the final position of the range.
*
* This member function works like @ref end() const but is granted to
* return a constant iterator even for a range to a mutable collection.
*/
const_iterator cend() const const_iterator cend() const
{ {
return Traits::template cend<value_type>(_handle); return Traits::template cend<value_type>(_handle);
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse begin of the range.
* @return Constant reverse iterator pointing to the reverse begin of the range.
*
* This member function returns a constant reverse iterator pointing
* to the last element of the range. If the range is empty the
* returned reverse iterator is the same as the one returned by
* @ref rend().
*/
const_reverse_iterator rbegin() const_reverse_iterator rbegin()
{ {
return crbegin(); return crbegin();
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse end of the range.
* @return Constant reverse iterator pointing to the reverse end of the range.
*
* This member function returns a constant reverse iterator pointing
* to the position before the first element of the range. If the range
* is empty the returned iterator is the same as the one returned by
* @ref rbegin().
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
const_reverse_iterator rend() const_reverse_iterator rend()
{ {
return crend(); return crend();
} }
/**
* @brief Check if the range does not contain any elements.
* @return @c true if there is no elements in the range, @c false otherwise.
*
* This member function returns @c true if the range does not contain
* any elements, otherwise it returns @c false.
*/
bool empty() const bool empty() const
{ {
return Traits::template empty<value_type>(_handle); return Traits::template empty<value_type>(_handle);
} }
/**
* @brief Get the number of elements in the range.
* @return Number of elements in the range.
*
* This member function returns the current number of elements in the
* range.
*/
size_type size() const size_type size() const
{ {
return Traits::template size<value_type>(_handle); return Traits::template size<value_type>(_handle);
} }
/**
* @brief Swap content with another range of the same type.
* @param other Another range of the same type.
*/
void swap(_self_type& other) void swap(_self_type& other)
{ {
std::swap(_handle, other._handle); std::swap(_handle, other._handle);
} }
protected: protected:
/**
* @internal
*/
native_handle_type _handle; native_handle_type _handle;
}; };
/**
* @brief Swap content between two @ref _const_range_template.
* @param lhs First @c _const_range_template object.
* @param rhs Second @c _const_range_template object.
*/
template <typename T, typename Traits> template <typename T, typename Traits>
void swap(_const_range_template<T, Traits>& lhs, _const_range_template<T, Traits>& rhs) void swap(_const_range_template<T, Traits>& lhs, _const_range_template<T, Traits>& rhs)
{ {
lhs.swap(rhs); lhs.swap(rhs);
} }
/**
* @brief Range implementation for mutable collections.
*/
template <typename T, typename Traits> template <typename T, typename Traits>
struct _mutable_range_template : _const_range_template<T, Traits> struct _mutable_range_template : _const_range_template<T, Traits>
{ {
typedef T value_type; typedef T value_type; /**< The type of each element. */
typedef typename Traits::template iterator<T>::type iterator; typedef typename Traits::template iterator<T>::type iterator; /**< Type for a iterator to the range. */
typedef std::reverse_iterator<iterator> reverse_iterator; typedef std::reverse_iterator<iterator> reverse_iterator; /**< Type for constant reverse iterator to the range. */
typedef typename Traits::template native_handle<T>::type native_handle_type; typedef typename Traits::template native_handle<T>::type native_handle_type; /**< Type for the native handle of the container. */
typedef _const_range_template<T, Traits> _base_type; typedef _const_range_template<T, Traits> _base_type; /**< Type for the base class. */
/**
* @brief Creates a range object wrapping the given native container handle.
*/
_mutable_range_template(native_handle_type handle) _mutable_range_template(native_handle_type handle)
: _base_type(handle) {} : _base_type(handle) {}
/**
* @brief Get a constant handle for the native Eina container.
* @return Constant handle for the native Eina container.
*/
native_handle_type native_handle() const native_handle_type native_handle() const
{ {
return Traits::template native_handle_from_const<T>(_base_type::native_handle()); return Traits::template native_handle_from_const<T>(_base_type::native_handle());
} }
/**
* @brief Get a reference to the last element.
* @return Reference to the last element of the range.
*/
value_type& back() const value_type& back() const
{ {
return Traits::template back<value_type>(native_handle()); return Traits::template back<value_type>(native_handle());
} }
/**
* @brief Get a reference to the first element.
* @return Reference to the first element of the range.
*/
value_type& front() const value_type& front() const
{ {
return Traits::template front<value_type>(native_handle()); return Traits::template front<value_type>(native_handle());
} }
/**
* @brief Get an iterator pointing to the first element of the range.
* @return Iterator to the initial position of the range.
*
* This member function returns an iterator pointing to the first
* element of the range. If the range contains no elements the
* returned iterator is the same as the one returned by @ref end() const.
*/
iterator begin() const iterator begin() const
{ {
return Traits::template begin<value_type>(native_handle()); return Traits::template begin<value_type>(native_handle());
} }
/**
* @brief Get an iterator to the position following the last element of the range.
* @return Iterator to the final position of the range.
*
* This member function returns an iterator to the position following
* the last element in the range. If the range contains no elements
* the returned iterator is the same as the one returned by
* @ref begin() const.
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
iterator end() const iterator end() const
{ {
return Traits::template end<value_type>(native_handle()); return Traits::template end<value_type>(native_handle());
} }
/**
* @brief Get a reverse iterator pointing to the reverse begin of the range.
* @return Reverse iterator pointing to the reverse begin of the range.
*
* This member function returns a reverse iterator pointing to the
* last element of the range. If the range is empty the returned
* reverse iterator is the same as the one returned by @ref rend().
*/
reverse_iterator rbegin() const reverse_iterator rbegin() const
{ {
return Traits::template rbegin<value_type>(native_handle()); return Traits::template rbegin<value_type>(native_handle());
} }
/**
* @brief Get a reverse iterator pointing to the reverse end of the range.
* @return Reverse iterator pointing to the reverse end of the range.
*
* This member function returns a reverse iterator pointing to the
* position before the first element of the range. If the range is
* empty the returned iterator is the same as the one returned by
* @ref rbegin().
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
reverse_iterator rend() const reverse_iterator rend() const
{ {
return Traits::template rend<value_type>(native_handle()); return Traits::template rend<value_type>(native_handle());
} }
protected: protected:
/**
* @internal
*/
using _base_type::_handle; using _base_type::_handle;
}; };
/**
* Range class.
*
* Provide objects for accessing and/or modifying elements inside a
* container without modifying the container itself.
*/
template <typename T, typename Traits> template <typename T, typename Traits>
struct _range_template : private std::conditional struct _range_template : private std::conditional
<std::is_const<T>::value <std::is_const<T>::value
, _const_range_template<typename std::remove_const<T>::type, Traits> , _const_range_template<typename std::remove_const<T>::type, Traits>
, _mutable_range_template<T, Traits> >::type , _mutable_range_template<T, Traits> >::type
{ {
typedef std::integral_constant<bool, !std::is_const<T>::value> is_mutable; typedef std::integral_constant<bool, !std::is_const<T>::value> is_mutable; /**< Type that specifies if the elements can be modified. */
typedef typename std::remove_const<T>::type value_type; typedef typename std::remove_const<T>::type value_type; /**< The type of each element. */
typedef typename std::conditional<is_mutable::value, _mutable_range_template<value_type, Traits> typedef typename std::conditional<is_mutable::value, _mutable_range_template<value_type, Traits>
, _const_range_template<value_type, Traits> >::type _base_type; , _const_range_template<value_type, Traits> >::type _base_type; /**< Type for the base class. */
typedef typename _base_type::native_handle_type native_handle_type; typedef typename _base_type::native_handle_type native_handle_type; /**< Type for the native handle of the container. */
typedef value_type& reference; typedef value_type& reference; /**< Type for a reference to an element. */
typedef value_type const& const_reference; typedef value_type const& const_reference; /**< Type for a constant reference to an element. */
typedef value_type* pointer; typedef value_type* pointer; /**< Type for a pointer to an element. */
typedef value_type const* const_pointer; typedef value_type const* const_pointer; /**< Type for a constant pointer to an element. */
typedef typename Traits::template const_iterator<T>::type const_iterator; typedef typename Traits::template const_iterator<T>::type const_iterator; /**< Type for constant iterator to the range. */
typedef typename _base_type::const_reverse_iterator const_reverse_iterator; typedef typename _base_type::const_reverse_iterator const_reverse_iterator; /**< Type for constant reverse iterator to the range. */
typedef typename Traits::template iterator<T>::type iterator; typedef typename Traits::template iterator<T>::type iterator; /**< Type for iterator to the range. */
typedef typename _base_type::reverse_iterator reverse_iterator; typedef typename _base_type::reverse_iterator reverse_iterator; /**< Type for reverse iterator to the range. */
typedef typename _base_type::size_type size_type; typedef typename _base_type::size_type size_type; /**< Type for size information. */
typedef typename _base_type::difference_type difference_type; typedef typename _base_type::difference_type difference_type; /**< Type to represent the distance between two iterators. */
/**
* @brief Creates a range object wrapping the given native container handle.
*/
_range_template(native_handle_type handle) _range_template(native_handle_type handle)
: _base_type(handle) : _base_type(handle)
{} {}
@ -175,6 +393,14 @@ protected:
using _base_type::_handle; using _base_type::_handle;
}; };
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -3,24 +3,75 @@
#include <functional> #include <functional>
/**
* @addtogroup Eina_Cxx_Tools_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Ref_Group Reference Wrapper
* @ingroup Eina_Cxx_Tools_Group
*
* @{
*/
/**
* @brief Creates a @c reference_wrapper to the given object.
* @return @c reference_wrapper holding a reference to the given object.
*
* Creates the appropriate reference_wrapper type to hold a reference to
* the given object. If the argument is itself a @c reference_wrapper,
* it creates a copy of it instead.
*/
using std::ref; using std::ref;
/**
* @brief Creates a @c reference_wrapper to the given object.
* @return @c reference_wrapper holding a reference to the given object.
*
* Specialized version of @ref ref for @c reference_wrapper to constant
* types.
*/
using std::cref; using std::cref;
/**
* Class that wraps a reference in a copyable, assignable object.
*/
using std::reference_wrapper; using std::reference_wrapper;
/**
* Get a reference from a @c reference_wrapper. If @p t is already a
* reference just return a reference to @p t.
*
* @{
*/
template <typename T> template <typename T>
T& unref(T& t) T& unref(T& t)
{ {
return t; return t;
} }
template <typename T> template <typename T>
T& unref(reference_wrapper<T> t) T& unref(reference_wrapper<T> t)
{ {
return t.get(); return t.get();
} }
/**
* @}
*/
/**
* @}
*/
}} }}
/**
* @}
*/
#endif #endif

View File

@ -7,11 +7,58 @@
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
/**
* @addtogroup Eina_Cxx_Data_Types_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Stringshare_Group Stringshare
* @ingroup Eina_Cxx_Data_Types_Group
*
* C++ Binding to Eina_Stringshare.
*
* This class allows you to store a single copy of a string, and use in
* multiple places throughout your program.
*
* This is a method to reduce the number of duplicated strings kept in
* memory. It's pretty common for the same strings to be dynamically
* allocated repeatedly between applications and libraries, especially in
* circumstances where you could have multiple copies of a structure that
* allocates the string. So rather than duplicating and freeing these
* strings, you request a read-only pointer to an existing string and
* only incur the overhead of a hash look-up.
*
* It sounds like micro-optimizing, but profiling has shown this can have
* a significant impact as you scale the number of copies up. It improves
* string creation/destruction speed, reduces memory use and decreases
* memory fragmentation, so a win all-around.
*
* @{
*/
/**
* Type for stealing the ownership of a string that was previously shared.
*/
struct steal_stringshare_ref_t {}; struct steal_stringshare_ref_t {};
/**
* Constant instance of @c steal_stringshare_ref_t for quick reference.
*/
steal_stringshare_ref_t const steal_stringshare_ref = {}; steal_stringshare_ref_t const steal_stringshare_ref = {};
/**
* Stringshare class. It provides an OOP interface to the
* @c Eina_Stringshare functions, and automatically take care of sharing
* the string upon construction and deleting it upon destruction using
* the RAII programming idiom.
*
* It also provides additional member functions to facilitate the access
* to the string content, much like a STL string.
*/
struct stringshare struct stringshare
{ {
typedef char value_type; typedef char value_type;
@ -24,17 +71,64 @@ struct stringshare
typedef std::ptrdiff_t difference_type; typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type; typedef std::size_t size_type;
/**
* @brief Default constructor. Creates a new object holding an shared empty string.
* @see stringshare(const char* str)
*/
stringshare() stringshare()
: _string( ::eina_stringshare_add("") ) : _string( ::eina_stringshare_add("") )
{} {}
/**
* @brief Share an instance of the given string wrapped by the newly created @c stringshare object.
* @param <tt>NULL</tt>-terminated string to be shared.
*
* This constructor creates an <tt>eina::stringshare</tt> object that
* shares the given string and wraps the shared pointer, providing an
* OOP interface to the string content. If the string is already
* shared this constructor simple increment its reference counter and
* wraps the shared pointer.
*
* @see stringshare(char* str, steal_stringshare_ref_t)
*/
stringshare(const char* str) stringshare(const char* str)
: _string( ::eina_stringshare_add(str) ) : _string( ::eina_stringshare_add(str) )
{ {
} }
/**
* @brief Create an <tt>eina::stringshare</tt> that steal the ownership of the given shared string.
* @param str Shared string whose ownership should be stolen.
*
* This constructor creates an <tt>eina::stringshare</tt> object that
* steals the ownership of the given shared string. At destruction
* time, the reference counter for the shared string will be
* decremented.
*
* The second parameter is an empty object of a specific type that
* should be supplied to explicitly inform that this is the intended
* constructor; and to differentiate this from
* @ref stringshare(const char* str).
*
* @warning @p str should be a string that was previously shared (most
* likely by an call to the native @c eina_stringshare_add function).
* If the string is not shared, upon destruction time bad things will
* happen, likely a segmentation fault.
*
* @see stringshare(const char* str)
*/
stringshare(char* str, steal_stringshare_ref_t) stringshare(char* str, steal_stringshare_ref_t)
: _string( str ) : _string( str )
{ {
} }
/**
* @brief Share the string between the iterator.
* @param i Iterator to the initial position of the string (inclusive).
* @param j Iterator to the final position of the string (exclusive).
* @note The ending position (pointed by @p j) is not considered.
* @see stringshare(const char* str)
*/
template <typename InputIterator> template <typename InputIterator>
stringshare(InputIterator i, InputIterator j stringshare(InputIterator i, InputIterator j
, typename eina::enable_if , typename eina::enable_if
@ -50,6 +144,14 @@ struct stringshare
} }
_string = ::eina_stringshare_add(tmp.c_str()); _string = ::eina_stringshare_add(tmp.c_str());
} }
/**
* @brief Share the string between the iterator.
* @param i Iterator to the initial position of the string (inclusive).
* @param j Iterator to the final position of the string (exclusive).
* @note The ending position (pointed by @p j) is not considered.
* @see stringshare(const char* str)
*/
template <typename ContiguousMemoryIterator> template <typename ContiguousMemoryIterator>
stringshare(ContiguousMemoryIterator i, ContiguousMemoryIterator j stringshare(ContiguousMemoryIterator i, ContiguousMemoryIterator j
, typename eina::enable_if , typename eina::enable_if
@ -58,81 +160,225 @@ struct stringshare
{ {
} }
/**
* @brief Destructor. Delete the shared string.
*
* Decreases the reference counter associated with the shared string.
* If the reference counter reaches 0, the memory associated with the
* string is freed.
*/
~stringshare() ~stringshare()
{ {
::eina_stringshare_del(_string); ::eina_stringshare_del(_string);
} }
/**
* @brief Copy constructor. Creates a new <tt>eina::stringshare</tt> associated with the same shared string.
* @param other Another <tt>eina::stringshare</tt>.
*
* This constructor increments the reference counter to the shared
* string associated with @p other.
*
* @see stringshare(const char* str)
*/
stringshare(stringshare const& other) stringshare(stringshare const& other)
: _string( eina_stringshare_ref(other._string) ) : _string( eina_stringshare_ref(other._string) )
{} {}
/**
* @brief Replace the current shared string.
* @param other Another <tt>eina::stringshare</tt>.
*
* This operator replaces the current shared string by the string
* shared by @p other. The reference counter of the older shared
* string is decremented (the string is released if needed) and the
* reference counter of the given shared string is incremented.
*/
stringshare& operator=(stringshare const& other) stringshare& operator=(stringshare const& other)
{ {
::eina_stringshare_refplace(&_string, other._string); ::eina_stringshare_refplace(&_string, other._string);
return *this; return *this;
} }
/**
* @brief Replace the current shared string.
* @param c_string <tt>NULL</tt>-terminated string.
*
* This operator replaces the shared string currently associated with
* this object by a shared instance of @p c_string.
*
* @see stringshare(const char* str)
*/
stringshare& operator=(const char* c_string) stringshare& operator=(const char* c_string)
{ {
::eina_stringshare_replace(&_string, c_string); ::eina_stringshare_replace(&_string, c_string);
return *this; return *this;
} }
/**
* @brief Get a constant iterator pointing to the first character of the string.
* @return Constant iterator to the initial position of the string.
*
* This member function returns a constant iterator pointing to the
* first character of the string. If the string is empty the iterator
* is equal to the one returned by @ref end() const.
*/
const_iterator begin() const const_iterator begin() const
{ {
return _string; return _string;
} }
/**
* @brief Get a constant iterator to the position following the last character of the string.
* @return Constant iterator to the final position of the string.
*
* This member function returns an constant iterator to the position
* following the last character in the string. If the string is empty
* the iterator is equal to the one returned by @ref begin().
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
const_iterator end() const const_iterator end() const
{ {
return _string + size(); return _string + size();
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse begin of the string.
* @return Constant reverse iterator pointing to the reverse begin of the string.
*
* This member function returns a constant reverse iterator pointing
* to the last character of the string. If the string is empty the
* returned reverse iterator is the same as the one returned by
* @ref rend() const.
*/
const_reverse_iterator rbegin() const const_reverse_iterator rbegin() const
{ {
return const_reverse_iterator(end()); return const_reverse_iterator(end());
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse end of the string.
* @return Constant reverse iterator pointing to the reverse end of the string.
*
* This member function returns a constant reverse iterator pointing
* to the position before the first character of the string. If the
* string is empty the returned iterator is the same as the one
* returned by @ref rbegin() const.
*
* @note Note that attempting to access this position causes undefined
* behavior.
*/
const_reverse_iterator rend() const const_reverse_iterator rend() const
{ {
return const_reverse_iterator(begin()); return const_reverse_iterator(begin());
} }
/**
* @brief Get a constant iterator pointing to the first character of the string.
* @return Constant iterator to the initial position of the string.
*
* This member function works just like @ref begin() const. But it is
* granted to always return a constant iterator.
*/
const_iterator cbegin() const const_iterator cbegin() const
{ {
return begin(); return begin();
} }
/**
* @brief Get a constant iterator to the position following the last character of the string.
* @return Constant iterator to the final position of the string.
*
* This member function works just like @ref end() const. But it is
* granted to always return a constant iterator.
*/
const_iterator cend() const const_iterator cend() const
{ {
return end(); return end();
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse begin of the string.
* @return Constant reverse iterator pointing to the reverse begin of the string.
*
* This member function works just like @ref rbegin() const. But it is
* granted to always return a constant reverse iterator.
*/
const_reverse_iterator crbegin() const const_reverse_iterator crbegin() const
{ {
return rbegin(); return rbegin();
} }
/**
* @brief Get a constant reverse iterator pointing to the reverse end of the string.
* @return Constant reverse iterator pointing to the reverse end of the string.
*
* This member function works just like @ref rend() const. But it is
* granted to always return a constant reverse iterator.
*/
const_reverse_iterator crend() const const_reverse_iterator crend() const
{ {
return rend(); return rend();
} }
/**
* @brief Get the size of the string.
* @return Number of characters in the string.
*/
size_type size() const size_type size() const
{ {
return eina_stringshare_strlen(_string); return eina_stringshare_strlen(_string);
} }
/**
* @brief Alias to @ref size() const.
*/
size_type length() const size_type length() const
{ {
return size(); return size();
} }
/**
* @brief Get the maximum number of characters a string can hold.
* @return Maximum number of characters a string can hold.
*/
size_type max_size() const size_type max_size() const
{ {
return -1; return -1;
} }
/**
* @brief Check if the string has no characters.
* @return @c true if the string has no characters, @c false otherwise.
*/
bool empty() const bool empty() const
{ {
return _string[0] == 0; return _string[0] == 0;
} }
/**
* @brief Get the character at the given position.
* @param i Position of the character in the string.
* @return Constant reference to the character at the given position.
* @note Do not check if the given position exceeds the string size.
*/
const_reference operator[](size_type i) const const_reference operator[](size_type i) const
{ {
return _string[i]; return _string[i];
} }
/**
* @brief Get the character at the given position.
* @param i Position of the character in the string.
* @return Constant reference to the character at the given position.
* @throw <tt>std::out_of_range</tt> if the given position exceeds the string size.
*
* This member function returns a constant reference to the character
* at the position @p i. If @p i exceeds the string size this function
* will throw a <tt>std::out_of_range</tt>.
*/
const_reference at(size_type i) const const_reference at(size_type i) const
{ {
if(i < size()) if(i < size())
@ -140,66 +386,143 @@ struct stringshare
else else
throw std::out_of_range(""); throw std::out_of_range("");
} }
/**
* @brief Get the last character of the string.
* @return Constant reference to the last character of the string.
*/
const_reference back() const const_reference back() const
{ {
return _string[size()-1]; return _string[size()-1];
} }
/**
* @brief Get the first character of the string.
* @return Constant reference to the first character of the string.
*/
const_reference front() const const_reference front() const
{ {
return _string[0]; return _string[0];
} }
/**
* @brief Swap shared strings with other <tt>eina::stringshare</tt>.
*/
void swap(stringshare& other) void swap(stringshare& other)
{ {
std::swap(_string, other._string); std::swap(_string, other._string);
} }
/**
* @brief Get the c-like shared string currently associated with the object.
* @return Pointer to the shared string.
* @note The pointer returned may be invalidated by calls to non-const member functions.
*/
const char* c_str() const const char* c_str() const
{ {
return _string; return _string;
} }
/**
* @brief Alias to @ref c_str() const.
*/
const char* data() const const char* data() const
{ {
return _string; return _string;
} }
private: private:
/**
* @internal
*/
Eina_Stringshare* _string; Eina_Stringshare* _string;
}; };
/**
* Specialization of the default template to define the
* <tt>stringshare::const_iterator</tt> as a contiguous iterator.
*/
template <> template <>
struct is_contiguous_iterator<stringshare::const_iterator> : true_type {}; struct is_contiguous_iterator<stringshare::const_iterator> : true_type {};
/**
* @brief Check if two <tt>eina::stringshare</tt> objects represent the same string.
* @return @c true if the strings of the objects are equal, @c false otherwise.
*
* This operator checks if two <tt>eina::stringshare</tt> objects
* represent the same string. Because of the nature of the objects,
* this operation falls into a simple pointer comparison, since
* identical strings are represented by the same instance.
*/
inline bool operator==(stringshare const& lhs, stringshare const& rhs) inline bool operator==(stringshare const& lhs, stringshare const& rhs)
{ {
return lhs.c_str() == rhs.c_str(); return lhs.c_str() == rhs.c_str();
} }
/**
* @brief Check if two <tt>eina::stringshare</tt> objects represent different strings.
* @return @c true if the strings of the objects are different, @c false otherwise.
*
* This function essentially returns the opposite of
* @ref operator==(stringshare const& lhs, stringshare const& rhs).
*/
inline bool operator!=(stringshare const& lhs, stringshare const& rhs) inline bool operator!=(stringshare const& lhs, stringshare const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @brief Compare an <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* string is equal the content of the given string, @c false
* otherwise.
*/
inline bool operator==(stringshare const& lhs, const char* rhs) inline bool operator==(stringshare const& lhs, const char* rhs)
{ {
return lhs.c_str() == rhs || std::strcmp(lhs.c_str(), rhs) == 0; return lhs.c_str() == rhs || std::strcmp(lhs.c_str(), rhs) == 0;
} }
/**
* @brief Compare an <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* string is different from content of the given string,
* @c false otherwise.
*/
inline bool operator!=(stringshare const& lhs, const char* rhs) inline bool operator!=(stringshare const& lhs, const char* rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @brief Compare an <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* string is equal the content of the given string, @c false
* otherwise.
*/
inline bool operator==(const char* lhs, stringshare const& rhs) inline bool operator==(const char* lhs, stringshare const& rhs)
{ {
return rhs == lhs; return rhs == lhs;
} }
/**
* @brief Compare an <tt>eina::stringshare</tt> object with a c-like string.
* @return @c true if the content of the <tt>eina::stringshare</tt>
* string is different from content of the given string,
* @c false otherwise.
*/
inline bool operator!=(const char* lhs, stringshare const& rhs) inline bool operator!=(const char* lhs, stringshare const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -13,23 +13,72 @@
#include <chrono> #include <chrono>
#include <mutex> #include <mutex>
/**
* @addtogroup Eina_Cxx_Tools_Group Tools
*
* @{
*/
#define EFL_EINA_BOOST_MOVABLE_BUT_NOT_COPYABLE(x) #define EFL_EINA_BOOST_MOVABLE_BUT_NOT_COPYABLE(x)
#define EFL_EINA_BOOST_RV_REF(x) x const& #define EFL_EINA_BOOST_RV_REF(x) x const&
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Mutex_Group Mutex
* @ingroup Eina_Cxx_Tools_Group
*
* @{
*/
/**
* Provides an OOP interface to the @c Eina_Lock and automatic resource
* allocation and deallocation using the RAII programming idiom.
*
* This class implements mutual exclusion variables (mutexes) in a way
* that strongly resembles the STL <tt>std::mutex</tt>.
*/
struct mutex struct mutex
{ {
typedef Eina_Lock* native_handle_type; typedef Eina_Lock* native_handle_type; /**< Type for the native Eina_Lock pointer. */
/**
* @brief Create a new mutex.
*
* Automatically allocates a new mutex and does any platform dependent
* initialization that is required.
*/
mutex() mutex()
{ {
::eina_lock_new(&_mutex); ::eina_lock_new(&_mutex);
} }
/**
* @brief Release mutex resources.
*
* Automatically deallocates the mutex and does any platform dependent
* cleanup that is required.
*/
~mutex() ~mutex()
{ {
::eina_lock_free(&_mutex); ::eina_lock_free(&_mutex);
} }
/**
* @brief Lock the mutex.
* @throw <tt>eina::system_error</tt> with the code
* <tt>eina::errc::resource_deadlock_would_occur</tt> if the
* operation fails because a deadlock condition exists. If some
* other condition causes the lock to fail (other than the
* mutex being already locked) the error code will be an
* internal Eina error code.
*
* This member function locks the mutex. If the mutex is locked
* already, this call will block until the lock is released. This is
* appropriate in many cases, but consider using @ref try_lock() if
* you don't need to block.
*/
void lock() void lock()
{ {
::Eina_Lock_Result r = ::eina_lock_take(&_mutex); ::Eina_Lock_Result r = ::eina_lock_take(&_mutex);
@ -44,6 +93,20 @@ struct mutex
throw system_error(get_error_code()); throw system_error(get_error_code());
} }
} }
/**
* @brief Attempts to lock the mutex.
* @return @c true if it succeed in locking the mutex, @c false otherwise.
* @throw <tt>eina::system_error</tt> with the code
* <tt>eina::errc::resource_deadlock_would_occur</tt> if the
* operation fails because a deadlock condition exists. If some
* other condition causes the lock to fail (other than the
* mutex being already locked) the error code will be an
* internal Eina error code.
*
* This member function attempts to lock the mutex, identical to
* @ref lock(), but returns immediately if the mutex is already locked.
*/
bool try_lock() bool try_lock()
{ {
::Eina_Lock_Result r = ::eina_lock_take_try(&_mutex); ::Eina_Lock_Result r = ::eina_lock_take_try(&_mutex);
@ -60,6 +123,21 @@ struct mutex
throw system_error(get_error_code()); throw system_error(get_error_code());
} }
} }
/**
* @brief Unlock the lock.
* @throw <tt>eina::system_error</tt> with the code
* <tt>eina::errc::resource_deadlock_would_occur</tt> if the
* operation fails because a deadlock condition exists. If some
* other condition causes the lock to fail the error code will
* be an internal Eina error code.
*
* This member function will unlock the mutex.
*
* @note If successful, and EINA_HAVE_DEBUG_THREADS is defined, the
* mutex is updated and information about the locking process
* is removed (e.g. thread number and backtrace for POSIX).
*/
void unlock() void unlock()
{ {
::Eina_Lock_Result r = ::eina_lock_release(&_mutex); ::Eina_Lock_Result r = ::eina_lock_release(&_mutex);
@ -74,37 +152,114 @@ struct mutex
throw system_error(get_error_code()); throw system_error(get_error_code());
} }
} }
/**
* @brief Print debug information about the mutex.
*
* This member function prints debug information for the mutex. The
* information is platform dependent. On POSIX systems it will print
* the address of mutex, lock state, thread number and a backtrace.
*/
void debug() void debug()
{ {
::eina_lock_debug(&_mutex); ::eina_lock_debug(&_mutex);
} }
/**
* @brief Get a handle for the wrapped @c Eina_Lock.
* @return Handle for the native @c Eina_Lock.
*
* This member function returns the native @c Eina_Lock handle that is
* wrapped inside this object.
*
* @warning It is important to take care when using it, since the
* handle will be automatically released upon object destruction.
*/
native_handle_type native_handle() native_handle_type native_handle()
{ {
return &_mutex; return &_mutex;
} }
private: private:
/** Disabled copy constructor. **/
mutex(mutex const&) = delete; mutex(mutex const&) = delete;
/** Disabled assignment operator. **/
mutex& operator=(mutex const&) = delete; mutex& operator=(mutex const&) = delete;
/**
* @internal
*/
Eina_Lock _mutex; Eina_Lock _mutex;
}; };
/**
* @brief Manage a mutex object by keeping it always locked.
*
* Inherited for the STL object <tt>std::lock_guard</tt>.
*/
using std::lock_guard; using std::lock_guard;
/**
* @brief Manages a mutex object.
*
* Inherited for the STL object <tt>std::unique_lock</tt>. This class
* guarantees an unlocked status on destruction.
*/
using std::unique_lock; using std::unique_lock;
/**
* @}
*/
/**
* @defgroup Eina_Cxx_Condition_Variable_Group Condition Variable
* @ingroup Eina_Cxx_Tools_Group
*
* @{
*/
/**
* Provides an OOP interface to the @c Eina_Condition and automatic
* resource allocation and deallocation using the RAII programming idiom.
*
* This class implements condition variables in a way that strongly
* resembles the STL <tt>std::condition_variable</tt>.
*/
struct condition_variable struct condition_variable
{ {
typedef Eina_Condition* native_handle_type; typedef Eina_Condition* native_handle_type; /**< Type for the native Eina_Lock pointer. */
/**
* @brief Create a new condition variable.
*
* Automatically allocates a new condition variable and does any
* platform dependent initialization that is required.
*/
condition_variable() condition_variable()
{ {
::eina_condition_new(&_cond, _mutex.native_handle()); ::eina_condition_new(&_cond, _mutex.native_handle());
} }
/**
* @brief Release the condition variable resources.
*
* Automatically deallocates the condition variable and does any
* platform dependent cleanup that is required.
*/
~condition_variable() ~condition_variable()
{ {
::eina_condition_free(&_cond); ::eina_condition_free(&_cond);
} }
/**
* @brief Unblock a thread waiting for this condition.
* @throw <tt>eina::system_error</tt> on fail.
*
* This member function unblock a thread waiting on this condition
* variable. If there is more than one thread waiting on this
* condition, one of them will be unblocked, but which one is
* undefined. If you do not know for sure that there is only one
* thread waiting, use @ref notify_all() instead.
*/
void notify_one() void notify_one()
{ {
eina::unique_lock<eina::mutex> l(_mutex); eina::unique_lock<eina::mutex> l(_mutex);
@ -112,6 +267,15 @@ struct condition_variable
if(!r) if(!r)
throw eina::system_error(eina::get_error_code()); throw eina::system_error(eina::get_error_code());
} }
/**
* @brief Unblock all threads waiting for this condition.
* @throw <tt>eina::system_error</tt> on fail.
*
* This member function unblocks all the threads waiting on the this
* condition. If you know for sure that there is only one thread
* waiting, use @ref notify_one instead to gain a little optimization.
*/
void notify_all() void notify_all()
{ {
eina::unique_lock<eina::mutex> l(_mutex); eina::unique_lock<eina::mutex> l(_mutex);
@ -119,6 +283,16 @@ struct condition_variable
if(!r) if(!r)
throw eina::system_error(eina::get_error_code()); throw eina::system_error(eina::get_error_code());
} }
/**
* @brief Causes a thread to wait until notified.
* @param lock A lockable object (@c mutex, @c unique_lock, etc) that
* is currently locked by this thread. All concurrent
* calls to wait member functions of this object shall use
* the same lockable object.
*
* This member function makes a thread block until notified.
*/
template <typename Lock> template <typename Lock>
void wait(Lock& lock) void wait(Lock& lock)
{ {
@ -127,47 +301,121 @@ struct condition_variable
::eina_condition_wait(&_cond); ::eina_condition_wait(&_cond);
lock.lock(); lock.lock();
} }
/**
* @brief Causes a thread to wait until notified.
* @param lock A lockable object (@c mutex, @c unique_lock, etc) that
* is currently locked by this thread. All concurrent
* calls to wait member functions of this object shall use
* the same lockable object.
* @param p A callable object or function that takes no arguments and
* returns a value that can be evaluated as a bool. This is
* called repeatedly until it evaluates to true.
*
* This member function only blocks the thread if @p p is evaluated to
* @c false. In this case the thread remains blocked until notified
* and the result of @p p evaluates to @c true.
*/
template <typename Lock, typename Predicate> template <typename Lock, typename Predicate>
void wait(Lock& lock, Predicate p) void wait(Lock& lock, Predicate p)
{ {
while(!p()) while(!p())
wait(lock); wait(lock);
} }
/**
* @brief Get a handle for the wrapped @c Eina_Condition.
* @return Handle for the native @c Eina_Condition.
*
* This member function returns the native @c Eina_Condition handle
* that is wrapped inside this object.
*
* @warning It is important to take care when using it, since the
* handle will be automatically released upon object destruction.
*/
native_handle_type native_handle() native_handle_type native_handle()
{ {
return &_cond; return &_cond;
} }
private: private:
/** Disabled copy constructor. **/
condition_variable(condition_variable const&); condition_variable(condition_variable const&);
/** Disabled assignment operator. **/
condition_variable& operator=(condition_variable const&); condition_variable& operator=(condition_variable const&);
mutex _mutex; mutex _mutex; /**< @internal */
Eina_Condition _cond; Eina_Condition _cond; /**< @internal */
}; };
/**
* @}
*/
/**
* @defgroup Eina_Cxx_Thread_Group Thread
* @ingroup Eina_Cxx_Tools_Group
*
* @{
*/
/**
* Thread identifier.
*/
struct thread_id struct thread_id
{ {
/**
* @brief Creates a @c thread_id that represents all non-joinable.
*/
thread_id() noexcept thread_id() noexcept
: _raw(0u) : _raw(0u)
{ {
} }
/**
* @brief
*/
thread_id(Eina_Thread raw) thread_id(Eina_Thread raw)
: _raw(raw) {} : _raw(raw) {}
/**
* @brief Check if two thread identifiers are the same.
* @return @c true if the thread identifiers have the same value.
*/
friend inline bool operator==(thread_id lhs, thread_id rhs) friend inline bool operator==(thread_id lhs, thread_id rhs)
{ {
return lhs._raw == rhs._raw; return lhs._raw == rhs._raw;
} }
/**
* @brief Check if two thread identifiers are different.
* @return @c true if the thread identifiers have different values.
*/
friend inline bool operator!=(thread_id lhs, thread_id rhs) friend inline bool operator!=(thread_id lhs, thread_id rhs)
{ {
return lhs._raw != rhs._raw; return lhs._raw != rhs._raw;
} }
/**
* @brief Less than comparison of thread identifiers.
* @param lhs @c thread_id at the left side of the expression.
* @param rhs @c thread_id at the right side of the expression.
* @return @c true if @c lhs is less than @c rhs, @c false otherwise.
* @note The order established by relational operators is
* implementation-defined.
*/
friend inline bool operator<(thread_id lhs, thread_id rhs) friend inline bool operator<(thread_id lhs, thread_id rhs)
{ {
return std::less<Eina_Thread>()(lhs._raw, rhs._raw); return std::less<Eina_Thread>()(lhs._raw, rhs._raw);
} }
private: private:
Eina_Thread _raw; Eina_Thread _raw; /**< @internal */
/**
* @brief Inserts a textual representation in the given stream.
* @param out Output stream where the textual representation will be inserted.
* @param id @c thread_id object.
* @return Reference to the modified <tt>std::basic_ostream</tt> object.
*/
template <typename charT, typename Traits> template <typename charT, typename Traits>
friend std::basic_ostream<charT, Traits>& friend std::basic_ostream<charT, Traits>&
operator<<(std::basic_ostream<charT, Traits>& out, thread_id id) operator<<(std::basic_ostream<charT, Traits>& out, thread_id id)
@ -176,21 +424,53 @@ private:
} }
}; };
/**
* @brief Less than or equal comparison of thread identifiers.
* @param lhs @c thread_id at the left side of the expression.
* @param rhs @c thread_id at the right side of the expression.
* @return @c true if @c lhs is less than or equal to @c rhs, @c false otherwise.
* @note The order established by relational operators is
* implementation-defined.
*/
inline bool operator<=(thread_id lhs, thread_id rhs) inline bool operator<=(thread_id lhs, thread_id rhs)
{ {
return (lhs == rhs) || lhs < rhs; return (lhs == rhs) || lhs < rhs;
} }
/**
* @brief More than comparison of thread identifiers.
* @param lhs @c thread_id at the left side of the expression.
* @param rhs @c thread_id at the right side of the expression.
* @return @c true if @c lhs is more than @c rhs, @c false otherwise.
* @note The order established by relational operators is
* implementation-defined.
*/
inline bool operator>(thread_id lhs, thread_id rhs) inline bool operator>(thread_id lhs, thread_id rhs)
{ {
return !(lhs <= rhs); return !(lhs <= rhs);
} }
/**
* @brief More than or equal comparison of thread identifiers.
* @param lhs @c thread_id at the left side of the expression.
* @param rhs @c thread_id at the right side of the expression.
* @return @c true if @c lhs is more than or equal to @c rhs, @c false otherwise.
* @note The order established by relational operators is
* implementation-defined.
*/
inline bool operator>=(thread_id lhs, thread_id rhs) inline bool operator>=(thread_id lhs, thread_id rhs)
{ {
return !(lhs < rhs); return !(lhs < rhs);
} }
/**
* @internal
*/
namespace _detail { namespace _detail {
/**
* @internal
*/
struct arguments struct arguments
{ {
Eina_Lock mutex; Eina_Lock mutex;
@ -199,6 +479,9 @@ struct arguments
std::function<void()> function; std::function<void()> function;
}; };
/**
* @internal
*/
inline void* create_thread(void* data, Eina_Thread) inline void* create_thread(void* data, Eina_Thread)
{ {
arguments* args = static_cast<arguments*>(data); arguments* args = static_cast<arguments*>(data);
@ -217,23 +500,47 @@ inline void* create_thread(void* data, Eina_Thread)
} }
/**
* Provides an OOP interface to the @c Eina_Thread and automatic
* resource allocation and deallocation using the RAII programming idiom.
*
* This class implements threads in a way that strongly resembles the
* STL <tt>std::thread</tt>.
*/
struct thread struct thread
{ {
typedef thread_id id; typedef thread_id id; /**< Type for the thread identifier. */
typedef Eina_Thread native_handle_type; typedef Eina_Thread native_handle_type; /**< Type for the native Eina_Thread handle. */
/**
* @brief Creates a thread object that does not represent any thread of execution.
*/
thread() noexcept thread() noexcept
: _joinable(false), _raw(0u) : _joinable(false), _raw(0u)
{ {
} }
/**
* @brief Creates a thread of execution.
* @param f Pointer to function or callable object to execute in the new thread.
* The return value (if any) is ignored.
* @param args Arguments to pass to the @p f.
*
* This constructor creates a thread object that represents a thread
* of execution. The new thread of execution calls @p f passing
* @p args as arguments (all arguments are copied/moved to
* thread-accessible storage).
*
* Any exceptions thrown during evaluation and copying/moving of the
* arguments are thrown in the current thread, not the new thread.
*/
template <typename F, class ... Args> template <typename F, class ... Args>
explicit thread(F&& f, Args&&... args) explicit thread(F&& f, Args&&... args)
{ {
_detail::arguments arguments; _detail::arguments arguments;
arguments.started = false; arguments.started = false;
arguments.function = std::bind(f, args...); arguments.function = std::bind(f, args...);
_joinable = true; _joinable = true;
Eina_Bool r = ::eina_lock_new(&arguments.mutex); Eina_Bool r = ::eina_lock_new(&arguments.mutex);
if(!r) throw eina::system_error(eina::get_error_code()); if(!r) throw eina::system_error(eina::get_error_code());
@ -264,11 +571,27 @@ struct thread
eina_lock_free(&arguments.mutex); eina_lock_free(&arguments.mutex);
} }
/**
* @brief Move constructor. Transfer the thread of execution to the new object.
* @param other Another thread object to construct this thread object with.
*
* This constructor creates a thread object that acquires the thread
* of execution represented by @p other. This operation does not
* affect the execution of the moved thread, it simply transfers its
* handler.
*
* @note After this call @p other no longer represents a thread of execution.
*/
thread(thread&& other) thread(thread&& other)
: _joinable(other._joinable), _raw(other._raw) : _joinable(other._joinable), _raw(other._raw)
{ {
} }
/**
* @brief Transfer the thread of execution.
* @param other Another thread object to assign to this thread object.
* @note After this call @p other no longer represents a thread of execution.
*/
thread& operator=(thread&& other) thread& operator=(thread&& other)
{ {
_raw = other._raw; _raw = other._raw;
@ -276,20 +599,50 @@ struct thread
return *this; return *this;
} }
/**
* @brief Destroys the thread object.
*/
~thread() ~thread()
{ {
assert(!joinable()); assert(!joinable());
} }
/**
* @brief Exchanges the underlying handles of two thread objects.
* @param other Another thread object.
*/
void swap(thread& other) noexcept void swap(thread& other) noexcept
{ {
std::swap(_raw, other._raw); std::swap(_raw, other._raw);
} }
/**
* @brief Check if the thread object identifies an active thread of execution.
* @return @c true if the thread object identifies an active thread of execution, @c false otherwise.
*
* This member function checks if the thread object identifies an
* active thread of execution. A default constructed thread is not
* joinable, as well as a thread that its members join or detach has
* been called.
*
* A thread that has finished executing code, but has not yet been
* joined is still considered an active thread of execution and is
* therefore joinable.
*/
bool joinable() const noexcept bool joinable() const noexcept
{ {
return _joinable; return _joinable;
} }
/**
* @brief Wait for the thread to finish its execution.
*
* This member function blocks the calling thread until the thread
* identified by this object finishes its execution.
*
* @note A joinable thread becomes not joinable after a call to this
* function.
*/
void join() void join()
{ {
assert(joinable()); assert(joinable());
@ -297,30 +650,70 @@ struct thread
_joinable = false; _joinable = false;
} }
/**
* @brief Detaches the thread from its handle, making it runs independently.
*
* This member function separates the thread of execution from the
* thread object, allowing execution to continue independently.
*
* @note After a call to this function, the thread object becomes
* non-joinable.
*/
void detach() void detach()
{ {
assert(joinable()); assert(joinable());
_joinable = false; _joinable = false;
} }
/**
* @brief Returns the identifier of the thread associated with this thread object.
* @return <tt>thread::id</tt> identifying the thread associated with this thread object.
*/
id get_id() const noexcept id get_id() const noexcept
{ {
return id(_raw); return id(_raw);
} }
/**
* @brief Get a handle for the wrapped @c Eina_Thread.
* @return Handle for the native @c Eina_Thread.
*
* This member function returns the native @c Eina_Thread handle that
* is wrapped inside this object.
*/
native_handle_type native_handle() const native_handle_type native_handle() const
{ {
return _raw; return _raw;
} }
/**
* @brief Get the number of hardware concurrent threads.
* @return A hint on the number of hardware concurrent threads, or
* @c 0 if the value is not well defined or not computable.
*
* This static member function returns the number of hardware
* concurrent threads.
*
* @note The interpretation of this value is implementation-specific,
* and may be just an approximation.
*/
static unsigned hardware_concurrency() noexcept static unsigned hardware_concurrency() noexcept
{ {
return ::eina_cpu_count(); return ::eina_cpu_count();
} }
private: private:
/** @internal */
bool _joinable; bool _joinable;
/** @internal */
Eina_Thread _raw; Eina_Thread _raw;
}; };
/**
* @brief Exchanges the underlying handles of two thread objects.
* @param lhs First thread object.
* @param rhs Second thread object.
*/
inline void swap(thread& lhs, thread& rhs) inline void swap(thread& lhs, thread& rhs)
{ {
lhs.swap(rhs); lhs.swap(rhs);
@ -328,22 +721,54 @@ inline void swap(thread& lhs, thread& rhs)
namespace this_thread { namespace this_thread {
/**
* @brief Return identifier of the current thread.
* @return <tt>thread::id</tt> identifying the current thread.
*/
inline thread::id get_id() inline thread::id get_id()
{ {
return thread::id(eina_thread_self()); return thread::id(eina_thread_self());
} }
/**
* @brief Provides a hint to the implementation to reschedule the
* execution of threads, allowing other threads to run.
*/
inline void yield() {} inline void yield() {}
/**
* @brief Block the execution of the current thread until a specified time point.
* @param abs_time Point in time when the calling thread shall resume its execution.
*
* @note This function may block for longer than until after @p rel_time
* has been reached due to scheduling or resource contention delays.
*/
template <typename Clock, typename Duration> template <typename Clock, typename Duration>
void sleep_until(std::chrono::time_point<Clock, Duration>const& abs_time); void sleep_until(std::chrono::time_point<Clock, Duration>const& abs_time);
/**
* @brief Block the execution of the current thread for a specified time duration.
* @param rel_time Time span after which the calling thread shall resume its execution.
*
* @note This function may block for longer than @p rel_time due to
* scheduling or resource contention delays.
*/
template <typename Rep, typename Period> template <typename Rep, typename Period>
void sleep_for(std::chrono::duration<Rep, Period>const& rel_time); void sleep_for(std::chrono::duration<Rep, Period>const& rel_time);
} }
/**
* @}
*/
} } } }
/**
* @internal
* Specialization of standard @c hash class to specify that a
* <tt>thread_id</tt> object should be handled as a unsigned long
* @{
*/
namespace std { namespace std {
template <typename T> struct hash; template <typename T> struct hash;
@ -352,5 +777,12 @@ struct hash< ::efl::eina::thread_id> : hash<unsigned long>
{}; {};
} }
/**
* @}
*/
/**
* @}
*/
#endif #endif

View File

@ -6,8 +6,20 @@
#include <string> #include <string>
#include <vector> #include <vector>
/**
* @addtogroup Eina_Cxx_Data_Types_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @internal
*
* @{
*/
using std::enable_if; using std::enable_if;
using std::is_integral; using std::is_integral;
using std::is_pod; using std::is_pod;
@ -46,6 +58,14 @@ struct if_ : if_c<U::value, T, F>
{ {
}; };
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif

View File

@ -6,8 +6,27 @@
#include <eina_stringshare.hh> #include <eina_stringshare.hh>
#include <eina_type_traits.hh> #include <eina_type_traits.hh>
/**
* @addtogroup Eina_Cxx_Data_Types_Group
*
* @{
*/
namespace efl { namespace eina { namespace efl { namespace eina {
/**
* @defgroup Eina_Cxx_Value_Group Generic Value Storage
* @ingroup Eina_Cxx_Data_Types_Group
*
* Abstracts generic data storage and access to it in an extensible
* and efficient way.
*
* It is meant for simple data types, providing uniform access, useful
* to exchange data preserving their types.
*
* @{
*/
template <typename T, typename Enable = void> template <typename T, typename Enable = void>
struct _eina_value_traits; struct _eina_value_traits;
@ -17,6 +36,9 @@ struct _eina_value_traits_base;
template <typename T> template <typename T>
struct _eina_value_traits_aux; struct _eina_value_traits_aux;
/**
* @internal
*/
template <typename T> template <typename T>
struct _eina_value_traits_base struct _eina_value_traits_base
{ {
@ -51,6 +73,9 @@ struct _eina_value_traits_base
// Indirection for uint64_t. uint64_t can be a typedef for unsigned // Indirection for uint64_t. uint64_t can be a typedef for unsigned
// long, so we can't specialize on the same template // long, so we can't specialize on the same template
/**
* @internal
*/
template <> template <>
struct _eina_value_traits_aux<uint64_t> struct _eina_value_traits_aux<uint64_t>
: _eina_value_traits_base<uint64_t> : _eina_value_traits_base<uint64_t>
@ -61,11 +86,17 @@ struct _eina_value_traits_aux<uint64_t>
} }
}; };
/**
* @internal
*/
template <typename T, typename Enable> template <typename T, typename Enable>
struct _eina_value_traits : _eina_value_traits_aux<T> struct _eina_value_traits : _eina_value_traits_aux<T>
{ {
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<unsigned char> struct _eina_value_traits<unsigned char>
: _eina_value_traits_base<unsigned char> : _eina_value_traits_base<unsigned char>
@ -76,6 +107,9 @@ struct _eina_value_traits<unsigned char>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<unsigned short> struct _eina_value_traits<unsigned short>
: _eina_value_traits_base<unsigned short> : _eina_value_traits_base<unsigned short>
@ -86,6 +120,9 @@ struct _eina_value_traits<unsigned short>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<unsigned int> struct _eina_value_traits<unsigned int>
: _eina_value_traits_base<unsigned int> : _eina_value_traits_base<unsigned int>
@ -96,6 +133,9 @@ struct _eina_value_traits<unsigned int>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<unsigned long> struct _eina_value_traits<unsigned long>
: _eina_value_traits_base<unsigned long> : _eina_value_traits_base<unsigned long>
@ -106,6 +146,9 @@ struct _eina_value_traits<unsigned long>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<char> struct _eina_value_traits<char>
: _eina_value_traits_base<char> : _eina_value_traits_base<char>
@ -116,6 +159,9 @@ struct _eina_value_traits<char>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<short> struct _eina_value_traits<short>
: _eina_value_traits_base<short> : _eina_value_traits_base<short>
@ -126,6 +172,9 @@ struct _eina_value_traits<short>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<int> struct _eina_value_traits<int>
: _eina_value_traits_base<int> : _eina_value_traits_base<int>
@ -136,6 +185,9 @@ struct _eina_value_traits<int>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<long> struct _eina_value_traits<long>
: _eina_value_traits_base<long> : _eina_value_traits_base<long>
@ -146,6 +198,9 @@ struct _eina_value_traits<long>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<float> struct _eina_value_traits<float>
: _eina_value_traits_base<float> : _eina_value_traits_base<float>
@ -156,6 +211,9 @@ struct _eina_value_traits<float>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<double> struct _eina_value_traits<double>
: _eina_value_traits_base<double> : _eina_value_traits_base<double>
@ -166,6 +224,9 @@ struct _eina_value_traits<double>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<stringshare> struct _eina_value_traits<stringshare>
: _eina_value_traits_base<stringshare> : _eina_value_traits_base<stringshare>
@ -186,6 +247,9 @@ struct _eina_value_traits<stringshare>
} }
}; };
/**
* @internal
*/
template <> template <>
struct _eina_value_traits<std::string> struct _eina_value_traits<std::string>
: _eina_value_traits_base<std::string> : _eina_value_traits_base<std::string>
@ -209,6 +273,9 @@ struct _eina_value_traits<std::string>
} }
}; };
/**
* @internal
*/
template <typename T> template <typename T>
struct _eina_value_traits<T[], typename eina::enable_if<eina::is_pod<T>::value>::type> struct _eina_value_traits<T[], typename eina::enable_if<eina::is_pod<T>::value>::type>
: _eina_value_traits_base<T[]> : _eina_value_traits_base<T[]>
@ -237,8 +304,15 @@ class value;
template <typename T> template <typename T>
T get(value const& v); T get(value const& v);
/**
* Store generic value
*/
class value class value
{ {
/**
* @brief Initialize the <tt>eina::value</tt> with the given argument.
* @param v Argument that the <tt>eina::value</tt> will store.
*/
template <typename T> template <typename T>
void primitive_init(T v) void primitive_init(T v)
{ {
@ -246,67 +320,138 @@ class value
_eina_value_traits<T>::set(_raw, v); _eina_value_traits<T>::set(_raw, v);
} }
public: public:
/**
* @brief Default constructor. Create an empty generic value storage.
*/
value() value()
: _raw(_eina_value_traits<char>::create()) : _raw(_eina_value_traits<char>::create())
{ {
} }
/**
* @brief Create an generic value storage holding the given argument.
* @param v Value to be stored.
*/
template <typename T> template <typename T>
value(T v) value(T v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a @c char value.
* @param v @c char value to be stored.
*/
value(char v) value(char v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a @c short value.
* @param v @c short value to be stored.
*/
value(short v) value(short v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a @c int value.
* @param v @c int value to be stored.
*/
value(int v) value(int v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a @c long value.
* @param v @c long value to be stored.
*/
value(long v) value(long v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a <tt>unsigned char</tt> value.
* @param v <tt>unsigned char</tt> value to be stored.
*/
value(unsigned char v) value(unsigned char v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a <tt>unsigned short</tt> value.
* @param v <tt>unsigned short</tt> value to be stored.
*/
value(unsigned short v) value(unsigned short v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a <tt>unsigned int</tt> value.
* @param v <tt>unsigned int</tt> value to be stored.
*/
value(unsigned int v) value(unsigned int v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a <tt>unsigned long</tt> value.
* @param v <tt>unsigned long</tt> value to be stored.
*/
value(unsigned long v) value(unsigned long v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a @c float value.
* @param v @c float value to be stored.
*/
value(float v) value(float v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Create an generic value storage holding a @c double value.
* @param v @c double value to be stored.
*/
value(double v) value(double v)
{ {
primitive_init(v); primitive_init(v);
} }
/**
* @brief Deallocate stored value.
*/
~value() ~value()
{ {
eina_value_free(_raw); eina_value_free(_raw);
} }
/**
* @brief Copy Constructor. Create an generic value storage holding the same value of @p other.
* @param other Another <tt>eina::value</tt> object.
*/
value(value const& other) value(value const& other)
: _raw(_eina_value_traits<char>::create()) : _raw(_eina_value_traits<char>::create())
{ {
if(!eina_value_copy(const_cast<Eina_Value const*>(other._raw), _raw)) if(!eina_value_copy(const_cast<Eina_Value const*>(other._raw), _raw))
throw eina::system_error(eina::get_error_code()); throw eina::system_error(eina::get_error_code());
} }
/**
* @brief Assignment operator. Replace the current stored value by the value in @p other.
* @param other Another <tt>eina::value</tt> object.
*/
value& operator=(value const& other) value& operator=(value const& other)
{ {
eina_value_flush(_raw); eina_value_flush(_raw);
@ -315,17 +460,41 @@ public:
return *this; return *this;
} }
/**
* @brief Swap stored values with the given <tt>eina::value</tt> object.
* @param other Another <tt>eina::value</tt> object.
*/
void swap(value& other) void swap(value& other)
{ {
std::swap(_raw, other._raw); std::swap(_raw, other._raw);
} }
/**
* @brief Get a handle for the wrapped @c Eina_Value.
* @return Handle for the native @c Eina_Value.
*
* This member function returns the native @c Eina_Value handle that
* is wrapped inside this object.
*
* @warning It is important to take care when using it, since the
* handle will be automatically released upon object destruction.
*/
typedef Eina_Value* native_handle_type; typedef Eina_Value* native_handle_type;
native_handle_type native_handle() const native_handle_type native_handle() const
{ {
return _raw; return _raw;
} }
/**
* Type for a constant pointer to an @c Eina_Value_Type.
* Describes the type of the data being stored.
*/
typedef Eina_Value_Type const* type_info_t; typedef Eina_Value_Type const* type_info_t;
/**
* @brief Get an identifier for the type of the value currently stored.
* @return @c Eina_Value_Type instance or @c NULL if type is invalid.
*/
type_info_t type_info() const type_info_t type_info() const
{ {
return ::eina_value_type_get(_raw); return ::eina_value_type_get(_raw);
@ -333,6 +502,21 @@ public:
private: private:
::Eina_Value* _raw; ::Eina_Value* _raw;
/**
* @brief Get the data stored in the given <tt>eina::value</tt>.
* @param v <tt>eina::value</tt> object.
* @param T Type of the value stored.
* @return Copy of the value stored in @p v.
* @throw <tt>eina::system_error</tt> with error the code
* @c EINA_ERROR_VALUE_FAILED if @p T doesn't match the type of
* the value currently stored. Or <tt>eina::system_error</tt>
* with an internal Eina error code if the operation fails for
* another reason.
*
* This function returns the value stored in @p v. The type of the
* value must be specified via the template parameter @p T, and must
* match the current stored value type.
*/
template <typename T> template <typename T>
friend T get(value const& v) friend T get(value const& v)
{ {
@ -340,17 +524,39 @@ private:
} }
}; };
/**
* @brief Swap the stored values between the given <tt>eina::value</tt> objects.
* @param lhs First <tt>eina::value</tt> object.
* @param rhs Second <tt>eina::value</tt> object.
*/
inline void swap(value& lhs, value& rhs) inline void swap(value& lhs, value& rhs)
{ {
lhs.swap(rhs); lhs.swap(rhs);
} }
/**
* @brief Compare if the stored values are equal.
* @param lhs <tt>eina::value</tt> object at the left side of the expression.
* @param rhs <tt>eina::value</tt> object at the right side of the expression.
* @return @c true if the stored values are of the same type and equals
* in content, @c false otherwise.
*/
inline bool operator==(value const& lhs, value const& rhs) inline bool operator==(value const& lhs, value const& rhs)
{ {
return lhs.type_info() == rhs.type_info() return lhs.type_info() == rhs.type_info()
&& eina_value_compare(lhs.native_handle(), rhs.native_handle()) == 0; && eina_value_compare(lhs.native_handle(), rhs.native_handle()) == 0;
} }
/**
* @brief Less than comparison between two <tt>eina::value</tt> objects.
* @param lhs <tt>eina::value</tt> object at the left side of the expression.
* @param rhs <tt>eina::value</tt> object at the right side of the expression.
* @return For objects holding values of the same type, returns @c true
* if @p lhs value is less than @p rhs value. For objects
* holding values of different types, returns @c true if the
* type identifier of @p lhs comes before the type indentifier
* of @p rhs. Returns @c false in all other cases.
*/
inline bool operator<(value const& lhs, value const& rhs) inline bool operator<(value const& lhs, value const& rhs)
{ {
return std::less<Eina_Value_Type const*>()(lhs.type_info(), rhs.type_info()) return std::less<Eina_Value_Type const*>()(lhs.type_info(), rhs.type_info())
@ -358,6 +564,16 @@ inline bool operator<(value const& lhs, value const& rhs)
&& eina_value_compare(lhs.native_handle(), rhs.native_handle()) < 0); && eina_value_compare(lhs.native_handle(), rhs.native_handle()) < 0);
} }
/**
* @brief More than comparison between two <tt>eina::value</tt> objects.
* @param lhs <tt>eina::value</tt> object at the left side of the expression.
* @param rhs <tt>eina::value</tt> object at the right side of the expression.
* @return For objects holding values of the same type, returns @c true
* if @p lhs value is more than @p rhs value. For objects
* holding values of different types, returns @c true if the
* type identifier of @p lhs comes after the type indentifier
* of @p rhs. Returns @c false in all other cases.
*/
inline bool operator>(value const& lhs, value const& rhs) inline bool operator>(value const& lhs, value const& rhs)
{ {
return std::less<Eina_Value_Type const*>()(rhs.type_info(), lhs.type_info()) return std::less<Eina_Value_Type const*>()(rhs.type_info(), lhs.type_info())
@ -365,21 +581,57 @@ inline bool operator>(value const& lhs, value const& rhs)
&& eina_value_compare(lhs.native_handle(), rhs.native_handle()) > 0); && eina_value_compare(lhs.native_handle(), rhs.native_handle()) > 0);
} }
/**
* @brief Less than or equal comparison between two <tt>eina::value</tt> objects.
* @param lhs <tt>eina::value</tt> object at the left side of the expression.
* @param rhs <tt>eina::value</tt> object at the right side of the expression.
* @return For objects holding values of the same type, returns @c true
* if @p lhs value is less than or equal to @p rhs value. For
* objects holding values of different types, returns @c true if
* the type identifier of @p lhs comes before the type
* indentifier of @p rhs. Returns @c false in all other cases.
*/
inline bool operator<=(value const& lhs, value const& rhs) inline bool operator<=(value const& lhs, value const& rhs)
{ {
return !(lhs > rhs); return !(lhs > rhs);
} }
/**
* @brief More than or equal comparison between two <tt>eina::value</tt> objects.
* @param lhs <tt>eina::value</tt> object at the left side of the expression.
* @param rhs <tt>eina::value</tt> object at the right side of the expression.
* @return For objects holding values of the same type, returns @c true
* if @p lhs value is more than or equal to @p rhs value. For
* objects holding values of different types, returns @c true if
* the type identifier of @p lhs comes after the type
* indentifier of @p rhs. Returns @c false in all other cases.
*/
inline bool operator>=(value const& lhs, value const& rhs) inline bool operator>=(value const& lhs, value const& rhs)
{ {
return !(lhs < rhs); return !(lhs < rhs);
} }
/**
* @brief Compare if the stored values are different.
* @param lhs <tt>eina::value</tt> object at the left side of the expression.
* @param rhs <tt>eina::value</tt> object at the right side of the expression.
* @return @c true if the value types are different or if the value of
* @p lhs is different from the value of @rhs, @c false
* otherwise.
*/
inline bool operator!=(value const& lhs, value const& rhs) inline bool operator!=(value const& lhs, value const& rhs)
{ {
return !(lhs == rhs); return !(lhs == rhs);
} }
/**
* @}
*/
} } } }
/**
* @}
*/
#endif #endif