1#ifndef LIBSBX_GRAPHICS_RESOURSE_STORAGE_HPP_
2#define LIBSBX_GRAPHICS_RESOURSE_STORAGE_HPP_
6#include <unordered_set>
10#include <libsbx/utility/assert.hpp>
12#include <libsbx/memory/aligned_storage.hpp>
14namespace sbx::graphics {
16template<
typename Type>
23 inline static constexpr auto invalid = std::uint32_t{0x00FFFFFF};
29 constexpr resource_handle(
const std::uint32_t handle,
const std::uint8_t generation)
31 _generation{generation} { }
33 constexpr auto handle()
const noexcept -> std::uint32_t {
37 constexpr auto generation()
const noexcept -> std::uint8_t {
41 constexpr auto operator==(
const resource_handle& other)
const noexcept ->
bool {
44 return std::memcmp(
this, &other,
sizeof(std::uint32_t)) == 0;
47 constexpr auto is_valid()
const noexcept ->
bool {
48 return _handle != invalid;
51 constexpr operator bool()
const noexcept {
57 std::uint32_t _handle : 24;
58 std::uint32_t _generation : 8;
63 std::filesystem::path path;
66template<
typename Type>
71 using value_type = Type;
72 using size_type = std::size_t;
76 _storage.reserve(32u);
77 _generations.reserve(32u);
78 _free_handles.reserve(32u);
89 template<
typename... Args>
90 requires (std::is_constructible_v<value_type, Args...>)
92 if (!_free_handles.empty()) {
93 const auto handle = _free_handles.back();
94 _free_handles.pop_back();
96 std::construct_at(_ptr(handle), std::forward<Args>(args)...);
98 const auto generation = ++_generations[handle];
103 const auto handle =
static_cast<std::uint32_t
>(_storage.size());
105 _storage.emplace_back();
106 std::construct_at(_ptr(handle), std::forward<Args>(args)...);
108 _generations.push_back(0u);
113 auto get(
const handle_type& handle) -> value_type& {
114 utility::assert_that(handle.handle() < _storage.size(),
"Handle is out of bounds");
115 utility::assert_that(handle.generation() == _generations[handle.handle()],
"Handle generation does not match");
117 return *_ptr(handle.handle());
120 auto get(
const handle_type& handle)
const ->
const value_type& {
121 utility::assert_that(handle.handle() < _storage.size(),
"Handle is out of bounds");
122 utility::assert_that(handle.generation() == _generations[handle.handle()],
"Handle generation does not match");
124 return *_ptr(handle.handle());
128 utility::assert_that(handle.handle() < _storage.size(),
"Handle is out of bounds");
129 utility::assert_that(handle.generation() == _generations[handle.handle()],
"Handle generation does not match");
131 std::destroy_at(_ptr(handle.handle()));
132 _free_handles.push_back(handle.handle());
135 auto clear() ->
void {
136 auto free_list = std::unordered_set<std::uint32_t>{_free_handles.begin(), _free_handles.end()};
138 for (std::uint32_t i = 0; i < _storage.size(); ++i) {
139 if (free_list.contains(i)) {
143 std::destroy_at(_ptr(i));
147 _generations.clear();
148 _free_handles.clear();
153 auto _ptr(
const size_type index) -> value_type* {
154 return std::launder(
reinterpret_cast<value_type*
>(_storage.data() + index));
157 auto _ptr(
const size_type index)
const ->
const value_type* {
158 return std::launder(
reinterpret_cast<const value_type*
>(_storage.data() + index));
161 std::vector<memory::storage_for_t<value_type>> _storage;
162 std::vector<std::uint8_t> _generations;
163 std::vector<std::uint32_t> _free_handles;
169template<
typename Type>
170struct std::hash<sbx::graphics::resource_handle<Type>> {
173 auto hash = std::size_t{};
175 sbx::utility::hash_combine(hash, handle.handle(), handle.generation());
Definition: resource_storage.hpp:17
Definition: resource_storage.hpp:67