eet-cxx: add implementation for eet C++.
authorFelipe Magno de Almeida <felipe@expertisesolutions.com.br>
Tue, 1 Apr 2014 10:08:07 +0000 (19:08 +0900)
committerCedric BAIL <cedric.bail@free.fr>
Tue, 1 Apr 2014 13:00:13 +0000 (22:00 +0900)
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>
15 files changed:
configure.ac
pc/.gitignore
pc/eet-cxx.pc.in [new file with mode: 0644]
src/Makefile.am
src/Makefile_Eet_Cxx.am [new file with mode: 0644]
src/bindings/eet_cxx/Eet.hh [new file with mode: 0644]
src/bindings/eet_cxx/eet_composite.hh [new file with mode: 0644]
src/bindings/eet_cxx/eet_fold.hh [new file with mode: 0644]
src/bindings/eet_cxx/eet_register.hh [new file with mode: 0644]
src/bindings/eet_cxx/eet_tuple.hh [new file with mode: 0644]
src/bindings/eet_cxx/eet_type.hh [new file with mode: 0644]
src/lib/eet/Eet.h
src/lib/eet/eet_data.c
src/tests/eet_cxx/eet_cxx_suite.cc [new file with mode: 0644]
src/tests/eet_cxx/eet_cxx_test_descriptors.cc [new file with mode: 0644]

index 4001d29..3642b96 100644 (file)
@@ -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
index 658f6cf..ae42f58 100644 (file)
@@ -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 (file)
index 0000000..2412c48
--- /dev/null
@@ -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
index e277678..f9c2497 100644 (file)
@@ -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 (file)
index 0000000..b2381aa
--- /dev/null
@@ -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 (file)
index 0000000..f725c68
--- /dev/null
@@ -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 (file)
index 0000000..2c8f6be
--- /dev/null
@@ -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 (file)
index 0000000..7ff19ae
--- /dev/null
@@ -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 (file)
index 0000000..e2a5142
--- /dev/null
@@ -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 (file)
index 0000000..2fbb395
--- /dev/null
@@ -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 (file)
index 0000000..e12bc98
--- /dev/null
@@ -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
index ab90733..60e58d4 100644 (file)
@@ -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.
index ea51ed0..c92a526 100644 (file)
@@ -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 (file)
index 0000000..26e658b
--- /dev/null
@@ -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 (file)
index 0000000..bc21418
--- /dev/null
@@ -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);
+}