#include "pch.h"



/* Based on Jon Watte's "simple C++ reflection mark-up library" Version 2009-04-20
   http://www.enchantedage.com/cpp-reflection

   Altered by Sylvain Vignaud to use a simpler interface 2010-07-23
*/

enum MemberDescriptionFlag
{
	Member_DefaultFlag = 0,
	Member_Serialized
};

struct TypeBase
{
	virtual void Marshal(void *, void const *) const = 0;
	virtual void Demarshal(void const *, void *) const = 0;
	virtual char const *name() const = 0;
	virtual size_t size() const = 0;
};

template<typename T> struct Type : TypeBase
{
	static Type<T> instance;
	// custom marshaling is handled by template specialization
	void Marshal(void *dst, void const *src) const { memcpy(dst, src, sizeof(T)); }
	void Demarshal(void const *src, void *dst) const { memcpy(dst, src, sizeof(T)); }
	char const *name() const { return typeid(T).name(); }
	size_t size() const { return sizeof(T); }
};

template <typename T> T& instance() {
	static T t;
	return t;
}

template<typename T, typename Q>
TypeBase *get_type(Q T::* /*mem*/) {
	return &instance<Type<Q> >();
}

typedef struct
{
	char const *name;
	TypeBase *type;
	size_t offset;
	const char *textDescription;
	size_t flags;
} member_t;

#define DefineClass(className) typedef className OwnerClass; enum { StartLine = __LINE__ }; \
	static const char* GetClassName() { return #className; } \
	template<int N> \
	class Members_RunOnLine \
	{ \
	public: \
 		static void Register() { Members_RunOnLine<N-1>::Register(); } \
		static void InitializeMembersToDefaultValue(OwnerClass &owner) { Members_RunOnLine<N-1>::InitializeMembersToDefaultValue(owner); } \
		enum { Count = Members_RunOnLine<N-1>::Count }; \
	}; \
 \
	template<> \
	class Members_RunOnLine<StartLine> \
	{ \
 	public: \
		static void Register() {} \
		static void InitializeMembersToDefaultValue(OwnerClass &/*owner*/) {} \
		enum { Count = 0 }; \
	};

#define EndClass() \
	public: \
	void InitializeMembersToDefaultValue() { Members_RunOnLine<__LINE__ - 1>::InitializeMembersToDefaultValue(*this); } \
	enum { NbrMembers = Members_RunOnLine<__LINE__ - 1>::Count }; \
	\
	public: \
	class ClassDescription \
	{ \
		int mNbrRegisteredMembers; \
	public: \
		member_t m_Members[OwnerClass::NbrMembers]; \
		int GetNbrMembers() const { return mNbrRegisteredMembers; } \
		\
		ClassDescription() : mNbrRegisteredMembers(0) { Members_RunOnLine<__LINE__ - 1>::Register(); } \
		\
		void Register( const char *name, TypeBase *type, size_t offset, const char *textDescription, size_t flags ) \
		{ \
			member_t memberDesc = { name, type, offset, textDescription, flags }; \
			assert( mNbrRegisteredMembers < OwnerClass::NbrMembers ); \
			m_Members[mNbrRegisteredMembers] = memberDesc; \
			++mNbrRegisteredMembers; \
		} \
		static const char* name() { return OwnerClass::GetClassName(); } \
		static size_t size() { return sizeof(OwnerClass); } \
	}; \
	\
	static ClassDescription& GetClassDescription() \
	{ \
		static ClassDescription description; \
		return description; \
	} \
	private:


#define Member(type, var, ...) \
	type var; \
	template<> \
	class Members_RunOnLine<__LINE__> \
	{ \
		Members_RunOnLine<__LINE__>() : mDescription("") {} \
		static Members_RunOnLine<__LINE__>& GetInstance() { static Members_RunOnLine<__LINE__> instance; return instance; } \
		\
		/* Define here all flags one can use in member description */ \
		static void Default(type v) { GetInstance().mDefaultValue = v; } \
		static void Description(const char *desc) { GetInstance().mDescription = desc; } \
		static void Serialized() { GetInstance().mFlags |= Member_Serialized; } \
		\
 	public: \
		static void Register() \
		{ \
			Members_RunOnLine<__LINE__ - 1>::Register(); \
			__VA_ARGS__; \
			Members_RunOnLine<__LINE__> &instance = GetInstance(); \
			OwnerClass::GetClassDescription().Register(#var, get_type(&OwnerClass::var), (size_t)&((OwnerClass*)0)->var, instance.mDescription, instance.mFlags ); \
		} \
		static void InitializeMembersToDefaultValue(OwnerClass &owner) \
		{ \
			Members_RunOnLine<__LINE__ - 1>::InitializeMembersToDefaultValue(owner); \
			owner.var = GetInstance().mDefaultValue; \
		} \
		enum { Count = 1 + Members_RunOnLine<__LINE__-1>::Count }; \
		\
		type mDefaultValue; \
		const char *mDescription; \
		unsigned long mFlags; \
	}

class Foo
{
public:
	Foo() {}
	virtual ~Foo() {}

private:
	DefineClass(Foo);

	Member(int, test, Default(0); Description("Some int") );
	Member(char *, mName, Default("foo"); Description("Some static text"); Serialized());

	Member(int*, mBuffer, Default(NULL), Description("Some ptr to nowhere"); Serialized());

	Member(int, foo);

	Member(int, foo2, Description("this one has a desc, unlike foo"));
	Member(int, foo3, Default(0xDead));

	EndClass();
};

int main(int /*argc*/, _TCHAR* /*argv*/[])
{
	Foo foo;
	foo.InitializeMembersToDefaultValue();

	const Foo::ClassDescription &desc = Foo::GetClassDescription();

	printf("type: %s\n", desc.name());
	printf("size: %d\n", desc.size());

	const int nbrMembers = desc.GetNbrMembers();
	for( int i=0; i<nbrMembers; ++i )
	{
		const member_t &member = desc.m_Members[i];
		printf("%10s: offset %3d size %3d  type: %10s - %s %s\n",
			member.name, member.offset,
			member.type->size(), member.type->name(),
			member.textDescription,
			(member.flags & Member_Serialized) ? " - serialized" : "" );
	}

	getchar();
	return 0;
}

