Newer
Older
WickedDocs / Serializing / test.cpp
#include <type_traits>
#include <cstdint>
#include <cctype>
#include <vector>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include "StackTrace.h"


// Some basic types that should build serializable structures from
template<typename T>
using Array      = std::vector<T>;
using Boolean    = bool;
using Byte       = uint8_t;
using Char       = int8_t;
using Unsigned32 = uint32_t;
using Unsigned64 = uint64_t;
using Integer32  = int32_t;
using Integer64  = int64_t;
using Float32    = float;
using Float64    = double;
using String     = std::string;
// discourage 16bit types, CPUs aren't so efficient at these
// TODO: enums

/*
 
   about enums:
   
        Looks like C++17 might make reflection of enums nice.
            http://aantron.github.io/better-enums/demo/C++17ReflectionProposal.html
        In the mean time, something like this gets close with the use of an ugly macro where the enums are declared
        however it provides similar syntax to what C++17 may have for using the reflection
            http://melpon.org/wandbox/permlink/QelcwZNLi4gIx8Ux
 
 */

struct EnumBaseValue
{
  Integer32   id;
  String      name;
};


struct EnumBase
{
  String                name;
  Array<EnumBaseValue>  values;
};


class VisitorBase
{
public:
  virtual ~VisitorBase() {}
  virtual void Enter(const char* name) = 0;
  virtual void Exit(const char* name) = 0;

  std::string quoted(const char* name)
  {
    return std::string("\"" + std::string(name) + "\"");
  }

  std::string indent(int spaces)
  {
    return std::string(spaces*2, ' ');
  }
};


class Serializer : public VisitorBase
{
public:
  virtual const std::string& Output() = 0;
  virtual void Reset() = 0;
};


class Deserializer : public VisitorBase
{
public:
  virtual void Reset(const std::string& a_input) = 0;
};



#include "XMLVisitor.h"
#include "JSONVisitor.h"




struct Person
{
  Boolean        m_bool;
  Byte           m_uint8;
  Char           m_int8;
  Unsigned32     m_uint32;
  Unsigned64     m_uint64;
  Integer32      m_int32;
  Integer64      m_int64;
  Float32        m_flt32;
  Float64        m_flt64;

  Integer32      id;
  String         name;
  Array<String>  email;
  Array<String>  phoneNumbers;

  // This can do both the serializing and de-serializing
  // This might be good to have generated, but possibly being more explicit could be better too
  // Also note the members could be private and this will still work
  template <class V>
  void Visit(V& v)
  {
    v.Enter("person");
    v.Visit("id",id);
    v.Visit("name",name);
    v.Visit("email",email);
    v.Visit("numbers",phoneNumbers);
    v.Exit("person");
  }
};


/*
struct Employer
{
  String  name;
  
};
*/


struct Property
{
  Property() : m_type(PT_Invalid) {}
  ~Property() {}

  explicit Property(Boolean    a_bool  ) : m_type(PT_Boolean   ) { m_basicType.m_bool   = a_bool  ; }
  explicit Property(Byte       a_uint8 ) : m_type(PT_Byte      ) { m_basicType.m_uint8  = a_uint8 ; }
  explicit Property(Char       a_int8  ) : m_type(PT_Char      ) { m_basicType.m_int8   = a_int8  ; }
  explicit Property(Unsigned32 a_uint32) : m_type(PT_Unsigned32) { m_basicType.m_uint32 = a_uint32; }
  explicit Property(Unsigned64 a_uint64) : m_type(PT_Unsigned64) { m_basicType.m_uint64 = a_uint64; }
  explicit Property(Integer32  a_int32 ) : m_type(PT_Integer32 ) { m_basicType.m_int32  = a_int32 ; }
  explicit Property(Integer64  a_int64 ) : m_type(PT_Integer64 ) { m_basicType.m_int64  = a_int64 ; }
  explicit Property(Float32    a_flt32 ) : m_type(PT_Float32   ) { m_basicType.m_flt32  = a_flt32 ; }
  explicit Property(Float64    a_flt64 ) : m_type(PT_Float64   ) { m_basicType.m_flt64  = a_flt64 ; }
  explicit Property(const Array<Property>& a_array ) : m_type(PT_Array ) { m_array      = a_array ; }
  explicit Property(const String&          a_string) : m_type(PT_String) { m_string     = a_string; }
  explicit Property(const char*            a_string) : m_type(PT_String) { m_string     = a_string; }

  enum PropertyType
  {
    // Uninitialize state
    PT_Invalid    = 0,
    // Basic types
    PT_Boolean    = 1, 
    PT_Byte       = 2, 
    PT_Char       = 3, 
    PT_Unsigned32 = 4,
    PT_Unsigned64 = 5,
    PT_Integer32  = 6, 
    PT_Integer64  = 7, 
    PT_Float32    = 8, 
    PT_Float64    = 9, 
    // Complex types
    PT_Array      = 10,
    PT_String     = 11,
  };

  PropertyType     m_type;

