packs manager (unused yet)
This commit is contained in:
parent
68320629de
commit
95fedfa3a3
131
src/content/PacksManager.cpp
Normal file
131
src/content/PacksManager.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#include "PacksManager.h"
|
||||
|
||||
#include "../util/listutil.h"
|
||||
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
|
||||
PacksManager::PacksManager() {
|
||||
}
|
||||
|
||||
void PacksManager::setSources(std::vector<fs::path> sources) {
|
||||
this->sources = sources;
|
||||
}
|
||||
|
||||
void PacksManager::scan() {
|
||||
packs.clear();
|
||||
|
||||
std::vector<ContentPack> packsList;
|
||||
for (auto& folder : sources) {
|
||||
ContentPack::scanFolder(folder, packsList);
|
||||
for (auto& pack : packsList) {
|
||||
packs.emplace(pack.id, pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> PacksManager::getAllNames() {
|
||||
std::vector<std::string> names;
|
||||
for (auto& entry : packs) {
|
||||
names.push_back(entry.first);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
static contentpack_error on_circular_dependency(std::queue<ContentPack*>& queue) {
|
||||
ContentPack* lastPack = queue.back();
|
||||
// circular dependency
|
||||
std::stringstream ss;
|
||||
ss << "circular dependency: " << lastPack->id;
|
||||
while (!queue.empty()) {
|
||||
auto* pack = queue.front();
|
||||
queue.pop();
|
||||
ss << " <- " << pack->id;
|
||||
}
|
||||
return contentpack_error(lastPack->id, lastPack->folder, ss.str());
|
||||
}
|
||||
|
||||
/// @brief Resolve pack dependencies
|
||||
/// @param pack current pack
|
||||
/// @param packs all available packs repository
|
||||
/// @param allNames all already done or enqueued packs
|
||||
/// @param added packs with all dependencies resolved
|
||||
/// @param queue current pass queue
|
||||
/// @param resolveWeaks make weak dependencies resolved if found but not added to queue
|
||||
/// @return true if all dependencies are already added or not found (optional/weak)
|
||||
/// @throws contentpack_error if required dependency is not found
|
||||
static bool resolve_dependencies (
|
||||
ContentPack* pack,
|
||||
std::unordered_map<std::string, ContentPack>& packs,
|
||||
std::vector<std::string>& allNames,
|
||||
std::vector<std::string>& added,
|
||||
std::queue<ContentPack*>& queue,
|
||||
bool resolveWeaks
|
||||
) {
|
||||
bool satisfied = true;
|
||||
for (auto& dep : pack->dependencies) {
|
||||
if (util::contains(added, dep.id)) {
|
||||
continue;
|
||||
}
|
||||
auto found = packs.find(dep.id);
|
||||
bool exists = found != packs.end();
|
||||
if (!exists && dep.level == DependencyLevel::required) {
|
||||
throw contentpack_error(pack->id, pack->folder, "missing dependency '"+dep.id+"'");
|
||||
}
|
||||
if (!exists) {
|
||||
// ignored for optional or weak dependencies
|
||||
continue;
|
||||
}
|
||||
if (resolveWeaks && dep.level == DependencyLevel::weak) {
|
||||
// dependency pack is found but not added yet
|
||||
// resolveWeaks is used on second iteration, so it's will not be added
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!util::contains(allNames, dep.id) && dep.level != DependencyLevel::weak) {
|
||||
allNames.push_back(dep.id);
|
||||
queue.push(&found->second);
|
||||
}
|
||||
satisfied = false;
|
||||
}
|
||||
return satisfied;
|
||||
}
|
||||
|
||||
std::vector<std::string> PacksManager::assembly(const std::vector<std::string>& names) {
|
||||
std::vector<std::string> allNames = names;
|
||||
std::vector<std::string> added;
|
||||
std::queue<ContentPack*> queue;
|
||||
std::queue<ContentPack*> queue2;
|
||||
|
||||
for (auto& name : names) {
|
||||
auto found = packs.find(name);
|
||||
if (found == packs.end()) {
|
||||
throw contentpack_error(name, fs::path(""), "pack not found");
|
||||
}
|
||||
queue.push(&found->second);
|
||||
}
|
||||
|
||||
bool resolveWeaks = false;
|
||||
while (!queue.empty()) {
|
||||
int addedInIteration = 0;
|
||||
while (!queue.empty()) {
|
||||
auto* pack = queue.front();
|
||||
queue.pop();
|
||||
|
||||
if (resolve_dependencies(pack, packs, allNames, added, queue, resolveWeaks)) {
|
||||
added.push_back(pack->id);
|
||||
addedInIteration++;
|
||||
} else {
|
||||
queue2.push(pack);
|
||||
}
|
||||
}
|
||||
std::swap(queue, queue2);
|
||||
|
||||
// nothing done but deferring
|
||||
if (addedInIteration == 0 && resolveWeaks) {
|
||||
throw on_circular_dependency(queue);
|
||||
}
|
||||
resolveWeaks = true;
|
||||
}
|
||||
return added;
|
||||
}
|
||||
36
src/content/PacksManager.h
Normal file
36
src/content/PacksManager.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef CONTENT_PACKS_MANAGER_H_
|
||||
#define CONTENT_PACKS_MANAGER_H_
|
||||
|
||||
#include "ContentPack.h"
|
||||
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class PacksManager {
|
||||
std::unordered_map<std::string, ContentPack> packs;
|
||||
std::vector<fs::path> sources;
|
||||
public:
|
||||
PacksManager();
|
||||
|
||||
/// @brief Set content packs sources (search folders)
|
||||
void setSources(std::vector<fs::path> sources);
|
||||
|
||||
/// @brief Scan sources and collect all found packs excluding duplication.
|
||||
/// Scanning order depends on sources order
|
||||
void scan();
|
||||
|
||||
/// @brief Get all found packs
|
||||
std::vector<std::string> getAllNames();
|
||||
|
||||
/// @brief Resolve all dependencies and fix packs order
|
||||
/// @param names required packs (method can add extra packs)
|
||||
/// @return resulting ordered vector of pack names
|
||||
/// @throws contentpack_error if required dependency not found or
|
||||
/// circular dependency detected
|
||||
std::vector<std::string> assembly(const std::vector<std::string>& names);
|
||||
};
|
||||
|
||||
#endif // CONTENT_PACKS_MANAGER_H_
|
||||
@ -1,13 +1,20 @@
|
||||
#ifndef UTIL_LISTUTIL_H_
|
||||
#define UTIL_LISTUTIL_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
namespace util {
|
||||
template<class T>
|
||||
bool contains(std::vector<T> vec, const T& value) {
|
||||
bool contains(const std::vector<T>& vec, const T& value) {
|
||||
return std::find(vec.begin(), vec.end(), value) != vec.end();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool contains(const std::queue<T>& queue, const T& value) {
|
||||
return std::find(queue.begin(), queue.end(), value) != queue.end();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // UTIL_LISTUTIL_H_
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user