eo-cxx: Fix race promises
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>
Wed, 14 Sep 2016 03:33:02 +0000 (00:33 -0300)
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>
Wed, 14 Sep 2016 03:33:22 +0000 (00:33 -0300)
src/bindings/cxx/eo_cxx/eo_future.hh [new file with mode: 0644]
src/bindings/cxx/eo_cxx/eo_promise.hh
src/bindings/cxx/eo_cxx/eo_promise_meta.hh
src/tests/eo_cxx/eo_cxx_test_promise.cc

diff --git a/src/bindings/cxx/eo_cxx/eo_future.hh b/src/bindings/cxx/eo_cxx/eo_future.hh
new file mode 100644 (file)
index 0000000..7154b5f
--- /dev/null
@@ -0,0 +1,356 @@
+///
+/// @file eo_future.hh
+///
+
+#ifndef EFL_CXX_EO_FUTURE_HH
+#define EFL_CXX_EO_FUTURE_HH
+
+#include <Efl.h>
+
+#include <Eina.hh>
+#include <Ecore_Manual.hh>
+
+#include <mutex>
+#include <condition_variable>
+
+#include <eina_tuple.hh>
+#include <eo_promise_meta.hh>
+
+namespace efl {
+
+template <typename...Args>
+struct shared_future;
+
+namespace _impl {
+
+template <typename V = char>
+struct wait_state
+{
+   bool available = false;
+   bool has_failed = false;
+   std::mutex mutex;
+   std::condition_variable cv;
+   typename std::aligned_storage<sizeof(V), alignof(V)>::type storage;
+   Eina_Error error;
+};
+
+static void get_error_cb(void* data, Efl_Event const* event)
+{ 
+   struct wait_state<>* wait_state = static_cast<struct wait_state<>*>(data);
+   Efl_Future_Event_Failure* info = static_cast<Efl_Future_Event_Failure*>(event->info);
+   std::unique_lock<std::mutex> l(wait_state->mutex);
+   wait_state->error = info->error;
+   wait_state->has_failed = true;
+   wait_state->available = true;
+   wait_state->cv.notify_one();
+}
+
+struct shared_future_common
+{
+   explicit shared_future_common(Efl_Future* future)
+     : _future(future) {}
+   shared_future_common()
+     : _future(nullptr) {}
+   ~shared_future_common()
+   {
+      if(_future)
+        efl_unref(_future);
+   }
+   shared_future_common(shared_future_common const& future)
+     : _future(efl_ref(future._future))
+   {
+   }
+   shared_future_common& operator=(shared_future_common const& other)
+   {
+      _self_type tmp(other);
+      tmp.swap(*this);
+      return *this;
+   }
+   shared_future_common(shared_future_common&& future)
+     : _future(future._future)
+   {
+      future._future = nullptr;
+   }
+   shared_future_common& operator=(shared_future_common&& other)
+   {
+      other.swap(*this);
+      return *this;
+   }
+   void swap(shared_future_common& other)
+   {
+      std::swap(_future, other._future);
+   }
+   bool valid() const noexcept
+   {
+      return _future != nullptr;
+   }
+   void wait() const
+   {
+      if(eina_main_loop_is())
+        throw std::runtime_error("Deadlock");
+
+      struct wait_state<> wait_state;
+      
+      efl::ecore::main_loop_thread_safe_call_async
+        ([&]
+         {
+            efl_future_then(this->_future, &wait_success, &wait_success, nullptr, &wait_state);
+         });
+
+      std::unique_lock<std::mutex> lock(wait_state.mutex);
+      while(!wait_state.available)
+        wait_state.cv.wait(lock);
+   }
+   static void wait_success(void* data, Efl_Event const*)
+   {
+      struct wait_state<>* wait_state = static_cast<struct wait_state<>*>(data);
+      std::unique_lock<std::mutex> l(wait_state->mutex);
+      wait_state->available = true;
+      wait_state->cv.notify_one();
+   }
+
+   typedef Efl_Future* native_handle_type;
+   native_handle_type native_handle() const noexcept { return _future; }
+
+   typedef shared_future_common _self_type;
+   Efl_Future* _future;
+};
+  
+template <typename T>
+struct shared_future_1_type : private shared_future_common
+{
+   typedef shared_future_common _base_type;
+
+   using _base_type::_base_type;
+   using _base_type::swap;
+   using _base_type::valid;
+   using _base_type::native_handle;
+   using _base_type::wait;
+   typedef _base_type::native_handle_type native_handle_type;
+
+   T get() const
+   {
+      if(eina_main_loop_is())
+        throw std::runtime_error("Deadlock");
+
+      struct wait_state<T> wait_state;
+
+      efl::ecore::main_loop_thread_safe_call_async
+        ([&]
+         {
+            efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state);
+         });
+
+      {
+        std::unique_lock<std::mutex> lock(wait_state.mutex);
+        while(!wait_state.available)
+          wait_state.cv.wait(lock);
+      }
+      if(wait_state.has_failed)
+        EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error"));
+      return *static_cast<T*>(static_cast<void*>(&wait_state.storage));
+   }
+
+   static void get_success(void* data, Efl_Event const* event)
+   {
+      struct wait_state<T>* wait_state = static_cast<struct wait_state<T>*>(data);
+      Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+
+      std::unique_lock<std::mutex> l(wait_state->mutex);
+      _impl::future_copy_traits<T>::copy(static_cast<T*>(static_cast<void*>(&wait_state->storage)), info);
+      wait_state->available = true;
+      wait_state->cv.notify_one();
+   }
+
+   typedef shared_future_1_type<T> _self_type;
+};
+
+template <typename T>
+struct shared_race_future_1_type : private shared_future_common
+{
+   typedef shared_future_common _base_type;
+
+   using _base_type::_base_type;
+   using _base_type::swap;
+   using _base_type::valid;
+   using _base_type::native_handle;
+   using _base_type::wait;
+   typedef _base_type::native_handle_type native_handle_type;
+
+   T get() const
+   {
+      if(eina_main_loop_is())
+        throw std::runtime_error("Deadlock");
+
+      struct wait_state<T> wait_state;
+
+      efl::ecore::main_loop_thread_safe_call_async
+        ([&]
+         {
+            efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state);
+         });
+
+      {
+        std::unique_lock<std::mutex> lock(wait_state.mutex);
+        while(!wait_state.available)
+          wait_state.cv.wait(lock);
+      }
+      if(wait_state.has_failed)
+        EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error"));
+      return *static_cast<T*>(static_cast<void*>(&wait_state.storage));
+   }
+
+   static void get_success(void* data, Efl_Event const* event)
+   {
+      struct wait_state<T>* wait_state = static_cast<struct wait_state<T>*>(data);
+      Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+
+      std::unique_lock<std::mutex> l(wait_state->mutex);
+      _impl::future_copy_traits<T>::copy_race(static_cast<T*>(static_cast<void*>(&wait_state->storage)), info);
+      wait_state->available = true;
+      wait_state->cv.notify_one();
+   }
+
+   typedef shared_future_1_type<T> _self_type;
+};
+  
+template <typename...Args>
+struct shared_future_varargs_type : private shared_future_common
+{
+   typedef shared_future_common _base_type;
+
+   using _base_type::_base_type;
+   using _base_type::swap;
+   using _base_type::valid;
+   using _base_type::native_handle;
+   using _base_type::wait;
+   typedef _base_type::native_handle_type native_handle_type;
+
+   typedef std::tuple<Args...> tuple_type;
+
+   std::tuple<Args...> get() const
+   {
+      if(eina_main_loop_is())
+        throw std::runtime_error("Deadlock");
+
+      struct wait_state<tuple_type> wait_state;
+
+      efl::ecore::main_loop_thread_safe_call_async
+        ([&]
+         {
+            efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state);
+         });
+
+      {
+        std::unique_lock<std::mutex> lock(wait_state.mutex);
+        while(!wait_state.available)
+          wait_state.cv.wait(lock);
+      }
+      if(wait_state.has_failed)
+        EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error"));
+      return *static_cast<tuple_type*>(static_cast<void*>(&wait_state.storage));
+   }
+
+   template <std::size_t N>
+   static void read_accessor(Eina_Accessor* accessor
+                             , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
+                             , wait_state<tuple_type>* wait_state
+                             , std::false_type)
+   {
+      typedef typename std::tuple_element<N, tuple_type>::type type;
+      void* value;
+      if(eina_accessor_data_get(accessor, N, &value))
+        {
+          eina::copy_from_c_traits<type>::copy_to_unitialized
+            (static_cast<type*>(static_cast<void*>(&std::get<N>(storage_tuple))), value);
+
+          _self_type::read_accessor<N+1>(accessor, storage_tuple, wait_state
+                                         , std::integral_constant<bool, (N+1 == sizeof...(Args))>());
+        }
+      else
+        {
+          std::abort();
+          // some error
+        }
+   }
+
+   template <std::size_t N, std::size_t...I>
+   static void read_accessor_end(std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
+                                 , wait_state<tuple_type>* wait_state
+                                 , eina::index_sequence<I...>)
+   {
+      std::unique_lock<std::mutex> l(wait_state->mutex);
+
+      new (&wait_state->storage) tuple_type{(*static_cast<typename std::tuple_element<I, tuple_type>::type*>
+                                             (static_cast<void*>(&std::get<I>(storage_tuple))))...};
+
+      wait_state->available = true;
+      wait_state->cv.notify_one();
+   }
+  
+   template <std::size_t N>
+   static void read_accessor(Eina_Accessor*
+                             , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
+                             , wait_state<tuple_type>* wait_state
+                             , std::true_type)
+   {
+      _self_type::read_accessor_end<N>(storage_tuple, wait_state, eina::make_index_sequence<sizeof...(Args)>{});
+   }
+  
+   static void get_success(void* data, Efl_Event const* event)
+   {
+      struct wait_state<tuple_type>* wait_state = static_cast<struct wait_state<tuple_type>*>(data);
+      Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+
+      Eina_Accessor* accessor = static_cast<Eina_Accessor*>(info->value);
+      std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...> storage_tuple;
+
+      _self_type::read_accessor<0u>(accessor, storage_tuple, wait_state, std::false_type());
+   }
+  
+   typedef shared_future_varargs_type<Args...> _self_type;
+};
+  
+}
+
+template <typename...Args>
+struct shared_future : private std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type
+{
+   typedef typename std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type _base_type;
+
+   using _base_type::_base_type;
+   using _base_type::swap;
+   using _base_type::valid;
+   using _base_type::get;
+   using _base_type::wait;
+   using _base_type::native_handle;
+   typedef typename _base_type::native_handle_type native_handle_type;
+};
+
+template <typename...Args>
+struct shared_race_future : private std::conditional<sizeof...(Args) == 1, _impl::shared_race_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, void>::type
+{
+   typedef typename std::conditional<sizeof...(Args) == 1, _impl::shared_race_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, void>::type _base_type;
+
+   using _base_type::_base_type;
+   using _base_type::swap;
+   using _base_type::valid;
+   using _base_type::get;
+   using _base_type::wait;
+   using _base_type::native_handle;
+   typedef typename _base_type::native_handle_type native_handle_type;
+};
+
+namespace _impl {
+
+template <typename T>
+struct is_race_future : std::false_type {};
+
+template <typename...Args>
+struct is_race_future<shared_race_future<Args...>> : std::true_type {};
+
+}
+  
+}
+
+#endif
index 30acfd4..f3b8714 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <eina_tuple.hh>
 #include <eo_promise_meta.hh>
