summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-08-15 14:47:16 -0300
committerFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2016-09-14 00:33:22 -0300
commit2bdad3f1d66ea3c4b38409eaa8bfa72245dc428b (patch)
treea60406a7a7d86f508fadabb50f81e3f5d04c09be
parentdbed78ad3ba9f247e64966a8dda6491a781bd240 (diff)
downloadefl-2bdad3f1d66ea3c4b38409eaa8bfa72245dc428b.tar.gz
eo-cxx: race for promises
-rw-r--r--src/Makefile_Eolian_Cxx.am3
-rw-r--r--src/bindings/cxx/eo_cxx/eo_promise.hh197
-rw-r--r--src/tests/eo_cxx/eo_cxx_test_promise.cc549
3 files changed, 730 insertions, 19 deletions
diff --git a/src/Makefile_Eolian_Cxx.am b/src/Makefile_Eolian_Cxx.am
index c142a4b5fa..71a930ef11 100644
--- a/src/Makefile_Eolian_Cxx.am
+++ b/src/Makefile_Eolian_Cxx.am
@@ -45,8 +45,7 @@ lib/eolian_cxx/grammar/sequence.hpp \
lib/eolian_cxx/grammar/string.hpp \
lib/eolian_cxx/grammar/type.hpp \
lib/eolian_cxx/grammar/type_impl.hpp \
-lib/eolian_cxx/grammar/type_traits.hpp \
-lib/eolian_cxx/grammar/variant.hpp
+lib/eolian_cxx/grammar/type_traits.hpp
### Binary
diff --git a/src/bindings/cxx/eo_cxx/eo_promise.hh b/src/bindings/cxx/eo_cxx/eo_promise.hh
index b325d9cd12..f9a32610e8 100644
--- a/src/bindings/cxx/eo_cxx/eo_promise.hh
+++ b/src/bindings/cxx/eo_cxx/eo_promise.hh
@@ -13,25 +13,119 @@
#include <mutex>
#include <condition_variable>
+#include <eina_tuple.hh>
+
namespace efl {
+template <typename...Args>
+struct shared_future;
+
namespace _impl {
-template <typename F, typename...Args>
-struct future_invoke_result_of;
+template <typename...Futures>
+struct all_result_type;
+
+template <typename...Args>
+struct all_result_type<shared_future<Args...>>
+{
+ typedef shared_future<Args...> type;
+};
+
+template <typename...Args1, typename...Args2>
+struct all_result_type<shared_future<Args1...>, shared_future<Args2...>>
+{
+ typedef shared_future<Args1..., Args2...> type;
+};
+
+template <typename...Args1, typename...Args2, typename...OtherFutures>
+struct all_result_type<shared_future<Args1...>, shared_future<Args2...>, OtherFutures...>
+{
+ typedef typename all_result_type<shared_future<Args1..., Args2...>, OtherFutures...>::type type;
+};
-template <typename F, typename A0>
-struct future_invoke_result_of<F, A0>
+template <typename...Futures>
+typename all_result_type<Futures...>::type
+all_impl(Futures const& ... futures)
{
- typedef typename std::result_of<F(A0)>::type type;
+ Efl_Future* future = ::efl_future_all_internal(futures.native_handle()..., NULL);
+ return typename all_result_type<Futures...>::type{ ::efl_ref(future)};
+}
+
+template <typename...Futures>
+struct race_result_type;
+
+template <typename...Args>
+struct race_result_type<shared_future<Args...>>
+{
+ typedef shared_future<Args...> type;
};
-template <typename F>
-struct future_invoke_result_of<F, void>
+template <typename T, typename...Args>
+struct race_compose_impl;
+
+template <typename T, typename A0, typename...Args>
+struct race_compose_impl<T, A0, Args...>
{
- typedef typename std::result_of<F()>::type type;
+ typedef typename std::conditional<eina::_mpl::tuple_contains<A0, T>::value
+ , typename race_compose_impl<T, Args...>::type
+ , typename race_compose_impl<typename eina::_mpl::push_back<T, A0>::type, Args...>::type
+ >::type type;
+};
+
+template <typename T>
+struct race_compose_impl<T>
+{
+ typedef T type;
+};
+
+template <typename T>
+struct variant_from_tuple;
+
+template <typename...Args>
+struct variant_from_tuple<std::tuple<Args...>>
+{
+ typedef eina::variant<Args...> type;
+};
+
+template <typename...Args>
+struct race_variant
+{
+ typedef typename variant_from_tuple<typename race_compose_impl<std::tuple<>, Args...>::type>::type type;
};
+template <typename A0>
+struct race_result_type<shared_future<A0>>
+{
+ typedef shared_future<A0> type;
+};
+
+template <typename A0>
+struct race_result_type<shared_future<eina::variant<A0>>>
+{
+ typedef shared_future<A0> type;
+};
+
+template <typename...Args1, typename...Args2>
+struct race_result_type<shared_future<Args1...>, shared_future<Args2...>>
+{
+ typedef typename race_result_type<shared_future<typename race_variant<Args1..., Args2...>::type>>::type type;
+};
+
+template <typename...Args1, typename...Args2, typename...OtherFutures>
+struct race_result_type<shared_future<Args1...>, shared_future<Args2...>, OtherFutures...>
+{
+ typedef typename race_result_type<shared_future<typename race_variant<Args1..., Args2...>::type>
+ , OtherFutures...>::type type;
+};
+
+template <typename...Futures>
+typename race_result_type<Futures...>::type
+race_impl(Futures const& ... futures)
+{
+ Efl_Future* future = ::efl_future_race_internal(futures.native_handle()..., NULL);
+ return typename race_result_type<Futures...>::type{ ::efl_ref(future)};
+}
+
template <typename A0, typename F>
typename std::enable_if
<
@@ -70,14 +164,74 @@ future_invoke(F f, Efl_Event const* event)
{
}
}
+
+template <std::size_t N, typename...Args, typename...StorageArgs>
+static void future_invoke_impl_read_accessor
+ (Eina_Accessor*, std::tuple<StorageArgs...>&, std::tuple<Args...>*, std::true_type)
+{
+}
+
+template <std::size_t N, typename...Args, typename...StorageArgs>
+static void future_invoke_impl_read_accessor
+ (Eina_Accessor* accessor
+ , std::tuple<StorageArgs...>& storage_tuple
+ , std::tuple<Args...>* args
+ , std::false_type)
+{
+ typedef std::tuple<Args...> tuple_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);
+
+ _impl::future_invoke_impl_read_accessor<N+1>
+ (accessor, storage_tuple, args
+ , std::integral_constant<bool, (N+1 == sizeof...(Args))>());
+ }
+ else
+ {
+ std::abort();
+ // some error
+ }
+}
+
+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...>)
+{
+ Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
+ try
+ {
+ typedef std::tuple<Args...> arguments;
+ typedef std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>
+ storage_tuple_type;
+ storage_tuple_type storage_tuple;
+
+ future_invoke_impl_read_accessor<0ul>
+ (static_cast<Eina_Accessor*>(info->value)
+ , storage_tuple
+ , arguments_dummy, std::false_type{});
+
+ auto r = f(*static_cast<typename std::tuple_element<I, arguments>::type*>
+ (static_cast<void*>(&std::get<I>(storage_tuple)))...);
+
+ typedef decltype(r) result_type;
+ typedef typename eina::alloc_to_c_traits<result_type>::c_type c_type;
+ c_type* c_value = eina::alloc_to_c_traits<result_type>::copy_alloc(r);
+ efl_promise_value_set(info->next, c_value, & eina::alloc_to_c_traits<result_type>::free_alloc);
+ }
+ catch(...)
+ {
+ }
+}
template <typename A0, typename A1, typename...OtherArgs, typename F>
-// typename future_invoke_result_of<F, A0, A1, OtherArgs...>::type
void
future_invoke(F f, Efl_Event const* event)
{
- Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info);
-
+ std::tuple<A0, A1, OtherArgs...>* p = nullptr;
+ _impl::future_invoke_impl(f, event, p, eina::make_index_sequence<sizeof...(OtherArgs) + 2>{});
}
}
@@ -174,9 +328,7 @@ struct shared_future_common
}
typedef Efl_Future* native_handle_type;
- typedef Efl_Future const* const_native_handle_type;
- native_handle_type native_handle() noexcept { return _future; }
- const_native_handle_type native_handle() const noexcept { return _future; }
+ native_handle_type native_handle() const noexcept { return _future; }
typedef shared_future_common _self_type;
Efl_Future* _future;
@@ -282,9 +434,6 @@ struct shared_future_varargs_type : private shared_future_common
eina::copy_from_c_traits<type>::copy_to_unitialized
(static_cast<type*>(static_cast<void*>(&std::get<N>(storage_tuple))), value);
- std::cout << "copied value " << *static_cast<type*>(static_cast<void*>(&std::get<N>(storage_tuple)))
- << std::endl;
-
_self_type::read_accessor<N+1>(accessor, storage_tuple, wait_state
, std::integral_constant<bool, (N+1 == sizeof...(Args))>());
}
@@ -405,6 +554,20 @@ void then(shared_future<Args...> future, F function)
}
+template <typename...Args1, typename...Args2, typename...Futures>
+typename _impl::all_result_type<shared_future<Args1...>, shared_future<Args2...>, Futures...>::type
+all(shared_future<Args1...> future1, shared_future<Args2...> future2, Futures...futures)
+{
+ return _impl::all_impl(future1, future2, futures...);
+}
+
+template <typename...Args1, typename...Args2, typename...Futures>
+typename _impl::race_result_type<shared_future<Args1...>, shared_future<Args2...>, Futures...>::type
+race(shared_future<Args1...> future1, shared_future<Args2...> future2, Futures...futures)
+{
+ return _impl::race_impl(future1, future2, futures...);
+}
+
template <typename...Args>
struct promise
{
diff --git a/src/tests/eo_cxx/eo_cxx_test_promise.cc b/src/tests/eo_cxx/eo_cxx_test_promise.cc
index b3a2b32b31..151b9376e9 100644
--- a/src/tests/eo_cxx/eo_cxx_test_promise.cc
+++ b/src/tests/eo_cxx/eo_cxx_test_promise.cc
@@ -333,6 +333,541 @@ START_TEST(eo_cxx_future_composite_get)
}
END_TEST
+START_TEST(eo_cxx_future_composite_then_value)
+{
+
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ Efl_Future *f3 = efl_future_all(f1, f2);
+ fail_if(!f3);
+
+ efl::shared_future<int, int> future(efl_ref(f3));
+ efl::shared_future<int> rfuture;
+
+ std::thread thread
+ ([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync
+ ([&]
+ {
+ rfuture = then
+ (future, [] (int i1, int i2) -> int
+ {
+ ck_assert_int_eq(i1, 5);
+ ck_assert_int_eq(i2, 42);
+ return 42;
+ }, [] (std::error_code)
+ {
+ throw std::bad_alloc();
+ });
+ });
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, &::free);
+ int* i2 = static_cast<int*>(malloc(sizeof(int)));
+ *i2 = 42;
+ efl_promise_value_set(p2, i2, &::free);
+ });
+
+ int i;
+ i = rfuture.get();
+ ck_assert_int_eq(i, 42);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_all_construct_and_destroy)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ Efl_Future *f3 = efl_future_all(f1, f2);
+ fail_if(!f3);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int, int> future3 = all(future1, future2);
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_all_wait)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future* f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future* f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int, int> future3 = all(future1, future2);
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, & ::free);
+ int* i2 = static_cast<int*>(malloc(sizeof(int)));
+ *i2 = 42;
+ efl_promise_value_set(p2, i2, & ::free);
+ });
+
+ future3.wait();
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_all_get)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int, int> future3 = all(future1, future2);
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, & ::free);
+ int* i2 = static_cast<int*>(malloc(sizeof(int)));
+ *i2 = 42;
+ efl_promise_value_set(p2, i2, & ::free);
+ });
+
+ std::tuple<int, int> tuple = future3.get();
+ ck_assert_int_eq(std::get<0>(tuple), 5);
+ ck_assert_int_eq(std::get<1>(tuple), 42);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_all_then_value)
+{
+
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ efl::shared_future<int> future1(efl_ref(f1)), future2(efl_ref(f2));
+ efl::shared_future<int, int> future = all(future1, future2);
+ efl::shared_future<int> rfuture;
+
+ std::thread thread
+ ([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync
+ ([&]
+ {
+ rfuture = then
+ (future, [] (int i1, int i2) -> int
+ {
+ ck_assert_int_eq(i1, 5);
+ ck_assert_int_eq(i2, 42);
+ return 42;
+ }, [] (std::error_code)
+ {
+ throw std::bad_alloc();
+ });
+ });
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, &::free);
+ int* i2 = static_cast<int*>(malloc(sizeof(int)));
+ *i2 = 42;
+ efl_promise_value_set(p2, i2, &::free);
+ });
+
+ int i;
+ i = rfuture.get();
+ ck_assert_int_eq(i, 42);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+// race
+START_TEST(eo_cxx_future_race_construct_and_destroy)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ 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);
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_race_wait)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future* f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future* f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int> future3 = race(future1, future2);
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, & ::free);
+ });
+
+ future3.wait();
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_race_get)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ efl::shared_future<int> future1(efl_ref(f1))
+ , future2(efl_ref(f2));
+ efl::shared_future<int> future3 = race(future1, future2);
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, & ::free);
+ });
+
+ int value = future3.get();
+ ck_assert_int_eq(value, 5);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_race_then_value)
+{
+
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ 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_future<int> rfuture;
+
+ std::thread thread
+ ([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync
+ ([&]
+ {
+ rfuture = then
+ (future, [] (int i) -> int
+ {
+ ck_assert_int_eq(i, 5);
+ return 42;
+ }, [] (std::error_code)
+ {
+ throw std::bad_alloc();
+ });
+ });
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, &::free);
+ });
+
+ int i;
+ i = rfuture.get();
+ ck_assert_int_eq(i, 42);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_race_variant_get)
+{
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ 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);
+
+ std::thread thread([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync([]{}); // wait for ecore_main_loop_begin() call to start
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, & ::free);
+ });
+
+ efl::eina::variant<int, double> value = future3.get();
+ ck_assert(efl::eina::get<int>(&value) != nullptr);
+ ck_assert_int_eq(efl::eina::get<int>(value), 5);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+START_TEST(eo_cxx_future_race_variant_then_value)
+{
+
+ ecore_init();
+
+ {
+ Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p1);
+
+ Efl_Future *f1 = efl_promise_future_get(p1);
+ fail_if(!f1);
+
+ Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get());
+ fail_if(!p2);
+
+ Efl_Future *f2 = efl_promise_future_get(p2);
+ fail_if(!f2);
+
+ 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_future<int> rfuture;
+
+ std::thread thread
+ ([&]
+ {
+ efl::ecore::main_loop_thread_safe_call_sync
+ ([&]
+ {
+ rfuture = then
+ (future, [] (efl::eina::variant<int, double> v) -> int
+ {
+ ck_assert(efl::eina::get<int>(&v) != nullptr);
+ ck_assert_int_eq(efl::eina::get<int>(v), 5);
+ return 42;
+ }, [] (std::error_code)
+ {
+ throw std::bad_alloc();
+ });
+ });
+ efl::ecore::main_loop_thread_safe_call_async
+ ([&]
+ {
+ int* i1 = static_cast<int*>(malloc(sizeof(int)));
+ *i1 = 5;
+ efl_promise_value_set(p1, i1, &::free);
+ });
+
+ int i;
+ i = rfuture.get();
+ ck_assert_int_eq(i, 42);
+ efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); });
+ });
+
+ ecore_main_loop_begin();
+ thread.join();
+ }
+ ecore_shutdown();
+}
+END_TEST
+
+
void
eo_cxx_test_promise(TCase* tc)
{
@@ -344,4 +879,18 @@ eo_cxx_test_promise(TCase* tc)
tcase_add_test(tc, eo_cxx_future_composite_construct_and_destroy);
tcase_add_test(tc, eo_cxx_future_composite_wait);
tcase_add_test(tc, eo_cxx_future_composite_get);
+ tcase_add_test(tc, eo_cxx_future_composite_then_value);
+
+ tcase_add_test(tc, eo_cxx_future_all_construct_and_destroy);
+ tcase_add_test(tc, eo_cxx_future_all_wait);
+ tcase_add_test(tc, eo_cxx_future_all_get);
+ tcase_add_test(tc, eo_cxx_future_all_then_value);
+
+ tcase_add_test(tc, eo_cxx_future_race_construct_and_destroy);
+ tcase_add_test(tc, eo_cxx_future_race_wait);
+ tcase_add_test(tc, eo_cxx_future_race_get);
+ tcase_add_test(tc, eo_cxx_future_race_then_value);
+
+ tcase_add_test(tc, eo_cxx_future_race_variant_get);
+ tcase_add_test(tc, eo_cxx_future_race_variant_then_value);
}