From ab3eb4b2d350d017eab6683202663244e11aa518 Mon Sep 17 00:00:00 2001 From: Felipe Magno de Almeida Date: Tue, 1 Apr 2014 19:08:07 +0900 Subject: [PATCH] eet-cxx: add implementation for eet C++. Usage example: struct type { int foo; float bar; }; type t0; auto descriptor = make_descriptor("type", &type::ofo, &type::bar); eet_data_write(file, descriptor.native_handle(), "type", &t0, false); std::unique_ptr p = read_by_ptr(file, "type", descriptor); type t = read(file, "type", descriptor); @feature Reviewers: cedric, smohanty Reviewed By: cedric CC: savio, cedric Differential Revision: https://phab.enlightenment.org/D659 Signed-off-by: Cedric BAIL --- configure.ac | 1 + pc/.gitignore | 1 + pc/eet-cxx.pc.in | 12 ++ src/Makefile.am | 1 + src/Makefile_Eet_Cxx.am | 42 +++++ src/bindings/eet_cxx/Eet.hh | 214 ++++++++++++++++++++++++ src/bindings/eet_cxx/eet_composite.hh | 49 ++++++ src/bindings/eet_cxx/eet_fold.hh | 32 ++++ src/bindings/eet_cxx/eet_register.hh | 132 +++++++++++++++ src/bindings/eet_cxx/eet_tuple.hh | 39 +++++ src/bindings/eet_cxx/eet_type.hh | 78 +++++++++ src/lib/eet/Eet.h | 37 +++++ src/lib/eet/eet_data.c | 38 +++++ src/tests/eet_cxx/eet_cxx_suite.cc | 104 ++++++++++++ src/tests/eet_cxx/eet_cxx_test_descriptors.cc | 231 ++++++++++++++++++++++++++ 15 files changed, 1011 insertions(+) create mode 100644 pc/eet-cxx.pc.in create mode 100644 src/Makefile_Eet_Cxx.am create mode 100644 src/bindings/eet_cxx/Eet.hh create mode 100644 src/bindings/eet_cxx/eet_composite.hh create mode 100644 src/bindings/eet_cxx/eet_fold.hh create mode 100644 src/bindings/eet_cxx/eet_register.hh create mode 100644 src/bindings/eet_cxx/eet_tuple.hh create mode 100644 src/bindings/eet_cxx/eet_type.hh create mode 100644 src/tests/eet_cxx/eet_cxx_suite.cc create mode 100644 src/tests/eet_cxx/eet_cxx_test_descriptors.cc diff --git a/configure.ac b/configure.ac index 4001d29..3642b96 100644 --- a/configure.ac +++ b/configure.ac @@ -4100,6 +4100,7 @@ pc/escape.pc pc/eina.pc pc/eina-cxx.pc pc/eet.pc +pc/eet-cxx.pc pc/eo.pc pc/eolian.pc pc/evas-fb.pc diff --git a/pc/.gitignore b/pc/.gitignore index 658f6cf..ae42f58 100644 --- a/pc/.gitignore +++ b/pc/.gitignore @@ -26,6 +26,7 @@ /efreet.pc /eina.pc /eina-cxx.pc +/eet-cxx.pc /eio.pc /eldbus.pc /embryo.pc diff --git a/pc/eet-cxx.pc.in b/pc/eet-cxx.pc.in new file mode 100644 index 0000000..2412c48 --- /dev/null +++ b/pc/eet-cxx.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Eet C++ +Description: C++ API for the eet library +Version: @VERSION@ +Requires.private: @requirements_pc_eet@ +Libs: -L${libdir} -leet +Libs.private: @requirements_libs_eet@ +Cflags: -I${includedir}/efl-@VMAJ@ -I${includedir}/eet-@VMAJ@ -I${includedir}/efl-@VMAJ@ -I${includedir}/eet_cxx-@VMAJ@ -I${includedir}/eet_cxx-@VMAJ@/eet_cxx diff --git a/src/Makefile.am b/src/Makefile.am index e277678..f9c2497 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,6 +32,7 @@ include Makefile_Escape.am include Makefile_Eina.am include Makefile_Eo.am include Makefile_Eet.am +include Makefile_Eet_Cxx.am include Makefile_Eolian.am include Makefile_Evas.am include Makefile_Ecore.am diff --git a/src/Makefile_Eet_Cxx.am b/src/Makefile_Eet_Cxx.am new file mode 100644 index 0000000..b2381aa --- /dev/null +++ b/src/Makefile_Eet_Cxx.am @@ -0,0 +1,42 @@ + +### Library + +installed_eetcxxmainheadersdir = $(includedir)/eet_cxx-@VMAJ@ +dist_installed_eetcxxmainheaders_DATA = bindings/eet_cxx/Eet.hh + +installed_eetcxxheadersdir = $(includedir)/eet_cxx-@VMAJ@/eet_cxx +dist_installed_eetcxxheaders_DATA = \ +bindings/eet_cxx/eet_composite.hh \ +bindings/eet_cxx/eet_fold.hh \ +bindings/eet_cxx/eet_register.hh \ +bindings/eet_cxx/eet_tuple.hh \ +bindings/eet_cxx/eet_type.hh + +### Unit tests + +if EFL_ENABLE_TESTS +if HAVE_CXX11 + +check_PROGRAMS += tests/eet_cxx/eet_cxx_suite +TESTS += tests/eet_cxx/eet_cxx_suite + +tests_eet_cxx_eet_cxx_suite_SOURCES = \ +tests/eet_cxx/eet_cxx_suite.cc \ +tests/eet_cxx/eet_cxx_test_descriptors.cc + +tests_eet_cxx_eet_cxx_suite_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +-I$(top_builddir)/src/bindings/eina_cxx \ +-I$(top_builddir)/src/bindings/eet_cxx \ +-I$(top_srcdir)/src/bindings/eina_cxx \ +-I$(top_srcdir)/src/bindings/eet_cxx \ +-DTESTS_WD=\"`pwd`\" \ +-DTESTS_SRC_DIR=\"$(top_srcdir)/src/tests/eet_cxx\" \ +-DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eet_cxx\" \ +@CHECK_CFLAGS@ \ +@EET_CFLAGS@ +tests_eet_cxx_eet_cxx_suite_LDADD = @CHECK_LIBS@ @USE_EET_LIBS@ +tests_eet_cxx_eet_cxx_suite_DEPENDENCIES = @USE_EET_INTERNAL_LIBS@ + +endif +endif diff --git a/src/bindings/eet_cxx/Eet.hh b/src/bindings/eet_cxx/Eet.hh new file mode 100644 index 0000000..f725c68 --- /dev/null +++ b/src/bindings/eet_cxx/Eet.hh @@ -0,0 +1,214 @@ +#ifndef EET_HH_ +#define EET_HH_ + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace efl { namespace eet { namespace _detail { + +template +void* _allocate( ::size_t size ) +{ + assert(size == sizeof(T)); + (void)size; + return new T(); +} + +template +void _deallocate( void* p ) +{ + delete static_cast(p); +} + +template +struct descriptor_type +{ + struct push_back + { + template + struct apply : _mpl::push_back::type> {}; + }; + + typedef typename _mpl::fold< std::tuple, push_back + , descriptor >::type type; +}; + +} + +#define EET_CXX_MEMBER(C, I) ::efl::eet::type(#I, &C::I) + +template +_detail::member_info type(const char* name, F f) +{ + typedef typename _detail::member_type::type member_type; + static_assert(is_eet_primitive::value, ""); + static_assert(std::is_member_pointer::value, ""); + return _detail::member_info{name, f}; +} + +template +_detail::member_info type(const char* name, F f, descriptor const& descriptor) +{ + typedef typename _detail::member_type::type member_type; + static_assert(!is_eet_primitive::value, ""); + static_assert(std::is_member_pointer::value, ""); + return _detail::member_info{name, f, &descriptor}; +} + +struct eet_init +{ + eet_init() + { + ::eet_init(); + } + ~eet_init() + { + ::eet_shutdown(); + } +}; + +template +struct descriptor +{ + typedef T object_type; + + descriptor() : _descriptor(nullptr) {} + descriptor( ::Eet_Data_Descriptor* descriptor + , std::array<_detail::member_desc_info, sizeof...(Args)> member_info) + : _descriptor(descriptor), _member_info(member_info) + { + } + descriptor(descriptor&& other) + : _descriptor(other._descriptor) + { + other._descriptor = 0; + } + descriptor& operator=(descriptor&& other) + { + if(_descriptor) + eet_data_descriptor_free(_descriptor); + _descriptor = other._descriptor; + other._descriptor = 0; + return *this; + } + ~descriptor() + { + if(_descriptor) + eet_data_descriptor_free(_descriptor); + } + typedef ::Eet_Data_Descriptor const* const_native_handle_type; + typedef ::Eet_Data_Descriptor* native_handle_type; + const_native_handle_type native_handle() const + { + return _descriptor; + } + native_handle_type native_handle() + { + return _descriptor; + } + typedef std::integral_constant members; + + std::array<_detail::member_desc_info, sizeof...(Args)> get_member_info() const { return _member_info; } +private: + ::Eet_Data_Descriptor* _descriptor; + typedef descriptor _self_type; + descriptor(descriptor const&) = delete; + descriptor& operator=(descriptor const&) = delete; + std::array<_detail::member_desc_info, sizeof...(Args)> _member_info; +}; + +template +std::unique_ptr read_by_ptr(Eet_File* file, const char* name, descriptor const& d) +{ + void* p = eet_data_read(file, const_cast&>(d).native_handle(), name); + return std::unique_ptr(static_cast(p)); +} + +template +T read(Eet_File* file, const char* name, descriptor const& d) +{ + typename std::aligned_storage::type buffer; + void * p = + ::eet_data_read_cipher_buffer + (file + , const_cast&>(d).native_handle() + , name, 0 + , static_cast(static_cast(&buffer)) + , sizeof(buffer)); + if(p) + { + assert(p == &buffer); + return *static_cast(p); + } + else + throw std::runtime_error(""); +} + +namespace _detail { + +template +inline void _item_fill(O*, ::Eet_Data_Descriptor*, member_desc_info*) {} + +template +inline void _item_fill(O* obj, ::Eet_Data_Descriptor* cls, member_desc_info* offset + , _detail::member_info arg0, FArgs... args) +{ + static_assert(std::is_member_object_pointer::value, ""); + offset->offset = static_cast( static_cast( &(obj ->* arg0.member) )) + - static_cast( static_cast( obj ) ); + offset->name = arg0.name; + _detail::_item_fill(obj, cls, ++offset, args...); +} + +} + +template +typename _detail::descriptor_type +::type + , _detail::member_info, Args... +>::type make_descriptor(const char* name, _detail::member_info a0, Args... args) +{ + typedef F member_pointer; + static_assert(std::is_member_object_pointer::value, ""); + typedef typename _detail::object_type::type object_type; + + typedef typename _detail::descriptor_type + , Args...>::type descriptor_type; + + ::Eet_Data_Descriptor_Class cls + { + EET_DATA_DESCRIPTOR_CLASS_VERSION + , name + , sizeof(object_type) + , { + & _detail::_allocate + , & _detail::_deallocate + } + }; + ::Eet_Data_Descriptor* native_handle = eet_data_descriptor_stream_new(&cls); + if(!native_handle) + throw std::runtime_error(""); + + typename std::aligned_storage::type buffer; + object_type* p = static_cast(static_cast(&buffer)); + + std::array<_detail::member_desc_info, sizeof...(Args)+1> offsets; + _detail::_item_fill(p, native_handle, &offsets[0], a0, args...); + _detail::descriptor_type_register(native_handle, &offsets[0], a0, args...); + + return descriptor_type(native_handle, offsets); +} + +} } + +#endif diff --git a/src/bindings/eet_cxx/eet_composite.hh b/src/bindings/eet_cxx/eet_composite.hh new file mode 100644 index 0000000..2c8f6be --- /dev/null +++ b/src/bindings/eet_cxx/eet_composite.hh @@ -0,0 +1,49 @@ +#ifndef EFL_EET_COMPOSITE_HH_ +#define EFL_EET_COMPOSITE_HH_ + +namespace efl { namespace eet { + +template struct descriptor; + +namespace _detail { + +struct member_desc_info +{ + const char* name; + std::size_t offset; +}; + +template +void descriptor_register_composite_member( ::Eet_Data_Descriptor*, int + , eet::descriptorconst* + , std::integral_constant) +{ +} + +template +void descriptor_register_composite_member( ::Eet_Data_Descriptor* cls, int offset_base + , eet::descriptorconst* descriptor + , std::integral_constant + , typename std::enable_if::type* = 0) +{ + typedef typename std::tuple_element >::type member_type; + eet_data_descriptor_element_add(cls, descriptor->get_member_info()[I].name + , _eet_type::value, EET_G_UNKNOWN + , offset_base + descriptor->get_member_info()[I].offset + , 0, nullptr, nullptr); + + _detail::descriptor_register_composite_member + (cls, offset_base, descriptor, std::integral_constant()); +} + +template +void descriptor_type_register_composite( ::Eet_Data_Descriptor* cls, member_desc_info info + , eet::descriptorconst* descriptor) +{ + _detail::descriptor_register_composite_member::members::value> + (cls, info.offset, descriptor, std::integral_constant()); +} + +} } } + +#endif diff --git a/src/bindings/eet_cxx/eet_fold.hh b/src/bindings/eet_cxx/eet_fold.hh new file mode 100644 index 0000000..7ff19ae --- /dev/null +++ b/src/bindings/eet_cxx/eet_fold.hh @@ -0,0 +1,32 @@ +#ifndef EFL_EET_FOLD_HH_ +#define EFL_EET_FOLD_HH_ + +#include + +namespace efl { namespace eet { + +namespace _mpl { + +template >::value> +struct fold_impl +{ + typedef typename F::template apply::type>::type result; + typedef typename fold_impl::type + , F, result + >::type + type; +}; + +template +struct fold_impl +{ + typedef A0 type; +}; + +template +struct fold : fold_impl +{}; + +} } } + +#endif diff --git a/src/bindings/eet_cxx/eet_register.hh b/src/bindings/eet_cxx/eet_register.hh new file mode 100644 index 0000000..e2a5142 --- /dev/null +++ b/src/bindings/eet_cxx/eet_register.hh @@ -0,0 +1,132 @@ +#ifndef EFL_EET_REGISTER_HH_ +#define EFL_EET_REGISTER_HH_ + +#include +#include + +namespace efl { namespace eet { + +template struct descriptor; + +namespace _detail { + +template +struct member_type; + +template +struct member_type +{ + typedef T type; +}; + +template +struct object_type; + +template +struct object_type +{ + typedef U type; +}; + +template +struct member_info +{ + typedef F member_type; + + const char* name; + F member; + eet::descriptor const* descriptor; +}; + +template +struct member_info +{ + typedef F member_type; + + const char* name; + F member; +}; + +template +void descriptor_type_register_impl + (std::false_type + , ::Eet_Data_Descriptor* cls + , member_desc_info i + , member_info arg0 + , typename std::enable_if + < + !std::is_pointer::type>::value + >::type* = 0) +{ + // composition by value + static_assert(std::is_member_object_pointer::value, ""); + typedef typename _detail::member_type::type member_type; + typedef typename _detail::object_type::type object_type; + static_assert(!std::is_pointer::value, ""); + static_assert(std::is_same::value, ""); + static_assert(std::is_pod::value, ""); + + _detail::descriptor_type_register_composite(cls, i, arg0.descriptor); +} + +template +void descriptor_type_register_impl + (std::false_type + , ::Eet_Data_Descriptor* cls + , member_desc_info i + , member_info arg0 + , typename std::enable_if + < + std::is_pointer::type>::value + >::type* = 0) +{ + // composition by pointer + static_assert(std::is_member_object_pointer::value, ""); + typedef typename _detail::member_type::type pointer_member_type; + typedef typename _detail::object_type::type object_type; + static_assert(std::is_pointer::value, ""); + typedef typename std::remove_pointer::type member_type; + static_assert(std::is_same::value, ""); + + eet_data_descriptor_element_add + (cls, i.name + , EET_T_UNKNOW + , EET_G_UNKNOWN + , i.offset + , 0 + , nullptr + , const_cast*>(arg0.descriptor)->native_handle()); +} + +template +void descriptor_type_register_impl + (std::true_type, ::Eet_Data_Descriptor* cls + , member_desc_info i + , member_info) +{ + static_assert(std::is_member_object_pointer::value, ""); + typedef typename _detail::member_type::type member_type; + typedef typename _detail::object_type::type object_type; + + eet_data_descriptor_element_add(cls, i.name, _eet_type::value, EET_G_UNKNOWN + , i.offset, 0, nullptr, nullptr); +} + +inline void descriptor_type_register( ::Eet_Data_Descriptor*, member_desc_info*) +{ +} + +template +void descriptor_type_register( ::Eet_Data_Descriptor* cls, member_desc_info* i + , member_info a0, FArgs... args) +{ + static_assert(std::is_member_object_pointer::value, ""); + typedef typename _detail::member_type::type member_type; + + _detail::descriptor_type_register_impl(is_eet_primitive(), cls, *i, a0); + _detail::descriptor_type_register(cls, ++i, args...); +} + +} } } + +#endif diff --git a/src/bindings/eet_cxx/eet_tuple.hh b/src/bindings/eet_cxx/eet_tuple.hh new file mode 100644 index 0000000..2fbb395 --- /dev/null +++ b/src/bindings/eet_cxx/eet_tuple.hh @@ -0,0 +1,39 @@ +#ifndef EFL_EET_EET_TUPLE_HH_ +#define EFL_EET_EET_TUPLE_HH_ + +namespace efl { namespace eet { + +namespace _mpl { + +template +struct push_back; + +template