libGimbal 0.2.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_class.h
Go to the documentation of this file.
1/*! \file
2 * \brief GblClass virtual-table structure and APIE
3 * \ingroup meta
4 *
5 * This file contains the GblClass structure,
6 * which is the inherited base type and first
7 * data member of all derievd class structures.
8 *
9 * While GblClass itself is empty other than its
10 * basic type info, a derived class typically
11 * contains data which is shared by all instances
12 * of a type, for deduplication and efficiency.
13 *
14 * This data is typically in the form of:
15 * - Overridable virtual methods (in the form of function pointers)
16 * - Static class data
17 *
18 * \sa gimbal_instance.h, gimbal_type.h
19 *
20 * \author 2023 Falco Girgis
21 * \copyright MIT License
22 */
23#ifndef GIMBAL_CLASS_H
24#define GIMBAL_CLASS_H
25
26#include "../types/gimbal_type.h"
27
28/*! \name Class Operators
29 * \brief Builtin operations for class structures
30 * \relatesalso GblClass
31 * @{
32 */
33//! Function-style cast to GblClass*: will always pass, here for consistence with other operators
34#define GBL_CLASS(klass) ((GblClass*)klass)
35//! Wraps GblClass_typeOf(), returning the type associated with the given class
36#define GBL_CLASS_TYPEOF(klass) GBL_CLASS_TYPEOF_(klass)
37//! Wraps GblClass_private(), returning the private structure on the class associated with the given type
38#define GBL_CLASS_PRIVATE(cType, klass) GBL_CLASS_PRIVATE_(cType, klass)
39//! Wraps GblClass_public(), returning the public class structure from the given type's private structure
40#define GBL_CLASS_PUBLIC(cType, priv) GBL_CLASS_PUBLIC_(cType, priv)
41//! Returns GBL_TRUE if the given class is type-compatible with and can be safely casted to the given type
42#define GBL_CLASS_TYPECHECK(cType, klass) GBL_CLASS_TYPECHECK_(cType, klass)
43//! Wraps GblClass_cast(), casting the given class to another type, returning NULL and raising an error upon failure
44#define GBL_CLASS_CAST(cType, klass) GBL_CLASS_CAST_(cType, klass)
45//! Wraps GblClass_as(), returning the given class as another type or gracefully returning NULL upon failure
46#define GBL_CLASS_AS(cType, klass) GBL_CLASS_AS_(cType, klass)
47//! @}
48
49/*! \name Static Class Type UUID and cast operators
50 * \brief UUID and cast operators for builtin static root class type
51 * @{
52 */
53#define GBL_STATIC_CLASS_TYPE (GBL_BUILTIN_TYPE(STATIC_CLASS)) //!< GblType UUID for builtin static class primitive
54#define GBL_STATIC_CLASS(klass) GBL_STATIC_CLASS_(klass) //!< Casts a class to a static class
55//! @}
56
57#define GBL_SELF_TYPE GblClass
58
60
61/*! \brief Base struct for all type classes.
62 * \ingroup meta
63 *
64 * A class represents a collection of data that is shared among
65 * all instances of a given type. This data is typically in the
66 * form of function pointers for modeling overridable methods
67 * or regular data for modeling static member variables.
68 *
69 * GblClass is the base structure which is to be inherited by all
70 * class structures within the meta type system. This means placing
71 * it or a type "inheriting" from it as the first member of a
72 * class struct, when using C.
73 *
74 * \sa GblInstance, GblType
75 */
76typedef struct GblClass {
78 uintptr_t metaClassInfo; //!< PRIVATE: Pointer-sized opaque member
80} GblClass;
81
82/*! Base GblClass VTable structure for static classes.
83 * \ingroup meta
84 *
85 * This is the base class structure which is to be extended to
86 * create static class subtypes.
87 *
88 * A "static class" is simply a GblType which only has a Gblclass
89 * structure, with no associated GblInstance structure, so it
90 * cannot be instantiated. it's typically ussed to implement
91 * singleton-style data types.
92 */
93typedef struct GblStaticClass {
94 GblClass base; //!< "Inherited" GblClass base structure.
95} GblStaticClass;
96
97/*! \name Default Class Management
98 * \brief Methods for managing references to internally-managed default class instances
99 * @{
100 */
101//! Returns a reference to the default class for \p type, instantiating it if necessary
103//! Releases a reference to the default version of the given class, possibly freeing it
105//! Returns a reference to the default class for \p type or NULL if it hasn't been created
107//! @}
108
109/*! \name Floating Class Mangement
110 * \brief Methods for managing lifetime of dynamic override class instances
111 * @{
112 */
113//! Creates a standalone, unowned, "floating" class for the given type, which can override defaults
115 size_t size/*=DEFAULT*/) GBL_NOEXCEPT;
116//! Constructs a standalone, unowned, overridable, "floating" class for the given type in-place
118//! Destroys the standalone, "floating" class, releasing its memory allocation
120//! Destructs the standalone, "floating" class, without releasing any allocated resources
122//! @}
123
124/*! \name Type Conversions
125 * \brief Methods for type casting and checking
126 * \relatesalso GblClass
127 * @{
128 */
129//! Returns GBL_TRUE if the given class can be casted to \p toType
131//! Casts the given class to a \p toType class, or returns NULL and emits an error if unsuccessful
133//! Casts the given class to a \p toType class, or gracefully returns NULL without erroring
135//! @}
136
137/*! \name Public and Private Data
138 * \brief Methods for accessing public and private segments
139 * \relatesalso GblClass
140 * @{
141 */
142//! Returns the private structure associated with the given \p base type of the class
144//! Casts back to the class structure from a base type's private data segment structure
145GBL_EXPORT GblClass* GblClass_public (const void* pPrivate, GblType base) GBL_NOEXCEPT;
146//! @}
147
148/*! \name Static Type Info
149 * \brief Methods for getting static class information
150 * \relatesalso GblClass
151 * @{
152 */
153//! Returns the GblType UUID associated with the given class
155//! Returns the size of the given class's public class structrue
157//! Returns the combined size of the class's private data segments
159//! Returns the class's combined DEFAULT size (not extended allocation size)
161//! @}
162
163/*! \name Dynamic Flags
164 * \brief Methods for checking dyanmic runtime flags
165 * \relatesalso GblClass
166 */
167//! Returns GBL_TRUE if the class is the internally-managed default for its type
169//! Returns GBL_TRUE if the class differs from the default class for its type
171//! Returns GBL_TRUE if the class is an interfaced type
173//! Returns GBL_TRUE if the class is another class's implementation of an interface
175//! Returns GBL_TRUE if the class is a non-default floating class and is unowned by an instance
177//! Returns GBL_TRUE if the class is a non-default floating class is uowned by an instance
179//! Returns GBL_TRUE if the class was constructed in-place with an existing allocation
181//! @}
182
183/*! \name Related Classes
184 * \brief Methods for fetching associated classes
185 * \relatesalso GblClass
186 */
187//! Returns the default class of the class's parent type or NULL if it's a root class
189//! Returns the default implementation of the given class
191//! @}
192
194
195//! \cond
196#define GblClass_createFloating(...)
197 GblClass_createFloatingDefault_(__VA_ARGS__)
198#define GblClass_createFloatingDefault_(...)
199 GblClass_createFloatingDefault__(__VA_ARGS__, 0)
200#define GblClass_createFloatingDefault__(type, size, ...)
201 (GblClass_createFloating)(type, size)
202
203#define GBL_CLASS_TYPEOF_(klass) (GblClass_typeOf(GBL_CLASS(klass)))
204#define GBL_CLASS_PRIVATE_(cType, klass) ((GBL_CLASS_PRIVATE_STRUCT(cType)*)GblClass_private(GBL_CLASS(klass), GBL_TYPEID(cType)))
205#define GBL_CLASS_PUBLIC_(cType, priv) ((GBL_CLASS_STRUCT(cType)*)GblClass_public(priv, GBL_TYPEID(cType)))
206#define GBL_CLASS_TYPECHECK_(cType, klass) (GblClass_check((GblClass*)klass, GBL_TYPEID(cType)))
207#define GBL_CLASS_CAST_(cType, klass) ((GBL_CLASS_STRUCT(cType)*)GblClass_cast((GblClass*)klass, GBL_TYPEID(cType)))
208#define GBL_CLASS_AS_(cType, klass) ((GBL_CLASS_STRUCT(cType)*)GblClass_as((GblClass*)klass, GBL_TYPEID(cType)))
209#define GBL_STATIC_CLASS_(klass) (GblClass_cast((GblClass*)klass, GBL_STATIC_CLASS_TYPE))
210//! \endcond
211
212/*! \def GBL_STATIC_CLASS_TYPE
213 * Builtin type ID for a class-only types
214 * \ingroup metaBuiltinTypes
215 */
216
217/*! \fn GBL_CLASS(klass)
218 * \param klass pointer to a GblClass-compatible
219 * \returns klass C-style casted to GblClass*
220 * \relatesalso GblClass
221 * Convenience function-style casting macro.
222 */
223
224/*! \fn GBL_CLASS_TYPEOF(klass)
225 * \param klass pointer to a GblClass-compatible
226 * \returns type associated with the class, or GBL_INVALID_TYPE if NULL
227 * \relatesalso GblClass
228 * \sa GblClass_typeOf()
229 * Convenience wrapper around GblClass_typeOf() which automatically casts.
230 */
231
232/*! \fn GBL_CLASS_PRIVATE(cType, klass)
233 * \param cType C type name of the supertype owning the private data
234 * \param klass pointer to a GblClass-compatible
235 * \returns private data owned by the given supertype or NULL if there is
236 * none, cType is not a parent, or cType is invalid
237 * \relatesalso GblClass
238 * \sa GblClass_private()
239 * Convenience wrapper around GblClass_private() which automatically casts.
240 */
241
242/*! \fn GBL_CLASS_PUBLIC(cType, priv)
243 * \param cType C type name of the supertype owning the private data
244 * \param priv void* pointer to private class data
245 * \returns public class pointer or NULL if none could be found
246 * \relatesalso GblClass
247 * \sa GblClass_public()
248 * Convenience wrapper around GblClass_public() which automatically casts.
249 */
250
251/*! \fn GBL_CLASS_TYPECHECK(cType, klass)
252 * \param cType C type name of the desired destination type
253 * \param klass pointer to a GblClass-compatible
254 * \returns true if the given class can be casted to a class of cType
255 * \relatesalso GblClass
256 * \sa GblClass_check()
257 * Convenience wrapper around GblClass_check() which automatically casts.
258 */
259
260/*! \fn GBL_CLASS_CAST(cType, klass)
261 * \param cType C type name of the destination type for the resulting class
262 * \param klass pointer to a GblClass-compatible
263 * \returns klass casted to the class structure of cType if the cast was successful, otherwise NULL
264 * \relatesalso GblClass
265 * \sa GBL_CLASS_AS(), GblClass_cast()
266 *
267 * Convenience wrapper around GblClass_cast() which automatically performs casting.
268 */
269
270/*! \fn GBL_CLASS_AS(cType, klass)
271 * \param cType C type name of the destination type for the resulting class
272 * \param klass pointer to a GblClass-compatible
273 * \returns klass casted to the class structure of cType if the cast was successful, otherwise NULL
274 * \relatesalso GblClass
275 * \sa GBL_CLASS_CAST(), GblClass_as()
276 *
277 * Convenience wrapper around GblClass_as() which automatically performs casting.
278 */
279
280/*!
281 * \fn GblClass* GblClass_refDefault(GblType type)
282 * Returns a new reference to the existing internally managed default class for the given type or
283 * lazily allocates a new one with an initial refCount of 1.
284 * \note
285 * When you're done using the reference, it must be released using GblClass_unrefDefault() in order to avoid
286 * memory leaks!
287 * \relatesalso GblClass
288 * \param type classed type ID
289 * \returns reference to internally managed class
290 * \sa GblClass_weakRefDefault, GblClass_unrefDefault
291 */
292
293/*!
294 * \fn GblRefCount GblClass_unrefDefault(GblClass* pSelf)
295 * Release a reference to the default class associated with pSelf,
296 * destroying the class if it's reference count hits 0.
297 * \note
298 * This should not be called to release a previously floating
299 * class, as it is not reference-counted. See GblClass_destructFloating
300 * and GblClass_destroyFloating
301 * \note
302 * It is safe to call this function with a NULL class, as
303 * libGimbal tries to be consistent with free() semantics.
304 * \note Types may be flagged as "persisting", despite
305 * their reference counts hitting zero. This is used for
306 * builtin types. See GBL_TYPE_FLAG_CLASS_PINNED.
307 * \param pSelf reference to class
308 * \returns remaining reference count
309 * \relatesalso GblClass
310 * \sa GblClass_refDefault
311 */
312
313/*!
314 * \fn GblClass* GblClass_weakRefDefault(GblType type)
315 * Returns a pointer to the default class for the given type without incrementing refCount.
316 * \note
317 * If there has not yet been a class created, or one is no longer active, this call will
318 * raise an error followed by returning NULL. Since no references are being created, only
319 * use this within contexts where you know a class reference already exists.
320 * \relatesalso GblClass
321 * \param type type of desired class
322 * \returns pointer to a GblClss or NULL upon failure
323 * \sa GblClass_refDefault
324 */
325
326/*!
327 * \fn GblClass* GblClass_createFloating(GblType type)
328 * Creates a new, unowned class for the given type on the heap.
329 * \relatesalso GblClass
330 * \param type classed type ID
331 * \returns dynamically allocated unowned class
332 * \sa GblClass_constructFloating, GblClass_destroyFloating, floatingClasses
333 */
334
335/*!
336 * \fn GBL_RESULT GblClass_destroyFloating(GblClass* pSelf)
337 * \relatesalso GblClass
338* Destructs then frees the given heap-allocated, floating
339* class.
340* \note
341* It is safe to call this function with a NULL class, as
342* libGimbal tries to be consistent with free() semantics.
343* \attention
344* Do not call this with a stack-constructed in-place floating class
345* constructed with GblClass_constructFloating()
346* Luckily libGyro will catch it for you and return an error.
347* \param pSelf GblClass pointer
348* \returns destructor result code or GBL_RESULT_ERROR_INVALID_OPERATION
349* \sa GblClass_destructFloating, GblClass_createFloating
350 */
351
352/*!
353 * \fn GBL_RESULT GblClass_constructFloating(GblClass* pSelf, GblType type)
354 * Placement constructs an unowned class for the given type using an existing
355 * user-provided allocation.
356 * \relatesalso GblClass
357 * \param pSelf pointer to instance allocation
358 * \param type type of instance to construct
359 * \returns result code
360 * \sa GblClass_createFloating, GblClass_destructFloating
361 */
362
363/*!
364 * \fn GBL_RESULT GblClass_destructFloating(GblClass* pSelf)
365 * Calls placement delete on the given floating class which was
366 * constructed in-place, using GblClass_constructFloating.
367 * It is safe to call this function with a NULL class, as
368 * libGimbal tries to be consistent with free() semantics.
369 * \attention
370 * Do not call this with a heap-allocated floating class,
371 * created with GblClass_createFloating().
372 * Luckily libGyro will catch it for you and return an error.
373 * \param pSelf class pointer
374 * \return destructor result code or GBL_RESULT_ERROR_INVALID_OPERATION
375 * \relatesalso GblClass
376 * \sa GblClass_destroyFloating, GblClass_constructFloating
377*/
378
379/*!
380 * \fn GblBool GblClass_check(const GblClass* pSelf, GblType toType)
381 * Returns true if the given class can be casted to the given class type.
382 * \note Also returns true if pClass is NULL AND toType is GBL_TYPE_INVALID,
383 * since that would semantically be a valid cast to the invalid type.
384 * \param pSelf class pointer
385 * \param toType desired destination type
386 * \returns true upon success
387 * \relatesalso GblClass
388 * \sa GblClass_cast, GblClass_as
389*/
390
391/*!
392 * \fn GblClass* GblClass_cast(GblClass* pSelf, GblType toType)
393 * Casts the given class to a class of the given type, raising errors and
394 * returning NULL upon failure.
395 * \param pSelf source class pointer
396 * \param toType desired destination type
397 * \returns pointer to GblClass upon success, NULL upon failure
398 * \relatesalso GblClass
399 * \sa GBL_CLASS_CAST(), GblClass_check, GblClass_as
400*/
401
402/*!
403 * \fn GblClass* GblClass_as(GblClass* pSelf, GblType toType)
404 * Equivalent to GblClass_cast(), except gracefully returning NULL
405 * with no errors getting raised if the given class could not be
406 * casted to toType.
407 * \note This is equivalent to a C++ dynamic cast.
408 * \param pSelf source class
409 * \param toType desired destination type
410 * \returns pointer to GblClass or NULL upon failure
411 * \relatesalso GblClass
412 * \sa GBL_CLASS_AS(), GblClass_cast(), GblClass_check()
413*/
414
415/*!
416 * \fn void* GblClass_private(const GblClass* pSelf, GblType type)
417 * Retrieves the private data pointer associated with the given base type or
418 * NULL if there isn't one.
419 * \param pSelf class pointer
420 * \param type type owning the private data
421 * \returns pointer to private data or NULL upon failure
422 * \relatesalso GblClass
423 * \sa GblClass_public()
424*/
425
426/*!
427 * \fn GblClass* GblClass_public(const void* pPrivate, GblType base)
428 * Retrieves the public GblClass corresponding to the given private data
429 * pointer for the given type or base type or NULL upon failure.
430 * \param pPrivate pointer to private data
431 * \param base type or base type that registered the private data
432 * \returns pointer to public GblClass* or NULL upon failure
433 * \relatesalso GblClass
434*/
435
436/*!
437 * \fn GblType GblClass_typeOf(const GblClass* pSelf)
438 * Returns the type associated with the given GblClass pointer,
439 * or GBL_INVALID_TYPE if the pointer is NULL.
440 * \param pSelf pointer to a GblClass
441 * \returns type ID of the class or GBL_INVALID_TYPE if NULL
442 * \relatesalso GblClass
443*/
444
445/*!
446 * \fn size_t GblClass_size(const GblClass* pSelf)
447 * Returns the size of the public class structure for the
448 * given GblClass pointer or 0 if NULL
449 * \param pSelf pointer to a GblClass
450 * \returns size or 0 if class is NULL
451 * \relatesalso GblClass
452 * \sa GblClass_privateSize(), GblClass_totalSize()
453*/
454
455/*!
456 * \fn size_t GblClass_privateSize(const GblClass* pSelf)
457 * Returns the TOTAL size of the private data structure
458 * associated with the type of the given class and all
459 * of its base types.
460 * \param pSelf pointer to a GblClass
461 * \returns size or 0 if class is NULL
462 * \relatesalso GblClass
463 * \sa GblClass_size(), GblClass_totalSize()
464*/
465
466/*!
467 * \fn size_t GblClass_totalSize(const GblClass* pSelf)
468 * Returns the total combined size of the public and private
469 * class structures for the class type and all of its inherited
470 * bases.
471 * \param pSelf pointer to a GblClass
472 * \returns size or 0 if class is NULL
473 * \relatesalso GblClass
474 * \sa GblClass_size(), GblClass_privateSize()
475*/
476
477/*!
478 * \fn GblClass* GblClass_super(const GblClass* pSelf)
479 * Returns the default class for the parent type of
480 * the given class type. This is typically used in the implementation of
481 * overridden methods to allow you to call into the base class's
482 * implementations.
483 * \note The returned class is a weak reference and does not impact
484 * the reference count for the parent's default class.
485 * \param pSelf pointer to a GblClass
486 * \returns pointer to parent GblClass or NULL if the given class is
487 * NULL or has no parent
488 * \relatesalso GblClass
489 * \sa GblClass_default()
490*/
491
492/*!
493 * \fn GblClass* GblClass_default(const GblClass* pSelf)
494 * Returns a weak reference to the internally-managed default class
495 * corresonding to the given class's type. This will only be different
496 * than the given argument if the class has been created either as a
497 * floating class, or if it is a pointer to the implementation of an
498 * interface. In the case of an interface, this is how you access the
499 * interface's default implementation as well.
500 * \note The returned class is a weak reference and does not impact
501 * the reference count for the default class.
502 * \param pSelf pointer to a GblClass
503 * \returns pointer to default GblClass or NULL if the given class is
504 * NULL
505 * \relatesalso GblClass
506 * \sa GblClass_isDefault()
507*/
508
509/*!
510 * \fn GblBool GblClass_isDefault(const GblClass* pSelf)
511 * Returns true if the given GblClass pointer points to the
512 * internally-managed default class for its type or false if it
513 * not the default.
514 * \note Note: The class will not be the default if it was created
515 * as separate floating class, or if it's the implementation of a
516 * GblInterface on another GblClass.
517 * \param pSelf pointer to a GblClass
518 * \returns true if default, false if not or if pSelf is NULL
519 * \relatesalso GblClass
520 * \sa GblClass_default()
521*/
522
523/*!
524 * \fn GblBool GblClass_isOverridden(const GblClass* pSelf)
525 * Inspects the internal memory of the given GblClass pointer
526 * and compares it to that of the internally managed default
527 * class, returning true if they differ or false if they are the
528 * same.
529 * \note Note: Just because a class is a floating class or an
530 * interface implementation doesn't necessarily mean it has
531 * actually been overridden to have non-default values!
532 * \param pSelf pointer to a GblClass
533 * \returns true if overridden, false if not or if pSelf is NULL
534 * \relatesalso GblClass
535*/
536
537/*!
538 * \fn GblBool GblClass_isFloating(const GblClass* pSelf)
539 * Returns true if the given GblClass is an unowned, floating
540 * class which must be manually managed, or false if it is
541 * either the default class or has been sunk by a GblInstance.
542 * \param pSelf pointer to a GblClass
543 * \returns true if floating, false if not or if pSelf is NULL
544 * \sa GblClass_createFloating(), GblClass_constructFloating(),
545 * GblInstance_sinkClass(),
546 * GblInstance_floatClass()
547 * \relatesalso GblClass
548*/
549
550/*!
551 * \fn GblBool GblClass_isFloating(const GblClass* pSelf)
552 * Returns true if the given GblClass is an unowned, floating
553 * class which must be manually managed, or false if it is
554 * either the default class or has been sunk by a GblInstance.
555 * \param pSelf pointer to a GblClass
556 * \returns true if floating, false if not or if pSelf is NULL
557 * \sa GblClass_createFloating(), GblClass_constructFloating(),
558 * GblInstance_sinkClass(),
559 * GblInstance_floatClass()
560 * \relatesalso GblClass
561*/
562
563/*!
564 * \fn GblBool GblClass_isInterface(const GblClass* pSelf)
565 * Returns true if the given GblClass is actually of or
566 * derived from GBL_INTERFACE_TYPE, false otherwise.
567 * \param pSelf pointer to a GblClass
568 * \returns true if pSelf is a GblInterface, false if not or if pSelf is NULL
569 * \sa GblClass_isInterfaceImpl
570 * \relatesalso GblClass
571*/
572
573/*!
574 * \fn GblBool GblClass_isInterfaceImpl(const GblClass* pSelf)
575 * Returns true if the given GblClass an interface *implementation*
576 * wihch has been mapped onto another GblClass, false otherwise.
577 * \param pSelf pointer to a GblClass
578 * \returns true if pSelf is a mapped GblInterface, false if not or if pSelf is NULL
579 * \sa GblClass_isInterface
580 * \relatesalso GblClass
581*/
582
583/*!
584 * \fn GblBool GblClass_isOwned(const GblClass* pSelf)
585 * Returns true if the given GblClass is a previously floating, nondefault
586 * class which has been sunk and is now owned by a GblInstance.
587 * \note This means that its lifetime has been bound to that of the instance,
588 * and it will be destructed (and deleted if necessary) with the instance.
589 * \param pSelf pointer to a GblClass
590 * \returns true if pSelf is a owned by a GblInstance, false if not or if pSelf is NULL
591 * \sa GblInstance_sinkClass(), GblInstance_floatClass()
592 * \relatesalso GblClass
593*/
594
595/*!
596 * \fn GblBool GblClass_isInPlace(const GblClass* pSelf)
597 * Returns true if the given GblClass was constructed from an existing,
598 * user-managed allocation, using GblClass_constructFloating().
599 * \note If a GblClass is both floating and in-place, it means that you are
600 * responsible for uninitializing it manually via GblClass_destructFloating()
601 * \param pSelf pointer to a GblClass
602 * \returns true if pSelf was constructed in-place, false if not or if pSelf is NULL
603 * \sa GblClass_constructFloating(), GblClass_destructFloating()
604 * \relatesalso GblClass
605*/
606
607/*! \page Classes Classes
608 * \brief Overview of classed types
609 * \tableofcontents
610 *
611 * ## GblClass
612 * \copydoc GblClass
613 *
614 * ## Floating Classes
615 *
616 * Typically, when you wish to override virtual methods on a class to provide
617 * custom functionality, you would need to register a new, derived static type
618 * inheriting from the existing type and overriding the desired methods within
619 * the class constructor.
620 *
621 * This is good for when you need to implement lots of custom state and logic or
622 * for when this logic is to be applied to all instances of a class... However,
623 * this can be extremely inconvenient and cumbersome when you simply wish to
624 * quickly override one or two methods on a single instance.
625 *
626 * This is where libGimbal's floating classes come into play. Lets say you
627 * wish to quickly create a new GblObject with a custom event handler:
628 *
629 * \code{.c}
630 * GblObject* pMyObj = GblInstance_create(GBL_OBJECT_TYPE);
631 * GblIEventHandler* pHandler = GBL_EVENT_HANDLER(pMyObj);
632 *
633 * // I want to override this, but don't want to register a new type!
634 * GblIEventHandler_eventNotify(pHandler, NULL);
635 * \endcode
636 * By creating a separate "floating" class, we are able to perform ad-hoc
637 * method overriding for a single instance:
638 * \code{.c}
639 * // We have a brand-new, unowned class just for us!
640 * GblObjectClass* pClass = GBL_OBJECT_CLASS(GblClass_createFloating(GBL_OBJECT_TYPE));
641 *
642 * // override a virtual method on the event handler interface to do our own thing
643 * pClass->iEventHandlerIFace.pFnEventNotify = my_event_notifier_function_;
644 *
645 * // now create an instance *using our floating class* instead of the default class:
646 * GblObject* pObj = GBL_OBJECT(GblInstance_createWithClass(pClass));
647 *
648 * // Tell the class to assume ownership of our "floating" class by "sinking" it.
649 * // If you don't sink the class, it's assumed you are maintaining its lifetime manually,
650 * // which can be useful if you want to share among multiple instances.
651 * GblInstance_sinkClass(GBL_INSTANCE(pObj));
652 *
653 * // now it calls into our method when the interface is used!
654 * GblIEventHandler_eventNotify(GBL_IEVENT_HANDLER(pObj), NULL);
655 *
656 * // Destroys the sunk class with it
657 * GblInstance_destroy(GBL_INSTANCE(pObj));
658 * \endcode
659 * \note
660 * If we do not "sink" the floating class, then we have to destory it manually,
661 * because its lifetime will not yet be bound to the instance. This can actually
662 * be useful for allowing you to manually manage the class's lifetime as it's
663 * shared among multiple instances.
664 *
665 * For extra credit, we can do the same trick with stack-allocated types as well:
666 * \code{.c}
667 * // call placement constructor on existing memory
668 * GblObjectClass klass;
669 * GblClass_constructFloating(GBL_CLASS(&klass), GBL_OBJECT_TYPE);
670 *
671 * pClass->iEventHandlerIFace.pFnEventNotify = my_event_notifier_function_;
672 *
673 * // call placement constructor on existing memory
674 * GblObject object;
675 * GblInstance_constructWithClass(GBL_INSTANCE(&object), &klass);
676 *
677 * GblInstance_sinkClass(GBL_INSTANCE(&object));
678 *
679 * // now it calls into our shit when the interface is used!
680 * GblIEventHandler_eventNotify(GBL_IEVENT_HANDLER(&object), NULL);
681 *
682 * // Call placement destructor which doesn't deallocate
683 * GblInstance_destruct(GBL_INSTANCE(&object));
684 * \endcode
685 * ## Class Swizzling
686 *
687 * Sometimes you would like to do something similar to the previous example,
688 * with ad-hoc virtual method overriding, but the creation of the object is
689 * not actually under your control. This is a time for libGimbal's class
690 * swizzling, inspired by Objective-C's "is-a" swizzling:
691 * \code{.c}
692 * GblObject* pObject = GblObject_create(GBL_OBJECT_TYPE,
693 * "name", "MyObject",
694 * "userdata", (void*)0xdeadbabe,
695 * NULL);
696 *
697 * GblObjectClass* pClass = GBL_OBJECT_CLASSOF(pObject);
698 *
699 * //nothing fancy, regular-ass reference counted internally managed, instance-shared class...
700 * assert(GblClass_isDefault(GBL_CLASS(pClass));
701 * assert(!GblClass_isOverridden(GBL_CLASS(pClass));
702 * assert(!GblClass_isFloating(GBL_CLASS(pClass));
703 *
704 * // k, now lets make a new class and do some C++'y shit upon events...
705 * GblObjectClass* pClass2 = GBL_OBJECT_CLASS(GblClass_createFloating(GBL_OBJECT));
706 *
707 * // a lambda is nice for being all ad-hoc
708 * pClass2->iEventHandlerIFace.pFnEvent = [](GblIEventHandler* pSelf, GblEvent* pEvent) {
709 * GBL_CTX_BEGIN(NULL);
710 * GBL_CTX_VERBOSE("So %s just sent a %s to a C++ lambda...",
711 * GblType_name(GBL_CLASS_TYPEOF(pSelf)),
712 * GblType_name(GblEvent_typeof(pEvent)));
713 * GblEvent_accept(pEvent);
714 * GBL_CTX_END();
715 * };
716 *
717 * // k, this class is now officially interesting
718 * assert(!GblClass_isDefault(pClass2));
719 * assert(GblClass_isOverridden(pClass2));
720 * assert(!GblClass_isOwned(pClass2));
721 *
722 * // K NOW LETS JUST SWAP THE FUCKER OUT RANDOMLY EVEN THOUGH ITS ALREADY INSTANTIATED LULUL
723 * // releases reference to default class and gets our override
724 * GblInstance_swizzleClass(GBL_INSTANCE(pObj), GBL_CLASS(pClass2));
725 *
726 * // tell the instance to take exclusive ownership:
727 * GblInstance_classClassSink(GBL_INSTANCE(pObj));
728 *
729 * GblEvent event;
730 * GblInstance_construct(&event, GBL_EVENT_TYPE);
731 * GblIEventHandler_eventNotify(GBL_IEVENT_HANDLER(pObj), pSomeEventObject);
732 *
733 * // K clean up our fuckery
734 * GblInstance_destroy(GBL_INSTANCE(pObj);
735 * \endcode
736 */
737/*! \page TypeTemplate Type Templates
738 * \brief Boilerplate macros for type operations
739 *
740 * At the top of the file for most libGimbal derived types, along with the type identifier,
741 * you will find a collection of convenience utility macros implementing function-style
742 * casts for the given type.
743 * \code{.c}
744 * // type UUID macro (expands to GblObject_type() registration function)
745 * #define GBL_OBJECT_TYPE (GBL_TYPEID(GblObject))
746 *
747 * // instance function-style cast macro
748 * #define GBL_OBJECT(instance) (GBL_CAST(GblObject, instance))
749 *
750 * // class cast function-style cast macro
751 * #define GBL_OBJECT_CLASS(klass) (GBL_CLASS_CAST(GblObject, klass))
752 *
753 * // instance-to-class cast macro
754 * #define GBL_OBJECT_CLASSOF(instance) (GBL_CLASSOF(GblObject, instance))
755 * \endcode
756 * While these macros are obviously optional, they do add a lot to the codebase in terms of readability
757 * and convenience as well as uniform styling. With these sorts of macros defined, we then gain access to
758 * lots of convenience:
759 * \code{.c}
760 * // create a floating object class
761 * // - easy cast to particular class
762 * GblObjectClass* pClass = GBL_OBJECT_CLASS(GblClass_createFloating(GBL_OBJECT_TYPE));
763 *
764 * // lets override just its implementation of the GblIEventHandlerClass interface
765 * // - easy cast to particular interface
766 * GblIEventHandlerClass* pIEvent = GBL_IEVENT_HANDLER_CLASS(pClass);
767 * // override virtual method
768 * pIEvent->pFnEvent = [&](GblIEventHandler* pSelf, GblEvent* pEvent) {
769 * // easy cast to particular instance type
770 * GblObject* pSelfObj = GBL_OBJECT(pSelf);
771 *
772 * printf("%s received an Event!", GblObject_name(pSelfObj));
773 *
774 *
775 * if(GBL_TYPECHECK(pEvent, MyEventType)) {
776 * // easy cast to particular event instance
777 * MyCustomEvent* pEvent = MY_CUSTOM_EVENT(pEvent);
778 *
779 * // do something
780 * } else if(GBL_TYPECHECK(pEvent, MyOtherEventType)) {
781 * // easy cast to particular event instance
782 * SomeOtherEvent* pEvent = SOME_OTHER_EVENT(pEvent);
783 *
784 * // do something
785 * }
786 * }
787 *
788 * GblObject* pObject = GblObject_createWithClass(pClass);
789 * // easy cast from object to GblInstance base
790 * GblInstance_sinkClass(GBL_INSTANCE(pObject));
791 * // easy cast from object to GblBox base
792 * GblBox_unref(GBL_BOX(pObject));
793 * \endcode
794 */
795
796#undef GBL_SELF_TYPE
797
798#endif // GIMBAL_CLASS_H
#define GBL_BUILTIN_TYPE(prefix)
Returns a type from the macro prefix of a builtin type.
GBL_RESULT GblClass_destructFloating(GblClass *pSelf)
Destructs the standalone, "floating" class, without releasing any allocated resources.
GblRefCount GblClass_unrefDefault(GblClass *pSelf)
Releases a reference to the default version of the given class, possibly freeing it.
GblClass * GblClass_createFloating(GblType type, size_t size)
Creates a standalone, unowned, "floating" class for the given type, which can override defaults.
GBL_RESULT GblClass_constructFloating(GblClass *pSelf, GblType type)
Constructs a standalone, unowned, overridable, "floating" class for the given type in-place.
GBL_RESULT GblClass_destroyFloating(GblClass *pSelf)
Destroys the standalone, "floating" class, releasing its memory allocation.
GblClass * GblClass_weakRefDefault(GblType type)
Returns a reference to the default class for type or NULL if it hasn't been created.
GblClass * GblClass_refDefault(GblType type)
Returns a reference to the default class for type, instantiating it if necessary.
#define GBL_NOEXCEPT
#define GBL_DECLS_BEGIN
#define GBL_CLASS_PRIVATE_STRUCT(instanceStruct)
#define GBL_TYPEID(instanceStruct)
#define GBL_PRIVATE_BEGIN
#define GBL_CLASS_STRUCT(cType)
#define GBL_EXPORT
#define GBL_PRIVATE_END
Private data structure.
uint8_t GblBool
Basic boolean type, standardized to sizeof(char)
uint16_t GblRefCount
Type able to hold a reference counter across the codebase.
#define GBL_STATIC_CLASS_TYPE
GblType UUID for builtin static class primitive.
uintptr_t GblType
Meta Type UUID.
Definition gimbal_type.h:52
Base struct for all type classes.
size_t GblClass_size(const GblClass *pSelf)
Returns the size of the given class's public class structrue.
GblBool GblClass_isOverridden(const GblClass *pSelf)
Returns GBL_TRUE if the class differs from the default class for its type.
void * GblClass_private(const GblClass *pSelf, GblType base)
Returns the private structure associated with the given base type of the class.
GblClass * GblClass_cast(GblClass *pSelf, GblType toType)
Casts the given class to a toType class, or returns NULL and emits an error if unsuccessful.
GblClass * GblClass_public(const void *pPrivate, GblType base)
Casts back to the class structure from a base type's private data segment structure.
GblType GblClass_typeOf(const GblClass *pSelf)
Returns the GblType UUID associated with the given class.
GblBool GblClass_isInterface(const GblClass *pSelf)
Returns GBL_TRUE if the class is an interfaced type.
GblBool GblClass_check(const GblClass *pSelf, GblType toType)
Returns GBL_TRUE if the given class can be casted to toType.
GblClass * GblClass_super(const GblClass *pSelf)
Returns the default class of the class's parent type or NULL if it's a root class.
size_t GblClass_privateSize(const GblClass *pSelf)
Returns the combined size of the class's private data segments.
GblBool GblClass_isInPlace(const GblClass *pSelf)
Returns GBL_TRUE if the class was constructed in-place with an existing allocation.
GblBool GblClass_isOwned(const GblClass *pSelf)
Returns GBL_TRUE if the class is a non-default floating class is uowned by an instance.
GblBool GblClass_isFloating(const GblClass *pSelf)
Returns GBL_TRUE if the class is a non-default floating class and is unowned by an instance.
uintptr_t metaClassInfo
PRIVATE: Pointer-sized opaque member.
GblBool GblClass_isDefault(const GblClass *pSelf)
Returns GBL_TRUE if the class is the internally-managed default for its type.
GblClass * GblClass_as(GblClass *pSelf, GblType toType)
Casts the given class to a toType class, or gracefully returns NULL without erroring.
GblBool GblClass_isInterfaceImpl(const GblClass *pSelf)
Returns GBL_TRUE if the class is another class's implementation of an interface.
GblClass * GblClass_default(const GblClass *pSelf)
Returns the default implementation of the given class.
size_t GblClass_totalSize(const GblClass *pSelf)
Returns the class's combined DEFAULT size (not extended allocation size)
Base GblClass VTable structure for static classes.
GblClass base
"Inherited" GblClass base structure.