+#include <eo_future.hh>
 
 namespace efl {
 
@@ -24,264 +25,7 @@ struct shared_future;
 template <typename T>
 struct progress;
 
-namespace _impl {
-
-template <typename V = char>
-struct wait_state
-{
-   bool available = false;
-   bool has_failed = false;
-   std::mutex mutex;
-   std::condition_variable cv;
-   typename std::aligned_storage<sizeof(V), alignof(V)>::type storage;
-   Eina_Error error;
-};
-
-static void get_error_cb(void* data, Efl_Event const* event)
-{ 
-   struct wait_state<>* wait_state = static_cast<struct wait_state<>*>(data);
-   Efl_Future_Event_Failure* info = static_cast<Efl_Future_Event_Failure*>(event->info);
-   std::unique_lock<std::mutex> l(wait_state->mutex);
-   wait_state->error = info->error;
-   wait_state->has_failed = true;
-   wait_state->available = true;
-   wait_state->cv.notify_one();
-}
-  
-struct shared_future_common
-{
-   explicit shared_future_common(Efl_Future* future)
-     : _future(future) {}
-   shared_future_common()
-     : _future(nullptr) {}
-   ~shared_future_common()
-   {
-      if(_future)
-        efl_unref(_future);
-   }
-   shared_future_common(shared_future_common const& future)
-     : _future(efl_ref(future._future))
-   {
-   }
-   shared_future_common& operator=(shared_future_common const& other)
-   {
-      _self_type tmp(other);
-      tmp.swap(*this);
-      return *this;
-   }
-   shared_future_common(shared_future_common&& future)
-     : _future(future._future)
-   {
-      future._future = nullptr;
-   }
-   shared_future_common& operator=(shared_future_common&& other)
-   {
-      other.swap(*this);
-      return *this;
-   }
-   void swap(shared_future_common& other)
-   {
-      std::swap(_future, other._future);
-   }
-   bool valid() const noexcept
-   {
-      return _future != nullptr;
-   }
-   void wait() const
-   {
-      if(eina_main_loop_is())
-        throw std::runtime_error("Deadlock");
-
-      struct wait_state<> wait_state;
-      
-      efl::ecore::main_loop_thread_safe_call_async
-        ([&]
-         {
-            efl_future_then(this->_future, &wait_success, &wait_success, nullptr, &wait_state);
-         });
-
-      std::unique_lock<std::mutex> lock(wait_state.mutex);
-      while(!wait_state.available)
-        wait_state.cv.wait(lock);
-   }
-   static void wait_success(void* data, Efl_Event const*)
-   {
-      struct wait_state<>* wait_state = static_cast<struct wait_state<>*>(data);
-      std::unique_lock<std::mutex> l(wait_state->mutex);
-      wait_state->available = true;
-      wait_state->cv.notify_one();
-   }
-
-   typedef Efl_Future* native_handle_type;
-   native_handle_type native_handle() const noexcept { return _future; }
-
-   typedef shared_future_common _self_type;
-   Efl_Future* _future;
-};
-  
-template <typename T>
-struct shared_future_1_type : private shared_future_common
-{
-   typedef shared_future_common _base_type;
-
-   using _base_type::_base_type;
-   using _base_type::swap;
-   using _base_type::valid;
-   using _base_type::native_handle;
-   using _base_type::wait;
-   typedef _base_type::native_handle_type native_handle_type;
-
-   T get() const
-   {
-      if(eina_main_loop_is())
-        throw std::runtime_error("Deadlock");
-
-      struct wait_state<T> wait_state;
-
-      efl::ecore::main_loop_thread_safe_call_async
-        ([&]
-         {
-            efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state);
-         });
-
-      {
-        std::unique_lock<std::mutex> lock(wait_state.mutex);
-        while(!wait_state.available)
-          wait_state.cv.wait(lock);
-      }
-      if(wait_state.has_failed)
-        EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error"));
-      return *static_cast<T*>(static_cast<void*>(&wait_state.storage));
-   }
-
-   static void get_success(void* data, Efl_Event const* event)
-   {
-      struct wait_state<T>* wait_state = static_cast<struct wait_state<T>*>(data);
-      Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
-
-      std::unique_lock<std::mutex> l(wait_state->mutex);
-      _impl::future_copy_traits<T>::copy(static_cast<T*>(static_cast<void*>(&wait_state->storage)), info);
-      wait_state->available = true;
-      wait_state->cv.notify_one();
-   }
-
-   typedef shared_future_1_type<T> _self_type;
-};
-
-template <typename...Args>
-struct shared_future_varargs_type : private shared_future_common
-{
-   typedef shared_future_common _base_type;
-
-   using _base_type::_base_type;
-   using _base_type::swap;
-   using _base_type::valid;
-   using _base_type::native_handle;
-   using _base_type::wait;
-   typedef _base_type::native_handle_type native_handle_type;
-
-   typedef std::tuple<Args...> tuple_type;
-
-   std::tuple<Args...> get() const
-   {
-      if(eina_main_loop_is())
-        throw std::runtime_error("Deadlock");
-
-      struct wait_state<tuple_type> wait_state;
-
-      efl::ecore::main_loop_thread_safe_call_async
-        ([&]
-         {
-            efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state);
-         });
-
-      {
-        std::unique_lock<std::mutex> lock(wait_state.mutex);
-        while(!wait_state.available)
-          wait_state.cv.wait(lock);
-      }
-      if(wait_state.has_failed)
-        EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error"));
-      return *static_cast<tuple_type*>(static_cast<void*>(&wait_state.storage));
-   }
-
-   template <std::size_t N>
-   static void read_accessor(Eina_Accessor* accessor
-                             , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
-                             , wait_state<tuple_type>* wait_state
-                             , std::false_type)
-   {
-      typedef typename std::tuple_element<N, tuple_type>::type type;
-      void* value;
-      if(eina_accessor_data_get(accessor, N, &value))
-        {
-          eina::copy_from_c_traits<type>::copy_to_unitialized
-            (static_cast<type*>(static_cast<void*>(&std::get<N>(storage_tuple))), value);
-
-          _self_type::read_accessor<N+1>(accessor, storage_tuple, wait_state
-                                         , std::integral_constant<bool, (N+1 == sizeof...(Args))>());
-        }
-      else
-        {
-          std::abort();
-          // some error
-        }
-   }
-
-   template <std::size_t N, std::size_t...I>
-   static void read_accessor_end(std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
-                                 , wait_state<tuple_type>* wait_state
-                                 , eina::index_sequence<I...>)
-   {
-      std::unique_lock<std::mutex> l(wait_state->mutex);
-
-      new (&wait_state->storage) tuple_type{(*static_cast<typename std::tuple_element<I, tuple_type>::type*>
-                                             (static_cast<void*>(&std::get<I>(storage_tuple))))...};
-
-      wait_state->available = true;
-      wait_state->cv.notify_one();
-   }
-  
-   template <std::size_t N>
-   static void read_accessor(Eina_Accessor*
-                             , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple
-                             , wait_state<tuple_type>* wait_state
-                             , std::true_type)
-   {
-      _self_type::read_accessor_end<N>(storage_tuple, wait_state, eina::make_index_sequence<sizeof...(Args)>{});
-   }
-  
-   static void get_success(void* data, Efl_Event const* event)
-   {
-      struct wait_state<tuple_type>* wait_state = static_cast<struct wait_state<tuple_type>*>(data);
-      Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
-
-      Eina_Accessor* accessor = static_cast<Eina_Accessor*>(info->value);
-      std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...> storage_tuple;
-
-      _self_type::read_accessor<0u>(accessor, storage_tuple, wait_state, std::false_type());
-   }
-  
-   typedef shared_future_varargs_type<Args...> _self_type;
-};
-  
-}
-
-template <typename...Args>
-struct shared_future : private std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type
-{
-   typedef typename std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type _base_type;
-
-   using _base_type::_base_type;
-   using _base_type::swap;
-   using _base_type::valid;
-   using _base_type::get;
-   using _base_type::wait;
-   using _base_type::native_handle;
-   typedef typename _base_type::native_handle_type native_handle_type;
-};
-
-template <typename...Args, typename Success, typename Error>
+template <template <typename...> class Future, typename...Args, typename Success, typename Error>
 shared_future
 <
   typename std::enable_if
