2026-03-05 20:24:47 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
2026-03-16 17:33:46 +01:00
|
|
|
#include <memory>
|
2026-03-16 06:37:51 +01:00
|
|
|
#include <pd/common.hpp>
|
2026-03-05 20:24:47 +01:00
|
|
|
namespace PD {
|
|
|
|
|
template <typename T, typename Alloc = std::allocator<T>>
|
|
|
|
|
class Pool {
|
|
|
|
|
public:
|
2026-03-16 15:19:12 +01:00
|
|
|
using value_type = T;
|
|
|
|
|
using iterator = T*;
|
2026-03-19 22:06:58 +01:00
|
|
|
using const_iterator = const T*;
|
2026-03-16 15:19:12 +01:00
|
|
|
|
2026-03-05 20:24:47 +01:00
|
|
|
Pool() = default;
|
2026-03-16 15:19:12 +01:00
|
|
|
~Pool() {
|
|
|
|
|
if (pData) {
|
|
|
|
|
pAlloc.deallocate(pData, pCap);
|
|
|
|
|
pData = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-05 20:24:47 +01:00
|
|
|
|
|
|
|
|
static Pool* Create(size_t size) { return new Pool(size); }
|
|
|
|
|
|
|
|
|
|
void Init(size_t size) {
|
|
|
|
|
pPos = 0;
|
|
|
|
|
pCap = size;
|
2026-03-16 15:19:12 +01:00
|
|
|
pData = pAlloc.allocate(size);
|
2026-03-16 17:33:46 +01:00
|
|
|
for (size_t i = 0; i < pCap; i++) {
|
|
|
|
|
std::allocator_traits<Alloc>::construct(pAlloc, &pData[i]);
|
|
|
|
|
}
|
|
|
|
|
PDLOG("Pool::Init({})", size);
|
2026-03-05 20:24:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pool(const Pool&) = delete;
|
|
|
|
|
Pool(Pool&&) = delete;
|
|
|
|
|
Pool& operator=(const Pool&) = delete;
|
|
|
|
|
Pool& operator=(Pool&&) = delete;
|
|
|
|
|
|
|
|
|
|
T* Allocate(size_t num = 1) {
|
2026-03-19 22:06:58 +01:00
|
|
|
ExpandIf(num);
|
2026-03-16 15:19:12 +01:00
|
|
|
T* ret = &pData[pPos];
|
2026-03-05 20:24:47 +01:00
|
|
|
pPos += num;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 22:06:58 +01:00
|
|
|
void Push(const T& elem) {
|
|
|
|
|
T* e = Allocate(1);
|
|
|
|
|
*e = elem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExpandIf(size_t req) {
|
|
|
|
|
if ((pPos + req) <= pCap) return;
|
|
|
|
|
size_t ncap = std::max(pCap * 2, pPos + req);
|
|
|
|
|
T* nu = pAlloc.allocate(ncap);
|
|
|
|
|
if (pData) {
|
|
|
|
|
for (size_t i = 0; i < pPos; i++) {
|
|
|
|
|
std::allocator_traits<Alloc>::construct(
|
|
|
|
|
pAlloc, &nu[i], std::move_if_noexcept(pData[i]));
|
|
|
|
|
}
|
|
|
|
|
pAlloc.deallocate(pData, pCap);
|
2026-03-05 20:24:47 +01:00
|
|
|
}
|
2026-03-19 22:06:58 +01:00
|
|
|
for (size_t i = pPos; i < ncap; i++) {
|
|
|
|
|
std::allocator_traits<Alloc>::construct(pAlloc, &nu[i]);
|
|
|
|
|
}
|
|
|
|
|
PDLOG("Pool::ExpandIf({}): {} -> {}", req, pCap, ncap);
|
|
|
|
|
pData = nu;
|
|
|
|
|
pCap = ncap;
|
2026-03-05 20:24:47 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-16 17:33:46 +01:00
|
|
|
void Reset() {
|
|
|
|
|
for (size_t i = 0; i < pCap; i++) {
|
|
|
|
|
std::allocator_traits<Alloc>::destroy(pAlloc, &pData[i]);
|
|
|
|
|
}
|
|
|
|
|
pPos = 0;
|
|
|
|
|
for (size_t i = 0; i < pCap; i++) {
|
|
|
|
|
std::allocator_traits<Alloc>::construct(pAlloc, &pData[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-05 20:24:47 +01:00
|
|
|
|
2026-03-16 15:19:12 +01:00
|
|
|
size_t size() const { return pPos; }
|
|
|
|
|
size_t capacity() const { return pCap; }
|
|
|
|
|
T& at(size_t idx) { return pData[idx]; }
|
|
|
|
|
const T& at(size_t idx) const { return pData[idx]; }
|
2026-03-19 22:06:58 +01:00
|
|
|
iterator begin() { return pData; }
|
|
|
|
|
iterator end() { return pData + pPos; }
|
|
|
|
|
const_iterator begin() const { return pData; }
|
|
|
|
|
const_iterator end() const { return pData + pPos; }
|
2026-03-16 15:19:12 +01:00
|
|
|
|
|
|
|
|
T& operator[](size_t idx) { return at(idx); }
|
|
|
|
|
const T& operator[](size_t idx) const { return at(idx); }
|
|
|
|
|
|
2026-03-05 20:24:47 +01:00
|
|
|
private:
|
2026-03-16 15:19:12 +01:00
|
|
|
Pool(size_t size) : pCap(size), pPos(0) { pData = pAlloc.allocate(size); }
|
2026-03-05 20:24:47 +01:00
|
|
|
size_t pCap = 0;
|
|
|
|
|
size_t pPos = 0;
|
2026-03-16 15:19:12 +01:00
|
|
|
Alloc pAlloc;
|
|
|
|
|
T* pData = nullptr;
|
2026-03-05 20:24:47 +01:00
|
|
|
};
|
|
|
|
|
} // namespace PD
|