--- /dev/null
+#ifndef MSP_GAME_REFLECTION_H_
+#define MSP_GAME_REFLECTION_H_
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <typeindex>
+#include <vector>
+
+namespace Msp::Game {
+namespace Reflection {
+
+class ClassBase;
+class Reflector;
+
+class PolymorphismBase
+{
+public:
+ virtual ~PolymorphismBase() = default;
+
+ virtual bool is_instance_of(const void *, const PolymorphismBase &) const = 0;
+};
+
+
+template<typename B>
+class RootedPolymorphism: public PolymorphismBase
+{
+public:
+ virtual bool is_instance(const B &) const = 0;
+};
+
+
+template<typename T, typename B>
+ requires std::is_base_of_v<B, T>
+class Polymorphism: public RootedPolymorphism<B>
+{
+public:
+ bool is_instance(const B &obj) const override { return std::is_same_v<B, T> || dynamic_cast<const T *>(&obj); }
+ bool is_instance_of(const void *, const PolymorphismBase &) const override;
+};
+
+
+class ClassBase
+{
+protected:
+ Reflector &reflector;
+ std::type_index type;
+ std::string name;
+ std::vector<const ClassBase *> bases;
+ std::unique_ptr<PolymorphismBase> polymorphism;
+
+ ClassBase(Reflector &, std::type_index);
+public:
+ virtual ~ClassBase() = default;
+
+ const std::type_index &get_type() const { return type; }
+ const std::string &get_name() const { return name; }
+
+ bool is_direct_base_of(const ClassBase &) const;
+ bool is_base_of(const ClassBase &) const;
+
+ template<typename T>
+ bool is_instance(const T &) const;
+
+ template<typename T>
+ bool has_polymorphic_base() const { return dynamic_cast<const RootedPolymorphism<T> *>(polymorphism.get()); }
+};
+
+
+template<typename T>
+class Class: public ClassBase
+{
+public:
+ Class(Reflector &r): ClassBase(r, typeid(T)) { }
+
+ template<typename B>
+ void set_polymorphic_base();
+
+ template<typename B>
+ void set_polymorphic_base(const T &obj) { set_polymorphic_base<B>(); check_bases<B>(obj); }
+
+private:
+ template<typename B>
+ void check_bases(const T &obj);
+};
+
+
+class Reflector
+{
+private:
+ std::vector<std::unique_ptr<ClassBase>> classes;
+
+ std::vector<std::unique_ptr<ClassBase>>::const_iterator lower_bound(const std::type_index &) const;
+
+public:
+ template<typename T>
+ Class<T> *find_class() const;
+
+ template<typename T>
+ Class<T> &get_or_create_class();
+
+ template<typename F>
+ std::vector<ClassBase *> find_classes_if(F &&) const;
+};
+
+
+inline std::vector<std::unique_ptr<ClassBase>>::const_iterator Reflector::lower_bound(const std::type_index &type) const
+{
+ return std::ranges::lower_bound(classes, type, {}, [](auto &c){ return c->get_type(); });
+}
+
+template<typename T>
+inline Class<T> *Reflector::find_class() const
+{
+ std::type_index type = typeid(T);
+ auto i = lower_bound(type);
+ return (i!=classes.end() && (*i)->get_type()==type ? static_cast<Class<T> *>(i->get()) : nullptr);
+}
+
+template<typename T>
+inline Class<T> &Reflector::get_or_create_class()
+{
+ std::type_index type = typeid(T);
+ auto i = lower_bound(type);
+ if(i==classes.end() || (*i)->get_type()!=type)
+ i = classes.emplace(i, std::make_unique<Class<T>>(std::ref(*this)));
+ return static_cast<Class<T> &>(*i->get());
+}
+
+template<typename F>
+inline std::vector<ClassBase *> Reflector::find_classes_if(F &&pred) const
+{
+ std::vector<ClassBase *> result;
+ for(auto &c: classes)
+ if(pred(*c))
+ result.push_back(&*c);
+ return result;
+}
+
+
+template<typename T, typename B>
+inline bool Polymorphism<T, B>::is_instance_of(const void *obj, const PolymorphismBase &other) const
+{
+ if(const RootedPolymorphism<B> *rooted = dynamic_cast<const RootedPolymorphism<B> *>(&other))
+ return rooted->is_instance(*static_cast<const T *>(obj));
+ return false;
+}
+
+
+template<typename T>
+inline bool ClassBase::is_instance(const T &obj) const
+{
+ if(const RootedPolymorphism<T> *p = dynamic_cast<const RootedPolymorphism<T> *>(polymorphism.get()))
+ return p->is_instance(obj);
+ else if(ClassBase *c = reflector.find_class<T>(); c->polymorphism)
+ return c->polymorphism->is_instance_of(&obj, *polymorphism);
+ return false;
+}
+
+
+template<typename T>
+template<typename B>
+inline void Class<T>::set_polymorphic_base()
+{
+ if(!polymorphism)
+ polymorphism = std::make_unique<Polymorphism<T, B>>();
+ else if(!dynamic_cast<const Polymorphism<T, B> *>(polymorphism.get()))
+ throw std::logic_error("conflicting polymorphism");
+}
+
+template<typename T>
+template<typename B>
+inline void Class<T>::check_bases(const T &obj)
+{
+ std::vector<const ClassBase *> candidate_bases;
+ for(const ClassBase *b: reflector.find_classes_if([](const ClassBase &c){ return c.has_polymorphic_base<B>(); }))
+ if(b!=this && b->is_instance<B>(obj))
+ candidate_bases.push_back(b);
+
+ for(auto i=candidate_bases.begin(); i!=candidate_bases.end(); )
+ {
+ if(std::ranges::any_of(candidate_bases, [i](const ClassBase *c){ return (c!=*i && (*i)->is_direct_base_of(*c)); }))
+ i = candidate_bases.erase(i);
+ else
+ ++i;
+ }
+
+ bases = std::move(candidate_bases);
+}
+
+} // namespace Reflection
+} // namespace Msp::Game
+
+#endif