diff options
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | pc/.gitignore | 1 | ||||
-rw-r--r-- | pc/eet-cxx.pc.in | 12 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/Makefile_Eet_Cxx.am | 42 | ||||
-rw-r--r-- | src/bindings/eet_cxx/Eet.hh | 214 | ||||
-rw-r--r-- | src/bindings/eet_cxx/eet_composite.hh | 49 | ||||
-rw-r--r-- | src/bindings/eet_cxx/eet_fold.hh | 32 | ||||
-rw-r--r-- | src/bindings/eet_cxx/eet_register.hh | 132 | ||||
-rw-r--r-- | src/bindings/eet_cxx/eet_tuple.hh | 39 | ||||
-rw-r--r-- | src/bindings/eet_cxx/eet_type.hh | 78 | ||||
-rw-r--r-- | src/lib/eet/Eet.h | 37 | ||||
-rw-r--r-- | src/lib/eet/eet_data.c | 38 | ||||
-rw-r--r-- | src/tests/eet_cxx/eet_cxx_suite.cc | 104 | ||||
-rw-r--r-- | src/tests/eet_cxx/eet_cxx_test_descriptors.cc | 231 |
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); +} |