eina-cxx: add eina_integer_sequence, eina_optional and their tests.

Summary: eina::optional mimics C++14 std::optional behavior and semantics.

Reviewers: felipealmeida, cedric, smohanty, woohyun, raster

CC: cedric

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

Signed-off-by: Cedric Bail <cedric.bail@free.fr>
This commit is contained in:
Felipe Magno de Almeida 2014-05-03 00:52:47 +02:00 committed by Cedric Bail
parent 98efcdcd63
commit 64c6c63725
6 changed files with 391 additions and 2 deletions

View File

@ -1,20 +1,22 @@
### Library
installed_einacxxmainheadersdir = $(includedir)/eina_cxx-@VMAJ@
installed_einacxxmainheadersdir = $(includedir)/eina-cxx-@VMAJ@
dist_installed_einacxxmainheaders_DATA = \
bindings/eina_cxx/Eina.hh
installed_einacxxheadersdir = $(includedir)/eina_cxx-@VMAJ@/eina_cxx
installed_einacxxheadersdir = $(includedir)/eina-cxx-@VMAJ@/eina-cxx
dist_installed_einacxxheaders_DATA = \
bindings/eina_cxx/eina_accessor.hh \
bindings/eina_cxx/eina_clone_allocators.hh \
bindings/eina_cxx/eina_error.hh \
bindings/eina_cxx/eina_inarray.hh \
bindings/eina_cxx/eina_inlist.hh \
bindings/eina_cxx/eina_integer_sequence.hh \
bindings/eina_cxx/eina_iterator.hh \
bindings/eina_cxx/eina_lists_auxiliary.hh \
bindings/eina_cxx/eina_log.hh \
bindings/eina_cxx/eina_optional.hh \
bindings/eina_cxx/eina_ptrarray.hh \
bindings/eina_cxx/eina_ptrlist.hh \
bindings/eina_cxx/eina_range_types.hh \
@ -44,6 +46,7 @@ tests/eina_cxx/eina_cxx_test_stringshare.cc \
tests/eina_cxx/eina_cxx_test_error.cc \
tests/eina_cxx/eina_cxx_test_accessor.cc \
tests/eina_cxx/eina_cxx_test_thread.cc \
tests/eina_cxx/eina_cxx_test_optional.cc \
tests/eina_cxx/eina_cxx_test_value.cc
tests_eina_cxx_eina_cxx_suite_CXXFLAGS = -I$(top_builddir)/src/lib/efl \

View File