  union {
    Boolean        m_bool;
    Byte           m_uint8;
    Char           m_int8;
    Unsigned32     m_uint32;
    Unsigned64     m_uint64;
    Integer32      m_int32;
    Integer64      m_int64;
    Float32        m_flt32;
    Float64        m_flt64;
  } m_basicType;

  Array<Property>  m_array;
  String           m_string;

  // This can do both the serializing and de-serializing
  // This might be good to have generated, but possibly being more explicit could be better too
  // Also note the members could be private and this will still work
  template <class V>
  void Visit(V& v)
  {
    v.Enter("Property");
    Integer32 t = m_type;
    v.Visit("type", t);
    switch (m_type)
    {
      case PT_Boolean:
        v.Visit("value", m_basicType.m_bool); break;
      case PT_Byte:
        v.Visit("value", m_basicType.m_uint8); break;
      case PT_Char:
        v.Visit("value", m_basicType.m_int8); break;
      case PT_Unsigned32:
        v.Visit("value", m_basicType.m_uint32); break;
      case PT_Unsigned64:
        v.Visit("value", m_basicType.m_uint64); break;
      case PT_Integer32:
        v.Visit("value", m_basicType.m_int32); break;
      case PT_Integer64:
        v.Visit("value", m_basicType.m_int64); break;
      case PT_Float32:
        v.Visit("value", m_basicType.m_flt32); break;
      case PT_Float64:
        v.Visit("value", m_basicType.m_flt64); break;
      case PT_Array:
        v.Visit("value", m_array); break;
      case PT_String:
        v.Visit("value", m_string); break;
    }
    v.Exit("Property");
  }
};


struct f_any
{
  f_any() : ptr() {}
  ~f_any() { delete ptr; }
  bool valid() const { return ptr != 0; }
  void f() { assert(ptr); ptr->f(); }

  struct placeholder
  {
    virtual ~placeholder() {}
    virtual void f() const = 0;
  };

  template < typename T >
  struct impl : placeholder
  {
    impl(T const& t) : val(t) {}
    void f() const { val.f(); }
    T val;
  };
  // ptr can now point to the entire family of 
  // struct types generated from impl<T>
  placeholder * ptr;

  template < typename T >
  f_any(T const& t) : ptr(new impl<T>(t)) {}

  // assignment, etc...
};

template<void(*ctor)()>
struct static_constructor
{
  struct constructor { constructor() { ctor(); } };
  static constructor c;
};
template<void(*ctor)()>
typename static_constructor<ctor>::constructor static_constructor<ctor>::c;



typedef void*(*getter)(void*);

struct VisitorAttribute
{
  VisitorAttribute(const char* name, getter a_getter) : m_name(name), m_getter(a_getter) {}
  const char*                    m_name;
  getter                         m_getter;
};

template <typename T>
struct BaseType
{
protected:
  typedef T _this_type;
  static std::vector<VisitorAttribute>& _this_members() { static std::vector<VisitorAttribute> _s_this_members; return _s_this_members; }
  static void AddMember(const char* a_name, getter a_func) { _this_members().push_back(VisitorAttribute(a_name, a_func)); }
};

/*
template <typename T, typename parent>
struct TypeWrapper
{
  T m_value;
protected:
  typedef T _wrapped_type;
  static const char* _wrapped_name() { return "#name"; }
  static type& get(void* _this) { return ((parent*)_this)->name; }
  static void run_once() { static_constructor<&run_once>::c; parent::AddMember(_wrapped_name(), (getter)&tmp_getter_##name); } 
};
*/

#include <tuple>
#include <tuple>
#include <utility> 

template<typename V, typename T, std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(V& v, T obj, std::tuple<Tp...> &) // Unused arguments are given no names.
{ }

template<typename V, typename T, std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(V& v, T obj, std::tuple<Tp...>& t)
{
  v.Visit(std::get<I>(t), std::get<I+1>(t)(obj));
  for_each<V, T, I + 2, Tp...>(v, obj, t);
}

