libcstl
Loading...
Searching...
No Matches
memory.h
Go to the documentation of this file.
1/*!
2 * @file
3 */
4
5#ifndef CSTL_MEMORY_H
6#define CSTL_MEMORY_H
7
8/*!
9 * @defgroup smartptr Smartish pointers
10 * @brief Non-automatic smart pointers
11 *
12 * In C++, memory can be allocated using unique_ptrs and shared_ptrs,
13 * and the memory associated with them is freed automatically when
14 * they go out of scope. The objects here attempt to mimic that behavior,
15 * but in C, the caller is responsible for managing the lifetime of
16 * the objects. The improvement here is that the caller must reset the
17 * object(s) whenever they go out of scope.
18 *
19 * For example, without a smart pointer, the code may look something like:
20 * @code{.c}
21 * {
22 * void * data = malloc(len);
23 *
24 * (void)somefunc(data);
25 *
26 * // uh-oh, did somefunc() keep a pointer to data?
27 * // who is supposed to free it? this function
28 * // or somefunc()?
29 * }
30 * @endcode
31 *
32 * With a smart pointer, the above would look like:
33 * @code{.c}
34 * {
35 * DECLARE_CSTL_UNIQUE_PTR(data);
36 * cstl_unique_ptr_alloc(&data, len, NULL);
37 *
38 * (void)somefunc(&data);
39 *
40 * // it doesn't matter whether somefunc() kept
41 * // the pointer or not. this code must reset
42 * // the object before it goes out of scope.
43 *
44 * cstl_unique_ptr_reset(&data);
45 * }
46 * @endcode
47 */
48
49#include "cstl/common.h"
50
51#include <stdlib.h>
52#include <stdbool.h>
53
54/*!
55 * @defgroup guardedptr Guarded pointers
56 * @ingroup smartptr
57 * @brief Object to guard against direct copying of pointers
58 *
59 * The smart pointer objects are defined in the header, and so the
60 * programmer may directly copy those data structures via the @p = operator.
61 * The cstl_guarded_ptr objects attempts to catch such uses, since the other
62 * smart pointers depend on the non-direct copyability of their structures.
63 */
64/*!
65 * @addtogroup guardedptr
66 * @{
67 */
68
69/*!
70 * @brief Initialize (at compile-time) a guarded pointer object
71 *
72 * @param[in] NAME The name of the object being initialized
73 */
74#define CSTL_GUARDED_PTR_INITIALIZER(NAME) \
75 { \
76 .ptr = NULL, \
77 .self = &NAME, \
78 }
79/*!
80 * @brief Declare and initialize a guarded pointer
81 *
82 * @param[in] NAME The name of the object being declared
83 */
84#define DECLARE_CSTL_GUARDED_PTR(NAME) \
85 struct cstl_guarded_ptr NAME = \
86 CSTL_GUARDED_PTR_INITIALIZER(NAME)
87
88/*!
89 * @brief Structure to hold a pointer and guard against its direct copying
90 *
91 * This object holds a pointer, but whenever that pointer is retrieved,
92 * the code detects whether the object was directly copied via the @p =
93 * operator. When such a use is detected, the code abort()s.
94 */
96{
97 /*! @privatesection */
98 void * self;
99 void * ptr;
100};
101
102/*!
103 * @brief Initialize a guarded pointer object to a specific pointer value
104 *
105 * @param[out] gp The guarded pointer to initialize
106 * @param[in] ptr The pointer to store within the object
107 *
108 * The guarded pointer is (re)initialized regardless of its current state
109 */
110static inline void cstl_guarded_ptr_set(
111 struct cstl_guarded_ptr * const gp,
112 void * const ptr)
113{
114 gp->ptr = ptr;
115 gp->self = gp;
116}
117
118/*!
119 * @brief Initialize a guarded pointer object to NULL
120 *
121 * @param[out] gp The guarded pointer to initialize
122 */
123static inline void cstl_guarded_ptr_init(struct cstl_guarded_ptr * const gp)
124{
125 cstl_guarded_ptr_set(gp, NULL);
126}
127
128/*!
129 * @brief Retrieve the stored pointer value
130 *
131 * If the object has been copied via the @p = operator, the attempt to
132 * retrieve this function will cause an abort().
133 *
134 * @param[in] gp A pointer to the guarded pointer object
135 *
136 * @return The value of the pointer being guarded
137 */
138static inline const void * cstl_guarded_ptr_get_const(
139 const struct cstl_guarded_ptr * const gp)
140{
141 if (gp->self != gp) {
142 abort();
143 }
144 return gp->ptr;
145}
146
147/*! @copydoc cstl_guarded_ptr_get_const() */
148static inline void * cstl_guarded_ptr_get(struct cstl_guarded_ptr * const gp)
149{
150 return (void *)cstl_guarded_ptr_get_const(gp);
151}
152
153/*!
154 * @brief Copy the cstl_guarded_ptr object to a new location
155 *
156 * The destination object is overwritten/(re)initialized, regardless of
157 * its current state. If the source object has previously been copied via
158 * the @p = operator, this function will cause an abort().
159 *
160 * @param[out] dst A pointer to the object to receive the copy
161 * @param[in] src A pointer to the object to be copied
162 */
163static inline void cstl_guarded_ptr_copy(
164 struct cstl_guarded_ptr * const dst,
165 const struct cstl_guarded_ptr * const src)
166{
168}
169
170/*!
171 * @brief Swap the pointers pointed to by the objects
172 *
173 * @param[in,out] a A pointer to a guarded pointer
174 * @param[in,out] b A pointer to a(nother) guarded pointer
175 */
176static inline void cstl_guarded_ptr_swap(
177 struct cstl_guarded_ptr * const a,
178 struct cstl_guarded_ptr * const b)
179{
180 void * const t = cstl_guarded_ptr_get(a);
183}
184
185/*!
186 * @}
187 */
188/*!
189 * @defgroup uniqueptr Unique Pointers
190 * @ingroup smartptr
191 * @brief Dynamically-allocated memory with a single owner
192 *
193 * The unique pointer is meant to have a single owner. It may be shared,
194 * but that sharing is temporary, i.e. the sharing must end when the
195 * callee returns/goes out of scope. Alternatively, the callee may take
196 * ownership of the pointer by transferring it out of the caller's
197 * unique pointer object and into its own.
198 *
199 * The unique pointer object manages the dynamically allocated memory
200 * via the cstl_guarded_ptr object, and some functions may abort() if they
201 * detect that that objects rules have been violated.
202 */
203/*!
204 * @addtogroup uniqueptr
205 * @{
206 */
207
208/*!
209 * @brief Initialize (at compile time) a unique pointer
210 *
211 * @param[in] NAME The name of the object being initialized
212 */
213#define CSTL_UNIQUE_PTR_INITIALIZER(NAME) \
214 { \
215 .gp = CSTL_GUARDED_PTR_INITIALIZER(NAME.gp), \
216 .clr = { \
217 .func = NULL, \
218 .priv = NULL, \
219 }, \
220 }
221/*!
222 * @brief Declare and initialize a unique pointer
223 *
224 * @param[in] NAME The name of the variable being declared
225 */
226#define DECLARE_CSTL_UNIQUE_PTR(NAME) \
227 cstl_unique_ptr_t NAME = \
228 CSTL_UNIQUE_PTR_INITIALIZER(NAME)
229
230/*!
231 * @brief A pointer that has a single "owner"
232 */
233typedef struct
234{
235 /*! @privatesection */
236 struct cstl_guarded_ptr gp;
237 struct
238 {
239 cstl_xtor_func_t * func;
240 void * priv;
241 } clr;
243
244/*!
245 * @brief Initialize a unique pointer
246 *
247 * @param[out] up A pointer to a unique pointer object
248 */
249static inline void cstl_unique_ptr_init(cstl_unique_ptr_t * const up)
250{
251 cstl_guarded_ptr_set(&up->gp, NULL);
252 up->clr.func = NULL;
253 up->clr.priv = NULL;
254}
255
256/*!
257 * @brief Dynamically allocate memory to be managed by the unique pointer
258 *
259 * The function allocates the requested number of bytes via malloc(),
260 * and stores the resulting pointer within the unique pointer object.
261 * The caller may provide a "clear" function that will be called prior
262 * to the memory being freed whin the unique pointer is reset.
263 *
264 * @param[in] up A pointer to a unique pointer object
265 * @param[in] len The number of bytes to allocate
266 * @param[in] clr A pointer to a function to call when the memory is freed.
267 * This pointer may be NULL
268 * @param[in] priv A pointer to be passed to the @p clr function
269 */
271 cstl_unique_ptr_t * up, size_t len, cstl_xtor_func_t * clr, void * priv);
272
273/*!
274 * @brief Get the pointer managed by the unique pointer object
275 *
276 * @param[in] up A pointer to a unique pointer object
277 *
278 * @return The pointer managed by the unique pointer object
279 * @retval NULL No pointer is managed by the unique pointer object
280 */
281static inline const void * cstl_unique_ptr_get_const(
282 const cstl_unique_ptr_t * const up)
283{
284 return cstl_guarded_ptr_get_const(&up->gp);
285}
286
287/*! @copydoc cstl_unique_ptr_get_const() */
288static inline void * cstl_unique_ptr_get(cstl_unique_ptr_t * const up)
289{
290 return (void *)cstl_unique_ptr_get_const(up);
291}
292
293/*!
294 * @brief Stop a unique pointer object from managing a pointer
295 *
296 * The managed pointer is returned, and the clear function is also
297 * returned via the parameter, if non-NULL. Upon return, the object
298 * does not manage any pointer and the caller is responsible for
299 * calling the associated clear function and freeing the memory.
300 *
301 * @param[in] up A pointer to a unique pointer object
302 * @param[out] clr A pointer to a function pointer to receive a pointer
303 * to the associated clear function. This parameter may
304 * be NULL
305 * @param[out] priv A pointer that would have been passed to the @p clr
306 * function
307 *
308 * @return The formerly managed pointer
309 * @retval NULL The object was not managing a pointer
310 */
311static inline void * cstl_unique_ptr_release(
312 cstl_unique_ptr_t * const up,
313 cstl_xtor_func_t ** const clr, void ** priv)
314{
315 void * const p = cstl_unique_ptr_get(up);
316 if (clr != NULL) {
317 *clr = up->clr.func;
318 }
319 if (priv != NULL) {
320 *priv = up->clr.priv;
321 }
323 return p;
324}
325
326/*!
327 * @brief Swap the objects pointed to by the parameters
328 *
329 * @param[in,out] up1 A pointer to a unique pointer object
330 * @param[in,out] up2 A pointer to a(nother) unique pointer object
331 */
332static inline void cstl_unique_ptr_swap(cstl_unique_ptr_t * const up1,
333 cstl_unique_ptr_t * const up2)
334{
335 uint8_t t[sizeof(up1->clr)];
336 cstl_guarded_ptr_swap(&up1->gp, &up2->gp);
337 cstl_swap(&up1->clr, &up2->clr, t, sizeof(t));
338}
339
340/*!
341 * @brief Free the memory managed by a unique pointer
342 *
343 * The managed pointer's clear function, if any, is called, and the
344 * memory managed by the unique pointer is freed. Upon return, the
345 * object no longer manages any memory and is in a newly initialized
346 * state
347 *
348 * @param[in,out] up A pointer to the unique pointer object
349 */
351
352/*!
353 * @}
354 */
355
356/*!
357 * @defgroup sharedptr Shared Pointers
358 * @ingroup smartptr
359 * @brief Reference-counted, dynamically-allocated memory
360 *
361 * The shared pointer object manages dynamically-allocated memory
362 * by allowing it to be shared through the use of reference counting.
363 * Multiple shared pointer objects may point to the same dynamically
364 * allocated memory. The caller is responsible for mediating access
365 * to the allocated memory, but the shared pointer object(s) will
366 * manage the lifetime of that memory.
367 *
368 * @see weakptr
369 */
370/*!
371 * @addtogroup sharedptr
372 * @{
373 */
374
375/*!
376 * @brief Compile-time initialization of a declared shared pointer
377 *
378 * @param[in] NAME The name of the variable being initialized
379 */
380#define CSTL_SHARED_PTR_INITIALIZER(NAME) \
381 { \
382 .data = CSTL_GUARDED_PTR_INITIALIZER(NAME.data), \
383 }
384/*!
385 * @brief Compile-time declaration and initialization of a shared pointer
386 *
387 * @param[in] NAME The name of the variable being declared
388 */
389#define DECLARE_CSTL_SHARED_PTR(NAME) \
390 cstl_shared_ptr_t NAME = CSTL_SHARED_PTR_INITIALIZER(NAME)
391
392/*!
393 * @brief The shared pointer object
394 */
395typedef struct
396{
397 /*! @privatesection */
398 struct cstl_guarded_ptr data;
400
401/*!
402 * @brief Initialize a shared pointer object
403 *
404 * Upon return, the shared pointer manages no memory.
405 *
406 * @param[out] sp A pointer to a shared pointer object
407 */
408static inline void cstl_shared_ptr_init(cstl_shared_ptr_t * const sp)
409{
410 cstl_guarded_ptr_set(&sp->data, NULL);
411}
412
413/*!
414 * @brief Dynamically allocated memory to be shared via the object
415 *
416 * The supplied shared pointer object must have already been initialized
417 * and will be reset an preparation for the new allocation.
418 *
419 * @param[in,out] sp A pointer to the shared pointer object
420 * @param[in] sz The number of bytes to allocate
421 * @param[in] clr A function to be called when the allocated memory is freed.
422 * This pointer may be NULL
423 */
425 cstl_shared_ptr_t * sp, size_t sz, cstl_xtor_func_t * clr);
426
427/*!
428 * @brief Determine if a shared pointer uniquely owns the underlying memory
429 *
430 * If this function returns true, there are no other pointers to the
431 * underlying memory, weak or shared.
432 *
433 * @param[in] sp A shared pointer object
434 *
435 * @retval true The shared pointer manages no memory or is the only owner
436 * of the memory it manages
437 * @retval false The underlying memory has more than one owner
438 */
440
441/*!
442 * @brief Get a pointer to the memory managed by the object
443 *
444 * @return A pointer to the managed memory
445 * @retval NULL No memory is managed by the object
446 */
447const void * cstl_shared_ptr_get_const(const cstl_shared_ptr_t *);
448
449/*! @copydoc cstl_shared_ptr_get_const() */
450static inline void * cstl_shared_ptr_get(cstl_shared_ptr_t * const sp)
451{
452 return (void *)cstl_shared_ptr_get_const(sp);
453}
454
455/*!
456 * @brief Create a new shared pointer object to manage the underlying memory
457 *
458 * @param[in] ex A pointer to the existing shared pointer
459 * @param[in,out] n A pointer to a object with which to shared
460 * the existing memory
461 */
463
464/*!
465 * @brief Swap the memory managed by the two objects
466 *
467 * @param[in,out] sp1 A pointer to a shared pointer object
468 * @param[in,out] sp2 A pointer to a(nother) shared pointer object
469 */
470static inline void cstl_shared_ptr_swap(cstl_shared_ptr_t * const sp1,
471 cstl_shared_ptr_t * const sp2)
472{
473 cstl_guarded_ptr_swap(&sp1->data, &sp2->data);
474}
475
476/*!
477 * @brief Stop managing the underlying memory via this object
478 *
479 * If this object is the last object managing the underlying memory,
480 * the underlying memory will be free with its clear function, if
481 * present, being called just prior to that.
482 *
483 * @param[in,out] sp A pointer to the shared object
484 */
486
487/*!
488 * @}
489 */
490/*!
491 * @defgroup weakptr Weak Pointers
492 * @ingroup smartptr
493 * @brief Non-"owning" reference to a shared pointer
494 *
495 * Weak pointers point to memory managed by one or more shared pointer
496 * objects, but do not "own" it. This means that a weak pointer may
497 * be converted to a shared pointer while there is at least one other
498 * valid shared pointer still managing the memory. If there are no other
499 * shared pointer objects still managing the underlying memory, then any
500 * attempt to convert a weak pointer to a shared pointer will fail.
501 */
502/*!
503 * @addtogroup weakptr
504 * @{
505 */
506
507/*!
508 * @brief Compile-time initialization of a weak pointer
509 *
510 * @param[in] NAME The name of the variable being initialized
511 */
512#define CSTL_WEAK_PTR_INITIALIZER(NAME) \
513 CSTL_SHARED_PTR_INITIALIZER(NAME)
514/*!
515 * @brief Compile-time declaration and initialization of a weak pointer
516 *
517 * @param[in] NAME The name of the variable being initialized
518 */
519#define DECLARE_CSTL_WEAK_PTR(NAME) \
520 cstl_weak_ptr_t NAME = CSTL_WEAK_PTR_INITIALIZER(NAME)
521
522/*!
523 * @brief The weak pointer object
524 */
526
527/*!
528 * @brief Initialize a weak pointer object
529 *
530 * @param[out] wp A pointer to an uninitialized weak pointer object
531 */
532static inline void cstl_weak_ptr_init(cstl_weak_ptr_t * const wp)
533{
535}
536
537/*!
538 * @brief Create a weak pointer from a shared pointer
539 *
540 * The weak pointer must have already been initialized, and it will
541 * be reset prior to becoming a reference to the shared memory.
542 *
543 * @param[in,out] wp A pointer to a weak pointer object
544 * @param[in] sp A pointer to a shared pointer object
545 */
547/*!
548 * @brief Convert a weak pointer to a shared pointer
549 *
550 * The weak pointer is not modified, but if the underlying memory
551 * is still "live", the shared pointer will become an owning reference
552 * to that memory.
553 *
554 * @param[in] wp A pointer to a weak pointer object
555 * @param[in,out] sp A pointer to a shared pointer object
556 */
558
559/*!
560 * @brief Swap the memory managed by the two weak pointer objects
561 *
562 * @param[in,out] wp1 A pointer to a weak pointer object
563 * @param[in,out] wp2 A pointer to a(nother) weak pointer object
564 */
565static inline void cstl_weak_ptr_swap(cstl_weak_ptr_t * const wp1,
566 cstl_weak_ptr_t * const wp2)
567{
568 cstl_shared_ptr_swap(wp1, wp2);
569}
570
571/*!
572 * @brief Drop the reference to the underlying managed memory
573 *
574 * The weak pointer does not "own" the managed memory, so if that memory
575 * is still live, this function will not cause it to be freed.
576 *
577 * @param[in,out] wp A pointer to a weak pointer object
578 */
580
581/*!
582 * @}
583 */
584
585#endif
static void cstl_swap(void *const x, void *const y, void *const t, const size_t sz)
Swap values at two memory locations via use of a third.
Definition common.h:137
void cstl_xtor_func_t(void *obj, void *priv)
Type for functions called to construct, clear, or destroy an object.
Definition common.h:97
static void cstl_guarded_ptr_set(struct cstl_guarded_ptr *const gp, void *const ptr)
Initialize a guarded pointer object to a specific pointer value.
Definition memory.h:110
static void cstl_guarded_ptr_copy(struct cstl_guarded_ptr *const dst, const struct cstl_guarded_ptr *const src)
Copy the cstl_guarded_ptr object to a new location.
Definition memory.h:163
static void cstl_guarded_ptr_init(struct cstl_guarded_ptr *const gp)
Initialize a guarded pointer object to NULL.
Definition memory.h:123
static const void * cstl_guarded_ptr_get_const(const struct cstl_guarded_ptr *const gp)
Retrieve the stored pointer value.
Definition memory.h:138
static void cstl_guarded_ptr_swap(struct cstl_guarded_ptr *const a, struct cstl_guarded_ptr *const b)
Swap the pointers pointed to by the objects.
Definition memory.h:176
static void * cstl_guarded_ptr_get(struct cstl_guarded_ptr *const gp)
Retrieve the stored pointer value.
Definition memory.h:148
static void cstl_shared_ptr_swap(cstl_shared_ptr_t *const sp1, cstl_shared_ptr_t *const sp2)
Swap the memory managed by the two objects.
Definition memory.h:470
void cstl_shared_ptr_reset(cstl_shared_ptr_t *sp)
Stop managing the underlying memory via this object.
Definition memory.c:128
bool cstl_shared_ptr_unique(const cstl_shared_ptr_t *sp)
Determine if a shared pointer uniquely owns the underlying memory.
Definition memory.c:92
static void * cstl_shared_ptr_get(cstl_shared_ptr_t *const sp)
Get a pointer to the memory managed by the object.
Definition memory.h:450
void cstl_shared_ptr_share(const cstl_shared_ptr_t *ex, cstl_shared_ptr_t *n)
Create a new shared pointer object to manage the underlying memory.
Definition memory.c:113
void cstl_shared_ptr_alloc(cstl_shared_ptr_t *sp, size_t sz, cstl_xtor_func_t *clr)
Dynamically allocated memory to be shared via the object.
Definition memory.c:65
const void * cstl_shared_ptr_get_const(const cstl_shared_ptr_t *)
Get a pointer to the memory managed by the object.
Definition memory.c:103
static void cstl_shared_ptr_init(cstl_shared_ptr_t *const sp)
Initialize a shared pointer object.
Definition memory.h:408
static void cstl_unique_ptr_swap(cstl_unique_ptr_t *const up1, cstl_unique_ptr_t *const up2)
Swap the objects pointed to by the parameters.
Definition memory.h:332
static void cstl_unique_ptr_init(cstl_unique_ptr_t *const up)
Initialize a unique pointer.
Definition memory.h:249
static void * cstl_unique_ptr_get(cstl_unique_ptr_t *const up)
Get the pointer managed by the unique pointer object.
Definition memory.h:288
void cstl_unique_ptr_reset(cstl_unique_ptr_t *up)
Free the memory managed by a unique pointer.
Definition memory.c:55
void cstl_unique_ptr_alloc(cstl_unique_ptr_t *up, size_t len, cstl_xtor_func_t *clr, void *priv)
Dynamically allocate memory to be managed by the unique pointer.
Definition memory.c:41
static void * cstl_unique_ptr_release(cstl_unique_ptr_t *const up, cstl_xtor_func_t **const clr, void **priv)
Stop a unique pointer object from managing a pointer.
Definition memory.h:311
static const void * cstl_unique_ptr_get_const(const cstl_unique_ptr_t *const up)
Get the pointer managed by the unique pointer object.
Definition memory.h:281
void cstl_weak_ptr_reset(cstl_weak_ptr_t *)
Drop the reference to the underlying managed memory.
Definition memory.c:215
static void cstl_weak_ptr_init(cstl_weak_ptr_t *const wp)
Initialize a weak pointer object.
Definition memory.h:532
static void cstl_weak_ptr_swap(cstl_weak_ptr_t *const wp1, cstl_weak_ptr_t *const wp2)
Swap the memory managed by the two weak pointer objects.
Definition memory.h:565
cstl_shared_ptr_t cstl_weak_ptr_t
The weak pointer object.
Definition memory.h:525
void cstl_weak_ptr_from(cstl_weak_ptr_t *wp, const cstl_shared_ptr_t *sp)
Create a weak pointer from a shared pointer.
Definition memory.c:146
void cstl_weak_ptr_lock(const cstl_weak_ptr_t *wp, cstl_shared_ptr_t *sp)
Convert a weak pointer to a shared pointer.
Definition memory.c:160
Structure to hold a pointer and guard against its direct copying.
Definition memory.h:96
The shared pointer object.
Definition memory.h:396
A pointer that has a single "owner".
Definition memory.h:234