#ifndef INCLUDE_RESOURCE_MANAGER_IMPLEMENTATION # error Never include this file directly include 'resource_manager.hpp' #endif #include template bool zgl::resource_manager::has_resource(StoreID store_id) { std::shared_lock lock(m_lock); return m_resource_lookup.contains(store_id); } template void zgl::resource_manager::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 std::optional> zgl::resource_manager::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 void zgl::resource_manager::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 void zgl::resource_manager::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 void zgl::resource_manager::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 zgl::resource_manager::size_type zgl::resource_manager::count_garbage() { std::shared_lock lock(m_lock); return m_unused_handles.size(); } template void zgl::resource_manager::extract_garbage( std::vector& 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(); } }