#define DECLARE_STRUCT(name) \
    class name : public BaseType<name> { \
        static const char* _this_name() { return #name; } \
      public: \
        std::tuple<int>  m_tup; \
        typedef struct { static decltype(std::make_tuple()) tuple() { return std::make_tuple(); }


#define DECLARE_MEMBER(type, name, ...) \
        } blah##name; \
        static type& tmp_getter_##name(void* _this) { return ((_this_type*)_this)->name; } \
        static void tmp_collect_##name() { static_constructor<&tmp_collect_##name>::c; AddMember(#name, (getter)&tmp_getter_##name); } \
        /*static auto get_tuple_for_##name() { static auto s_tuple = std::make_tuple<int,int>(1,1); return s_tuple; }*/ \
        type name = type(__VA_ARGS__); \
        typedef struct { static decltype(std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, tmp_getter_##name))) tuple() { return std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, tmp_getter_##name)); }


#define END_STRUCT(name) \
        } last; \
        template <class V> \
        void Visit(V& v) \
        { \
          v.Enter(_this_name()); \
          auto tup = last::tuple(); \
          for_each(v, this, tup); \
          /*for (auto i: _this_members())*/ \
          /*    v.Visit(i.m_name, *(int*)i.m_getter(this));*/ \
          v.Exit(_this_name()); \
        } \
    };



DECLARE_STRUCT(TestStruct)
DECLARE_MEMBER(int, m_int, 9)
DECLARE_MEMBER(bool, m_bool, false)
END_STRUCT(TestStruct)



#include <iostream>
#include <memory>
#include <utility>
#include <array>
   
struct A {
  A(int&& n) { std::cout << "rvalue overload, n=" << n << "\n"; }
  A(int& n)  { std::cout << "lvalue overload, n=" << n << "\n"; }
  A(const char*& n)    { std::cout << "lvalue str overload, n=" << n << "\n"; }
  A(const char*&& n)  { std::cout << "rvalue str overload, n=" << n << "\n"; }
};

template<class T, class U>
std::unique_ptr<T> make_unique1(U&& u)
{
  return std::unique_ptr<T>(new T(std::forward<U>(u)));
}


#include <cstdio>
#include <iostream>
#include <sstream>
#include <cxxabi.h>



class Z { public: Z() { PrintStackTrace(); } };
class B { public: B() { Z z; } };
class C { public: C() { B b; } };
class D { public: D() { C c; } };

int main(int argc, char* argv[])
{
  auto p1 = make_unique1<A>(2); // rvalue
  int i = 1;
  auto p2 = make_unique1<A>(i); // lvalue
  auto p3 = make_unique1<A>("blah"); // rvalue
  const char *i2 = "foo";
  auto p4 = make_unique1<A>(i2); // lvalue


                typedef struct { static decltype(std::make_tuple()) tuple() { return std::make_tuple(); }
  } blah_name1; typedef struct { static decltype(std::tuple_cat(blah_name1::tuple(), std::make_tuple("x",     1))) tuple() { return std::tuple_cat(blah_name1::tuple(), std::make_tuple("x",      1)); }
  } blah_name2; typedef struct { static decltype(std::tuple_cat(blah_name2::tuple(), std::make_tuple("xb", true))) tuple() { return std::tuple_cat(blah_name2::tuple(), std::make_tuple("xb",  true)); }
  } blah_name3; typedef struct { static decltype(std::tuple_cat(blah_name3::tuple(), std::make_tuple("y",     2))) tuple() { return std::tuple_cat(blah_name3::tuple(), std::make_tuple("y",      2)); }
  } blah_name4; typedef struct { static decltype(std::tuple_cat(blah_name4::tuple(), std::make_tuple("x", false))) tuple() { return std::tuple_cat(blah_name4::tuple(), std::make_tuple("yb", false)); }
  } blah_name5; typedef struct { static decltype(std::tuple_cat(blah_name5::tuple(), std::make_tuple("z",     3))) tuple() { return std::tuple_cat(blah_name5::tuple(), std::make_tuple("z",      3)); }
  } blah_name6; typedef struct { static decltype(std::tuple_cat(blah_name6::tuple(), std::make_tuple("zb", true))) tuple() { return std::tuple_cat(blah_name6::tuple(), std::make_tuple("zb",  true)); }
  } last;

  std::cout << "mangled:   " <<                     typeid(last::tuple()).name()           << std::endl;
  std::cout << "demangled: " << abi::__cxa_demangle(typeid(last::tuple()).name(), 0, 0, 0) << std::endl;

  D stack;

  XMLSerializerVisitor serializer;
  printf("%s", serializer.Output().c_str());

  {
    TestStruct t;
//    t.m_int = 1234;
//    t.m_bool = true;

    XMLSerializerVisitor serializer;
    serializer.Visit(t);
    printf("%s", serializer.Output().c_str());
  }


  return 0;

  std::string input;

  {  
    Person a;
    a.id = 10;
    a.name = "blah";
    a.email.push_back("em@ail.com");
    a.email.push_back("other@add.com");
    a.phoneNumbers.push_back("123555");

    XMLSerializerVisitor serializer;
    serializer.Visit(a);
    printf("%s", serializer.Output().c_str());
    input = serializer.Output();
  }

  {
    Person b;

    XMLDeserializerVisitor deserializer(input);
    deserializer.Visit(b);

    {
      XMLSerializerVisitor serializer;
      serializer.Visit(b);
      printf("%s", serializer.Output().c_str());
    }
  }


  {  
    Person a;
    a.id = 10;
    a.name = "blah";
    a.email.push_back("em@ail.com");
    a.email.push_back("other@add.com");
    a.phoneNumbers.push_back("123555");

    JsonSerializerVisitor serializer;
    serializer.Visit(a);
    printf("%s", serializer.Output().c_str());
    input = serializer.Output();
  }

  {
    Person b;

    JsonDeserializerVisitor deserializer(input);
    deserializer.Visit(b);

    {
      JsonSerializerVisitor serializer;
      serializer.Visit(b);
      printf("%s", serializer.Output().c_str());
    }
  }

  {  
    Property p("hello world");
    Property i(100);
    Array<Property> vals;
    vals.push_back(p);
    vals.push_back(i);
    Property a(vals);

    XMLSerializerVisitor serializer;
    serializer.Visit(a);
    printf("%s", serializer.Output().c_str());
    input = serializer.Output();
  }

}