diff options
author | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-08-07 16:52:48 -0300 |
---|---|---|
committer | Felipe Magno de Almeida <felipe@expertisesolutions.com.br> | 2016-09-11 23:44:05 -0300 |
commit | a63cfcafc7f8524dfad4e1bba763fb17c69d50e1 (patch) | |
tree | adc59470b9cb5f6458351842bcc82de523dec247 /src/bindings | |
parent | 98229bc5d6cf1ebe11af4bb05a32f2a30b470f6e (diff) | |
download | efl-a63cfcafc7f8524dfad4e1bba763fb17c69d50e1.tar.gz |
eolian-cxx: Implement future template class for C++
Diffstat (limited to 'src/bindings')
-rw-r--r-- | src/bindings/cxx/ecore_cxx/Ecore.hh | 164 | ||||
-rw-r--r-- | src/bindings/cxx/ecore_cxx/Ecore_Manual.hh | 176 | ||||
-rw-r--r-- | src/bindings/cxx/eina_cxx/Eina.hh | 1 | ||||
-rw-r--r-- | src/bindings/cxx/eina_cxx/eina_copy_traits.hh | 43 | ||||
-rw-r--r-- | src/bindings/cxx/eo_cxx/Eo.hh | 3 | ||||
-rw-r--r-- | src/bindings/cxx/eo_cxx/eo_cxx_interop.hh | 34 | ||||
-rw-r--r-- | src/bindings/cxx/eo_cxx/eo_promise.hh | 416 |
7 files changed, 664 insertions, 173 deletions
diff --git a/src/bindings/cxx/ecore_cxx/Ecore.hh b/src/bindings/cxx/ecore_cxx/Ecore.hh index 75ebc3e26a..bd2cd7e40a 100644 --- a/src/bindings/cxx/ecore_cxx/Ecore.hh +++ b/src/bindings/cxx/ecore_cxx/Ecore.hh @@ -13,168 +13,6 @@ #ifdef EFL_BETA_API_SUPPORT #include <Ecore.eo.hh> #endif - -namespace efl { namespace ecore { - -template <typename T> -struct _identity -{ - typedef T type; -}; - -template <typename F> -void _ecore_main_loop_thread_safe_call_async_callback(void* data) -{ - std::unique_ptr<F> f (static_cast<F*>(data)); - try - { - (*f)(); - } - catch(std::bad_alloc const& e) - { - eina_error_set(ENOMEM); - } - catch(std::system_error const& e) - { - efl::eina::set_error_code(e.code()); - } - catch(...) - { - eina_error_set( efl::eina::unknown_error() ); - } -} - -template <typename T> -struct _return_buffer -{ - typename std::aligned_storage<sizeof(T),std::alignment_of<T>::value>::type buffer; -}; - -template <> -struct _return_buffer<void> -{ -}; - -template <typename F> -struct _data -{ - F& f; - std::exception_ptr exception; - typedef typename std::result_of<F()>::type result_type; - _return_buffer<result_type> return_buffer; -}; - -template <typename F> -void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<void>) -{ - d->f(); - if(eina_error_get()) - d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code())); - return 0; -} - -template <typename F, typename R> -void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<R>) -{ - typedef R result_type; - new (&d->return_buffer.buffer) result_type ( std::move(d->f()) ); - if(eina_error_get()) - { - d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code())); - eina_error_set(0); - result_type* p = static_cast<result_type*>(static_cast<void*>(&d->return_buffer.buffer)); - p->~result_type(); - } - return 0; -} - -template <typename F> -void* _ecore_main_loop_thread_safe_call_sync_callback(void* data) -{ - _data<F>* d = static_cast<_data<F>*>(data); - try - { - return _ecore_main_loop_thread_safe_call_sync_callback_aux - (d, _identity<typename std::result_of<F()>::type>()); - } - catch(std::bad_alloc const& e) - { - d->exception = std::current_exception(); - } - catch(std::system_error const& e) - { - d->exception = std::current_exception(); - } - catch(...) - { - d->exception = std::current_exception(); - } - return 0; -} - -template <typename F> -void main_loop_thread_safe_call_async(F&& f) -{ - ::ecore_main_loop_thread_safe_call_async( &ecore::_ecore_main_loop_thread_safe_call_async_callback<F> - , new F(std::forward<F>(f)) ); -} - -template <typename F> -void _get_return_value(_data<F>& data, _identity<void>) -{ - if(data.exception) - { - std::rethrow_exception(data.exception); - } -} - -template <typename F, typename R> -R _get_return_value(_data<F>& data, _identity<R>) -{ - if(!data.exception) - { - R* b_ = static_cast<R*>(static_cast<void*>(&data.return_buffer.buffer)); - struct destroy - { - destroy(R* x_) : p_(x_) - {} - ~destroy() - { - p_->~R(); - } - R* p_; - } destroy_temp(b_); - return std::move(*b_); - } - else - { - std::rethrow_exception(data.exception); - } -} - -template <typename F> -typename std::result_of<F()>::type -main_loop_thread_safe_call_sync(F&& f) -{ - typedef typename std::result_of<F()>::type result_type; - _data<F> data {f, nullptr, {}}; - ::ecore_main_loop_thread_safe_call_sync - (&ecore::_ecore_main_loop_thread_safe_call_sync_callback<F>, &data); - return _get_return_value(data, _identity<result_type>()); -} - -struct ecore_init -{ - ecore_init() - { - ::ecore_init(); - } - ~ecore_init() - { - ::ecore_shutdown(); - } -}; - -} } +#include <Ecore_Manual.hh> #endif diff --git a/src/bindings/cxx/ecore_cxx/Ecore_Manual.hh b/src/bindings/cxx/ecore_cxx/Ecore_Manual.hh new file mode 100644 index 0000000000..4bc90629a3 --- /dev/null +++ b/src/bindings/cxx/ecore_cxx/Ecore_Manual.hh @@ -0,0 +1,176 @@ +#ifndef _EFL_ECORE_CXX_ECORE_MANUAL_HH +#define _EFL_ECORE_CXX_ECORE_MANUAL_HH + +#include <Ecore.h> + +#include <Eina.hh> + +#include <utility> +#include <type_traits> +#include <memory> +#include <cstring> + +namespace efl { namespace ecore { + +template <typename T> +struct _identity +{ + typedef T type; +}; + +template <typename F> +void _ecore_main_loop_thread_safe_call_async_callback(void* data) +{ + std::unique_ptr<F> f (static_cast<F*>(data)); + try + { + (*f)(); + } + catch(std::bad_alloc const& e) + { + eina_error_set( ::EINA_ERROR_OUT_OF_MEMORY); + } + catch(std::system_error const& e) + { + efl::eina::set_error_code(e.code()); + } + catch(...) + { + eina_error_set( efl::eina::unknown_error() ); + } +} + +template <typename T> +struct _return_buffer +{ + typename std::aligned_storage<sizeof(T),std::alignment_of<T>::value>::type buffer; +}; + +template <> +struct _return_buffer<void> +{ +}; + +template <typename F> +struct _data +{ + F& f; + std::exception_ptr exception; + typedef typename std::result_of<F()>::type result_type; + _return_buffer<result_type> return_buffer; +}; + +template <typename F> +void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<void>) +{ + d->f(); + if(eina_error_get()) + d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code())); + return 0; +} + +template <typename F, typename R> +void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, _identity<R>) +{ + typedef R result_type; + new (&d->return_buffer.buffer) result_type ( std::move(d->f()) ); + if(eina_error_get()) + { + d->exception = make_exception_ptr(std::system_error(efl::eina::get_error_code())); + eina_error_set(0); + result_type* p = static_cast<result_type*>(static_cast<void*>(&d->return_buffer.buffer)); + p->~result_type(); + } + return 0; +} + +template <typename F> +void* _ecore_main_loop_thread_safe_call_sync_callback(void* data) +{ + _data<F>* d = static_cast<_data<F>*>(data); + try + { + return _ecore_main_loop_thread_safe_call_sync_callback_aux + (d, _identity<typename std::result_of<F()>::type>()); + } + catch(std::bad_alloc const& e) + { + d->exception = std::current_exception(); + } + catch(std::system_error const& e) + { + d->exception = std::current_exception(); + } + catch(...) + { + d->exception = std::current_exception(); + } + return 0; +} + +template <typename F> +void main_loop_thread_safe_call_async(F&& f) +{ + ::ecore_main_loop_thread_safe_call_async( &ecore::_ecore_main_loop_thread_safe_call_async_callback<F> + , new F(std::forward<F>(f)) ); +} + +template <typename F> +void _get_return_value(_data<F>& data, _identity<void>) +{ + if(data.exception) + { + std::rethrow_exception(data.exception); + } +} + +template <typename F, typename R> +R _get_return_value(_data<F>& data, _identity<R>) +{ + if(!data.exception) + { + R* b_ = static_cast<R*>(static_cast<void*>(&data.return_buffer.buffer)); + struct destroy + { + destroy(R* x_) : p_(x_) + {} + ~destroy() + { + p_->~R(); + } + R* p_; + } destroy_temp(b_); + return std::move(*b_); + } + else + { + std::rethrow_exception(data.exception); + } +} + +template <typename F> +typename std::result_of<F()>::type +main_loop_thread_safe_call_sync(F&& f) +{ + typedef typename std::result_of<F()>::type result_type; + _data<F> data {f, nullptr, {}}; + ::ecore_main_loop_thread_safe_call_sync + (&ecore::_ecore_main_loop_thread_safe_call_sync_callback<F>, &data); + return _get_return_value(data, _identity<result_type>()); +} + +struct ecore_init +{ + ecore_init() + { + ::ecore_init(); + } + ~ecore_init() + { + ::ecore_shutdown(); + } +}; + +} } + +#endif diff --git a/src/bindings/cxx/eina_cxx/Eina.hh b/src/bindings/cxx/eina_cxx/Eina.hh index c98681551d..f613415064 100644 --- a/src/bindings/cxx/eina_cxx/Eina.hh +++ b/src/bindings/cxx/eina_cxx/Eina.hh @@ -26,6 +26,7 @@ #include <eina_workarounds.hh> #include <eina_future.hh> #include <eina_deleter.hh> +#include <eina_copy_traits.hh> /** * @page eina_cxx_main Eina C++ (BETA) diff --git a/src/bindings/cxx/eina_cxx/eina_copy_traits.hh b/src/bindings/cxx/eina_cxx/eina_copy_traits.hh new file mode 100644 index 0000000000..0db8bd85b4 --- /dev/null +++ b/src/bindings/cxx/eina_cxx/eina_copy_traits.hh @@ -0,0 +1,43 @@ +/// +/// @file eo_concrete.hh +/// + +#ifndef EFL_CXX_EINA_COPY_TRAITS_HH +#define EFL_CXX_EINA_COPY_TRAITS_HH + +namespace efl { namespace eina { + +template <typename T, typename Enable = void> +struct copy_from_c_traits; + +template <typename T> +struct copy_from_c_traits<T, typename std::enable_if<std::is_fundamental<T>::value>::type> +{ + static void copy_to_unitialized(T* storage, void const* data) + { + std::memcpy(storage, data, sizeof(T)); + } +}; + +template <typename T, typename Enable = void> +struct alloc_to_c_traits; + +template <typename T> +struct alloc_to_c_traits<T, typename std::enable_if<std::is_fundamental<T>::value>::type> +{ + typedef T c_type; + static c_type* copy_alloc(T const& value) + { + c_type* v = static_cast<c_type*>(malloc(sizeof(c_type))); + std::memcpy(v, &value, sizeof(c_type)); + return v; + } + static void free_alloc(void* data) + { + ::free(data); + } +}; + +} } + +#endif diff --git a/src/bindings/cxx/eo_cxx/Eo.hh b/src/bindings/cxx/eo_cxx/Eo.hh index b7d1e856a3..771ee12da9 100644 --- a/src/bindings/cxx/eo_cxx/Eo.hh +++ b/src/bindings/cxx/eo_cxx/Eo.hh @@ -4,8 +4,9 @@ #include <eo_concrete.hh> #include <eo_init.hh> #include <eo_wref.hh> -// #include <eo_inherit.hh> +//#include <eo_inherit.hh> //#include <eo_own_ptr.hh> +#include <eo_promise.hh> #include <eo_cxx_interop.hh> #include <eo_event.hh> diff --git a/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh b/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh index 597ef3b703..fc1793fb67 100644 --- a/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh +++ b/src/bindings/cxx/eo_cxx/eo_cxx_interop.hh @@ -55,14 +55,14 @@ struct out_traits<eina::optional<T&>> { typedef eina::optional<T&> type; }; template <> struct out_traits<void*> { typedef void*& type; }; template <typename T> -struct out_traits<efl::eina::future<T>> { typedef efl::eina::future<T>& type; }; +struct out_traits<efl::shared_future<T>> { typedef efl::shared_future<T>& type; }; template <typename T> struct inout_traits { typedef T& type; }; template <> struct inout_traits<void> { typedef void* type; }; template <typename T> -struct inout_traits<efl::eina::future<T>> { typedef efl::eina::future<T>& type; }; +struct inout_traits<efl::shared_future<T>> { typedef efl::shared_future<T>& type; }; template <typename T> struct return_traits { typedef T type; }; @@ -126,7 +126,11 @@ void assign_out_impl(T& lhs, Eo const* rhs, tag<T&, Eo const*> lhs._reset(const_cast<Eo*>(rhs)); } template <typename T> -void assign_out_impl(efl::eina::future<T>& /*v*/, Eina_Promise*, tag<efl::eina::future<T>&, Eina_Promise*>) +void assign_out_impl(efl::promise<T>& /*v*/, Eina_Promise*, tag<efl::promise<T>&, Eina_Promise*>) +{ +} +template <typename T> +void assign_out_impl(efl::shared_future<T>& /*v*/, Efl_Future*, tag<efl::shared_future<T>&, Efl_Future*>) { } template <typename Tag> @@ -257,7 +261,12 @@ Eo const* convert_inout_impl(T v, tag<T, Eo const*> return v._eo_ptr(); } template <typename T> -Eina_Promise* convert_inout_impl(efl::eina::future<T>& /*v*/, tag<efl::eina::future<T>, Eina_Promise*>) +Eina_Promise* convert_inout_impl(efl::promise<T>& /*v*/, tag<efl::promise<T>, Eina_Promise*>) +{ + return nullptr; +} +template <typename T> +Efl_Future* convert_inout_impl(efl::shared_future<T>& /*v*/, tag<efl::shared_future<T>, Efl_Future*>) { return nullptr; } @@ -511,7 +520,12 @@ inline const char* convert_to_c_impl(efl::eina::stringshare x, tag<const char*, return eina_stringshare_ref(x.c_str()); } template <typename T> -Eina_Promise* convert_to_c_impl(efl::eina::future<T> const&, tag<Eina_Promise*, efl::eina::future<T>const&>) +Eina_Promise* convert_to_c_impl(efl::promise<T> const&, tag<Eina_Promise*, efl::promise<T>const&>) +{ + std::abort(); +} +template <typename T> +Efl_Future* convert_to_c_impl(efl::shared_future<T> const&, tag<Efl_Future*, efl::shared_future<T>const&>) { std::abort(); } @@ -653,11 +667,13 @@ eina::accessor<T> convert_to_return(Eina_Accessor* value, tag<Eina_Accessor*, ei return eina::accessor<T>{ value }; } template <typename T> -struct is_future : std::false_type {}; -template <typename T> -struct is_future<efl::eina::future<T>> : std::true_type {}; +efl::promise<T> convert_to_return(Eina_Promise* /*value*/, tag<Eina_Promise*, efl::promise<T>>) +{ + std::abort(); + return {}; +} template <typename T> -T convert_to_return(Eina_Promise* /*value*/, tag<Eina_Promise*, T>, typename std::enable_if<is_future<T>::value>::type* = 0) +efl::shared_future<T> convert_to_return(Efl_Future* /*value*/, tag<Efl_Future*, efl::shared_future<T>>) { std::abort(); return {}; diff --git a/src/bindings/cxx/eo_cxx/eo_promise.hh b/src/bindings/cxx/eo_cxx/eo_promise.hh new file mode 100644 index 0000000000..b325d9cd12 --- /dev/null +++ b/src/bindings/cxx/eo_cxx/eo_promise.hh @@ -0,0 +1,416 @@ +/// +/// @file eo_concrete.hh +/// + +#ifndef EFL_CXX_EO_PROMISE_HH +#define EFL_CXX_EO_PROMISE_HH + +#include <Efl.h> + +#include <Eina.hh> +#include <Ecore_Manual.hh> + +#include <mutex> +#include <condition_variable> + +namespace efl { + +namespace _impl { + +template <typename F, typename...Args> +struct future_invoke_result_of; + +template <typename F, typename A0> +struct future_invoke_result_of<F, A0> +{ + typedef typename std::result_of<F(A0)>::type type; +}; + +template <typename F> +struct future_invoke_result_of<F, void> +{ + typedef typename std::result_of<F()>::type type; +}; + +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; + eina::copy_from_c_traits<A0>::copy_to_unitialized + (static_cast<A0*>(static_cast<void*>(&storage)), info->value); + 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 <typename A0, typename A1, typename...OtherArgs, typename F> +// typename future_invoke_result_of<F, A0, A1, OtherArgs...>::type +void +future_invoke(F f, Efl_Event const* event) +{ + Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info); + +} + +} + +template <typename T> +struct progress; + +namespace _impl { + +template <typename V = char> +struct wait_state +{ + bool available = false; + bool has_failed = false; + std::mutex mutex; + std::condition_variable cv; + typename std::aligned_storage<sizeof(V), alignof(V)>::type storage; + Eina_Error error; +}; + +static void get_error_cb(void* data, Efl_Event const* event) +{ + struct wait_state<>* wait_state = static_cast<struct wait_state<>*>(data); + Efl_Future_Event_Failure* info = static_cast<Efl_Future_Event_Failure*>(event->info); + std::unique_lock<std::mutex> 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<std::mutex> 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<struct wait_state<>*>(data); + std::unique_lock<std::mutex> l(wait_state->mutex); + wait_state->available = true; + wait_state->cv.notify_one(); + } + + typedef Efl_Future* native_handle_type; + typedef Efl_Future const* const_native_handle_type; + native_handle_type native_handle() noexcept { return _future; } + const_native_handle_type native_handle() const noexcept { return _future; } + + typedef shared_future_common _self_type; + Efl_Future* _future; +}; + +template <typename T> +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<T> 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<std::mutex> 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<T*>(static_cast<void*>(&wait_state.storage)); + } + + static void get_success(void* data, Efl_Event const* event) + { + struct wait_state<T>* wait_state = static_cast<struct wait_state<T>*>(data); + Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info); + + std::unique_lock<std::mutex> l(wait_state->mutex); + eina::copy_from_c_traits<T>::copy_to_unitialized + (static_cast<T*>(static_cast<void*>(&wait_state->storage)), info->value); + wait_state->available = true; + wait_state->cv.notify_one(); + } + + typedef shared_future_1_type<T> _self_type; +}; + +template <typename...Args> +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<Args...> tuple_type; + + std::tuple<Args...> get() const + { + if(eina_main_loop_is()) + throw std::runtime_error("Deadlock"); + + struct wait_state<tuple_type> 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<std::mutex> 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<tuple_type*>(static_cast<void*>(&wait_state.storage)); + } + + template <std::size_t N> + static void read_accessor(Eina_Accessor* accessor + , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple + , wait_state<tuple_type>* wait_state + , std::false_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); + + std::cout << "copied value " << *static_cast<type*>(static_cast<void*>(&std::get<N>(storage_tuple))) + << std::endl; + + _self_type::read_accessor<N+1>(accessor, storage_tuple, wait_state + , std::integral_constant<bool, (N+1 == sizeof...(Args))>()); + } + else + { + std::abort(); + // some error + } + } + + template <std::size_t N, std::size_t...I> + static void read_accessor_end(std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple + , wait_state<tuple_type>* wait_state + , eina::index_sequence<I...>) + { + std::unique_lock<std::mutex> l(wait_state->mutex); + + new (&wait_state->storage) tuple_type{(*static_cast<typename std::tuple_element<I, tuple_type>::type*> + (static_cast<void*>(&std::get<I>(storage_tuple))))...}; + + wait_state->available = true; + wait_state->cv.notify_one(); + } + + template <std::size_t N> + static void read_accessor(Eina_Accessor* + , std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...>& storage_tuple + , wait_state<tuple_type>* wait_state + , std::true_type) + { + _self_type::read_accessor_end<N>(storage_tuple, wait_state, eina::make_index_sequence<sizeof...(Args)>{}); + } + + static void get_success(void* data, Efl_Event const* event) + { + struct wait_state<tuple_type>* wait_state = static_cast<struct wait_state<tuple_type>*>(data); + Efl_Future_Event_Success* info = static_cast<Efl_Future_Event_Success*>(event->info); + + Eina_Accessor* accessor = static_cast<Eina_Accessor*>(info->value); + std::tuple<typename std::aligned_storage<sizeof(Args), alignof(Args)>::type...> storage_tuple; + + _self_type::read_accessor<0u>(accessor, storage_tuple, wait_state, std::false_type()); + } + + typedef shared_future_varargs_type<Args...> _self_type; +}; + +} + +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 +{ + 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; + + 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 <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(shared_future<Args...> future, Success success_cb, Error error_cb) +{ + struct private_data + { + Success success_cb; + Error error_cb; + shared_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); + // 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...Args> +struct promise +{ + +}; + +} + +#endif |