@@ -290,13 +34,13 @@ shared_future
     && !std::is_same<void, typename std::result_of<Success(Args...)>::type>::value
     , typename std::result_of<Success(Args...)>::type
   >::type
-> then(shared_future<Args...> future, Success success_cb, Error error_cb)
+> then(Future<Args...> future, Success success_cb, Error error_cb)
 {
   struct private_data
   {
     Success success_cb;
     Error error_cb;
-    shared_future<Args...> future;
+    Future<Args...> future;
   };
   private_data* pdata = new private_data
     {std::move(success_cb), std::move(error_cb), std::move(future)};
@@ -307,7 +51,7 @@ shared_future
        private_data* pdata = static_cast<private_data*>(data);
        try
          {
-           _impl::future_invoke<Args...>(pdata->success_cb, event);
+           _impl::future_invoke<Args...>(pdata->success_cb, event, _impl::is_race_future<Future<Args...>>{});
            // should value_set the next promise
          }
        catch(...)
@@ -331,7 +75,7 @@ shared_future
     = efl_future_then(pdata->future.native_handle(), raw_success_cb, raw_error_cb, nullptr, pdata);
   return shared_future<typename std::result_of<Success(Args...)>::type>{efl_ref(new_future)};
 }
-
+  
 template <typename...Args, typename F>
 void then(shared_future<Args...> future, F function)
 {
index 88f4197..6259428 100644 (file)
@@ -10,6 +10,9 @@ namespace efl {
 template <typename...Args>
 struct shared_future;
 
+template <typename...Args>
+struct shared_race_future;
+
 namespace _impl {
 
 template <typename...Futures>
@@ -47,7 +50,7 @@ struct race_result_type;
 template <typename...Args>
 struct race_result_type<shared_future<Args...>>
 {
-  typedef shared_future<Args...> type;
+  typedef shared_race_future<Args...> type;
 };
 
 template <typename T, typename...Args>
@@ -86,13 +89,13 @@ struct race_variant
 template <typename A0>
 struct race_result_type<shared_future<A0>>
 {
-  typedef shared_future<A0> type;
+  typedef shared_race_future<A0> type;
 };
 
 template <typename A0>
 struct race_result_type<shared_future<eina::variant<A0>>>
 {
-  typedef shared_future<A0> type;
+  typedef shared_race_future<A0> type;
 };
   
 template <typename...Args1, typename...Args2>
@@ -124,6 +127,12 @@ struct future_copy_traits
       eina::copy_from_c_traits<T>::copy_to_unitialized
         (storage, info->value);
    }
+   static void copy_race(T* storage, Efl_Future_Event_Success const* info)
+   {
+      Efl_Future_Race_Success const* race = static_cast<Efl_Future_Race_Success const*>(info->value);
+      eina::copy_from_c_traits<T>::copy_to_unitialized
+        (storage, race->value);
+   }
 };
 
 template <typename...Args>
@@ -150,29 +159,35 @@ struct future_copy_traits<eina::variant<Args...>>
      else
        copy_impl(storage, value, index, std::integral_constant<std::size_t, I+1>{}, max);
    }
