Skip to content

Instantly share code, notes, and snippets.

@benloong
Last active October 19, 2017 09:59
Show Gist options
  • Save benloong/15fb15aeec562ec07113c6c2f6c1e4af to your computer and use it in GitHub Desktop.
Save benloong/15fb15aeec562ec07113c6c2f6c1e4af to your computer and use it in GitHub Desktop.
c++ reflection
#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;
}
#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");
}
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