Files
xtree.ng.zwo/nodes/znode.h
2025-08-13 18:30:47 +02:00

402 lines
9.6 KiB
C++

/***************************************************************************
source::worx xtree
Copyright © 2024-2025 c.holzheuer
christoph.holzheuer@gmail.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#ifndef ZNODE_H
#define ZNODE_H
#include <vector>
#include <string>
#include <memory>
//#include <typeinfo>
#include <QString>
#include <QDebug>
#include <xqmaptor.h>
#include <xsingleton.h>
#include <znode_iterator.h>
//#include <znode_vector.h>
#include <znode_id.h>
#include <znode_payload.h>
namespace znode
{
/// ----------------- snip 8< -----------------------------------------------------------------------------------------------------------------------------
// forward declaration of base class zbasic_node ...
//template<class str_t>
//class zbasic_node;
// ... used here for conveniance typedef
//template<class str_t>
//using zshared_node = std::shared_ptr<zbasic_node<str_t>>;
// main class
template<class str_t>
class zbasic_node : public zid, public zpayload<str_t>, public std::enable_shared_from_this<zbasic_node<str_t>>
{
public:
using str_cref = const str_t&;
using str_list = std::vector<str_t>;
//using zshared_node = std::shared_ptr<zbasic_node>;
//using znode_list = znode_vector<zbasic_node>;
//using znode_list = znode_vector<zshared_node<str_t>>;
//using znode_list = std::vector<zshared_node<str_t>>;
using zweak_node = std::weak_ptr<zbasic_node>;
using zshared_node = std::shared_ptr<zbasic_node>;
using znode_list = std::vector<zshared_node>;
using zshared_cref = const std::shared_ptr<zbasic_node>&;
//using ziterator = znode_iterator<zshared_node>;
using ziterator = znode_iterator<zbasic_node>;
protected:
//zbasic_node* _parent;
zweak_node _parent;
znode_list _children;
struct match_id
{
match_id( int match )
: _match{match}
{}
bool operator()( zshared_node node )
{
return _match == node->_id;
}
int _match{};
};
public:
static zshared_node make_node( str_cref arg1, str_cref arg2 = "" , zshared_cref parent = nullptr )
{
return std::make_shared<zbasic_node>( arg1, arg2, parent );
}
zbasic_node() = default;
// ...
zbasic_node( str_cref tag_name, zshared_cref parent = nullptr )
//zbasic_node( str_cref tag_name, zbasic_node* parent = nullptr )
: zpayload<str_t>{tag_name}, _parent{parent}
{
//_parent = parent;
}
// ...
zbasic_node( str_cref tag_name, str_cref value, zshared_cref parent = nullptr )
//zbasic_node( str_cref tag_name, str_cref value, zbasic_node* parent = nullptr )
: zpayload<str_t>{tag_name,value}
{
_parent = parent;
}
zbasic_node( str_cref tag_name, const str_list& attributes, zshared_cref parent = nullptr )
: zbasic_node{tag_name, parent}
{
for( str_cref entry : attributes )
{
str_t key_value, data_value;
if( xstr_split_by( entry, "=", key_value, data_value) )
set_attribute( key_value, data_value );
}
}
virtual ~zbasic_node()
{
_children.clear();
}
/*
virtual zbasic_node* clone() const
{
// start a new node hierarchy with the existing parent
zbasic_node* new_me = new zbasic_node( _tag_name, _value, _parent );
new_me->_attributes = _attributes;
//new_me->_id = _id;
// clone my children with myself as new parent.
for( zbasic_node* child : _children )
new_me->children().push_back( child->clone( new_me ) );
return new_me;
}
*/
/*
virtual zbasic_node* clone(zbasic_node* new_parent) const
{
zbasic_node* new_me = new zbasic_node(_tag_name, _value, new_parent );
new_me->_attributes = _attributes;
for (zbasic_node* child : _children)
new_me->children().push_back(child->clone( new_me ));
return new_me;
}
*/
// STL-ish traverse iterators
auto begin()
{
return ziterator(this);
}
auto end()
{
return ziterator(nullptr);
}
// ... set_int
// ... as_int
//zweak_node parent()
zshared_node parent()
{
return _parent.lock();
}
//void set_parent( zbasic_node* parent )
void set_parent( zshared_node parent )
{
_parent = parent;
}
zshared_node sibling()
{
if( !parent() )
//return zshared_node( make_node("WTF1") );
return zshared_node();
znode_list& childs = parent()->_children;
auto it = std::find( childs.begin(), childs.end(), this->shared_from_this() );
if( ++it != childs.end())
return *(it);
//return zshared_node( make_node("WTF?") );
return zshared_node();
}
inline const znode_list& children() const
{
return _children;
}
bool has_children() const
{
return !children().empty();
}
zshared_node first_child()
{
if(!children().empty())
return children().front();
return nullptr;
}
zshared_node last_child()
{
if(!children().empty())
return children().back();
return nullptr;
}
zshared_node child( int idx )
{
if(idx>-1 && idx<children().size())
return _children[idx];
return nullptr;
}
int add_child( zshared_node node )
{
_children.push_back( node );
node->set_parent( this->shared_from_this() );
return int(children().size() - 1);
}
int add_child_at( int idx, zshared_node node )
{
_children.insert(children().begin() + idx, node );
node->set_parent( this->shared_from_this() );
return int(children().size() - 1);
}
int own_pos()
{
auto pos = parent()->child_pos(_id);
if( pos == parent()->children().end() )
throw std::runtime_error("own_pos: own id not found!");
return std::distance( parent()->children().begin(), pos );
}
inline auto child_pos(int node_id)
{
// fix!
return std::find_if(children().begin(), children().end(), match_id(node_id));
return children().end();
}
void add_me_at_id( int id )
{
auto pos = parent()->child_pos( id );
if( pos != parent()->children().end() )
parent()->_children.insert( pos, this->shared_from_this() );
}
void add_me_at_pos( int offset )
{
auto pos = parent()->children().begin();
parent()->_children.insert( pos + offset, this->shared_from_this() );
}
zshared_node find_child_by_attribute(str_cref attrkey, str_cref attrvalue )
{
for( auto child : _children )
{
qDebug() << " --#- " << child->name() << " : " << child->has_attribute( attrkey, attrvalue );
if( child->has_attribute( attrkey, attrvalue ))
return child;
}
return zshared_node();
}
zshared_node find_child_by_tag_name(str_cref tagname )
{
for( auto child : _children )
{
if( child->tag_name() == tagname )
return child;
}
return zshared_node();
}
zshared_node find_child_by_id( int id )
{
for (auto child : _children )
{
if (child->_id == id)
return child;
}
return zshared_node();
}
void unlink_child( zshared_node node )
{
/*
* fix!
zbasic_node* child = nullptr;
auto pos = child_pos(node->_id);
if( pos != children().end() )
{
child = *pos;
qDebug() << " --- delete child: _id: " << child->_id;
children().erase( pos );
}
*/
}
void unlink_self()
{
parent()->unlink_child( this->shared_from_this() );
}
void dump(int indent = 0) const
{
// fix_me!
qDebug() << std::string(indent * 2, ' ').c_str() << this->to_string();
//qDebug() << to_string();
//qDebug() << '\n';// std::endl;
if (!children().empty())
{
for (auto child : _children)
{
//qDebug() << " --- type: " << typeid(child).name();
child.get()->dump( indent + 1 );
}
}
}
template<typename T>
bool for_each_x( T func, int depth = 0 )
//bool for_each( auto func ) const
{
if( !apply( func, depth ) )
return false;
if( !children().empty() )
{
for( auto child : _children )
{
if( !child->for_each( func, depth+1 ) )
return false;
}
}
return true;
}
// find ...
// depth first ...
// by attr
// by child
// by value
// by find( auto xxx )
// ...
};
class zbasic_node_walker
{
public:
virtual void begin()
{}
template<class str_t>
void for_each_node( zbasic_node<str_t>* node );
virtual void end()
{}
};
} //namespace znode
#endif // zplain_node_H