-   
    static void copy(eina::variant<Args...>* storage, Efl_Future_Event_Success const* other_info)
    {
+     std::abort();
+   }
+   static void copy_race(eina::variant<Args...>* storage, Efl_Future_Event_Success const* other_info)
+   {
       Efl_Future_Race_Success const* info = static_cast<Efl_Future_Race_Success const*>
-        (static_cast<void const*>(other_info));
+        (static_cast<void const*>(other_info->value));
       copy_impl(storage, info->value, info->index, std::integral_constant<std::size_t, 0ul>{}
                 , std::integral_constant<std::size_t, sizeof...(Args)>{});
    }
 };
   
-template <typename A0, typename F>
+template <typename A0, typename F, bool IsRace>
 typename std::enable_if
 <
   !std::is_same<A0, void>::value
   && !std::is_same<typename std::result_of<F(A0)>::type, void>::value
 >::type
-future_invoke(F f, Efl_Event const* event)
+future_invoke(F f, Efl_Event const* event, std::integral_constant<bool, IsRace> /* is_race */)
 {
    Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
    try
      {
         typename std::aligned_storage<sizeof(A0), alignof(A0)>::type storage;
-        future_copy_traits<A0>::copy(static_cast<A0*>(static_cast<void*>(&storage)), info);
+        if(IsRace)
+          future_copy_traits<A0>::copy_race(static_cast<A0*>(static_cast<void*>(&storage)), info);
+        else
+          future_copy_traits<A0>::copy(static_cast<A0*>(static_cast<void*>(&storage)), info);
         auto r = f(*static_cast<A0*>(static_cast<void*>(&storage)));
         typedef decltype(r) result_type;
         typedef typename eina::alloc_to_c_traits<result_type>::c_type c_type;
@@ -184,9 +199,9 @@ future_invoke(F f, Efl_Event const* event)
      }
 }
 
