2#ifndef LIBSBX_GRAPHICS_RESOURSE_STORAGE_HPP_
3#define LIBSBX_GRAPHICS_RESOURSE_STORAGE_HPP_
7#include <unordered_set>
11#include <libsbx/utility/assert.hpp>
13#include <libsbx/memory/aligned_storage.hpp>
15namespace sbx::graphics {
17template<
typename Type>
24 inline static constexpr auto invalid = std::uint32_t{0x00FFFFFF};
30 constexpr resource_handle(
const std::uint32_t handle,
const std::uint8_t generation)
32 _generation{generation} { }
34 constexpr auto handle()
const noexcept -> std::uint32_t {
38 constexpr auto generation()
const noexcept -> std::uint8_t {
42 constexpr auto operator==(
const resource_handle& other)
const noexcept ->
bool {
43 return std::memcmp(
this, &other,
sizeof(std::uint32_t)) == 0;
46 constexpr auto is_valid()
const noexcept ->
bool {
47 return _handle != invalid;
50 constexpr operator bool()
const noexcept {
56 std::uint32_t _handle : 24;
57 std::uint32_t _generation : 8;
62 std::filesystem::path path;
65template<
typename Type>
70 using value_type = Type;
71 using size_type = std::size_t;
75 _storage.reserve(32u);
76 _generations.reserve(32u);
77 _free_handles.reserve(32u);
88 template<
typename... Args>
89 requires (std::is_constructible_v<value_type, Args...>)
91 if (!_free_handles.empty()) {
92 const auto handle = _free_handles.back();
93 _free_handles.pop_back();
95 std::construct_at(_ptr(handle), std::forward<Args>(args)...);
97 const auto generation = ++_generations[handle];
102 const auto handle =
static_cast<std::uint32_t
>(_storage.size());
104 _storage.emplace_back();
105 std::construct_at(_ptr(handle), std::forward<Args>(args)...);
107 _generations.push_back(0u);
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");
116 return *_ptr(handle.handle());
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");
123 return *_ptr(handle.handle());
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");
130 std::destroy_at(_ptr(handle.handle()));
131 _free_handles.push_back(handle.handle());
134 auto clear() ->
void {
135 auto free_list = std::unordered_set<std::uint32_t>{_free_handles.begin(), _free_handles.end()};
137 for (std::uint32_t i = 0; i < _storage.size(); ++i) {
138 if (free_list.contains(i)) {
142 std::destroy_at(_ptr(i));
146 _generations.clear();
147 _free_handles.clear();
152 auto _ptr(
const size_type index) -> value_type* {
153 return std::launder(
reinterpret_cast<value_type*
>(_storage.data() + index));
156 auto _ptr(
const size_type index)
const ->
const value_type* {
157 return std::launder(
reinterpret_cast<const value_type*
>(_storage.data() + index));
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;
168template<
typename Type>
169struct std::hash<sbx::graphics::resource_handle<Type>> {
172 auto hash = std::size_t{};
174 sbx::utility::hash_combine(hash, handle.handle(), handle.generation());
Definition: resource_storage.hpp:18
Definition: resource_storage.hpp:66