1
0

Arena.h 2.8 KB

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