forked from enlightenment/efl
eo-cxx: race for promises
This commit is contained in:
parent
dbed78ad3b
commit
2bdad3f1d6
|
@ -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
|
||||
|
||||
|
|
|
@ -13,24 +13,118 @@
|
|||
#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 F, typename A0>
|
||||
struct future_invoke_result_of<F, A0>
|
||||
template <typename...Args>
|
||||
struct all_result_type<shared_future<Args...>>
|
||||
{
|
||||
typedef typename std::result_of<F(A0)>::type type;
|
||||
typedef shared_future<Args...> type;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct future_invoke_result_of<F, void>
|
||||
template <typename...Args1, typename...Args2>
|
||||
struct all_result_type<shared_future<Args1...>, shared_future<Args2...>>
|
||||
{
|
||||
typedef typename std::result_of<F()>::type type;
|
||||
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...Futures>
|
||||
typename all_result_type<Futures...>::type
|
||||
all_impl(Futures const& ... futures)
|
||||
{
|
||||
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 T, typename...Args>
|
||||
struct race_compose_impl;
|
||||
|
||||
template <typename T, typename A0, typename...Args>
|
||||
struct race_compose_impl<T, A0, Args...>
|
||||
{
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue