Arena.h 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #ifndef MANDEL_ARENA_H
  2. #define MANDEL_ARENA_H
  3. #include <vector>
  4. #include <array>
  5. #include <utility>
  6. #include <memory>
  7. namespace mnd
  8. {
  9. namespace util
  10. {
  11. //!
  12. //! \brief Arena-allocator for a generic type
  13. //!
  14. //! The arena allocator provides an allocate function to allocate
  15. //! and construct objects of type T. All allocated objects live as
  16. //! long as the Arena lives and are destructed in the inverse order.
  17. //!
  18. //! \tparam T the type for the Arena to allocate
  19. //! \tparam chunkSize the Arena allocates objects in chunks of this size
  20. //!
  21. template <typename T, int chunkSize = 64>
  22. class Arena
  23. {
  24. struct Chunk
  25. {
  26. char data[sizeof(T) * chunkSize];
  27. int used = 0;
  28. bool full(void) const { return used == chunkSize; }
  29. template<typename... Args>
  30. T* allocate(Args&&... args)
  31. {
  32. return new(reinterpret_cast<T*>(&data[(used++) * sizeof(T)])) T(std::forward<Args>(args)...);
  33. }
  34. ~Chunk(void)
  35. {
  36. for (int i = used - 1; i >= 0; i--) {
  37. reinterpret_cast<T*>(&data[i * sizeof(T)])->~T();
  38. }
  39. }
  40. };
  41. std::vector<std::unique_ptr<Chunk>> chunks;
  42. Chunk& lastChunk(void) { return *chunks[chunks.size() - 1]; }
  43. public:
  44. Arena(void) = default;
  45. Arena(const Arena&) = delete;
  46. Arena(Arena&&) = default;
  47. ~Arena(void)
  48. {
  49. for (auto it = chunks.rbegin(); it != chunks.rend(); ++it) {
  50. *it = nullptr;
  51. }
  52. }
  53. Arena& operator=(const Arena&) = delete;
  54. Arena& operator=(Arena&&) = default;
  55. //!
  56. //! \brief construct one object whose lifetime is managed by
  57. //! the arena.
  58. //!
  59. template<typename... Args>
  60. T* allocate(Args&&... args)
  61. {
  62. if (chunks.empty() || lastChunk().full()) {
  63. chunks.push_back(std::make_unique<Chunk>());
  64. }
  65. return lastChunk().allocate(std::forward<Args>(args)...);
  66. }
  67. };
  68. }
  69. }
  70. #endif // MANDEL_ARENA_H