-template <typename A0, typename F>
+template <typename A0, typename F, bool IsRace>
 typename std::enable_if<std::is_same<A0, void>::value>::type
-future_invoke(F f, Efl_Event const* event)
+future_invoke(F f, Efl_Event const* event, std::integral_constant<bool, IsRace>)
 {
    Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
    try
@@ -230,8 +245,8 @@ static void future_invoke_impl_read_accessor
      }
 }
   
-template <typename F, typename...Args, std::size_t...I>
-void future_invoke_impl(F f, Efl_Event const* event, std::tuple<Args...>* arguments_dummy, eina::index_sequence<I...>)
+template <typename F, typename...Args, std::size_t...I, bool IsRace>
+void future_invoke_impl(F f, Efl_Event const* event, std::tuple<Args...>* arguments_dummy, std::integral_constant<bool, IsRace> race, eina::index_sequence<I...>)
 {
    Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
    try
@@ -259,12 +274,12 @@ void future_invoke_impl(F f, Efl_Event const* event, std::tuple<Args...>* argume
      }
 }
   
-template <typename A0, typename A1, typename...OtherArgs, typename F>
+template <typename A0, typename A1, typename...OtherArgs, typename F, bool IsRace>
 void
-future_invoke(F f, Efl_Event const* event)
+future_invoke(F f, Efl_Event const* event, std::integral_constant<bool, IsRace> race)
 {
   std::tuple<A0, A1, OtherArgs...>* p = nullptr;
-  _impl::future_invoke_impl(f, event, p, eina::make_index_sequence<sizeof...(OtherArgs) + 2>{});
+  _impl::future_invoke_impl(f, event, p, race, eina::make_index_sequence<sizeof...(OtherArgs) + 2>{});
 }
   
 } }
