object_pool.h 2.8 KB

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