LCOV - code coverage report
Current view: top level - libs/mem/src - mem.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.0 % 4 3
Test Date: 2026-03-01 04:31:48 Functions: 100.0 % 1 1
Branches: 50.0 % 2 1

             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 */
        

Generated by: LCOV version 2.0-1