Skip to content

Instantly share code, notes, and snippets.

@Winded
Created August 7, 2016 15:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Winded/a9876b337ee1c055a176abfd9f06ade0 to your computer and use it in GitHub Desktop.
Save Winded/a9876b337ee1c055a176abfd9f06ade0 to your computer and use it in GitHub Desktop.
C++ Meta-object system
#include "attribute.h"
WMetaAttribute::WMetaAttribute(std::string name, std::string value)
: WMetaInfo(TYPE_ATTRIBUTE), mName(name), mValue(value)
{
}
std::string WMetaAttribute::name() const
{
return mName;
}
std::string WMetaAttribute::value() const
{
return mValue;
}
#ifndef WMETAATTRIBUTE_H
#define WMETAATTRIBUTE_H
#include "object.h"
/**
* @brief Attributes are static data attached to class metadata.
*/
class WINDENGINE_DLL WMetaAttribute : public WMetaInfo
{
public:
WMetaAttribute(std::string name, std::string value);
std::string name() const;
std::string value() const;
private:
std::string mName, mValue;
};
#endif // WMETAATTRIBUTE_H
#include "input.h"
WMetaInput::WMetaInput(std::string name, std::vector<WMetaPropertyType> parameterTypes)
: WMetaInfo(TYPE_INPUT), mName(name), mParameterTypes(parameterTypes)
{
}
std::string WMetaInput::name() const
{
return mName;
}
int WMetaInput::parameterCount() const
{
return mParameterTypes.size();
}
WMetaPropertyType WMetaInput::getParameterType(int index) const
{
return mParameterTypes[index];
}
#ifndef WMETAINPUT_H
#define WMETAINPUT_H
#include "object.h"
#include "property.h"
class WINDENGINE_DLL WMetaInput : public WMetaInfo
{
public:
WMetaInput(std::string name, std::vector<WMetaPropertyType> parameterTypes);
std::string name() const;
int parameterCount() const;
WMetaPropertyType getParameterType(int index) const;
virtual void invoke(void *obj, void *p1 = 0) = 0;
private:
std::string mName;
std::vector<WMetaPropertyType> mParameterTypes;
};
template<class C>
class WMetaInputNoParams : public WMetaInput
{
public:
typedef void(C::*FuncP)();
WMetaInputNoParams(std::string name, std::vector<WMetaPropertyType> parameterTypes, FuncP methodPointer)
: WMetaInput(name, parameterTypes), mMethodPointer(methodPointer)
{
}
void invoke(void *obj, void *p1 = 0)
{
(((C*)obj)->*mMethodPointer)();
}
private:
FuncP mMethodPointer;
};
template<class C, class T>
class WMetaInputOneParam : public WMetaInput
{
public:
typedef void(C::*FuncP)(T);
WMetaInputOneParam(std::string name, std::vector<WMetaPropertyType> parameterTypes, FuncP methodPointer)
: WMetaInput(name, parameterTypes), mMethodPointer(methodPointer)
{
}
void invoke(void *obj, void *p1 = 0)
{
(((C*)obj)->*mMethodPointer)(*((T*)p1));
}
private:
FuncP mMethodPointer;
};
#endif // WMETAINPUT_H
#ifndef WMETAMACROS_H
#define WMETAMACROS_H
#define META_OBJECT_INIT(C, BC) \
public: \
typedef BC BaseClass; \
virtual WMetaObject *metaObject() const; \
static WMetaObject *staticMetaObject(); \
static std::vector<WMetaInfo*> getMetaInfo(); \
private: \
static WMetaObject sMetaObject;
#define META_OBJECT_REGISTER(C, BC) \
WMetaObject *C::metaObject() const { \
return &C::sMetaObject; \
} \
WMetaObject *C::staticMetaObject() { \
return &sMetaObject; \
} \
static void *getDefaultConstructorOf##C() { \
return new C(); \
} \
WMetaObject C::sMetaObject(#C, #BC, &getDefaultConstructorOf##C, C::getMetaInfo());
#define META_INFO_BEGIN(C) \
std::vector<WMetaInfo*> C::getMetaInfo() { \
typedef C ThisClass; \
C inst; \
std::vector<WMetaInfo*> metaInfo; \
#define META_INFO_END() \
return metaInfo; \
}
#define META_PROPERTY(Name, Type, Flags) \
metaInfo.push_back(new WMetaProperty(#Name, Type, Flags, \
(char*)&inst.Name - (char*)&inst, sizeof(inst.Name)));
#define META_PROPERTY_OBJECT(Name, Flags) \
metaInfo.push_back(new WMetaProperty(#Name, inst.Name.type(), Flags, \
(char*)&inst.Name - (char*)&inst, sizeof(inst.Name)));
#define META_INPUT_NO_PARAMS(Name) \
std::vector<WMetaPropertyType> pTypesFor##Name; \
metaInfo.push_back(new WMetaInputNoParams<ThisClass>(#Name, \
pTypesFor##Name, &ThisClass::Name));
#define META_INPUT_ONE_PARAM(Name, Type1, ActualType1) \
std::vector<WMetaPropertyType> pTypesFor##Name; \
pTypesFor##Name.push_back(Type1); \
metaInfo.push_back(new WMetaInputOneParam<ThisClass, ActualType1>(#Name, \
pTypesFor##Name, &ThisClass::Name));
#define META_OUTPUT_NO_PARAMS(Name) \
std::vector<WMetaPropertyType> pTypesFor##Name; \
metaInfo.push_back(new WMetaOutput(#Name, pTypesFor##Name, (char*)&inst.Name - (char*)&inst));
#define META_OUTPUT_ONE_PARAM(Name, Type1) \
std::vector<WMetaPropertyType> pTypesFor##Name; \
pTypesFor##Name.push_back(Type1); \
metaInfo.push_back(new WMetaOutput(#Name, pTypesFor##Name, (char*)&inst.Name - (char*)&inst));
#define META_ATTRIBUTE(Name, Value) \
metaInfo.push_back(new WMetaAttribute(#Name, Value));
#endif // WMETAMACROS_H
#include "object.h"
#include "repository.h"
#include "../object/wobject.h"
#include "../util/pointer.h"
WMetaObject::WMetaObject(std::string name, std::string baseClassName, DefaultConstructorFunc defaultConstructor,
std::vector<WMetaInfo *> info) :
mName(name), mBaseClassName(baseClassName), mDefaultConstructor(defaultConstructor)
{
for(int i = 0; i < info.size(); i++) {
WMetaInfo *inf = info[i];
inf->mMetaObject = this;
switch(inf->infoType()) {
case WMetaInfo::TYPE_PROPERTY:
mProperties.push_back((WMetaProperty*)inf);
break;
case WMetaInfo::TYPE_INPUT:
mInputs.push_back((WMetaInput*)inf);
break;
case WMetaInfo::TYPE_OUTPUT:
mOutputs.push_back((WMetaOutput*)inf);
break;
case WMetaInfo::TYPE_ATTRIBUTE:
mAttributes.push_back((WMetaAttribute*)inf);
break;
}
}
WMetaRepository *repo = WMetaRepository::getInstance();
repo->addMetaObject(this);
}
WMetaObject::~WMetaObject()
{
for(auto it = mProperties.begin(); it != mProperties.end(); ++it) {
if(*it) {
delete *it;
}
}
for(auto it = mInputs.begin(); it != mInputs.end(); ++it) {
if(*it) {
delete *it;
}
}
for(auto it = mOutputs.begin(); it != mOutputs.end(); ++it) {
if(*it) {
delete *it;
}
}
for(auto it = mAttributes.begin(); it != mAttributes.end(); ++it) {
if(*it) {
delete *it;
}
}
}
std::string WMetaObject::name() const
{
return mName;
}
std::string WMetaObject::baseClassName() const
{
return mBaseClassName;
}
WMetaObject *WMetaObject::baseClass() const
{
WMetaRepository *repo = WMetaRepository::getInstance();
for(int i = 0; i < repo->metaObjectCount(); i++) {
WMetaObject *obj = repo->metaObject(i);
if(obj->name() == mBaseClassName)
return obj;
}
return 0;
}
bool WMetaObject::isSubclassOf(std::string type) const
{
if(name() == type)
return true;
WMetaObject *bMeta = baseClass();
while(true) {
if(!bMeta)
return false;
if(bMeta->name() == type)
return true;
bMeta = bMeta->baseClass();
}
}
void *WMetaObject::createInstance()
{
return mDefaultConstructor();
}
void WMetaObject::copyProperties(void *from, void *to)
{
WMetaObject *b = baseClass();
if(b)
b->copyProperties(from, to);
for(auto it = mProperties.begin(); it != mProperties.end(); ++it) {
WMetaProperty *prop = *it;
switch(prop->type()) {
case PROPERTY_STRING:
{
std::string str;
prop->getValue(from, &str);
prop->setValue(to, &str);
break;
}
case PROPERTY_OBJECT:
{
WPointer<WObject> p;
prop->getValue(from, &p);
prop->setValue(to, &p);
break;
}
default:
{
void *m = malloc(prop->size());
prop->getValue(from, m);
prop->setValue(to, m);
free(m);
break;
}
}
}
}
std::vector<WMetaProperty*>::const_iterator WMetaObject::propertiesBegin() const
{
return mProperties.begin();
}
std::vector<WMetaProperty*>::const_iterator WMetaObject::propertiesEnd() const
{
return mProperties.end();
}
WMetaProperty *WMetaObject::getProperty(std::string name) const
{
for(int i = 0; i < mProperties.size(); i++) {
WMetaProperty *prop = mProperties[i];
if(prop->name() == name)
return prop;
}
WMetaObject *b = baseClass();
if(b)
return b->getProperty(name);
else
return 0;
}
std::vector<WMetaInput*>::const_iterator WMetaObject::inputsBegin() const
{
return mInputs.begin();
}
std::vector<WMetaInput*>::const_iterator WMetaObject::inputsEnd() const
{
return mInputs.end();
}
WMetaInput *WMetaObject::getInput(std::string name)
{
for(int i = 0; i < mInputs.size(); i++) {
WMetaInput *inp = mInputs[i];
if(inp->name() == name)
return inp;
}
WMetaObject *b = baseClass();
if(b)
return b->getInput(name);
else
return 0;
}
std::vector<WMetaOutput*>::const_iterator WMetaObject::outputsBegin() const
{
return mOutputs.begin();
}
std::vector<WMetaOutput*>::const_iterator WMetaObject::outputsEnd() const
{
return mOutputs.end();
}
WMetaOutput *WMetaObject::getOutput(std::string name)
{
for(int i = 0; i < mOutputs.size(); i++) {
WMetaOutput *outp = mOutputs[i];
if(outp->name() == name)
return outp;
}
WMetaObject *b = baseClass();
if(b)
return b->getOutput(name);
else
return 0;
}
std::vector<WMetaAttribute*>::const_iterator WMetaObject::attributesBegin() const
{
return mAttributes.begin();
}
std::vector<WMetaAttribute*>::const_iterator WMetaObject::attributesEnd() const
{
return mAttributes.end();
}
std::string WMetaObject::getAttribute(std::string name, bool recursive) const
{
for(auto it = mAttributes.begin(); it != mAttributes.end(); ++it) {
WMetaAttribute *att = *it;
if(att->name() == name)
return att->value();
}
if(recursive) {
WMetaObject *b = baseClass();
if(b)
return b->getAttribute(name, true);
}
return "";
}
#ifndef WMETAOBJECT_H
#define WMETAOBJECT_H
#include "../global.h"
#include <string>
#include <vector>
class WMetaInfo;
class WMetaProperty;
class WMetaInput;
class WMetaOutput;
class WMetaAttribute;
/**
* @brief Provides metadata about a WObject class.
*/
class WINDENGINE_DLL WMetaObject
{
public:
typedef void*(*DefaultConstructorFunc)();
WMetaObject(std::string name, std::string baseClassName, DefaultConstructorFunc defaultConstructor,
std::vector<WMetaInfo*> info);
~WMetaObject();
std::string name() const;
std::string baseClassName() const;
WMetaObject *baseClass() const;
bool isSubclassOf(std::string type) const;
void *createInstance();
/**
* @brief Copy properties from one object to another.
* NOTE: Objects must be of MetaObject's representing type.
*/
void copyProperties(void *from, void *to);
std::vector<WMetaProperty*>::const_iterator propertiesBegin() const;
std::vector<WMetaProperty*>::const_iterator propertiesEnd() const;
/** Find property meta info with the given name. Searches recursively from base classes as well. */
WMetaProperty *getProperty(std::string name) const;
std::vector<WMetaInput*>::const_iterator inputsBegin() const;
std::vector<WMetaInput*>::const_iterator inputsEnd() const;
/** Find input meta info with the given name. Searches recursively from base classes as well. */
WMetaInput *getInput(std::string name);
std::vector<WMetaOutput*>::const_iterator outputsBegin() const;
std::vector<WMetaOutput*>::const_iterator outputsEnd() const;
/** Find output meta info with the given name. Searches recursively from base classes as well. */
WMetaOutput *getOutput(std::string name);
std::vector<WMetaAttribute*>::const_iterator attributesBegin() const;
std::vector<WMetaAttribute*>::const_iterator attributesEnd() const;
/** Get value of an attribute of given name. Not recursive by default. */
std::string getAttribute(std::string name, bool recursive = false) const;
private:
std::string mName;
std::string mBaseClassName;
DefaultConstructorFunc mDefaultConstructor;
std::vector<WMetaProperty*> mProperties;
std::vector<WMetaInput*> mInputs;
std::vector<WMetaOutput*> mOutputs;
std::vector<WMetaAttribute*> mAttributes;
};
class WMetaInfo
{
public:
enum Type {
TYPE_PROPERTY,
TYPE_INPUT,
TYPE_OUTPUT,
TYPE_ATTRIBUTE
};
WMetaInfo(Type type) : mInfoType(type), mMetaObject(0) {}
Type infoType() const
{
return mInfoType;
}
WMetaObject *metaObject() const
{
return mMetaObject;
}
private:
friend class WMetaObject;
Type mInfoType;
WMetaObject *mMetaObject;
};
#endif // WMETAOBJECT_H
#include "output.h"
#include "../events/woutput.h"
WMetaOutput::WMetaOutput(std::string name, std::vector<WMetaPropertyType> parameterTypes, int offset)
: WMetaInfo(TYPE_OUTPUT), mName(name), mParameterTypes(parameterTypes), mOffset(offset)
{
}
std::string WMetaOutput::name() const
{
return mName;
}
int WMetaOutput::offset() const
{
return mOffset;
}
int WMetaOutput::parameterCount() const
{
return mParameterTypes.size();
}
WMetaPropertyType WMetaOutput::getParameterType(int index) const
{
return mParameterTypes[index];
}
WOutput *WMetaOutput::getReference(void *obj) const
{
return (WOutput*)((char*)obj + mOffset);
}
#ifndef WMETAOUTPUT_H
#define WMETAOUTPUT_H
#include "object.h"
#include "property.h"
class WOutput;
class WINDENGINE_DLL WMetaOutput : public WMetaInfo
{
public:
WMetaOutput(std::string name, std::vector<WMetaPropertyType> parameterTypes, int offset);
std::string name() const;
int offset() const;
int parameterCount() const;
WMetaPropertyType getParameterType(int index) const;
WOutput *getReference(void *obj) const;
private:
std::string mName;
std::vector<WMetaPropertyType> mParameterTypes;
int mOffset;
};
#endif // WMETAOUTPUT_H
#include "property.h"
#include "../util/pointer.h"
#include <cstring>
#include <memory>
WMetaProperty::WMetaProperty(std::string name, WMetaPropertyType type, int flags, int offset, int size)
: WMetaInfo(TYPE_PROPERTY), mName(name), mType(type), mFlags(flags), mOffset(offset), mSize(size)
{
}
WMetaProperty::WMetaProperty(std::string name, std::string objectType, int flags, int offset, int size)
: WMetaInfo(TYPE_PROPERTY), mName(name), mType(PROPERTY_OBJECT), mObjectType(objectType), mFlags(flags), mOffset(offset), mSize(size)
{
}
std::string WMetaProperty::name() const
{
return mName;
}
WMetaPropertyType WMetaProperty::type() const
{
return mType;
}
std::string WMetaProperty::objectType() const
{
return mObjectType;
}
int WMetaProperty::flags() const
{
return mFlags;
}
int WMetaProperty::offset() const
{
return mOffset;
}
int WMetaProperty::size() const
{
return mSize;
}
void WMetaProperty::getValue(void *obj, void *buf)
{
switch(mType) {
case PROPERTY_STRING:
{
std::string *str = (std::string*)buf;
std::string *objStr = (std::string*)((char*)obj + mOffset);
*str = *objStr;
break;
}
//case PROPERTY_ENTITY:
//case PROPERTY_COMPONENT:
//case PROPERTY_ASSET:
case PROPERTY_OBJECT:
{
WPointerBase *objSp = (WPointerBase*)((char*)obj + mOffset);
WPointerBase *sp = (WPointerBase*)buf;
sp->set(objSp->rawPointer());
break;
}
default:
memcpy(buf, (char*)obj + mOffset, mSize);
break;
}
}
void WMetaProperty::setValue(void *obj, void *buf)
{
switch(mType) {
case PROPERTY_STRING:
{
std::string *str = (std::string*)buf;
std::string *objStr = (std::string*)((char*)obj + mOffset);
*objStr = *str;
break;
}
//case PROPERTY_ENTITY:
//case PROPERTY_COMPONENT:
//case PROPERTY_ASSET:
case PROPERTY_OBJECT:
{
WPointerBase *objSp = (WPointerBase*)((char*)obj + mOffset);
WPointerBase *sp = (WPointerBase*)buf;
objSp->set(sp->rawPointer());
break;
}
default:
memcpy((char*)obj + mOffset, buf, mSize);
break;
}
}
#ifndef WMETAPROPERTY_H
#define WMETAPROPERTY_H
#include <string>
#include "object.h"
enum WMetaPropertyType
{
PROPERTY_BOOL,
PROPERTY_FLOAT,
PROPERTY_DOUBLE,
PROPERTY_INT8,
PROPERTY_INT16,
PROPERTY_INT32,
PROPERTY_INT64,
PROPERTY_UINT8,
PROPERTY_UINT16,
PROPERTY_UINT32,
PROPERTY_UINT64,
PROPERTY_STRING,
PROPERTY_VECTOR,
PROPERTY_ANGLE,
PROPERTY_QUATERNION,
PROPERTY_TRANSFORM,
PROPERTY_MATRIX,
PROPERTY_COLOR,
PROPERTY_UID,
PROPERTY_OBJECT,
// Special property type, with very limited use
PROPERTY_CUSTOM
};
enum WMetaPropertyFlags
{
PFLAGS_NONE = 0, // No flags
PFLAGS_EDITABLE = (1 << 0), // Property is editable within the SDK
PFLAGS_ARRAY = (1 << 1), // Property is an array of the given type, and not a single instance
PFLAGS_SERIALIZEABLE = (1 << 2), // Property can be serialized
};
class WINDENGINE_DLL WMetaProperty : public WMetaInfo
{
public:
WMetaProperty(std::string name, WMetaPropertyType type, int flags, int offset, int size);
WMetaProperty(std::string name, std::string objectType, int flags, int offset, int size);
std::string name() const;
WMetaPropertyType type() const;
/**
* @brief Return object type name. Only useful if property type is OBJECT
* @return
*/
std::string objectType() const;
int flags() const;
int offset() const;
int size() const;
void getValue(void *obj, void *buf);
void setValue(void *obj, void *buf);
private:
std::string mName;
WMetaPropertyType mType;
std::string mObjectType;
int mFlags;
int mOffset;
int mSize;
};
#endif // WMETAPROPERTY_H
#include "repository.h"
WMetaRepository *WMetaRepository::sInstance = 0;
WMetaRepository *WMetaRepository::getInstance()
{
if(!sInstance)
sInstance = new WMetaRepository();
return sInstance;
}
WMetaRepository::WMetaRepository()
{
}
int WMetaRepository::metaObjectCount() const
{
return mMetaObjects.size();
}
WMetaObject *WMetaRepository::metaObject(int index) const
{
return mMetaObjects[index];
}
WMetaObject *WMetaRepository::findByClassName(std::string name) const
{
for(int i = 0; i < mMetaObjects.size(); i++) {
WMetaObject *obj = mMetaObjects[i];
if(obj->name() == name)
return obj;
}
return 0;
}
void WMetaRepository::addMetaObject(WMetaObject *obj)
{
if(findByClassName(obj->name())) {
return;
}
mMetaObjects.push_back(obj);
}
#ifndef WMETAREPOSITORY_H
#define WMETAREPOSITORY_H
#include <vector>
#include <string>
#include "object.h"
#include "property.h"
#include "input.h"
#include "output.h"
#include "attribute.h"
#include "macros.h"
/**
* @brief Global container for all meta objects and other data.
*/
class WINDENGINE_DLL WMetaRepository
{
public:
static WMetaRepository *getInstance();
WMetaRepository();
int metaObjectCount() const;
WMetaObject *metaObject(int index) const;
WMetaObject *findByClassName(std::string name) const;
void addMetaObject(WMetaObject *obj);
private:
static WMetaRepository *sInstance;
std::vector<WMetaObject*> mMetaObjects;
};
#endif // WMETAREPOSITORY_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment