Common System 0.2.0
Common interfaces and patterns for system integration
Loading...
Searching...
No Matches
utils.cppm
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
17module;
18
19// Standard library imports needed before module declaration
20#include <array>
21#include <cstddef>
22#include <functional>
23#include <memory>
24#include <mutex>
25#include <new>
26#include <optional>
27#include <stack>
28#include <utility>
29#include <vector>
30
31// Feature detection for source_location
32#if __has_include(<source_location>)
33 #include <source_location>
34 #define KCENON_MODULE_HAS_SOURCE_LOCATION 1
35#else
36 #define KCENON_MODULE_HAS_SOURCE_LOCATION 0
37#endif
38
39export module kcenon.common:utils;
40
41export namespace kcenon::common {
42
43// ============================================================================
44// Source Location
45// ============================================================================
46
47#if KCENON_MODULE_HAS_SOURCE_LOCATION
48using source_location = std::source_location;
49#else
55public:
56 constexpr source_location(
57 const char* file = __builtin_FILE(),
58 const char* function = __builtin_FUNCTION(),
59 int line = __builtin_LINE()
60 ) noexcept
61 : file_(file), function_(function), line_(line), column_(0) {}
62
63 constexpr const char* file_name() const noexcept { return file_; }
64 constexpr const char* function_name() const noexcept { return function_; }
65 constexpr int line() const noexcept { return line_; }
66 constexpr int column() const noexcept { return column_; }
67
68 static constexpr source_location current(
69 const char* file = __builtin_FILE(),
70 const char* function = __builtin_FUNCTION(),
71 int line = __builtin_LINE()
72 ) noexcept {
73 return source_location(file, function, line);
74 }
75
76private:
77 const char* file_;
78 const char* function_;
79 int line_;
80 int column_;
81};
82#endif
83
84} // namespace kcenon::common
85
86export namespace kcenon::common::utils {
87
88// ============================================================================
89// Circular Buffer
90// ============================================================================
91
99template<typename T, std::size_t Capacity>
101 static_assert(Capacity > 0, "CircularBuffer capacity must be greater than zero");
102
103public:
104 CircularBuffer() = default;
105
112 bool push(const T& value, bool overwrite = false) {
113 std::lock_guard<std::mutex> lock(mutex_);
114 if (is_full_locked() && !overwrite) {
115 return false;
116 }
117 if (is_full_locked()) {
118 pop_locked();
119 }
120 buffer_[tail_] = value;
121 advance(tail_);
122 ++size_;
123 return true;
124 }
125
126 bool push(T&& value, bool overwrite = false) {
127 std::lock_guard<std::mutex> lock(mutex_);
128 if (is_full_locked() && !overwrite) {
129 return false;
130 }
131 if (is_full_locked()) {
132 pop_locked();
133 }
134 buffer_[tail_] = std::move(value);
135 advance(tail_);
136 ++size_;
137 return true;
138 }
139
144 [[nodiscard]] std::optional<T> pop() {
145 std::lock_guard<std::mutex> lock(mutex_);
146 return pop_locked();
147 }
148
149 [[nodiscard]] bool empty() const {
150 std::lock_guard<std::mutex> lock(mutex_);
151 return size_ == 0;
152 }
153
154 [[nodiscard]] bool full() const {
155 std::lock_guard<std::mutex> lock(mutex_);
156 return size_ == Capacity;
157 }
158
159 [[nodiscard]] std::size_t size() const {
160 std::lock_guard<std::mutex> lock(mutex_);
161 return size_;
162 }
163
164 [[nodiscard]] constexpr std::size_t capacity() const {
165 return Capacity;
166 }
167
168private:
169 void advance(std::size_t& index) noexcept {
170 index = (index + 1) % Capacity;
171 }
172
173 bool is_full_locked() const noexcept {
174 return size_ == Capacity;
175 }
176
177 std::optional<T> pop_locked() {
178 if (size_ == 0) {
179 return std::nullopt;
180 }
181 auto value = std::move(buffer_[head_]);
182 advance(head_);
183 --size_;
184 return value;
185 }
186
187 mutable std::mutex mutex_;
188 std::array<T, Capacity> buffer_{};
189 std::size_t head_{0};
190 std::size_t tail_{0};
191 std::size_t size_{0};
192};
193
194// ============================================================================
195// Object Pool
196// ============================================================================
197
198namespace detail {
199template<typename T>
200struct RawDelete {
201 void operator()(T* ptr) const noexcept {
202 ::operator delete(static_cast<void*>(ptr));
203 }
204};
205} // namespace detail
206
217template<typename T>
219public:
220 using value_type = T;
221
222 explicit ObjectPool(std::size_t growth = 32)
223 : growth_(growth == 0 ? 1 : growth) {}
224
231 template<typename... Args>
232 std::unique_ptr<T, std::function<void(T*)>> acquire(bool* reused, Args&&... args) {
233 T* raw = nullptr;
234 bool reused_local = false;
235 {
236 std::lock_guard<std::mutex> lock(mutex_);
237 if (free_list_.empty()) {
239 } else {
240 reused_local = true;
241 }
242
243 raw = free_list_.top();
244 free_list_.pop();
245 }
246
247 if (reused) {
248 *reused = reused_local;
249 }
250
251 new (raw) T(std::forward<Args>(args)...);
252 return std::unique_ptr<T, std::function<void(T*)>>(raw, [this](T* ptr) {
253 this->release(ptr);
254 });
255 }
256
257 template<typename... Args>
258 std::unique_ptr<T, std::function<void(T*)>> acquire(Args&&... args) {
259 return acquire(static_cast<bool*>(nullptr), std::forward<Args>(args)...);
260 }
261
265 void release(T* ptr) noexcept {
266 if (!ptr) {
267 return;
268 }
269
270 ptr->~T();
271 std::lock_guard<std::mutex> lock(mutex_);
272 free_list_.push(ptr);
273 }
274
278 void reserve(std::size_t count) {
279 if (count == 0) {
280 return;
281 }
282 std::lock_guard<std::mutex> lock(mutex_);
284 }
285
289 void clear() {
290 std::lock_guard<std::mutex> lock(mutex_);
291 free_list_ = std::stack<T*>();
292 storage_.clear();
293 }
294
295 [[nodiscard]] std::size_t available() const {
296 std::lock_guard<std::mutex> lock(mutex_);
297 return free_list_.size();
298 }
299
300private:
301 using RawPtr = std::unique_ptr<T, detail::RawDelete<T>>;
302
303 void allocate_block_unlocked(std::size_t count) {
304 for (std::size_t i = 0; i < count; ++i) {
305 RawPtr block(static_cast<T*>(::operator new(sizeof(T))));
306 free_list_.push(block.get());
307 storage_.push_back(std::move(block));
308 }
309 }
310
311 std::size_t growth_;
312 mutable std::mutex mutex_;
313 std::stack<T*> free_list_;
314 std::vector<RawPtr> storage_;
315};
316
317} // namespace kcenon::common::utils
Thread-safe fixed-size circular buffer.
Definition utils.cppm:100
constexpr std::size_t capacity() const
Definition utils.cppm:164
bool push(T &&value, bool overwrite=false)
Definition utils.cppm:126
bool push(const T &value, bool overwrite=false)
Push a value to the buffer.
Definition utils.cppm:112
std::optional< T > pop()
Pop a value from the buffer.
Definition utils.cppm:144
void advance(std::size_t &index) noexcept
Thread-safe object pool that reuses raw storage for expensive objects.
Definition utils.cppm:218
void release(T *ptr) noexcept
Return raw storage to the pool (destructor already run).
void allocate_block_unlocked(std::size_t count)
std::vector< RawPtr > storage_
std::unique_ptr< T, std::function< void(T *)> > acquire(bool *reused, Args &&... args)
Acquire an object constructed with the provided arguments.
Definition utils.cppm:232
pointer_type acquire(bool *reused, Args &&... args)
Acquire an object constructed with the provided arguments.
Definition object_pool.h:82
ObjectPool(std::size_t growth=32)
Definition utils.cppm:222
void reserve(std::size_t count)
Add count additional blocks to the pool.
Definition utils.cppm:278
std::unique_ptr< T, detail::RawDelete< T > > RawPtr
std::unique_ptr< T, std::function< void(T *)> > acquire(Args &&... args)
Definition utils.cppm:258
std::size_t available() const
Definition utils.cppm:295
void clear()
Destroy all cached instances and release memory.
Definition utils.cppm:289
Core interfaces.
Definition adapter.h:21
C++17-compatible source_location implementation using compiler builtins.
Definition utils.cppm:54
constexpr source_location(const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE()) noexcept
Definition utils.cppm:56
static constexpr source_location current(const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE()) noexcept
Definition utils.cppm:68
constexpr int line() const noexcept
constexpr int column() const noexcept
Definition utils.cppm:66
constexpr const char * file_name() const noexcept
Definition utils.cppm:63
constexpr const char * function_name() const noexcept
Definition utils.cppm:64
void operator()(T *ptr) const noexcept
Definition utils.cppm:201