cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=64c6c63725d96f03baf34b660ca71e13b29078c1

commit 64c6c63725d96f03baf34b660ca71e13b29078c1
Author: Felipe Magno de Almeida <[email protected]>
Date:   Sat May 3 00:52:47 2014 +0200

    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 <[email protected]>
---
 src/Makefile_Eina_Cxx.am                       |   7 +-
 src/bindings/eina_cxx/Eina.hh                  |   2 +
 src/bindings/eina_cxx/eina_integer_sequence.hh |  41 +++++
 src/bindings/eina_cxx/eina_optional.hh         | 199 +++++++++++++++++++++++++
 src/tests/eina_cxx/eina_cxx_suite.cc           |   2 +
 src/tests/eina_cxx/eina_cxx_test_optional.cc   | 142 ++++++++++++++++++
 6 files changed, 391 insertions(+), 2 deletions(-)

diff --git a/src/Makefile_Eina_Cxx.am b/src/Makefile_Eina_Cxx.am
index d82493a..1e32656 100644
--- a/src/Makefile_Eina_Cxx.am
+++ b/src/Makefile_Eina_Cxx.am
@@ -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 \
diff --git a/src/bindings/eina_cxx/Eina.hh b/src/bindings/eina_cxx/Eina.hh
index 37741b6..9ba0ca3 100644
--- a/src/bindings/eina_cxx/Eina.hh
+++ b/src/bindings/eina_cxx/Eina.hh
@@ -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 {
 
diff --git a/src/bindings/eina_cxx/eina_integer_sequence.hh 
b/src/bindings/eina_cxx/eina_integer_sequence.hh
new file mode 100644
index 0000000..4ec1762
--- /dev/null
+++ b/src/bindings/eina_cxx/eina_integer_sequence.hh
@@ -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
diff --git a/src/bindings/eina_cxx/eina_optional.hh 
b/src/bindings/eina_cxx/eina_optional.hh
new file mode 100644
index 0000000..e6d853f
--- /dev/null
+++ b/src/bindings/eina_cxx/eina_optional.hh
@@ -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_
diff --git a/src/tests/eina_cxx/eina_cxx_suite.cc 
b/src/tests/eina_cxx/eina_cxx_suite.cc
index 4ef8a9f..942d539 100644
--- a/src/tests/eina_cxx/eina_cxx_suite.cc
+++ b/src/tests/eina_cxx/eina_cxx_suite.cc
@@ -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 }
diff --git a/src/tests/eina_cxx/eina_cxx_test_optional.cc 
b/src/tests/eina_cxx/eina_cxx_test_optional.cc
new file mode 100644
index 0000000..a809f66
--- /dev/null
+++ b/src/tests/eina_cxx/eina_cxx_test_optional.cc
@@ -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);
+}

-- 


Reply via email to