Skip to content

Instantly share code, notes, and snippets.

@Rexagon
Last active June 23, 2022 13:33
Show Gist options
  • Save Rexagon/28a6d045f9d5b824df76e7c9ee630c52 to your computer and use it in GitHub Desktop.
Save Rexagon/28a6d045f9d5b824df76e7c9ee630c52 to your computer and use it in GitHub Desktop.
C++ resource manager
#pragma once
#include <typeindex>
#include <memory>
#include <string>
#include <map>
#include "Resource.h"
class AbstractFactory
{
public:
virtual ~AbstractFactory() {};
virtual void* load() = 0;
virtual void clear() = 0;
};
// Allows deffered creating of resources
class ResourceManager
{
public:
// Clears up all resources
static void close()
{
m_factories.clear();
}
// Attaches resource factory to specified name
template <class T, class... Args>
static void bind(const std::string& name, Args&&... args)
{
static_assert(std::is_base_of<Resource, T>::value,
"Template parameter of function ResourceManager::bind must be a child class of Resource class");
auto key = std::make_pair(name, std::type_index(typeid(T)));
auto it = m_factories.find(key);
if (it == m_factories.end()) {
m_factories[key] = std::make_unique<ResourceFactory<T, Args...>>(std::forward<Args>(args)...);
}
}
// Attaches existing resource to specified name
// Detaches resource factory from specified name
template <class T>
static void unbind(const std::string& name)
{
static_assert(std::is_base_of<Resource, T>::value,
"Template parameter of function ResourceManager::unbind must be a child class of Resource class");
auto key = std::make_pair(name, std::type_index(typeid(T)));
auto it = m_factories.find(key);
if (it != m_factories.end()) {
m_factories.erase(it);
}
}
// Returns resource of specified name and type
// If there is no such resource nullptr will be returned
template <class T>
static T* get(const std::string& name)
{
static_assert(std::is_base_of<Resource, T>::value,
"Template parameter of function ResourceManager::get must be a child class of Resource class");
auto key = std::make_pair(name, std::type_index(typeid(T)));
auto it = m_factories.find(key);
if (it == m_factories.end()) {
return nullptr;
}
else {
return reinterpret_cast<T*>(it->second->load());
}
}
// Clear specified resource, but don't delete it from map
template <class T>
static void clear(const std::string& name)
{
static_assert(std::is_base_of<Resource, T>::value,
"Template parameter of function ResourceManager::clear must be a child class of Resource class");
auto key = std::make_pair(name, std::type_index(typeid(T)));
auto it = m_factories.find(key);
if (it != m_factories.end()) {
return it->second->clear();
}
}
private:
static std::map<std::pair<std::string, std::type_index>, std::unique_ptr<AbstractFactory>> m_factories;
};
//
template <class T, class... Args>
class ResourceFactory : public AbstractFactory
{
// Helper functions
template <int... Is>
struct index {};
template <int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> {};
template <int... Is>
struct gen_seq<0, Is...> : index<Is...> {};
public:
static_assert(std::is_base_of<Resource, T>::value, "You can only create ResourceFactory of Resource child class");
ResourceFactory(Args&&... args) :
m_resource(nullptr), m_arguments(std::forward<Args>(args)...)
{
}
void* load() override
{
if (m_resource == nullptr) {
load_resource(gen_seq<sizeof...(Args)>{});
}
return m_resource.get();
}
void clear() override
{
m_resource.reset(nullptr);
}
private:
template <int... Is>
void load_resource(index<Is...>)
{
m_resource = std::make_unique<T>(std::get<Is>(m_arguments)...);
}
std::unique_ptr<T> m_resource;
std::tuple<Args...> m_arguments;
};
/////////////////////////////////////////
// PUT INTO ResourceManager.cpp
std::map<std::pair<std::string, std::type_index>, std::unique_ptr<AbstractFactory>> ResourceManager::m_factories;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment