diff --git a/Serializing/Property.h b/Serializing/Property.h new file mode 100644 index 0000000..1ba70c3 --- /dev/null +++ b/Serializing/Property.h @@ -0,0 +1,99 @@ +#ifndef PROPERTY_H +#define PROPERTY_H + + +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& 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 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 + 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"); + } +}; + + +#endif // PROPERTY_H + diff --git a/Serializing/Property.h b/Serializing/Property.h new file mode 100644 index 0000000..1ba70c3 --- /dev/null +++ b/Serializing/Property.h @@ -0,0 +1,99 @@ +#ifndef PROPERTY_H +#define PROPERTY_H + + +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& 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 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 + 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"); + } +}; + + +#endif // PROPERTY_H + diff --git a/Serializing/Types.h b/Serializing/Types.h new file mode 100644 index 0000000..9f73bdc --- /dev/null +++ b/Serializing/Types.h @@ -0,0 +1,91 @@ +#ifndef TYPES_H +#define TYPES_H + + +#include +#include + + +// Some basic types that should build serializable structures from +template +using Array = std::vector; +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 values; +}; + + +#define DECLARE_STRUCT(name) \ + struct name { \ + private: \ + typedef name _this_type; \ + static const char* _this_name() { return #name; } \ + public: \ + typedef struct { \ + static const decltype(std::make_tuple()) tuple() { \ + return std::make_tuple(); \ + } + +#define DECLARE_MEMBER(type, name, ...) \ + } blah##name; \ + \ + type name = type(__VA_ARGS__); \ + \ + typedef struct { \ + static type& get_##name(_this_type& _this) { \ + return _this.name; \ + } \ + typedef decltype(std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name))) ret_type; \ + static const ret_type tuple() { \ + return std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name)); \ + } + +#define END_STRUCT() \ + } last; \ + template \ + void Visit(V& v) \ + { \ + v.Enter(_this_name()); \ + static auto tup = last::tuple(); \ + for_each(v, *this, tup); \ + v.Exit(_this_name()); \ + } \ + }; + + +#endif // TYPES_H + diff --git a/Serializing/Property.h b/Serializing/Property.h new file mode 100644 index 0000000..1ba70c3 --- /dev/null +++ b/Serializing/Property.h @@ -0,0 +1,99 @@ +#ifndef PROPERTY_H +#define PROPERTY_H + + +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& 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 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 + 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"); + } +}; + + +#endif // PROPERTY_H + diff --git a/Serializing/Types.h b/Serializing/Types.h new file mode 100644 index 0000000..9f73bdc --- /dev/null +++ b/Serializing/Types.h @@ -0,0 +1,91 @@ +#ifndef TYPES_H +#define TYPES_H + + +#include +#include + + +// Some basic types that should build serializable structures from +template +using Array = std::vector; +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 values; +}; + + +#define DECLARE_STRUCT(name) \ + struct name { \ + private: \ + typedef name _this_type; \ + static const char* _this_name() { return #name; } \ + public: \ + typedef struct { \ + static const decltype(std::make_tuple()) tuple() { \ + return std::make_tuple(); \ + } + +#define DECLARE_MEMBER(type, name, ...) \ + } blah##name; \ + \ + type name = type(__VA_ARGS__); \ + \ + typedef struct { \ + static type& get_##name(_this_type& _this) { \ + return _this.name; \ + } \ + typedef decltype(std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name))) ret_type; \ + static const ret_type tuple() { \ + return std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name)); \ + } + +#define END_STRUCT() \ + } last; \ + template \ + void Visit(V& v) \ + { \ + v.Enter(_this_name()); \ + static auto tup = last::tuple(); \ + for_each(v, *this, tup); \ + v.Exit(_this_name()); \ + } \ + }; + + +#endif // TYPES_H + diff --git a/Serializing/Utilities.h b/Serializing/Utilities.h new file mode 100644 index 0000000..2740bb0 --- /dev/null +++ b/Serializing/Utilities.h @@ -0,0 +1,79 @@ +#ifndef UTILITIES_H +#define UTILITIES_H + + +#include +#include + + +// This comes from here: +// http://stackoverflow.com/questions/4988939/how-do-boostvariant-and-boostany-work +// Currently not using this, but it might be useful in the future and explains idea behine how boost::any works +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 + placeholder * ptr; + + template < typename T > + f_any(T const& t) : ptr(new impl(t)) {} + + // assignment, etc... +}; + + +// The idea comes from here: +// http://stackoverflow.com/questions/1197106/static-constructors-in-c-need-to-initialize-private-static-objects +// Currently this isn't being used, but it is a neat solution and for some reason it was low in the +// voted for solutions. It appears quite low on the stackoverflow page. I actually quite like it. +// Usage: static void StaticTest() { +// static_constructor<&Test::StaticTest>::c; +// // +// } +template +struct static_constructor +{ + struct constructor { constructor() { ctor(); } }; + static constructor c; +}; +template +typename static_constructor::constructor static_constructor::c; + + + +// The idea behind this comes from here: +// http://stackoverflow.com/questions/1198260/iterate-over-tuple +template +inline typename std::enable_if::type +for_each(V& v, T obj, std::tuple &) // Unused arguments are given no names. +{ } + +template +inline typename std::enable_if::type +for_each(V& v, T obj, std::tuple& t) +{ + v.Visit(std::get(t), std::get(t)(obj)); + for_each(v, obj, t); +} + + +#endif // UTILITIES_H + diff --git a/Serializing/Property.h b/Serializing/Property.h new file mode 100644 index 0000000..1ba70c3 --- /dev/null +++ b/Serializing/Property.h @@ -0,0 +1,99 @@ +#ifndef PROPERTY_H +#define PROPERTY_H + + +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& 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 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 + 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"); + } +}; + + +#endif // PROPERTY_H + diff --git a/Serializing/Types.h b/Serializing/Types.h new file mode 100644 index 0000000..9f73bdc --- /dev/null +++ b/Serializing/Types.h @@ -0,0 +1,91 @@ +#ifndef TYPES_H +#define TYPES_H + + +#include +#include + + +// Some basic types that should build serializable structures from +template +using Array = std::vector; +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 values; +}; + + +#define DECLARE_STRUCT(name) \ + struct name { \ + private: \ + typedef name _this_type; \ + static const char* _this_name() { return #name; } \ + public: \ + typedef struct { \ + static const decltype(std::make_tuple()) tuple() { \ + return std::make_tuple(); \ + } + +#define DECLARE_MEMBER(type, name, ...) \ + } blah##name; \ + \ + type name = type(__VA_ARGS__); \ + \ + typedef struct { \ + static type& get_##name(_this_type& _this) { \ + return _this.name; \ + } \ + typedef decltype(std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name))) ret_type; \ + static const ret_type tuple() { \ + return std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name)); \ + } + +#define END_STRUCT() \ + } last; \ + template \ + void Visit(V& v) \ + { \ + v.Enter(_this_name()); \ + static auto tup = last::tuple(); \ + for_each(v, *this, tup); \ + v.Exit(_this_name()); \ + } \ + }; + + +#endif // TYPES_H + diff --git a/Serializing/Utilities.h b/Serializing/Utilities.h new file mode 100644 index 0000000..2740bb0 --- /dev/null +++ b/Serializing/Utilities.h @@ -0,0 +1,79 @@ +#ifndef UTILITIES_H +#define UTILITIES_H + + +#include +#include + + +// This comes from here: +// http://stackoverflow.com/questions/4988939/how-do-boostvariant-and-boostany-work +// Currently not using this, but it might be useful in the future and explains idea behine how boost::any works +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 + placeholder * ptr; + + template < typename T > + f_any(T const& t) : ptr(new impl(t)) {} + + // assignment, etc... +}; + + +// The idea comes from here: +// http://stackoverflow.com/questions/1197106/static-constructors-in-c-need-to-initialize-private-static-objects +// Currently this isn't being used, but it is a neat solution and for some reason it was low in the +// voted for solutions. It appears quite low on the stackoverflow page. I actually quite like it. +// Usage: static void StaticTest() { +// static_constructor<&Test::StaticTest>::c; +// // +// } +template +struct static_constructor +{ + struct constructor { constructor() { ctor(); } }; + static constructor c; +}; +template +typename static_constructor::constructor static_constructor::c; + + + +// The idea behind this comes from here: +// http://stackoverflow.com/questions/1198260/iterate-over-tuple +template +inline typename std::enable_if::type +for_each(V& v, T obj, std::tuple &) // Unused arguments are given no names. +{ } + +template +inline typename std::enable_if::type +for_each(V& v, T obj, std::tuple& t) +{ + v.Visit(std::get(t), std::get(t)(obj)); + for_each(v, obj, t); +} + + +#endif // UTILITIES_H + diff --git a/Serializing/Visitor.h b/Serializing/Visitor.h new file mode 100644 index 0000000..1081ef3 --- /dev/null +++ b/Serializing/Visitor.h @@ -0,0 +1,60 @@ +#ifndef VISITOR_H +#define VISITOR_H + + +// With this defined, the virtual interfaces are +// declared and declared pure virtual so must be +// implemented. However the base class is here +// purely for checking the implementation of +// sub-classes meets the desired interface, the +// actual usage of sub-classes is using the CRTP +// and so we don't actually need virtual dispatch +// and can optionally not declare any virtual +// functions by not defining the below define and +// we won't pay any code to have a vtable and be +// doing virtual calls when we use this interface +#define VISITOR_INHERITED_INTERFACE_CHECK + + +class VisitorBase +{ +public: +#ifdef VISITOR_INHERITED_INTERFACE_CHECK + virtual ~VisitorBase() {} + virtual void Enter(const char* name) = 0; + virtual void Exit(const char* name) = 0; +#endif + 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: +#ifdef VISITOR_INHERITED_INTERFACE_CHECK + virtual const std::string& Output() = 0; + virtual void Reset() = 0; +#endif +}; + + +class Deserializer : public VisitorBase +{ +public: +#ifdef VISITOR_INHERITED_INTERFACE_CHECK + virtual void Reset(const std::string& a_input) = 0; +#endif +}; + + +#endif // VISITOR_H + + diff --git a/Serializing/Property.h b/Serializing/Property.h new file mode 100644 index 0000000..1ba70c3 --- /dev/null +++ b/Serializing/Property.h @@ -0,0 +1,99 @@ +#ifndef PROPERTY_H +#define PROPERTY_H + + +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& 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 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 + 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"); + } +}; + + +#endif // PROPERTY_H + diff --git a/Serializing/Types.h b/Serializing/Types.h new file mode 100644 index 0000000..9f73bdc --- /dev/null +++ b/Serializing/Types.h @@ -0,0 +1,91 @@ +#ifndef TYPES_H +#define TYPES_H + + +#include +#include + + +// Some basic types that should build serializable structures from +template +using Array = std::vector; +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 values; +}; + + +#define DECLARE_STRUCT(name) \ + struct name { \ + private: \ + typedef name _this_type; \ + static const char* _this_name() { return #name; } \ + public: \ + typedef struct { \ + static const decltype(std::make_tuple()) tuple() { \ + return std::make_tuple(); \ + } + +#define DECLARE_MEMBER(type, name, ...) \ + } blah##name; \ + \ + type name = type(__VA_ARGS__); \ + \ + typedef struct { \ + static type& get_##name(_this_type& _this) { \ + return _this.name; \ + } \ + typedef decltype(std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name))) ret_type; \ + static const ret_type tuple() { \ + return std::tuple_cat(blah##name::tuple(), std::make_tuple(#name, get_##name)); \ + } + +#define END_STRUCT() \ + } last; \ + template \ + void Visit(V& v) \ + { \ + v.Enter(_this_name()); \ + static auto tup = last::tuple(); \ + for_each(v, *this, tup); \ + v.Exit(_this_name()); \ + } \ + }; + + +#endif // TYPES_H + diff --git a/Serializing/Utilities.h b/Serializing/Utilities.h new file mode 100644 index 0000000..2740bb0 --- /dev/null +++ b/Serializing/Utilities.h @@ -0,0 +1,79 @@ +#ifndef UTILITIES_H +#define UTILITIES_H + + +#include +#include + + +// This comes from here: +// http://stackoverflow.com/questions/4988939/how-do-boostvariant-and-boostany-work +// Currently not using this, but it might be useful in the future and explains idea behine how boost::any works +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 + placeholder * ptr; + + template < typename T > + f_any(T const& t) : ptr(new impl(t)) {} + + // assignment, etc... +}; + + +// The idea comes from here: +// http://stackoverflow.com/questions/1197106/static-constructors-in-c-need-to-initialize-private-static-objects +// Currently this isn't being used, but it is a neat solution and for some reason it was low in the +// voted for solutions. It appears quite low on the stackoverflow page. I actually quite like it. +// Usage: static void StaticTest() { +// static_constructor<&Test::StaticTest>::c; +// // +// } +template +struct static_constructor +{ + struct constructor { constructor() { ctor(); } }; + static constructor c; +}; +template +typename static_constructor::constructor static_constructor::c; + + + +// The idea behind this comes from here: +// http://stackoverflow.com/questions/1198260/iterate-over-tuple +template +inline typename std::enable_if::type +for_each(V& v, T obj, std::tuple &) // Unused arguments are given no names. +{ } + +template +inline typename std::enable_if::type +for_each(V& v, T obj, std::tuple& t) +{ + v.Visit(std::get(t), std::get(t)(obj)); + for_each(v, obj, t); +} + + +#endif // UTILITIES_H + diff --git a/Serializing/Visitor.h b/Serializing/Visitor.h new file mode 100644 index 0000000..1081ef3 --- /dev/null +++ b/Serializing/Visitor.h @@ -0,0 +1,60 @@ +#ifndef VISITOR_H +#define VISITOR_H + + +// With this defined, the virtual interfaces are +// declared and declared pure virtual so must be +// implemented. However the base class is here +// purely for checking the implementation of +// sub-classes meets the desired interface, the +// actual usage of sub-classes is using the CRTP +// and so we don't actually need virtual dispatch +// and can optionally not declare any virtual +// functions by not defining the below define and +// we won't pay any code to have a vtable and be +// doing virtual calls when we use this interface +#define VISITOR_INHERITED_INTERFACE_CHECK + + +class VisitorBase +{ +public: +#ifdef VISITOR_INHERITED_INTERFACE_CHECK + virtual ~VisitorBase() {} + virtual void Enter(const char* name) = 0; + virtual void Exit(const char* name) = 0; +#endif + 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: +#ifdef VISITOR_INHERITED_INTERFACE_CHECK + virtual const std::string& Output() = 0; + virtual void Reset() = 0; +#endif +}; + + +class Deserializer : public VisitorBase +{ +public: +#ifdef VISITOR_INHERITED_INTERFACE_CHECK + virtual void Reset(const std::string& a_input) = 0; +#endif +}; + + +#endif // VISITOR_H + + diff --git a/Serializing/test.cpp b/Serializing/test.cpp index 798334b..21c66f2 100644 --- a/Serializing/test.cpp +++ b/Serializing/test.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include #include @@ -8,89 +6,12 @@ #include #include #include "StackTrace.h" - - -// Some basic types that should build serializable structures from -template -using Array = std::vector; -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 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 "Utilities.h" +#include "Types.h" +#include "Visitor.h" #include "XMLVisitor.h" #include "JSONVisitor.h" - - +#include "Property.h" struct Person @@ -135,226 +56,55 @@ */ -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& 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; } +DECLARE_STRUCT(BaseStruct) +DECLARE_MEMBER(int, m_int, 9) +DECLARE_MEMBER(bool, m_bool, false) +END_STRUCT() - 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 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 - 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 - placeholder * ptr; - - template < typename T > - f_any(T const& t) : ptr(new impl(t)) {} - - // assignment, etc... -}; - -template -struct static_constructor -{ - struct constructor { constructor() { ctor(); } }; - static constructor c; -}; -template -typename static_constructor::constructor static_constructor::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 -struct BaseType -{ -protected: - typedef T _this_type; - static std::vector& _this_members() { static std::vector _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 -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 -#include -#include - -template -inline typename std::enable_if::type -for_each(V& v, T obj, std::tuple &) // Unused arguments are given no names. -{ } - -template -inline typename std::enable_if::type -for_each(V& v, T obj, std::tuple& t) -{ - v.Visit(std::get(t), std::get(t)(obj)); - for_each(v, obj, t); -} - -#define DECLARE_STRUCT(name) \ - class name : public BaseType { \ - static const char* _this_name() { return #name; } \ - public: \ - std::tuple 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(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 \ - 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(BaseStruct2) +DECLARE_MEMBER(int, m_int) +DECLARE_MEMBER(bool, m_bool) +END_STRUCT() DECLARE_STRUCT(TestStruct) -DECLARE_MEMBER(int, m_int, 9) -DECLARE_MEMBER(bool, m_bool, false) -END_STRUCT(TestStruct) +DECLARE_MEMBER(BaseStruct, m_base) +DECLARE_MEMBER(Integer32, m_int, 100) +DECLARE_MEMBER(Float32, m_flt, 9.0) +DECLARE_MEMBER(BaseStruct2, m_other) +DECLARE_MEMBER(Boolean, m_bool, false) +END_STRUCT() +DECLARE_STRUCT(Person2) +DECLARE_MEMBER(Integer32, id) +DECLARE_MEMBER(String, name) +DECLARE_MEMBER(Array, email) +DECLARE_MEMBER(Array, phoneNumbers) +END_STRUCT() + +struct PlainBaseStruct { + int m_int = 9; + bool m_bool = false; +}; + +struct PlainBaseStruct2 { + int m_int; + bool m_bool; +}; + +struct PlainTestStruct { + PlainBaseStruct m_base; + int m_int = 100; + float m_flt = 9.0; + PlainBaseStruct2 m_other; + bool m_bool = false; +}; + + +static_assert(sizeof(BaseStruct) == sizeof(BaseStruct2), "blah 1"); +static_assert(sizeof(PlainBaseStruct) == sizeof(PlainBaseStruct2), "blah 2"); +static_assert(sizeof(PlainBaseStruct) == sizeof(BaseStruct), "blah 3"); +static_assert(sizeof(PlainTestStruct) == sizeof(TestStruct), "blah 4"); #include @@ -414,19 +164,22 @@ XMLSerializerVisitor serializer; printf("%s", serializer.Output().c_str()); - { TestStruct t; -// t.m_int = 1234; -// t.m_bool = true; - + t.m_int = 1234; + t.m_bool = true; + XMLSerializerVisitor serializer; + serializer.Visit(t); + printf("%s", serializer.Output().c_str()); + } + { + TestStruct t; XMLSerializerVisitor serializer; serializer.Visit(t); printf("%s", serializer.Output().c_str()); } - return 0; std::string input; @@ -443,9 +196,23 @@ printf("%s", serializer.Output().c_str()); input = serializer.Output(); } + { + Person2 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(); + } + return 0; { - Person b; + Person2 b; XMLDeserializerVisitor deserializer(input); deserializer.Visit(b);