meta/runtime/reflection.h
2024-03-05 09:45:08 +08:00

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> &params) 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