2024-06-25
最后编辑于:2024-09-15
constexpr size_t DEFAULT_ALLOCATION_SIZE = 64;
struct AllocatorNode {
AllocatorNode* next;
};
struct AllocatorBlock {
size_t nodeSize;
size_t capacity;
AllocatorNode* free;
AllocatorBlock* next;
};
AllocatorBlock* allocatorGetBlock(AllocatorBlock* allocator, size_t nodeSize, size_t capacity = DEFAULT_ALLOCATION_SIZE) {
if (!capacity) { capacity = 1; }
unsigned char* blockPtr = new unsigned char[sizeof(AllocatorBlock) + capacity * (sizeof(AllocatorNode) + nodeSize)];
AllocatorBlock* newBlock = reinterpret_cast<AllocatorBlock*>(blockPtr);
newBlock->nodeSize = nodeSize;
newBlock->capacity = capacity;
newBlock->free = nullptr;
newBlock->next = nullptr;
if (!allocator) { allocator = newBlock; }
else {
newBlock->next = allocator->next;
allocator->next = newBlock;
}
unsigned char* nodePtr = blockPtr + sizeof(AllocatorBlock);
AllocatorNode* firstNewNode = reinterpret_cast<AllocatorNode*>(nodePtr);
for (size_t i = 0; i < capacity - 1; ++i) {
AllocatorNode* newNode = reinterpret_cast<AllocatorNode*>(nodePtr);
newNode->next = reinterpret_cast<AllocatorNode*>(nodePtr + sizeof(AllocatorNode) + nodeSize);
nodePtr += sizeof(AllocatorNode) + nodeSize;
}
{
AllocatorNode* newNode = reinterpret_cast<AllocatorNode*>(nodePtr);
newNode->next = nullptr;
}
allocator->free = firstNewNode;
return allocator;
}
AllocatorBlock* allocatorInitialize(size_t nodeSize, size_t capacity = DEFAULT_ALLOCATION_SIZE) {
return allocatorGetBlock(nullptr, nodeSize, capacity);
}
void allocatorUninitialize(AllocatorBlock* allocator) {
while (allocator) {
AllocatorBlock* next = allocator->next;
delete [] reinterpret_cast<unsigned char*>(allocator);
allocator = next;
}
}
void* allocatorGet(AllocatorBlock* allocator) {
if (!allocator) { return nullptr; }
if (!allocator->free) {
size_t newCapacity = (allocator->capacity + 1) >> 1;
allocator = allocatorGetBlock(allocator, allocator->nodeSize, newCapacity);
allocator->capacity += newCapacity;
}
AllocatorNode* freeNode = allocator->free;
void* dataPtr = reinterpret_cast<unsigned char*>(freeNode) + sizeof(AllocatorNode);
allocator->free = freeNode->next;
freeNode->next = nullptr;
return dataPtr;
}
template <typename T>
class Allocator {
public:
Allocator(size_t capacity = DEFAULT_ALLOCATION_SIZE) {
Reserve(capacity);
}
~Allocator() {
allocatorUninitialize(allocator);
}
void Reserve(size_t capacity = DEFAULT_ALLOCATION_SIZE) {
if (!allocator) { allocator = allocatorInitialize(sizeof(T), capacity); }
}
T* allocate() {
if (!allocator) { Reserve(); }
T* object = reinterpret_cast<T*>(allocatorGet(allocator));
return new(object) T();
}
void free(const T* object) {
if (!object) { return; }
object->~T();
allocatorFree(allocator, object);
}
void Reset() {
allocatorUninitialize(allocator);
allocator = nullptr;
}
private:
Allocator(const Allocator<T>& rhs);
Allocator<T>& operator = (const Allocator<T>& rhs);
AllocatorBlock* allocator;
};
void allocatorFree(AllocatorBlock* allocator, void* ptr) {
if (!allocator || !ptr) { return; }
unsigned char* dataPtr = reinterpret_cast<unsigned char*>(ptr);
AllocatorNode* freeNode = reinterpret_cast<AllocatorNode*>(dataPtr - sizeof(AllocatorNode));
freeNode->next = allocator->free;
allocator->free = freeNode;
}