← Back to file list Raw

src/CNode.h

#pragma once
#include <map>
#include <string>
#include <sstream>
#include <memory>
#include <vector>
#include <functional>
#include <unordered_map>
#include "U_String.h"
template<typename T>
class CNode
{
public:
CNode<T>* Parent = nullptr;
std::string Name;
CNode() = default;
CNode(const std::string& name, CNode<T>* parent) : Name(name), Parent(parent) {}
std::unordered_map<std::string, std::unique_ptr<CNode>> Children;
T Value;
std::string GetPath() const
{
const CNode<T>* curr = this;
std::string path;
while(curr)
{
if(!curr->Name.empty())
{
path.insert(0, ("." + curr->Name));
}
curr = curr->Parent;
}
if(!path.empty())
{
path.erase(path.begin());
}
return path;
}
void Trace(const std::function<void(const CNode<T>* nod)>& func, bool first_parent = true)
{
if(first_parent)
{
func(this);
}
for(auto& kv : Children)
{
kv.second->Trace(func, first_parent);
}
if(!first_parent)
{
func(this);
}
}
CNode<T>* GetNode(const std::string& path) const
{
std::vector<std::string> nodes;
StringUtils::split_str(path, '.', nodes);
if (nodes.empty()) { return nullptr; }
const CNode<T>* current = this;
for (std::string& nod : nodes)
{
if(StringUtils::IsEmpty(nod)) { continue; }
auto it = current->Children.find(nod);
if (it == current->Children.end())
{
return nullptr;
}
current = it->second.get();
}
return const_cast<CNode<T>*>(current); //HACK
}
void DeleteNode(CNode<T>* nod, bool cleanup_nodes = true) //TODO fix (maybe cleanup_nodes should be done before deleting the nod itself?)
{
if (nod == nullptr || nod->Parent == nullptr)
{
return;
}
auto it = nod->Parent->Children.begin();
while (it != nod->Parent->Children.end())
{
if (it->second.get() == nod)
{
break;
}
++it;
}
if (it != nod->Parent->Children.end())
{
nod->Parent->Children.erase(it);
}
if (cleanup_nodes)
{
CNode<T>* current = nod->Parent;
while (current != nullptr && current->Children.empty())
{
CNode<T>* parent = current->Parent;
if (parent != nullptr)
{
auto it = parent->Children.begin();
while (it != parent->Children.end())
{
if (it->second.get() == current)
{
parent->Children.erase(it);
break;
}
++it;
}
}
current = parent;
}
}
}
CNode<T>* CreateNode(const std::string& path)
{
std::istringstream stream(path);
std::string segment;
CNode<T>* current = this;
while (std::getline(stream, segment, '.'))
{
if (current->Children.find(segment) == current->Children.end())
{
current->Children[segment] = std::make_unique<CNode<T>>(segment, current);
}
current = current->Children[segment].get();
}
return current;
}
};