/*************************************************************************** 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 #include #include //#include #include #include #include #include #include //#include #include #include namespace znode { /// ----------------- snip 8< ----------------------------------------------------------------------------------------------------------------------------- // forward declaration of base class zbasic_node ... //template //class zbasic_node; // ... used here for conveniance typedef //template //using zshared_node = std::shared_ptr>; // main class template class zbasic_node : public zid, public zpayload, public std::enable_shared_from_this> { public: using str_cref = const str_t&; using str_list = std::vector; //using zshared_node = std::shared_ptr; //using znode_list = znode_vector; //using znode_list = znode_vector>; //using znode_list = std::vector>; using zweak_node = std::weak_ptr; using zshared_node = std::shared_ptr; using znode_list = std::vector; using zshared_cref = const std::shared_ptr&; //using ziterator = znode_iterator; using ziterator = znode_iterator; 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( 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{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{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 && idxset_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 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 void for_each_node( zbasic_node* node ); virtual void end() {} }; } //namespace znode #endif // zplain_node_H