summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>2014-04-01 19:08:07 +0900
committerCedric BAIL <cedric.bail@free.fr>2014-04-01 19:49:09 +0900
commit763c0c79df30ccbdb6ec803ddefa4bd36c176ec3 (patch)
tree076e50c43b9f9784bd707ef974e753a21def1123
parent32aee212a61f0fc8d4cd52cb2a06602d5240ed4d (diff)
downloadefl-763c0c79df30ccbdb6ec803ddefa4bd36c176ec3.tar.gz
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<type> 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 <cedric.bail@free.fr>
-rw-r--r--configure.ac1
-rw-r--r--pc/.gitignore1
-rw-r--r--pc/eet-cxx.pc.in12
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile_Eet_Cxx.am42
-rw-r--r--src/bindings/eet_cxx/Eet.hh214
-rw-r--r--src/bindings/eet_cxx/eet_composite.hh49
-rw-r--r--src/bindings/eet_cxx/eet_fold.hh32
-rw-r--r--src/bindings/eet_cxx/eet_register.hh132
-rw-r--r--src/bindings/eet_cxx/eet_tuple.hh39
-rw-r--r--src/bindings/eet_cxx/eet_type.hh78
-rw-r--r--src/lib/eet/Eet.h37
-rw-r--r--src/lib/eet/eet_data.c38
-rw-r--r--src/tests/eet_cxx/eet_cxx_suite.cc104
-rw-r--r--src/tests/eet_cxx/eet_cxx_test_descriptors.cc231
15 files changed, 1011 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 4001d29e5a..3642b96a65 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 658f6cfff8..ae42f58ef3 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 0000000000..2412c487a3
--- /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 e277678667..f9c2497f4a 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 0000000000..b2381aaeda
--- /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 0000000000..f725c6877f
--- /dev/null
+++ b/src/bindings/eet_cxx/Eet.hh
@@ -0,0 +1,214 @@
+#ifndef EET_HH_
+#define EET_HH_
+
+#include <Eet.h>
+
+#include <eet_type.hh>
+#include <eet_fold.hh>
+#include <eet_register.hh>
+
+#include <type_traits>
+#include <cassert>
+#include <stdexcept>
+
+#include <iostream>
+#include <array>
+
+namespace efl { namespace eet { namespace _detail {
+
+template <typename T>
+void* _allocate( ::size_t size )
+{
+ assert(size == sizeof(T));
+ (void)size;
+ return new T();
+}
+
+template <typename T>
+void _deallocate( void* p )
+{
+ delete static_cast<T*>(p);
+}
+
+template <typename T, typename... Args>
+struct descriptor_type
+{
+ struct push_back
+ {
+ template <typename A, typename B>
+ struct apply : _mpl::push_back<A, typename _detail::member_type<typename B::member_type>::type> {};
+ };
+
+ typedef typename _mpl::fold< std::tuple<Args...>, push_back
+ , descriptor<T> >::type type;
+};
+
+}
+
+#define EET_CXX_MEMBER(C, I) ::efl::eet::type(#I, &C::I)
+
+template <typename F>
+_detail::member_info<F, void> type(const char* name, F f)
+{
+ typedef typename _detail::member_type<F>::type member_type;
+ static_assert(is_eet_primitive<member_type>::value, "");
+ static_assert(std::is_member_pointer<F>::value, "");
+ return _detail::member_info<F, void>{name, f};
+}
+
+template <typename F, typename U, typename... Args>
+_detail::member_info<F, U, Args...> type(const char* name, F f, descriptor<U, Args...> const& descriptor)
+{
+ typedef typename _detail::member_type<F>::type member_type;
+ static_assert(!is_eet_primitive<member_type>::value, "");
+ static_assert(std::is_member_pointer<F>::value, "");
+ return _detail::member_info<F, U, Args...>{name, f, &descriptor};
+}
+
+struct eet_init
+{
+ eet_init()
+ {
+ ::eet_init();
+ }
+ ~eet_init()
+ {
+ ::eet_shutdown();
+ }
+};
+
+template <typename T, typename... Args>
+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<std::size_t, sizeof...(Args)> members;
+
+ std::array<_detail::member_desc_info, sizeof...(Args)> get_member_info() const { return _member_info; }
+private:
+ ::Eet_Data_Descriptor* _descriptor;
+ typedef descriptor<T, Args...> _self_type;
+ descriptor(descriptor const&) = delete;
+ descriptor& operator=(descriptor const&) = delete;
+ std::array<_detail::member_desc_info, sizeof...(Args)> _member_info;
+};
+
+template <typename T, typename... Args>
+std::unique_ptr<T> read_by_ptr(Eet_File* file, const char* name, descriptor<T, Args...> const& d)
+{
+ void* p = eet_data_read(file, const_cast<descriptor<T, Args...>&>(d).native_handle(), name);
+ return std::unique_ptr<T>(static_cast<T*>(p));
+}
+
+template <typename T, typename... Args>
+T read(Eet_File* file, const char* name, descriptor<T, Args...> const& d)
+{
+ typename std::aligned_storage<sizeof(T), alignof(T)>::type buffer;
+ void * p =
+ ::eet_data_read_cipher_buffer
+ (file
+ , const_cast<descriptor<T, Args...>&>(d).native_handle()
+ , name, 0
+ , static_cast<char*>(static_cast<void*>(&buffer))
+ , sizeof(buffer));
+ if(p)
+ {
+ assert(p == &buffer);
+ return *static_cast<T*>(p);
+ }
+ else
+ throw std::runtime_error("");
+}
+
+namespace _detail {
+
+template <typename O>
+inline void _item_fill(O*, ::Eet_Data_Descriptor*, member_desc_info*) {}
+
+template <typename O, typename F, typename D, typename... Args, typename... FArgs>
+inline void _item_fill(O* obj, ::Eet_Data_Descriptor* cls, member_desc_info* offset
+ , _detail::member_info<F, D, Args...> arg0, FArgs... args)
+{
+ static_assert(std::is_member_object_pointer<F>::value, "");
+ offset->offset = static_cast<char*>( static_cast<void*>( &(obj ->* arg0.member) ))
+ - static_cast<char*>( static_cast<void*>( obj ) );
+ offset->name = arg0.name;
+ _detail::_item_fill(obj, cls, ++offset, args...);
+}
+
+}
+
+template <typename F, typename D, typename... OArgs, typename... Args>
+typename _detail::descriptor_type
+<typename _detail::object_type<F>::type
+ , _detail::member_info<F, D, OArgs...>, Args...
+>::type make_descriptor(const char* name, _detail::member_info<F, D, OArgs...> a0, Args... args)
+{
+ typedef F member_pointer;
+ static_assert(std::is_member_object_pointer<member_pointer>::value, "");
+ typedef typename _detail::object_type<member_pointer>::type object_type;
+
+ typedef typename _detail::descriptor_type
+ <object_type, _detail::member_info<F, D, OArgs...>, Args...>::type descriptor_type;
+
+ ::Eet_Data_Descriptor_Class cls
+ {
+ EET_DATA_DESCRIPTOR_CLASS_VERSION
+ , name
+ , sizeof(object_type)
+ , {
+ & _detail::_allocate<object_type>
+ , & _detail::_deallocate<object_type>
+ }
+ };
+ ::Eet_Data_Descriptor* native_handle = eet_data_descriptor_stream_new(&cls);
+ if(!native_handle)
+ throw std::runtime_error("");
+
+ typename std::aligned_storage<sizeof(object_type), alignof(object_type)>::type buffer;
+ object_type* p = static_cast<object_type*>(static_cast<void*>(&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 0000000000..2c8f6bea99
--- /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 <typename, typename...> struct descriptor;
+
+namespace _detail {
+
+struct member_desc_info
+{
+ const char* name;
+ std::size_t offset;
+};
+
+template <std::size_t E, typename U, typename... Types>
+void descriptor_register_composite_member( ::Eet_Data_Descriptor*, int
+ , eet::descriptor<U, Types...>const*
+ , std::integral_constant<std::size_t, E>)
+{
+}
+
+template <std::size_t E, typename U, typename... Types, std::size_t I>
+void descriptor_register_composite_member( ::Eet_Data_Descriptor* cls, int offset_base
+ , eet::descriptor<U, Types...>const* descriptor
+ , std::integral_constant<std::size_t, I>
+ , typename std::enable_if<E != I>::type* = 0)
+{
+ typedef typename std::tuple_element<I, std::tuple<Types...> >::type member_type;
+ eet_data_descriptor_element_add(cls, descriptor->get_member_info()[I].name
+ , _eet_type<member_type>::value, EET_G_UNKNOWN
+ , offset_base + descriptor->get_member_info()[I].offset
+ , 0, nullptr, nullptr);
+
+ _detail::descriptor_register_composite_member<E>
+ (cls, offset_base, descriptor, std::integral_constant<std::size_t, I+1>());
+}
+
+template <typename U, typename...Types>
+void descriptor_type_register_composite( ::Eet_Data_Descriptor* cls, member_desc_info info
+ , eet::descriptor<U, Types...>const* descriptor)
+{
+ _detail::descriptor_register_composite_member<eet::descriptor<U, Types...>::members::value>
+ (cls, info.offset, descriptor, std::integral_constant<std::size_t, 0u>());
+}
+
+} } }
+
+#endif
diff --git a/src/bindings/eet_cxx/eet_fold.hh b/src/bindings/eet_cxx/eet_fold.hh
new file mode 100644
index 0000000000..7ff19aee1c
--- /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 <eet_tuple.hh>
+
+namespace efl { namespace eet {
+
+namespace _mpl {
+
+template <typename T, typename F, typename A0, bool B = std::is_same<T, std::tuple<> >::value>
+struct fold_impl
+{
+ typedef typename F::template apply<A0, typename std::tuple_element<0, T>::type>::type result;
+ typedef typename fold_impl<typename pop_front<T>::type
+ , F, result
+ >::type
+ type;
+};
+
+template <typename T, typename F, typename A0>
+struct fold_impl<T, F, A0, true>
+{
+ typedef A0 type;
+};
+
+template <typename T, typename F, typename A0>
+struct fold : fold_impl<T, F, A0>
+{};
+
+} } }
+
+#endif
diff --git a/src/bindings/eet_cxx/eet_register.hh b/src/bindings/eet_cxx/eet_register.hh
new file mode 100644
index 0000000000..e2a5142ca6
--- /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 <eet_type.hh>
+#include <eet_composite.hh>
+
+namespace efl { namespace eet {
+
+template <typename, typename...> struct descriptor;
+
+namespace _detail {
+
+template <typename T>
+struct member_type;
+
+template <typename T, typename U>
+struct member_type<T(U::*)>
+{
+ typedef T type;
+};
+
+template <typename T>
+struct object_type;
+
+template <typename T, typename U>
+struct object_type<T(U::*)>
+{
+ typedef U type;
+};
+
+template <typename F, typename T, typename... Args>
+struct member_info
+{
+ typedef F member_type;
+
+ const char* name;
+ F member;
+ eet::descriptor<T, Args...> const* descriptor;
+};
+
+template <typename F>
+struct member_info<F, void>
+{
+ typedef F member_type;
+
+ const char* name;
+ F member;
+};
+
+template <typename F, typename U, typename... Args>
+void descriptor_type_register_impl
+ (std::false_type
+ , ::Eet_Data_Descriptor* cls
+ , member_desc_info i
+ , member_info<F, U, Args...> arg0
+ , typename std::enable_if
+ <
+ !std::is_pointer<typename _detail::member_type<F>::type>::value
+ >::type* = 0)
+{
+ // composition by value
+ static_assert(std::is_member_object_pointer<F>::value, "");
+ typedef typename _detail::member_type<F>::type member_type;
+ typedef typename _detail::object_type<F>::type object_type;
+ static_assert(!std::is_pointer<member_type>::value, "");
+ static_assert(std::is_same<member_type, U>::value, "");
+ static_assert(std::is_pod<member_type>::value, "");
+
+ _detail::descriptor_type_register_composite(cls, i, arg0.descriptor);
+}
+
+template <typename F, typename U, typename... Args>
+void descriptor_type_register_impl
+ (std::false_type
+ , ::Eet_Data_Descriptor* cls
+ , member_desc_info i
+ , member_info<F, U, Args...> arg0
+ , typename std::enable_if
+ <
+ std::is_pointer<typename _detail::member_type<F>::type>::value
+ >::type* = 0)
+{
+ // composition by pointer
+ static_assert(std::is_member_object_pointer<F>::value, "");
+ typedef typename _detail::member_type<F>::type pointer_member_type;
+ typedef typename _detail::object_type<F>::type object_type;
+ static_assert(std::is_pointer<pointer_member_type>::value, "");
+ typedef typename std::remove_pointer<pointer_member_type>::type member_type;
+ static_assert(std::is_same<member_type, U>::value, "");
+
+ eet_data_descriptor_element_add
+ (cls, i.name
+ , EET_T_UNKNOW
+ , EET_G_UNKNOWN
+ , i.offset
+ , 0
+ , nullptr
+ , const_cast<descriptor<U, Args...>*>(arg0.descriptor)->native_handle());
+}
+
+template <typename F>
+void descriptor_type_register_impl
+ (std::true_type, ::Eet_Data_Descriptor* cls
+ , member_desc_info i
+ , member_info<F, void>)
+{
+ static_assert(std::is_member_object_pointer<F>::value, "");
+ typedef typename _detail::member_type<F>::type member_type;
+ typedef typename _detail::object_type<F>::type object_type;
+
+ eet_data_descriptor_element_add(cls, i.name, _eet_type<member_type>::value, EET_G_UNKNOWN
+ , i.offset, 0, nullptr, nullptr);
+}
+
+inline void descriptor_type_register( ::Eet_Data_Descriptor*, member_desc_info*)
+{
+}
+
+template <typename F, typename D, typename... Args, typename... FArgs>
+void descriptor_type_register( ::Eet_Data_Descriptor* cls, member_desc_info* i
+ , member_info<F, D, Args...> a0, FArgs... args)
+{
+ static_assert(std::is_member_object_pointer<F>::value, "");
+ typedef typename _detail::member_type<F>::type member_type;
+
+ _detail::descriptor_type_register_impl(is_eet_primitive<member_type>(), 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 0000000000..2fbb3950b5
--- /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 <typename A, typename... Args>
+struct push_back;
+
+template <template <typename... Args> class C, typename... Args, typename... AArgs>
+struct push_back<C<Args...>, AArgs...>
+{
+ typedef C<Args..., AArgs...> type;
+};
+
+template <typename A, typename... Args>
+struct push_front;
+
+template <template <typename... Args> class C, typename... Args, typename... AArgs>
+struct push_front<C<Args...>, AArgs...>
+{
+ typedef C<Args..., AArgs...> type;
+};
+
+template <typename A>
+struct pop_front;
+
+template <template <typename...> class C, typename T, typename... Args>
+struct pop_front<C<T, Args...> >
+{
+ typedef C<Args...> type;
+};
+
+}
+
+} }
+
+#endif
diff --git a/src/bindings/eet_cxx/eet_type.hh b/src/bindings/eet_cxx/eet_type.hh
new file mode 100644
index 0000000000..e12bc982cf
--- /dev/null
+++ b/src/bindings/eet_cxx/eet_type.hh
@@ -0,0 +1,78 @@
+#ifndef _EET_TYPE_HH
+#define _EET_TYPE_HH
+
+#include <Eet.h>
+#include <Eina.hh>
+
+#include <type_traits>
+
+namespace efl { namespace eet {
+
+template <typename T>
+struct _eet_type;
+
+template <>
+struct _eet_type<char> : std::integral_constant<int, EET_T_CHAR>
+{};
+
+template <>
+struct _eet_type<short> : std::integral_constant<int, EET_T_SHORT>
+{};
+
+template <>
+struct _eet_type<int> : std::integral_constant<int, EET_T_INT>
+{};
+
+template <>
+struct _eet_type<long long> : std::integral_constant<int, EET_T_LONG_LONG>
+{};
+
+template <>
+struct _eet_type<float> : std::integral_constant<int, EET_T_FLOAT>
+{};
+
+template <>
+struct _eet_type<double> : std::integral_constant<int, EET_T_DOUBLE>
+{};
+
+template <>
+struct _eet_type<unsigned char> : std::integral_constant<int, EET_T_UCHAR>
+{};
+
+template <>
+struct _eet_type<unsigned short> : std::integral_constant<int, EET_T_USHORT>
+{};
+
+template <>
+struct _eet_type<unsigned int> : std::integral_constant<int, EET_T_UINT>
+{};
+
+template <>
+struct _eet_type<unsigned long long> : std::integral_constant<int, EET_T_ULONG_LONG>
+{};
+
+template <>
+struct _eet_type<char*> : std::integral_constant<int, EET_T_STRING>
+{};
+
+template <>
+struct _eet_type<void*> : std::integral_constant<int, EET_T_NULL>
+{};
+
+template <>
+struct _eet_type<eina::value> : std::integral_constant<int, EET_T_VALUE>
+{};
+
+template <typename T>
+struct _void { typedef void type; };
+
+template <typename T, typename Enabler = void>
+struct is_eet_primitive : std::false_type {};
+
+template <typename T>
+struct is_eet_primitive<T, typename _void<typename _eet_type<T>::type>::type>
+ : std::true_type {};
+
+} }
+
+#endif
diff --git a/src/lib/eet/Eet.h b/src/lib/eet/Eet.h
index ab907335cc..60e58d4541 100644
--- a/src/lib/eet/Eet.h
+++ b/src/lib/eet/Eet.h
@@ -3528,6 +3528,43 @@ eet_data_read_cipher(Eet_File *ef,
const char *cipher_key);
/**
+ * Read a data structure from an eet file and decodes it into a buffer using a cipher,
+ * @param ef The eet file handle to read from.
+ * @param edd The data descriptor handle to use when decoding.
+ * @param name The key the data is stored under in the eet file.
+ * @param cipher_key The key to use as cipher.
+ * @param buffer Buffer
+ * @return A pointer to buffer if successful and NULL on error.
+ *
+ * This function decodes a data structure stored in an eet file, returning
+ * a pointer to it if it decoded successfully, or NULL on failure. This
+ * can save a programmer dozens of hours of work in writing configuration
+ * file parsing and writing code, as eet does all that work for the program
+ * and presents a program-friendly data structure, just as the programmer
+ * likes. Eet can handle members being added or deleted from the data in
+ * storage and safely zero-fills unfilled members if they were not found
+ * in the data. It checks sizes and headers whenever it reads data, allowing
+ * the programmer to not worry about corrupt data.
+ *
+ * Once a data structure has been described by the programmer with the
+ * fields they wish to save or load, storing or retrieving a data structure
+ * from an eet file, or from a chunk of memory is as simple as a single
+ * function call.
+ *
+ * @see eet_data_read_cipher()
+ *
+ * @since 1.10.0
+ * @ingroup Eet_Data_Cipher_Group
+ */
+EAPI void *
+eet_data_read_cipher_buffer(Eet_File *ef,
+ Eet_Data_Descriptor *edd,
+ const char *name,
+ const char *cipher_key,
+ char *buffer,
+ int buffer_size);
+
+/**
* Read a data structure from an eet extended attribute and decodes it using a cipher.
* @param filename The file to extract the extended attribute from.
* @param attribute The attribute to get the data from.
diff --git a/src/lib/eet/eet_data.c b/src/lib/eet/eet_data.c
index ea51ed0f4a..c92a526819 100644
--- a/src/lib/eet/eet_data.c
+++ b/src/lib/eet/eet_data.c
@@ -2284,6 +2284,44 @@ eet_data_read_cipher(Eet_File *ef,
return data_dec;
}
+EAPI void *
+eet_data_read_cipher_buffer(Eet_File *ef,
+ Eet_Data_Descriptor *edd,
+ const char *name,
+ const char *cipher_key,
+ char* buffer,
+ int buffer_size)
+{
+ const Eet_Dictionary *ed = NULL;
+ const void *data = NULL;
+ void *data_dec;
+ Eet_Free_Context context;
+ int required_free = 0;
+ int size;
+
+ ed = eet_dictionary_get(ef);
+
+ if (!cipher_key)
+ data = eet_read_direct(ef, name, &size);
+
+ if (!data)
+ {
+ required_free = 1;
+ data = eet_read_cipher(ef, name, &size, cipher_key);
+ if (!data)
+ return NULL;
+ }
+
+ eet_free_context_init(&context);
+ data_dec = _eet_data_descriptor_decode(&context, ed, edd, data, size, buffer, buffer_size);
+ eet_free_context_shutdown(&context);
+
+ if (required_free)
+ free((void *)data);
+
+ return data_dec;
+}
+
EAPI Eet_Node *
eet_data_node_read_cipher(Eet_File *ef,
const char *name,
diff --git a/src/tests/eet_cxx/eet_cxx_suite.cc b/src/tests/eet_cxx/eet_cxx_suite.cc
new file mode 100644
index 0000000000..26e658b803
--- /dev/null
+++ b/src/tests/eet_cxx/eet_cxx_suite.cc
@@ -0,0 +1,104 @@
+
+#include "Eet.hh"
+#include <Eina.h>
+
+#include <cassert>
+#include <algorithm>
+
+#include <check.h>
+
+void eet_test_descriptors(TCase* tc);
+
+typedef struct _Eet_Test_Case Eet_Test_Case;
+struct _Eet_Test_Case
+{
+ const char *test_case;
+ void (*build)(TCase *tc);
+};
+
+static const Eet_Test_Case etc[] = {
+ { "Descriptors", eet_test_descriptors },
+ { NULL, NULL }
+};
+
+static void
+_list_tests(void)
+{
+ const Eet_Test_Case *itr = etc;
+ fputs("Available Test Cases:\n", stderr);
+ for (; itr->test_case; itr++)
+ fprintf(stderr, "\t%s\n", itr->test_case);
+}
+
+static Eina_Bool
+_use_test(int argc, const char **argv, const char *test_case)
+{
+ if (argc < 1)
+ return 1;
+
+ for (; argc > 0; argc--, argv++)
+ if (strcmp(test_case, *argv) == 0)
+ return 1;
+
+ return 0;
+}
+
+Suite *
+eet_build_suite(int argc, const char **argv)
+{
+ TCase *tc;
+ Suite *s;
+ int i;
+
+ s = suite_create("Eet C++");
+
+ for (i = 0; etc[i].test_case; ++i)
+ {
+ if (!_use_test(argc, argv, etc[i].test_case))
+ continue;
+
+ tc = tcase_create(etc[i].test_case);
+ tcase_set_timeout(tc, 0);
+
+ etc[i].build(tc);
+ suite_add_tcase(s, tc);
+ }
+
+ return s;
+}
+
+int main(int argc, char* argv[])
+{
+ Suite *s;
+ SRunner *sr;
+ int i, failed_count;
+
+ for (i = 1; i < argc; i++)
+ if ((strcmp(argv[i], "-h") == 0) ||
+ (strcmp(argv[i], "--help") == 0))
+ {
+ fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n",
+ argv[0]);
+ _list_tests();
+ return 0;
+ }
+ else if ((strcmp(argv[i], "-l") == 0) ||
+ (strcmp(argv[i], "--list") == 0))
+ {
+ _list_tests();
+ return 0;
+ }
+
+ putenv(const_cast<char*>("EFL_RUN_IN_TREE=1"));
+
+ s = eet_build_suite(argc - 1, (const char **)argv + 1);
+ sr = srunner_create(s);
+
+ srunner_set_xml(sr, TESTS_BUILD_DIR "/check-results.xml");
+
+ srunner_run_all(sr, CK_ENV);
+ failed_count = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (failed_count == 0) ? 0 : 255;
+}
diff --git a/src/tests/eet_cxx/eet_cxx_test_descriptors.cc b/src/tests/eet_cxx/eet_cxx_test_descriptors.cc
new file mode 100644
index 0000000000..bc214181d6
--- /dev/null
+++ b/src/tests/eet_cxx/eet_cxx_test_descriptors.cc
@@ -0,0 +1,231 @@
+
+#include "Eet.hh"
+
+#include <algorithm>
+
+#include <iostream>
+
+#include <check.h>
+
+struct pod_type
+{
+ int i;
+ char c;
+};
+
+START_TEST(eet_cxx_descriptors)
+{
+ efl::eet::eet_init init;
+
+ auto d = efl::eet::make_descriptor
+ ("pod_type"
+ , efl::eet::type("i", &pod_type::i)
+ , efl::eet::type("c", &pod_type::c));
+ static_assert(std::is_same<efl::eet::descriptor<pod_type, int, char>, decltype(d)>::value, "");
+
+ Eet_File* file = eet_open("/tmp/eet_file_test.eet", EET_FILE_MODE_READ_WRITE);
+ ck_assert(file != 0);
+
+ pod_type pod = {1, 2};
+
+ int s = eet_data_write(file, d.native_handle(), "pod", &pod, true);
+ std::cout << "bytes written " << s << std::endl;
+ ck_assert(s > 0);
+ eet_sync(file);
+ auto p = efl::eet::read_by_ptr(file, "pod", d);
+ ck_assert(p != 0);
+ ck_assert(p->i == 1);
+ ck_assert(p->c == 2);
+
+ eet_close(file);
+}
+END_TEST
+
+int constructors_called = 0
+ , destructors_called = 0;
+
+struct non_pod
+{
+ non_pod() : i(10)
+ {
+ ++constructors_called;
+ }
+ non_pod(non_pod const& other)
+ : i(other.i)
+ {
+ ++constructors_called;
+ }
+ ~non_pod()
+ {
+ ++destructors_called;
+ }
+
+ int i;
+};
+
+START_TEST(eet_cxx_descriptors_non_pod)
+{
+ efl::eet::eet_init init;
+
+ auto d = efl::eet::make_descriptor
+ ("pod_type", EET_CXX_MEMBER(non_pod, i));
+ static_assert(std::is_same<efl::eet::descriptor<non_pod, int>, decltype(d)>::value, "");
+
+ {
+ Eet_File* file = eet_open("/tmp/eet_file_test.eet", EET_FILE_MODE_READ_WRITE);
+ ck_assert(file != 0);
+
+ ::non_pod non_pod;
+
+ int s = eet_data_write(file, d.native_handle(), "non_pod", &non_pod, true);
+ std::cout << "bytes written " << s << std::endl;
+ ck_assert(s > 0);
+ eet_sync(file);
+ auto p = efl::eet::read_by_ptr(file, "non_pod", d);
+ ck_assert(p != 0);
+ ck_assert(p->i == 10);
+
+ auto v = efl::eet::read(file, "non_pod", d);
+ ck_assert(v.i == 10);
+
+ eet_close(file);
+ }
+
+ std::cout << "constructors called for non pod: " << constructors_called
+ << " destructors called for non pod: " << destructors_called << std::endl;
+
+ ck_assert(constructors_called == destructors_called);
+}
+END_TEST
+
+struct pod_composited
+{
+ pod_type* member;
+};
+
+struct pod_composited_with_non_pod
+{
+ non_pod* member;
+};
+
+struct pod_value_composited
+{
+ pod_type member;
+};
+
+START_TEST(eet_cxx_descriptors_composition)
+{
+ efl::eet::eet_init init;
+
+ auto pod_descriptor = efl::eet::make_descriptor
+ ("pod_type"
+ , efl::eet::type("i", &pod_type::i)
+ , efl::eet::type("c", &pod_type::c));
+ static_assert(std::is_same<efl::eet::descriptor<pod_type, int, char>
+ , decltype(pod_descriptor)>::value, "");
+
+ auto non_pod_descriptor = efl::eet::make_descriptor
+ ("non_pod"
+ , efl::eet::type("i", &non_pod::i));
+ static_assert(std::is_same<efl::eet::descriptor<non_pod, int>
+ , decltype(non_pod_descriptor)>::value, "");
+
+ {
+ auto d = efl::eet::make_descriptor
+ ("pod_composited", efl::eet::type("pod_composited", &pod_composited::member, pod_descriptor));
+ static_assert(std::is_same<efl::eet::descriptor<pod_composited, pod_type*>, decltype(d)>::value, "");
+
+ Eet_File* file = eet_open("/tmp/eet_file_test.eet", EET_FILE_MODE_READ_WRITE);
+ ck_assert(file != 0);
+
+ ::pod_composited pod_composited {new pod_type{5, 'a'}};
+
+ int s = eet_data_write(file, d.native_handle(), "foo", &pod_composited, false);
+ ck_assert(s > 0);
+ eet_sync(file);
+ auto p = efl::eet::read_by_ptr(file, "foo", d);
+ ck_assert(p != 0);
+ ck_assert(p->member->i == 5);
+ ck_assert(p->member->c == 'a');
+
+ delete p->member;
+
+ auto v = efl::eet::read(file, "foo", d);
+ ck_assert(v.member->i == 5);
+ ck_assert(v.member->c == 'a');
+
+ delete v.member;
+
+ eet_close(file);
+ }
+
+ {
+ auto d = efl::eet::make_descriptor
+ ("pod_composited_with_non_pod", efl::eet::type("pod_composited_with_non_pod", &pod_composited_with_non_pod::member, non_pod_descriptor));
+ static_assert(std::is_same<efl::eet::descriptor<pod_composited_with_non_pod, non_pod*>, decltype(d)>::value, "");
+
+ Eet_File* file = eet_open("/tmp/eet_file_test.eet", EET_FILE_MODE_READ_WRITE);
+ ck_assert(file != 0);
+
+ ::pod_composited_with_non_pod pod_composited_with_non_pod {new non_pod};
+
+ int s = eet_data_write(file, d.native_handle(), "foo", &pod_composited_with_non_pod, false);
+ ck_assert(s > 0);
+ eet_sync(file);
+ auto p = efl::eet::read_by_ptr(file, "foo", d);
+ ck_assert(p != 0);
+ ck_assert(p->member->i == 10);
+
+ delete p->member;
+
+ auto v = efl::eet::read(file, "foo", d);
+ ck_assert(v.member->i == 10);
+
+ delete v.member;
+
+ eet_close(file);
+
+ delete pod_composited_with_non_pod.member;
+ }
+
+ std::cout << "constructors called for non pod: " << constructors_called
+ << " destructors called for non pod: " << destructors_called << std::endl;
+
+ ck_assert(constructors_called == destructors_called);
+
+ {
+ auto d = efl::eet::make_descriptor
+ ("pod_value_composited", efl::eet::type("member"
+ , &pod_value_composited::member, pod_descriptor));
+ static_assert(std::is_same<efl::eet::descriptor<pod_value_composited, pod_type>, decltype(d)>::value, "");
+
+ Eet_File* file = eet_open("/tmp/eet_file_test.eet", EET_FILE_MODE_READ_WRITE);
+ ck_assert(file != 0);
+
+ ::pod_value_composited pod_value_composited {{5, 'a'}};
+
+ int s = eet_data_write(file, d.native_handle(), "foo", &pod_value_composited, false);
+ ck_assert(s > 0);
+ eet_sync(file);
+ auto p = efl::eet::read_by_ptr(file, "foo", d);
+ ck_assert(p != 0);
+ ck_assert(p->member.i == 5);
+ ck_assert(p->member.c == 'a');
+
+ auto v = efl::eet::read(file, "foo", d);
+ ck_assert(v.member.i == 5);
+ ck_assert(v.member.c == 'a');
+
+ eet_close(file);
+ }
+
+}
+END_TEST
+
+void
+eet_test_descriptors(TCase* tc)
+{
+ tcase_add_test(tc, eet_cxx_descriptors);
+ tcase_add_test(tc, eet_cxx_descriptors_non_pod);
+ tcase_add_test(tc, eet_cxx_descriptors_composition);
+}