diff options
author | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-08-15 14:47:16 -0300 |
---|---|---|
committer | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-09-14 00:33:22 -0300 |
commit | 2bdad3f1d66ea3c4b38409eaa8bfa72245dc428b (patch) | |
tree | a60406a7a7d86f508fadabb50f81e3f5d04c09be | |
parent | dbed78ad3ba9f247e64966a8dda6491a781bd240 (diff) | |
download | efl-2bdad3f1d66ea3c4b38409eaa8bfa72245dc428b.tar.gz |
eo-cxx: race for promises
-rw-r--r-- | src/Makefile_Eolian_Cxx.am | 3 | ||||
-rw-r--r-- | src/bindings/cxx/eo_cxx/eo_promise.hh | 197 | ||||
-rw-r--r-- | src/tests/eo_cxx/eo_cxx_test_promise.cc | 549 |
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); } |