Last active
October 19, 2017 09:59
-
-
Save benloong/15fb15aeec562ec07113c6c2f6c1e4af to your computer and use it in GitHub Desktop.
c++ reflection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<any> | |
#include<tuple> | |
using any = std::any; | |
namespace { | |
constexpr bool strings_equal(char const * a, char const * b) { | |
return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1)); | |
} | |
} | |
class MethodInfo | |
{ | |
protected: | |
using Invoker = any(*)(const MethodInfo* method, any target, const any* args); | |
constexpr MethodInfo(const char*name, Invoker invoker, int argc) : name{ name }, invoker{ invoker }, argc{ argc } | |
{ | |
} | |
public: | |
const char* name; | |
Invoker invoker; | |
int argc; | |
template<typename R, typename...Args> | |
R Invoke(any target, Args... args) | |
{ | |
any anyargs[] = { args... }; | |
return std::any_cast<R>(invoker(this, target, anyargs)); | |
} | |
}; | |
template<typename T, typename U> | |
class Method; | |
template<typename T, typename R, typename ... Args > | |
class Method<T, R(Args...)> : public MethodInfo { | |
R(T::*fn)(Args...); | |
template<typename... Ts, size_t... Is> | |
static auto create_tuple(const any* p, any target, std::index_sequence<Is...>) { | |
return std::tuple<T*, Ts...>(std::any_cast<T*>(target), std::any_cast<Ts>(p[Is])...); | |
} | |
static any _Invoker(const MethodInfo* method, any target, const any* args) | |
{ | |
T* self = std::any_cast<T*>(target); | |
auto m = (const Method*)method; | |
auto tuple = create_tuple<Args...>(args, target, std::make_index_sequence<sizeof...(Args)>{}); | |
return std::apply(m->fn, tuple); | |
} | |
public: | |
constexpr Method(const char *name, R(T::*fn)(Args...)) : | |
MethodInfo(name, _Invoker, sizeof...(Args)), | |
fn{ fn } | |
{ | |
} | |
}; | |
template<typename T, typename R, typename...Args> | |
constexpr auto MakeMethod(const char* name, R(T::*fn)(Args...)) | |
{ | |
return Method<T, R(Args...)>(name, fn); | |
} | |
//template<typename T, typename...Args> | |
//constexpr auto MakeStaticMethod(const char* name, R(*fn)(Args...)) | |
//{ | |
// return Method<T, Args...>(name, fn); | |
//} | |
class MethodList { | |
protected: | |
constexpr MethodList(const MethodInfo** list, int count) : list{ list }, count{ count } | |
{ | |
} | |
public: | |
const MethodInfo** list; | |
const int count; | |
}; | |
template<int N> | |
class MethodListN : public MethodList | |
{ | |
public: | |
const MethodInfo* properties[N]; | |
template<typename ... Args> | |
constexpr MethodListN(Args ... args) : | |
MethodList(properties, N), properties{ args... } | |
{ | |
} | |
}; | |
template<typename...Args> | |
constexpr auto MakeMethodList(Args... args) { | |
return MethodListN<sizeof...(args)>(args...); | |
} | |
struct Table | |
{ | |
int Hello(int i) { | |
return i * 10; | |
} | |
}; | |
auto m = MakeMethod("Hello", &Table::Hello); | |
int main() { | |
Table table; | |
int x = m.Invoke<int, int>(&table, 10); | |
return x; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<any> | |
#include<optional> | |
#include<utility> | |
using any = std::any; | |
class PropertyInfo; | |
namespace { | |
constexpr bool strings_equal(char const * a, char const * b) { | |
return *a == *b && (*a == '\0' || strings_equal(a + 1, b + 1)); | |
} | |
} | |
class PropertyInfo | |
{ | |
public: | |
using Getter = any (*)(const PropertyInfo* prop, any target); | |
using Setter = void (*)(const PropertyInfo* prop, any target, any value); | |
const char* name; | |
const Getter getter; | |
const Setter setter; | |
protected: | |
constexpr PropertyInfo(const char*name, Getter getter, Setter setter) : name{ name }, getter{getter}, setter{setter} | |
{ | |
} | |
}; | |
template<typename T, typename P> | |
class Property : public PropertyInfo { | |
public: | |
P T::*property; | |
static any _Get(const PropertyInfo* prop, any target) | |
{ | |
T* t = std::any_cast<T*>(target); | |
const Property* self = (const Property*) prop; | |
return t->*(self->property); | |
} | |
static void _Set(const PropertyInfo* prop, any target, any value) | |
{ | |
T* t = std::any_cast<T*>(target); | |
Property* self = (Property*) prop; | |
t->*(self->property) = std::any_cast<P>(value); | |
} | |
public: | |
constexpr Property(const char *name, P T::*property) : | |
PropertyInfo(name, _Get, _Set), | |
property(property) | |
{ | |
} | |
}; | |
template<typename T, typename P> | |
constexpr auto MakeProperty(const char* name, P T::*property){ | |
return Property<T,P>(name, property); | |
} | |
class PropertyList { | |
protected: | |
constexpr PropertyList(const PropertyInfo** list, int count) : list{list}, count{count} | |
{ | |
} | |
public: | |
const PropertyInfo** list; | |
const int count; | |
void Set(any target, const char* name, any value) | |
{ | |
for(int i = 0; i < count; i++) { | |
const auto prop = list[i]; | |
if(strings_equal(prop->name, name)) { | |
prop->setter(prop, target, value); | |
break; | |
} | |
} | |
} | |
template<typename V> | |
V Get(any target, const char* name) | |
{ | |
for(int i = 0; i < count; i++) { | |
const auto prop = list[i]; | |
if(strings_equal(prop->name, name)) { | |
return std::any_cast<V>(prop->getter(prop, target)); | |
} | |
} | |
throw std::exception(); | |
} | |
}; | |
template<int N> | |
class PropertyListN : public PropertyList | |
{ | |
public: | |
const PropertyInfo* properties[N]; | |
template<typename ... Args> | |
constexpr PropertyListN(Args ... args) : | |
PropertyList(properties, N), properties{ args... } | |
{ | |
} | |
}; | |
struct Person | |
{ | |
const char* name; | |
int age; | |
}; | |
constexpr auto person_name = MakeProperty("name", &Person::name); | |
constexpr auto person_age = MakeProperty("age", &Person::age); | |
template<typename...Args> | |
constexpr auto MakePropertyList(Args... args){ | |
return PropertyListN<sizeof...(args)>(args...); | |
} | |
constexpr auto PropertyList = MakePropertyList(&person_name, &person_age); | |
int main(){ | |
Person p = {"hello", 10}; | |
person_name.setter(&person_name, p, 20); | |
return 0;// PropertyList.Get<int>(&p, "name"); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BaseClass; | |
class TypeInfo { | |
protected: | |
using FactoryFunction = BaseClass* (*)(); | |
constexpr TypeInfo(int id, int size, FactoryFunction factory, const TypeInfo* base, const TypeInfo** interfaces, int interface_size) : | |
id{ id }, | |
base{ base }, | |
size{ size }, | |
factory{ factory }, | |
interfaces{ interfaces }, | |
interface_size{ interface_size } | |
{ | |
} | |
public: | |
const TypeInfo* base; | |
const FactoryFunction factory; | |
const TypeInfo** interfaces; | |
const int interface_size; | |
const int size; | |
const int id; | |
template<typename Super> | |
constexpr bool IsDerivedFrom() const { | |
auto super_rtti = Super::GetStaticRTTI(); | |
for (const TypeInfo* base = this; base != nullptr; base = base->base) { | |
if (base->id == super_rtti->id) { | |
return true; | |
} | |
} | |
return false; | |
} | |
template<typename Interface> | |
constexpr bool IsImplement() const { | |
const TypeInfo* interface_rtti = Interface::GetStaticRTTI(); | |
for (int i = 0; i < interface_size; i++) | |
{ | |
if (interfaces[i]->id == interface_rtti->id || interfaces[i]->IsImplement<Interface>()) | |
{ | |
return true; | |
} | |
} | |
if (this->base && base->IsImplement<Interface>()) { | |
return true; | |
} | |
return false; | |
} | |
}; | |
template<int N> | |
class Type : public TypeInfo { | |
const TypeInfo* arr[N]; | |
public: | |
template<typename ... Args> | |
constexpr Type(int id, int size, FactoryFunction factory, const TypeInfo* base, Args ... args) : | |
TypeInfo(id, size, factory, base, arr, N), arr{ args... } | |
{ | |
} | |
}; | |
template<> | |
class Type<0> : public TypeInfo { | |
public: | |
constexpr Type(int id, int size, FactoryFunction factory, const TypeInfo* base) : | |
TypeInfo(id, size, factory, base, nullptr, 0) | |
{ | |
} | |
}; | |
template<typename T, typename Base, typename ... Interface> | |
constexpr decltype(auto) MakeClass() { | |
constexpr auto factory = []() -> BaseClass* { | |
return new T(); | |
}; | |
return Type<sizeof...(Interface)>(T::TypeId, sizeof(T), factory, Base::GetStaticRTTI(), Interface::GetStaticRTTI()...); | |
} | |
template<typename T, typename Base, typename ... Interface> | |
constexpr decltype(auto) MakeInterface() { | |
return Type<sizeof...(Interface)>(T::TypeId, sizeof(T), nullptr, Base::GetStaticRTTI(), Interface::GetStaticRTTI()...); | |
} | |
namespace | |
{ | |
class Void { | |
public: | |
constexpr static int TypeId = 0; | |
constexpr static const TypeInfo* GetStaticRTTI() { | |
return nullptr; | |
} | |
}; | |
template<typename T, typename Base, typename ... Interface> | |
constexpr static decltype(auto) class_rtti = MakeClass<T, Base, Interface...>(); | |
template<typename T, typename Base, typename ... Interface> | |
constexpr static decltype(auto) interface_rtti = MakeInterface<T, Base, Interface...>(); | |
} | |
class BaseInterface { | |
public: | |
constexpr static int TypeId = -1; | |
constexpr static const TypeInfo* GetStaticRTTI(); | |
}; | |
constexpr const TypeInfo* BaseInterface::GetStaticRTTI() { | |
return &interface_rtti<BaseInterface, Void>; | |
} | |
class BaseClass { | |
public: | |
constexpr static int TypeId = 0; | |
constexpr static const TypeInfo* GetStaticRTTI() { | |
return &class_rtti<BaseClass, Void>; | |
} | |
virtual const TypeInfo* GetRTTI() { | |
return GetStaticRTTI(); | |
} | |
}; | |
template<typename T, int ID, typename Base, typename ... Interface> | |
class RTTIClass : public Base, Interface... { | |
RTTIClass() {} | |
friend T; | |
public: | |
constexpr static int TypeId = ID; | |
constexpr static const TypeInfo* GetStaticRTTI() { | |
return &class_rtti<T, Base, Interface...>; | |
} | |
virtual const TypeInfo* GetRTTI() override { | |
return &class_rtti<T, Base, Interface...>; | |
} | |
}; | |
template<typename T, int ID, typename ... Interface> | |
class RTTIInterface : public Interface... { | |
using Ty = RTTIInterface<T, ID, Interface...>; | |
public: | |
constexpr static int TypeId = ID; | |
constexpr static const TypeInfo* GetStaticRTTI() { | |
return &interface_rtti<T, Void, Interface...>; | |
} | |
}; | |
template<typename T> | |
constexpr const TypeInfo* typeof() { | |
return T::GetStaticRTTI(); | |
} | |
class IHandler : public RTTIInterface<IHandler, -2> { | |
public: | |
virtual void Handle() = 0; | |
}; | |
class ISerializer : public RTTIInterface<ISerializer, -3> { | |
public: | |
virtual void Serialize() = 0; | |
}; | |
class IRunnable : public RTTIInterface<IRunnable, -4> { | |
public: | |
virtual void Run() = 0; | |
}; | |
class IRunnable1 : public RTTIInterface<IRunnable1, -5> { | |
public: | |
virtual void Run1() = 0; | |
}; | |
class IRunnable2 : public RTTIInterface<IRunnable2, -6> { | |
public: | |
virtual void Run2() = 0; | |
}; | |
class RTTIObject : public RTTIClass<RTTIObject, 2, BaseClass, IHandler, ISerializer> | |
{ | |
void Handle() override { | |
} | |
void Serialize() override { | |
} | |
}; | |
class Node : public RTTIClass<Node, 3, BaseClass, IRunnable1, IRunnable2> { | |
void Run1() override { | |
} | |
void Run2() override { | |
} | |
}; | |
int main() { | |
constexpr auto rtti = RTTIObject::GetStaticRTTI(); | |
static_assert(rtti->IsDerivedFrom<BaseClass>()); | |
static_assert(rtti->IsImplement<ISerializer>()); | |
static_assert(rtti->IsImplement<IHandler>()); | |
// static_assert(rtti->IsImplement<IRunnable>()); | |
auto rtti11 = typeof<Node>(); | |
auto rttiobject = rtti11->factory(); | |
return rtti11 == rttiobject->GetRTTI(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment