#pragma once #include // Atomic operations library for lock-free programming #include // Standard definitions, including size_t #include // Standard integer types #include // Memory management #include // Type traits #include // Input/output stream #include #include #ifdef _WIN32 #include // Windows system calls #else #include // Linux memory mapping #include // Linux system calls #endif namespace hhb { namespace core { // Object pool configuration template struct ObjectPoolConfig { static constexpr size_t DEFAULT_BLOCK_SIZE = 1024 * 1024; // 1MB block size static constexpr size_t DEFAULT_OBJECTS_PER_BLOCK = 1024; // Default objects per block }; // Memory block header structure // alignas(64): Force alignment to 64 bytes, the size of a cache line struct alignas(64) BlockHeader { std::atomic next; // Atomic pointer to next block std::atomic used; // Number of used objects size_t capacity; // Block capacity char data[]; // Flexible array for actual objects }; // Free object node struct FreeNode { std::atomic next; // Atomic pointer to next free node }; // High-performance object pool template class ObjectPool { public: // Constructor: Initialize object pool // objects_per_block: Number of objects per block ObjectPool(size_t objects_per_block = ObjectPoolConfig::DEFAULT_OBJECTS_PER_BLOCK) : objects_per_block_(objects_per_block), // Calculate block size: block header size + object size * object count block_size_(sizeof(BlockHeader) + sizeof(T) * objects_per_block), head_block_(nullptr), free_list_(nullptr) { try { // Pre-allocate first block allocate_block(); } catch (const std::exception& e) { std::cerr << "Exception in ObjectPool constructor: " << e.what() << std::endl; throw; } } // Destructor: Release all blocks ~ObjectPool() { // Release all blocks BlockHeader* block = head_block_; while (block) { BlockHeader* next = block->next; deallocate_block(block); block = next; } } // Disable copy and move ObjectPool(const ObjectPool&) = delete; ObjectPool& operator=(const ObjectPool&) = delete; ObjectPool(ObjectPool&&) = delete; ObjectPool& operator=(ObjectPool&&) = delete; // Allocate object T* allocate() { // Try to get from free list FreeNode* node = free_list_.load(std::memory_order_acquire); while (node) { // Load next node with acquire memory order FreeNode* next = node->next.load(std::memory_order_acquire); // Compare-exchange weak: lock-free CAS operation if (free_list_.compare_exchange_weak(node, next, std::memory_order_acq_rel, std::memory_order_acquire)) { // Reinterpret cast: convert FreeNode* to T* return reinterpret_cast(node); } } // Free list is empty, try to allocate in existing blocks BlockHeader* block = head_block_.load(std::memory_order_acquire); while (block) { size_t used = block->used.load(std::memory_order_acquire); while (used < block->capacity) { if (block->used.compare_exchange_weak( used, used + 1, std::memory_order_acq_rel, std::memory_order_acquire)) { return reinterpret_cast(block->data + sizeof(T) * used); } } block = block->next.load(std::memory_order_acquire); } // All blocks are full, allocate new block and retry on head allocate_block(); BlockHeader* head = head_block_.load(std::memory_order_acquire); while (true) { size_t used = head->used.load(std::memory_order_acquire); if (used >= head->capacity) { allocate_block(); head = head_block_.load(std::memory_order_acquire); continue; } if (head->used.compare_exchange_weak( used, used + 1, std::memory_order_acq_rel, std::memory_order_acquire)) { return reinterpret_cast(head->data + sizeof(T) * used); } } } // Deallocate object void deallocate(T* ptr) { // Convert object to free node FreeNode* node = reinterpret_cast(ptr); // Load free list head with acquire memory order FreeNode* old_head = free_list_.load(std::memory_order_acquire); do { // Set new node's next pointer to old head node->next.store(old_head, std::memory_order_release); // CAS operation: try to set new node as list head } while (!free_list_.compare_exchange_weak(old_head, node, std::memory_order_acq_rel, std::memory_order_acquire)); } // Get number of allocated objects size_t size() const { size_t total = 0; BlockHeader* block = head_block_.load(std::memory_order_acquire); while (block) { total += block->used.load(std::memory_order_acquire); block = block->next.load(std::memory_order_acquire); } return total; } // Iterate all objects and execute callback template void for_each(Func func) { BlockHeader* block = head_block_.load(std::memory_order_acquire); while (block) { size_t used = block->used.load(std::memory_order_acquire); for (size_t i = 0; i < used; ++i) { T* obj = reinterpret_cast(block->data + sizeof(T) * i); func(obj); } block = block->next.load(std::memory_order_acquire); } } // Access object by index T& operator[](size_t index) { size_t current_index = 0; BlockHeader* block = head_block_.load(std::memory_order_acquire); // Reverse traversal since blocks are linked in reverse order std::vector blocks; while (block) { blocks.push_back(block); block = block->next.load(std::memory_order_acquire); } // Traverse in reverse order (oldest first) for (auto it = blocks.rbegin(); it != blocks.rend(); ++it) { BlockHeader* b = *it; size_t used = b->used.load(std::memory_order_acquire); if (index < current_index + used) { size_t offset = index - current_index; return *reinterpret_cast(b->data + sizeof(T) * offset); } current_index += used; } throw std::out_of_range("Index out of range"); } // Const access const T& operator[](size_t index) const { return const_cast(this)->operator[](index); } private: // Allocate new memory block void allocate_block() { try { // Calculate block size size_t actual_block_size = block_size_; std::cout << "Allocating block with size: " << actual_block_size << " bytes" << std::endl; // Allocate memory void* memory = nullptr; #ifdef _WIN32 // Windows: Use VirtualAlloc to allocate virtual memory // MEM_COMMIT | MEM_RESERVE: Reserve and commit memory // PAGE_READWRITE: Readable and writable std::cout << "Calling VirtualAlloc" << std::endl; memory = VirtualAlloc(nullptr, actual_block_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); std::cout << "VirtualAlloc returned: " << memory << std::endl; #else // Linux: Use mmap to allocate memory // MAP_PRIVATE | MAP_ANONYMOUS: Private, anonymous mapping // PROT_READ | PROT_WRITE: Readable and writable memory = mmap(nullptr, actual_block_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #endif if (!memory) { std::cerr << "Failed to allocate memory" << std::endl; throw std::bad_alloc(); } // Initialize block header BlockHeader* block = reinterpret_cast(memory); block->used.store(0, std::memory_order_release); block->capacity = objects_per_block_; BlockHeader* old_head = head_block_.load(std::memory_order_acquire); do { block->next.store(old_head, std::memory_order_release); } while (!head_block_.compare_exchange_weak(old_head, block, std::memory_order_acq_rel, std::memory_order_acquire)); std::cout << "Block allocated successfully" << std::endl; } catch (const std::exception& e) { std::cerr << "Exception in allocate_block: " << e.what() << std::endl; throw; } } // Release memory block void deallocate_block(BlockHeader* block) { #ifdef _WIN32 // Windows: Use VirtualFree to release memory // MEM_RELEASE: Release entire memory block VirtualFree(block, 0, MEM_RELEASE); #else // Linux: Use munmap to release memory munmap(block, block_size_); #endif } size_t objects_per_block_; // Number of objects per block size_t block_size_; // Size of each block std::atomic head_block_; // Head block pointer std::atomic free_list_; // Free list (atomic pointer) }; } // namespace core } // namespace hhb