forked from enlightenment/efl
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
|
### Library
|
||||||
|
|
||||||
installed_einacxxmainheadersdir = $(includedir)/eina_cxx-@VMAJ@
|
installed_einacxxmainheadersdir = $(includedir)/eina-cxx-@VMAJ@
|
||||||
dist_installed_einacxxmainheaders_DATA = \
|
dist_installed_einacxxmainheaders_DATA = \
|
||||||
bindings/eina_cxx/Eina.hh
|
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 = \
|
dist_installed_einacxxheaders_DATA = \
|
||||||
bindings/eina_cxx/eina_accessor.hh \
|
bindings/eina_cxx/eina_accessor.hh \
|
||||||
bindings/eina_cxx/eina_clone_allocators.hh \
|
bindings/eina_cxx/eina_clone_allocators.hh \
|
||||||
bindings/eina_cxx/eina_error.hh \
|
bindings/eina_cxx/eina_error.hh \
|
||||||
bindings/eina_cxx/eina_inarray.hh \
|
bindings/eina_cxx/eina_inarray.hh \
|
||||||
bindings/eina_cxx/eina_inlist.hh \
|
bindings/eina_cxx/eina_inlist.hh \
|
||||||
|
bindings/eina_cxx/eina_integer_sequence.hh \
|
||||||
bindings/eina_cxx/eina_iterator.hh \
|
bindings/eina_cxx/eina_iterator.hh \
|
||||||
bindings/eina_cxx/eina_lists_auxiliary.hh \
|
bindings/eina_cxx/eina_lists_auxiliary.hh \
|
||||||
bindings/eina_cxx/eina_log.hh \
|
bindings/eina_cxx/eina_log.hh \
|
||||||
|
bindings/eina_cxx/eina_optional.hh \
|
||||||
bindings/eina_cxx/eina_ptrarray.hh \
|
bindings/eina_cxx/eina_ptrarray.hh \
|
||||||
bindings/eina_cxx/eina_ptrlist.hh \
|
bindings/eina_cxx/eina_ptrlist.hh \
|
||||||
bindings/eina_cxx/eina_range_types.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_error.cc \
|
||||||
tests/eina_cxx/eina_cxx_test_accessor.cc \
|
tests/eina_cxx/eina_cxx_test_accessor.cc \
|
||||||
tests/eina_cxx/eina_cxx_test_thread.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_test_value.cc
|
||||||
|
|
||||||
tests_eina_cxx_eina_cxx_suite_CXXFLAGS = -I$(top_builddir)/src/lib/efl \
|
tests_eina_cxx_eina_cxx_suite_CXXFLAGS = -I$(top_builddir)/src/lib/efl \
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include <eina_value.hh>
|
#include <eina_value.hh>
|
||||||
#include <eina_ref.hh>
|
#include <eina_ref.hh>
|
||||||
#include <eina_log.hh>
|
#include <eina_log.hh>
|
||||||
|
#include <eina_optional.hh>
|
||||||
|
#include <eina_integer_sequence.hh>
|
||||||
|
|
||||||
namespace efl { namespace eina {
|
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_error(TCase* tc);
|
||||||
void eina_test_accessor(TCase* tc);
|
void eina_test_accessor(TCase* tc);
|
||||||
void eina_test_thread(TCase* tc);
|
void eina_test_thread(TCase* tc);
|
||||||
|
void eina_test_optional(TCase* tc);
|
||||||
void eina_test_value(TCase* tc);
|
void eina_test_value(TCase* tc);
|
||||||
void eina_test_log(TCase* tc);
|
void eina_test_log(TCase* tc);
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ static const Eina_Test_Case etc[] = {
|
||||||
{ "Error", eina_test_error },
|
{ "Error", eina_test_error },
|
||||||
{ "Accessor", eina_test_accessor },
|
{ "Accessor", eina_test_accessor },
|
||||||
{ "Thread", eina_test_thread },
|
{ "Thread", eina_test_thread },
|
||||||
|
{ "Optional", eina_test_optional },
|
||||||
{ "Value", eina_test_value },
|
{ "Value", eina_test_value },
|
||||||
{ "Log", eina_test_log },
|
{ "Log", eina_test_log },
|
||||||
{ NULL, NULL }
|
{ 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