Last active
June 23, 2022 13:33
-
-
Save Rexagon/28a6d045f9d5b824df76e7c9ee630c52 to your computer and use it in GitHub Desktop.
C++ resource manager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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