/* ** EPITECH PROJECT, 2021 ** Bomberman ** File description: ** Cache */ #pragma once #include #include #include #include #include #include "Exceptions/RayError.hpp" #include #include #include #include namespace RAY { //! @brief A templated class used to cache ressources, indexed with a string template class Cache { public: //! @brief Cache(std::function dataLoader, std::function dataUnloader): _dataLoader(dataLoader), _dataUnloader(dataUnloader) {}; //! @brief Default destructor, will destroy ray's data ~Cache() = default; //! @brief default copy constructor Cache(const Cache &) = default; //! @brief a cache is assignable Cache &operator=(const Cache &) = default; //! @param path path of the file //! @param lonely: should be set to true if the loaded data must be held by no other active entites //! @return a newly loaded ressource if it hasn't be previously loaded, or one from cache std::shared_ptrfetch(const std::string &path, bool lonely = false) { if (!this->_cache.contains(path)) this->_cache.emplace(path, std::vector>()); std::vector> &matchingDataVector = this->_cache.at(path); if (matchingDataVector.size()) { for (std::shared_ptr &i: matchingDataVector) { if (!lonely) return i; if (lonely && i.use_count() == 1) return i; } } matchingDataVector.push_back(std::shared_ptr( new T(this->_dataLoader(path.c_str())), [this](T *p) { this->_dataUnloader(*p); delete p; })); return matchingDataVector.back(); }; private: //! @brief function to call to load data std::function _dataLoader; //! @brief function to call when the ray data will be unloaded std::function _dataUnloader; //! @brief map storing shared ptr of caches std::unordered_map>> _cache; }; template<> class Cache<::ModelAnimation> { public: Cache(std::function<::ModelAnimation *(const char *, int *)> dataLoader, std::functiondataUnloader): _dataLoader(std::move(dataLoader)), _dataUnloader(std::move(dataUnloader)) {}; std::shared_ptr<::ModelAnimation> fetch(const std::string &path, int *counter) { if (this->_cache.find(path) != this->_cache.end()) return this->_cache[path]; ::ModelAnimation *animations = this->_dataLoader(path.c_str(), counter); unsigned int animCount = *counter; this->_cache.emplace(path, std::shared_ptr<::ModelAnimation>( animations, [this, animCount](::ModelAnimation *p) { this->_dataUnloader(p, animCount); })); return this->_cache[path]; }; private: //! @brief function to call to load data std::function<::ModelAnimation *(const char *, int *)> _dataLoader; //! @brief function to call when the ray data will be unloaded std::function _dataUnloader; //! @brief map storing shared ptr of caches std::unordered_map> _cache; }; template<> class Cache<::Shader> { public: Cache(std::function<::Shader(const char *, const char *)> dataLoader, std::function dataUnloader) : _dataLoader(std::move(dataLoader)), _dataUnloader(std::move(dataUnloader)) {}; std::shared_ptr<::Shader> fetch(const std::string &vertexFile, const std::string &fragmentFile) { const std::string index = vertexFile + fragmentFile; if (vertexFile.empty() && fragmentFile.empty()) { throw RAY::Exception::WrongInputError(); } if (this->_cache.find(index) != this->_cache.end()) return this->_cache[index]; this->_cache.emplace(index, std::shared_ptr<::Shader>( new ::Shader( this->_dataLoader(vertexFile.empty() ? nullptr : vertexFile.c_str(), fragmentFile.c_str())), [this](::Shader *p) { this->_dataUnloader(*p); })); return this->_cache[index]; }; private: //! @brief function to call to load data std::function<::Shader(const char *, const char *)> _dataLoader; //! @brief function to call when the ray data will be unloaded std::function _dataUnloader; //! @brief map storing shared ptr of caches std::unordered_map> _cache; }; }