Configuration

dynostatic-buffer has no runtime configuration: everything is fixed at compile time through preprocessor macros. This keeps the footprint fully predictable — the size of an instance, the number of allocations it can hold and the alignment it guarantees are all known when the binary is linked.

Important

These macros change sizeof(dynostatic_buffer_t) and the meaning of the offsets stored in it. Every translation unit that includes dynostatic-buffer.h — the library itself and all of your code — must be compiled with identical values. Mismatched values compile cleanly but lead to silent memory corruption. Define them once in a shared place: a CMake cache entry, the DYNOSTATIC_BUFFER_CPPFLAGS Make variable, or a -D on every compile line.

Each macro is guarded with #ifndef, so any value you define (via CMake, KConfig, or -D) before the header is included takes precedence over the default shown below.

Options

DS_BUFFER_MEMORY_SIZE

Default: 1024.

Size in bytes of the arena embedded in each instance — the total pool every allocation is carved from. This is the dominant term in the instance’s memory footprint. Must be at least DS_MAX_ALLOCATION_SIZE.

DS_MAX_ALLOCATION_COUNT

Default: 10.

Maximum number of allocator records, i.e. the hard cap on how many blocks (live or parked for reuse) can exist at once. When they are exhausted, ds_malloc() fails with ERROR_DS_NO_ALLOCATORS regardless of how much memory is free. Must be positive.

DS_MAX_ALLOCATION_SIZE

Default: 256.

The largest size a single allocation may request. Requests above this cap are rejected with ERROR_DS_TOO_BIG_CHUNK. Must be positive, a multiple of DS_ALIGNMENT, and no larger than DS_BUFFER_MEMORY_SIZE.

DS_ALIGNMENT

Default: 4.

Alignment, in bytes, of every returned pointer and the rounding granularity for block capacities. Must be a power of two, at least the alignment of a 32-bit type, and no larger than the platform’s strictest fundamental alignment. Larger values waste more to internal rounding but satisfy stricter types (e.g. SIMD or DMA buffers).

DS_ZERO_ON_FREE

Default: 0.

When set to 1, the full capacity of a block is zeroed on ds_free() (and when a block is released during a relocating ds_realloc()). Useful for scrubbing sensitive data or getting deterministic contents, at the cost of the zeroing work. Note this does not affect ds_calloc(), whose zero-fill is unconditional.

DS_LOG_ENABLE

Default: 0.

When set to 1, enables the library’s internal logging. Leave it off unless you are debugging the allocator itself.

Compile-time validation

The header turns the constraints above into _Static_assert (C11) / static_assert (C++) checks, so an inconsistent configuration fails to compile rather than misbehaving at runtime. The enforced invariants are:

  • DS_ALIGNMENT is a power of two.

  • DS_ALIGNMENT is at least the alignment required by 32-bit types.

  • DS_ALIGNMENT does not exceed the strictest fundamental alignment on the platform.

  • DS_MAX_ALLOCATION_SIZE <= DS_BUFFER_MEMORY_SIZE.

  • DS_MAX_ALLOCATION_COUNT and DS_MAX_ALLOCATION_SIZE are both positive.

  • DS_MAX_ALLOCATION_SIZE is a whole multiple of DS_ALIGNMENT.

  • DS_MAX_ALLOCATION_SIZE is small enough that the internal align-up arithmetic cannot overflow size_t.

Sizing an instance

An instance costs approximately:

DS_BUFFER_MEMORY_SIZE  +  DS_MAX_ALLOCATION_COUNT * sizeof(ds_allocator_t)

bytes (plus a small fixed header and any padding). sizeof(ds_allocator_t) is two size_t fields and an enum, so on a 32-bit target each record is on the order of a dozen bytes. Two forces pull in opposite directions:

  • Raising DS_MAX_ALLOCATION_COUNT lets you hold more concurrent blocks but grows every instance, even ones that never use all the slots.

  • Lowering DS_ALIGNMENT reduces the bytes lost to per-block rounding but may be too weak for types with strict alignment needs.

Because the whole footprint is compile-time constant, you can size it against a concrete budget and be confident it will not grow at runtime.