Skip to content
Snippets Groups Projects
tree.hpp 13.4 KiB
Newer Older
/*
 * tree.hpp
 *
 * Created on: Jul 2, 2016
 * Author: Jan Travnicek
 */

#ifndef __TREE_HPP_
#define __TREE_HPP_

namespace std {

template < class Data >
class BaseNode {
	Data * parent;

	template < class D, class CD, class C >
	friend class NullaryNode;
	template < class D, class CD, class C >
	friend class UnaryNode;
	template < class D, class CD, class C >
	friend class BinaryNode;
	template < class D, class CD, class C >
	friend class TernaryNode;
	template < class D, int I, class CD, class C >
	friend class AnyaryNode;
	template < class D, class CD, class C >
	friend class FixedaryNode;
	template < class D, class CD, class C >
	friend class VararyNode;

	Data * operator ->( ) {
		return static_cast < Data * > ( this );
	}

	const Data * operator ->( ) const {
		return static_cast < Data * > ( this );
	}

public:
	BaseNode ( ) : parent ( nullptr ) {
	}

	virtual ~BaseNode ( ) noexcept {
	}

	BaseNode ( const BaseNode & ) : parent ( nullptr ) {
	}

	BaseNode ( BaseNode && ) noexcept : parent ( nullptr ) {
	}

	BaseNode & operator =( const BaseNode & ) {
		return * this;
	}

	BaseNode & operator =( BaseNode && ) noexcept {
		return * this;
	}

	Data * getParent ( ) {
		return parent;
	}

	const Data * getParent ( ) const {
		return parent;
	}

};

Jan Trávníček's avatar
Jan Trávníček committed
template < class Data, int arity, class ConstData = Data, class Cast = Data >
class AnyaryNode {
	typename TupleBuilder < Data, arity >::type children;
Jan Trávníček's avatar
Jan Trávníček committed
	template < std::size_t ... Indices >
	void setParent ( std::index_sequence < Indices ... > ) {
		( void ) std::initializer_list < void * > { std::get < Indices > ( children )->parent = static_cast < Cast * > ( this ) ... };
	}
Jan Trávníček's avatar
Jan Trávníček committed
	AnyaryNode ( typename TupleBuilder < Data, arity >::type children ) : children ( std::move ( children ) ) {
		setParent ( std::make_index_sequence < arity > ( ) );
Jan Trávníček's avatar
Jan Trávníček committed
	virtual ~AnyaryNode ( ) noexcept {
Jan Trávníček's avatar
Jan Trávníček committed
	AnyaryNode ( const AnyaryNode & other ) : AnyaryNode ( other.children ) {
Jan Trávníček's avatar
Jan Trávníček committed
	AnyaryNode ( AnyaryNode && other ) noexcept : AnyaryNode ( std::move ( other.children ) ) {
Jan Trávníček's avatar
Jan Trávníček committed
	AnyaryNode & operator =( const AnyaryNode & other ) {
		return * this = AnyaryNode ( other );
Jan Trávníček's avatar
Jan Trávníček committed
	AnyaryNode & operator =( AnyaryNode && other ) noexcept {
		std::swap ( this->children, other.children );
Jan Trávníček's avatar
Jan Trávníček committed
		setParent ( std::make_index_sequence < arity > ( ) );
Jan Trávníček's avatar
Jan Trávníček committed
	const typename TupleBuilder < Data, arity >::type & getElements ( ) {
		return children;
Jan Trávníček's avatar
Jan Trávníček committed
	const typename TupleBuilder < ConstData, arity >::type & getElements ( ) const {
		return reinterpret_cast < const typename TupleBuilder < ConstData, arity >::type & > ( children );
Jan Trávníček's avatar
Jan Trávníček committed
	template < int N >
	const ConstData & getElement ( ) const {
		return reinterpret_cast < const ConstData & > ( std::get < N > ( children ) );
Jan Trávníček's avatar
Jan Trávníček committed
	}

	template < int N >
	Data & getElement ( ) {
		return std::get < N > ( children );
	}

	void setElements ( typename TupleBuilder < Data, arity >::type children ) {
		children = std::move ( children );
		setParent ( std::make_index_sequence < arity > ( ) );
	}

	template < int N >
	void setElement ( Data d ) {
		std::get < N > ( children ) = std::move ( d );
		std::get < N > ( children )->parent = static_cast < Cast * > ( this );
	}

};

template < class Data, class ConstData = Data, class Cast = Data >
class NullaryNode : public AnyaryNode < Data, 0, ConstData, Cast > {
	NullaryNode ( ) : AnyaryNode < Data, 0, ConstData, Cast > ( std::tuple < > ( ) ) {
Jan Trávníček's avatar
Jan Trávníček committed
template < class Data, class ConstData = Data, class Cast = Data >
class UnaryNode : public AnyaryNode < Data, 1, ConstData, Cast > {
public:
	UnaryNode ( Data c ) : AnyaryNode < Data, 1, ConstData, Cast > ( std::make_tuple ( std::move ( c ) ) ) {
Jan Trávníček's avatar
Jan Trávníček committed
	Data & getChild ( ) {
		return this->template getElement < 0 > ( );
Jan Trávníček's avatar
Jan Trávníček committed
	const ConstData & getChild ( ) const {
		return this->template getElement < 0 > ( );
Jan Trávníček's avatar
Jan Trávníček committed
	void setChild ( Data c ) {
		this->template setElement < 0 > ( std::move ( c ) );
	}
Jan Trávníček's avatar
Jan Trávníček committed
template < class Data, class ConstData = Data, class Cast = Data >
class BinaryNode : public AnyaryNode < Data, 2, ConstData, Cast > {
public:
	BinaryNode ( Data l, Data r ) : AnyaryNode < Data, 2, ConstData, Cast > ( std::make_tuple ( std::move ( l ), std::move ( r ) ) ) {
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 0 > ( );
	}

	const ConstData & getLeft ( ) const {
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 0 > ( );
	}

	void setLeft ( Data l ) {
Jan Trávníček's avatar
Jan Trávníček committed
		this->template setElement < 0 > ( std::move ( l ) );
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 1 > ( );
	}

	const ConstData & getRight ( ) const {
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 1 > ( );
	}

	void setRight ( Data r ) {
Jan Trávníček's avatar
Jan Trávníček committed
		this->template setElement < 1 > ( std::move ( r ) );
	}

};

template < class Data, class ConstData = Data, class Cast = Data >
Jan Trávníček's avatar
Jan Trávníček committed
class TernaryNode : public AnyaryNode < Data, 3, ConstData, Cast > {
Jan Trávníček's avatar
Jan Trávníček committed
	TernaryNode ( Data f, Data s, Data t ) : AnyaryNode < Data, 3, ConstData, Cast > ( std::make_tuple ( std::move ( f ), std::move ( s ), std::move ( t ) ) ) {
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 0 > ( );
	}

	const ConstData & getFirst ( ) const {
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 0 > ( );
	}

	void setFirst ( Data f ) {
Jan Trávníček's avatar
Jan Trávníček committed
		this->template setElement < 0 > ( std::move ( f ) );
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 1 > ( );
	}

	const ConstData & getSecond ( ) const {
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 1 > ( );
	}

	void setSecond ( Data s ) {
Jan Trávníček's avatar
Jan Trávníček committed
		this->template setElement < 1 > ( std::move ( s ) );
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 2 > ( );
	}

	const ConstData & getThird ( ) const {
Jan Trávníček's avatar
Jan Trávníček committed
		return this->template getElement < 2 > ( );
	}

	void setThird ( Data t ) {
Jan Trávníček's avatar
Jan Trávníček committed
		this->template setElement < 2 > ( std::move ( t ) );
	}

};

template < class Data, class ConstData = Data, class Cast = Data >
class FixedaryNode {
	std::vector < Data > children;

public:
	template < typename ... Types >
	FixedaryNode ( Types ... data ) {
		Data args[] { std::move ( data ) ... };

		for ( Data & child : args )
			children.push_back ( std::move ( child ) );

		for ( Data & child : children )
			child->parent = static_cast < Cast * > ( this );
	}

	FixedaryNode ( std::vector < Data > c ) : children ( std::move ( c ) ) {
		for ( Data & child : children )
			child->parent = static_cast < Cast * > ( this );
	}

	virtual ~FixedaryNode ( ) noexcept {
	}

	FixedaryNode ( const FixedaryNode & other ) : FixedaryNode ( other.children ) {
	}

	FixedaryNode ( FixedaryNode && other ) noexcept : FixedaryNode ( std::move ( other.children ) ) {
	}

	FixedaryNode & operator =( const FixedaryNode & other ) {
		return * this = FixedaryNode ( other );
	}

	FixedaryNode & operator =( FixedaryNode && other ) noexcept {
		std::swap ( this->children, other.children );

		for ( Data & child : children )
			child->parent = static_cast < Cast * > ( this );
	std::vector < Data > & getChildren ( ) {
		return children;
	}

	const std::vector < ConstData > & getChildren ( ) const {
		return reinterpret_cast < const std::vector < ConstData > & > ( children );
	}

	void setChildren ( std::vector < Data > c ) {
		if ( c.size ( ) != children.size ( ) )
			throw "Arity != size";

		children = std::move ( c );

		for ( Data & child : children )
			child->parent = static_cast < Cast * > ( this );
	}

	void setChild ( Data d, int index ) {
		if ( children.size ( ) >= index )
			throw "Index out of bounds";

		children[index] = std::move ( d );

		children[index]->parent = static_cast < Cast * > ( this );
	}

};

template < class Data, class ConstData = Data, class Cast = Data >
class VararyNode {
	std::vector < Data > children;

public:
	VararyNode ( std::vector < Data > c ) : children ( std::move ( c ) ) {
		for ( Data & child : children )
			child->parent = static_cast < Cast * > ( this );
	}

	virtual ~VararyNode ( ) noexcept {
	}

	VararyNode ( const VararyNode & other ) : VararyNode ( other.children ) {
	}

	VararyNode ( VararyNode && other ) noexcept : VararyNode ( std::move ( other.children ) ) {
	}

	VararyNode & operator =( const VararyNode & other ) {
		return * this = VararyNode ( other );
	}

	VararyNode & operator =( VararyNode && other ) noexcept {
		std::swap ( this->children, other.children );

		for ( Data & child : children )
			child->parent = static_cast < Cast * > ( this );
	std::vector < Data > & getChildren ( ) {
		return children;
	}

	const std::vector < ConstData > & getChildren ( ) const {
		return reinterpret_cast < const std::vector < ConstData > & > ( children );
	}

	void setChildren ( std::vector < Data > c ) {
		children = std::move ( c );

		for ( Data & child : children )
			child->parent = static_cast < Cast * > ( this );
	}

	void setChild ( Data d, int index ) {
		children[index] = std::move ( d );

		children[index]->parent = static_cast < Cast * > ( this );
	}

	void setChild ( Data d, typename std::vector < Data >::iterator it ) {
		* it = std::move ( d );

		( * it )->parent = static_cast < Cast * > ( this );
	}

	typename std::vector < Data >::iterator insert ( typename std::vector < Data >::iterator it, Data d ) {
		it = children.insert ( it, std::move ( d ) );

		( * std::prev ( it ) ) -> parent = static_cast < Cast * > ( this );

		return it;
	}

	template < class InputIterator >
	typename std::vector < Data >::iterator insert ( typename std::vector < Data >::iterator it, InputIterator first, InputIterator last ) {
		size_t off = it - children.begin ( );
		size_t size = last - first;

		children.insert ( it, first, last );
		it = children.begin ( ) + off;

		 // TODO on g++-4.9 use: it = children->insert( it, first, last );
		typename std::vector < Data >::iterator end = it + size;

		for ( ; it != end; it++ )
			( * it )->parent = static_cast < Cast * > ( this );

		return it;
	}

	void pushBackChild ( Data d ) {
		children.push_back ( std::move ( d ) );
		children[children.size ( ) - 1]->parent = static_cast < Cast * > ( this );
	}

};

template < class Data, class ConstData, class Cast >
class Tree {
public:
	static void setChild ( const UnaryNode < Data, ConstData, Cast > & node, Data child ) {
		const_cast < UnaryNode < Data, ConstData, Cast > & > ( node ).setChild ( std::move ( child ) );
	}

	static void setLeft ( const BinaryNode < Data, ConstData, Cast > & node, Data child ) {
		const_cast < BinaryNode < Data, ConstData, Cast > & > ( node ).setLeft ( std::move ( child ) );
	}

	static void setRight ( const BinaryNode < Data, ConstData, Cast > & node, Data child ) {
		const_cast < BinaryNode < Data, ConstData, Cast > & > ( node ).setRight ( std::move ( child ) );
	}

	static void setFirst ( const TernaryNode < Data, ConstData, Cast > & node, Data child ) {
		const_cast < TernaryNode < Data, ConstData, Cast > & > ( node ).setFirst ( std::move ( child ) );
	}

	static void setSecond ( const TernaryNode < Data, ConstData, Cast > & node, Data child ) {
		const_cast < TernaryNode < Data, ConstData, Cast > & > ( node ).setSecond ( std::move ( child ) );
	}

	static void setThird ( const TernaryNode < Data, ConstData, Cast > & node, Data child ) {
		const_cast < TernaryNode < Data, ConstData, Cast > & > ( node ).setThird ( std::move ( child ) );
	}

	template < int arity >
	static void setChildren ( const AnyaryNode < Data, arity, ConstData, Cast > & node, typename TupleBuilder < Data, arity >::type children ) {
		const_cast < AnyaryNode < Data, arity, ConstData, Cast > & > ( node ).setChildren ( std::move ( children ) );
	}

	template < class N, int arity >
	static void setChild ( const AnyaryNode < Data, arity, ConstData, Cast > & node, Data child ) {
		const_cast < AnyaryNode < Data, arity, ConstData, Cast > & > ( node ).template setChild < N > ( std::move ( child ) );
	}

	static void setChildren ( const FixedaryNode < Data, ConstData, Cast > & node, std::vector < Data > child ) {
		const_cast < FixedaryNode < Data, ConstData, Cast > & > ( node ).setChildren ( std::move ( child ) );
	}

	static void setChild ( const FixedaryNode < Data, ConstData, Cast > & node, Data child, int index ) {
		const_cast < FixedaryNode < Data, ConstData, Cast > & > ( node ).setChild ( std::move ( child ), index );
	}

	static void setChildren ( const VararyNode < Data, ConstData, Cast > & node, std::vector < Data > children ) {
		const_cast < VararyNode < Data, ConstData, Cast > & > ( node ).setChildren ( std::move ( children ) );
	}

	static void setChild ( const VararyNode < Data, ConstData, Cast > & node, Data child, int index ) {
		const_cast < VararyNode < Data, ConstData, Cast > & > ( node ).setChild ( std::move ( child ), index );
	}

	static void setChild ( const VararyNode < Data, ConstData, Cast > & node, Data child, typename std::vector < Data >::iterator it ) {
		const_cast < VararyNode < Data, ConstData, Cast > & > ( node ).setChild ( std::move ( child ), it );
	}

	typename std::vector < Data >::iterator insert ( const VararyNode < Data, ConstData, Cast > & node, typename std::vector < Data >::iterator it, Data child ) {
		const_cast < VararyNode < Data, ConstData, Cast > & > ( node ).insert ( it, std::move ( child ) );
	}

	template < class InputIterator >
	typename std::vector < Data >::iterator insert ( const VararyNode < Data, ConstData, Cast > & node, typename std::vector < Data >::iterator it, InputIterator first, InputIterator last ) {
		const_cast < VararyNode < Data, ConstData, Cast > & > ( node ).insert ( it, first, last );
	}

	static void pushBackChild ( const VararyNode < Data, ConstData, Cast > & node, Data child ) {
		const_cast < VararyNode < Data, ConstData, Cast > & > ( node ).pushBackChild ( std::move ( child ) );
	}

};

} /* namespace std */

#endif /* __TREE_HPP_ */