rutile-game/src/core/resource_manager.cppm

123 lines
4.2 KiB
C++

module;
#include <cassert>
#include <map>
#include <optional>
#include <string>
#include <vector>
export module core.resource_manager;
export namespace core
{
template <typename ResourceLoaderType, typename ResourceType>
concept IsResourceLoader = requires(ResourceLoaderType loader, const std::string& name)
{
{ loader.load_resource(name) } -> std::same_as<ResourceType>;
};
template <
typename ResourceIDType,
typename ResourceType,
IsResourceLoader<ResourceType> ResourceLoaderType
>
class ResourceManager
{
// Resource loader
ResourceLoaderType& resource_loader_;
// Registry of loaded resources, array index is resource ID
std::vector<ResourceType> resource_registry_;
// Mapping of all loaded resources from (file) name to resource ID
std::map<std::string, ResourceIDType> resource_name_map_;
public:
ResourceManager() = delete;
explicit ResourceManager(ResourceLoaderType& resource_loader)
: resource_loader_{resource_loader}
{}
// No copy or move operations
ResourceManager(const ResourceManager&) = delete;
ResourceManager& operator=(const ResourceManager&) = delete;
ResourceManager(ResourceManager&&) = delete;
ResourceManager& operator=(ResourceManager&&) = delete;
~ResourceManager() = default;
/**
* Adds a new resource to the registry and returns its ID.
*/
ResourceIDType add_resource(ResourceType&& resource)
{
// Add resource to end of vector
resource_registry_.push_back(std::move(resource));
// Return the index of the newly added resource
return static_cast<ResourceIDType>(resource_registry_.size() - 1);
}
/**
* Adds a new resource to the registry, associates the name with it and returns its ID.
*/
ResourceIDType add_resource(ResourceType&& resource, const std::string& name)
{
// Add resource
ResourceIDType resource_id = add_resource(std::move(resource));
// Associate name with resource ID for future access
resource_name_map_.emplace(name, resource_id);
return resource_id;
}
/**
* Gets the resource ID for a given resource name, or `std::nullopt` if the resource was not found.
*/
std::optional<ResourceIDType> get_resource_id_by_name(const std::string& name) const
{
// Check if resource is already loaded
if (
const auto search = resource_name_map_.find(name);
search != resource_name_map_.end()
) {
// Return resource ID
return search->second;
}
return std::nullopt;
}
/**
* Loads a resource (e.g. from a file) and adds it to the registry if it isn't loaded yet.
* Returns the resource ID.
*/
ResourceIDType load_resource_by_name(const std::string& name)
{
// Check if resource is already loaded
if (
auto resource_id = get_resource_id_by_name(name);
resource_id.has_value()
) {
return resource_id.value();
}
// Load resource and add it to the registry
return add_resource(resource_loader_.load_resource(name), name);
}
/**
* Returns a reference to the resource with the given ID.
* The reference is not guaranteed to be valid after adding new resources to the registry.
* Assumes that the resource ID is valid.
*/
const ResourceType& get_resource(const ResourceIDType resource_id) const
{
assert(resource_id < resource_registry_.size());
return resource_registry_[resource_id];
}
};
}