|
| 1 | +# ObjectPool |
| 2 | +**A Modern C++23 Object Pool Implementation (Header-only)** |
| 3 | + |
| 4 | +--- |
| 5 | + |
| 6 | +## Overview |
| 7 | + |
| 8 | +ObjectPool is a lightweight, header‑only implementation of the **Object Pool** pattern. |
| 9 | +It pre-allocates a fixed number of objects and lets you mark slots as *in use* or *free*, |
| 10 | +iterate only over the *used* ones, and (re)construct elements in place when needed. |
| 11 | +It follows modern C++ practices and adheres to my [C++23 Code Style Guide](https://gist.github.com/AbsintheScripting/4f2be73c91fc49fc6bc2cefbb2a52895). |
| 12 | + |
| 13 | +This implementation focuses on simplicity, performance, and clarity. |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Features |
| 18 | + |
| 19 | +- 🧠 **Templated Design** — Works with any default-constructible type |
| 20 | +- 🚀 **Smart & Fast Iterators** — STL conform forward-iterator skips objects not in use |
| 21 | +- 🧱 **Header-only Library** — Just include `CObjectPool.hpp` |
| 22 | +- 🧩 **`noexcept` Correctness** — Explicit exception guarantees throughout |
| 23 | +- ⚙️ **Deterministic Allocation Pattern** — Fixed preallocation, no dynamic growth at runtime |
| 24 | +- ✅ **Unit Tested** — Includes GoogleTest-based tests in `tests/ObjectPool.cpp` |
| 25 | + |
| 26 | +> 🧵 **Note:** This implementation is **not thread-safe**. |
| 27 | +> If you need concurrency, wrap it with synchronization primitives externally. |
| 28 | +
|
| 29 | +--- |
| 30 | + |
| 31 | +## Example Usage |
| 32 | + |
| 33 | +```cpp |
| 34 | +#include "CObjectPool.hpp" |
| 35 | +#include <print> |
| 36 | + |
| 37 | +using namespace ObjectPool; |
| 38 | + |
| 39 | +struct CMyObject |
| 40 | +{ |
| 41 | + int32_t value = 0; |
| 42 | +}; |
| 43 | + |
| 44 | +int main() |
| 45 | +{ |
| 46 | + // Create a pool with 10 pre-allocated objects |
| 47 | + CObjectPool<CMyObject> pool(10); |
| 48 | + |
| 49 | + // Acquire an object from the pool |
| 50 | + size_t foundIdx; |
| 51 | + auto result = pool.UseNext(foundIdx); |
| 52 | + if (!result.has_value()) |
| 53 | + { |
| 54 | + std::println("ERROR: Object pool full: {}", ToString(result.error())); |
| 55 | + return 1; |
| 56 | + } |
| 57 | + // Modify the object |
| 58 | + auto pObject = result.value(); |
| 59 | + pObject->value = 42; |
| 60 | + |
| 61 | + // Iterate over all used objects (in this case only pool[0]) |
| 62 | + for (const auto& object : pool) |
| 63 | + { |
| 64 | + std::println("Object value: {}", object.value); |
| 65 | + } |
| 66 | + |
| 67 | + // UnUse the object |
| 68 | + auto result2 = pool.UnUse(foundIdx); |
| 69 | + if (!result2.has_value()) |
| 70 | + { |
| 71 | + // either EPoolError::OUT_OF_RANGE or EPoolError::ALREADY_UNUSED |
| 72 | + std::println("ERROR: Could not unuse the object: {}", ToString(result2.error())); |
| 73 | + return 1; |
| 74 | + } |
| 75 | + |
| 76 | + return 0; |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +--- |
| 81 | + |
| 82 | +## Tests & Behavior Reference |
| 83 | + |
| 84 | +The repository includes a comprehensive GoogleTest suite covering: |
| 85 | +- Construction (default / with args), bounds & overflow |
| 86 | +- `Use`, `UseNext`, `UseNextReplace` semantics and gap filling |
| 87 | +- `UnUse` / `Replace` (default and with args) behavior |
| 88 | +- Safe access via `Get`, direct access via `operator[]` |
| 89 | +- Iterator correctness: skipping gaps, `++it`/post‑increment, `->`/`*`, equality/inequality |
| 90 | +- Compatibility with `<algorithm>` & `<ranges>` (`find_if`, `transform`, `for_each`, `all_of`/`any_of`/`none_of`, views + filters) |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +## Building and Testing |
| 95 | + |
| 96 | +The project uses **CMake** and **GoogleTest**. |
| 97 | + |
| 98 | +```bash |
| 99 | +# Clone repository |
| 100 | +git clone https://github.com/AbsintheScripting/object-pool.git |
| 101 | +cd object-pool |
| 102 | + |
| 103 | +# Configure and build |
| 104 | +# Make sure you use at least g++-14, if not add -DCMAKE_CXX_COMPILER=g++-14 |
| 105 | +cmake -B build -DCMAKE_BUILD_TYPE=Debug |
| 106 | +cmake --build build |
| 107 | + |
| 108 | +# Run tests |
| 109 | +cd build && ctest --output-on-failure |
| 110 | +``` |
| 111 | + |
| 112 | +### Dependencies |
| 113 | +- **CMake ≥ 3.20** |
| 114 | +- **C++23-compatible compiler** (MSVC v145+, GCC 14+, Clang 16+) |
| 115 | +- **GoogleTest 1.17.0** (automatically fetched via `FetchContent`) |
| 116 | + |
| 117 | +--- |
| 118 | + |
| 119 | +## File Structure |
| 120 | + |
| 121 | +``` |
| 122 | +CObjectPool/ |
| 123 | +│ |
| 124 | +├── include/ |
| 125 | +│ └── CObjectPool.hpp # Header-only Object Pool implementation |
| 126 | +│ |
| 127 | +├── tests/ |
| 128 | +│ └── ObjectPool.cpp # GoogleTest-based tests |
| 129 | +│ |
| 130 | +└── CMakeLists.txt # Build + test configuration |
| 131 | +``` |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +## Code Style |
| 136 | + |
| 137 | +This repository follows the [My C++23 Code Style Guide](https://gist.github.com/AbsintheScripting/4f2be73c91fc49fc6bc2cefbb2a52895), |
| 138 | +which enforces: |
| 139 | + |
| 140 | +- Explicit ownership (`unique_ptr`, RAII) |
| 141 | +- Fixed-width integer types (`<cstdint>`) |
| 142 | +- Consistent naming (`C` for classes, `b` for booleans, etc.) |
| 143 | +- Const- and `noexcept`-correct design |
| 144 | +- Clean header separation and modern includes |
| 145 | +- Readability over cleverness |
| 146 | + |
| 147 | +> All contributions must conform to this style guide. |
| 148 | +
|
| 149 | +--- |
| 150 | + |
| 151 | +## License |
| 152 | + |
| 153 | +This project is released under the **MIT License** — see [`LICENSE`](LICENSE). |
| 154 | + |
| 155 | +--- |
| 156 | + |
| 157 | +## Author |
| 158 | + |
| 159 | +**Migos (Daniel Contu)** |
| 160 | +Tech Lead / C++ Developer |
| 161 | +[GitHub Profile](https://github.com/AbsintheScripting) |
| 162 | +[Code Style Gist](https://gist.github.com/AbsintheScripting/4f2be73c91fc49fc6bc2cefbb2a52895) |
0 commit comments