summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/object_pool.h
blob: a573add3271fe4a209cee368c6111dd4b050093b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <memory>
#include <type_traits>
#include <utility>

namespace Shader {

template <typename T, size_t chunk_size = 8192>
requires std::is_destructible_v<T> class ObjectPool {
public:
    ~ObjectPool() {
        std::unique_ptr<Chunk> tree_owner;
        Chunk* chunk{&root};
        while (chunk) {
            for (size_t obj_id = chunk->free_objects; obj_id < chunk_size; ++obj_id) {
                chunk->storage[obj_id].object.~T();
            }
            tree_owner = std::move(chunk->next);
            chunk = tree_owner.get();
        }
    }

    template <typename... Args>
    requires std::is_constructible_v<T, Args...> [[nodiscard]] T* Create(Args&&... args) {
        return std::construct_at(Memory(), std::forward<Args>(args)...);
    }

    void ReleaseContents() {
        Chunk* chunk{&root};
        while (chunk) {
            if (chunk->free_objects == chunk_size) {
                break;
            }
            for (; chunk->free_objects < chunk_size; ++chunk->free_objects) {
                chunk->storage[chunk->free_objects].object.~T();
            }
            chunk = chunk->next.get();
        }
        node = &root;
    }

private:
    struct NonTrivialDummy {
        NonTrivialDummy() noexcept {}
    };

    union Storage {
        Storage() noexcept {}
        ~Storage() noexcept {}

        NonTrivialDummy dummy{};
        T object;
    };

    struct Chunk {
        size_t free_objects = chunk_size;
        std::array<Storage, chunk_size> storage;
        std::unique_ptr<Chunk> next;
    };

    [[nodiscard]] T* Memory() {
        Chunk* const chunk{FreeChunk()};
        return &chunk->storage[--chunk->free_objects].object;
    }

    [[nodiscard]] Chunk* FreeChunk() {
        if (node->free_objects > 0) {
            return node;
        }
        if (node->next) {
            node = node->next.get();
            return node;
        }
        node->next = std::make_unique<Chunk>();
        node = node->next.get();
        return node;
    }

    Chunk* node{&root};
    Chunk root;
};

} // namespace Shader