sandbox
Loading...
Searching...
No Matches
resource_storage.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_GRAPHICS_RESOURSE_STORAGE_HPP_
3#define LIBSBX_GRAPHICS_RESOURSE_STORAGE_HPP_
4
5#include <vector>
6#include <memory>
7#include <unordered_set>
8#include <filesystem>
9
11#include <libsbx/utility/assert.hpp>
12
13#include <libsbx/memory/aligned_storage.hpp>
14
15namespace sbx::graphics {
16
17template<typename Type>
19
20public:
21
22 using type = Type;
23
24 inline static constexpr auto invalid = std::uint32_t{0x00FFFFFF};
25
26 constexpr resource_handle()
27 : _handle{invalid},
28 _generation{0} { }
29
30 constexpr resource_handle(const std::uint32_t handle, const std::uint8_t generation)
31 : _handle{handle},
32 _generation{generation} { }
33
34 constexpr auto handle() const noexcept -> std::uint32_t {
35 return _handle;
36 }
37
38 constexpr auto generation() const noexcept -> std::uint8_t {
39 return _generation;
40 }
41
42 constexpr auto operator==(const resource_handle& other) const noexcept -> bool {
43 return std::memcmp(this, &other, sizeof(std::uint32_t)) == 0;
44 }
45
46 constexpr auto is_valid() const noexcept -> bool {
47 return _handle != invalid;
48 }
49
50 constexpr operator bool() const noexcept {
51 return is_valid();
52 }
53
54private:
55
56 std::uint32_t _handle : 24;
57 std::uint32_t _generation : 8;
58
59}; // class resource_handle
60
62 std::filesystem::path path;
63}; // struct resource_metadata
64
65template<typename Type>
67
68public:
69
70 using value_type = Type;
71 using size_type = std::size_t;
73
75 _storage.reserve(32u);
76 _generations.reserve(32u);
77 _free_handles.reserve(32u);
78 }
79
80 resource_storage(const resource_storage& other) = delete;
81
83 clear();
84 }
85
86 auto operator=(const resource_storage& other) -> resource_storage& = delete;
87
88 template<typename... Args>
89 requires (std::is_constructible_v<value_type, Args...>)
90 auto emplace(Args&&... args) -> handle_type {
91 if (!_free_handles.empty()) {
92 const auto handle = _free_handles.back();
93 _free_handles.pop_back();
94
95 std::construct_at(_ptr(handle), std::forward<Args>(args)...);
96
97 const auto generation = ++_generations[handle];
98
99 return handle_type{handle, generation};
100 }
101
102 const auto handle = static_cast<std::uint32_t>(_storage.size());
103
104 _storage.emplace_back();
105 std::construct_at(_ptr(handle), std::forward<Args>(args)...);
106
107 _generations.push_back(0u);
108
109 return handle_type{handle, _generations[handle]};
110 }
111
112 auto get(const handle_type& handle) -> value_type& {
113 utility::assert_that(handle.handle() < _storage.size(), "Handle is out of bounds");
114 utility::assert_that(handle.generation() == _generations[handle.handle()], "Handle generation does not match");
115
116 return *_ptr(handle.handle());
117 }
118
119 auto get(const handle_type& handle) const -> const value_type& {
120 utility::assert_that(handle.handle() < _storage.size(), "Handle is out of bounds");
121 utility::assert_that(handle.generation() == _generations[handle.handle()], "Handle generation does not match");
122
123 return *_ptr(handle.handle());
124 }
125
126 auto remove(const handle_type& handle) -> void {
127 utility::assert_that(handle.handle() < _storage.size(), "Handle is out of bounds");
128 utility::assert_that(handle.generation() == _generations[handle.handle()], "Handle generation does not match");
129
130 std::destroy_at(_ptr(handle.handle()));
131 _free_handles.push_back(handle.handle());
132 }
133
134 auto clear() -> void {
135 auto free_list = std::unordered_set<std::uint32_t>{_free_handles.begin(), _free_handles.end()};
136
137 for (std::uint32_t i = 0; i < _storage.size(); ++i) {
138 if (free_list.contains(i)) {
139 continue;
140 }
141
142 std::destroy_at(_ptr(i));
143 }
144
145 _storage.clear();
146 _generations.clear();
147 _free_handles.clear();
148 }
149
150private:
151
152 auto _ptr(const size_type index) -> value_type* {
153 return std::launder(reinterpret_cast<value_type*>(_storage.data() + index));
154 }
155
156 auto _ptr(const size_type index) const -> const value_type* {
157 return std::launder(reinterpret_cast<const value_type*>(_storage.data() + index));
158 }
159
160 std::vector<memory::storage_for_t<value_type>> _storage;
161 std::vector<std::uint8_t> _generations;
162 std::vector<std::uint32_t> _free_handles;
163
164}; // class resource_storage
165
166} // namespace sbx::graphics
167
168template<typename Type>
169struct std::hash<sbx::graphics::resource_handle<Type>> {
170
171 auto operator()(const sbx::graphics::resource_handle<Type>& handle) const noexcept -> std::size_t {
172 auto hash = std::size_t{};
173
174 sbx::utility::hash_combine(hash, handle.handle(), handle.generation());
175
176 return hash;
177 }
178
179}; // struct std::hash
180
181#endif // LIBSBX_GRAPHICS_RESOURSE_STORAGE_HPP_
Definition: resource_storage.hpp:18
Definition: resource_storage.hpp:66
Definition: resource_storage.hpp:61