10#include "libxr_def.hpp"
45template <
typename Data>
63 requires std::is_default_constructible_v<Data>
70 template <typename... Args>
71 requires std::is_constructible_v<Data, Args...>
72 explicit
Slot(std::in_place_t, Args&&... args) : data_(std::forward<Args>(args)...)
77 Slot& operator=(
const Slot&) =
delete;
83 std::atomic<uint32_t> references_{0};
113 : pool_(std::exchange(other.pool_,
nullptr)),
114 index_(std::exchange(other.index_,
IndexType{}))
124 pool_ = std::exchange(other.pool_,
nullptr);
125 index_ = std::exchange(other.index_,
IndexType{});
134 [[nodiscard]]
bool Valid()
const {
return pool_ !=
nullptr; }
140 return pool_->slots_[index_].data_;
145 [[nodiscard]]
const Data&
Get()
const
148 return pool_->slots_[index_].data_;
171 ObjectPool* pool = std::exchange(pool_,
nullptr);
175 pool->Release(index);
207 : pool_(other.pool_), index_(other.index_)
209 if (pool_ !=
nullptr)
211 pool_->Retain(index_);
217 : pool_(std::exchange(other.pool_,
nullptr)),
218 index_(std::exchange(other.index_,
IndexType{}))
225 : pool_(std::exchange(writer.pool_,
nullptr)),
226 index_(std::exchange(writer.index_,
IndexType{}))
234 if (pool_ != other.pool_ || index_ != other.index_)
267 [[nodiscard]]
bool Valid()
const {
return pool_ !=
nullptr; }
271 [[nodiscard]]
const Data&
Get()
const
274 return pool_->slots_[index_].data_;
293 ObjectPool* pool = std::exchange(pool_,
nullptr);
297 pool->Release(index);
304 std::swap(pool_, other.pool_);
305 std::swap(index_, other.index_);
316 template <
typename T = Data>
317 requires std::is_default_constructible_v<T>
319 : slots_(new
Slot[slot_count]), slot_count_(slot_count), owns_slots_(true)
321 InitializeFreeStack();
335 : slots_(slots), slot_count_(slot_count), owns_slots_(false)
337 ASSERT(slots_ !=
nullptr);
338 InitializeFreeStack();
370 ASSERT(!handle.
Valid());
371#ifdef LIBXR_DEBUG_BUILD
376 ASSERT(acquiring_.compare_exchange_strong(idle, 1U, std::memory_order_acquire,
377 std::memory_order_relaxed));
384 free_count_.fetch_sub(1U, std::memory_order_relaxed);
385 DEV_ASSERT(slots_[index].references_.load(std::memory_order_relaxed) == 0U);
386 slots_[index].references_.store(1U, std::memory_order_relaxed);
387 handle =
Handle(
this, index);
390#ifdef LIBXR_DEBUG_BUILD
391 acquiring_.store(0U, std::memory_order_release);
404 return free_count_.load(std::memory_order_relaxed);
411 [[nodiscard]]
size_t Size()
const {
return slot_count_; }
423 ASSERT(index < slot_count_);
424 return slots_[index].data_;
435 [[nodiscard]]
const Data&
UnsafeAt(
size_t index)
const
437 ASSERT(index < slot_count_);
438 return slots_[index].data_;
442 static constexpr IndexType EMPTY_INDEX = std::numeric_limits<IndexType>::max();
447 DEV_ASSERT(
static_cast<size_t>(index) < slot_count_);
448 [[maybe_unused]]
const uint32_t previous =
449 slots_[index].references_.fetch_add(1U, std::memory_order_relaxed);
450 DEV_ASSERT(previous > 0U);
451 ASSERT(previous < std::numeric_limits<uint32_t>::max());
456 DEV_ASSERT(
static_cast<size_t>(index) < slot_count_);
459 const uint32_t previous =
460 slots_[index].references_.fetch_sub(1U, std::memory_order_acq_rel);
461 DEV_ASSERT(previous > 0U);
464 free_count_.fetch_add(1U, std::memory_order_relaxed);
469 void InitializeFreeStack()
471 ASSERT(slot_count_ > 0);
472 ASSERT(slot_count_ <
static_cast<size_t>(EMPTY_INDEX));
473 for (
size_t index = 0; index < slot_count_; ++index)
475 slots_[index].next_ =
static_cast<IndexType>(index + 1U);
477 slots_[slot_count_ - 1U].next_ = EMPTY_INDEX;
478 free_head_.store(0U, std::memory_order_relaxed);
479 free_count_.store(
static_cast<uint32_t
>(slot_count_), std::memory_order_relaxed);
486 IndexType head = free_head_.load(std::memory_order_acquire);
490 if (head == EMPTY_INDEX)
494 DEV_ASSERT(
static_cast<size_t>(head) < slot_count_);
498 next = slots_[head].next_;
499 }
while (!free_head_.compare_exchange_weak(head, next, std::memory_order_acquire,
500 std::memory_order_acquire));
509 IndexType head = free_head_.load(std::memory_order_relaxed);
514 slots_[index].next_ = head;
515 }
while (!free_head_.compare_exchange_weak(head, index, std::memory_order_release,
516 std::memory_order_relaxed));
520 const size_t slot_count_;
521 const bool owns_slots_;
522 std::atomic<IndexType> free_head_{EMPTY_INDEX};
523 std::atomic<uint32_t> free_count_{0};
527 std::atomic<uint32_t> acquiring_{0};
只读句柄:共享一个槽位,可以复制。 Read-only handle: shares one slot, copyable.
ConstHandle(ConstHandle &&other) noexcept
转移引用并清空源句柄 / Transfer the reference and empty the source.
~ConstHandle()
释放本引用;最后一个引用归还槽位 / Release; the final reference returns the slot.
ConstHandle & operator=(const ConstHandle &other) noexcept
复制赋值:先保留新引用再释放旧引用 / Copy-assign: retain the new reference before releasing the old one.
bool Valid() const
是否持有引用 / Whether this handle owns a reference.
const Data & Get() const
只读访问负载,句柄必须有效 / Read-only payload access; requires a valid handle.
const Data * operator->() const
返回只读负载指针 / Return a read-only payload pointer.
ConstHandle(const ConstHandle &other) noexcept
复制引用 / Copy the reference.
const Data & operator*() const
只读解引用 / Dereference read-only.
void Reset()
清空句柄并释放引用;空句柄无操作 / Empty and release; no-op on an empty handle.
ConstHandle()=default
构造空句柄 / Construct an empty handle.
ConstHandle & operator=(Handle &&writer) noexcept
接过可写句柄的槽位并释放旧引用 / Take over a writable handle's slot and release the old reference.
ConstHandle & operator=(ConstHandle &&other) noexcept
转移赋值并释放旧引用 / Move-assign and release the old reference.
IndexType Index() const
返回有效句柄的槽索引 / Return the slot index of a valid handle.
ConstHandle(Handle &&writer) noexcept
接过可写句柄的槽位,源句柄变空 / Take over a writable handle's slot; the source becomes empty.
可写句柄:独占一个槽位,只能移动。 Writable handle: exclusive owner of one slot, move-only.
void Reset()
清空句柄并释放槽位;空句柄无操作 / Empty and release; no-op on an empty handle.
Data & operator*()
解引用 / Dereference.
IndexType Index() const
返回有效句柄的槽索引 / Return the slot index of a valid handle.
bool Valid() const
是否持有槽位 / Whether this handle owns a slot.
const Data * operator->() const
返回只读负载指针 / Return a read-only payload pointer.
~Handle()
释放槽位 / Release the slot.
Handle & operator=(const Handle &)=delete
禁止拷贝赋值 / Non-copy-assignable.
Handle(Handle &&other) noexcept
转移槽位并清空源句柄 / Transfer the slot and empty the source.
const Data & Get() const
只读访问负载,句柄必须有效 / Read-only payload access; requires a valid handle.
const Data & operator*() const
只读解引用 / Dereference read-only.
Handle & operator=(Handle &&other) noexcept
转移槽位并释放原有槽位 / Transfer the slot and release the previous one.
Data & Get()
访问负载,句柄必须有效 / Access the payload; requires a valid handle.
Handle()=default
构造空句柄 / Construct an empty handle.
Data * operator->()
返回负载指针 / Return the payload pointer.
Handle(const Handle &)=delete
禁止拷贝构造 / Non-copyable.
槽位:引用计数、空闲链接和常驻负载。 Slot: reference count, free-stack link and resident payload.
Slot()=default
默认构造负载 / Default-construct the payload.
带引用计数的固定槽对象池 / Fixed-slot object pool with reference counting.
size_t Size() const
返回槽位总数 / Return the total number of slots.
const Data & UnsafeAt(size_t index) const
按槽位索引只读访问对象,不检查所有权。 Read-only access by slot index without ownership checks.
ObjectPool(size_t slot_count, Slot *slots)
用外部槽数组构造池 / Construct the pool with caller-provided slots.
ObjectPool(size_t slot_count)
用内部槽数组构造池 / Construct the pool with internal slots.
size_t EmptySize() const
返回空闲槽位数 / Return the number of free slots.
Data ValueType
槽内对象类型 / Slot object type.
Data & UnsafeAt(size_t index)
按槽位索引直接访问对象,不检查所有权。 Access an object by slot index without ownership checks.
~ObjectPool()
析构池;所有句柄必须已释放 / Destroy the pool; all handles must be released.
uint32_t IndexType
槽索引类型 / Slot index type.
ErrorCode Acquire(Handle &handle)
获取一个空闲槽位 / Acquire one free slot.
LibXR 命名空间 / LibXR namespace.
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ OK
操作成功 / Operation successful