Allocator

2024-06-25

最后编辑于:2024-09-15

    #Cpp
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;

}