object_pool.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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> class ObjectPool {
  11. public:
  12. explicit ObjectPool(size_t chunk_size = 8192) : new_chunk_size{chunk_size} {
  13. node = &chunks.emplace_back(new_chunk_size);
  14. }
  15. template <typename... Args>
  16. requires std::is_constructible_v<T, Args...>[[nodiscard]] T* Create(Args&&... args) {
  17. return std::construct_at(Memory(), std::forward<Args>(args)...);
  18. }
  19. void ReleaseContents() {
  20. if (chunks.empty()) {
  21. return;
  22. }
  23. Chunk& root{chunks.front()};
  24. if (root.used_objects == root.num_objects) {
  25. // Root chunk has been filled, squash allocations into it
  26. const size_t total_objects{root.num_objects + new_chunk_size * (chunks.size() - 1)};
  27. chunks.clear();
  28. chunks.emplace_back(total_objects);
  29. } else {
  30. root.Release();
  31. chunks.resize(1);
  32. }
  33. chunks.shrink_to_fit();
  34. node = &chunks.front();
  35. }
  36. private:
  37. struct NonTrivialDummy {
  38. NonTrivialDummy() noexcept {}
  39. };
  40. union Storage {
  41. Storage() noexcept {}
  42. ~Storage() noexcept {}
  43. NonTrivialDummy dummy{};
  44. T object;
  45. };
  46. struct Chunk {
  47. explicit Chunk() = default;
  48. explicit Chunk(size_t size)
  49. : num_objects{size}, storage{std::make_unique<Storage[]>(size)} {}
  50. Chunk& operator=(Chunk&& rhs) noexcept {
  51. Release();
  52. used_objects = std::exchange(rhs.used_objects, 0);
  53. num_objects = std::exchange(rhs.num_objects, 0);
  54. storage = std::move(rhs.storage);
  55. }
  56. Chunk(Chunk&& rhs) noexcept
  57. : used_objects{std::exchange(rhs.used_objects, 0)},
  58. num_objects{std::exchange(rhs.num_objects, 0)}, storage{std::move(rhs.storage)} {}
  59. ~Chunk() {
  60. Release();
  61. }
  62. void Release() {
  63. std::destroy_n(storage.get(), used_objects);
  64. used_objects = 0;
  65. }
  66. size_t used_objects{};
  67. size_t num_objects{};
  68. std::unique_ptr<Storage[]> storage;
  69. };
  70. [[nodiscard]] T* Memory() {
  71. Chunk* const chunk{FreeChunk()};
  72. return &chunk->storage[chunk->used_objects++].object;
  73. }
  74. [[nodiscard]] Chunk* FreeChunk() {
  75. if (node->used_objects != node->num_objects) {
  76. return node;
  77. }
  78. node = &chunks.emplace_back(new_chunk_size);
  79. return node;
  80. }
  81. Chunk* node{};
  82. std::vector<Chunk> chunks;
  83. size_t new_chunk_size{};
  84. };
  85. } // namespace Shader