#pragma once #include #include #include #include #include #include #include #include #include #include #define LOGRM(x) LOG("ResourceManager", x) namespace MM { // modeled heavily after entt::resource_cache // https://github.com/skypjack/entt/blob/master/src/entt/resource/cache.hpp template class ResourceManager { public: using res_id_type = typename entt::hashed_string::hash_type; using handle_type = std::shared_ptr; using container_type = std::unordered_map; using size_type = typename container_type::size_type; private: ResourceManager(void) = default; container_type _storage; public: ResourceManager(ResourceManager const&) = delete; void operator=(ResourceManager const&) = delete; static ResourceManager& ref(void) { static ResourceManager instance{}; return instance; } // Loader s must implement a load method template bool load(const res_id_type id, Args &&... args) { //static_assert(std::is_base_of, Loader>::value); if (!contains(id)) { handle_type r = Loader{}.load(std::forward(args)...); if (static_cast(r)) { _storage[id] = std::move(r); } else { return false; } } return true; } // string overload template bool load(const char* id, Args &&... args) { return load(entt::hashed_string{id}.value(), std::forward(args)...); } template bool reload(const res_id_type id, Args &&... args) { discard(id); return load(id, std::forward(args)...); } // string overload template bool reload(const char* id, Args &&... args) { return reload(entt::hashed_string{id}.value(), std::forward(args)...); } void discard(const res_id_type id) ENTT_NOEXCEPT { if (auto it = _storage.find(id); it != _storage.end()) { _storage.erase(it); } } void discard(const char* id) ENTT_NOEXCEPT { discard(entt::hashed_string{id}.value()); } void each(std::function)>& fn) { for (auto& it : _storage) { fn(it.first, it.second); } } size_type size(void) const { return _storage.size(); } bool empty(void) const { return _storage.empty(); } void clear(void) ENTT_NOEXCEPT { _storage.clear(); } bool contains(const res_id_type id) const ENTT_NOEXCEPT { return (_storage.find(id) != _storage.cend()); } handle_type get(const res_id_type id) const { using namespace entt::literals; auto it = _storage.find(id); if (it == _storage.end()) { if (id != "default"_hs) { LOGRM("not in cache, loading default..."); return get("default"_hs); } else { return nullptr; } } else { return it->second; } } // TODO: fix //handle_type get(const char* id) const { //return get(entt::hashed_string{id}.value()); //} // reverse lookup std::optional id_from_handle(const std::shared_ptr& handle) { if (static_cast(handle)) { auto it = std::find_if(_storage.cbegin(), _storage.cend(), [&](auto& v) { return handle == v.second; }); if (it != _storage.cend()) { return it->first; } } return std::nullopt; } }; } // namespace MM #undef LOGRM