libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
object_pool.hpp
1#pragma once
2
3#include <cstddef>
4#include <cstdint>
5#include <limits>
6#include <new>
7#include <type_traits>
8#include <utility>
9
10#include "libxr_def.hpp"
11#include "queue.hpp"
12
13namespace LibXR
14{
31template <typename QueueType>
33 requires(QueueType queue, const typename QueueType::ValueType& index_const,
34 typename QueueType::ValueType& index_mut) {
35 typename QueueType::ValueType;
36 { queue.Push(index_const) } -> std::same_as<ErrorCode>;
37 { queue.Pop(index_mut) } -> std::same_as<ErrorCode>;
38 { queue.Size() } -> std::convertible_to<size_t>;
39 };
40
57template <typename Data, PoolIndexQueue FreeQueue>
59{
60 public:
61 using ValueType = Data;
62 using QueueType = FreeQueue;
63 using IndexType = typename FreeQueue::ValueType;
64
66 static_assert(std::is_integral_v<IndexType>,
67 "BasicObjectPool requires an integral index queue");
69 static_assert(std::is_unsigned_v<IndexType>,
70 "BasicObjectPool requires an unsigned index queue");
71
81 class Handle
82 {
83 public:
88 Handle() = default;
89
96 Handle(BasicObjectPool* pool, IndexType index) : pool_(pool), index_(index) {}
97
99 Handle(const Handle&) = delete;
101 Handle& operator=(const Handle&) = delete;
102
108 Handle(Handle&& other) noexcept
109 : pool_(std::exchange(other.pool_, nullptr)),
110 index_(std::exchange(other.index_, IndexType{}))
111 {
112 }
113
120 Handle& operator=(Handle&& other) noexcept
121 {
122 if (this == &other)
123 {
124 return *this;
125 }
126
127 Reset();
128 pool_ = std::exchange(other.pool_, nullptr);
129 index_ = std::exchange(other.index_, IndexType{});
130 return *this;
131 }
132
137 ~Handle() { Reset(); }
138
145 [[nodiscard]] bool Valid() const { return pool_ != nullptr; }
146
152 [[nodiscard]] Data& Get()
153 {
154 ASSERT(pool_ != nullptr);
155 return pool_->slots_[index_];
156 }
157
163 [[nodiscard]] const Data& Get() const
164 {
165 ASSERT(pool_ != nullptr);
166 return pool_->slots_[index_];
167 }
168
174 [[nodiscard]] Data* operator->() { return &Get(); }
175
181 [[nodiscard]] const Data* operator->() const { return &Get(); }
182
188 [[nodiscard]] Data& operator*() { return Get(); }
189
195 [[nodiscard]] const Data& operator*() const { return Get(); }
196
202 [[nodiscard]] IndexType Index() const
203 {
204 ASSERT(pool_ != nullptr);
205 return index_;
206 }
207
212 void Reset()
213 {
214 if (pool_ == nullptr)
215 {
216 return;
217 }
218
219 const ErrorCode ec = pool_->Release(index_);
220 ASSERT(ec == ErrorCode::OK);
221 pool_ = nullptr;
222 index_ = IndexType{};
223 }
224
225 private:
228 };
229
235 template <typename T = Data>
236 requires std::is_default_constructible_v<T>
237 explicit BasicObjectPool(size_t slot_count) : slot_count_(slot_count)
238 {
239 ASSERT(slot_count_ > 0);
243 }
244
255 BasicObjectPool(size_t slot_count, Data* slots) : slot_count_(slot_count), slots_(slots)
256 {
257 ASSERT(slot_count_ > 0);
258 ASSERT(slots_ != nullptr);
261 }
262
274 template <typename T = Data>
275 requires std::is_default_constructible_v<T>
276 BasicObjectPool(FreeQueue& free_queue, size_t slot_count)
277 : free_queue_(&free_queue), slot_count_(slot_count)
278 {
279 ASSERT(slot_count_ > 0);
280 ASSERT(free_queue.Size() == 0);
283 }
284
300 BasicObjectPool(FreeQueue& free_queue, size_t slot_count, Data* slots)
301 : free_queue_(&free_queue), slot_count_(slot_count), slots_(slots)
302 {
303 ASSERT(slot_count_ > 0);
304 ASSERT(slots_ != nullptr);
305 ASSERT(free_queue.Size() == 0);
307 }
308
314 {
315 ASSERT(EmptySize() == slot_count_);
316
317 if (owns_slots_)
318 {
319 delete[] slots_;
320 }
321
323 {
324 free_queue_->~FreeQueue();
325 }
326 }
327
336
345 [[nodiscard]] ErrorCode Acquire(Handle& handle)
346 {
347 ASSERT(!handle.Valid());
348
349 IndexType index = 0;
350 const ErrorCode ec = free_queue_->Pop(index);
351 if (ec != ErrorCode::OK)
352 {
353 return ec;
354 }
355
356 ASSERT(static_cast<size_t>(index) < slot_count_);
357 handle = Handle(this, index);
358 return ErrorCode::OK;
359 }
360
366 [[nodiscard]] size_t EmptySize() const { return free_queue_->Size(); }
367
373 [[nodiscard]] size_t Size() const { return slot_count_; }
374
387 [[nodiscard]] Data& UnsafeAt(size_t index)
388 {
389 ASSERT(index < slot_count_);
390 return slots_[index];
391 }
392
405 [[nodiscard]] const Data& UnsafeAt(size_t index) const
406 {
407 ASSERT(index < slot_count_);
408 return slots_[index];
409 }
410
411 private:
419 {
420 ASSERT(static_cast<size_t>(index) < slot_count_);
421 return free_queue_->Push(index);
422 }
423
430 void ConstructOwnedQueue(size_t slot_count)
431 {
432 free_queue_ = new (free_queue_storage_) FreeQueue(slot_count);
433 owns_free_queue_ = true;
434 }
435
441 {
442 slots_ = new Data[slot_count_];
443 owns_slots_ = true;
444 }
445
451 {
452 ASSERT(slot_count_ > 0);
453 ASSERT(slot_count_ - 1 <= static_cast<size_t>(std::numeric_limits<IndexType>::max()));
454 for (size_t index = 0; index < slot_count_; ++index)
455 {
456 const ErrorCode ec = free_queue_->Push(static_cast<IndexType>(index));
457 ASSERT(ec == ErrorCode::OK);
458 }
459 }
460
463 alignas(FreeQueue) std::byte free_queue_storage_[sizeof(FreeQueue)] = {};
464 FreeQueue* free_queue_ =
465 nullptr;
466 const size_t slot_count_;
467 Data* slots_ = nullptr;
469 false;
471 false;
472};
473
480template <typename Data, typename IndexType = uint32_t>
482
489template <typename Data, typename IndexType = uint32_t>
491
498template <typename Data, typename IndexType = uint32_t>
500} // namespace LibXR
槽索引必须是整数类型。 Slot indices must use an integral type.
BasicObjectPool * pool_
所属对象池。 Owning object pool.
Handle & operator=(const Handle &)=delete
禁止拷贝赋值。 Non-copy-assignable.
Data & operator*()
解引用当前槽位对象。
Data & Get()
返回当前槽位对象的可写引用。
void Reset()
主动归还当前槽位,并使 handle 失效。
IndexType index_
当前槽位索引。 Current slot index.
Handle & operator=(Handle &&other) noexcept
移动赋值 handle,并转移槽位所有权。
const Data & operator*() const
只读解引用当前槽位对象。
const Data & Get() const
返回当前槽位对象的只读引用。
bool Valid() const
判断当前 handle 是否持有有效槽位。
Handle(BasicObjectPool *pool, IndexType index)
用指定 pool 和槽位索引构造 handle。
Handle(const Handle &)=delete
禁止拷贝构造。 Non-copyable.
Handle()=default
构造一个空 handle。
const Data * operator->() const
以只读指针形式访问当前槽位对象。
Data * operator->()
以指针形式访问当前槽位对象。
IndexType Index() const
返回当前持有的槽位索引。
~Handle()
析构 handle,并自动归还槽位。
Handle(Handle &&other) noexcept
移动构造 handle,并转移槽位所有权。
基于空闲索引队列的 RAII 槽池。
BasicObjectPool(size_t slot_count)
用内部 queue 和内部 slots 构造 pool。
BasicObjectPool(const BasicObjectPool &)=delete
禁止拷贝构造。 Non-copyable.
BasicObjectPool(size_t slot_count, Data *slots)
用内部 queue 和外部 slots 构造 pool。
BasicObjectPool & operator=(BasicObjectPool &&)=delete
禁止移动赋值。 Non-move-assignable.
Data * slots_
槽数组指针。 Pointer to slot storage.
FreeQueue * free_queue_
空闲索引队列指针。 Pointer to the free-index queue.
size_t EmptySize() const
返回当前仍可获取的空闲槽位数。
void AllocateOwnedSlots()
申请并拥有内部槽数组。
bool owns_slots_
是否拥有内部 slots。 Whether this pool owns the slot storage.
void ConstructOwnedQueue(size_t slot_count)
在内部存储区里构造一个自拥有空闲队列。
typename FreeQueue::ValueType IndexType
槽索引类型。 Slot index type.
const size_t slot_count_
槽位总数。 Total slot count.
size_t Size() const
返回对象池总槽位数。
ErrorCode Release(IndexType index)
把指定槽位索引归还到空闲队列。
BasicObjectPool(BasicObjectPool &&)=delete
禁止移动构造。 Non-movable.
const Data & UnsafeAt(size_t index) const
通过槽位索引只读直接访问对象,不参与所有权检查。
BasicObjectPool(FreeQueue &free_queue, size_t slot_count)
用外部 queue 和内部 slots 构造 pool。
ErrorCode Acquire(Handle &handle)
获取一个槽位 handle。
~BasicObjectPool()
析构对象池,并释放其拥有的内部资源。
FreeQueue QueueType
空闲索引队列类型。 Free-index queue type.
Data ValueType
槽内对象类型。 Slot object type.
bool owns_free_queue_
是否拥有内部 queue。 Whether this pool owns the free queue.
BasicObjectPool & operator=(const BasicObjectPool &)=delete
禁止拷贝赋值。 Non-copy-assignable.
BasicObjectPool(FreeQueue &free_queue, size_t slot_count, Data *slots)
用外部 queue 和外部 slots 构造 pool。
std::byte free_queue_storage_[sizeof(FreeQueue)]
内部自拥有 queue 的原地构造存储区。 In-place storage for an internally owned queue.
Data & UnsafeAt(size_t index)
通过槽位索引直接访问对象,不参与所有权检查。
void InitializeFreeQueue()
用 0 .. slot_count - 1 初始化空闲索引队列。
可作为对象池空闲索引队列的类型约束。
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ OK
操作成功 | Operation successful