forked from enlightenment/efl
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>
This commit is contained in:
parent
b218c13fb7
commit
ab3eb4b2d3
|
@ -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
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
/efreet.pc
|
||||
/eina.pc
|
||||
/eina-cxx.pc
|
||||
/eet-cxx.pc
|
||||
/eio.pc
|
||||
/eldbus.pc
|
||||
/embryo.pc
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -3527,6 +3527,43 @@ eet_data_read_cipher(Eet_File *ef,
|
|||
const char *name,
|
||||
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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue