#pragma once
#include "../root.h"
#include <algorithm>
#include <climits>
#include <functional>
#include <string>
#include <string_view>
#include <vector>
namespace whiteout::storages::casc {
struct PathTrieNode {
struct Child {
std::string segment;
u32 nodeIndex; };
std::vector<Child> children;
std::vector<u32> entryIndices; };
inline const PathTrieNode::Child* trieFindChild(const PathTrieNode& node,
std::string_view segment) {
auto it = std::lower_bound(
node.children.begin(), node.children.end(), segment,
[](const PathTrieNode::Child& c, std::string_view s) { return c.segment < s; });
if (it != node.children.end() && it->segment == segment)
return &*it;
return nullptr;
}
inline u32 trieWalkTo(const std::vector<PathTrieNode>& nodes, const std::string& normalizedPrefix) {
if (nodes.empty())
return UINT32_MAX;
if (normalizedPrefix.empty())
return 0;
u32 cur = 0;
size_t pos = 0;
while (pos < normalizedPrefix.size()) {
size_t sep = normalizedPrefix.find('\\', pos);
std::string_view segment;
if (sep == std::string::npos) {
segment = std::string_view(normalizedPrefix).substr(pos);
pos = normalizedPrefix.size();
} else {
segment = std::string_view(normalizedPrefix).substr(pos, sep - pos);
pos = sep + 1;
}
if (segment.empty())
continue;
auto* child = trieFindChild(nodes[cur], segment);
if (!child)
return UINT32_MAX;
cur = child->nodeIndex;
}
return cur;
}
inline bool trieDfs(const std::vector<PathTrieNode>& nodes, u32 nodeIdx,
const std::vector<RootEntry>& entries,
std::function<bool(const RootEntry&)>& callback) {
const auto& node = nodes[nodeIdx];
for (u32 idx : node.entryIndices) {
if (!callback(entries[idx]))
return false;
}
for (const auto& child : node.children) {
if (!trieDfs(nodes, child.nodeIndex, entries, callback))
return false;
}
return true;
}
inline void trieInsert(std::vector<PathTrieNode>& nodes, const std::string& path, u32 entryIndex) {
u32 cur = 0; size_t pos = 0;
while (pos < path.size()) {
size_t sep = path.find('\\', pos);
std::string_view segment;
if (sep == std::string::npos) {
segment = std::string_view(path).substr(pos);
pos = path.size();
} else {
segment = std::string_view(path).substr(pos, sep - pos);
pos = sep + 1;
}
if (segment.empty())
continue;
auto& children = nodes[cur].children;
u32 found = UINT32_MAX;
for (size_t i = 0; i < children.size(); ++i) {
if (children[i].segment == segment) {
found = children[i].nodeIndex;
break;
}
}
if (found == UINT32_MAX) {
u32 newIdx = static_cast<u32>(nodes.size());
std::string segStr(segment);
nodes.emplace_back();
nodes[cur].children.push_back({std::move(segStr), newIdx});
cur = newIdx;
} else {
cur = found;
}
}
nodes[cur].entryIndices.push_back(entryIndex);
}
inline void trieSortAll(std::vector<PathTrieNode>& nodes, u32 nodeIdx = 0) {
auto& children = nodes[nodeIdx].children;
std::sort(children.begin(), children.end(),
[](const PathTrieNode::Child& a, const PathTrieNode::Child& b) {
return a.segment < b.segment;
});
for (auto& c : children)
trieSortAll(nodes, c.nodeIndex);
}
}