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:
parent
98efcdcd63
commit
64c6c63725
|
@ -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 \
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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 }
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue