140 lines
3.3 KiB
C++
140 lines
3.3 KiB
C++
#ifndef INCLUDE_RESOURCE_MANAGER_IMPLEMENTATION
|
|
# error Never include this file directly include 'resource_manager.hpp'
|
|
#endif
|
|
|
|
#include <ranges>
|
|
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
bool zgl::resource_manager<StoreID, MetaData>::has_resource(StoreID store_id)
|
|
{
|
|
std::shared_lock lock(m_lock);
|
|
return m_resource_lookup.contains(store_id);
|
|
}
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
void zgl::resource_manager<StoreID, MetaData>::add_resource(StoreID store_id, gl_id_type gl_id, MetaData meta)
|
|
{
|
|
std::unique_lock lock(m_lock);
|
|
m_resource_lookup.emplace(store_id, { gl_id, std::move(meta) });
|
|
m_reference_counters.emplace(gl_id, 1);
|
|
}
|
|
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
std::optional<std::pair<zgl::resource_handle, MetaData>> zgl::resource_manager<StoreID, MetaData>::get_resource(
|
|
StoreID store_id
|
|
) {
|
|
std::unique_lock lock(m_lock);
|
|
|
|
const auto resource_it = m_resource_lookup.find(store_id);
|
|
if (resource_it == m_resource_lookup.end())
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
|
|
const auto gl_id = resource_it.first;
|
|
|
|
auto [ counter_it, inserted ] = m_reference_counters.try_emplace(gl_id, 0);
|
|
|
|
++counter_it->second;
|
|
|
|
return std::pair{ resource_handle(gl_id, this), resource_it->second };
|
|
}
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
void zgl::resource_manager<StoreID, MetaData>::collect_garbage()
|
|
{
|
|
std::unique_lock lock(m_lock);
|
|
|
|
for (auto& counter : m_reference_counters | std::ranges::views::values)
|
|
{
|
|
if (counter & unused_resource_flag)
|
|
{
|
|
const auto value = counter & ~unused_resource_flag;
|
|
counter = (value + 1) | unused_resource_flag;
|
|
}
|
|
}
|
|
|
|
std::erase_if(
|
|
m_reference_counters,
|
|
[&](const auto& entry)
|
|
{
|
|
auto& counter = entry.second;
|
|
|
|
const auto value = counter & ~unused_resource_flag;
|
|
|
|
if (value == counter) // Still in use
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (value < max_unused_collection_cycle_count)
|
|
{
|
|
counter = (value + 1) | unused_resource_flag;
|
|
return false;
|
|
}
|
|
|
|
m_unused_handles.emplace(entry.first);
|
|
|
|
return true;
|
|
}
|
|
);
|
|
|
|
std::erase_if(
|
|
m_resource_lookup,
|
|
[&](const auto& entry)
|
|
{
|
|
return m_unused_handles.contains(entry.second);
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
void zgl::resource_manager<StoreID, MetaData>::add_reference(const gl_id_type id)
|
|
{
|
|
std::unique_lock lock(m_lock);
|
|
auto [it, inserted] = m_reference_counters.try_emplace(id, 0);
|
|
++it->second;
|
|
}
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
void zgl::resource_manager<StoreID, MetaData>::remove_reference(const gl_id_type id)
|
|
{
|
|
std::unique_lock lock(m_lock);
|
|
if (const auto it = m_reference_counters.find(id); it != m_reference_counters.end())
|
|
{
|
|
if (it->second == 1)
|
|
{
|
|
it->second = unused_resource_flag;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
typename zgl::resource_manager<StoreID, MetaData>::size_type zgl::resource_manager<StoreID, MetaData>::count_garbage()
|
|
{
|
|
std::shared_lock lock(m_lock);
|
|
return m_unused_handles.size();
|
|
}
|
|
|
|
template<typename StoreID, typename MetaData>
|
|
void zgl::resource_manager<StoreID, MetaData>::extract_garbage(
|
|
std::vector<gl_id_type>& dst
|
|
) {
|
|
{
|
|
std::shared_lock lock(m_lock);
|
|
dst.reserve(m_unused_handles.size());
|
|
}
|
|
{
|
|
std::unique_lock lock(m_lock);
|
|
|
|
dst.resize(m_unused_handles.size());
|
|
|
|
std::ranges::copy(m_unused_handles, dst.begin());
|
|
|
|
m_unused_handles.clear();
|
|
}
|
|
}
|