libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
Classes

Overview of classed types.

GblClass

Base struct for all type classes.

A class represents a collection of data that is shared among all instances of a given type. This data is typically in the form of function pointers for modeling overridable methods or regular data for modeling static member variables.

GblClass is the base structure which is to be inherited by all class structures within the meta type system. This means placing it or a type "inheriting" from it as the first member of a class struct, when using C.

See also
GblInstance, GblType

Floating Classes

Typically, when you wish to override virtual methods on a class to provide custom functionality, you would need to register a new, derived static type inheriting from the existing type and overriding the desired methods within the class constructor.

This is good for when you need to implement lots of custom state and logic or for when this logic is to be applied to all instances of a class... However, this can be extremely inconvenient and cumbersome when you simply wish to quickly override one or two methods on a single instance.

This is where libGimbal's floating classes come into play. Lets say you wish to quickly create a new GblObject with a custom event handler:

GblIEventHandler* pHandler = GBL_EVENT_HANDLER(pMyObj);
// I want to override this, but don't want to register a new type!
GblIEventHandler_eventNotify(pHandler, NULL);
GblInstance * GblInstance_create(GblType type, size_t publicSize, GblClass *pClass)
Creates and returns an instance, optionally with an extended size and/or non-default class.
#define GBL_OBJECT_TYPE
GblType UUID for GblObject.
Main Object-Oriented Instance with Properties, EventHandlers, and Parenting.

By creating a separate "floating" class, we are able to perform ad-hoc method overriding for a single instance:

// We have a brand-new, unowned class just for us!
// override a virtual method on the event handler interface to do our own thing
pClass->iEventHandlerIFace.pFnEventNotify = my_event_notifier_function_;
// now create an instance *using our floating class* instead of the default class:
GblObject* pObj = GBL_OBJECT(GblInstance_createWithClass(pClass));
// Tell the class to assume ownership of our "floating" class by "sinking" it.
// If you don't sink the class, it's assumed you are maintaining its lifetime manually,
// which can be useful if you want to share among multiple instances.
GblInstance_sinkClass(GBL_INSTANCE(pObj));
// now it calls into our method when the interface is used!
GblIEventHandler_eventNotify(GBL_IEVENT_HANDLER(pObj), NULL);
// Destroys the sunk class with it
GblClass * GblClass_createFloating(GblType type, size_t size)
Creates a standalone, unowned, "floating" class for the given type, which can override defaults.
GblRefCount GblInstance_destroy(GblInstance *pSelf)
Destructs and deallocates an instance. It must have been created with GblInstance_create().
#define GBL_INSTANCE(self)
Casts GblInstance-compatible to GblInstance.
#define GBL_OBJECT(self)
Casts a GblInstance to a GblObject.
#define GBL_OBJECT_CLASS(klass)
Casts a GblClass to a GblObjectClass.
GblClass structure for GblObject.
Note
If we do not "sink" the floating class, then we have to destory it manually, because its lifetime will not yet be bound to the instance. This can actually be useful for allowing you to manually manage the class's lifetime as it's shared among multiple instances.

For extra credit, we can do the same trick with stack-allocated types as well:

// call placement constructor on existing memory
pClass->iEventHandlerIFace.pFnEventNotify = my_event_notifier_function_;
// call placement constructor on existing memory
GblObject object;
GblInstance_constructWithClass(GBL_INSTANCE(&object), &klass);
GblInstance_sinkClass(GBL_INSTANCE(&object));
// now it calls into our shit when the interface is used!
GblIEventHandler_eventNotify(GBL_IEVENT_HANDLER(&object), NULL);
// Call placement destructor which doesn't deallocate
GBL_RESULT GblClass_constructFloating(GblClass *pSelf, GblType type)
Constructs a standalone, unowned, overridable, "floating" class for the given type in-place.
GblRefCount GblInstance_destruct(GblInstance *pSelf)
Destructs but doesn't deallocate an instance. It must have been created with GblInstance_construct().

Class Swizzling

Sometimes you would like to do something similar to the previous example, with ad-hoc virtual method overriding, but the creation of the object is not actually under your control. This is a time for libGimbal's class swizzling, inspired by Objective-C's "is-a" swizzling:

"name", "MyObject",
"userdata", (void*)0xdeadbabe,
NULL);
//nothing fancy, regular-ass reference counted internally managed, instance-shared class...
assert(GblClass_isDefault(GBL_CLASS(pClass));
assert(!GblClass_isOverridden(GBL_CLASS(pClass));
assert(!GblClass_isFloating(GBL_CLASS(pClass));
// k, now lets make a new class and do some C++'y shit upon events...
// a lambda is nice for being all ad-hoc
pClass2->iEventHandlerIFace.pFnEvent = [](GblIEventHandler* pSelf, GblEvent* pEvent) {
GBL_CTX_BEGIN(NULL);
GBL_CTX_VERBOSE("So %s just sent a %s to a C++ lambda...",
GblType_name(GBL_CLASS_TYPEOF(pSelf)),
GblType_name(GblEvent_typeof(pEvent)));
GblEvent_accept(pEvent);
GBL_CTX_END();
};
// k, this class is now officially interesting
assert(!GblClass_isDefault(pClass2));
assert(GblClass_isOverridden(pClass2));
assert(!GblClass_isOwned(pClass2));
// K NOW LETS JUST SWAP THE FUCKER OUT RANDOMLY EVEN THOUGH ITS ALREADY INSTANTIATED LULUL
// releases reference to default class and gets our override
GblInstance_swizzleClass(GBL_INSTANCE(pObj), GBL_CLASS(pClass2));
// tell the instance to take exclusive ownership:
GblInstance_classClassSink(GBL_INSTANCE(pObj));
GblEvent event;
GblIEventHandler_eventNotify(GBL_IEVENT_HANDLER(pObj), pSomeEventObject);
// K clean up our fuckery
#define GBL_EVENT_TYPE
Returns the GblType for GblEvent.
GBL_RESULT GblInstance_construct(GblInstance *pSelf, GblType type, GblClass *pClass)
Constructs an instance, optionally with a non-default class, returning a result code.
#define GBL_OBJECT_GET_CLASS(self)
Gets a GblObjectClass from a GblInstance.
GblObject * GblObject_create(GblType type,...)
Creates an object-derived type on the heap, intializing it with a NULL-terminated K,...
const char * GblType_name(GblType self)
Returns the type name string associated with the given GblType.
Event base class for use with the event system.