283 lines
9.1 KiB
C++
283 lines
9.1 KiB
C++
#pragma once
|
|
#ifndef META_RUNTIME_REFLECTION_H
|
|
#define META_RUNTIME_REFLECTION_H
|
|
#include "any.h"
|
|
#include <cstdlib>
|
|
#include <cxxabi.h>
|
|
#include <sled/log/log.h>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace meta {
|
|
namespace reflection {
|
|
namespace detail {
|
|
inline std::string
|
|
RemoveTypeSpace(const std::string &str, const std::string &chars = "[]()<>*&:")
|
|
{
|
|
std::string result;
|
|
// trim
|
|
{
|
|
result = str.substr(str.find_first_not_of(' '));
|
|
result = result.substr(0, result.find_last_not_of(' ') + 1);
|
|
}
|
|
|
|
// remove right space
|
|
for (size_t i = 0; i < result.size();) {
|
|
if (result[i] == ' ') {
|
|
bool left_is_chars = i > 0 && chars.find(result[i - 1]) != std::string::npos;
|
|
bool right_is_chars
|
|
= (i + 1 < str.size()) && chars.find(result[i + 1]) != std::string::npos;
|
|
if (left_is_chars || right_is_chars) {
|
|
result.erase(i, 1);
|
|
} else {
|
|
++i;
|
|
}
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template<typename T, typename U = typename std::decay<T>::type>
|
|
inline std::string
|
|
PrettyNameImpl()
|
|
{
|
|
const std::string name = typeid(U).name();
|
|
std::string pretty_name = name;
|
|
int status = -4;
|
|
char *res = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status);
|
|
if (status == 0) { pretty_name = std::string(res); }
|
|
free(res);
|
|
return RemoveTypeSpace(pretty_name);
|
|
}
|
|
}// namespace detail
|
|
|
|
template<typename T>
|
|
inline const std::string &
|
|
PrettyName()
|
|
{
|
|
static std::string pretty_name = detail::PrettyNameImpl<T>();
|
|
return pretty_name;
|
|
}
|
|
|
|
#if defined(__REFLECTION_PARSER__)
|
|
#define META(...) __attribute__((annotate(#__VA_ARGS__)))
|
|
#define CLASS(class_name, ...) class __attribute__((annotate(#__VA_ARGS__))) class_name
|
|
#define STRUCT(struct_name, ...) struct __attribute__((annotate(#__VA_ARGS__))) struct_name
|
|
#else
|
|
#define META(...)
|
|
#define CLASS(class_name, ...) class class_name
|
|
#define STRUCT(struct_name, ...) struct struct_name
|
|
#endif// __REFLECTION_PARSER_ \
|
|
|
|
#define META_REFLECTION_BODY(class_name) \
|
|
class class_name##_Class; \
|
|
class class_name##_Constructor; \
|
|
class class_name##_Method; \
|
|
class class_name##_Field; \
|
|
class class_name##_Serializer; \
|
|
friend class class_name##_Class; \
|
|
friend class class_name##_Constructor; \
|
|
friend class class_name##_Method; \
|
|
friend class class_name##_Field; \
|
|
friend class class_name##_Serializer; \
|
|
friend class ::meta::reflection::Registry;
|
|
|
|
class Constructor;
|
|
class Method;
|
|
class Field;
|
|
class Class;
|
|
|
|
class BaseType {
|
|
public:
|
|
BaseType(const std::string &name, std::shared_ptr<Class> parent) : name_(name), parent_(parent)
|
|
{}
|
|
|
|
virtual ~BaseType() = default;
|
|
|
|
std::string Name() const { return name_; }
|
|
|
|
std::shared_ptr<Class> Parent() const { return parent_; }
|
|
|
|
private:
|
|
const std::string name_;
|
|
std::shared_ptr<Class> parent_;
|
|
};
|
|
|
|
class Method : public BaseType {
|
|
public:
|
|
Method(const std::string &name, std::shared_ptr<Class> parent) : BaseType(name, parent) {}
|
|
|
|
~Method() override = default;
|
|
|
|
std::shared_ptr<Class> Parent() const { return parent_; }
|
|
|
|
template<typename ReturnT,
|
|
typename std::enable_if<!std::is_void<ReturnT>::value, ReturnT>::type * = nullptr,
|
|
typename... Params>
|
|
inline ReturnT InvokeAndCast(void *instance, Params &&...params) const
|
|
{
|
|
return ::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {params...}));
|
|
}
|
|
|
|
template<typename ReturnT,
|
|
typename std::enable_if<std::is_void<ReturnT>::value, int>::type * = nullptr,
|
|
typename... Params>
|
|
inline void InvokeAndCast(void *instance, Params &&...params) const
|
|
{
|
|
::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {params...}));
|
|
}
|
|
|
|
template<typename... Params>
|
|
inline ::meta::reflection::any Invoke(void *instance, Params &&...params) const
|
|
{
|
|
return InvokeImpl(instance, {params...});
|
|
}
|
|
|
|
protected:
|
|
virtual ::meta::reflection::any
|
|
InvokeImpl(void *instance, const std::vector<::meta::reflection::any> ¶ms) const
|
|
= 0;
|
|
|
|
private:
|
|
std::shared_ptr<Class> parent_;
|
|
};
|
|
|
|
class Field : public BaseType {
|
|
public:
|
|
Field(const std::string &name, std::shared_ptr<Class> parent) : BaseType(name, parent) {}
|
|
|
|
template<typename T, typename std::enable_if<!std::is_void<T>::value, T>::type * = nullptr>
|
|
inline T GetAndCast(void *instance) const
|
|
{
|
|
return ::meta::reflection::any_cast<T>(GetImpl(instance));
|
|
}
|
|
|
|
::meta::reflection::any Get(void *instance) const { return GetImpl(instance); }
|
|
|
|
template<typename T>
|
|
inline void Set(void *instance, const T &value) const
|
|
{
|
|
SetImpl(instance, ::meta::reflection::any(value));
|
|
}
|
|
|
|
protected:
|
|
virtual ::meta::reflection::any GetImpl(void *instance) const = 0;
|
|
virtual void SetImpl(void *instance, const ::meta::reflection::any &value) const = 0;
|
|
};
|
|
|
|
class Class : public BaseType {
|
|
public:
|
|
Class(const std::string &name, std::shared_ptr<Class> base_class = nullptr)
|
|
: BaseType(name, base_class)
|
|
{}
|
|
|
|
inline std::vector<std::shared_ptr<Class>> GetBaseClasses() const { return base_classes_; }
|
|
|
|
inline std::shared_ptr<Class> GetBaseClass(const std::string &name) const
|
|
{
|
|
auto iter = base_class_by_name_.find(name);
|
|
if (iter != base_class_by_name_.end()) { return iter->second; }
|
|
return nullptr;
|
|
}
|
|
|
|
inline std::vector<std::shared_ptr<Method>> GetMethods() const { return methods_; }
|
|
|
|
inline std::shared_ptr<Method> GetMethod(const std::string &name) const
|
|
{
|
|
auto iter = method_by_name_.find(name);
|
|
if (iter != method_by_name_.end()) { return iter->second; }
|
|
return nullptr;
|
|
}
|
|
|
|
inline std::vector<std::shared_ptr<Field>> GetFields() const { return fields_; }
|
|
|
|
inline std::shared_ptr<Field> GetField(const std::string &name) const
|
|
{
|
|
auto iter = field_by_name_.find(name);
|
|
if (iter != field_by_name_.end()) { return iter->second; }
|
|
return nullptr;
|
|
}
|
|
|
|
protected:
|
|
void AddBaseClass(std::shared_ptr<Class> clz)
|
|
{
|
|
if (base_class_by_name_.find(clz->Name()) != base_class_by_name_.end()) { return; }
|
|
base_classes_.push_back(clz);
|
|
base_class_by_name_[clz->Name()] = clz;
|
|
}
|
|
|
|
void AddMethod(std::shared_ptr<Method> method)
|
|
{
|
|
if (method_by_name_.find(method->Name()) != method_by_name_.end()) { return; }
|
|
methods_.push_back(method);
|
|
method_by_name_[method->Name()] = method;
|
|
}
|
|
|
|
void AddField(std::shared_ptr<Field> field)
|
|
{
|
|
fields_.push_back(field);
|
|
field_by_name_[field->Name()] = field;
|
|
}
|
|
|
|
private:
|
|
std::unordered_map<std::string, std::shared_ptr<Class>> base_class_by_name_;
|
|
std::unordered_map<std::string, std::shared_ptr<Method>> method_by_name_;
|
|
std::unordered_map<std::string, std::shared_ptr<Field>> field_by_name_;
|
|
|
|
std::vector<std::shared_ptr<Class>> base_classes_;
|
|
std::vector<std::shared_ptr<Method>> methods_;
|
|
std::vector<std::shared_ptr<Field>> fields_;
|
|
};
|
|
|
|
class Registry {
|
|
public:
|
|
static Registry *Instance()
|
|
{
|
|
static Registry instance;
|
|
return &instance;
|
|
}
|
|
|
|
~Registry() {}
|
|
|
|
static void RegisterAll();
|
|
static void UnregisterAll();
|
|
|
|
static std::shared_ptr<Class> GetClass(const std::string &name)
|
|
{
|
|
return Instance()->GetClassInner(name);
|
|
}
|
|
|
|
static void RegisterClass(std::shared_ptr<Class> clz) { Instance()->RegisterClassInner(clz); }
|
|
|
|
static std::vector<std::shared_ptr<Class>> GetClasses() { return Instance()->classes(); }
|
|
|
|
private:
|
|
std::shared_ptr<Class> GetClassInner(const std::string &name) const
|
|
{
|
|
auto iter = class_by_name_.find(name);
|
|
if (iter != class_by_name_.end()) { return iter->second; }
|
|
return nullptr;
|
|
}
|
|
|
|
inline void RegisterClassInner(std::shared_ptr<Class> clz)
|
|
{
|
|
if (class_by_name_.find(clz->Name()) != class_by_name_.end()) { return; }
|
|
classes_.push_back(clz);
|
|
class_by_name_[clz->Name()] = clz;
|
|
}
|
|
|
|
inline std::vector<std::shared_ptr<Class>> classes() const { return classes_; }
|
|
|
|
std::unordered_map<std::string, std::shared_ptr<Class>> class_by_name_;
|
|
std::vector<std::shared_ptr<Class>> classes_;
|
|
};
|
|
}// namespace reflection
|
|
|
|
}// namespace meta
|
|
|
|
#endif// META_RUNTIME_REFLECTION_H
|