felipealmeida pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=10293e652055a5e741f3b9f87c14e7919bb2d267
commit 10293e652055a5e741f3b9f87c14e7919bb2d267 Author: Felipe Magno de Almeida <fel...@expertisesolutions.com.br> Date: Tue Sep 20 23:30:13 2016 -0300 eo-cxx: Add progress to future and promise --- src/bindings/cxx/eo_cxx/eo_future.hh | 199 +++++++++++++++++++++++++---- src/bindings/cxx/eo_cxx/eo_promise.hh | 121 ++++-------------- src/bindings/cxx/eo_cxx/eo_promise_meta.hh | 44 +++++++ src/tests/eo_cxx/eo_cxx_test_promise.cc | 40 ++++++ 4 files changed, 285 insertions(+), 119 deletions(-) diff --git a/src/bindings/cxx/eo_cxx/eo_future.hh b/src/bindings/cxx/eo_cxx/eo_future.hh index 7154b5f..fbab965 100644 --- a/src/bindings/cxx/eo_cxx/eo_future.hh +++ b/src/bindings/cxx/eo_cxx/eo_future.hh @@ -116,17 +116,15 @@ struct shared_future_common Efl_Future* _future; }; -template <typename T> -struct shared_future_1_type : private shared_future_common +template <typename T, typename Progress = void> +struct shared_future_1_type : shared_future_common { typedef shared_future_common _base_type; using _base_type::_base_type; - using _base_type::swap; - using _base_type::valid; - using _base_type::native_handle; - using _base_type::wait; - typedef _base_type::native_handle_type native_handle_type; + shared_future_1_type() = default; + shared_future_1_type(shared_future_common const& other) + : _base_type(other) {} T get() const { @@ -162,20 +160,17 @@ struct shared_future_1_type : private shared_future_common wait_state->cv.notify_one(); } - typedef shared_future_1_type<T> _self_type; + typedef shared_future_1_type<T, Progress> _self_type; }; template <typename T> -struct shared_race_future_1_type : private shared_future_common +struct shared_race_future_1_type : shared_future_common { typedef shared_future_common _base_type; using _base_type::_base_type; - using _base_type::swap; - using _base_type::valid; - using _base_type::native_handle; - using _base_type::wait; - typedef _base_type::native_handle_type native_handle_type; + shared_race_future_1_type(_base_type const& other) + : _base_type(other) {} T get() const { @@ -211,20 +206,18 @@ struct shared_race_future_1_type : private shared_future_common wait_state->cv.notify_one(); } - typedef shared_future_1_type<T> _self_type; + typedef shared_race_future_1_type<T> _self_type; }; - + template <typename...Args> -struct shared_future_varargs_type : private shared_future_common +struct shared_future_varargs_type : shared_future_common { typedef shared_future_common _base_type; using _base_type::_base_type; - using _base_type::swap; - using _base_type::valid; - using _base_type::native_handle; - using _base_type::wait; - typedef _base_type::native_handle_type native_handle_type; + shared_future_varargs_type() = default; + shared_future_varargs_type(_base_type const& other) + : _base_type(other) {} typedef std::tuple<Args...> tuple_type; @@ -314,17 +307,59 @@ struct shared_future_varargs_type : private shared_future_common } template <typename...Args> -struct shared_future : private std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type +struct shared_future : private + std::conditional + < + sizeof...(Args) == 1 + , _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type> + , typename std::conditional + <_impl::is_progress<typename std::tuple_element<sizeof...(Args) - 1, std::tuple<Args...>>::type>::value + , typename std::conditional + <sizeof...(Args) == 2 + , _impl::shared_future_1_type<Args...> + , _impl::shared_future_varargs_type<Args...> + >::type + , _impl::shared_future_varargs_type<Args...> + >::type + >::type { - typedef typename std::conditional<sizeof...(Args) == 1, _impl::shared_future_1_type<typename std::tuple_element<0u, std::tuple<Args...>>::type>, _impl::shared_future_varargs_type<Args...>>::type _base_type; - + typedef typename + std::conditional + < + sizeof...(Args) == 1 + , _impl::shared_future_1_type<Args...> + , typename std::conditional + <_impl::is_progress<typename std::tuple_element<sizeof...(Args) - 1, std::tuple<Args...>>::type>::value + , typename std::conditional + <sizeof...(Args) == 2 + , _impl::shared_future_1_type<Args...> + , _impl::shared_future_varargs_type<Args...> + >::type + , _impl::shared_future_varargs_type<Args...> + >::type + >::type + _base_type; + typedef typename _impl::progress_param<Args...>::type progress_param_type; + typedef typename _impl::progress_type<progress_param_type>::type progress_type; + typedef typename _base_type::native_handle_type native_handle_type; using _base_type::_base_type; using _base_type::swap; using _base_type::valid; using _base_type::get; using _base_type::wait; using _base_type::native_handle; - typedef typename _base_type::native_handle_type native_handle_type; + + shared_future() = default; + template <typename...OtherArgs> + shared_future(shared_future<OtherArgs...> const& other + , typename std::enable_if<_impl::is_progress_param_compatible + <progress_param_type, typename _impl::progress_param<OtherArgs...>::type>::value>::type* = nullptr) + : _base_type(static_cast< _impl::shared_future_common const&>(other)) + { + } + + template <typename...OtherArgs> + friend struct shared_future; }; template <typename...Args> @@ -350,7 +385,119 @@ template <typename...Args> struct is_race_future<shared_race_future<Args...>> : std::true_type {}; } + +template <template <typename...> class Future, typename...Args, typename F> +typename std::enable_if +< + !std::is_same<typename Future<Args...>::progress_type, void>::value +>::type on_progress(Future<Args...> future, F function) +{ + struct private_data + { + F progress_cb; + Future<Args...> future; + }; + private_data* pdata = new private_data + {std::move(function), std::move(future)}; + + typedef typename Future<Args...>::progress_type progress_type; + + Efl_Event_Cb raw_progress_cb = + [] (void* data, Efl_Event const* event) + { + private_data* pdata = static_cast<private_data*>(data); + try + { + Efl_Future_Event_Progress const* info = static_cast<Efl_Future_Event_Progress const*>(event->info); + pdata->progress_cb(*static_cast<progress_type const*>(info->progress)); + } + catch(...) + { + // what should happen if progress_cb fails? + } + }; + Efl_Event_Cb raw_delete_cb = + [] (void* data, Efl_Event const*) + { + private_data* pdata = static_cast<private_data*>(data); + delete pdata; + }; + + assert(pdata->future.valid()); + efl_future_then(pdata->future.native_handle(), raw_delete_cb, raw_delete_cb, raw_progress_cb, pdata); +} + +template <template <typename...> class Future, typename...Args, typename Success, typename Error> +shared_future +< + typename std::enable_if + < + !std::is_same<void, typename std::tuple_element<0, std::tuple<Args...>>::type>::value + && !std::is_same<void, typename std::result_of<Success(Args...)>::type>::value + , typename std::result_of<Success(Args...)>::type + >::type +> then(Future<Args...> future, Success success_cb, Error error_cb) +{ + struct private_data + { + Success success_cb; + Error error_cb; + Future<Args...> future; + }; + private_data* pdata = new private_data + {std::move(success_cb), std::move(error_cb), std::move(future)}; + + Efl_Event_Cb raw_success_cb = + [] (void* data, Efl_Event const* event) + { + private_data* pdata = static_cast<private_data*>(data); + try + { + _impl::future_invoke<Args...>(pdata->success_cb, event, _impl::is_race_future<Future<Args...>>{}); + // should value_set the next promise + } + catch(...) + { + // should fail the next promise + } + delete pdata; + }; + Efl_Event_Cb raw_error_cb = + [] (void* data, Efl_Event const* event) + { + private_data* pdata = static_cast<private_data*>(data); + Efl_Future_Event_Failure* info = static_cast<Efl_Future_Event_Failure*>(event->info); + pdata->error_cb(eina::error_code(info->error, eina::eina_error_category())); + // should error the next promise (or should the promise do that for me automatically?) + delete pdata; + }; + + assert(pdata->future.valid()); + Efl_Future* new_future + = efl_future_then(pdata->future.native_handle(), raw_success_cb, raw_error_cb, nullptr, pdata); + return shared_future<typename std::result_of<Success(Args...)>::type>{efl_ref(new_future)}; +} +template <typename...Args, typename F> +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...); +} + } #endif diff --git a/src/bindings/cxx/eo_cxx/eo_promise.hh b/src/bindings/cxx/eo_cxx/eo_promise.hh index f3b8714..943507f 100644 --- a/src/bindings/cxx/eo_cxx/eo_promise.hh +++ b/src/bindings/cxx/eo_cxx/eo_promise.hh @@ -22,80 +22,6 @@ namespace efl { template <typename...Args> struct shared_future; -template <typename T> -struct progress; - -template <template <typename...> class Future, typename...Args, typename Success, typename Error> -shared_future -< - typename std::enable_if - < - !std::is_same<void, typename std::tuple_element<0, std::tuple<Args...>>::type>::value - && !std::is_same<void, typename std::result_of<Success(Args...)>::type>::value - , typename std::result_of<Success(Args...)>::type - >::type -> then(Future<Args...> future, Success success_cb, Error error_cb) -{ - struct private_data - { - Success success_cb; - Error error_cb; - Future<Args...> future; - }; - private_data* pdata = new private_data - {std::move(success_cb), std::move(error_cb), std::move(future)}; - - Efl_Event_Cb raw_success_cb = - [] (void* data, Efl_Event const* event) - { - private_data* pdata = static_cast<private_data*>(data); - try - { - _impl::future_invoke<Args...>(pdata->success_cb, event, _impl::is_race_future<Future<Args...>>{}); - // should value_set the next promise - } - catch(...) - { - // should fail the next promise - } - delete pdata; - }; - Efl_Event_Cb raw_error_cb = - [] (void* data, Efl_Event const* event) - { - private_data* pdata = static_cast<private_data*>(data); - Efl_Future_Event_Failure* info = static_cast<Efl_Future_Event_Failure*>(event->info); - pdata->error_cb(eina::error_code(info->error, eina::eina_error_category())); - // should error the next promise (or should the promise do that for me automatically?) - delete pdata; - }; - - assert(pdata->future.valid()); - Efl_Future* new_future - = efl_future_then(pdata->future.native_handle(), raw_success_cb, raw_error_cb, nullptr, pdata); - return shared_future<typename std::result_of<Success(Args...)>::type>{efl_ref(new_future)}; -} - -template <typename...Args, typename F> -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...); -} - namespace _impl { struct promise_common @@ -144,15 +70,28 @@ struct promise_common Efl_Promise* _promise; }; - -template <typename T> -struct promise_1_type : promise_common + +template <typename P> +struct promise_progress : promise_common { - typedef promise_common _base_type; - using _base_type::_base_type; - using _base_type::swap; - using _base_type::set_exception; + void set_progress(P const& progress) + { + efl_promise_progress_set(this->_promise, &progress); + } +}; + +template <> +struct promise_progress<void> : promise_common +{ + void set_progress() + { + efl_promise_progress_set(this->_promise, nullptr); + } +}; +template <typename T, typename Progress> +struct promise_1_type : promise_progress<Progress> +{ void set_value(T const& v) { typedef typename eina::alloc_to_c_traits<T>::c_type c_type; @@ -167,14 +106,9 @@ struct promise_1_type : promise_common } }; -template <> -struct promise_1_type<void> : promise_common +template <typename Progress> +struct promise_1_type<void, Progress> : promise_progress<Progress> { - 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); @@ -184,19 +118,20 @@ struct promise_1_type<void> : promise_common } template <typename T, typename Progress = void> -struct promise : private _impl::promise_1_type<T> +struct promise : private _impl::promise_1_type<T, Progress> { - typedef _impl::promise_1_type<T> _base_type; + typedef _impl::promise_1_type<T, Progress> _base_type; using _base_type::_base_type; using _base_type::set_value; + using _base_type::set_progress; using _base_type::set_exception; - shared_future<T> get_future() + shared_future<T, progress<Progress>> get_future() { - return shared_future<T>{ ::efl_ref( ::efl_promise_future_get(this->_promise)) }; + return shared_future<T, progress<Progress>>{ ::efl_ref( ::efl_promise_future_get(this->_promise)) }; } - void swap(promise<T>& other) + void swap(promise<T, progress<Progress>>& other) { _base_type::swap(other); } diff --git a/src/bindings/cxx/eo_cxx/eo_promise_meta.hh b/src/bindings/cxx/eo_cxx/eo_promise_meta.hh index 18b37d7..aa2894f 100644 --- a/src/bindings/cxx/eo_cxx/eo_promise_meta.hh +++ b/src/bindings/cxx/eo_cxx/eo_promise_meta.hh @@ -13,8 +13,52 @@ struct shared_future; template <typename...Args> struct shared_race_future; +template <typename T> +struct progress; + namespace _impl { +template <typename T> +struct is_progress : std::false_type {}; + +template <typename T> +struct is_progress<progress<T>> : std::true_type {}; + +template <typename L, typename R> +struct is_progress_param_compatible : std::false_type {}; + +template <typename T> +struct is_progress_param_compatible<T, T> : std::true_type {}; + +template <> +struct is_progress_param_compatible<void, progress<void>> : std::true_type {}; + +template <> +struct is_progress_param_compatible<progress<void>, void> : std::true_type {}; + +template <typename...Args> +struct progress_param : std::conditional + <is_progress<typename std::tuple_element<sizeof...(Args) - 1, std::tuple<Args...>>::type>::value + , typename std::tuple_element<sizeof...(Args) - 1, std::tuple<Args...>>::type + , void> +{ +}; + +template <typename T> +struct progress_type; + +template <typename T> +struct progress_type<progress<T>> +{ + typedef T type; +}; + +template <> +struct progress_type<void> +{ + typedef void type; +}; + template <typename...Futures> struct all_result_type; diff --git a/src/tests/eo_cxx/eo_cxx_test_promise.cc b/src/tests/eo_cxx/eo_cxx_test_promise.cc index 01b45c7..3edc5e8 100644 --- a/src/tests/eo_cxx/eo_cxx_test_promise.cc +++ b/src/tests/eo_cxx/eo_cxx_test_promise.cc @@ -930,6 +930,45 @@ START_TEST(eo_cxx_promise_value_set) } END_TEST +template <typename T> +void eo_cxx_promise_progress_set_impl() +{ + ecore_init(); + + { + efl::promise<int, T> promise; + efl::shared_future<int, efl::progress<T>> f = promise.get_future(); + + on_progress + (f, [&] (T const& value) + { + ck_assert_int_eq(value, test_value_get<T>::get()); + ecore_main_loop_quit(); + }); + + 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_progress(test_value_get<T>::get()); + }); + }); + + ecore_main_loop_begin(); + + thread.join(); + } + ecore_shutdown(); +} + +START_TEST(eo_cxx_promise_progress_set) +{ + eo_cxx_promise_progress_set_impl<int>(); +} +END_TEST + void eo_cxx_test_promise(TCase* tc) { @@ -958,4 +997,5 @@ eo_cxx_test_promise(TCase* tc) tcase_add_test(tc, eo_cxx_promise_construct_and_destroy); tcase_add_test(tc, eo_cxx_promise_value_set); + tcase_add_test(tc, eo_cxx_promise_progress_set); } --