diff options
author | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-08-17 20:48:24 -0300 |
---|---|---|
committer | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-09-14 00:33:22 -0300 |
commit | 3339f039644243952f98713a99987878a682e1db (patch) | |
tree | ebb287bc09f9d7482a54f190e2a21200be5bd9bf | |
parent | e0b444f95f2831738a307cbf64690d8f3bba63b3 (diff) | |
download | efl-3339f039644243952f98713a99987878a682e1db.tar.gz |
eo-cxx: Add promise type
-rw-r--r-- | src/bindings/cxx/eo_cxx/eo_promise.hh | 374 | ||||
-rw-r--r-- | src/bindings/cxx/eo_cxx/eo_promise_meta.hh | 272 | ||||
-rw-r--r-- | src/tests/eo_cxx/eo_cxx_test_promise.cc | 65 |
3 files changed, 448 insertions, 263 deletions
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 <condition_variable> #include <eina_tuple.hh> +#include <eo_promise_meta.hh> namespace efl { template <typename...Args> struct shared_future; -namespace _impl { - -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...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 T, typename Enabler = void> -struct future_copy_traits -{ - static void copy(T* storage, Efl_Future_Event_Success const* info) - { - eina::copy_from_c_traits<T>::copy_to_unitialized - (storage, info->value); - } -}; - -template <typename...Args> -struct future_copy_traits<eina::variant<Args...>> -{ - template <std::size_t I> - static void copy_impl(eina::variant<Args...>*, void const*, int, std::integral_constant<std::size_t, I> - , std::integral_constant<std::size_t, I>) - { - std::abort(); - } - - template <std::size_t I, std::size_t N> - static void copy_impl(eina::variant<Args...>* storage, void const* value, int index, std::integral_constant<std::size_t, I> - , std::integral_constant<std::size_t, N> max - , typename std::enable_if<I != N>::type* = 0) - { - if(I == index) - { - eina::copy_from_c_traits<eina::variant<Args...>>::copy_to_unitialized - (storage, static_cast<typename std::tuple_element<I, std::tuple<Args...>>::type const*> - (static_cast<void const*>(value))); - } - 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) - { - Efl_Future_Race_Success const* info = static_cast<Efl_Future_Race_Success const*> - (static_cast<void const*>(other_info)); - 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> -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) -{ - 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); - 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; - 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 F> -typename std::enable_if<std::is_same<A0, void>::value>::type -future_invoke(F f, Efl_Event const* event) -{ - Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info); - try - { - f(); - } - catch(...) - { - } -} - -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> -void -future_invoke(F f, Efl_Event const* event) -{ - std::tuple<A0, A1, OtherArgs...>* p = nullptr; - _impl::future_invoke_impl(f, event, p, eina::make_index_sequence<sizeof...(OtherArgs) + 2>{}); -} - -} - template <typename T> struct progress; @@ -609,13 +351,119 @@ race(shared_future<Args1...> future1, shared_future<Args2...> future2, Futures.. { return _impl::race_impl(future1, future2, futures...); } + +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*/) + { + } -template <typename...Args> -struct promise + Efl_Promise* _promise; +}; + +template <typename T> +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<T>::c_type c_type; + c_type* c_value = eina::alloc_to_c_traits<T>::copy_alloc(v); + efl_promise_value_set(this->_promise, c_value, & eina::alloc_to_c_traits<T>::free_alloc); + } + void set_value(T&& v) + { + typedef typename eina::alloc_to_c_traits<T>::c_type c_type; + c_type* c_value = eina::alloc_to_c_traits<T>::copy_alloc(std::move(v)); + efl_promise_value_set(this->_promise, c_value, & eina::alloc_to_c_traits<T>::free_alloc); + } }; - + +template <> +struct promise_1_type<void> : 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 <typename T, typename Progress = void> +struct promise : private _impl::promise_1_type<T> +{ + typedef _impl::promise_1_type<T> _base_type; + using _base_type::_base_type; + using _base_type::set_value; + using _base_type::set_exception; + + shared_future<T> get_future() + { + return shared_future<T>{ ::efl_ref( ::efl_promise_future_get(this->_promise)) }; + } + + void swap(promise<T>& other) + { + _base_type::swap(other); + } +}; + +template <typename...Args> +void swap(promise<Args...>& lhs, promise<Args...>& 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 <typename...Args> +struct shared_future; + +namespace _impl { + +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...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 T, typename Enabler = void> +struct future_copy_traits +{ + static void copy(T* storage, Efl_Future_Event_Success const* info) + { + eina::copy_from_c_traits<T>::copy_to_unitialized + (storage, info->value); + } +}; + +template <typename...Args> +struct future_copy_traits<eina::variant<Args...>> +{ + template <std::size_t I> + static void copy_impl(eina::variant<Args...>*, void const*, int, std::integral_constant<std::size_t, I> + , std::integral_constant<std::size_t, I>) + { + std::abort(); + } + + template <std::size_t I, std::size_t N> + static void copy_impl(eina::variant<Args...>* storage, void const* value, int index, std::integral_constant<std::size_t, I> + , std::integral_constant<std::size_t, N> max + , typename std::enable_if<I != N>::type* = 0) + { + if(I == index) + { + eina::copy_from_c_traits<eina::variant<Args...>>::copy_to_unitialized + (storage, static_cast<typename std::tuple_element<I, std::tuple<Args...>>::type const*> + (static_cast<void const*>(value))); + } + 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) + { + Efl_Future_Race_Success const* info = static_cast<Efl_Future_Race_Success const*> + (static_cast<void const*>(other_info)); + 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> +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) +{ + 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); + 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; + 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 F> +typename std::enable_if<std::is_same<A0, void>::value>::type +future_invoke(F f, Efl_Event const* event) +{ + Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info); + try + { + f(); + } + catch(...) + { + } +} + +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> +void +future_invoke(F f, Efl_Event const* event) +{ + std::tuple<A0, A1, OtherArgs...>* p = nullptr; + _impl::future_invoke_impl(f, event, p, eina::make_index_sequence<sizeof...(OtherArgs) + 2>{}); +} + +} } + +#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 <typename...Args> +void eo_cxx_promise_construct_and_destroy_impl() +{ + ecore_init(); + + { + efl::promise<Args...> promise; + efl::shared_future<Args...> f = promise.get_future(); + } + ecore_shutdown(); +} + +START_TEST(eo_cxx_promise_construct_and_destroy) +{ + eo_cxx_promise_construct_and_destroy_impl<int>(); +} +END_TEST + +template <typename T> +struct test_value_get; + +template <> +struct test_value_get<int> +{ + static int get() { return 5; } +}; + +template <typename T> +void eo_cxx_promise_value_set_impl() +{ + ecore_init(); + + { + efl::promise<T> promise; + efl::shared_future<T> 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<T>::get()); + }); + + T value = f.get(); + ck_assert_int_eq(value, test_value_get<T>::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<int>(); +} +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); } |