@ -13,6 +13,8 @@
#include <eina_value.hh>
#include <eina_ref.hh>
#include <eina_log.hh>
#include <eina_optional.hh>
#include <eina_integer_sequence.hh>
namespace efl { namespace eina {

View File

@ -0,0 +1,41 @@
#ifndef EINA_CXX_EINA_INTEGER_SEQUENCE_HH
#define EINA_CXX_EINA_INTEGER_SEQUENCE_HH
namespace efl { namespace eina {
template <typename T, T... Ints>
struct integer_sequence
{
typedef T value_type;
static constexpr std::size_t size() { return sizeof...(Ints); }
typedef integer_sequence<T, Ints...> type;
};
template<class S1, class S2> struct concat;
template<typename T, T... I1, T... I2>
struct concat<integer_sequence<T, I1...>, integer_sequence<T, I2...> >
: integer_sequence<T, I1..., (sizeof...(I1)+I2)...> {};
template<class S1, class S2>
using Concat = typename concat<S1, S2>::type;
template<typename T, T N> struct gen_seq;
template<typename T, T N> using make_integer_sequence = typename gen_seq<T, N>::type;
template<typename T, T N>
struct gen_seq : Concat<make_integer_sequence<T, N/2>
, make_integer_sequence<T, N - N/2>>{};
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 <std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;
template <std::size_t I>
using make_index_sequence = make_integer_sequence<std::size_t, I>;
} }
#endif

View File

@ -0,0 +1,199 @@
#ifndef EINA_OPTIONAL_HH_
#define EINA_OPTIONAL_HH_
#include <cstddef>
#include <algorithm>
#include <utility>
namespace efl_eina_swap_adl {
template <typename T>
void swap_impl(T& lhs, T& rhs)
{
using namespace std;
swap(lhs, rhs);
}
}
namespace efl { namespace eina {
template <typename T>
void adl_swap(T& lhs, T& rhs)
{
::efl_eina_swap_adl::swap_impl<T>(lhs, rhs);
}
template <typename T>
struct optional
{
typedef optional<T> _self_type;
optional(std::nullptr_t) : engaged(false)
{}
optional() : engaged(false)
{}
optional(T&& other) : engaged(false)
{
_construct(std::move(other));
}
optional(T const& other) : engaged(false)
{
_construct(std::move(other));
}
optional(optional<T> const& other)
: engaged(false)
{
if(other.engaged) _construct(*other);
}
optional(optional<T>&& other)
: engaged(false)
{
_construct(std::move(*other));
other._destroy();
}
_self_type& operator=(optional<T>&& other)
{
_destroy();
engaged = other.engaged;
if(engaged)
_construct(std::move(*other));
other._destroy();
return *this;
}
_self_type& operator=(optional<T>const& other)
{
optional<T> tmp(other);
tmp.swap(*this);
return *this;
}
~optional()
{
_destroy();
}
explicit operator bool() const
{
return is_engaged();
}
bool operator!() const
{
bool b ( *this );
return !b;
}
T* operator->()
{
assert(is_engaged());
return static_cast<T*>(static_cast<void*>(&buffer));
}
T const* operator->() const
{
return const_cast<_self_type&>(*this).operator->();
}
T& operator*() { return get(); }
T const& operator*() const { return get(); }
T& get() { return *this->operator->(); }
T const& get() const { return *this->operator->(); }
void swap(optional<T>& other)
{
if(is_engaged() && other.is_engaged())
{
eina::adl_swap(**this, *other);
}
else if(is_engaged())
{
other._construct(std::move(**this));
_destroy();
}
else if(other.is_engaged())
{
_construct(std::move(*other));
other._destroy();
}
}
bool is_engaged() const
{
return engaged;
}
private:
template <typename U>
void _construct(U&& object)
{
assert(!is_engaged());
new (&buffer) T(std::move(object));
engaged = true;
}
void _destroy()
{
if(is_engaged())
{
static_cast<T*>(static_cast<void*>(&buffer))->~T();
engaged = false;
}
}
typedef typename std::aligned_storage
<sizeof(T),std::alignment_of<T>::value>::type buffer_type;
buffer_type buffer;
bool engaged;
};
template <typename T>
void swap(optional<T>& lhs, optional<T>& rhs)
{
lhs.swap(rhs);
}
template <typename T>
bool operator==(optional<T> const& lhs, optional<T> const& rhs)
{
if(!lhs && !rhs)
return true;
else if(!lhs || !rhs)
return false;
else
return *lhs == *rhs;
}
template <typename T>
bool operator!=(optional<T> const& lhs, optional<T> const& rhs)
{
return !(lhs == rhs);
}
template <typename T>
bool operator<(optional<T> const& lhs, optional<T> const& rhs)
{
if(!lhs && !rhs)
return false;
else if(!lhs)
return true;
else if(!rhs)
return false;
else
return *lhs < *rhs;
}
template <typename T>
bool operator<=(optional<T> const& lhs, optional<T> const& rhs)
{
return lhs < rhs || lhs == rhs;
}
template <typename T>
bool operator>(optional<T> const& lhs, optional<T> const& rhs)
{
return !(lhs <= rhs);
}
template <typename T>
bool operator>=(optional<T> const& lhs, optional<T> const& rhs)
{
return !(lhs < rhs);
}
} } // efl::eina
#endif // EINA_OPTIONAL_HH_

View File

@ -15,6 +15,7 @@ void eina_test_stringshare(TCase* tc);
void eina_test_error(TCase* tc);
void eina_test_accessor(TCase* tc);
void eina_test_thread(TCase* tc);
void eina_test_optional(TCase* tc);
void eina_test_value(TCase* tc);
void eina_test_log(TCase* tc);
@ -35,6 +36,7 @@ static const Eina_Test_Case etc[] = {
{ "Error", eina_test_error },
{ "Accessor", eina_test_accessor },
{ "Thread", eina_test_thread },
{ "Optional", eina_test_optional },
{ "Value", eina_test_value },
{ "Log", eina_test_log },
{ NULL, NULL }

View File

@ -0,0 +1,142 @@
#include "Eina.hh"
#include <algorithm>
#include <check.h>
#include <iostream>
std::size_t nonpod_constructed = 0u
, nonpod_destructed = 0u;
struct nonpod
{
nonpod() { nonpod_constructed++; }
nonpod(nonpod const&) { nonpod_constructed++; }
nonpod(nonpod&&) { nonpod_constructed++; }
~nonpod() { nonpod_destructed++; }
};
START_TEST(eina_cxx_optional_constructors)
{
namespace eina = efl::eina;
eina::eina_init init;
{
eina::optional<int> optional;
ck_assert(!optional);
}
{
eina::optional<int> optional(nullptr);
ck_assert(!optional);
}
{
eina::optional<int> optional(5);
ck_assert(!!optional);
ck_assert(*optional == 5);
}
{
eina::optional<nonpod> optional;
ck_assert(!optional);
ck_assert(::nonpod_constructed == 0u);
}
{
::nonpod object;
eina::optional<nonpod> optional(object);
ck_assert(!!optional);
}
std::cout << "nonpod_constructed " << nonpod_constructed
<< " nonpod_destructed " << nonpod_destructed << std::endl;
ck_assert(::nonpod_constructed == ::nonpod_destructed);
}
END_TEST
START_TEST(eina_cxx_optional_rel_ops)
{
namespace eina = efl::eina;
eina::eina_init init;
eina::optional<int> empty;
eina::optional<int> one(1);
eina::optional<int> two(2);
eina::optional<int> one_again(1);
ck_assert(empty == empty);
ck_assert(one == one);
ck_assert(one == one_again);
ck_assert(one <= one_again);
ck_assert(one >= one_again);
ck_assert(empty < one);
ck_assert(one >= empty);
ck_assert(one > empty);
ck_assert(one < two);
ck_assert(one <= two);
ck_assert(two > one);
ck_assert(two >= one);
ck_assert(!(empty < empty));
ck_assert(!(one < one_again));
ck_assert(empty != one);
ck_assert(!(one != one));
ck_assert(!(one != one_again));
}
END_TEST
START_TEST(eina_cxx_optional_assignment)
{
namespace eina = efl::eina;
eina::eina_init init;
eina::optional<int> a;
eina::optional<int> b(1);
eina::optional<int> c(2);
eina::optional<int> d(1);
assert(!a); assert(b); assert(c); assert(d);
a = a;
ck_assert(a == a);
ck_assert(!a);
assert(!a); assert(b); assert(c); assert(d);
b = a;
ck_assert(b == a);
ck_assert(b != d);
ck_assert(!b);
assert(!a); assert(!b); assert(c); assert(d);
a = d;
ck_assert(a == d);
ck_assert(a != b);
ck_assert(!!a);
ck_assert(*a == 1);
assert(a); assert(!b); assert(c); assert(d);
c = d;
ck_assert(c == d);
ck_assert(c != b);
ck_assert(!!c);
ck_assert(*c == 1);
assert(a); assert(!b); assert(c); assert(d);
}
END_TEST
void
eina_test_optional(TCase* tc)
{
tcase_add_test(tc, eina_cxx_optional_constructors);
tcase_add_test(tc, eina_cxx_optional_rel_ops);
tcase_add_test(tc, eina_cxx_optional_assignment);
}