libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_ring_list.h
Go to the documentation of this file.
1/*! \file
2 * \brief GblRingList structure and related functions
3 * \ingroup containers
4 *
5 * This file provides the GblRingList container structure and its public API
6 * for operating upon it.
7 *
8 * \author 2023, 2025 Falco Girgis
9 * \author 2025 Agustín Bellagamba
10 * \copyright MIT License
11 */
12#ifndef GIMBAL_RING_LIST_H
13#define GIMBAL_RING_LIST_H
14
15#include <stdarg.h>
16
17#include "../core/gimbal_result.h"
18#include <gimbal/meta/classes/gimbal_opaque.h>
19#include <gimbal/meta/ifaces/gimbal_itable_variant.h>
21
22//! size_t type denoting an invalid array index or position within a GblRingList
23#define GBL_RING_LIST_NPOS GBL_NPOS
24
25/*! \name Type System
26 * \brief Type UUID and cast macros
27 * @{
28 */
29#define GBL_RING_LIST_TYPE (GBL_TYPEID(GblRingList)) //!< Type UUID for GblRingList
30#define GBL_RING_LIST_CLASS(klass) (GBL_CLASS_CAST(GblRingList, klass)) //!< Casts a GblClass to a GblRingListClass
31//! @}
32
33/*! \brief For-loop style iteration over a GblRingList
34
35 Iterates over every entry within a GblRingList, setting the \p item variable to the current entry's value.
36 Optionally takes in a \p type parameter to specify the type of the \p item variable, which defaults to void*.
37*/
38#define GblRingList_foreach(/* list, item, type=void* */...) GblRingList_foreachDefault_(__VA_ARGS__)
39
40#define GBL_SELF_TYPE GblRingList
41
43
45
46/*! \struct GblRingListClass
47 * \extends GblOpaqueClass
48 * \implements GblITableVariantClass
49 * \brief GblClass structure for GblRingList
50 *
51 * GblRingListClass is the class structure for the GblRingList container.
52 * It also provides an inner GblType that defaults to GBL_POINTER_TYPE,
53 * used by its GblITableVariant implementation, for the GblType of each element.
54 */
55GBL_CLASS_DERIVE(GblRingList, GblOpaque, GblITableVariant)
56 GblType innerType; //!< GblType UUID representing the type of values stored within the GblRingList, defaulting to GBL_POINTER_TYPE.
58
59/*! \name User-Operator Callbacks
60 * \brief Typedefs for applying various user-supplied functions over a ring list.
61 * @{
62*/
63//! Iterator callback function which gets called over every entry within a GblRingList, being passed back its stored value and an arbitrary closure, returning true should iteration cease early.
64typedef GblBool (*GblRingListIterFn)(void* pValue, void* pClosure);
65//! Comparator callback for comparing the values of two different entries within a GblRingList, also getting passed back the closure that was passed to the API call. 0 should be returned if equal.
66typedef int (*GblRingListCmpFn) (const void* pVal1, const void* pVal2, void* pClosure);
67//! Returns a copy of the value of each entry within a GblRingList, also getting passed back the closure that was passed to the initial API call.
68typedef void* (*GblRingListCopyFn)(const void* pValue, void* pClosure);
69//! Destructs the value of each entry within a GblRingList, also getting passed back the closure that was passed to the iniital API call, and returning a GBL_RESULT for the status.
70typedef GBL_RESULT (*GblRingListDtorFn)(void* pValue, void* pClosure);
71//! @}
72
73/*! \brief Non-intrusive circularly doubly linked list with C++-style STL API
74 * \ingroup containers
75 *
76 * GblRingList is a non-intrusive circular doubly-linked
77 * list with an API mirroring C++'s std::vector, or that of
78 * an abstract List from other languges, except for the list
79 * can also be indexed from back-to-front with negative indices.
80 *
81 * All values are stored in the form of void* pointers.
82 *
83 * Each entry within the list is maintained as a simple
84 * GblDoublyLinkedListNode connecting it to the prevous and next
85 * entries along with a void* as a data payload (with the list
86 * head storing its size in that union field instead). While
87 * these nodes are directly accessible, a higher-level API
88 * is presented, which manages allocations and node relationships
89 * internally.
90 *
91 * The GblRingList API has been tweaked for convenience within
92 * the C programming language. This is why many of the methods
93 * are provided as overridden macros implementing default values
94 * and function overloading for doing things such as inserting
95 * or removing multiple entries at once.
96 *
97 * Operation |Time Complexity
98 * ----------------------------------|------------------
99 * iteration | O(N)
100 * insertion/removal (middle) | O(N)
101 * insertion/removal (front or back) | O(1)
102 * access (front or back) | O(1)
103 * random access (middle) | O(N)
104 *
105 * \note
106 * Each node should be 12 bytes large on 32-bit and 24-bytes
107 * large on 64-bit architectures.
108 *
109 * \note
110 * As it's non-intrusive, every list entry must dynamically
111 * allocate a new node when a value is added to the list,
112 * which would normally result in lots of small, disjoint
113 * heap allocations, causing fragmentation. However, this
114 * is not the case with GblRingList. LibGimbal uses an
115 * arena allocator internally to efficiently allocate
116 * each node from contiguous blocks of data, also
117 * maintaining a free list to reuse nodes as they become
118 * available.
119 *
120 * \sa GblDoublyLinkedListNode, GblRingList
121 */
122typedef struct GblRingList {
123 union { //!< Unionization of linked list node pointers, so they can be referred to generically or strongly-typed.
124 GblDoublyLinkedListNode listNode; //!< Linked list node as a generic GblDoublyLinkedListNode type.
125 struct {
126 struct GblRingList* pNext; //!< Points to next node within the list (or wraps back to first node, if list tail).
127 struct GblRingList* pPrev; //!< Points to previous node within the list (or wraps back to last, if list head)
128 } ringNode; //!< Linked list node as strongly-typed GblRingList pointers.
129 };
130 union { //!< Unionization between payload data types for the list head and list nodes.
131 uintptr_t size; //!< List head contains the total number of nodes within the list.
132 void* pData; //!< List entries contain void* pointers to arbitrary data payloads.
133 };
134} GblRingList;
135
136//! Returns the GblType UUID associated with GblRingList.
138
139/*! \name Lifetime
140 * \brief Methods for creating, acquring, and releasing a list.
141 * @{
142 */
143//! Creates a new, empty GblRingList of size 0 and returns a reference to it.
145//! Creates a new GblRingList, given an initial value and an optional list of additional values, returning a reference to the list.
146GBL_EXPORT GblRingList* GblRingList_create (void* pData, ...) GBL_NOEXCEPT;
147//! Unreferences an existing GblRingList, destroying it if this was the last reference, using an optional, user-provided per-entry destructor which gets passed back the given optional closure data.
149 GblRingListDtorFn pFnDtor/*=NULL*/,
150 void* pCl/*=NULL*/) GBL_NOEXCEPT;
151//! Returns a new reference to an existing GblRingList, incrementing its reference counter by 1.
153//! Creates a copy of the given GblRingList, optionally deep-copying each entry by using the user-provided copy function which optionally gets passed back a pointer to arbitrary closure data.
155 GblRingListCopyFn pFnCpy/*=NULL*/,
156 void* pCl/*=NULL*/) GBL_NOEXCEPT;
157//! @}
158
159/*! \name Properties
160 * \brief Methods for querying the properties of a list.
161 * @{
162 */
163//! Returns the number of active references to the given GblRingList.
165//! Returns the number of entries held by the given GblRingList.
167//! Returns true if the given GblRingList has no entries held within it.
169//! @}
170
171/*! \name Retrieval
172 * \brief Methods for retrieving entries within a list.
173 * @{
174 */
175//! Returns a pointer to the value held within the first entry of the list, or NULL if the list is empty.
177//! Returns a pointer to the value held within the last entry of the list, or NULL if the list is empty.
179//! Linearly traverses the list to the given \p index, returning a pointer to the value held within that entry, or NULL if the entry is invalid. NOTE that negative indices start at the last entry and enumerate backwards.
181//! Searches the list for an entry with the given value, or for an entry which matches the value based on the optional comparison callback, which takes an optional closure pointer. The index of the matching entry or `GBL_RING_LIST_NPOS` is returned.
183 const void* pVal,
184 GblRingListCmpFn pFnCmp/*=NULL*/,
185 void* pCl/*=NULL*/) GBL_NOEXCEPT;
186
187//! @}
188
189/*! \name Insertion
190 * \brief Methods for adding entries into the list.
191 * @{
192 */
193//! Adds a comma-separated list of values to the end of the given GblRingList.
195//! Equivalent to GblRingList_pushBack(), except taking a va_list*, rather than a variadic argument list.
197//! Adds a comma-separated list of values to the front of the given GblRingList.
199//! Equivalent to GblRingList_pushFront(), except taking a va_list*, rather than a variadic argument list.
201//! Inserts the comma-separated list of values into the given GblRingList, so that the first value is at the position of the given index.
202GBL_EXPORT GBL_RESULT GblRingList_insert (GBL_SELF, intptr_t index, ...) GBL_NOEXCEPT;
203//! Equivalent to GblRingList_insert(), except taking a va_list* rather than a variadic argument list.
205 intptr_t index,
206 va_list* pList) GBL_NOEXCEPT;
207//! Inserts a value into a sorted list, optionally taking a comparator for sort direction and an optional closure which gets passed back.
209 void* pData,
210 GblRingListCmpFn pFnCmp/*=NULL*/,
211 void* pCl/*=NULL*/) GBL_NOEXCEPT;
212//! Joins \p pOther into the given GblRingList such that its first entry is positioned at the given \p index, returning GBL_TRUE if it succeeded. Do NOT forget to still call GblRingList_unref() on the now empty \p pOther list.
214 GblRingList* pOther,
215 int32_t index) GBL_NOEXCEPT;
216//! Replaces the entry within the given GblRingList located at \p pIndex with the \p pData value, returning its old value (or NULL upon failure).
218 intptr_t index,
219 void* pData) GBL_NOEXCEPT;
220//! @}
221
222/*! \name Removing
223 * \brief Methods for removing entries from a list.
224 * @{
225 */
226//! Removes the last entry from the given list, returning its previously held value, or NULL if the list was empty.
228//! Removes the first entry from the given list, returning its previously held value, or NULL if the list was empty.
230//! Removes \p count items from the given GblRingList, starting at the given \p index, returning the value previously held by the last item which was removed.
232 intptr_t index,
233 size_t count/*=1*/) GBL_NOEXCEPT;
234//! Returns the value which was held by the given GblRingList node within the given list, also removing it from the list.
236 GblRingList* pNode) GBL_NOEXCEPT;
237//! Erases all entries from the GblRingList, returning its size back to 0.
239//! @}
240
241/*! \name Operations
242 * \brief Other operations which can be performed on a list.
243 * @{
244 */
245//! Sorts the given GblRingList, optionally using a user-specified comparator which can optionally take an closure data pointer.
247 GblRingListCmpFn pFnCmp/*=NULL*/,
248 void* pCl/*=NULL*/) GBL_NOEXCEPT;
249//! Rotates the positions of all entries within the given GblRingList, such that they ahve been offset by \p n, where positives rotate right and negatives rotate left.
251//! Reverses the order of the entire GblRingList, such that the tail becomes the head entry, and all values are now in opposite order.
253//! Iterates over every entry within the given GblRingList, passing their values to the given iterator function, wich may optionally take a closure data pointer. Iteration ends early when the iterator returns GBL_TRUE.
255 GblRingListIterFn pFnIt,
256 void* pCl/*=NULL*/) GBL_NOEXCEPT;
257//! @}
258
260
261// ========= BEWARE YOUNG GRUGS, THERE BE COMPLEXITY DEMONS AND EVIL SHIT DEYOND HERE! =========
262
263// ==== Macro Overrides (for default arguments) ====
264#define GblRingList_create(...) (GblRingList_create)(__VA_ARGS__, GBL_NULL)
265#define GblRingList_copy(...) GblRingList_copyDefault_(__VA_ARGS__)
266#define GblRingList_unref(...) GblRingList_unrefDefault_(__VA_ARGS__)
267#define GblRingList_pushBack(self, ...) (GblRingList_pushBack)(self, __VA_ARGS__, GBL_NULL)
268#define GblRingList_pushFront(self, ...) (GblRingList_pushFront)(self, __VA_ARGS__, GBL_NULL)
269#define GblRingList_insert(self, ...) (GblRingList_insert)(self, __VA_ARGS__, GBL_NULL)
270#define GblRingList_insertSorted(...) GblRingList_insertSortedDefault_(__VA_ARGS__)
271#define GblRingList_splice(...) GblRingList_spliceDefault_(__VA_ARGS__)
272#define GblRingList_popBack(...) GblRingList_popBackDefault_(__VA_ARGS__)
273#define GblRingList_popFront(...) GblRingList_popFrontDefault_(__VA_ARGS__)
274#define GblRingList_remove(...) GblRingList_removeDefault_(__VA_ARGS__)
275#define GblRingList_sort(...) GblRingList_sortDefault_(__VA_ARGS__)
276#define GblRingList_iterate(...) GblRingList_iterateDefault_(__VA_ARGS__)
277#define GblRingList_find(...) GblRingList_findDefault_(__VA_ARGS__)
278
279// ===== IMPL =====
280
281//! \cond
282#define GblRingList_copyDefault_(...)
283 GblRingList_copyDefault__(__VA_ARGS__, GBL_NULL, GBL_NULL)
284#define GblRingList_copyDefault__(list, cpFn, cl, ...)
285 (GblRingList_copy)(list, cpFn, cl)
286
287#define GblRingList_unrefDefault_(...)
288 GblRingList_unrefDefault__(__VA_ARGS__, GBL_NULL, GBL_NULL)
289#define GblRingList_unrefDefault__(list, dtor, cl, ...)
290 (GblRingList_unref)(list, dtor, cl)
291
292#define GblRingList_insertSortedDefault_(...)
293 GblRingList_insertSortedDefault__(__VA_ARGS__, GBL_NULL, GBL_NULL)
294#define GblRingList_insertSortedDefault__(list, data, cmp, cl, ...)
295 (GblRingList_insertSorted)(list, data, cmp, cl)
296
297#define GblRingList_spliceDefault_(...)
298 GblRingList_spliceDefault__(__VA_ARGS__, -1)
299#define GblRingList_spliceDefault__(list1, list2, index, ...)
300 (GblRingList_splice)(list1, list2, index)
301
302#define GblRingList_popBackDefault_(...)
303 GblRingList_popBackDefault__(__VA_ARGS__, 1)
304#define GblRingList_popBackDefault__(list, count, ...)
305 (GblRingList_popBack)(list, count)
306
307#define GblRingList_popFrontDefault_(...)
308 GblRingList_popFrontDefault__(__VA_ARGS__, 1)
309#define GblRingList_popFrontDefault__(list, count, ...)
310 (GblRingList_popFront)(list, count)
311
312#define GblRingList_removeDefault_(...)
313 GblRingList_removeDefault__(__VA_ARGS__, 1)
314#define GblRingList_removeDefault__(list, idx, count, ...)
315 (GblRingList_remove)(list, idx, count)
316
317#define GblRingList_sortDefault_(...)
318 GblRingList_sortDefault__(__VA_ARGS__, GBL_NULL, GBL_NULL)
319#define GblRingList_sortDefault__(list, cmp, cl, ...)
320 (GblRingList_sort)(list, cmp, cl)
321
322#define GblRingList_foreachDefault_(...)
323 GblRingList_foreachDefault__(__VA_ARGS__, void*)
324#define GblRingList_foreachDefault__(list, item, type, ...)
325 GblRingList_foreachImpl_(list, item, type)
326#define GblRingList_foreachImpl_(list, item, type)
327 GblRingList* GBL_APPEND_LINE(pNode) = list->ringNode.pNext;
328 for(type item = (type)GBL_APPEND_LINE(pNode)->pData;
329 GBL_APPEND_LINE(pNode) != list;
330 GBL_APPEND_LINE(pNode) = GBL_APPEND_LINE(pNode)->ringNode.pNext,
331 item = (type)GBL_APPEND_LINE(pNode)->pData)
332
333#define GblRingList_iterateDefault_(...)
334 GblRingList_iterateDefault__(__VA_ARGS__, GBL_NULL)
335#define GblRingList_iterateDefault__(list, it, cl, ...)
336 (GblRingList_iterate)(list, it, cl)
337
338#define GblRingList_findDefault_(...)
339 GblRingList_findDefault__(__VA_ARGS__, GBL_NULL, GBL_NULL)
340#define GblRingList_findDefault__(list, val, cmp, cl, ...)
341 (GblRingList_find)(list, val, cmp, cl)
342//! \endcond
343
344#undef GBL_SELF_TYPE
345
346#endif // GIMBAL_RING_LIST_H
#define GBL_NULL
#define GBL_NOEXCEPT
#define GBL_DECLS_BEGIN
#define GBL_FORWARD_DECLARE_STRUCT(S)
#define GBL_TYPEID(instanceStruct)
#define GBL_CLASS_DERIVE(...)
#define GBL_EXPORT
#define GBL_CLASS_END
#define GBL_APPEND_LINE(a)
size_t GblRingList_find(const GblRingList *pSelf, const void *pVal, GblRingListCmpFn pFnCmp, void *pCl)
Searches the list for an entry with the given value, or for an entry which matches the value based on...
GBL_RESULT GblRingList_insert(GblRingList *pSelf, intptr_t index,...)
Inserts the comma-separated list of values into the given GblRingList, so that the first value is at ...
GBL_RESULT GblRingList_pushFrontVaList(GblRingList *pSelf, va_list *plist)
Equivalent to GblRingList_pushFront(), except taking a va_list*, rather than a variadic argument list...
void * GblRingList_replace(GblRingList *pSelf, intptr_t index, void *pData)
Replaces the entry within the given GblRingList located at pIndex with the pData value,...
#define GblRingList_create(...)
#define GblRingList_insert(self,...)
GblType GblRingList_type(void)
Returns the GblType UUID associated with GblRingList.
GblBool GblRingList_iterate(GblRingList *pSelf, GblRingListIterFn pFnIt, void *pCl)
Iterates over every entry within the given GblRingList, passing their values to the given iterator fu...
void GblRingList_sort(GblRingList *pSelf, GblRingListCmpFn pFnCmp, void *pCl)
Sorts the given GblRingList, optionally using a user-specified comparator which can optionally take a...
GblBool GblRingList_empty(const GblRingList *pSelf)
Returns true if the given GblRingList has no entries held within it.
GBL_RESULT GblRingList_pushFront(GblRingList *pSelf,...)
Adds a comma-separated list of values to the front of the given GblRingList.
GblRingList * GblRingList_ref(const GblRingList *pSelf)
Returns a new reference to an existing GblRingList, incrementing its reference counter by 1.
#define GblRingList_insertSorted(...)
GblRingList * GblRingList_create(void *pData,...)
Creates a new GblRingList, given an initial value and an optional list of additional values,...
GblRingList * GblRingList_copy(const GblRingList *pSelf, GblRingListCopyFn pFnCpy, void *pCl)
Creates a copy of the given GblRingList, optionally deep-copying each entry by using the user-provide...
void * GblRingList_popBack(GblRingList *pSelf, size_t count)
Removes the last entry from the given list, returning its previously held value, or NULL if the list ...
#define GblRingList_popFront(...)
GblBool GblRingList_splice(GblRingList *pSelf, GblRingList *pOther, int32_t index)
Joins pOther into the given GblRingList such that its first entry is positioned at the given index,...
void * GblRingList_front(const GblRingList *pSelf)
Returns a pointer to the value held within the first entry of the list, or NULL if the list is empty.
#define GblRingList_pushBack(self,...)
#define GblRingList_splice(...)
#define GblRingList_unref(...)
void * GblRingList_back(const GblRingList *pSelf)
Returns a pointer to the value held within the last entry of the list, or NULL if the list is empty.
GBL_RESULT GblRingList_clear(GblRingList *pSelf)
Erases all entries from the GblRingList, returning its size back to 0.
GBL_RESULT GblRingList_pushBackVaList(GblRingList *pSelf, va_list *pList)
Equivalent to GblRingList_pushBack(), except taking a va_list*, rather than a variadic argument list.
void *(* GblRingListCopyFn)(const void *pValue, void *pClosure)
Returns a copy of the value of each entry within a GblRingList, also getting passed back the closure ...
void * GblRingList_remove(GblRingList *pSelf, intptr_t index, size_t count)
Removes count items from the given GblRingList, starting at the given index, returning the value prev...
#define GblRingList_remove(...)
void * GblRingList_extract(GblRingList *pSelf, GblRingList *pNode)
Returns the value which was held by the given GblRingList node within the given list,...
GblRingList * GblRingList_createEmpty(void)
Creates a new, empty GblRingList of size 0 and returns a reference to it.
#define GblRingList_copy(...)
GBL_RESULT GblRingList_insertVaList(GblRingList *pSelf, intptr_t index, va_list *pList)
Equivalent to GblRingList_insert(), except taking a va_list* rather than a variadic argument list.
#define GblRingList_pushFront(self,...)
size_t GblRingList_size(const GblRingList *pSelf)
Returns the number of entries held by the given GblRingList.
GblRefCount GblRingList_refCount(const GblRingList *pSelf)
Returns the number of active references to the given GblRingList.
#define GblRingList_find(...)
GblRefCount GblRingList_unref(const GblRingList *pSelf, GblRingListDtorFn pFnDtor, void *pCl)
Unreferences an existing GblRingList, destroying it if this was the last reference,...
void * GblRingList_popFront(GblRingList *pSelf, size_t count)
Removes the first entry from the given list, returning its previously held value, or NULL if the list...
#define GblRingList_sort(...)
void * GblRingList_at(const GblRingList *pSelf, intptr_t index)
Linearly traverses the list to the given index, returning a pointer to the value held within that ent...
GBL_RESULT GblRingList_pushBack(GblRingList *pSelf,...)
Adds a comma-separated list of values to the end of the given GblRingList.
void GblRingList_rotate(GblRingList *pSelf, intptr_t n)
Rotates the positions of all entries within the given GblRingList, such that they ahve been offset by...
#define GblRingList_popBack(...)
void GblRingList_reverse(GblRingList *pSelf)
Reverses the order of the entire GblRingList, such that the tail becomes the head entry,...
int(* GblRingListCmpFn)(const void *pVal1, const void *pVal2, void *pClosure)
Comparator callback for comparing the values of two different entries within a GblRingList,...
#define GblRingList_iterate(...)
GBL_RESULT GblRingList_insertSorted(GblRingList *pSelf, void *pData, GblRingListCmpFn pFnCmp, void *pCl)
Inserts a value into a sorted list, optionally taking a comparator for sort direction and an optional...
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_NPOS
uintptr_t GblType
Meta Type UUID.
Definition gimbal_type.h:52
GblType innerType
GblType UUID representing the type of values stored within the GblRingList, defaulting to GBL_POINTER...
Non-intrusive circularly doubly linked list with C++-style STL API.
struct GblRingList * pNext
Points to next node within the list (or wraps back to first node, if list tail).
GblDoublyLinkedListNode listNode
< Unionization of linked list node pointers, so they can be referred to generically or strongly-typed...
void * pData
List entries contain void* pointers to arbitrary data payloads.
struct GblRingList * pPrev
Points to previous node within the list (or wraps back to last, if list head)
uintptr_t size
< Unionization between payload data types for the list head and list nodes.