object_pool.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <memory>
  6. #include <type_traits>
  7. #include <utility>
  8. namespace Shader {
  9. template <typename T>
  10. requires std::is_destructible_v<T>
  11. class ObjectPool {
  12. public:
  13. explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
  14. node = &chunks.emplace_back(new_chunk_size);
  15. }
  16. template <typename... Args>
  17. requires std::is_constructible_v<T, Args...>
  18. [[nodiscard]] T* Create(Args&&... args) {
  19. return std::construct_at(Memory(), std::forward<Args>(args)...);
  20. }
  21. void ReleaseContents() {
  22. if (chunks.empty()) {
  23. return;
  24. }
  25. Chunk& root{chunks.front()};
  26. if (root.used_objects == root.num_objects) {
  27. // Root chunk has been filled, squash allocations into it
  28. const size_t total_objects{root.num_objects + new_chunk_size * (chunks.size() - 1)};
  29. chunks.clear();
  30. chunks.emplace_back(total_objects);
  31. } else {
  32. root.Release();
  33. chunks.resize(1);
  34. }
  35. chunks.shrink_to_fit();
  36. node = &chunks.front();
  37. }
  38. private:
  39. struct NonTrivialDummy {
  40. NonTrivialDummy() noexcept {}
  41. };
  42. union Storage {
  43. Storage() noexcept {}
  44. ~Storage() noexcept {}
  45. NonTrivialDummy dummy{};
  46. T object;
  47. };
  48. struct Chunk {
  49. explicit Chunk() = default;
  50. explicit Chunk(size_t size)
  51. : num_objects{size}, storage{std::make_unique<Storage[]>(size)} {}
  52. Chunk& operator=(Chunk&& rhs) noexcept {
  53. Release();
  54. used_objects = std::exchange(rhs.used_objects, 0);
  55. num_objects = std::exchange(rhs.num_objects, 0);
  56. storage = std::move(rhs.storage);
  57. return *this;
  58. }
  59. Chunk(Chunk&& rhs) noexcept
  60. : used_objects{std::exchange(rhs.used_objects, 0)},
  61. num_objects{std::exchange(rhs.num_objects, 0)}, storage{std::move(rhs.storage)} {}
  62. ~Chunk() {
  63. Release();
  64. }
  65. void Release() {
  66. std::destroy_n(storage.get(), used_objects);
  67. used_objects = 0;
  68. }
  69. size_t used_objects{};
  70. size_t num_objects{};
  71. std::unique_ptr<Storage[]> storage;
  72. };
  73. [[nodiscard]] T* Memory() {
  74. Chunk* const chunk{FreeChunk()};
  75. return &chunk->storage[chunk->used_objects++].object;
  76. }
  77. [[nodiscard]] Chunk* FreeChunk() {
  78. if (node->used_objects != node->num_objects) {
  79. return node;
  80. }
  81. node = &chunks.emplace_back(new_chunk_size);
  82. return node;
  83. }
  84. Chunk* node{};
  85. std::vector<Chunk> chunks;
  86. size_t new_chunk_size{};
  87. };
  88. } // namespace Shader