diff --git a/src/bindings/cxx/eo_cxx/eo_future.hh b/src/bindings/cxx/eo_cxx/eo_future.hh new file mode 100644 index 0000000000..7154b5f89b --- /dev/null +++ b/src/bindings/cxx/eo_cxx/eo_future.hh @@ -0,0 +1,356 @@ +/// +/// @file eo_future.hh +/// + +#ifndef EFL_CXX_EO_FUTURE_HH +#define EFL_CXX_EO_FUTURE_HH + +#include + +#include +#include + +#include +#include + +#include +#include + +namespace efl { + +template +struct shared_future; + +namespace _impl { + +template +struct wait_state +{ + bool available = false; + bool has_failed = false; + std::mutex mutex; + std::condition_variable cv; + typename std::aligned_storage::type storage; + Eina_Error error; +}; + +static void get_error_cb(void* data, Efl_Event const* event) +{ + struct wait_state<>* wait_state = static_cast*>(data); + Efl_Future_Event_Failure* info = static_cast(event->info); + std::unique_lock l(wait_state->mutex); + wait_state->error = info->error; + wait_state->has_failed = true; + wait_state->available = true; + wait_state->cv.notify_one(); +} + +struct shared_future_common +{ + explicit shared_future_common(Efl_Future* future) + : _future(future) {} + shared_future_common() + : _future(nullptr) {} + ~shared_future_common() + { + if(_future) + efl_unref(_future); + } + shared_future_common(shared_future_common const& future) + : _future(efl_ref(future._future)) + { + } + shared_future_common& operator=(shared_future_common const& other) + { + _self_type tmp(other); + tmp.swap(*this); + return *this; + } + shared_future_common(shared_future_common&& future) + : _future(future._future) + { + future._future = nullptr; + } + shared_future_common& operator=(shared_future_common&& other) + { + other.swap(*this); + return *this; + } + void swap(shared_future_common& other) + { + std::swap(_future, other._future); + } + bool valid() const noexcept + { + return _future != nullptr; + } + void wait() const + { + if(eina_main_loop_is()) + throw std::runtime_error("Deadlock"); + + struct wait_state<> wait_state; + + efl::ecore::main_loop_thread_safe_call_async + ([&] + { + efl_future_then(this->_future, &wait_success, &wait_success, nullptr, &wait_state); + }); + + std::unique_lock lock(wait_state.mutex); + while(!wait_state.available) + wait_state.cv.wait(lock); + } + static void wait_success(void* data, Efl_Event const*) + { + struct wait_state<>* wait_state = static_cast*>(data); + std::unique_lock l(wait_state->mutex); + wait_state->available = true; + wait_state->cv.notify_one(); + } + + typedef Efl_Future* native_handle_type; + native_handle_type native_handle() const noexcept { return _future; } + + typedef shared_future_common _self_type; + Efl_Future* _future; +}; + +template +struct shared_future_1_type : private 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; + + T get() const + { + if(eina_main_loop_is()) + throw std::runtime_error("Deadlock"); + + struct wait_state wait_state; + + efl::ecore::main_loop_thread_safe_call_async + ([&] + { + efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state); + }); + + { + std::unique_lock lock(wait_state.mutex); + while(!wait_state.available) + wait_state.cv.wait(lock); + } + if(wait_state.has_failed) + EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error")); + return *static_cast(static_cast(&wait_state.storage)); + } + + static void get_success(void* data, Efl_Event const* event) + { + struct wait_state* wait_state = static_cast*>(data); + Efl_Future_Event_Success* info = static_cast(event->info); + + std::unique_lock l(wait_state->mutex); + _impl::future_copy_traits::copy(static_cast(static_cast(&wait_state->storage)), info); + wait_state->available = true; + wait_state->cv.notify_one(); + } + + typedef shared_future_1_type _self_type; +}; + +template +struct shared_race_future_1_type : private 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; + + T get() const + { + if(eina_main_loop_is()) + throw std::runtime_error("Deadlock"); + + struct wait_state wait_state; + + efl::ecore::main_loop_thread_safe_call_async + ([&] + { + efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state); + }); + + { + std::unique_lock lock(wait_state.mutex); + while(!wait_state.available) + wait_state.cv.wait(lock); + } + if(wait_state.has_failed) + EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error")); + return *static_cast(static_cast(&wait_state.storage)); + } + + static void get_success(void* data, Efl_Event const* event) + { + struct wait_state* wait_state = static_cast*>(data); + Efl_Future_Event_Success* info = static_cast(event->info); + + std::unique_lock l(wait_state->mutex); + _impl::future_copy_traits::copy_race(static_cast(static_cast(&wait_state->storage)), info); + wait_state->available = true; + wait_state->cv.notify_one(); + } + + typedef shared_future_1_type _self_type; +}; + +template +struct shared_future_varargs_type : private 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; + + typedef std::tuple tuple_type; + + std::tuple get() const + { + if(eina_main_loop_is()) + throw std::runtime_error("Deadlock"); + + struct wait_state wait_state; + + efl::ecore::main_loop_thread_safe_call_async + ([&] + { + efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state); + }); + + { + std::unique_lock lock(wait_state.mutex); + while(!wait_state.available) + wait_state.cv.wait(lock); + } + if(wait_state.has_failed) + EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error")); + return *static_cast(static_cast(&wait_state.storage)); + } + + template + static void read_accessor(Eina_Accessor* accessor + , std::tuple::type...>& storage_tuple + , wait_state* wait_state + , std::false_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); + + _self_type::read_accessor(accessor, storage_tuple, wait_state + , std::integral_constant()); + } + else + { + std::abort(); + // some error + } + } + + template + static void read_accessor_end(std::tuple::type...>& storage_tuple + , wait_state* wait_state + , eina::index_sequence) + { + std::unique_lock l(wait_state->mutex); + + new (&wait_state->storage) tuple_type{(*static_cast::type*> + (static_cast(&std::get(storage_tuple))))...}; + + wait_state->available = true; + wait_state->cv.notify_one(); + } + + template + static void read_accessor(Eina_Accessor* + , std::tuple::type...>& storage_tuple + , wait_state* wait_state + , std::true_type) + { + _self_type::read_accessor_end(storage_tuple, wait_state, eina::make_index_sequence{}); + } + + static void get_success(void* data, Efl_Event const* event) + { + struct wait_state* wait_state = static_cast*>(data); + Efl_Future_Event_Success* info = static_cast(event->info); + + Eina_Accessor* accessor = static_cast(info->value); + std::tuple::type...> storage_tuple; + + _self_type::read_accessor<0u>(accessor, storage_tuple, wait_state, std::false_type()); + } + + typedef shared_future_varargs_type _self_type; +}; + +} + +template +struct shared_future : private std::conditional>::type>, _impl::shared_future_varargs_type>::type +{ + typedef typename std::conditional>::type>, _impl::shared_future_varargs_type>::type _base_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; +}; + +template +struct shared_race_future : private std::conditional>::type>, void>::type +{ + typedef typename std::conditional>::type>, void>::type _base_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; +}; + +namespace _impl { + +template +struct is_race_future : std::false_type {}; + +template +struct is_race_future> : std::true_type {}; + +} + +} + +#endif diff --git a/src/bindings/cxx/eo_cxx/eo_promise.hh b/src/bindings/cxx/eo_cxx/eo_promise.hh index 30acfd4f20..f3b8714329 100644 --- a/src/bindings/cxx/eo_cxx/eo_promise.hh +++ b/src/bindings/cxx/eo_cxx/eo_promise.hh @@ -15,6 +15,7 @@ #include #include +#include namespace efl { @@ -24,264 +25,7 @@ struct shared_future; template struct progress; -namespace _impl { - -template -struct wait_state -{ - bool available = false; - bool has_failed = false; - std::mutex mutex; - std::condition_variable cv; - typename std::aligned_storage::type storage; - Eina_Error error; -}; - -static void get_error_cb(void* data, Efl_Event const* event) -{ - struct wait_state<>* wait_state = static_cast*>(data); - Efl_Future_Event_Failure* info = static_cast(event->info); - std::unique_lock l(wait_state->mutex); - wait_state->error = info->error; - wait_state->has_failed = true; - wait_state->available = true; - wait_state->cv.notify_one(); -} - -struct shared_future_common -{ - explicit shared_future_common(Efl_Future* future) - : _future(future) {} - shared_future_common() - : _future(nullptr) {} - ~shared_future_common() - { - if(_future) - efl_unref(_future); - } - shared_future_common(shared_future_common const& future) - : _future(efl_ref(future._future)) - { - } - shared_future_common& operator=(shared_future_common const& other) - { - _self_type tmp(other); - tmp.swap(*this); - return *this; - } - shared_future_common(shared_future_common&& future) - : _future(future._future) - { - future._future = nullptr; - } - shared_future_common& operator=(shared_future_common&& other) - { - other.swap(*this); - return *this; - } - void swap(shared_future_common& other) - { - std::swap(_future, other._future); - } - bool valid() const noexcept - { - return _future != nullptr; - } - void wait() const - { - if(eina_main_loop_is()) - throw std::runtime_error("Deadlock"); - - struct wait_state<> wait_state; - - efl::ecore::main_loop_thread_safe_call_async - ([&] - { - efl_future_then(this->_future, &wait_success, &wait_success, nullptr, &wait_state); - }); - - std::unique_lock lock(wait_state.mutex); - while(!wait_state.available) - wait_state.cv.wait(lock); - } - static void wait_success(void* data, Efl_Event const*) - { - struct wait_state<>* wait_state = static_cast*>(data); - std::unique_lock l(wait_state->mutex); - wait_state->available = true; - wait_state->cv.notify_one(); - } - - typedef Efl_Future* native_handle_type; - native_handle_type native_handle() const noexcept { return _future; } - - typedef shared_future_common _self_type; - Efl_Future* _future; -}; - -template -struct shared_future_1_type : private 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; - - T get() const - { - if(eina_main_loop_is()) - throw std::runtime_error("Deadlock"); - - struct wait_state wait_state; - - efl::ecore::main_loop_thread_safe_call_async - ([&] - { - efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state); - }); - - { - std::unique_lock lock(wait_state.mutex); - while(!wait_state.available) - wait_state.cv.wait(lock); - } - if(wait_state.has_failed) - EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error")); - return *static_cast(static_cast(&wait_state.storage)); - } - - static void get_success(void* data, Efl_Event const* event) - { - struct wait_state* wait_state = static_cast*>(data); - Efl_Future_Event_Success* info = static_cast(event->info); - - std::unique_lock l(wait_state->mutex); - _impl::future_copy_traits::copy(static_cast(static_cast(&wait_state->storage)), info); - wait_state->available = true; - wait_state->cv.notify_one(); - } - - typedef shared_future_1_type _self_type; -}; - -template -struct shared_future_varargs_type : private 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; - - typedef std::tuple tuple_type; - - std::tuple get() const - { - if(eina_main_loop_is()) - throw std::runtime_error("Deadlock"); - - struct wait_state wait_state; - - efl::ecore::main_loop_thread_safe_call_async - ([&] - { - efl_future_then(this->_future, &get_success, &_impl::get_error_cb, nullptr, &wait_state); - }); - - { - std::unique_lock lock(wait_state.mutex); - while(!wait_state.available) - wait_state.cv.wait(lock); - } - if(wait_state.has_failed) - EFL_CXX_THROW(eina::system_error(eina::error_code(wait_state.error, eina::eina_error_category()), "EFL Eina Error")); - return *static_cast(static_cast(&wait_state.storage)); - } - - template - static void read_accessor(Eina_Accessor* accessor - , std::tuple::type...>& storage_tuple - , wait_state* wait_state - , std::false_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); - - _self_type::read_accessor(accessor, storage_tuple, wait_state - , std::integral_constant()); - } - else - { - std::abort(); - // some error - } - } - - template - static void read_accessor_end(std::tuple::type...>& storage_tuple - , wait_state* wait_state - , eina::index_sequence) - { - std::unique_lock l(wait_state->mutex); - - new (&wait_state->storage) tuple_type{(*static_cast::type*> - (static_cast(&std::get(storage_tuple))))...}; - - wait_state->available = true; - wait_state->cv.notify_one(); - } - - template - static void read_accessor(Eina_Accessor* - , std::tuple::type...>& storage_tuple - , wait_state* wait_state - , std::true_type) - { - _self_type::read_accessor_end(storage_tuple, wait_state, eina::make_index_sequence{}); - } - - static void get_success(void* data, Efl_Event const* event) - { - struct wait_state* wait_state = static_cast*>(data); - Efl_Future_Event_Success* info = static_cast(event->info); - - Eina_Accessor* accessor = static_cast(info->value); - std::tuple::type...> storage_tuple; - - _self_type::read_accessor<0u>(accessor, storage_tuple, wait_state, std::false_type()); - } - - typedef shared_future_varargs_type _self_type; -}; - -} - -template -struct shared_future : private std::conditional>::type>, _impl::shared_future_varargs_type>::type -{ - typedef typename std::conditional>::type>, _impl::shared_future_varargs_type>::type _base_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; -}; - -template +template