Branch data Line data Source code
1 : : #ifndef MEM_H
2 : : #define MEM_H
3 : :
4 : : #include "rational.h"
5 : : #include <stddef.h>
6 : : #include <stdlib.h>
7 : : #include <stdint.h> /* SIZE_MAX */
8 : : #include <limits.h>
9 : : #include "mem_telemetry.h"
10 : :
11 : : /** Minimum allocation block size (in bytes) for the helper. */
12 : : #define MEMORY_BLOCK_BYTES (4UL * 1024)
13 : :
14 : : /**
15 : : * @file mem.h
16 : : * @brief Public API for a small, typed dynamic-memory helper.
17 : : *
18 : : * This library provides a tiny descriptor (`struct memory`) that stores the size
19 : : * of one element, the current element count (`length`), and a data pointer. The element
20 : : * size is fixed once via the `create(T, name)` macro and reused by allocation
21 : : * routines.
22 : : *
23 : : * @see mem_resize.c and related implementation units for details.
24 : : */
25 : :
26 : : /**
27 : : * @brief Memory Helper API
28 : : *
29 : : * Top-level group for all public symbols of the memory helper.
30 : : */
31 : :
32 : : /**
33 : : * @struct memory
34 : : * @brief Describes a typed dynamic memory block.
35 : : *
36 : : * @var memory::element_size
37 : : * Size in bytes of one array element. Set once by @ref create.
38 : : *
39 : : * @var memory::length
40 : : * Current number of elements in the allocated block.
41 : : *
42 : : * @var memory::actually_allocated_bytes
43 : : * Actually allocated memory in bytes
44 : : *
45 : : * @var memory::data
46 : : * Pointer to the beginning of the allocated block (or NULL if none).
47 : : */
48 : : typedef struct memory {
49 : : size_t element_size;
50 : : size_t length;
51 : : size_t actually_allocated_bytes;
52 : : void *data;
53 : : } memory;
54 : :
55 : : /**
56 : : * @brief Resize behavior flags for @ref memory_resize.
57 : : *
58 : : * These masks can be combined to tune how @ref memory_resize behaves:
59 : : * - `ZERO_NEW_MEMORY` mirrors `calloc` semantics by clearing any bytes that
60 : : * become newly addressable when a descriptor grows.
61 : : * - `RELEASE_UNUSED` instructs the helper to release excess capacity immediately
62 : : * when the requested length decreases, instead of holding on to the buffer.
63 : : *
64 : : * Flags may be OR-ed together (for example, `ZERO_NEW_MEMORY | RELEASE_UNUSED`)
65 : : * so that both behaviors are enabled during one call.
66 : : */
67 : : typedef enum
68 : : {
69 : : ZERO_NEW_MEMORY = 0x01u,
70 : : RELEASE_UNUSED = 0x02u
71 : : } RESIZEMODES;
72 : :
73 : : /**
74 : : * @brief Allocation functions
75 : : *
76 : : * Functions for allocating, resizing, and freeing memory.
77 : : */
78 : :
79 : : /**
80 : : * @brief Resize the managed block to hold the given number of elements.
81 : : *
82 : : * @param memory_object Pointer to a descriptor initialized via @ref create.
83 : : * @param element_count New number of elements.
84 : : * @param ... Optional @ref RESIZEMODES mask controlling zero-fill or shrink behavior.
85 : : * @return `SUCCESS` on success; `FAILURE` otherwise. All failures are reported
86 : : * through @ref report for easier diagnostics.
87 : : *
88 : : * @post If @p element_count is 0, the function frees the block and sets
89 : : * @ref memory::data to NULL and @ref memory::length to 0.
90 : : *
91 : : * @warning The returned data pointer may change; always refresh any cached
92 : : * pointers after a successful resize.
93 : : */
94 : : Return memory_resize(
95 : : memory *memory_object,
96 : : size_t element_count,
97 : : ...);
98 : :
99 : : /**
100 : : * @brief Free the allocated block and reset the descriptor (except element size).
101 : : *
102 : : * @param memory_object Pointer to a descriptor.
103 : : *
104 : : * @post Sets @ref memory::data to NULL and @ref memory::length to 0.
105 : : * The @ref memory::element_size remains unchanged so the descriptor can be
106 : : * allocated again for the same element type.
107 : : */
108 : : Return memory_delete(memory *memory_object);
109 : :
110 : : /**
111 : : * @brief Copy the contents of @p source descriptor into @p destination.
112 : : *
113 : : * @param destination Pointer to the destination descriptor (resized if needed).
114 : : * @param source Pointer to the source descriptor to copy from.
115 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
116 : : */
117 : : Return memory_copy(
118 : : memory *destination,
119 : : const memory *source);
120 : :
121 : : /**
122 : : * @brief Copy a raw byte buffer into a descriptor.
123 : : *
124 : : * Interprets @p buffer_size as the exact number of source bytes to import.
125 : : * The destination is resized to hold the same payload size in descriptor
126 : : * elements (`buffer_size / element_size`) and then receives a byte-for-byte
127 : : * copy.
128 : : *
129 : : * Behavior details:
130 : : * - @p destination must be initialized (non-zero @ref memory::element_size).
131 : : * - @p buffer_size must be divisible by @ref memory::element_size.
132 : : * - If @p source_buffer is `NULL` and @p buffer_size is 0, the destination is
133 : : * cleared (`resize(destination,0)` behavior).
134 : : * - If @p source_buffer is `NULL` and @p buffer_size is non-zero, the call fails.
135 : : *
136 : : * @param destination Pointer to the destination descriptor (resized if needed).
137 : : * @param source_buffer Pointer to source bytes.
138 : : * @param buffer_size Number of bytes to copy from @p source_buffer.
139 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
140 : : */
141 : : Return memory_copy_buffer(
142 : : memory *destination,
143 : : const void *source_buffer,
144 : : size_t buffer_size);
145 : :
146 : : /**
147 : : * @brief Copy visible string bytes from a known-size source buffer.
148 : : *
149 : : * Interprets @p source_buffer as a bounded C-string region. The visible source
150 : : * length is computed with @ref memory_string_length semantics (scan up to first
151 : : * `'\0'` or @p source_buffer_size bytes), then copied into @p destination with
152 : : * exactly one trailing null terminator.
153 : : *
154 : : * @param destination Pointer to destination descriptor.
155 : : * @param source_buffer Pointer to source bytes.
156 : : * @param source_buffer_size Total bytes available in @p source_buffer.
157 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
158 : : */
159 : : Return memory_copy_cstring(
160 : : memory *destination,
161 : : const char *source_buffer,
162 : : size_t source_buffer_size);
163 : :
164 : : /**
165 : : * @brief Append the contents of @p source descriptor to @p destination.
166 : : *
167 : : * @param destination Pointer to the destination descriptor to extend.
168 : : * @param source Pointer to the source descriptor to append from.
169 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
170 : : */
171 : : Return memory_append(
172 : : memory *destination,
173 : : const memory *source);
174 : :
175 : : /**
176 : : * @brief Concatenate string data held in descriptors, keeping exactly one trailing NUL.
177 : : *
178 : : * Treats the managed memory as byte-oriented strings (element size must be 1). The
179 : : * resulting descriptor is resized to `len(destination) + len(source) + 1` and made
180 : : * null-terminated even if the inputs lacked a terminator.
181 : : *
182 : : * @param destination Pointer to the descriptor receiving the concatenated string.
183 : : * @param source Pointer to the descriptor providing the appended string.
184 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
185 : : */
186 : : Return memory_concat_strings(
187 : : memory *destination,
188 : : const memory *source);
189 : :
190 : : /**
191 : : * @brief Concatenate visible bytes from a known-size source string buffer.
192 : : *
193 : : * Treats @p source_buffer as byte-oriented string data bounded by
194 : : * @p source_buffer_size bytes. The visible source length is computed with
195 : : * @ref memory_string_length semantics (scan up to first `'\0'` or the provided
196 : : * byte bound, whichever comes first), then appended to @p destination.
197 : : *
198 : : * The destination is interpreted as a C-style string descriptor and the result
199 : : * keeps exactly one trailing null terminator.
200 : : *
201 : : * @param destination Pointer to the descriptor receiving appended data.
202 : : * @param source_buffer Pointer to source bytes.
203 : : * @param source_buffer_size Total bytes available in @p source_buffer.
204 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
205 : : */
206 : : Return memory_concat_cstring(
207 : : memory *destination,
208 : : const char *source_buffer,
209 : : size_t source_buffer_size);
210 : :
211 : : /**
212 : : * @brief Concatenate a raw byte buffer to a descriptor.
213 : : *
214 : : * Interprets @p source_buffer_size as exact bytes and appends them as-is.
215 : : * No string parsing is performed, embedded `'\0'` bytes are preserved, and no
216 : : * trailing terminator is injected.
217 : : *
218 : : * Behavior details:
219 : : * - @p destination must be initialized (non-zero @ref memory::element_size).
220 : : * - @p source_buffer_size must be divisible by @ref memory::element_size.
221 : : * - If @p source_buffer is `NULL` and @p source_buffer_size is 0, the call is
222 : : * treated as a no-op.
223 : : * - If @p source_buffer is `NULL` and @p source_buffer_size is non-zero, the
224 : : * call fails.
225 : : *
226 : : * @param destination Pointer to the descriptor receiving appended data.
227 : : * @param source_buffer Pointer to source bytes.
228 : : * @param source_buffer_size Total bytes available in @p source_buffer.
229 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
230 : : */
231 : : Return memory_concat_buffer(
232 : : memory *destination,
233 : : const void *source_buffer,
234 : : size_t source_buffer_size);
235 : :
236 : : /**
237 : : * @brief Append a C-style literal string to a descriptor holding byte-sized elements.
238 : : *
239 : : * Resizes @p destination to `len(destination) + strlen(literal) + 1`, copies the literal,
240 : : * and guarantees a single trailing null terminator.
241 : : *
242 : : * @param destination Pointer to the descriptor receiving the literal contents.
243 : : * @param literal Pointer to a null-terminated C string.
244 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
245 : : */
246 : : Return memory_concat_literal(
247 : : memory *destination,
248 : : const char *literal);
249 : :
250 : : /**
251 : : * @brief Copy a C-style literal string into a descriptor holding byte-sized elements.
252 : : *
253 : : * Resizes @p destination to `strlen(literal) + 1`, copies the literal, and guarantees a
254 : : * trailing null terminator. Previous contents of @p destination are discarded.
255 : : *
256 : : * @param destination Pointer to the descriptor receiving the literal.
257 : : * @param literal Pointer to a null-terminated C string.
258 : : * @return `SUCCESS` on success; `FAILURE` otherwise.
259 : : */
260 : : Return memory_copy_literal(
261 : : memory *destination,
262 : : const char *literal);
263 : :
264 : : /** @cond INTERNAL */
265 : : /**
266 : : * @brief Multiply two size_t values with overflow detection.
267 : : *
268 : : * Used by implementation files to detect overflows when computing byte counts.
269 : : *
270 : : * @param left Left operand.
271 : : * @param right Right operand.
272 : : * @param product Output pointer for the product on success.
273 : : * @return Return status indicating whether the multiplication succeeded.
274 : : */
275 : : Return memory_guarded_size(
276 : : size_t left,
277 : : size_t right,
278 : : size_t *product);
279 : : /** @endcond */
280 : :
281 : : /**
282 : : * @brief Compute the visible length of string data stored in a descriptor.
283 : : *
284 : : * The scan stops either at the first null byte or once @ref memory::length bytes
285 : : * have been inspected. This ensures the function never reads beyond descriptor
286 : : * bounds while still supporting partially filled buffers.
287 : : *
288 : : * Behavior details:
289 : : * - Invalid arguments (`memory_object == NULL` or `length_out == NULL`) return
290 : : * `FAILURE`.
291 : : * - If @ref memory::length is 0, `*length_out` is set to 0.
292 : : * - If @ref memory::data is `NULL`, `*length_out` is set to 0.
293 : : * - Otherwise, `*length_out` receives the visible prefix length in bytes.
294 : : *
295 : : * Return-path details:
296 : : * - The function returns via `provide(...)`.
297 : : * - If global status (`global_return_status`) is not `SUCCESS`, the returned
298 : : * value may be overridden by that global status.
299 : : * - For control-flow checks that treat graceful non-error statuses as
300 : : * acceptable, prefer `(status & TRIUMPH) != 0`.
301 : : *
302 : : * @param memory_object Descriptor whose contents are interpreted as a string.
303 : : * @param length_out Output pointer that receives the computed length.
304 : : * @return Local result is `SUCCESS`/`FAILURE`; final returned value is subject
305 : : * to `provide(...)` global-status propagation.
306 : : */
307 : : Return memory_string_length(
308 : : const memory *memory_object,
309 : : size_t *length_out);
310 : :
311 : : /**
312 : : * @brief Provide a safe read-only pointer to descriptor-backed string data.
313 : : *
314 : : * Guarantees that callers always receive a valid, null-terminated byte sequence:
315 : : * - When @p memory_object is NULL, uninitialized, or sized for non-byte
316 : : * elements, the function returns an empty string.
317 : : * - When the descriptor lacks a null terminator within @ref memory::length
318 : : * bytes, the function also falls back to an empty string rather than exposing
319 : : * potentially uninitialized memory.
320 : : *
321 : : * This helper is ideal when passing managed buffers to functions such as
322 : : * `printf`, `puts`, or regex engines where a missing terminator would otherwise
323 : : * lead to undefined behavior.
324 : : *
325 : : * @param memory_object Descriptor interpreted as a character buffer.
326 : : * @return Pointer to a guaranteed null-terminated string (never NULL).
327 : : */
328 : : const char *memory_getcstring(const memory *memory_object);
329 : :
330 : : /**
331 : : * @brief Provide a writable pointer to descriptor-backed string data, creating
332 : : * an empty string fallback when needed.
333 : : *
334 : : * Ensures that callers can safely treat a descriptor as holding a mutable
335 : : * C-style string:
336 : : * - If the descriptor is NULL or its metadata is invalid, the helper returns a
337 : : * pointer to a shared zero byte instead of NULL.
338 : : * - If the descriptor has zero length, it is resized to hold at least one
339 : : * null terminator.
340 : : * - If the descriptor lacks a terminator within @ref memory::length bytes, the
341 : : * first byte is set to `'\0'` before returning.
342 : : *
343 : : * @param memory_object Descriptor interpreted as a mutable character buffer.
344 : : * @return Pointer to a writable string (never NULL). When fallbacks are used,
345 : : * modifications affect only the shared zero byte.
346 : : */
347 : : char *memory_getstring(memory *memory_object);
348 : :
349 : : /**
350 : : * @brief Checked typed access
351 : : *
352 : : * Runtime type verification and typed data access.
353 : : */
354 : :
355 : : /**
356 : : * @brief Verify that the descriptor's element size matches @p expected_element_size.
357 : : *
358 : : * @param memory_object Pointer to a descriptor.
359 : : * @param expected_element_size Expected element size in bytes (typically `sizeof(T)`).
360 : : * @return `SUCCESS` if the sizes match; `FAILURE` otherwise (or when
361 : : * @p memory_object is NULL).
362 : : */
363 : : Return memory_verify_type(
364 : : const memory *memory_object,
365 : : size_t expected_element_size);
366 : :
367 : : /**
368 : : * @brief Return a writable data pointer after verifying the element size.
369 : : *
370 : : * Performs a runtime check that the descriptor's element size matches
371 : : * @p expected_element_size. On mismatch, the function logs the error and
372 : : * returns `NULL`.
373 : : *
374 : : * @param memory_object Pointer to a descriptor.
375 : : * @param expected_element_size Expected element size in bytes (typically `sizeof(T)`).
376 : : * @return Non-NULL `void*` on success; `NULL` on error.
377 : : */
378 : : void *memory_data_checked(
379 : : memory *memory_object,
380 : : size_t expected_element_size);
381 : :
382 : : /**
383 : : * @brief Return a read-only data pointer after verifying the element size.
384 : : *
385 : : * Same behavior as @ref memory_data_checked but returns a `const void*`.
386 : : *
387 : : * @param memory_object Pointer to a descriptor.
388 : : * @param expected_element_size Expected element size in bytes (typically `sizeof(T)`).
389 : : * @return Non-NULL `const void*` on success; `NULL` on error.
390 : : */
391 : : const void *memory_const_data_checked(
392 : : const memory *memory_object,
393 : : size_t expected_element_size);
394 : :
395 : : /**
396 : : * @brief Return the descriptor's raw data pointer without additional checks.
397 : : *
398 : : * @param memory_object Pointer to the descriptor.
399 : : * @return Underlying pointer or NULL when @p memory_object itself is NULL.
400 : : */
401 : 1612 : static inline void *memory_rawdata(const memory * const memory_object)
402 : : {
403 [ - + ]: 1612 : if(memory_object == NULL)
404 : : {
405 : 0 : return NULL;
406 : : }
407 : 1612 : return memory_object->data;
408 : : }
409 : :
410 : : /**
411 : : * @brief Return the descriptor's raw read-only pointer without additional checks.
412 : : *
413 : : * @param memory_object Pointer to the descriptor.
414 : : * @return Underlying pointer or NULL when @p memory_object itself is NULL.
415 : : */
416 : : static inline const void *memory_raw_const_data(const memory * const memory_object)
417 : : {
418 : : if(memory_object == NULL)
419 : : {
420 : : return NULL;
421 : : }
422 : : return memory_object->data;
423 : : }
424 : :
425 : : /**
426 : : * @brief Convenience macros
427 : : *
428 : : * Declarative and helper macros for user code.
429 : : */
430 : :
431 : : /**
432 : : * @def create(T, variable_name)
433 : : * @brief Declare and initialize a @ref memory descriptor on the stack.
434 : : *
435 : : * Sets @ref memory::element_size to `sizeof(T)`, zeroes the count, and sets
436 : : * @ref memory::data to `NULL`.
437 : : *
438 : : * @param T The element type (e.g., `int`, `struct point`, `double`).
439 : : * @param variable_name The descriptor variable name to declare.
440 : : *
441 : : * Internally it declares a storage descriptor named `_variable_name` and exposes
442 : : * `memory *variable_name` pointing to that storage so client code can always use
443 : : * pointer-style access.
444 : : *
445 : : * @warning This macro expands to a variable declaration. Use it only where
446 : : * declarations are allowed. The macro does not include a trailing
447 : : * semicolon; add one at the call site.
448 : : */
449 : : #define create(T,variable_name) \
450 : : memory _ ## variable_name = (memory){sizeof(T),0,0,NULL}; \
451 : : memory *variable_name = &_ ## variable_name
452 : :
453 : : /**
454 : : * @def resize(variable_name, number_of_elements)
455 : : * @brief Resize (or allocate) the block to @p number_of_elements elements.
456 : : */
457 : : #define resize(descriptor_expression,number_of_elements,...) \
458 : : memory_resize((descriptor_expression),(number_of_elements) \
459 : : __VA_OPT__( ,__VA_ARGS__),UCHAR_MAX)
460 : :
461 : : /**
462 : : * @def del(variable_name)
463 : : * @brief Free the allocation and reset the descriptor (except element size).
464 : : */
465 : : #define del(descriptor_expression) \
466 : : memory_delete((descriptor_expression))
467 : :
468 : : /**
469 : : * @def data(T, variable_name)
470 : : * @brief Get a writable typed pointer with a runtime check.
471 : : *
472 : : * Internally calls @ref memory_data_checked with `sizeof(T)` and casts the result
473 : : * to `T*`. Returns `NULL` on mismatch and logs the error.
474 : : */
475 : : #define data(T,descriptor_expression) \
476 : : ((T *)memory_data_checked((descriptor_expression),sizeof(T)))
477 : :
478 : : /**
479 : : * @def rawdata(variable_name)
480 : : * @brief Obtain the raw writable pointer (may be NULL if descriptor is NULL).
481 : : */
482 : : #define rawdata(descriptor_expression) \
483 : : memory_rawdata((descriptor_expression))
484 : :
485 : : /**
486 : : * @def cdata(T, variable_name)
487 : : * @brief Get a read-only typed pointer with a runtime check.
488 : : *
489 : : * Internally calls @ref memory_const_data_checked with `sizeof(T)` and casts the result
490 : : * to `const T*`. Returns `NULL` on mismatch and logs the error.
491 : : */
492 : : #define cdata(T,descriptor_expression) \
493 : : ((const T *)memory_const_data_checked((descriptor_expression),sizeof(T)))
494 : :
495 : : /**
496 : : * @def rawcdata(variable_name)
497 : : * @brief Obtain the raw read-only pointer (may be NULL if descriptor is NULL).
498 : : */
499 : : #define rawcdata(descriptor_expression) \
500 : : memory_raw_const_data((descriptor_expression))
501 : :
502 : : /**
503 : : * @def getstring(variable_name)
504 : : * @brief Obtain a writable C-style string pointer that is always safe to use.
505 : : *
506 : : * Internally calls @ref memory_getstring to guarantee that a null terminator is
507 : : * available. The descriptor must describe byte-sized elements.
508 : : */
509 : : #define getstring(descriptor_expression) \
510 : : memory_getstring((descriptor_expression))
511 : :
512 : : /**
513 : : * @def getcstring(variable_name)
514 : : * @brief Obtain a read-only C-style string pointer that is always safe to use.
515 : : *
516 : : * Internally calls @ref memory_getcstring to guard against NULL descriptors,
517 : : * missing allocations, or absent null terminators.
518 : : */
519 : : #define getcstring(descriptor_expression) \
520 : : memory_getcstring((descriptor_expression))
521 : :
522 : : /**
523 : : * @def copy(destination, source)
524 : : * @brief Copy one descriptor into another (resizing destination if needed).
525 : : */
526 : : #define copy(destination,source) \
527 : : memory_copy((destination),(source))
528 : :
529 : : /**
530 : : * @def copy_buffer(destination, buffer, buffer_size)
531 : : * @brief Copy a raw byte buffer into a descriptor.
532 : : */
533 : : #define copy_buffer(destination,buffer,buffer_size) \
534 : : memory_copy_buffer((destination),(buffer),(buffer_size))
535 : :
536 : : /**
537 : : * @def copy_cstring(destination, source_buffer, source_buffer_size)
538 : : * @brief Copy visible string bytes from a known-size source buffer.
539 : : */
540 : : #define copy_cstring(destination,source_buffer,source_buffer_size) \
541 : : memory_copy_cstring((destination),(source_buffer),(source_buffer_size))
542 : :
543 : : /**
544 : : * @def append(destination, source)
545 : : * @brief Append @p source contents to @p destination (resizing destination as needed).
546 : : */
547 : : #define append(destination,source) \
548 : : memory_append((destination),(source))
549 : :
550 : : /**
551 : : * @def concat_strings(destination, source)
552 : : * @brief Concatenate string descriptors, ensuring a single trailing `'\0'`.
553 : : */
554 : : #define concat_strings(destination,source) \
555 : : memory_concat_strings((destination),(source))
556 : :
557 : : /**
558 : : * @def concat_cstring(destination, source_buffer, source_buffer_size)
559 : : * @brief Concatenate visible bytes from a known-size source string buffer.
560 : : */
561 : : #define concat_cstring(destination,source_buffer,source_buffer_size) \
562 : : memory_concat_cstring((destination),(source_buffer),(source_buffer_size))
563 : :
564 : : /**
565 : : * @def concat_buffer(destination, source_buffer, source_buffer_size)
566 : : * @brief Concatenate exact bytes from a known-size raw buffer.
567 : : */
568 : : #define concat_buffer(destination,source_buffer,source_buffer_size) \
569 : : memory_concat_buffer((destination),(source_buffer),(source_buffer_size))
570 : :
571 : : /**
572 : : * @def concat_literal(destination, literal_string)
573 : : * @brief Append a null-terminated literal C string to a descriptor with byte-sized elements.
574 : : */
575 : : #define concat_literal(destination,literal_string) \
576 : : memory_concat_literal((destination),(literal_string))
577 : :
578 : : /**
579 : : * @def copy_literal(destination, literal_string)
580 : : * @brief Copy a null-terminated literal C string into a descriptor with byte-sized elements.
581 : : */
582 : : #define copy_literal(destination,literal_string) \
583 : : memory_copy_literal((destination),(literal_string))
584 : :
585 : : /**
586 : : * @brief Free an arbitrary pointer and reset it to NULL.
587 : : *
588 : : * This helper mirrors the legacy `memold` API and works for any pointer, not just
589 : : * descriptors created via @ref create.
590 : : *
591 : : * @param pointer_handle Address of the pointer to release.
592 : : */
593 : : void FREE_AND_RESET(void **pointer_handle);
594 : :
595 : : /**
596 : : * @def reset(pointer_expression)
597 : : * @brief Convenience macro that casts arguments to `void **` for @ref FREE_AND_RESET.
598 : : */
599 : : #define reset(pointer_expression) \
600 : : FREE_AND_RESET((void **)(pointer_expression))
601 : :
602 : : /**
603 : : * @def string_length(descriptor, length_out)
604 : : * @brief Measure the utilized byte length within a descriptor interpreted as a string.
605 : : */
606 : : #define string_length(descriptor_expression,length_out) \
607 : : memory_string_length((descriptor_expression),(length_out))
608 : :
609 : : /**
610 : : * @page mem_usage Usage Guide & Best Practices
611 : : *
612 : : * @section mem_usage_intro Introduction
613 : : * This page demonstrates typical patterns when using the memory helper.
614 : : *
615 : : * @section mem_usage_quick Quick start
616 : : * @code
617 : : * #include "mem.h"
618 : : * typedef struct { int x, y; } point;
619 : : *
620 : : * int main(void)
621 : : * {
622 : : * create(point,points); // declare + initialize descriptor
623 : : * if(CRITICAL & resize(points,10)) { } // handle error
624 : : * point *p = data(point,points); // checked typed access
625 : : * p[0] = (point){1,2};
626 : : * if(CRITICAL & resize(points,20)) { } // handle error
627 : : * p = data(point,points); // refresh pointer after resizing
628 : : * del(points);
629 : : * return 0;
630 : : * }
631 : : * @endcode
632 : : *
633 : : * @section mem_usage_notes Notes & Recommendations
634 : : * - Always refresh any cached typed pointer after a successful @ref resize.
635 : : * - Consider wrapping error codes with your project’s error-handling utilities.
636 : : * - `resize(...,0)` is equivalent to `free` and resets the descriptor
637 : : * (`data = NULL`, `length = 0`).
638 : : * - Always go through the helper macros so pointer conversions stay explicit and safe.
639 : : */
640 : : #endif /* MEM_H */
|