Skip to content

Instantly share code, notes, and snippets.

@Bueddl
Last active January 14, 2017 23:43
Show Gist options
  • Save Bueddl/6a5fa8da57909d2e4bc85f5509273024 to your computer and use it in GitHub Desktop.
Save Bueddl/6a5fa8da57909d2e4bc85f5509273024 to your computer and use it in GitHub Desktop.
Runtime Type Information
#include <exception>
#include <iostream>
#include <unordered_map>
class object_base;
struct rt_type_info
{
const char *name;
const rt_type_info *base;
object_base* (*create_fn)();
void (*delete_fn)(object_base *);
};
class object_base
{
public:
virtual ~object_base()
{}
virtual const rt_type_info *type_info() const = 0;
};
template<class T, class B = T>
class rt_type_info_enabled : virtual public rt_type_info_enabled<T>, virtual public rt_type_info_enabled<B>, public B
{
const rt_type_info *type_info() const override
{
return rt_type_info_enabled<T>::type_info();
}
};
template<class T, class B>
class type_info_factory;
template<class T>
class rt_type_info_enabled<T, T> : virtual public object_base
{
friend class rt_type_info_init;
template<class fT, class fB>
friend class type_info_factory;
public:
const rt_type_info *type_info() const override
{
return _rtti;
}
static const rt_type_info *get()
{
return _rtti;
}
private:
static void set(rt_type_info *type_info)
{
_rtti = type_info;
}
static rt_type_info *_rtti;
};
template<class T>
rt_type_info *rt_type_info_enabled<T>::_rtti = nullptr;
template<class C, class T>
bool instance_of(T *object)
{
return rt_type_info_enabled<C>::get() == object->type_info();
}
template<class B, class T>
bool derived_by(T *object)
{
for(const rt_type_info *rtti = object->type_info(); rtti; rtti = rtti->base)
if (rt_type_info_enabled<B>::get() == rtti)
return true;
return false;
}
template<class T, class B>
T *try_cast(B *object)
{
if (!derived_by<T>(object))
return nullptr;
return reinterpret_cast<T *>(object);
};
std::unordered_map<std::string, const rt_type_info*> type_info_storage;
template<class T>
object_base* default_creator()
{
return new T;
}
void default_deleter(object_base *object)
{
delete object;
}
template<class T, class B = T>
struct type_info_factory
{
static void init(const char *name)
{
static rt_type_info info{name, rt_type_info_enabled<B>::get(), default_creator<T>, default_deleter};
rt_type_info_enabled<T>::set(&info);
type_info_storage.emplace(name, &info);
}
static void init_abstract(const char *name)
{
static rt_type_info info{name, rt_type_info_enabled<B>::get(), nullptr, nullptr};
rt_type_info_enabled<T>::set(&info);
type_info_storage.emplace(name, &info);
}
};
template<class T>
struct type_info_factory<T, T>
{
static void init(const char *name)
{
static rt_type_info info{name, nullptr, default_creator<T>, default_deleter};
rt_type_info_enabled<T>::set(&info);
type_info_storage.emplace(name, &info);
}
static void init_abstract(const char *name)
{
static rt_type_info info{name, nullptr, nullptr, nullptr};
rt_type_info_enabled<T>::set(&info);
type_info_storage.emplace(name, &info);
}
};
class illegal_create_request_exception : public std::exception
{
public:
illegal_create_request_exception(const rt_type_info *type_info)
: _type_info(type_info)
{}
const char *what() const noexcept override
{
static std::string message = "cannot create instance of abstract class ";
message += _type_info->name;
return message.c_str();
}
private:
const rt_type_info *_type_info;
};
class unresolved_create_request_exception : public std::exception
{
public:
unresolved_create_request_exception(const std::string class_name)
: _class_name(class_name)
{}
const char *what() const noexcept override
{
static std::string message = "cannot create instance of unresolved class ";
message += _class_name;
return message.c_str();
}
private:
const std::string _class_name;
};
object_base* create_object(const rt_type_info *type_info)
{
if (!type_info->create_fn)
throw illegal_create_request_exception(type_info);
return type_info->create_fn();
}
object_base* create_object(const object_base *original)
{
return create_object(original->type_info());
}
object_base* create_object(const std::string &class_name)
{
std::unordered_map<std::string, const rt_type_info*>::iterator it
= type_info_storage.find(class_name);
if (it == type_info_storage.end())
throw unresolved_create_request_exception(class_name);
return create_object(it->second);
}
// --------------------------------------------------------
class base : public rt_type_info_enabled<base>
{
public:
void method_in_base() const
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class derived : public rt_type_info_enabled<derived, base>
{
public:
void method_in_derived() const
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class other : public rt_type_info_enabled<other>
{
public:
};
// --------------------------------------------------------
class type_info_init
{
public:
type_info_init()
{
type_info_factory<object_base>::init_abstract("object_base");
type_info_factory<base, object_base>::init("base");
type_info_factory<derived, base>::init("derived");
type_info_factory<other, object_base>::init("other");
}
} rtti_init;
int main()
{
object_base *object = new derived;
std::cout << "object is of type " << object->type_info()->name << std::endl;
object_base *clone = create_object(object);
object->type_info()->delete_fn(object);
std::cout << "clone is of type " << clone->type_info()->name << std::endl;
derived *d;
if (d = try_cast<derived>(clone))
d->method_in_derived();
clone->type_info()->delete_fn(clone);
object_base *object_by_str = create_object("object_base");
std::cout << "object_by_str is of type " << object_by_str->type_info()->name << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment