forked from enlightenment/efl
eo-cxx: Add progress to future and promise
This commit is contained in:
parent
bed6c84afb
commit
10293e6520
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue