diff --git a/src/bindings/cxx/eo_cxx/eo_promise.hh b/src/bindings/cxx/eo_cxx/eo_promise.hh index 7c3741adde..30acfd4f20 100644 --- a/src/bindings/cxx/eo_cxx/eo_promise.hh +++ b/src/bindings/cxx/eo_cxx/eo_promise.hh @@ -1,5 +1,5 @@ /// -/// @file eo_concrete.hh +/// @file eo_promise.hh /// #ifndef EFL_CXX_EO_PROMISE_HH @@ -14,271 +14,13 @@ #include #include +#include namespace efl { template struct shared_future; -namespace _impl { - -template -struct all_result_type; - -template -struct all_result_type> -{ - typedef shared_future type; -}; - -template -struct all_result_type, shared_future> -{ - typedef shared_future type; -}; - -template -struct all_result_type, shared_future, OtherFutures...> -{ - typedef typename all_result_type, OtherFutures...>::type type; -}; - -template -typename all_result_type::type -all_impl(Futures const& ... futures) -{ - Efl_Future* future = ::efl_future_all_internal(futures.native_handle()..., NULL); - return typename all_result_type::type{ ::efl_ref(future)}; -} - -template -struct race_result_type; - -template -struct race_result_type> -{ - typedef shared_future type; -}; - -template -struct race_compose_impl; - -template -struct race_compose_impl -{ - typedef typename std::conditional::value - , typename race_compose_impl::type - , typename race_compose_impl::type, Args...>::type - >::type type; -}; - -template -struct race_compose_impl -{ - typedef T type; -}; - -template -struct variant_from_tuple; - -template -struct variant_from_tuple> -{ - typedef eina::variant type; -}; - -template -struct race_variant -{ - typedef typename variant_from_tuple, Args...>::type>::type type; -}; - -template -struct race_result_type> -{ - typedef shared_future type; -}; - -template -struct race_result_type>> -{ - typedef shared_future type; -}; - -template -struct race_result_type, shared_future> -{ - typedef typename race_result_type::type>>::type type; -}; - -template -struct race_result_type, shared_future, OtherFutures...> -{ - typedef typename race_result_type::type> - , OtherFutures...>::type type; -}; - -template -typename race_result_type::type -race_impl(Futures const& ... futures) -{ - Efl_Future* future = ::efl_future_race_internal(futures.native_handle()..., NULL); - return typename race_result_type::type{ ::efl_ref(future)}; -} - -template -struct future_copy_traits -{ - static void copy(T* storage, Efl_Future_Event_Success const* info) - { - eina::copy_from_c_traits::copy_to_unitialized - (storage, info->value); - } -}; - -template -struct future_copy_traits> -{ - template - static void copy_impl(eina::variant*, void const*, int, std::integral_constant - , std::integral_constant) - { - std::abort(); - } - - template - static void copy_impl(eina::variant* storage, void const* value, int index, std::integral_constant - , std::integral_constant max - , typename std::enable_if::type* = 0) - { - if(I == index) - { - eina::copy_from_c_traits>::copy_to_unitialized - (storage, static_cast>::type const*> - (static_cast(value))); - } - else - copy_impl(storage, value, index, std::integral_constant{}, max); - } - - static void copy(eina::variant* storage, Efl_Future_Event_Success const* other_info) - { - Efl_Future_Race_Success const* info = static_cast - (static_cast(other_info)); - copy_impl(storage, info->value, info->index, std::integral_constant{} - , std::integral_constant{}); - } -}; - -template -typename std::enable_if -< - !std::is_same::value - && !std::is_same::type, void>::value ->::type -future_invoke(F f, Efl_Event const* event) -{ - Efl_Future_Event_Success* info = static_cast(event->info); - try - { - typename std::aligned_storage::type storage; - future_copy_traits::copy(static_cast(static_cast(&storage)), info); - auto r = f(*static_cast(static_cast(&storage))); - typedef decltype(r) result_type; - typedef typename eina::alloc_to_c_traits::c_type c_type; - c_type* c_value = eina::alloc_to_c_traits::copy_alloc(r); - efl_promise_value_set(info->next, c_value, & eina::alloc_to_c_traits::free_alloc); - } - catch(...) - { - } -} - -template -typename std::enable_if::value>::type -future_invoke(F f, Efl_Event const* event) -{ - Efl_Future_Event_Success* info = static_cast(event->info); - try - { - f(); - } - catch(...) - { - } -} - -template -static void future_invoke_impl_read_accessor - (Eina_Accessor*, std::tuple&, std::tuple*, std::true_type) -{ -} - -template -static void future_invoke_impl_read_accessor - (Eina_Accessor* accessor - , std::tuple& storage_tuple - , std::tuple* args - , std::false_type) -{ - typedef std::tuple tuple_type; - typedef typename std::tuple_element::type type; - void* value; - if(eina_accessor_data_get(accessor, N, &value)) - { - eina::copy_from_c_traits::copy_to_unitialized - (static_cast(static_cast(&std::get(storage_tuple))), value); - - _impl::future_invoke_impl_read_accessor - (accessor, storage_tuple, args - , std::integral_constant()); - } - else - { - std::abort(); - // some error - } -} - -template -void future_invoke_impl(F f, Efl_Event const* event, std::tuple* arguments_dummy, eina::index_sequence) -{ - Efl_Future_Event_Success* info = static_cast(event->info); - try - { - typedef std::tuple arguments; - typedef std::tuple::type...> - storage_tuple_type; - storage_tuple_type storage_tuple; - - future_invoke_impl_read_accessor<0ul> - (static_cast(info->value) - , storage_tuple - , arguments_dummy, std::false_type{}); - - auto r = f(*static_cast::type*> - (static_cast(&std::get(storage_tuple)))...); - - typedef decltype(r) result_type; - typedef typename eina::alloc_to_c_traits::c_type c_type; - c_type* c_value = eina::alloc_to_c_traits::copy_alloc(r); - efl_promise_value_set(info->next, c_value, & eina::alloc_to_c_traits::free_alloc); - } - catch(...) - { - } -} - -template -void -future_invoke(F f, Efl_Event const* event) -{ - std::tuple* p = nullptr; - _impl::future_invoke_impl(f, event, p, eina::make_index_sequence{}); -} - -} - template struct progress; @@ -609,13 +351,119 @@ race(shared_future future1, shared_future future2, Futures.. { return _impl::race_impl(future1, future2, futures...); } - -template -struct promise + +namespace _impl { + +struct promise_common { + explicit promise_common(Efl_Promise* _promise) : _promise(_promise) {} + explicit promise_common(std::nullptr_t) : _promise(nullptr) {} + promise_common() + { + _promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + } + ~promise_common() + { + if(_promise) + ::efl_unref(_promise); + } + promise_common(promise_common const& other) + : _promise( ::efl_ref(other._promise)) + { + } + promise_common(promise_common&& other) + : _promise(nullptr) + { + std::swap(*this, other); + } + promise_common& operator=(promise_common const& other) + { + _promise = ::efl_ref(other._promise); + return *this; + } + promise_common& operator=(promise_common&& other) + { + std::swap(*this, other); + return *this; + } + bool valid() const + { + return _promise != nullptr; + } + void swap(promise_common& other) + { + std::swap(*this, other); + } + void set_exception(std::exception_ptr /*p*/) + { + } + Efl_Promise* _promise; }; - + +template +struct promise_1_type : promise_common +{ + typedef promise_common _base_type; + using _base_type::_base_type; + using _base_type::swap; + using _base_type::set_exception; + + void set_value(T const& v) + { + typedef typename eina::alloc_to_c_traits::c_type c_type; + c_type* c_value = eina::alloc_to_c_traits::copy_alloc(v); + efl_promise_value_set(this->_promise, c_value, & eina::alloc_to_c_traits::free_alloc); + } + void set_value(T&& v) + { + typedef typename eina::alloc_to_c_traits::c_type c_type; + c_type* c_value = eina::alloc_to_c_traits::copy_alloc(std::move(v)); + efl_promise_value_set(this->_promise, c_value, & eina::alloc_to_c_traits::free_alloc); + } +}; + +template <> +struct promise_1_type : promise_common +{ + typedef promise_common _base_type; + using _base_type::_base_type; + using _base_type::swap; + using _base_type::set_exception; + + void set_value() + { + efl_promise_value_set(this->_promise, nullptr, nullptr); + } +}; + +} + +template +struct promise : private _impl::promise_1_type +{ + typedef _impl::promise_1_type _base_type; + using _base_type::_base_type; + using _base_type::set_value; + using _base_type::set_exception; + + shared_future get_future() + { + return shared_future{ ::efl_ref( ::efl_promise_future_get(this->_promise)) }; + } + + void swap(promise& other) + { + _base_type::swap(other); + } +}; + +template +void swap(promise& lhs, promise& rhs) +{ + lhs.swap(rhs); +} + } #endif diff --git a/src/bindings/cxx/eo_cxx/eo_promise_meta.hh b/src/bindings/cxx/eo_cxx/eo_promise_meta.hh new file mode 100644 index 0000000000..88f4197960 --- /dev/null +++ b/src/bindings/cxx/eo_cxx/eo_promise_meta.hh @@ -0,0 +1,272 @@ +/// +/// @file eo_promise_meta.hh +/// + +#ifndef EFL_CXX_EO_PROMISE_META_HH +#define EFL_CXX_EO_PROMISE_META_HH + +namespace efl { + +template +struct shared_future; + +namespace _impl { + +template +struct all_result_type; + +template +struct all_result_type> +{ + typedef shared_future type; +}; + +template +struct all_result_type, shared_future> +{ + typedef shared_future type; +}; + +template +struct all_result_type, shared_future, OtherFutures...> +{ + typedef typename all_result_type, OtherFutures...>::type type; +}; + +template +typename all_result_type::type +all_impl(Futures const& ... futures) +{ + Efl_Future* future = ::efl_future_all_internal(futures.native_handle()..., NULL); + return typename all_result_type::type{ ::efl_ref(future)}; +} + +template +struct race_result_type; + +template +struct race_result_type> +{ + typedef shared_future type; +}; + +template +struct race_compose_impl; + +template +struct race_compose_impl +{ + typedef typename std::conditional::value + , typename race_compose_impl::type + , typename race_compose_impl::type, Args...>::type + >::type type; +}; + +template +struct race_compose_impl +{ + typedef T type; +}; + +template +struct variant_from_tuple; + +template +struct variant_from_tuple> +{ + typedef eina::variant type; +}; + +template +struct race_variant +{ + typedef typename variant_from_tuple, Args...>::type>::type type; +}; + +template +struct race_result_type> +{ + typedef shared_future type; +}; + +template +struct race_result_type>> +{ + typedef shared_future type; +}; + +template +struct race_result_type, shared_future> +{ + typedef typename race_result_type::type>>::type type; +}; + +template +struct race_result_type, shared_future, OtherFutures...> +{ + typedef typename race_result_type::type> + , OtherFutures...>::type type; +}; + +template +typename race_result_type::type +race_impl(Futures const& ... futures) +{ + Efl_Future* future = ::efl_future_race_internal(futures.native_handle()..., NULL); + return typename race_result_type::type{ ::efl_ref(future)}; +} + +template +struct future_copy_traits +{ + static void copy(T* storage, Efl_Future_Event_Success const* info) + { + eina::copy_from_c_traits::copy_to_unitialized + (storage, info->value); + } +}; + +template +struct future_copy_traits> +{ + template + static void copy_impl(eina::variant*, void const*, int, std::integral_constant + , std::integral_constant) + { + std::abort(); + } + + template + static void copy_impl(eina::variant* storage, void const* value, int index, std::integral_constant + , std::integral_constant max + , typename std::enable_if::type* = 0) + { + if(I == index) + { + eina::copy_from_c_traits>::copy_to_unitialized + (storage, static_cast>::type const*> + (static_cast(value))); + } + else + copy_impl(storage, value, index, std::integral_constant{}, max); + } + + static void copy(eina::variant* storage, Efl_Future_Event_Success const* other_info) + { + Efl_Future_Race_Success const* info = static_cast + (static_cast(other_info)); + copy_impl(storage, info->value, info->index, std::integral_constant{} + , std::integral_constant{}); + } +}; + +template +typename std::enable_if +< + !std::is_same::value + && !std::is_same::type, void>::value +>::type +future_invoke(F f, Efl_Event const* event) +{ + Efl_Future_Event_Success* info = static_cast(event->info); + try + { + typename std::aligned_storage::type storage; + future_copy_traits::copy(static_cast(static_cast(&storage)), info); + auto r = f(*static_cast(static_cast(&storage))); + typedef decltype(r) result_type; + typedef typename eina::alloc_to_c_traits::c_type c_type; + c_type* c_value = eina::alloc_to_c_traits::copy_alloc(r); + efl_promise_value_set(info->next, c_value, & eina::alloc_to_c_traits::free_alloc); + } + catch(...) + { + } +} + +template +typename std::enable_if::value>::type +future_invoke(F f, Efl_Event const* event) +{ + Efl_Future_Event_Success* info = static_cast(event->info); + try + { + f(); + } + catch(...) + { + } +} + +template +static void future_invoke_impl_read_accessor + (Eina_Accessor*, std::tuple&, std::tuple*, std::true_type) +{ +} + +template +static void future_invoke_impl_read_accessor + (Eina_Accessor* accessor + , std::tuple& storage_tuple + , std::tuple* args + , std::false_type) +{ + typedef std::tuple tuple_type; + typedef typename std::tuple_element::type type; + void* value; + if(eina_accessor_data_get(accessor, N, &value)) + { + eina::copy_from_c_traits::copy_to_unitialized + (static_cast(static_cast(&std::get(storage_tuple))), value); + + _impl::future_invoke_impl_read_accessor + (accessor, storage_tuple, args + , std::integral_constant()); + } + else + { + std::abort(); + // some error + } +} + +template +void future_invoke_impl(F f, Efl_Event const* event, std::tuple* arguments_dummy, eina::index_sequence) +{ + Efl_Future_Event_Success* info = static_cast(event->info); + try + { + typedef std::tuple arguments; + typedef std::tuple::type...> + storage_tuple_type; + storage_tuple_type storage_tuple; + + future_invoke_impl_read_accessor<0ul> + (static_cast(info->value) + , storage_tuple + , arguments_dummy, std::false_type{}); + + auto r = f(*static_cast::type*> + (static_cast(&std::get(storage_tuple)))...); + + typedef decltype(r) result_type; + typedef typename eina::alloc_to_c_traits::c_type c_type; + c_type* c_value = eina::alloc_to_c_traits::copy_alloc(r); + efl_promise_value_set(info->next, c_value, & eina::alloc_to_c_traits::free_alloc); + } + catch(...) + { + } +} + +template +void +future_invoke(F f, Efl_Event const* event) +{ + std::tuple* p = nullptr; + _impl::future_invoke_impl(f, event, p, eina::make_index_sequence{}); +} + +} } + +#endif diff --git a/src/tests/eo_cxx/eo_cxx_test_promise.cc b/src/tests/eo_cxx/eo_cxx_test_promise.cc index 151b9376e9..4e5cf9a675 100644 --- a/src/tests/eo_cxx/eo_cxx_test_promise.cc +++ b/src/tests/eo_cxx/eo_cxx_test_promise.cc @@ -867,6 +867,68 @@ START_TEST(eo_cxx_future_race_variant_then_value) } END_TEST +template +void eo_cxx_promise_construct_and_destroy_impl() +{ + ecore_init(); + + { + efl::promise promise; + efl::shared_future f = promise.get_future(); + } + ecore_shutdown(); +} + +START_TEST(eo_cxx_promise_construct_and_destroy) +{ + eo_cxx_promise_construct_and_destroy_impl(); +} +END_TEST + +template +struct test_value_get; + +template <> +struct test_value_get +{ + static int get() { return 5; } +}; + +template +void eo_cxx_promise_value_set_impl() +{ + ecore_init(); + + { + efl::promise promise; + efl::shared_future f = promise.get_future(); + + 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 + ([&] + { + promise.set_value(test_value_get::get()); + }); + + T value = f.get(); + ck_assert_int_eq(value, test_value_get::get()); + efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); }); + }); + + ecore_main_loop_begin(); + + thread.join(); + } + ecore_shutdown(); +} + +START_TEST(eo_cxx_promise_value_set) +{ + eo_cxx_promise_value_set_impl(); +} +END_TEST void eo_cxx_test_promise(TCase* tc) @@ -893,4 +955,7 @@ eo_cxx_test_promise(TCase* tc) tcase_add_test(tc, eo_cxx_future_race_variant_get); tcase_add_test(tc, eo_cxx_future_race_variant_then_value); + + tcase_add_test(tc, eo_cxx_promise_construct_and_destroy); + tcase_add_test(tc, eo_cxx_promise_value_set); }