index 4e5cf9a..883229d 100644 (file)
@@ -605,8 +605,8 @@ START_TEST(eo_cxx_future_race_construct_and_destroy)
 
       efl::shared_future<int> future1(efl_ref(f1)), future2(efl_ref(f2));
       efl::shared_future<double> future3(efl_ref(f2));
-      efl::shared_future<int> race1 = race(future1, future2);
-      efl::shared_future<efl::eina::variant<int, double>> race2 = race(future1, future3);
+      efl::shared_race_future<int> race1 = race(future1, future2);
+      efl::shared_race_future<efl::eina::variant<int, double>> race2 = race(future1, future3);
    }
    ecore_shutdown();
 }
@@ -631,7 +631,7 @@ START_TEST(eo_cxx_future_race_wait)
 
       efl::shared_future<int> future1(efl_ref(f1))
         , future2(efl_ref(f2));
-      efl::shared_future<int> future3 = race(future1, future2);
+      efl::shared_race_future<int> future3 = race(future1, future2);
 
       std::thread thread([&]
                          {
@@ -675,7 +675,7 @@ START_TEST(eo_cxx_future_race_get)
       
       efl::shared_future<int> future1(efl_ref(f1))
         , future2(efl_ref(f2));
-      efl::shared_future<int> future3 = race(future1, future2);
+      efl::shared_race_future<int> future3 = race(future1, future2);
 
       std::thread thread([&]
                          {
@@ -720,7 +720,7 @@ START_TEST(eo_cxx_future_race_then_value)
       fail_if(!f2);
 
       efl::shared_future<int> future1(efl_ref(f1)), future2(efl_ref(f2));
-      efl::shared_future<int> future = race(future1, future2);
+      efl::shared_race_future<int> future = race(future1, future2);
       efl::shared_future<int> rfuture;
       
       std::thread thread
@@ -779,7 +779,7 @@ START_TEST(eo_cxx_future_race_variant_get)
       
       efl::shared_future<int> future1(efl_ref(f1));
       efl::shared_future<double> future2(efl_ref(f2));
-      efl::shared_future<efl::eina::variant<int, double>> future3 = race(future1, future2);
+      efl::shared_race_future<efl::eina::variant<int, double>> future3 = race(future1, future2);
 
       std::thread thread([&]
                          {
@@ -826,7 +826,7 @@ START_TEST(eo_cxx_future_race_variant_then_value)
 
       efl::shared_future<int> future1(efl_ref(f1));
       efl::shared_future<double> future2(efl_ref(f2));
-      efl::shared_future<efl::eina::variant<int, double>> future = race(future1, future2);
+      efl::shared_race_future<efl::eina::variant<int, double>> future = race(future1, future2);
       efl::shared_future<int> rfuture;
       
       std::thread thread