Skip to content
Snippets Groups Projects
tree.hpp 26.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jan Trávníček's avatar
    Jan Trávníček committed
     * bidirectional_tree.hpp
    
     *
     * Created on: Jul 2, 2016
     * Author: Jan Travnicek
     */
    
    #ifndef __TREE_HPP_
    #define __TREE_HPP_
    
    namespace std {
    
    
    template < class T, class ArityChecker = AnyArity < T > >
    class tree {
    
    	ArityChecker arityChecker;
    
    	struct tree_node {
    		T data;
    
    		tree_node * parent;
    		std::vector < tree_node > children;
    
    
    		tree_node ( const T & data, const std::vector < tree_node > & children ) : data ( data ), parent ( nullptr ), children ( children ) {
    
    			for ( tree_node & child : this->children )
    				child.parent = this;
    		}
    
    
    		tree_node ( T && data, std::vector < tree_node > && children ) : data ( std::move ( data ) ), parent ( nullptr ), children ( std::move ( children ) ) {
    
    			for ( tree_node & child : this->children )
    				child.parent = this;
    		}
    
    
    		template < class AnotherArityChecker >
    		tree_node ( const typename tree < T, AnotherArityChecker >::tree_node & node, const AnotherArityChecker & arityChecker ) : data ( node.data ), parent ( nullptr ), children ( ) {
    			// INFO: The AnotherArityChecker parameter is there only to deduce the template parameter, it cannot be used to check that resulting tree_node comply with the arity checker of the resulting tree because it is different
    			for ( const typename tree < T, AnotherArityChecker >::tree_node & child : node.children ) {
    				children.push_back ( tree_node ( child, arityChecker ) );
    				children [ children.size ( ) - 1 ].parent = this;
    			}
    		}
    
    		template < class AnotherArityChecker >
    		tree_node ( typename tree < T, AnotherArityChecker >::tree_node && node, const AnotherArityChecker & arityChecker ) : data ( std::move ( node.data ) ), parent ( nullptr ), children ( ) {
    			// INFO: The AnotherArityChecker parameter is there only to deduce the template parameter, it cannot be used to check that resulting tree_node comply with the arity checker of the resulting tree because it is different
    			for ( typename tree < T, AnotherArityChecker >::tree_node & child : node.children ) {
    				children.push_back ( tree_node ( std::move ( child ), arityChecker ) );
    				children [ children.size ( ) - 1 ].parent = this;
    			}
    		}
    
    
    		~tree_node ( ) noexcept {
    		}
    
    		tree_node ( const tree_node & node ) : data ( node.data ), parent ( node.parent ), children ( node.children ) {
    			for ( tree_node & child : children )
    				child.parent = this;
    		}
    
    		tree_node ( tree_node && node ) noexcept : data ( std::move ( node.data ) ), parent ( node.parent ), children ( std::move ( node.children ) ) {
    			for ( tree_node & child : children )
    				child.parent = this;
    		}
    
    		tree_node & operator =( const tree_node & node ) {
    			return this->operator =( tree_node ( node ) );
    		}
    
    		tree_node & operator =( tree_node && node ) noexcept {
    			data = std::move ( node.data );
    			children = std::move ( node.children );
    
    			for ( tree_node & child : children )
    				child.parent = this;
    
    			return * this;
    		}
    
    		tree_node * getParent ( ) {
    			return parent;
    		}
    
    		const tree_node * getParent ( ) const {
    			return parent;
    		}
    
    		T & getData ( ) {
    			return data;
    		}
    
    		const T & getData ( ) const {
    			return data;
    		}
    
    		std::vector < tree_node > & getChildren ( ) {
    			return children;
    		}
    
    		const std::vector < tree_node > & getChildren ( ) const {
    			return children;
    		}
    
    
    		void nicePrint ( std::ostream & os, const std::string & prefix, const bool last ) const {
    			os << prefix;
    
    			std::string nextPrefix ( prefix );
    
    			if ( last ) {
    				os << "\\-";
    				nextPrefix += "  ";
    			} else {
    				os << "|-";
    				nextPrefix += "| ";
    			}
    
    			os << getData ( ) << std::endl;
    
    			for ( unsigned int i = 0; i < children.size ( ); ++i ) {
    				os << nextPrefix << "|" << std::endl;
    				children[i].nicePrint ( os, nextPrefix, i == children.size ( ) - 1 );
    			}
    		}
    
    		friend struct tree_node;
    
    
    	};
    
    	tree_node root;
    
    	std::vector < tree_node > fromTree ( const std::vector < tree < T, ArityChecker > > & input ) {
    		std::vector < tree_node > res;
    
    		for ( const tree < T, ArityChecker > & subtree : input )
    			res.push_back ( subtree.root );
    
    		return res;
    	}
    
    public:
    	class const_children_iterator : public std::iterator < std::bidirectional_iterator_tag, T > {
    		typename std::vector < tree_node >::const_iterator node;
    
    	public:
    		const_children_iterator ( typename std::vector < tree_node >::const_iterator node ) : node ( node ) {
    		}
    
    		const_children_iterator ( const const_children_iterator & other ) : node ( other.node ) {
    		}
    
    		const_children_iterator & operator ++( ) {
    			++node;
    			return * this;
    		}
    
    		const_children_iterator operator ++( int ) {
    			const_children_iterator tmp ( * this );
    
    			operator ++( );
    			return tmp;
    		}
    
    		const_children_iterator & operator --( ) {
    			--node;
    			return * this;
    		}
    
    		const_children_iterator operator --( int ) {
    			const_children_iterator tmp ( * this );
    
    			operator --( );
    			return tmp;
    		}
    
    		bool operator ==( const const_children_iterator & other ) {
    			return node == other.node;
    		}
    
    		bool operator !=( const const_children_iterator & other ) {
    			return !( * this == other );
    		}
    
    		const T & operator *( ) const {
    			return node->getData ( );
    		}
    
    
    		const T * operator ->( ) const {
    			return & node->getData ( );
    		}
    
    
    		size_t operator -( const const_children_iterator other ) const {
    			return node - other.node;
    		}
    
    		const_children_iterator begin ( ) const {
    			return node->getChildren ( ).begin ( );
    		}
    
    		const_children_iterator end ( ) const {
    			return node->getChildren ( ).end ( );
    		}
    
    		const_children_iterator parent ( ) const {
    			return typename std::vector < tree_node >::const_iterator ( node->getParent ( ) );
    		}
    
    	private:
    		const tree_node & getTreeNode ( ) const {
    			return * node;
    		}
    
    		typename std::vector < tree_node >::const_iterator getUnderlyingIterator ( ) const {
    			return node;
    		}
    
    		template < class F, class G >
    		friend class tree;
    	};
    
    	class const_structure_iterator : public std::iterator < std::bidirectional_iterator_tag, T > {
    		typename std::vector < tree_node >::const_iterator node;
    		unsigned level;
    
    		bool virtual_node;
    		bool isEnd;
    
    	public:
    		const_structure_iterator ( typename std::vector < tree_node >::const_iterator node ) : node ( node ), level ( 0 ), virtual_node ( false ), isEnd ( false ) {
    		}
    
    		const_structure_iterator ( const const_structure_iterator & other ) : node ( other.node ), level ( other.level ), virtual_node ( other.virtual_node ) {
    		}
    
    		const_structure_iterator & operator ++( ) {
    			if ( virtual_node ) {
    				const tree_node * parent = node->getParent ( );
    
    				if ( parent != nullptr ) {
    					++node;
    
    					if ( node == parent->getChildren ( ).end ( ) ) {
    						--level;
    						node = typename std::vector < tree_node >::const_iterator ( parent );
    					} else {
    						virtual_node = false;
    					}
    				} else {
    					++node;
    					virtual_node = false;
    					isEnd = true;
    				}
    			} else {
    				typename std::vector < tree_node >::const_iterator newIter = node->getChildren ( ).begin ( );
    
    				if ( newIter != node->getChildren ( ).end ( ) ) {
    					++level;
    					node = newIter;
    				} else {
    					virtual_node = true;
    				}
    			}
    
    			return * this;
    		}
    
    		const_structure_iterator operator ++( int ) {
    			const_structure_iterator tmp ( * this );
    
    			operator ++( );
    			return tmp;
    		}
    
    		const_structure_iterator & operator --( ) {
    			if ( isEnd ) {
    				--node;
    				virtual_node = true;
    				isEnd = false;
    			} else if ( virtual_node ) {
    				typename std::vector < tree_node >::const_iterator newIter = node->getChildren ( ).end ( );
    
    				if ( newIter != node->getChildren ( ).begin ( ) ) {
    					++level;
    					node = newIter;
    					--node;
    				} else {
    					virtual_node = false;
    				}
    			} else {
    				const tree_node * parent = node->getParent ( );
    
    				if ( parent != nullptr ) {
    					if ( node == parent->getChildren ( ).begin ( ) ) {
    						--level;
    						node = typename std::vector < tree_node >::const_iterator ( parent );
    					} else {
    						--node;
    						virtual_node = true;
    					}
    				}
    			}
    
    			return * this;
    		}
    
    		const_structure_iterator operator --( int ) {
    			const_structure_iterator tmp ( * this );
    
    			operator --( );
    			return tmp;
    		}
    
    		bool operator ==( const const_structure_iterator & other ) {
    			return node == other.node && virtual_node == other.virtual_node;
    		}
    
    		bool operator !=( const const_structure_iterator & other ) {
    			return !( * this == other );
    		}
    
    		const T & operator *( ) const {
    			return node->getData ( );
    		}
    
    
    		const T * operator ->( ) const {
    			return & node->getData ( );
    		}
    
    
    		unsigned getLevel ( ) const {
    			return level;
    		}
    
    		bool getVirtual ( ) const {
    			return virtual_node;
    		}
    
    	private:
    		const tree_node & getTreeNode ( ) const {
    			return * node;
    		}
    
    		typename std::vector < tree_node >::const_iterator getUnderlyingIterator ( ) const {
    			return node;
    		}
    
    		template < class F, class G >
    		friend class tree;
    	};
    
    	class const_prefix_iterator : public std::iterator < std::bidirectional_iterator_tag, T > {
    		const_structure_iterator node;
    
    	public:
    		const_prefix_iterator ( typename std::vector < tree_node >::const_iterator node ) : node ( node ) {
    		}
    
    		const_prefix_iterator ( const const_prefix_iterator & other ) : node ( other.node ) {
    		}
    
    		const_prefix_iterator & operator ++( ) {
    			while ( ( ++node ).getVirtual ( ) );
    
    			return * this;
    		}
    
    		const_prefix_iterator operator ++( int ) {
    			const_prefix_iterator tmp ( * this );
    
    			operator ++( );
    			return tmp;
    		}
    
    		const_prefix_iterator & operator --( ) {
    			while ( ( --node ).getVirtual ( ) );
    
    			return * this;
    		}
    
    		const_prefix_iterator operator --( int ) {
    			const_prefix_iterator tmp ( * this );
    
    			operator --( );
    			return tmp;
    		}
    
    		bool operator ==( const const_prefix_iterator & other ) {
    			return node == other.node;
    		}
    
    		bool operator !=( const const_prefix_iterator & other ) {
    			return !( * this == other );
    		}
    
    		const T & operator *( ) const {
    			return * node;
    		}
    
    
    		const T * operator ->( ) const {
    			return & node->getData ( );
    		}
    
    
    		unsigned getLevel ( ) const {
    			return node.getLevel ( );
    		}
    
    	private:
    		const tree_node & getTreeNode ( ) const {
    			return node.getTreeNode ( );
    		}
    
    		typename std::vector < tree_node >::const_iterator getUnderlyingIterator ( ) const {
    			return node.getUnderlyingIterator;
    		}
    
    		template < class F, class G >
    		friend class tree;
    	};
    
    	class const_postfix_iterator : public std::iterator < std::bidirectional_iterator_tag, T > {
    		const_structure_iterator node;
    
    	public:
    		const_postfix_iterator ( typename std::vector < tree_node >::const_iterator node ) : node ( node ) {
    		}
    
    		const_postfix_iterator ( const const_postfix_iterator & other ) : node ( other.node ) {
    		}
    
    		const_postfix_iterator & operator ++( ) {
    			while ( !( ++node ).getVirtual ( ) && !node.isEnd );
    
    			return * this;
    		}
    
    		const_postfix_iterator operator ++( int ) {
    			const_postfix_iterator tmp ( * this );
    
    			operator ++( );
    			return tmp;
    		}
    
    		const_postfix_iterator & operator --( ) {
    			while ( !( --node ).getVirtual ( ) );
    
    			return * this;
    		}
    
    		const_postfix_iterator operator --( int ) {
    			const_postfix_iterator tmp ( * this );
    
    			operator --( );
    			return tmp;
    		}
    
    		bool operator ==( const const_postfix_iterator & other ) {
    			return node == other.node;
    		}
    
    		bool operator !=( const const_postfix_iterator & other ) {
    			return !( * this == other );
    		}
    
    		const T & operator *( ) const {
    			return * node;
    		}
    
    
    		const T * operator ->( ) const {
    			return & node->getData ( );
    		}
    
    
    		unsigned getLevel ( ) const {
    			return node.getLevel ( );
    		}
    
    	private:
    		const tree_node & getTreeNode ( ) const {
    			return node.getTreeNode ( );
    		}
    
    		typename std::vector < tree_node >::const_iterator getUnderlyingIterator ( ) const {
    			return node.getUnderlyingIterator ( );
    		}
    
    		template < class F, class G >
    		friend class tree;
    	};
    
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	void checkArities ( const tree_node & node ) const {
    		if ( !arityChecker ( node.getData ( ), node.getChildren ( ).size ( ) ) )
    			throw std::length_error ( "Invalid number of children" );
    
    		for ( const tree_node & child : node.getChildren ( ) )
    			checkArities ( child );
    	}
    
    	void checkArities ( ) const {
    		return checkArities ( root );
    	}
    
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    private:
    	const_children_iterator insert_helper ( const_children_iterator under, const_children_iterator position, const_children_iterator begin, const_children_iterator end ) {
    		tree_node * under_node = const_cast < tree_node * > ( & under.getTreeNode ( ) );
    		std::vector < tree_node > & children = const_cast < std::vector < tree_node > & > ( under_node->getChildren ( ) );
    
    		size_t insertedSize = end - begin;
    
    		if ( !arityChecker ( * under, children.size ( ) + insertedSize ) )
    
    			throw std::length_error ( "Invalid number of children" );
    
    
    		std::vector < tree_node > inserted;
    
    		for ( const_children_iterator beginCopy = begin; beginCopy != end; ++beginCopy )
    			inserted.push_back ( beginCopy.getTreeNode ( ) );
    
    		typename std::vector < tree_node >::iterator iter = children.insert ( position.getUnderlyingIterator ( ), inserted.begin ( ), inserted.end ( ) );
    
    		for ( typename std::vector < tree_node >::iterator iterCopy = iter; begin != end; ++begin, ++iterCopy )
    			iterCopy->parent = under_node;
    
    		typename std::vector < tree_node >::const_iterator citer = iter;
    		return citer;
    	}
    
    public:
    	const_children_iterator insert ( const_children_iterator under, const_children_iterator position, const tree < T, ArityChecker > & value ) {
    		std::vector < tree_node > & children = const_cast < std::vector < tree_node > & > ( under.getTreeNode ( ).getChildren ( ) );
    
    		typename std::vector < tree_node >::iterator iter = children.insert ( position.getUnderlyingIterator ( ), value.root );
    		iter->parent = const_cast < tree_node * > ( & under.getTreeNode ( ) );
    		typename std::vector < tree_node >::const_iterator res = iter;
    		return res;
    	}
    
    	const_children_iterator insert ( const_children_iterator under, const_children_iterator position, tree < T, ArityChecker > && value ) {
    		std::vector < tree_node > & children = const_cast < std::vector < tree_node > & > ( under.getTreeNode ( ).getChildren ( ) );
    
    		typename std::vector < tree_node >::iterator iter = children.insert ( position.getUnderlyingIterator ( ), std::move ( value.root ) );
    		iter->parent = const_cast < tree_node * > ( & under.getTreeNode ( ) );
    		typename std::vector < tree_node >::const_iterator res = iter;
    		return res;
    	}
    
    	template < class Iterator >
    	const_children_iterator insert ( const_children_iterator under, const_children_iterator position, Iterator begin, Iterator end ) {
    		std::vector < tree_node > children;
    
    		for ( ; begin != end; ++begin )
    			children.push_back ( tree_node ( * begin, { } ) );
    
    		return insert_helper ( under, position, children.cbegin ( ), children.cend ( ) );
    	}
    
    	const_children_iterator insert ( const_children_iterator under, const_children_iterator position, const_children_iterator begin, const_children_iterator end ) {
    		return insert_helper ( under, position, begin, end );
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    public:
    	tree ( const T & data, const std::vector < tree < T, ArityChecker > > & subtrees, ArityChecker arityChecker = ArityChecker ( ) ) : arityChecker ( arityChecker ), root ( data, fromTree ( subtrees ) ) {
    		if ( !arityChecker ( data, subtrees.size ( ) ) )
    
    			throw std::length_error ( "Invalid number of children" );
    
    	}
    
    	template < typename ... Types >
    	tree ( const T & data, Types ... subtrees, ArityChecker arityChecker ) : tree ( data, std::vector < tree < T, ArityChecker > > { subtrees ... }, arityChecker ) {
    	}
    
    	template < typename ... Types >
    	tree ( const T & data, Types ... subtrees ) : tree ( data, std::vector < tree < T, ArityChecker > > { subtrees ... }, ArityChecker ( ) ) {
    	}
    
    	template < typename Iterator, typename std::enable_if < std::is_iterator < Iterator >::value >::type >
    	tree ( const T & data, Iterator begin, Iterator end ) : root ( data, { } ) {
    		std::vector < tree_node > children;
    
    		for ( ; begin != end; ++begin )
    			children.push_back ( tree_node ( * begin, { } ) );
    
    		insert_helper ( begin ( ), begin ( ).end ( ), children.cbegin ( ), children.cend ( ) );
    	}
    
    	tree ( const T & data, const_children_iterator begin, const_children_iterator end ) : root ( data, { } ) {
    		insert_helper ( begin ( ), begin ( ).end ( ), begin, end );
    	}
    
    
    	template < class AnotherArityChecker = AnyArity < T > >
    	tree ( const tree < T, AnotherArityChecker > & other, ArityChecker arityChecker = ArityChecker ( ) ) : arityChecker ( arityChecker ), root ( other.root, AnotherArityChecker ( ) ) {
    		checkArities ( );
    	}
    
    	template < class AnotherArityChecker = AnyArity < T > >
    	tree ( tree < T, AnotherArityChecker > && other, ArityChecker arityChecker = ArityChecker ( ) ) : arityChecker ( arityChecker ), root ( std::move ( other.root ), AnotherArityChecker ( ) ) {
    		checkArities ( );
    	}
    
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	const_children_iterator begin ( ) const {
    		return typename std::vector < tree_node >::const_iterator ( & root );
    	}
    
    	const_children_iterator end ( ) const {
    		return typename std::vector < tree_node >::const_iterator ( & root + 1 );
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	const_prefix_iterator prefix_begin ( ) const {
    		return typename std::vector < tree_node >::const_iterator ( & root );
    	}
    
    	const_prefix_iterator prefix_end ( ) const {
    		const_prefix_iterator res ( typename std::vector < tree_node >::const_iterator ( & root + 1 ) );
    
    		res.node.isEnd = true;
    		return res;
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	const_postfix_iterator postfix_begin ( ) const {
    		const_postfix_iterator res { typename std::vector < tree_node >::const_iterator ( & root ) };
    
    		while ( !( res.node ).getVirtual ( ) ) ++res.node;
    
    		return res;
    	}
    
    	const_postfix_iterator postfix_end ( ) const {
    		const_postfix_iterator res ( typename std::vector < tree_node >::const_iterator ( & root + 1 ) );
    
    		res.node.isEnd = true;
    		return res;
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	const_structure_iterator structure_begin ( ) const {
    		return typename std::vector < tree_node >::const_iterator ( & root );
    	}
    
    	const_structure_iterator structure_end ( ) const {
    		const_structure_iterator res ( typename std::vector < tree_node >::const_iterator ( & root + 1 ) );
    
    		res.isEnd = true;
    		return res;
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	void push_back ( const_children_iterator under, const T & value ) {
    		std::vector < tree_node > & children = const_cast < std::vector < tree_node > & > ( under.getTreeNode ( ).getChildren ( ) );
    
    		if ( !arityChecker ( * under, children.size ( ) + 1 ) )
    
    			throw std::length_error ( "Invalid number of children" );
    
    
    		children.push_back ( tree_node ( value, { } ) );
    		std::prev ( children.end ( ) )->parent = const_cast < tree_node * > ( & under.getTreeNode ( ) );
    	}
    
    	void push_back ( const_children_iterator under, T && value ) {
    		std::vector < tree_node > & children = const_cast < std::vector < tree_node > & > ( under.getTreeNode ( ).getChildren ( ) );
    
    		if ( !arityChecker ( * under, children.size ( ) + 1 ) )
    
    			throw std::length_error ( "Invalid number of children" );
    
    
    		children.push_back ( tree_node ( std::move ( value ), { } ) );
    		std::prev ( children.end ( ) )->parent = const_cast < tree_node * > ( & under.getTreeNode ( ) );
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	const_children_iterator erase ( const_children_iterator under, const_children_iterator position ) {
    		std::vector < tree_node > & children = const_cast < std::vector < tree_node > & > ( under.getTreeNode ( ).getChildren ( ) );
    
    		if ( !arityChecker ( * under, children.size ( ) - 1 ) )
    
    			throw std::length_error ( "Invalid number of children" );
    
    
    		typename std::vector < tree_node >::iterator iter = children.erase ( position.getUnderlyingIterator ( ) );
    		typename std::vector < tree_node >::const_iterator res = iter;
    		return res;
    	}
    
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    
    	template < class ... Indexes >
    	const T & operator ()( Indexes ... indexes ) const {
    		const tree_node * node = & root;
    
    		( void ) std::initializer_list < int > { ( node = & node->getChildren ( )[indexes], 0 ) ... };
    
    		return node->getData ( );
    	}
    
    private:
    	class SubscriptAccess {
    		tree_node * node;
    		const ArityChecker & arityChecker;
    
    	public:
    		SubscriptAccess ( tree_node * node, const ArityChecker & arityChecker ) : node ( node ), arityChecker ( arityChecker ) {
    		}
    
    		SubscriptAccess ( const SubscriptAccess & ) = delete;
    		SubscriptAccess ( SubscriptAccess && ) = delete;
    
    		SubscriptAccess & operator =( const SubscriptAccess & ) = delete;
    		SubscriptAccess & operator =( SubscriptAccess && ) = delete;
    
    		operator const T &( ) {
    			return node->getData ( );
    		}
    
    		SubscriptAccess & operator =( const T & data ) {
    			if ( !arityChecker ( data, node->getChildren ( ).size ( ) ) )
    
    				throw std::length_error ( "Invalid number of children" );
    
    
    			node->getData ( ) = data;
    
    			return * this;
    		}
    
    		SubscriptAccess & operator =( const tree < T, ArityChecker > & data ) {
    			* node = data.root;
    
    			return * this;
    		}
    
    		friend void swap ( SubscriptAccess && first, SubscriptAccess && second ) {
    			tree_node tmp = std::move ( * first.node );
    
    			* first.node = std::move ( * second.node );
    			* second.node = std::move ( tmp );
    		}
    
    	};
    
    public:
    	template < class ... Indexes >
    	SubscriptAccess operator ()( Indexes ... indexes ) {
    		tree_node * node = & root;
    
    		( void ) std::initializer_list < int > { ( node = & node->getChildren ( )[indexes], 0 ) ... };
    
    		return { node, arityChecker };
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	bool checkStructure ( const tree_node & node ) const {
    		bool sign = true;
    
    		for ( const tree_node & child : node.getChildren ( ) )
    			sign &= child.getParent ( ) == & node && checkStructure ( child );
    
    		return sign;
    	}
    
    	bool checkStructure ( ) const {
    		return root.parent == nullptr && checkStructure ( root );
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	friend void swap ( tree & first, tree & second ) {
    		swap ( std::move ( first ( ) ), std::move ( second ( ) ) );
    	}
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	int compare ( const tree & other ) const {
    		std::compare < typename std::decay < T >::type > comp;
    		auto iterF = this->prefix_begin ( );
    		auto iterS = other.prefix_begin ( );
    
    		for ( ; iterF != this->prefix_end ( ) || iterS != other.prefix_end ( ); ++iterF, ++iterS ) {
    			int res = comp ( * iterF, * iterS );
    
    			if ( res != 0 ) return res;
    		}
    
    		if ( iterF != this->prefix_end ( ) ) return -1;
    
    		if ( iterS != other.prefix_end ( ) ) return 1;
    
    		return 0;
    	}
    
    	bool operator ==( const tree & other ) {
    		return compare ( other ) == 0;
    	}
    
    	bool operator !=( const tree & other ) {
    		return compare ( other ) != 0;
    	}
    
    	bool operator <( const tree & other ) {
    		return compare ( other ) < 0;
    	}
    
    	bool operator <=( const tree & other ) {
    		return compare ( other ) <= 0;
    	}
    
    	bool operator >( const tree & other ) {
    		return compare ( other ) > 0;
    	}
    
    	bool operator >=( const tree & other ) {
    		return compare ( other ) >= 0;
    	}
    
    
    // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    
    	std::ostream & nicePrint ( std::ostream & os ) const {
    		root.nicePrint ( os, "", true );
    		return os;
    	}
    
    
    	template < class R, class AnotherArityChecker >
    	friend class tree;
    
    
    };
    
    template < class T, class ... Ts >
    std::ostream & operator <<( std::ostream & out, const tree < T, Ts ... > & t ) {
    	out << "[";
    
    	unsigned level = 0;
    
    	for ( typename tree < T, Ts ... >::const_prefix_iterator iter = t.prefix_begin ( ); iter != t.prefix_end ( ); ) {
    		while ( iter.getLevel ( ) > level ) {
    			out << "[";
    			++level;
    		}
    
    		out << level << * iter;
    		++iter;
    
    		bool printComma = iter.getLevel ( ) == level;
    
    		while ( iter.getLevel ( ) < level ) {
    			out << "]";
    			--level;
    			printComma = true;
    		}
    
    		if ( printComma && ( level != 0 ) )
    			out << ",";
    	}
    
    	out << "]";
    	return out;
    }
    
    template < class T, class ... Ts >
    struct compare < tree < T, Ts ... > > {
    	int operator ()( const tree < T, Ts ... > & first, const tree < T, Ts ... > & second ) const {
    		return first.compare ( second );
    	}
    
    };
    
    
    } /* namespace std */
    
    #endif /* __TREE_HPP_ */