forked from enlightenment/efl
eolian-cxx: Implement future template class for C++
This commit is contained in:
parent
98229bc5d6
commit
a63cfcafc7
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 {};
|
||||
efl::promise<T> convert_to_return(Eina_Promise* /*value*/, tag<Eina_Promise*, efl::promise<T>>)
|
||||
{
|
||||
std::abort();
|
||||
return {};
|
||||
}
|
||||
template <typename T>
|
||||
struct is_future<efl::eina::future<T>> : std::true_type {};
|
||||
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 {};
|
||||
|
|
|
@ -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
|
|
@ -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, [&]
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue