/*! @file src/Utils/Arena.hpp @brief 线性分配内存池,支持非平凡析构对象的自动清理 @author PuqiAR (im@puqiar.top) @date 2026-03-08 */ #pragma once #include #include #include #include namespace Fig { class Arena { private: struct DestructorNode { void (*destructor)(void *); void *object; DestructorNode *next; }; static constexpr std::size_t CHUNK_SIZE = 64 * 1024; // 64KB 块大小 std::vector chunks; char *currentPtr = nullptr; std::size_t remaining = 0; DestructorNode *destructorHead = nullptr; public: Arena() = default; ~Arena() { // 逆序调用析构函数 DestructorNode *node = destructorHead; while (node) { node->destructor(node->object); node = node->next; } // 释放所有分配的内存块 for (char *chunk : chunks) { delete[] chunk; } } // 禁止拷贝和移动,防止内存所有权混乱 Arena(const Arena &) = delete; Arena &operator=(const Arena &) = delete; template T *Allocate(Args &&...args) { std::size_t size = sizeof(T); std::size_t alignment = alignof(T); // 在当前块中尝试对齐并分配 void *ptr = allocateRaw(size, alignment); // 在分配的内存上构造对象 T *obj = new (ptr) T(std::forward(args)...); // 如果 T 需要析构(如包含 String),注册到销毁链表 if constexpr (!std::is_trivially_destructible_v) { // 注意: DestructorNode 本身是 POD,直接在 Arena 里分配,不需要注册析构 void *nodeRaw = allocateRaw(sizeof(DestructorNode), alignof(DestructorNode)); DestructorNode *node = new (nodeRaw) DestructorNode(); node->object = obj; node->destructor = [](void *p) { static_cast(p)->~T(); }; node->next = destructorHead; destructorHead = node; } return obj; } private: void *allocateRaw(std::size_t size, std::size_t alignment) { // 对齐计算 std::size_t adjustment = 0; std::size_t currentAddr = reinterpret_cast(currentPtr); if (alignment > 0 && (currentAddr % alignment) != 0) { adjustment = alignment - (currentAddr % alignment); } if (remaining < (size + adjustment)) { // 当前块空间不足,分配新块 std::size_t nextChunkSize = (size > CHUNK_SIZE) ? size : CHUNK_SIZE; currentPtr = new char[nextChunkSize]; chunks.push_back(currentPtr); remaining = nextChunkSize; adjustment = 0; // 新分配的块通常是最大对齐的 } currentPtr += adjustment; void *res = currentPtr; currentPtr += size; remaining -= (size + adjustment); return res; } }; } // namespace Fig