Skip to content

Instantly share code, notes, and snippets.

@veryjos
Created March 14, 2018 05:46
Show Gist options
  • Save veryjos/2ab605d90f964775175c738e29b33dca to your computer and use it in GitHub Desktop.
Save veryjos/2ab605d90f964775175c738e29b33dca to your computer and use it in GitHub Desktop.
#pragma once
#include <string>
#include <functional>
#include <unordered_map>
#include <vector>
#include <type_traits>
namespace Reflect {
/**
* Forward declarations..
*/
namespace internal {
template <typename... A>
void PackArgList(char** out, A... args);
};
/**
* Used to call getters, setters, function invokers..
*/
using _meta_Setter = void (*)(void*, void*);
using _meta_Getter = void* (*)(void*);
using _meta_Invoker = void* (*)(void*, void*);
struct MemberVariable {
std::string name;
size_t offset;
template <typename T, typename V>
void Set(T* instance, V value) {
*((V*)((char*)instance) + offset) = value;
};
template <typename R, typename T>
R Get(T* instance) {
return *((R*)((char*)instance) + offset);
};
};
struct MemberFunction {
std::string name;
_meta_Invoker invoker;
template <typename T, typename... A>
void Invoke(T* instance, A... a) {
char* packedArgs;
internal::PackArgList<A...>(&packedArgs, a...);
invoker((void*)instance, packedArgs);
};
};
struct Class {
std::string name;
std::unordered_map<std::string, MemberVariable> memberVariables;
std::unordered_map<std::string, MemberFunction> memberFunctions;
};
inline std::unordered_map<std::string, Class> classes;
namespace internal {
/**
* Some types wrapped for use at compile time
*/
template <int i>
struct MetaIndex {
static constexpr const int value = i;
};
template <bool v>
struct MetaFlag {
static constexpr const int value = v;
};
/**
* Helpers for counting arguments
*/
template <typename... A>
struct ArgCounter {
static constexpr int value = sizeof...(A);
};
template <typename R, typename... A>
const int constexpr GetArgCount(R (A...)) {
return ArgCounter<A...>::value;
};
template <typename R, typename U, typename... A>
const int constexpr GetArgCount(R (U::*) (A...)) {
return ArgCounter<A...>::argCount;
};
/**
* Helpers for summing sizeof(argument list[n])
*/
template <typename... A>
struct ArgListSizeCounter;
template <typename U, typename... A>
struct ArgListSizeCounter<U, A...> {
static const int constexpr GetSize() {
return sizeof(U) + ArgListSizeCounter<A...>::GetSize();
};
};
template <>
struct ArgListSizeCounter<> {
static const int constexpr GetSize() {
return 0;
};
};
template <typename... A>
const int constexpr GetArgListSize() {
return ArgListSizeCounter<A...>::GetSize();
};
/**
* Helpers for getting a list of argument ID's
*/
template <typename... A>
struct ArgIdentifier;
template <typename A, typename... R>
struct ArgIdentifier<A, R...> {
static void GetArgIdsImpl(std::vector<size_t>& list) {
list.push_back(typeid(A).hash_code());
ArgIdentifier<R...>::GetArgIdsImpl(list);
};
};
template<>
struct ArgIdentifier<> {
static void GetArgIdsImpl(std::vector<size_t>& list) {
};
};
template <typename R, typename... A>
std::vector<size_t> GetArgIds(R (A...)) {
std::vector<size_t> list;
ArgIdentifier<A...>::GetArgIdsImpl(list);
return list;
};
template <typename R, typename U, typename... A>
std::vector<size_t> GetArgIds(R (U::*) (A...)) {
std::vector<size_t> list;
ArgIdentifier<A...>::GetArgIdsImpl(list);
return list;
};
/**
* Helpers for packing/unpacking arugments
*/
template <typename... A>
struct ArgPacker;
template <typename U, typename... A>
struct ArgPacker<U, A...> {
static void Pack(char* out, U c, A... a) {
using nakedType = typename std::remove_reference<U>::type;
*((nakedType*)out) = c;
out += sizeof(U);
ArgPacker<A...>::Pack(out, a...);
};
};
template <>
struct ArgPacker<> {
static void Pack(char* out) {
};
};
template <typename... A>
void PackArgList(char** out, A... args) {
*out = (char*)malloc(GetArgListSize<A...>());
ArgPacker<A...>::Pack(*out, args...);
};
template <typename I, typename T, typename... A>
struct ArgUnpacker;
template <typename I, typename T, typename U, typename... A>
struct ArgUnpacker<I, T, U, A...> {
static void Unpack(T& tuple, char* args) {
std::get<I::value>(tuple) = *((U*)args);
args += sizeof(U);
ArgUnpacker<MetaIndex<I::value + 1>, T, A...>::Unpack(tuple, args);
};
};
template <typename I, typename T>
struct ArgUnpacker<I, T> {
static void Unpack(T& tuple, char* args) {
};
};
template <typename R, typename U, typename... A>
void MemberInvokeProxy(R (U::*fun) (A...), U* instance, A... args) {
(instance->*fun)(args...);
};
template <typename R, typename U, typename... A>
R Invoke(R (U::*fun) (A...), U* instance, A... args) {
return std::invoke(
&MemberInvokeProxy<R, U, A...>,
args...
);
};
template <typename R, typename U, typename... A>
R InvokeWithPackedArgs(R (U::*fun) (A...), U* instance, char* args) {
std::tuple<A...> unpackedArgs;
ArgUnpacker<MetaIndex<0>, decltype(unpackedArgs), A...>::Unpack(unpackedArgs, args);
return std::apply(
&MemberInvokeProxy<R, U, A...>,
std::tuple_cat(
std::make_tuple(fun, instance),
unpackedArgs
)
);
};
/**
* ClassMetaStore will be specialized for each type at compile time and store
* the metadata for that type
*/
template <typename T>
struct ClassMetaStore {
static inline ClassMetaStore<T>* instance;
Class cl;
};
/**
* Registers a ClassMetaStore at alloc time (before main)
*/
template <typename T>
struct Registrar {
Registrar(const char* name) {
ClassMetaStore<T>::instance = new ClassMetaStore<T>();
ClassMetaStore<T>::instance->cl.name = name;
T::_meta_InitClassMetaStore();
Reflect::classes[name] = ClassMetaStore<T>::instance->cl;
};
};
/**
* Gets the next value in a counter. Will be called recursively at
* compile time, checking if the definition for "_meta_coounter" has been
* overloaded for the index that was passed in
*/
template <typename T, typename I, typename invalidator>
static constexpr const int NextValueForCounter() {
if constexpr (decltype(T::_meta_counter(I{}))::value == false) {
return I::value;
} else {
return NextValueForCounter<T, MetaIndex<I::value + 1>, invalidator>();
}
};
};
};
#define REFLECT_ENABLE(type) \
using _meta_myType = type; \
friend struct Reflect::internal::ClassMetaStore<_meta_myType>; \
friend struct Reflect::internal::Registrar<_meta_myType>; \
\
static inline Reflect::internal::Registrar<_meta_myType> _meta_registrar = Reflect::internal::Registrar<_meta_myType>(#type); \
\
template <typename I> \
static constexpr Reflect::internal::MetaFlag<false> _meta_counter(I); \
\
template <typename I> \
static void _meta_InitNext(I) { }; \
\
static void _meta_InitClassMetaStore() { \
_meta_InitNext(Reflect::internal::MetaIndex<0>{}); \
} \
#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)
#define REFLECT(name) _REFLECT_IMPL(name, CONCAT(_meta_index_, name), __LINE__)
#define _REFLECT_IMPL(name, ident, line) \
static constexpr const int ident = Reflect::internal::NextValueForCounter< \
_meta_myType, \
Reflect::internal::MetaIndex<0>, \
Reflect::internal::MetaIndex<line> \
>(); \
static constexpr const Reflect::internal::MetaFlag<true> _meta_counter(Reflect::internal::MetaIndex<ident>); \
\
template <typename T> \
static typename std::enable_if< \
std::is_member_function_pointer<decltype(&T::name)>::value, \
void \
>::type \
_meta_InitMemberFunction(Reflect::internal::MetaIndex<ident>) { \
auto meta = Reflect::internal::ClassMetaStore<_meta_myType>::instance; \
\
auto invoker = [](void* instance, void* args) -> void* { \
T* specialized = (T*)instance ; \
\
Reflect::internal::InvokeWithPackedArgs(&T::name, specialized, (char*)args); \
\
return nullptr; \
}; \
\
Reflect::MemberFunction memberFunction = { \
#name, \
invoker \
}; \
\
meta->cl.memberFunctions[#name] = memberFunction; \
} \
\
template <typename T> \
static typename std::enable_if< \
!std::is_member_function_pointer<decltype(&T::name)>::value, \
void \
>::type \
_meta_InitMemberFunction(Reflect::internal::MetaIndex<ident>) { \
} \
\
template <typename T> \
static typename std::enable_if< \
std::is_member_object_pointer<decltype(&T::name)>::value, \
void \
>::type \
_meta_InitMemberVariable(Reflect::internal::MetaIndex<ident>) { \
auto meta = Reflect::internal::ClassMetaStore<_meta_myType>::instance; \
Reflect::MemberVariable memberVariable = { \
#name, \
offsetof(T, name) \
}; \
\
meta->cl.memberVariables[#name] = memberVariable; \
} \
\
template <typename T> \
static typename std::enable_if< \
!std::is_member_object_pointer<decltype(&T::name)>::value, \
void \
>::type \
_meta_InitMemberVariable(Reflect::internal::MetaIndex<ident>) { \
} \
\
static void _meta_InitNext(Reflect::internal::MetaIndex<ident>) { \
_meta_InitMemberVariable<_meta_myType>(Reflect::internal::MetaIndex<ident>{}); \
_meta_InitMemberFunction<_meta_myType>(Reflect::internal::MetaIndex<ident>{}); \
\
_meta_InitNext(Reflect::internal::MetaIndex<ident + 1>{}); \
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment