Cross-platform C++17 Runtime Reflection Library
MIT License
Refureku is a powerful C++17 runtime reflection dynamic library. It is split in 2 parts:
Check the Wiki to get started!
Refureku was initially developed with game engine development in mind, which greatly influenced the global design and architecture. The usage was mostly inspired by UE4, and the API by the C# native reflection system.
The concept is simple: you write what you want to reflect once, include the generated files, and the code generator does the rest. Users don't have any extra step to care about. Reflected entities are automatically registered to the reflection system and available right away. Manual reflection was an absolute no-go because it is error prone and time-consuming.
Another point addressed by this library is the reflection syntax. It is sometimes annoying to be tied to the macro syntax of a third party library, especially when it is heavily used accross a project. Using Refureku x Kodgen, the user has full control over the generated files / macros names to make the reflection integrate well in any project.
Another key point of Kodgen is that it is simple to insert and mix custom generated code to the reflection generated code. The Refureku code generator is a simple module added to the Kodgen generator. Users can create and add up as many code generation modules as they want to Kodgen, allowing custom generated code injection to the whole codebase without changing a single line of code in the target program.
#include <Refureku/Refureku.h>
//TestClass.h
#pragma once
#include "Generated/TestClass.rfkh.h"
class CLASS() TestClass
{
FIELD()
int _intField;
METHOD()
void testMethod();
TestClass_GENERATED
};
File_TestClass_GENERATED
//TestClass.cpp, or any source file being part of your project
#include "Generated/TestClass.rfks.h"
//From name
rfk::Class const* c = rfk::getDatabase().getFileLevelClassByName("TestClass");
//From static type
rfk::Class const& c2 = TestClass::staticGetArchetype();
//From reflected/unreflected type
rfk::Archetype const* c3 = rfk::getArchetype<TestClass>(); //nullptr if not reflected
This feature is only available to classes that publicly derive from rfk::Object (#include <Refureku/Object.h>).
TestClass instance;
rfk::Object const* instancePtr = &instance;
rfk::Class const& archetype = instancePtr->getArchetype();
//Get field
rfk::Field const* field = TestClass::staticGetArchetype().getFieldByName("_intField");
TestClass instance;
//Read field value
int value = field->get<int>(instance);
//Write field value
field->set(instance, 3);
//Get method
rfk::Method const* method = TestClass::staticGetArchetype().getMethodByName("testMethod");
TestClass instance;
//Call method without arguments
method->invoke(instance);
//With arguments and returned value
int returnedValue = method->invoke<int>(instance, 1, 2, 3);
rfk::Class const* c = rfk::getDatabase().getFileLevelClassByName("TestClass");
//Instantiate from default ctor
rfk::SharedPtr<TestClass> instance = c->makeSharedInstance<TestClass>();
//If TestClass has a base class, we can do
rfk::SharedPtr<BaseClass> instance2 = c->makeSharedInstance<BaseClass>();
It is also possible to instantiate a class with parameters, by providing a custom instantiator when declaring the class:
//TestClass2.h
#pragma once
#include <Refureku/Properties/Instantiator.h>
#include "Generated/TestClass2.rfkh.h"
class CLASS() TestClass2 : public BaseClass
{
METHOD(rfk::Instantiator)
static rfk::SharedPtr<TestClass2> customInstantiator(int i)
{
//Use this if you don't need custom deleter
//return rfk::makeShared<TestClass2>();
//Use this if you want to provide a custom deleter
return rfk::SharedPtr<TestClass2>(new TestClass2(), [](TestClass2* ptr)
{
delete ptr; //Simple delete for example simplicity
});
}
TestClass2_GENERATED
};
File_TestClass2_GENERATED
//TestClass2.cpp
#include "Generated/TestClass2.rfks.h"
rfk::Class const* c2 = rfk::getDatabase().getFileLevelClassByName("TestClass2");
//Call customInstantiator
rfk::SharedPtr<BaseClass> instance3 = c2->makeSharedInstance<BaseClass>(42);
//ExampleProperty.h
#pragma once
#include <Refureku/Properties/PropertySettings.h>
#include "Generated/ExampleProperty.rfkh.h"
class CLASS(rfk::PropertySettings(rfk::EEntityKind::Struct | rfk::EEntityKind::Class))
ExampleProperty : public rfk::Property
{
public:
int someData;
ExampleProperty(int data):
someData{data}
{}
ExampleProperty_GENERATED
};
File_ExampleProperty_GENERATED
//ExampleProperty.cpp, or any source file being part of your project
#include "Generated/ExampleProperty.rfks.h"
Then, we can attach ExampleProperty to any reflected struct or class, as specified by the first argument of PropertySettings. Attaching the property to any other entity will trigger a compilation error with an explicit error message.
//TestClass3.h
#pragma once
#include "ExampleProperty.h" //Include the custom property first
#include "Generated/TestClass3.rfkh.h"
class CLASS(ExampleProperty(42)) TestClass3
{
TestClass3_GENERATED
};
File_TestClass3_GENERATED
//TestClass3.cpp
#include "Generated/TestClass3.rfks.h"
rfk::Class const* c = rfk::getDatabase().getFileLevelClassByName("TestClass3");
//From name
rfk::Property const* prop = c->getPropertyByName("ExampleProperty");
//From static type
ExampleProperty const* prop2 = c->getProperty<ExampleProperty>();
This library has been tested and is stable on the following configurations: