#ifndef MANDEL_ARENA_H #define MANDEL_ARENA_H #include #include #include #include #include namespace mnd { namespace util { //! //! \brief Arena-allocator for a generic type //! //! The arena allocator provides an allocate function to allocate //! and construct objects of type T. All allocated objects live as //! long as the Arena lives and are destructed in the inverse order. //! //! \tparam T the type for the Arena to allocate //! \tparam chunkSize the Arena allocates objects in chunks of this size //! template class Arena { struct Chunk { char data[sizeof(T) * chunkSize]; int used = 0; bool full(void) const { return used == chunkSize; } template T* allocate(Args&&... args) { return new(reinterpret_cast(&data[(used++) * sizeof(T)])) T(std::forward(args)...); } T& at(int index) { return *reinterpret_cast(&data[index * sizeof(T)]); } ~Chunk(void) { for (int i = used - 1; i >= 0; i--) { reinterpret_cast(&data[i * sizeof(T)])->~T(); } } }; std::vector> chunks; Chunk& lastChunk(void) { return *chunks[chunks.size() - 1]; } public: Arena(void) = default; Arena(const Arena&) = delete; Arena(Arena&&) = default; ~Arena(void) { for (auto it = chunks.rbegin(); it != chunks.rend(); ++it) { *it = nullptr; } } Arena& operator=(const Arena&) = delete; Arena& operator=(Arena&&) = default; //! //! \brief construct one object whose lifetime is managed by //! the arena. //! template T* allocate(Args&&... args) { if (chunks.empty() || lastChunk().full()) { chunks.push_back(std::make_unique()); } return lastChunk().allocate(std::forward(args)...); } void forAll(std::function f) { for (auto& chunk : chunks) { for (int i = 0; i < chunk->used; i++) { f(chunk->at(i)); } } } }; } } #endif // MANDEL_ARENA_H