199 lines
4.0 KiB
C++
199 lines
4.0 KiB
C++
/*
|
|
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
|
*/
|
|
|
|
#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 {
|
|
|
|
class AssetManager;
|
|
|
|
template<typename T>
|
|
class AssetRef;
|
|
|
|
template<typename T>
|
|
struct AssetContainer {
|
|
|
|
friend AssetManager;
|
|
friend AssetRef<T>;
|
|
|
|
private:
|
|
T m_obj;
|
|
mutable int m_references = 0;
|
|
|
|
public:
|
|
template<class... Args>
|
|
explicit constexpr 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;
|
|
}
|
|
|
|
constexpr int references() const noexcept {
|
|
return m_references;
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
class AssetRef {
|
|
private:
|
|
const AssetContainer<T> *m_ctr = nullptr;
|
|
|
|
public:
|
|
explicit constexpr AssetRef(const AssetContainer<T> *c = nullptr) noexcept: m_ctr(c) {
|
|
}
|
|
|
|
constexpr AssetRef(const AssetRef &h) noexcept {
|
|
m_ctr = h.m_ctr;
|
|
if (m_ctr) {
|
|
m_ctr->incRefs();
|
|
}
|
|
}
|
|
|
|
constexpr 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;
|
|
|
|
virtual void gc() noexcept = 0;
|
|
};
|
|
|
|
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());
|
|
}
|
|
|
|
void gc() noexcept final {
|
|
for (const auto &ack : m_cache.keys()) {
|
|
auto &ac = m_cache[ack];
|
|
if (ac->references()) {
|
|
m_cache.erase(ack);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
ox::HashMap<ox::String, ox::UniquePtr<AssetTypeManagerBase>> m_assetTypeManagers;
|
|
|
|
template<typename T>
|
|
AssetTypeManager<T> *getTypeManager() noexcept {
|
|
constexpr auto typeName = ox::requireModelTypeName<T>();
|
|
static_assert(ox_strcmp(typeName, "") != 0, "Types must have TypeName to use AssetManager");
|
|
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);
|
|
}
|
|
|
|
void gc() noexcept {
|
|
for (const auto &amk : m_assetTypeManagers.keys()) {
|
|
auto &am = m_assetTypeManagers[amk];
|
|
am->gc();
|
|
}
|
|
}
|
|
};
|
|
|
|
} |