Gama C Library
Gama C API Documentation
body_list.h
Go to the documentation of this file.
1/**
2 * @file body_list.h
3 * @brief Provides a dynamic, NULL-terminated pointer list implementation.
4 *
5 * This file contains a generic pointer list (`gmPtrList`) and a specialized
6 * version for physics bodies (`gmBodies`). The lists automatically resize and
7 * are always NULL-terminated, making them easy to iterate.
8 *
9 * @note The functions in this file that return a new list (e.g., push, pop)
10 * allocate new memory. It is the caller's responsibility to free the
11 * original list pointer to prevent memory leaks. Specifically, `gm_ptr_list_pop_at`
12 * uses `malloc` internally to create a new list.
13 */
14#pragma once
15
16#include "body.h"
17#include <stdlib.h>
18
19// ---------------------------------------------------------------------------
20// --------------------------- Generic Pointer List --------------------------
21// ---------------------------------------------------------------------------
22
23/**
24 * @brief A dynamic, NULL-terminated array of generic `void*` pointers.
25 *
26 * This type is a `void**` and represents a resizable array that is always
27 * terminated by a `NULL` pointer.
28 */
29typedef void **gmPtrList;
30
31/**
32 * @brief Calculates the number of elements in a pointer list.
33 * @param list The NULL-terminated pointer list.
34 * @return The number of elements, excluding the NULL terminator.
35 */
37 if (list == NULL)
38 return 0;
39 size_t i = 0;
40 while (list[i] != NULL)
41 i++;
42 return i;
43}
44
45/**
46 * @brief Checks if a pointer list is empty.
47 * @param list The list to check.
48 * @return 1 if the list is NULL or has zero length, 0 otherwise.
49 */
51 return list == NULL || list[0] == NULL;
52}
53
54/**
55 * @brief Counts the occurrences of a specific pointer in the list.
56 * @param list The list to search.
57 * @param obj The pointer to count.
58 * @return The number of times `obj` appears in the list.
59 */
60size_t gm_ptr_list_count(gmPtrList list, void *obj) {
61 if (list == NULL)
62 return 0;
63 size_t count = 0;
64 for (size_t i = 0; list[i] != NULL; i++) {
65 if (list[i] == obj)
66 count++;
67 }
68 return count;
69}
70
71/**
72 * @brief Adds a pointer to the end of the list.
73 * @param list The list to append to.
74 * @param obj The pointer to add.
75 * @return A new pointer to the resized list. **The original list pointer
76 * is reallocated and should be replaced by the returned pointer.**
77 */
79 size_t length = gm_ptr_list_length(list);
80 gmPtrList new_list = realloc(list, (length + 2) * sizeof(void *));
81 new_list[length] = obj;
82 new_list[length + 1] = NULL;
83 return new_list;
84}
85
86/**
87 * @brief Removes the last element from the list.
88 * @param list The list to modify.
89 * @return A new pointer to the resized list. **The original list pointer
90 * is reallocated and should be replaced by the returned pointer.**
91 */
93 size_t len = gm_ptr_list_length(list);
94 if (len == 0)
95 return list;
96 gmPtrList new_list = realloc(list, len * sizeof(void *));
97 new_list[len - 1] = NULL;
98 return new_list;
99}
100
101/**
102 * @brief Removes all occurrences of a specific pointer from the list.
103 * @param list The list to modify.
104 * @param obj The pointer to remove.
105 * @return A new pointer to the resized list. **The original list pointer
106 * is freed internally and replaced by the returned pointer.**
107 */
109 size_t len = gm_ptr_list_length(list);
110 size_t count = gm_ptr_list_count(list, obj);
111 if (count == 0)
112 return list;
113
114 gmPtrList new_list = malloc((len - count + 1) * sizeof(void *));
115 size_t index = 0;
116 for (size_t i = 0; i < len; i++) {
117 if (list[i] != obj) {
118 new_list[index++] = list[i];
119 }
120 }
121 new_list[index] = NULL;
122 free(list);
123 return new_list;
124}
125
126/**
127 * @brief Removes an element at a specific index.
128 * @param list The list to modify.
129 * @param idx The index of the element to remove.
130 * @return A new pointer to the resized list. **The original list pointer
131 * is freed internally and replaced by the returned pointer.**
132 */
134 size_t len = gm_ptr_list_length(list);
135 if (idx >= len)
136 return list;
137
138 gmPtrList new_list = malloc(len * sizeof(void *));
139 size_t new_idx = 0;
140 for (size_t i = 0; i < len; i++) {
141 if (i != idx) {
142 new_list[new_idx++] = list[i];
143 }
144 }
145 new_list[new_idx] = NULL;
146 free(list);
147 return new_list;
148}
149
150/**
151 * @brief Inserts a pointer at a specific index.
152 * @param list The list to modify.
153 * @param idx The index at which to insert the value.
154 * @param value The pointer to insert.
155 * @return A new pointer to the resized list. **The original list pointer
156 * is freed internally and replaced by the returned pointer.**
157 */
158gmPtrList gm_ptr_list_insert_at(gmPtrList list, size_t idx, void *value) {
159 size_t len = gm_ptr_list_length(list);
160 if (idx > len)
161 idx = len;
162
163 gmPtrList new_list = malloc((len + 2) * sizeof(void *));
164 for (size_t i = 0; i < idx; i++) {
165 new_list[i] = list[i];
166 }
167 new_list[idx] = value;
168 for (size_t i = idx; i < len; i++) {
169 new_list[i + 1] = list[i];
170 }
171 new_list[len + 1] = NULL;
172 free(list);
173 return new_list;
174}
175
176/**
177 * @brief Finds the index of a specific pointer.
178 * @param list The list to search.
179 * @param value The pointer to find.
180 * @return The index of the first occurrence of the value, or -1 if not found.
181 */
182int gm_ptr_list_find(gmPtrList list, void *value) {
183 if (list == NULL)
184 return -1;
185 for (size_t i = 0; list[i] != NULL; i++) {
186 if (list[i] == value)
187 return i;
188 }
189 return -1;
190}
191
192/**
193 * @brief Retrieves the element at a specific index.
194 * @param list The list.
195 * @param index The index of the element to retrieve.
196 * @return The pointer at the specified index, or NULL if the index is out of
197 * bounds.
198 */
199void *gm_ptr_list_get(gmPtrList list, size_t index) {
200 if (list == NULL || index >= gm_ptr_list_length(list)) {
201 return NULL;
202 }
203 return list[index];
204}
205
206/**
207 * @brief Retrieves the last element of the list.
208 * @param list The list.
209 * @return The last pointer in the list, or NULL if the list is empty.
210 */
212 if (gm_ptr_list_is_empty(list))
213 return NULL;
214 return list[gm_ptr_list_length(list) - 1];
215}
216
217/**
218 * @brief Frees the memory used by the list.
219 * @param list The list to clear.
220 */
222 if (list != NULL) {
223 free(list);
224 }
225}
226
227/**
228 * @brief A macro for iterating over a `gmPtrList`.
229 * @param item The variable to hold the current item (e.g., `gmBody* item`).
230 * @param list The `gmPtrList` to iterate over.
231 */
232#define gm_ptr_list_for_each(item, list) \
233 for (size_t i = 0; (list != NULL) && (item = list[i]) != NULL; i++)
234
235// ---------------------------------------------------------------------------
236// ---------------------------- Body List Wrapper ----------------------------
237// ---------------------------------------------------------------------------
238
239/**
240 * @brief A specialized dynamic, NULL-terminated list for `gmBody` pointers.
241 *
242 * This type is `gmBody**` and provides convenience wrappers around `gmPtrList`
243 * for type safety with physics bodies.
244 */
245typedef gmBody **gmBodies;
246
247/**
248 * @brief Calculates the number of elements in a `gmBodies` list.
249 * @param list The `gmBodies` list.
250 * @return The number of `gmBody*` elements, excluding the NULL terminator.
251 */
252static inline size_t gm_bodies_length(gmBodies list) {
253 return gm_ptr_list_length((gmPtrList)list);
254}
255/**
256 * @brief Checks if a `gmBodies` list is empty.
257 * @param list The list to check.
258 * @return 1 if the list is NULL or has zero length, 0 otherwise.
259 */
260static inline int gm_bodies_is_empty(gmBodies list) {
261 return gm_ptr_list_is_empty((gmPtrList)list);
262}
263/**
264 * @brief Counts the occurrences of a specific `gmBody` pointer in the list.
265 * @param list The list to search.
266 * @param obj The `gmBody*` to count.
267 * @return The number of times `obj` appears in the list.
268 */
269static inline size_t gm_bodies_count(gmBodies list, gmBody *obj) {
270 return gm_ptr_list_count((gmPtrList)list, obj);
271}
272/**
273 * @brief Adds a `gmBody` pointer to the end of the list.
274 * @param list The list to append to.
275 * @param obj The `gmBody*` to add.
276 * @return A new pointer to the resized list. **The original list pointer
277 * is reallocated and should be replaced by the returned pointer.**
278 */
279static inline gmBodies gm_bodies_push(gmBodies list, gmBody *obj) {
280 return (gmBodies)gm_ptr_list_push((gmPtrList)list, obj);
281}
282/**
283 * @brief Removes the last `gmBody` pointer from the list.
284 * @param list The list to modify.
285 * @return A new pointer to the resized list. **The original list pointer
286 * is reallocated and should be replaced by the returned pointer.**
287 */
288static inline gmBodies gm_bodies_pop(gmBodies list) {
289 return (gmBodies)gm_ptr_list_pop((gmPtrList)list);
290}
291/**
292 * @brief Removes all occurrences of a specific `gmBody` pointer from the list.
293 * @param list The list to modify.
294 * @param obj The `gmBody*` to remove.
295 * @return A new pointer to the resized list. **The original list pointer
296 * is freed internally and replaced by the returned pointer.**
297 */
298static inline gmBodies gm_bodies_remove(gmBodies list, gmBody *obj) {
299 return (gmBodies)gm_ptr_list_remove((gmPtrList)list, obj);
300}
301/**
302 * @brief Removes a `gmBody` pointer at a specific index.
303 * @param list The list to modify.
304 * @param idx The index of the `gmBody*` to remove.
305 * @return A new pointer to the resized list. **The original list pointer
306 * is freed internally and replaced by the returned pointer.**
307 */
308static inline gmBodies gm_bodies_pop_at(gmBodies list, size_t idx) {
309 return (gmBodies)gm_ptr_list_pop_at((gmPtrList)list, idx);
310}
311/**
312 * @brief Inserts a `gmBody` pointer at a specific index.
313 * @param list The list to modify.
314 * @param idx The index at which to insert the `gmBody*`.
315 * @param value The `gmBody*` to insert.
316 * @return A new pointer to the resized list. **The original list pointer
317 * is freed internally and replaced by the returned pointer.**
318 */
319static inline gmBodies gm_bodies_insert_at(gmBodies list, size_t idx,
320 gmBody *value) {
321 return (gmBodies)gm_ptr_list_insert_at((gmPtrList)list, idx, value);
322}
323/**
324 * @brief Finds the index of a specific `gmBody` pointer.
325 * @param list The list to search.
326 * @param value The `gmBody*` to find.
327 * @return The index of the first occurrence of the value, or -1 if not found.
328 */
329static inline int gm_bodies_find(gmBodies list, gmBody *value) {
330 return gm_ptr_list_find((gmPtrList)list, value);
331}
332/**
333 * @brief Retrieves the `gmBody` pointer at a specific index.
334 * @param list The list.
335 * @param index The index of the element to retrieve.
336 * @return The `gmBody*` at the specified index, or NULL if the index is out of
337 * bounds.
338 */
339static inline gmBody *gm_bodies_get(gmBodies list, size_t index) {
340 return (gmBody *)gm_ptr_list_get((gmPtrList)list, index);
341}
342/**
343 * @brief Retrieves the last `gmBody` pointer of the list.
344 * @param list The list.
345 * @return The last `gmBody*` in the list, or NULL if the list is empty.
346 */
347static inline gmBody *gm_bodies_last(gmBodies list) {
348 return (gmBody *)gm_ptr_list_last((gmPtrList)list);
349}
350/**
351 * @brief Frees the memory used by the `gmBodies` list itself (not the bodies it points to).
352 * @param list The list to clear.
353 */
354static inline void gm_bodies_clear(gmBodies list) {
356}
357
358/**
359 * @brief A macro for iterating over a `gmBodies` list.
360 * @param item A `gmBody*` variable to hold the current item.
361 * @param list The `gmBodies` list to iterate over.
362 */
363#define gm_bodies_for_each(item, list) \
364 for (size_t i = 0; (list != NULL) && (item = list[i]) != NULL; i++)
gmPtrList gm_ptr_list_pop_at(gmPtrList list, size_t idx)
Removes an element at a specific index.
Definition body_list.h:133
gmPtrList gm_ptr_list_insert_at(gmPtrList list, size_t idx, void *value)
Inserts a pointer at a specific index.
Definition body_list.h:158
void * gm_ptr_list_last(gmPtrList list)
Retrieves the last element of the list.
Definition body_list.h:211
gmPtrList gm_ptr_list_push(gmPtrList list, void *obj)
Adds a pointer to the end of the list.
Definition body_list.h:78
void ** gmPtrList
A dynamic, NULL-terminated array of generic void* pointers.
Definition body_list.h:29
size_t gm_ptr_list_length(gmPtrList list)
Calculates the number of elements in a pointer list.
Definition body_list.h:36
gmPtrList gm_ptr_list_pop(gmPtrList list)
Removes the last element from the list.
Definition body_list.h:92
void gm_ptr_list_clear(gmPtrList list)
Frees the memory used by the list.
Definition body_list.h:221
gmPtrList gm_ptr_list_remove(gmPtrList list, void *obj)
Removes all occurrences of a specific pointer from the list.
Definition body_list.h:108
int gm_ptr_list_is_empty(gmPtrList list)
Checks if a pointer list is empty.
Definition body_list.h:50
gmBody ** gmBodies
A specialized dynamic, NULL-terminated list for gmBody pointers.
Definition body_list.h:245
int gm_ptr_list_find(gmPtrList list, void *value)
Finds the index of a specific pointer.
Definition body_list.h:182
size_t gm_ptr_list_count(gmPtrList list, void *obj)
Counts the occurrences of a specific pointer in the list.
Definition body_list.h:60
void * gm_ptr_list_get(gmPtrList list, size_t index)
Retrieves the element at a specific index.
Definition body_list.h:199
void * malloc(size_t size)
Custom implementation of malloc using a static memory pool.
Definition malloc.h:144
void * realloc(void *ptr, size_t size)
Custom implementation of realloc for memory allocated by malloc (this custom version).
Definition malloc.h:236
void free(void *ptr)
Custom implementation of free for memory allocated by malloc (this custom version).
Definition malloc.h:189
Structure representing a physics body with properties for collision and movement.
Definition body.h:25