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 | |
parent | 98229bc5d6cf1ebe11af4bb05a32f2a30b470f6e (diff) | |
download | efl-a63cfcafc7f8524dfad4e1bba763fb17c69d50e1.tar.gz |
eolian-cxx: Implement future template class for C++
-rw-r--r-- | src/Makefile_Cxx.am | 34 | ||||
-rw-r--r-- | src/Makefile_Ecore.am | 13 | ||||
-rw-r--r-- | src/Makefile_Eolian_Cxx.am | 4 | ||||
-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 | ||||
-rw-r--r-- | src/lib/eolian_cxx/grammar/type_impl.hpp | 8 | ||||
-rw-r--r-- | src/tests/eo_cxx/eo_cxx_suite.cc | 27 | ||||
-rw-r--r-- | src/tests/eo_cxx/eo_cxx_suite.h | 11 | ||||
-rw-r--r-- | src/tests/eo_cxx/eo_cxx_test_promise.cc | 347 |
14 files changed, 1096 insertions, 185 deletions
diff --git a/src/Makefile_Cxx.am b/src/Makefile_Cxx.am index 2fda128446..917d285aca 100644 --- a/src/Makefile_Cxx.am +++ b/src/Makefile_Cxx.am @@ -13,6 +13,7 @@ bindings/cxx/eo_cxx/Eo.hh \ bindings/cxx/eo_cxx/eo_init.hh \ bindings/cxx/eo_cxx/eo_ops.hh \ bindings/cxx/eo_cxx/eo_wref.hh \ +bindings/cxx/eo_cxx/eo_promise.hh \ bindings/cxx/eo_cxx/eo_private.hh ### Elementary C++ @@ -120,7 +121,8 @@ CLEANFILES += $(edje_eolian_cxx_hh) $(edje_eolian_cxx_impl) lib/edje/Edje.hh ### Ecore src/lib/ecore installed_ecorecxxheadersdir = $(includedir)/ecore-cxx-@VMAJ@ dist_installed_ecorecxxheaders_DATA = \ -bindings/cxx/ecore_cxx/Ecore.hh +bindings/cxx/ecore_cxx/Ecore.hh \ +bindings/cxx/ecore_cxx/Ecore_Manual.hh nodist_installed_ecorecxxheaders_DATA = $(ecore_eolian_cxx_hh) $(ecore_eolian_cxx_impl) \ lib/ecore/Ecore.eo.hh @@ -168,6 +170,7 @@ bindings/cxx/eina_cxx/eina_tuple_unwrap.hh \ bindings/cxx/eina_cxx/eina_type_traits.hh \ bindings/cxx/eina_cxx/eina_value.hh \ bindings/cxx/eina_cxx/eina_workarounds.hh \ +bindings/cxx/eina_cxx/eina_copy_traits.hh \ bindings/cxx/eina_cxx/Eina.hh ### Eio @@ -186,9 +189,9 @@ CLEANFILES += $(eio_eolian_cxx_hh) $(eio_eolian_cxx_impl) lib/eio/Eio.hh if EFL_ENABLE_TESTS -### Tests for Eina -check_PROGRAMS += tests/eina_cxx/eina_cxx_suite -TESTS += tests/eina_cxx/eina_cxx_suite +### Tests for Eina and Eo +check_PROGRAMS += tests/eina_cxx/eina_cxx_suite tests/eo_cxx/eo_cxx_suite +TESTS += tests/eina_cxx/eina_cxx_suite tests/eo_cxx/eo_cxx_suite tests_eina_cxx_eina_cxx_suite_SOURCES = \ tests/eina_cxx/eina_cxx_suite.cc \ @@ -232,11 +235,34 @@ tests_eina_cxx_eina_cxx_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ @CHECK_CFLAGS@ \ @EO_CFLAGS@ \ @ECORE_CFLAGS@ \ +@ECORE_CXX_CFLAGS@ \ @EO_CXX_CFLAGS@ \ @EINA_CXX_CFLAGS@ tests_eina_cxx_eina_cxx_suite_LDADD = @CHECK_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@ tests_eina_cxx_eina_cxx_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ +tests_eo_cxx_eo_cxx_suite_SOURCES = \ +tests/eo_cxx/eo_cxx_suite.cc \ +tests/eo_cxx/eo_cxx_test_promise.cc + +tests_eo_cxx_eo_cxx_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eo_cxx\" \ +-DPACKAGE_BUILD_DIR=\"$(abs_top_builddir)/src/tests/eo_cxx\" \ +-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eo_cxx\" \ +-I$(top_builddir)/src/lib/efl \ +-I$(top_builddir)/src/lib/efl/interfaces \ +-I$(top_srcdir)/src/bin/eina_cxx \ +-I$(top_builddir)/src/tests/eina_cxx \ +@CHECK_CFLAGS@ \ +@EO_CFLAGS@ \ +@ECORE_CFLAGS@ \ +@ECORE_CXX_CFLAGS@ \ +@EO_CXX_CFLAGS@ \ +@EINA_CXX_CFLAGS@ +tests_eo_cxx_eo_cxx_suite_LDADD = @CHECK_LIBS@ @USE_EINA_LIBS@ @USE_EO_LIBS@ @USE_ECORE_LIBS@ +tests_eo_cxx_eo_cxx_suite_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ @USE_EO_INTERNAL_LIBS@ @USE_ECORE_INTERNAL_LIBS@ + ### Tests for ecore check_PROGRAMS += tests/ecore_cxx/ecore_cxx_suite tests/ecore_cxx/cxx_compile_test diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am index 4a1d6a6795..606ae66482 100644 --- a/src/Makefile_Ecore.am +++ b/src/Makefile_Ecore.am @@ -6,7 +6,7 @@ ecore_eolian_files_legacy = \ lib/ecore/ecore_exe.eo \ lib/ecore/efl_loop_timer.eo -ecore_eolian_files = \ +ecore_eolian_files_public = \ lib/ecore/efl_loop.eo \ lib/ecore/efl_loop_user.eo \ lib/ecore/efl_loop_fd.eo \ @@ -20,8 +20,11 @@ ecore_eolian_files = \ lib/ecore/efl_io_stderr.eo \ lib/ecore/efl_io_file.eo \ lib/ecore/efl_io_copier.eo \ + lib/ecore/ecore_parent.eo + +ecore_eolian_files = \ + $(ecore_eolian_files_public) \ lib/ecore/efl_promise.eo \ - lib/ecore/ecore_parent.eo \ $(ecore_eolian_files_legacy) ecore_eolian_type_files = \ @@ -300,7 +303,7 @@ endif if HAVE_JS -generated_ecore_js_bindings = $(ecore_eolian_files:%.eo=%.eo.js.cc) +generated_ecore_js_bindings = $(ecore_eolian_files_public:%.eo=%.eo.js.cc) GENERATED_JS_BINDINGS += $(generated_ecore_js_bindings) @@ -308,7 +311,7 @@ endif if HAVE_CXX11 -ecore_eolian_cxx_hh = $(ecore_eolian_files:%.eo=%.eo.hh) -ecore_eolian_cxx_impl = $(ecore_eolian_files:%.eo=%.eo.impl.hh) +ecore_eolian_cxx_hh = $(ecore_eolian_files_public:%.eo=%.eo.hh) +ecore_eolian_cxx_impl = $(ecore_eolian_files_public:%.eo=%.eo.impl.hh) endif diff --git a/src/Makefile_Eolian_Cxx.am b/src/Makefile_Eolian_Cxx.am index b8fad1cf4a..c142a4b5fa 100644 --- a/src/Makefile_Eolian_Cxx.am +++ b/src/Makefile_Eolian_Cxx.am @@ -57,7 +57,7 @@ bin_eolian_cxx_eolian_cxx_SOURCES = \ bin_eolian_cxx_eolian_cxx_CXXFLAGS = -I$(top_builddir)/src/lib/efl \ -I$(top_srcdir)/src/lib/eolian_cxx/ \ -@CHECK_CFLAGS@ @EINA_CFLAGS@ @EINA_CXX_CFLAGS@ @EO_CFLAGS@ \ +@CHECK_CFLAGS@ @EINA_CFLAGS@ @EINA_CXX_CFLAGS@ @EO_CXX_CFLAGS@ @ECORE_CXX_CFLAGS@ @EO_CFLAGS@ \ -I$(top_srcdir)/src/bindings/cxx/eina_cxx \ @EOLIAN_CXX_CFLAGS@ @EOLIAN_CFLAGS@ @@ -159,7 +159,7 @@ tests_eolian_cxx_eolian_cxx_suite_CXXFLAGS = \ -DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eolian_cxx\" \ @CHECK_CFLAGS@ @EOLIAN_CXX_CFLAGS@ @EINA_CXX_CFLAGS@ \ @EOLIAN_CFLAGS@ @EINA_CFLAGS@ @EO_CFLAGS@ @ECORE_CFLAGS@ \ -@EO_CXX_CFLAGS@ +@EO_CXX_CFLAGS@ @ECORE_CXX_CFLAGS@ tests_eolian_cxx_eolian_cxx_suite_CFLAGS = ${tests_eolian_cxx_eolian_cxx_suite_CXXFLAGS} tests_eolian_cxx_eolian_cxx_suite_CPPFLAGS = ${tests_eolian_cxx_eolian_cxx_suite_CXXFLAGS} 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 diff --git a/src/lib/eolian_cxx/grammar/type_impl.hpp b/src/lib/eolian_cxx/grammar/type_impl.hpp index 6e18b2bda1..ac1118f077 100644 --- a/src/lib/eolian_cxx/grammar/type_impl.hpp +++ b/src/lib/eolian_cxx/grammar/type_impl.hpp @@ -256,7 +256,13 @@ struct visitor_generate , {"promise", nullptr, nullptr, [&] { return replace_outer - (complex, regular_type_def{" ::efl::eina::future", complex.outer.base_qualifier, {}}); + (complex, regular_type_def{" ::efl::promise", complex.outer.base_qualifier, {}}); + } + } + , {"future", nullptr, nullptr, [&] + { + return replace_outer + (complex, regular_type_def{" ::efl::shared_future", complex.outer.base_qualifier, {}}); } } , {"iterator", nullptr, nullptr, [&] diff --git a/src/tests/eo_cxx/eo_cxx_suite.cc b/src/tests/eo_cxx/eo_cxx_suite.cc new file mode 100644 index 0000000000..2362d38359 --- /dev/null +++ b/src/tests/eo_cxx/eo_cxx_suite.cc @@ -0,0 +1,27 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "eo_cxx_suite.h" +#include "../efl_check.h" + +static const Efl_Test_Case etc[] = { + { "Promise", eo_cxx_test_promise }, + { NULL, NULL } +}; + +int +main(int argc, char* argv[]) +{ + int failed_count; + + if (!_efl_test_option_disp(argc, argv, etc)) + return 0; + + putenv(const_cast<char*>("EFL_RUN_IN_TREE=1")); + + failed_count = _efl_suite_build_and_run(argc - 1, (const char **)argv + 1, + "Eo C++", etc); + + return (failed_count == 0) ? 0 : 255; +} diff --git a/src/tests/eo_cxx/eo_cxx_suite.h b/src/tests/eo_cxx/eo_cxx_suite.h new file mode 100644 index 0000000000..a5a1d6147c --- /dev/null +++ b/src/tests/eo_cxx/eo_cxx_suite.h @@ -0,0 +1,11 @@ +#ifndef _EINA_CXX_SUITE_H +#define _EINA_CXX_SUITE_H + +#include <cassert> +#include <algorithm> + +#include <check.h> + +void eo_cxx_test_promise(TCase* tc); + +#endif /* _EINA_CXX_SUITE_H */ diff --git a/src/tests/eo_cxx/eo_cxx_test_promise.cc b/src/tests/eo_cxx/eo_cxx_test_promise.cc new file mode 100644 index 0000000000..b3a2b32b31 --- /dev/null +++ b/src/tests/eo_cxx/eo_cxx_test_promise.cc @@ -0,0 +1,347 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Eina.hh> +#include <Eo.hh> +#include <Ecore.hh> + +#include "eo_cxx_suite.h" + +START_TEST(eo_cxx_future_construct_and_destroy) +{ + Efl_Promise *p; + Efl_Future *f; + + ecore_init(); + + { + p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p); + + f = efl_promise_future_get(p); + fail_if(!f); + + efl::shared_future<int> future(efl_ref(f)); + } + ecore_shutdown(); +} +END_TEST + +START_TEST(eo_cxx_future_wait) +{ + Efl_Promise *p; + Efl_Future *f; + + ecore_init(); + + p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p); + + f = efl_promise_future_get(p); + fail_if(!f); + + { + efl::shared_future<int> future(efl_ref(f)); + + 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 + ([&] + { + int* i = static_cast<int*>(malloc(sizeof(int))); + *i = 5; + efl_promise_value_set(p, i, & ::free); + }); + + future.wait(); + efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); }); + }); + + ecore_main_loop_begin(); + + thread.join(); + } + ecore_shutdown(); +} +END_TEST + +START_TEST(eo_cxx_future_get) +{ + Efl_Promise *p; + Efl_Future *f; + + ecore_init(); + + p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p); + + f = efl_promise_future_get(p); + fail_if(!f); + + { + efl::shared_future<int> future(efl_ref(f)); + + 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 + ([&] + { + int* i = static_cast<int*>(malloc(sizeof(int))); + *i = 5; + efl_promise_value_set(p, i, & ::free); + }); + + int i = future.get(); + ck_assert_int_eq(i, 5); + efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); }); + }); + + ecore_main_loop_begin(); + + thread.join(); + } + ecore_shutdown(); +} +END_TEST + +START_TEST(eo_cxx_future_get_error) +{ + Efl_Promise *p; + Efl_Future *f; + + ecore_init(); + + p = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p); + + f = efl_promise_future_get(p); + fail_if(!f); + + { + efl::shared_future<int> future(efl_ref(f)); + + 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 + ([&] + { + efl_promise_failed_set(p, EINA_ERROR_OUT_OF_MEMORY); + }); + + try { + future.get(); + ck_abort_msg("Execution should not have continued, exception expected"); + } + catch(std::system_error const& e) + { + } + efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); }); + }); + + ecore_main_loop_begin(); + + thread.join(); + } + ecore_shutdown(); +} +END_TEST + +START_TEST(eo_cxx_future_then_value) +{ + Efl_Promise *promise; + Efl_Future *f; + + ecore_init(); + + promise = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!promise); + + f = efl_promise_future_get(promise); + fail_if(!f); + + { + efl::shared_future<int> future(efl_ref(f)), rfuture; + + + std::thread thread + ([&] + { + efl::ecore::main_loop_thread_safe_call_sync + ([&] + { + rfuture = then + (future, [] (int i) -> int + { + ck_assert_int_eq(i, 5); + return 42; + }, [] (std::error_code) + { + throw std::bad_alloc(); + }); + }); + efl::ecore::main_loop_thread_safe_call_async + ([&] + { + int* i = static_cast<int*>(malloc(sizeof(int))); + *i = 5; + efl_promise_value_set(promise, i, &::free); + }); + + int i = rfuture.get(); + ck_assert_int_eq(i, 42); + efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); }); + }); + + ecore_main_loop_begin(); + thread.join(); + } + ecore_shutdown(); +} +END_TEST + +START_TEST(eo_cxx_future_composite_construct_and_destroy) +{ + ecore_init(); + + { + Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p1); + + Efl_Future *f1 = efl_promise_future_get(p1); + fail_if(!f1); + + Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p1); + + Efl_Future *f2 = efl_promise_future_get(p2); + fail_if(!f2); + + Efl_Future *f3 = efl_future_all(f1, f2); + fail_if(!f3); + + efl::shared_future<int> future1(efl_ref(f1)) + , future2(efl_ref(f2)); + efl::shared_future<int, int> future3(efl_ref(f3)); + } + ecore_shutdown(); +} +END_TEST + +START_TEST(eo_cxx_future_composite_wait) +{ + ecore_init(); + + { + Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p1); + + Efl_Future* f1 = efl_promise_future_get(p1); + fail_if(!f1); + + Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p2); + + Efl_Future* f2 = efl_promise_future_get(p2); + fail_if(!f2); + + Efl_Future *f3 = efl_future_all(f1, f2); + fail_if(!f3); + + efl::shared_future<int> future1(efl_ref(f1)) + , future2(efl_ref(f2)); + efl::shared_future<int, int> future3(efl_ref(f3)); + + 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 + ([&] + { + int* i1 = static_cast<int*>(malloc(sizeof(int))); + *i1 = 5; + efl_promise_value_set(p1, i1, & ::free); + int* i2 = static_cast<int*>(malloc(sizeof(int))); + *i2 = 42; + efl_promise_value_set(p2, i2, & ::free); + }); + + future3.wait(); + efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); }); + }); + + ecore_main_loop_begin(); + + thread.join(); + } + ecore_shutdown(); +} +END_TEST + +START_TEST(eo_cxx_future_composite_get) +{ + ecore_init(); + + { + Efl_Promise *p1 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p1); + + Efl_Future *f1 = efl_promise_future_get(p1); + fail_if(!f1); + + Efl_Promise *p2 = efl_add(EFL_PROMISE_CLASS, ecore_main_loop_get()); + fail_if(!p2); + + Efl_Future *f2 = efl_promise_future_get(p2); + fail_if(!f2); + + Efl_Future *f3 = efl_future_all(f1, f2); + fail_if(!f3); + + efl::shared_future<int> future1(efl_ref(f1)) + , future2(efl_ref(f2)); + efl::shared_future<int, int> future3(efl_ref(f3)); + + 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 + ([&] + { + int* i1 = static_cast<int*>(malloc(sizeof(int))); + *i1 = 5; + efl_promise_value_set(p1, i1, & ::free); + int* i2 = static_cast<int*>(malloc(sizeof(int))); + *i2 = 42; + efl_promise_value_set(p2, i2, & ::free); + }); + + std::tuple<int, int> tuple = future3.get(); + ck_assert_int_eq(std::get<0>(tuple), 5); + ck_assert_int_eq(std::get<1>(tuple), 42); + efl::ecore::main_loop_thread_safe_call_sync([] { ecore_main_loop_quit(); }); + }); + + ecore_main_loop_begin(); + + thread.join(); + } + ecore_shutdown(); +} +END_TEST + +void +eo_cxx_test_promise(TCase* tc) +{ + tcase_add_test(tc, eo_cxx_future_construct_and_destroy); + tcase_add_test(tc, eo_cxx_future_wait); + tcase_add_test(tc, eo_cxx_future_get); + tcase_add_test(tc, eo_cxx_future_get_error); + tcase_add_test(tc, eo_cxx_future_then_value); + tcase_add_test(tc, eo_cxx_future_composite_construct_and_destroy); + tcase_add_test(tc, eo_cxx_future_composite_wait); + tcase_add_test(tc, eo_cxx_future_composite_get); +} |