[nostalgia/core] Add AssetManager
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2016 - 2021 gary@drinkingtea.net
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/model/typenamecatcher.hpp>
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/utility.hpp>
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
template<typename T>
|
||||
class AssetRef;
|
||||
|
||||
template<typename T>
|
||||
struct AssetContainer {
|
||||
|
||||
friend AssetRef<T>;
|
||||
|
||||
private:
|
||||
T m_obj;
|
||||
mutable int m_references = 0;
|
||||
|
||||
public:
|
||||
template<class... Args>
|
||||
explicit AssetContainer(Args&&... args): m_obj(ox::forward<Args>(args)...) {
|
||||
}
|
||||
|
||||
constexpr T *get() noexcept {
|
||||
return &m_obj;
|
||||
}
|
||||
|
||||
constexpr const T *get() const noexcept {
|
||||
return &m_obj;
|
||||
}
|
||||
|
||||
protected:
|
||||
constexpr void incRefs() const noexcept {
|
||||
++m_references;
|
||||
}
|
||||
|
||||
constexpr void decRefs() const noexcept {
|
||||
--m_references;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class AssetRef {
|
||||
private:
|
||||
const AssetContainer<T> *m_ctr = nullptr;
|
||||
|
||||
public:
|
||||
explicit AssetRef(const AssetContainer<T> *c = nullptr) noexcept: m_ctr(c) {
|
||||
}
|
||||
|
||||
AssetRef(const AssetRef &h) noexcept {
|
||||
m_ctr = h.m_ctr;
|
||||
if (m_ctr) {
|
||||
m_ctr->incRefs();
|
||||
}
|
||||
}
|
||||
|
||||
AssetRef(AssetRef &&h) noexcept {
|
||||
m_ctr = h.m_ctr;
|
||||
h.m_ctr = nullptr;
|
||||
}
|
||||
|
||||
~AssetRef() noexcept {
|
||||
if (m_ctr) {
|
||||
m_ctr->decRefs();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const T *get() const noexcept {
|
||||
return m_ctr->get();
|
||||
}
|
||||
|
||||
constexpr const T &operator*() const & noexcept {
|
||||
return *m_ctr->get();
|
||||
}
|
||||
|
||||
constexpr const T &&operator*() const && noexcept {
|
||||
return *m_ctr->get();
|
||||
}
|
||||
|
||||
constexpr const T *operator->() const noexcept {
|
||||
return m_ctr->get();
|
||||
}
|
||||
|
||||
AssetRef &operator=(const AssetRef &h) noexcept {
|
||||
if (this == &h) {
|
||||
return *this;
|
||||
}
|
||||
if (m_ctr) {
|
||||
m_ctr->decRefs();
|
||||
}
|
||||
m_ctr = h.m_ctr;
|
||||
if (m_ctr) {
|
||||
m_ctr->incRefs();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
AssetRef &operator=(AssetRef &&h) noexcept {
|
||||
if (this == &h) {
|
||||
return *this;
|
||||
}
|
||||
m_ctr = h.m_ctr;
|
||||
h.m_ctr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit constexpr operator bool() const noexcept {
|
||||
return m_ctr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class AssetManager {
|
||||
private:
|
||||
class AssetTypeManagerBase {
|
||||
public:
|
||||
virtual ~AssetTypeManagerBase() = default;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class AssetTypeManager: public AssetTypeManagerBase {
|
||||
private:
|
||||
ox::HashMap<ox::String, ox::UniquePtr<AssetContainer<T>>> m_cache;
|
||||
|
||||
public:
|
||||
ox::Result<AssetRef<T>> getAsset(const ox::String &path) const noexcept {
|
||||
auto out = m_cache.at(path);
|
||||
oxReturnError(out);
|
||||
return AssetRef<T>(out.value.get());
|
||||
}
|
||||
|
||||
ox::Result<AssetRef<T>> setAsset(const ox::String &path, const T &obj) noexcept {
|
||||
auto &p = m_cache[path] = ox::make_unique<AssetContainer<T>>(obj);
|
||||
return AssetRef<T>(p.get());
|
||||
}
|
||||
};
|
||||
|
||||
ox::HashMap<ox::String, ox::UniquePtr<AssetTypeManagerBase>> m_assetTypeManagers;
|
||||
|
||||
template<typename T>
|
||||
AssetTypeManager<T> *getTypeManager() noexcept {
|
||||
#if __cplusplus >= 202002L
|
||||
constexpr auto typeName = ox::getModelTypeName<T>();
|
||||
static_assert(ox_strcmp(typeName, "") != 0, "Types must have TypeName to use AssetManager");
|
||||
#else
|
||||
const auto typeName = ox::getModelTypeName<T>();
|
||||
oxAssert(ox_strcmp(typeName, "") != 0, "Types must have TypeName to use AssetManager");
|
||||
#endif
|
||||
auto &am = m_assetTypeManagers[typeName];
|
||||
if (!am) {
|
||||
am = ox::make_unique<AssetTypeManager<T>>();
|
||||
}
|
||||
return dynamic_cast<AssetTypeManager<T>*>(am.get());
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
ox::Result<AssetRef<T>> getAsset(const ox::String &path) noexcept {
|
||||
auto m = getTypeManager<T>();
|
||||
return m->getAsset(path);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Result<AssetRef<T>> setAsset(const ox::String &path, const T &obj) noexcept {
|
||||
auto m = getTypeManager<T>();
|
||||
return m->setAsset(path, obj);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user