Skip to content
/ LibeRTTI Public

Liberate your C++ with reflection! 🗽 LibeRTTI is a header only and dependency-free library which provides type data for your (and selected built-in) C++ types.

License

Notifications You must be signed in to change notification settings

Wuszt/LibeRTTI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Liberate your C++ with reflection!



LibeRTTI is a header only and dependency-free library which provides type data for your (and selected built-in) c++ types. The minimal requirement is C++14.

Features 🗽

Feature Description
Hierarchy based Every registered type gets its unique nested type class, e.g if you have a class A then it's type class will be A::Type. These type classes create a hierarchy based on their original classes hierarchy. So for instance, if class A : public B, then class A::Type : class B::Type. Also, all type classes are virtual, even if their original classes are not. It allows you to take advantage of polymorphic features like having a function parameter of type const A::Type& and passing the children types of A as arguments. rtti:Type is the root class for all types classes.
Namespaces and nested types friendly Types within namespaces and other types are fully supported.
"Super" keyword A well known feature from other languages. The Super keyword refers to the parent class of your class.
Instantiating/Destroying/Copying without knowing true type Type classes are able to instantiate, destroy or copy raw memory which contains the types they represent.
Move without knowing true type (Optional) Same as above but with the move operation. It forces all registered types to be movable. It might be disabled by defining RTTI_REQUIRE_MOVE_CTOR 0 before including the LibeRTTI header.
Recognizing object's true type You can get the true type of your polymorphic class instance.
Types register LibeRTTI gives you access to all registered types.
Properties and Methods Types might keep data about the their member variables and methods to make them accessible in runtime.
Metadata Types and properties can store additional string-based metadata.
Unique and persistent IDs All registered types and their properties get unique IDs which persist between executions unless the name of the type/property changes.
Primitive Types All primitive types are registered out of the box.
Enums Custom enum classes can also be registered.
Pointer Types Pointer types are registered lazily at runtime when the need for them arrises. You're not limited by the amount of indirections (properties like float***** are allowed). Pointer types follow their original classes hierarchy. I.e PointerType<B> inherits from PointerType<A> if B also inherits from A.
Runtime Types You can compose completely new type with selected properties in runtime. Such types can still inherit from other types and preserve hierarchy of classes.
std::
shared_ptr,
unique_ptr,
vector,
unordered_set,
unordered_map,
pair,
string
Types (Optional)
All these types are registered out of the box and might be disabled using config defines:
RTTI_CFG_CREATE_STD_SHAREDPTR_TYPE 0,
RTTI_CFG_CREATE_STD_UNIQUEPTR_TYPE 0,
RTTI_CFG_CREATE_STD_VECTOR_TYPE 0,
RTTI_CFG_CREATE_STD_SET_TYPE 0,
RTTI_CFG_CREATE_STD_MAP_TYPE 0,
RTTI_CFG_CREATE_STD_PAIR_TYPE 0,
RTTI_CFG_CREATE_STD_STRING_TYPE 0

Demo 🗽

More examples can be found in Tests or Forge project source code.

// .h
struct BaseStruct
{
  RTTI_DECLARE_STRUCT( BaseStruct );
};

struct MyStruct : public BaseStruct
{
  RTTI_DECLARE_STRUCT( MyStruct, BaseStruct );

  float myFloat;
  MyStruct* myPtr;
  BaseStruct myCustomInstance;

  MyStruct* Foo( Float input )
  {
    myFloat = input;
    return this;
  }
}

// .cpp
RTTI_IMPLEMENT_TYPE( BaseStruct );
RTTI_IMPLEMENT_TYPE( MyStruct,
  RTTI_REGISTER_PROPERTY( myFloat,
    RTTI_ADD_METADATA( MyCustomMetadata, 321 );
  );
  RTTI_REGISTER_PROPERTY( myPtr );
  RTTI_REGISTER_PROPERTY( myCustomInstance );
  RTTI_REGISTER_METHOD( Foo );
  RTTI_ADD_METADATA( MyCustomMetadata );
  RTTI_ADD_METADATA( MyCustomMetadataWithValue, 123 );
);

static_assert( MyStruct::GetTypeStatic().InheritsFrom< BaseStruct::Type > );

void Func( void* rawInstance, const rtti::Type& type )
{
  if( type.IsA< MyType >() )
  {
    const MyStruct::Type& myType = static_cast< const MyStruct::Type& >( type );

    // Accessing properties
    const rtti::Property* floatProperty = myType.FindProperty( "myFloat" );
    if ( floatProperty->GetType().IsA< float >() )
    {
      floatProperty->GetValue< float >( rawInstance ) = 3.14f;
    }
    myType.FindProperty( "myCustomInstance" )->GetValue< BaseStruct >( rawInstance ) = BaseStruct();

    // Calling methods
    MyType* fooResult = nullptr;
    float arg = 3.14f;
    myType.FindMethod( "Foo" )->Call( /*instance*/ rawInstance, /*args*/ &arg, /*outcome*/ &fooResult );

    // Accessing metadata
    if ( myType.HasMetadata( "MyCustomMetadata ) )
    {
      // type contains provided metadata
    }
    if (const std::string* metadataValue = myType.GetMetadataValue( "MyCustomMetadataWithValue" )
    {
      *metadataValue == "123 // true
    }
    if( myType.FindProperty( "myFloat" )->HasMetadata( "MyCustomMetadata ") )
    {
      // property contains provided metadata
    }
  }
}

Usage 🗽

Registering your type requires 2 steps.

1. Declare type

Put one of the following macros into your type's body.

Type Macro
Regular, non virtual class
 RTTI_DECLARE_CLASS( <class_name>, <parent_name_with_namespace> (optional) ) 
Virtual class
 RTTI_DECLARE_POLYMORPHIC_CLASS( <class_name>, <parent_name_with_namespace> (optional) ) 
Abstract class
 RTTI_DECLARE_ABSTRACT_CLASS( <class_name>, <parent_name_with_namespace> (optional) ) 
Struct
 RTTI_DECLARE_STRUCT( <struct_name>, <parent_name_with_namespace> (optional) ) 

2. Implement type

Structs and Classes

Put the following macro in .cpp file.

RTTI_IMPLEMENT_TYPE( <class_name_with_namespace>, <properties/methods/metadata_registration_macros... (optional)> );

To register property of your type use:

RTTI_REGISTER_PROPERTY( <property_name>, <metadata_macros... (optional)...> );

For methods use:

RTTI_REGISTER_METHOD( <method_name> );

To add type or property metadata:

RTTI_ADD_METADATA( <key>, <value (optional)> );

and put it in RTTI_IMPLEMENT_TYPE (for types) or RTTI_REGISTER_PROPERTY (for properties) macro.


Enums

To register your custom enum put the following macro in .cpp file.

RTTI_DECLARE_AND_IMPLEMENT_ENUM( <enum_name_with_namespace>, <enum_members...> )

To register enum's members use:

RTTI_REGISTER_ENUM_MEMBER( <member_name> );

and put it in RTTI_DECLARE_AND_IMPLEMENT_ENUM macro.

About

Liberate your C++ with reflection! 🗽 LibeRTTI is a header only and dependency-free library which provides type data for your (and selected built-in) C++ types.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages