#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();
}
}