@ -1,44 +1,32 @@
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
template <char Tseparator>
|
||||
class SeparatorPrefixTree
|
||||
{
|
||||
public:
|
||||
SeparatorPrefixTree(QStringList paths)
|
||||
{
|
||||
insert(paths);
|
||||
}
|
||||
class SeparatorPrefixTree {
|
||||
public:
|
||||
SeparatorPrefixTree(QStringList paths) { insert(paths); }
|
||||
|
||||
SeparatorPrefixTree(bool contained = false)
|
||||
{
|
||||
m_contained = contained;
|
||||
}
|
||||
SeparatorPrefixTree(bool contained = false) { m_contained = contained; }
|
||||
|
||||
void insert(QStringList paths)
|
||||
{
|
||||
for(auto &path: paths)
|
||||
{
|
||||
for (auto& path : paths) {
|
||||
insert(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// insert an exact path into the tree
|
||||
SeparatorPrefixTree & insert(QString path)
|
||||
SeparatorPrefixTree& insert(QString path)
|
||||
{
|
||||
auto sepIndex = path.indexOf(Tseparator);
|
||||
if(sepIndex == -1)
|
||||
{
|
||||
if (sepIndex == -1) {
|
||||
children[path] = SeparatorPrefixTree(true);
|
||||
return children[path];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
auto prefix = path.left(sepIndex);
|
||||
if(!children.contains(prefix))
|
||||
{
|
||||
if (!children.contains(prefix)) {
|
||||
children[prefix] = SeparatorPrefixTree(false);
|
||||
}
|
||||
return children[prefix].insert(path.mid(sepIndex + 1));
|
||||
@ -56,26 +44,20 @@ public:
|
||||
bool covers(QString path) const
|
||||
{
|
||||
// if we found some valid node, it's good enough. the tree covers the path
|
||||
if(m_contained)
|
||||
{
|
||||
if (m_contained) {
|
||||
return true;
|
||||
}
|
||||
auto sepIndex = path.indexOf(Tseparator);
|
||||
if(sepIndex == -1)
|
||||
{
|
||||
if (sepIndex == -1) {
|
||||
auto found = children.find(path);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return false;
|
||||
}
|
||||
return (*found).covers(QString());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
auto prefix = path.left(sepIndex);
|
||||
auto found = children.find(prefix);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return false;
|
||||
}
|
||||
return (*found).covers(path.mid(sepIndex + 1));
|
||||
@ -86,41 +68,33 @@ public:
|
||||
QString cover(QString path) const
|
||||
{
|
||||
// if we found some valid node, it's good enough. the tree covers the path
|
||||
if(m_contained)
|
||||
{
|
||||
if (m_contained) {
|
||||
return QString("");
|
||||
}
|
||||
auto sepIndex = path.indexOf(Tseparator);
|
||||
if(sepIndex == -1)
|
||||
{
|
||||
if (sepIndex == -1) {
|
||||
auto found = children.find(path);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return QString();
|
||||
}
|
||||
auto nested = (*found).cover(QString());
|
||||
if(nested.isNull())
|
||||
{
|
||||
if (nested.isNull()) {
|
||||
return nested;
|
||||
}
|
||||
if(nested.isEmpty())
|
||||
if (nested.isEmpty())
|
||||
return path;
|
||||
return path + Tseparator + nested;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
auto prefix = path.left(sepIndex);
|
||||
auto found = children.find(prefix);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return QString();
|
||||
}
|
||||
auto nested = (*found).cover(path.mid(sepIndex + 1));
|
||||
if(nested.isNull())
|
||||
{
|
||||
if (nested.isNull()) {
|
||||
return nested;
|
||||
}
|
||||
if(nested.isEmpty())
|
||||
if (nested.isEmpty())
|
||||
return prefix;
|
||||
return prefix + Tseparator + nested;
|
||||
}
|
||||
@ -130,21 +104,16 @@ public:
|
||||
bool exists(QString path) const
|
||||
{
|
||||
auto sepIndex = path.indexOf(Tseparator);
|
||||
if(sepIndex == -1)
|
||||
{
|
||||
if (sepIndex == -1) {
|
||||
auto found = children.find(path);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
auto prefix = path.left(sepIndex);
|
||||
auto found = children.find(prefix);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return false;
|
||||
}
|
||||
return (*found).exists(path.mid(sepIndex + 1));
|
||||
@ -152,24 +121,19 @@ public:
|
||||
}
|
||||
|
||||
/// find a node in the tree by name
|
||||
const SeparatorPrefixTree * find(QString path) const
|
||||
const SeparatorPrefixTree* find(QString path) const
|
||||
{
|
||||
auto sepIndex = path.indexOf(Tseparator);
|
||||
if(sepIndex == -1)
|
||||
{
|
||||
if (sepIndex == -1) {
|
||||
auto found = children.find(path);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &(*found);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
auto prefix = path.left(sepIndex);
|
||||
auto found = children.find(prefix);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return (*found).find(path.mid(sepIndex + 1));
|
||||
@ -177,70 +141,48 @@ public:
|
||||
}
|
||||
|
||||
/// is this a leaf node?
|
||||
bool leaf() const
|
||||
{
|
||||
return children.isEmpty();
|
||||
}
|
||||
bool leaf() const { return children.isEmpty(); }
|
||||
|
||||
/// is this node actually contained in the tree, or is it purely structural?
|
||||
bool contained() const
|
||||
{
|
||||
return m_contained;
|
||||
}
|
||||
bool contained() const { return m_contained; }
|
||||
|
||||
/// Remove a path from the tree
|
||||
bool remove(QString path)
|
||||
{
|
||||
return removeInternal(path) != Failed;
|
||||
}
|
||||
bool remove(QString path) { return removeInternal(path) != Failed; }
|
||||
|
||||
/// Clear all children of this node tree node
|
||||
void clear()
|
||||
{
|
||||
children.clear();
|
||||
}
|
||||
void clear() { children.clear(); }
|
||||
|
||||
QStringList toStringList() const
|
||||
{
|
||||
QStringList collected;
|
||||
// collecting these is more expensive.
|
||||
auto iter = children.begin();
|
||||
while(iter != children.end())
|
||||
{
|
||||
while (iter != children.end()) {
|
||||
QStringList list = iter.value().toStringList();
|
||||
for(int i = 0; i < list.size(); i++)
|
||||
{
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
list[i] = iter.key() + Tseparator + list[i];
|
||||
}
|
||||
collected.append(list);
|
||||
if((*iter).m_contained)
|
||||
{
|
||||
if ((*iter).m_contained) {
|
||||
collected.append(iter.key());
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
return collected;
|
||||
}
|
||||
private:
|
||||
enum Removal
|
||||
{
|
||||
Failed,
|
||||
Succeeded,
|
||||
HasChildren
|
||||
};
|
||||
|
||||
private:
|
||||
enum Removal { Failed, Succeeded, HasChildren };
|
||||
Removal removeInternal(QString path = QString())
|
||||
{
|
||||
if(path.isEmpty())
|
||||
{
|
||||
if(!m_contained)
|
||||
{
|
||||
if (path.isEmpty()) {
|
||||
if (!m_contained) {
|
||||
// remove all children - we are removing a prefix
|
||||
clear();
|
||||
return Succeeded;
|
||||
}
|
||||
m_contained = false;
|
||||
if(children.size())
|
||||
{
|
||||
if (children.size()) {
|
||||
return HasChildren;
|
||||
}
|
||||
return Succeeded;
|
||||
@ -248,42 +190,32 @@ private:
|
||||
Removal remStatus = Failed;
|
||||
QString childToRemove;
|
||||
auto sepIndex = path.indexOf(Tseparator);
|
||||
if(sepIndex == -1)
|
||||
{
|
||||
if (sepIndex == -1) {
|
||||
childToRemove = path;
|
||||
auto found = children.find(childToRemove);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return Failed;
|
||||
}
|
||||
remStatus = (*found).removeInternal();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
childToRemove = path.left(sepIndex);
|
||||
auto found = children.find(childToRemove);
|
||||
if(found == children.end())
|
||||
{
|
||||
if (found == children.end()) {
|
||||
return Failed;
|
||||
}
|
||||
remStatus = (*found).removeInternal(path.mid(sepIndex + 1));
|
||||
}
|
||||
switch (remStatus)
|
||||
{
|
||||
switch (remStatus) {
|
||||
case Failed:
|
||||
case HasChildren:
|
||||
{
|
||||
case HasChildren: {
|
||||
return remStatus;
|
||||
}
|
||||
case Succeeded:
|
||||
{
|
||||
case Succeeded: {
|
||||
children.remove(childToRemove);
|
||||
if(m_contained)
|
||||
{
|
||||
if (m_contained) {
|
||||
return HasChildren;
|
||||
}
|
||||
if(children.size())
|
||||
{
|
||||
if (children.size()) {
|
||||
return HasChildren;
|
||||
}
|
||||
return Succeeded;
|
||||
@ -292,7 +224,7 @@ private:
|
||||
return Failed;
|
||||
}
|
||||
|
||||
private:
|
||||
QMap<QString,SeparatorPrefixTree<Tseparator>> children;
|
||||
private:
|
||||
QMap<QString, SeparatorPrefixTree<Tseparator>> children;
|
||||
bool m_contained = false;
|
||||
};
|
||||
|
Reference in New Issue
Block a user