pbr-cpp-memory-pool 1.2.0
Fixed-block-size O(1) memory pool — C++17 with an ANSI C public surface
Loading...
Searching...
No Matches
memory_pool.h
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: MIT
3 * Copyright (c) 2026 Daniel Polo
4 */
5
6#ifndef IT_D4NP_MEMORYPOOL_MEMORY_POOL_H_
7#define IT_D4NP_MEMORYPOOL_MEMORY_POOL_H_
8
25#include <stddef.h>
26
27/*
28 * Diagnostics gate (ADR-0019 §1). A single macro controls the entire
29 * free-list diagnostic surface: the C accessors below and the C++
30 * `free_list_iterator.hpp` iterator. The default is build-type driven so
31 * the surface is available in debug builds and compiled out of release
32 * builds; an explicit definition (e.g. the CMake option
33 * PBR_MEMORY_POOL_ENABLE_DIAGNOSTICS, which defines it to 1 PUBLIC-ly on
34 * the library target) always wins. Walking the free list is O(free_count)
35 * and has no place on the allocation hot path — hence "disabled in release
36 * unless explicitly enabled" (ROADMAP 3.4).
37 */
38/* This is a preprocessor gate (it drives `#if` below and in the C++
39 * iterator header), so it must be a macro, not a constexpr constant — hence
40 * the cppcoreguidelines-macro-usage suppression around the definitions. */
41/* NOLINTBEGIN(cppcoreguidelines-macro-usage) */
42#ifndef PBR_MEMORY_POOL_DIAGNOSTICS
43#ifdef NDEBUG
44#define PBR_MEMORY_POOL_DIAGNOSTICS 0
45#else
46#define PBR_MEMORY_POOL_DIAGNOSTICS 1
47#endif
48#endif
49/* NOLINTEND(cppcoreguidelines-macro-usage) */
50
51/*
52 * Thread-safety mode (ADR-0020 §2). Selects how the implementation
53 * synchronizes the free-list head: NONE (no synchronization — the
54 * single-thread fast path, spec §2.4), MUTEX (a std::mutex), or LOCKFREE
55 * (an ABA-tagged Treiber-stack CAS). Bound at COMPILE TIME (a policy
56 * selected once, not a per-call branch) so the single-thread build pays
57 * nothing. Selected library-wide at build time via the
58 * PBR_MEMORY_POOL_THREAD_SAFETY macro (CMake option); the default is NONE.
59 * These are preprocessor constants (they drive `#if` selection in
60 * memory_pool.cpp), hence the cppcoreguidelines-macro-usage suppression.
61 */
62/* NOLINTBEGIN(cppcoreguidelines-macro-usage) */
63#define PBR_MEMORY_POOL_THREAD_SAFETY_NONE 0
64#define PBR_MEMORY_POOL_THREAD_SAFETY_MUTEX 1
65#define PBR_MEMORY_POOL_THREAD_SAFETY_LOCKFREE 2
66#ifndef PBR_MEMORY_POOL_THREAD_SAFETY
67#define PBR_MEMORY_POOL_THREAD_SAFETY PBR_MEMORY_POOL_THREAD_SAFETY_NONE
68#endif
69/* NOLINTEND(cppcoreguidelines-macro-usage) */
70
71/*
72 * Opt-in debug-hardening gate (ADR-0043). When 1, the intrusive free list
73 * gains freed-block poisoning, a per-slot guard word (overflow + double-free
74 * detection), and next-pointer safe-linking; see pool_hardening.hpp. OFF by
75 * default — a release build is byte-for-byte unchanged. Set library-wide at
76 * build time via the PBR_MEMORY_POOL_HARDENING CMake option (defined PUBLIC,
77 * because a hardened build changes the on-disk free-list layout, so the
78 * library and every consumer must agree). Preprocessor gate → a macro, not a
79 * constexpr constant; hence the cppcoreguidelines-macro-usage suppression.
80 */
81/* NOLINTBEGIN(cppcoreguidelines-macro-usage) */
82#ifndef PBR_MEMORY_POOL_HARDENING
83#define PBR_MEMORY_POOL_HARDENING 0
84#endif
85/* NOLINTEND(cppcoreguidelines-macro-usage) */
86
87#ifdef __cplusplus
88extern "C" {
89#endif
90
92/* The struct tag is snake_case to match the C convention for forward-
93 * declared opaque types; the .clang-tidy StructCase rule (CamelCase) is
94 * the right default for new C++ types, suppressed here for the C-interop
95 * boundary per the same rationale recorded at the definition site in
96 * memory_pool.cpp. */
97/* NOLINTNEXTLINE(readability-identifier-naming) */
98typedef struct memory_pool memory_pool_t;
99
126memory_pool_t* memory_pool_create(size_t block_size, size_t block_count);
127
150memory_pool_t* memory_pool_create_dynamic(size_t block_size, size_t block_count, size_t growth_factor);
151
165
190void memory_pool_free(memory_pool_t* pool, void* block);
191
205
227
242
257
258#if PBR_MEMORY_POOL_DIAGNOSTICS
259
274
288const void* memory_pool_debug_free_list_next(const memory_pool_t* pool, const void* current);
289
300
301#endif /* PBR_MEMORY_POOL_DIAGNOSTICS */
302
303#ifdef __cplusplus
304}
305#endif
306
307#endif
void * memory_pool_alloc(memory_pool_t *pool)
Allocate one block from pool in O(1).
struct memory_pool memory_pool_t
Opaque handle to a memory pool instance.
Definition memory_pool.h:98
void memory_pool_destroy(memory_pool_t *pool)
Destroy pool and release every byte of pre-allocated backing storage back to the operating system,...
size_t memory_pool_debug_free_count(const memory_pool_t *pool)
Diagnostics — count the free slots currently in pool's free list by walking it in O(free_count) (ADR-...
size_t memory_pool_metadata_bytes(const memory_pool_t *pool)
Report the per-pool metadata overhead in bytes (spec section 3.2 / ADR-0015).
memory_pool_t * memory_pool_create(size_t block_size, size_t block_count)
Create a memory pool able to vend block_count blocks of block_size bytes each.
size_t memory_pool_growths(const memory_pool_t *pool)
Report how many times pool has grown — i.e.
const void * memory_pool_debug_free_list_head(const memory_pool_t *pool)
Diagnostics — return the head of pool's implicit free list (ADR-0019 §2).
size_t memory_pool_block_size(const memory_pool_t *pool)
Report the configured per-block size of pool in bytes (ADR-0018 §3).
memory_pool_t * memory_pool_create_dynamic(size_t block_size, size_t block_count, size_t growth_factor)
Create a memory pool in dynamic-growth mode (spec section 2.2): when exhausted it acquires a new cont...
const void * memory_pool_debug_free_list_next(const memory_pool_t *pool, const void *current)
Diagnostics — given a free slot current obtained from memory_pool_debug_free_list_head or a previous ...
void memory_pool_free(memory_pool_t *pool, void *block)
Return a previously allocated block to pool in O(1).