/*
 * ptr_vector.hpp
 *
 * This file is part of Algorithms library toolkit.
 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)

 * Algorithms library toolkit 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 3 of the License, or
 * (at your option) any later version.

 * Algorithms library toolkit is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Created on: Feb 28, 2014
 * Author: Jan Travnicek
 */

#ifndef __PTR_VECTOR_HPP_
#define __PTR_VECTOR_HPP_

#include <ostream>
#include <sstream>
#include <string>

#include <extensions/compare.hpp>
#include <extensions/range.hpp>
#include <extensions/clone.hpp>
#include <extensions/container/vector.hpp>

namespace ext {

/**
 * \brief
 * Implementation of vector storing dynamicaly allocated instances of given type. The class mimicks the iterface of the standard library vector, but effectively allows polymorphic objects to be stored inside.
 *
 * \tparam T the type of stored values
 * \tparam N the size of the vector
 */
template < class T >
class ptr_vector {
	/**
	 * \brief
	 * The vector of pointers to stored values
	 */
	ext::vector < T * > m_data;

public:
	/**
	 * \brief
	 * The type of values.
	 */
	using value_type = T;

	/**
	 * \brief
	 * The type of sizes.
	 */
	using size_type = std::size_t;

	/**
	 * \brief
	 * The type of size differences.
	 */
	using diference_type = std::ptrdiff_t;

	/**
	 * \brief
	 * The type of reference to values.
	 */
	using reference = value_type &;

	/**
	 * \brief
	 * The type of reference to constant values.
	 */
	using const_reference = const value_type &;

	/**
	 * \brief
	 * The type of pointer to values.
	 */
	using pointer = T *;

	/**
	 * \brief
	 * The type of pointer to constant value.
	 */
	using const_pointer = const T *;

	/**
	 * \brief
	 * The type of values iterator.
	 */
	using iterator = dereferencing_iterator < typename std::vector < T * >::iterator >;

	/**
	 * \brief
	 * The type of constant values iterator.
	 */
	using const_iterator = dereferencing_iterator < typename std::vector < T * >::const_iterator >;

	/**
	 * \brief
	 * The type of reverse values iterator.
	 */
	using reverse_iterator = dereferencing_iterator < typename std::vector < T * >::reverse_iterator >;

	/**
	 * \brief
	 * The type of constant reverse values iterator.
	 */
	using const_reverse_iterator = dereferencing_iterator < typename std::vector < T * >::const_reverse_iterator >;

	/**
	 * \brief
	 * The default constructor creating empty vector.
	 */
	ptr_vector ( ) noexcept = default;

	/**
	 * \brief
	 * The constructor of the vecto from initializer list. The vector will store dynamically allocated copies of objects from inside of the initializer list.
	 *
	 * \tparam R the types stored inside the initializer list
	 *
	 * \param init the initializer list
	 */
	template < class R >
	ptr_vector ( std::initializer_list < R > init ) {
		insert ( cbegin ( ), std::move ( init ) );
	}

	/**
	 * \brief
	 * The constructor of the vector of specific size. Elements of the vector are defaultly constructed values of type R.
	 *
	 * \tparam R the actual type of values inside the constructed vector.
	 *
	 * \param count the size of the constructed vector
	 */
	template < class R = T >
	explicit ptr_vector ( size_type count ) {
		resize < R > ( count );
	}

	/**
	 * \brief
	 * Constructor of the vector from range specified by iterators.
	 *
	 * \tparam InputIt the iterator type
	 *
	 * \param first the begining of the range
	 * \param last the end of the range
	 */
	template < class InputIt >
	ptr_vector ( InputIt first, InputIt last ) {
		insert ( cbegin ( ), first, last );
	}

	/**
	 * Constructor from range of values.
	 *
	 * \tparam Iterator the type of range iterator
	 *
	 * \param range the source range
	 */
	template < class Iterator >
	ptr_vector ( const ext::iterator_range < Iterator > & range ) : ptr_vector ( range.begin ( ), range.end ( ) ) {
	}

	/**
	 * \brief
	 * Constructor of the vector of size given by \p count and filled with values from \p value.
	 *
	 * \tparam R the actual type of value to fill with
	 *
	 * \param count the size of the vector
	 * \param value the value to fill the vector with
	 */
	template < class R >
	ptr_vector ( size_type count, const R & value ) {
		insert ( cbegin ( ), count, value );
	}

	/**
	 * \brief
	 * Copy constrctor of the pointer vector.
	 *
	 * \param other the other instance
	 */
	ptr_vector ( const ptr_vector& other ) {
		insert ( cbegin ( ), other.begin ( ), other.end ( ) );
	}

	/**
	 * \brief
	 * Move constrctor of the pointer vector.
	 *
	 * \param other the other instance
	 */
	ptr_vector ( ptr_vector && other ) noexcept {
		std::swap ( m_data, other.m_data );
	}

	/**
	 * \brief
	 * The destructor of the vector
	 */
	~ptr_vector ( ) noexcept {
		clear ( );
	}

	/**
	 * \brief
	 * The copy operator of assignment.
	 *
	 * \param other the other instance
	 */
	ptr_vector < T > & operator = ( const ptr_vector < T > & other ) {
		if ( this == & other )
			return * this;

		assign ( other.begin ( ), other.end ( ) );

		return *this;
	}

	/**
	 * \brief
	 * The move operator of assignment.
	 *
	 * \param other the other instance
	 */
	ptr_vector < T > & operator = ( ptr_vector < T > && other ) noexcept {
		std::swap ( m_data, other.m_data );

		return *this;
	}

	/**
	 * \brief
	 * Sets the content of the vector to value copied count times.
	 *
	 * \tparam R the actual type of value to fill with
	 *
	 * \param count the number how many time copy the value
	 * \param the value to fill the container with
	 */
	template < class R >
	void assign ( size_type count, const R & value ) {
		clear ( );
		insert ( cbegin ( ), count, value );
	}

	/**
	 * \brief
	 * Sets the content of the vector to values in the given range.
	 *
	 * \tparam InputIt the iterator type
	 *
	 * \param first the begining of the range
	 * \param last the end of the range
	 */
	template< class InputIt >
	void assign ( InputIt first, InputIt last ) {
		clear ( );
		insert ( cbegin ( ), first, last );
	}

	/**
	 * \brief
	 * Sets the content of the vector to values in the initializer list
	 *
	 * \tparam R the types stored inside the initializer list
	 *
	 * \param ilist the initializer list
	 */
	template < class R >
	void assign ( std::initializer_list < R > ilist ) {
		clear ( );
		insert ( cbegin ( ), std::move ( ilist ) );
	}

	/**
	 * \brief
	 * Getter of a reference to the value on given index.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to a value at given index
	 */
	reference at ( size_type index ) {
		return * m_data.at ( index );
	}

	/**
	 * \brief
	 * Getter of a reference to the value on given index.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to a value at given index
	 */
	const_reference at ( size_type index ) const {
		return * m_data.at ( index );
	}

	/**
	 * \brief
	 * Array subscript operator.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to a value at given index
	 */
	reference operator [ ] ( size_type index ) {
		return * m_data [ index ];
	}

	/**
	 * \brief
	 * Array subscript operator.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to a value at given index
	 */
	const_reference operator [ ] ( size_type index ) const {
		return * m_data [ index ];
	}

	/**
	 * \brief
	 * Getter of a value on the lowest index.
	 *
	 * \return reference to a value on the lowest index
	 */
	reference front ( ) {
		return * m_data.front ( );
	}

	/**
	 * \brief
	 * Getter of a value on the lowest index.
	 *
	 * \return reference to a value on the lowest index
	 */
	const_reference front ( ) const {
		return * m_data.front ( );
	}

	/**
	 * \brief
	 * Getter of a value on the highest index.
	 *
	 * \return reference to a value on the highest index
	 */
	reference back ( ) {
		return * m_data.back ( );
	}

	/**
	 * \brief
	 * Getter of a value on the highest index.
	 *
	 * \return reference to a value on the highest index
	 */
	const_reference back ( ) const {
		return * m_data.back ( );
	}

	/**
	 * \brief
	 * Iterator to the begining of the values range in the vector.
	 *
	 * \return iterator to the begining
	 */
	iterator begin ( ) & noexcept {
		return dereferencer ( m_data.begin ( ) );
	}

	/**
	 * \brief
	 * Const iterator to the begining of the values range in the vector.
	 *
	 * \return iterator to the begining
	 */
	const_iterator begin ( ) const & noexcept {
		return dereferencer ( m_data.begin ( ) );
	}

	/**
	 * \brief
	 * Move iterator to the begining of the values range in the vector.
	 *
	 * \return move iterator to the begining
	 */
	auto begin ( ) && noexcept {
		return make_move_iterator ( this->begin ( ) );
	}

	/**
	 * \brief
	 * Iterator to the begining of the values range in the vector.
	 *
	 * \return iterator to the begining
	 */
	const_iterator cbegin ( ) const noexcept {
		return dereferencer ( m_data.cbegin ( ) );
	}

	/**
	 * \brief
	 * Iterator one past the last element of the values range in the vector.
	 *
	 * \return iterator to the end
	 */
	iterator end ( ) & noexcept {
		return dereferencer ( m_data.end ( ) );
	}

	/**
	 * \brief
	 * Const iterator one past the last element of the values range in the vector.
	 *
	 * \return iterator to the end
	 */
	const_iterator end ( ) const & noexcept {
		return dereferencer ( m_data.end ( ) );
	}

	/**
	 * \brief
	 * Move iterator to the begining of the values range in the vector.
	 *
	 * \return iterator to the begining
	 */
	auto end ( ) && noexcept {
		return make_move_iterator ( this->end ( ) );
	}

	/**
	 * \brief
	 * Iterator one past the last element of the values range in the vector.
	 *
	 * \return iterator to the end
	 */
	const_iterator cend ( ) const noexcept {
		return dereferencer ( m_data.cend ( ) );
	}

	/**
	 * \brief
	 * Reverse iterator to the begining of the reversed range of values in the vector.
	 *
	 * \return reverse iterator to the begining
	 */
	reverse_iterator rbegin ( ) noexcept {
		return dereferencer ( m_data.rbegin ( ) );
	}

	/**
	 * \brief
	 * Reverse iterator to the begining of the reversed range of values in the vector.
	 *
	 * \return reverse iterator to the begining
	 */
	const_reverse_iterator rbegin ( ) const noexcept {
		return dereferencer ( m_data.rbegin ( ) );
	}

	/**
	 * \brief
	 * Reverse iterator to the begining of the reversed range of values in the vector.
	 *
	 * \return reverse iterator to the begining
	 */
	const_reverse_iterator crbegin ( ) const noexcept {
		return dereferencer ( m_data.crbegin ( ) );
	}

	/**
	 * \brief
	 * Reverse iterator one past the last element of the reversed range of values in the vector.
	 *
	 * \return reverse iterator to the end
	 */
	reverse_iterator rend ( ) noexcept {
		return dereferencer ( m_data.rend ( ) );
	}

	/**
	 * \brief
	 * Reverse iterator one past the last element of the reversed range of values in the vector.
	 *
	 * \return reverse iterator to the end
	 */
	const_reverse_iterator rend ( ) const noexcept {
		return dereferencer ( m_data.rend ( ) );
	}

	/**
	 * \brief
	 * Reverse iterator one past the last element of the reversed range of values in the vector.
	 *
	 * \return reverse iterator to the end
	 */
	const_reverse_iterator crend ( ) const noexcept {
		return dereferencer ( m_data.crend ( ) );
	}

	/**
	 * \brief
	 * Make range of non-const begin to end iterators.
	 *
	 * \return full range over container values
	 */
	auto range ( ) & {
		auto endIter = end ( );
		auto beginIter = begin ( );
		return ext::iterator_range < decltype ( endIter ) > ( beginIter, endIter );
	}

	/**
	 * \brief
	 * Make range of non-const begin to end iterators.
	 *
	 * \return full range over container values
	 */
	auto range ( ) const & {
		auto endIter = end ( );
		auto beginIter = begin ( );
		return ext::iterator_range < decltype ( endIter ) > ( beginIter, endIter );
	}

	/**
	 * \brief
	 * Make range of move begin to end iterators.
	 *
	 * \return full range over container values
	 */
	auto range ( ) && {
		auto endIter = std::move ( * this ).end ( );
		auto beginIter = std::move ( * this ).begin ( );
		return ext::iterator_range < decltype ( endIter ) > ( beginIter, endIter );
	}

	/**
	 * \brief
	 * Array emptines test.
	 *
	 * \return true it vector is empty, false othervise
	 */
	bool empty ( ) const noexcept {
		return m_data.empty ( );
	}

	/**
	 * \brief
	 * Getter of the vector size.
	 *
	 * \return the size of the vector
	 */
	size_type size ( ) const noexcept {
		return m_data.size ( );
	}

	/**
	 * \brief
	 * Returns the maximal number of values possible to store inside the container.
	 *
	 * \return the maximal number of values
	 */
	size_type max_size ( ) const noexcept {
		return m_data.max_size ( );
	}

	/**
	 * \brief
	 * Prealocates space for given number of elements. Does not shrink the vector
	 *
	 * \param new_cap the preallocated size of the vector
	 */
	void reserve ( size_type new_cap ) {
		m_data.reserve ( new_cap );
	}

	/**
	 * \brief
	 * Returns the preallocated size of the vector.
	 *
	 * \return the preallocated size of the vector
	 */
	size_type capacity ( ) const noexcept {
		return m_data.capacity ( );
	}

	/**
	 * \brief
	 * Reallocates the vector to have the miniaml space overhead.
	 */
	void shrink_to_fit ( ) {
		m_data.shrink_to_fit ( );
	}

	/**
	 * \brief
	 * Removes all values from the vector.
	 */
	void clear ( ) noexcept {
		for ( T * data : m_data ) {
			delete data;
		}
		m_data.clear ( );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to set
	 * \param value the value to place to that position
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R >
	iterator set ( iterator pos, R && value ) {
		return set ( const_iterator ( pos ), std::forward < R > ( value ) );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to set
	 * \param value the value to place to that position
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R >
	iterator set ( const_iterator pos, R && value ) {
		size_type dist = std::distance ( cbegin ( ), pos );

		// If the set value and value at position pos are same instances first clone, then delete
		delete std::exchange ( m_data.at ( dist ), ext::clone ( std::forward < R > ( value ) ) );

		return dereferencer ( m_data.begin ( ) + dist );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to set
	 * \param value the value to place to that position
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R >
	reverse_iterator set ( reverse_iterator pos, R && value ) {
		return set ( const_reverse_iterator ( pos ), std::forward < R > ( value ) );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to set
	 * \param value the value to place to that position
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R >
	reverse_iterator set ( const_reverse_iterator pos, R && value ) {
		size_type dist = std::distance ( crbegin ( ), pos );

		// If the set value and value at position pos are same instances first clone, then delete
		delete std::exchange ( m_data.at ( m_data.size ( ) - dist - 1 ), ext::clone ( std::forward < R > ( value ) ) );

		return dereferencer ( m_data.rbegin ( ) + dist );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R = T, class ... Args >
	iterator emplace_set ( iterator pos, Args && ... args ) {
		return emplace_set ( const_iterator ( pos ), std::forward < Args > ( args ) ... );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R = T, class ... Args >
	iterator emplace_set ( const_iterator pos, Args && ... args ) {
		return set ( pos, R ( std::forward < Args > ( args ) ... ) );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R = T, class ... Args >
	reverse_iterator emplace_set ( reverse_iterator pos, Args && ... args ) {
		return emplace_set ( const_reverse_iterator ( pos ), std::forward < Args > ( args ) ... );
	}

	/**
	 * \brief
	 * Changes the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the changed location
	 */
	template < class R = T, class ... Args >
	reverse_iterator emplace_set ( const_reverse_iterator pos, Args && ... args ) {
		return set ( pos, R ( std::forward < Args > ( args ) ... ) );
	}

	/**
	 * \brief
	 * Inserts the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	iterator insert ( iterator pos, R && value ) {
		return insert ( const_insert ( pos ), std::forward < R > ( value ) );
	}

	/**
	 * \brief
	 * Inserts the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	iterator insert ( const_iterator pos, R && value ) {
		return dereferencer ( m_data.insert ( pos.base ( ), ext::clone ( std::forward < R > ( value ) ) ) );
	}

	/**
	 * \brief
	 * Inserts the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	reverse_iterator insert ( reverse_iterator pos, R && value ) {
		return insert ( const_reverse_iterator ( pos ), std::forward < R > ( value ) );
	}

	/**
	 * \brief
	 * Inserts the value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	reverse_iterator insert ( const_reverse_iterator pos, R && value ) {
		return dereferencer ( m_data.insert ( pos.base ( ), ext::clone ( std::forward < R > ( value ) ) ) );
	}

	/**
	 * \brief
	 * Inserts the \p count copies of value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param count the number of copies to insert
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	iterator insert ( iterator pos, size_type count, const R & value ) {
		return insert ( const_iterator ( pos ), count, value );
	}

	/**
	 * \brief
	 * Inserts the \p count copies of value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param count the number of copies to insert
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	iterator insert ( const_iterator pos, size_type count, const R & value ) {
		iterator res = dereferencer ( m_data.insert ( pos.base ( ), count, nullptr ) );
		for ( size_type i = 0; i < count; ++ i ) {
			* ( res.base ( ) + i ) = ext::clone ( value );
		}
		return res;
	}

	/**
	 * \brief
	 * Inserts the \p count copies of value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param count the number of copies to insert
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	reverse_iterator insert ( reverse_iterator pos, size_type count, const R & value ) {
		return insert ( const_reverse_iterator ( pos ), count, value );
	}

	/**
	 * \brief
	 * Inserts the \p count copies of value on position given by iterator \p pos
	 *
	 * \tparam R the actual type of value stored inside the vector
	 *
	 * \param pos the position to insert at
	 * \param count the number of copies to insert
	 * \param value the value to insert
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	reverse_iterator insert ( const_reverse_iterator pos, size_type count, const R & value ) {
		reverse_iterator res = dereferencer ( m_data.insert ( pos, count, nullptr ) );
		for ( size_type i = 0; i < count; ++ i ) {
			* ( std::next ( res.base ( ) ).base ( ) + i ) = ext::clone ( value );
		}
		return res;
	}

	/**
	 * \brief
	 * Inserts the values from the given range to positions starting at given iterator \p pos
	 *
	 * \tparam InputIt the iterator type
	 *
	 * \param first the begining of the range
	 * \param last the end of the range
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class InputIt >
	iterator insert ( iterator pos, InputIt first, InputIt last ) {
		return insert ( const_iterator ( pos ), first, last );
	}

	/**
	 * \brief
	 * Inserts the values from the given range to positions starting at given iterator \p pos
	 *
	 * \tparam InputIt the iterator type
	 *
	 * \param first the begining of the range
	 * \param last the end of the range
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class InputIt >
	iterator insert ( const_iterator pos, InputIt first, InputIt last ) {
		size_type size = std::distance ( first, last );
		iterator res = dereferencer ( m_data.insert ( pos.base ( ), size, nullptr ) );

		for ( size_type i = 0; i < size; ++ first, ++ i )
			* ( res.base ( ) + i ) = ext::clone ( * first );

		return res;
	}

	/**
	 * \brief
	 * Inserts the values from the given range to positions starting at given iterator \p pos
	 *
	 * \tparam InputIt the iterator type
	 *
	 * \param first the begining of the range
	 * \param last the end of the range
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class InputIt >
	reverse_iterator insert ( reverse_iterator pos, InputIt first, InputIt last ) {
		return insert ( const_reverse_iterator ( pos ), first, last );
	}

	/**
	 * \brief
	 * Inserts the values from the given range to positions starting at given iterator \p pos
	 *
	 * \tparam InputIt the iterator type
	 *
	 * \param first the begining of the range
	 * \param last the end of the range
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class InputIt >
	reverse_iterator insert ( const_reverse_iterator pos, InputIt first, InputIt last ) {
		size_type size = std::distance ( first, last );
		reverse_iterator res = dereferencer ( m_data.insert ( pos, size, nullptr ) );

		for ( size_type i = 0; i < size; ++ first, ++ i )
			* ( std::next ( res.base ( ) ).base ( ) + i ) = ext::clone ( * first );

		return res;
	}

	/**
	 * \brief
	 * Inserts the values from the given initializer list to positions starting at given iterator \p pos
	 *
	 * \tparam R the types stored inside the initializer list
	 *
	 * \param pos the position to insert at
	 * \param ilist the initializer list
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	iterator insert ( iterator pos, std::initializer_list < R > ilist ) {
		return insert ( const_iterator ( pos ), std::move ( ilist ) );
	}

	/**
	 * \brief
	 * Inserts the values from the given initializer list to positions starting at given iterator \p pos
	 *
	 * \tparam R the types stored inside the initializer list
	 *
	 * \param pos the position to insert at
	 * \param ilist the initializer list
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	iterator insert ( const_iterator pos, std::initializer_list < R > ilist ) {
		return insert ( pos, ilist.begin ( ), ilist.end ( ) );
	}

	/**
	 * \brief
	 * Inserts the values from the given initializer list to positions starting at given iterator \p pos
	 *
	 * \tparam R the types stored inside the initializer list
	 *
	 * \param pos the position to insert at
	 * \param ilist the initializer list
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	reverse_iterator insert ( reverse_iterator pos, std::initializer_list < R > ilist ) {
		return insert ( const_reverse_iterator ( pos ), std::move ( ilist ) );
	}

	/**
	 * \brief
	 * Inserts the values from the given initializer list to positions starting at given iterator \p pos
	 *
	 * \tparam R the types stored inside the initializer list
	 *
	 * \param pos the position to insert at
	 * \param ilist the initializer list
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R >
	reverse_iterator insert ( const_reverse_iterator pos, std::initializer_list < R > ilist ) {
		return insert ( pos, ilist.begin ( ), ilist.end ( ) );
	}

	/**
	 * \brief
	 * Inserts a new value to the container at position given by parameter \p pos. The new value is constructed inside the method from constructor parameters.
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R = T, class ... Args >
	iterator emplace ( iterator pos, Args && ... args ) {
		return emplace ( const_iterator ( pos ), std::forward < Args > ( args ) ... );
	}

	/**
	 * \brief
	 * Inserts a new value to the container at position given by parameter \p pos. The new value is constructed inside the method from constructor parameters.
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R = T, class ... Args >
	iterator emplace ( const_iterator pos, Args && ... args ) {
		return insert ( pos, R ( std::forward < Args > ( args ) ... ) );
	}

	/**
	 * \brief
	 * Inserts a new value to the container at position given by parameter \p pos. The new value is constructed inside the method from constructor parameters.
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R = T, class ... Args >
	reverse_iterator emplace ( reverse_iterator pos, Args && ... args ) {
		return emplace ( const_reverse_iterator ( pos ), std::forward < Args > ( args ) ... );
	}

	/**
	 * \brief
	 * Inserts a new value to the container at position given by parameter \p pos. The new value is constructed inside the method from constructor parameters.
	 *
	 * \tparam R the actual type of value stored inside the vector
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return updated iterator to the newly inserted value
	 */
	template < class R = T, class ... Args >
	reverse_iterator emplace ( const_reverse_iterator pos, Args && ... args ) {
		return insert ( pos, R ( std::forward < Args > ( args ) ... ) );
	}

	/**
	 * \brief
	 * Removes element from the container at position given by parameter \p pos
	 *
	 * \param pos the iterator pointing to the value to removed
	 *
	 * \returns updated iterator to value after the removed one
	 */
	iterator erase ( iterator pos ) {
		return erase ( const_iterator ( pos ) );
	}

	/**
	 * \brief
	 * Removes element from the container at position given by parameter \p pos
	 *
	 * \param pos the iterator pointing to the value to removed
	 *
	 * \returns updated iterator to value after the removed one
	 */
	iterator erase ( const_iterator pos ) {
		delete std::addressof ( * pos );
		return dereferencer ( m_data.erase ( pos.base ( ) ) );
	}

	/**
	 * \brief
	 * Removes element from the container at position given by parameter \p pos
	 *
	 * \param pos the iterator pointing to the value to removed
	 *
	 * \returns updated iterator to value after the removed one
	 */
	reverse_iterator erase ( reverse_iterator pos ) {
		return erase ( const_reverse_iterator ( pos ) );
	}

	/**
	 * \brief
	 * Removes element from the container at position given by parameter \p pos
	 *
	 * \param pos the iterator pointing to the value to removed
	 *
	 * \returns updated iterator to value after the removed one
	 */
	reverse_iterator erase ( const_reverse_iterator pos ) {
		delete std::addressof ( * pos );
		return dereferencer ( m_data.erase ( pos.base ( ) ) );
	}

	/**
	 * \brief
	 * Removes elements from the container in range given parameters \p first and \p last
	 *
	 * \param first the begining of the removed range
	 * \param last the end of the removed range
	 *
	 * \returns updated iterator to value after the removed ones
	 */
	iterator erase ( iterator first, iterator last ) {
		return erase ( const_iterator ( first ), const_iterator ( last ) );
	}

	/**
	 * \brief
	 * Removes elements from the container in range given parameters \p first and \p last
	 *
	 * \param first the begining of the removed range
	 * \param last the end of the removed range
	 *
	 * \returns updated iterator to value after the removed ones
	 */
	iterator erase ( const_iterator first, const_iterator last ) {
		for ( const_iterator first_copy = first; first_copy != last; ++ first_copy ) {
			delete std::addressof ( * first_copy );
		}
		return dereferencer ( m_data.erase ( first.base ( ), last.base ( ) ) );
	}

	/**
	 * \brief
	 * Removes elements from the container in range given parameters \p first and \p last
	 *
	 * \param first the begining of the removed range
	 * \param last the end of the removed range
	 *
	 * \returns updated iterator to value after the removed ones
	 */
	reverse_iterator erase ( reverse_iterator first, reverse_iterator last ) {
		return erase ( const_reverse_iterator ( first ), const_reverse_iterator ( last ) );
	}

	/**
	 * \brief
	 * Removes elements from the container in range given parameters \p first and \p last
	 *
	 * \param first the begining of the removed range
	 * \param last the end of the removed range
	 *
	 * \returns updated iterator to value after the removed ones
	 */
	reverse_iterator erase ( const_reverse_iterator first, const_reverse_iterator last ) {
		for ( const_reverse_iterator first_copy = first; first_copy != last; ++ first_copy ) {
			delete std::addressof ( * first_copy );
		}
		return dereferencer ( m_data.erase ( first.base ( ), last.base ( ) ) );
	}

	/**
	 * \brief
	 * Appends a new value at the end of the container.
	 *
	 * \tparam R the actual type of appended value
	 *
	 * \param value the appended value
	 */
	template < class R >
	void push_back ( R && value ) {
		insert ( cend ( ), std::forward < R > ( value ) );
	}

	/**
	 * \brief
	 * Appends a new value at the end of the container. The value is constructed inside the method using provided constructor parameters.
	 *
	 * \tparam R the actual type of appended value
	 * \tparam Args ... the types of arguments of the R constructor
	 *
	 * \param pos the position to set
	 * \param args ... the arguments of the R constructor
	 *
	 * \return reference to the emplaced value
	 */
	template < class R = T, class ... Args >
	reference emplace_back ( Args && ... args ) {
		return * emplace < R > ( cend ( ), std::forward < Args > ( args ) ... );
	}

	/**
	 * \brief
	 * Removes element from the end of the container.
	 */
	void pop_back ( ) {
		delete m_data.back ( );
		m_data.pop_back ( );
	}

	/**
	 * \brief
	 * Changes the size of the vector, allocates new elements if the size increases. The possibly needed values are defaultly constructed values of type R. The vector can both increase or decrease in size.
	 *
	 * \tparam R the type of the constructed values at possibly new indexes
	 *
	 * \param count the requested new size of the vector
	 */
	template < class R = T >
	void resize ( size_type count ) {
		for ( size_type i = count; i < m_data.size ( ); ++ i ) {
			delete m_data [ i ];
		}
		size_type i = m_data.size ( );
		m_data.resize ( count );
		for ( ; i < count; ++ i ) {
			m_data [ i ] = new R ( );
		}
	}

	/**
	 * \brief
	 * Changes the size of the vector. If the container increases in size copies of the \p value are used at new positions.
	 *
	 * \tparam R the actual type of the default value of new positions
	 *
	 * \param count the requested new size of the vector
	 * \param value the fill value of new positions
	 */
	template < class R >
	void resize ( size_type count, const R & value ) {
		for ( size_type i = count; i < m_data.size ( ); ++ i ) {
			delete m_data [ i ];
		}
		size_type i = m_data.size ( );
		m_data.resize ( count );
		for ( ; i < count; ++ i ) {
			m_data [ i ] = ext::clone ( value );
		}
	}

	/**
	 * \brief
	 * Like resize but only shrinks the container. If the requested size of the vector is bigger than actual size, nothing happens.
	 *
	 * \param count the requested new size of the vector
	 */
	void shrink ( size_type count ) {
		for ( size_type i = count; i < m_data.size ( ); ++ i ) {
			delete m_data [ i ];
		}
		m_data.resize ( std::min ( count, m_data.size ( ) ) );
	}

	/**
	 * \brief
	 * Swaps two instances of pointer vector
	 *
	 * \param x the other instance to swap with
	 */
	void swap ( ptr_vector & other ) {
		std::swap ( this->m_data, other.m_data );
	}

};

/**
 * \brief
 * Operator to print the vector to the output stream.
 *
 * \param out the output stream
 * \param vector the vector to print
 *
 * \tparam T the type of values inside the vector
 *
 * \return the output stream from the \p out
 */
template< class T >
std::ostream& operator<<(std::ostream& out, const ext::ptr_vector < T > & ptr_vector) {
	out << "[";

	bool first = true;
	for(const T& item : ptr_vector) {
		if(!first) out << ", ";
		first = false;
		out << item;
	}

	out << "]";
	return out;
}

/**
 * \brief
 * Specialisation of the compare structure implementing the three-way comparison.
 *
 * \tparam T the type of values inside the vector
 */
template<class T >
struct compare < ext::ptr_vector < T > > {

	/**
	 * \brief
	 * Implementation of the three-way comparison.
	 *
	 * \param first the left operand of the comparison
	 * \param second the right operand of the comparison
	 *
	 * \return negative value of left < right, positive value if left > right, zero if left == right
	 */
	int operator()(const ext::ptr_vector < T >& first, const ext::ptr_vector < T > & second) const {
		if(first.size() < second.size()) return -1;
		if(first.size() > second.size()) return 1;

		static compare<typename std::decay < T >::type > comp;
		for(auto iterF = first.begin(), iterS = second.begin(); iterF != first.end(); ++iterF, ++iterS) {
			int res = comp(*iterF, *iterS);
			if(res != 0) return res;
		}
		return 0;
	}
};

/**
 * \brief
 * Overload of to_string function.
 *
 * \param value the vector to be converted to string
 *
 * \tparam T the type of values inside the vector
 *
 * \return string representation
 */
template < class T >
std::string to_string ( const ext::ptr_vector < T > & value ) {
	std::stringstream ss;
	ss << value;
	return ss.str();
}

/**
 * \brief
 * Specialisation of equality operator for pointer vector.
 *
 * \tparam T the type of values inside the vector
 *
 * \param first the first compared value
 * \param second the second compared value
 *
 * \return true if compared values are the same, false othervise
 */
template < class T >
bool operator == ( const ptr_vector < T > & first, const ptr_vector < T > & second ) {
	static compare < ptr_vector < T > > comp;
	return comp ( first, second ) == 0;
}

/**
 * \brief
 * Specialisation of non-equality operator for pointer vector.
 *
 * \tparam T the type of values inside the vector
 *
 * \param first the first compared value
 * \param second the second compared value
 *
 * \return true if compared values are not the same, false othervise
 */
template < class T >
bool operator != ( const ptr_vector < T > & first, const ptr_vector < T > & second ) {
	return ! ( first == second );
}

/**
 * \brief
 * Specialisation of less than operator for pointer vector.
 *
 * \tparam T the type of values inside the vector
 *
 * \param first the first compared value
 * \param second the second compared value
 *
 * \return true if the first value is smaller than the second, false othervise
 */
template < class T >
bool operator < ( const ptr_vector < T > & first, const ptr_vector < T > & second ) {
	static compare < ptr_vector < T > > comp;
	return comp ( first, second ) < 0;
}

/**
 * \brief
 * Specialisation of greater than operator for pointer vector.
 *
 * \tparam T the type of values inside the vector
 *
 * \param first the first compared value
 * \param second the second compared value
 *
 * \return true if the first value is bigger than the second, false othervise
 */
template < class T >
bool operator > ( const ptr_vector < T > & first, const ptr_vector < T > & second ) {
	return second < first;
}

/**
 * \brief
 * Specialisation of less than or equal operator for pointer vector.
 *
 * \tparam T the type of values inside the vector
 *
 * \param first the first compared value
 * \param second the second compared value
 *
 * \return true if the first value is smaller or equal to the second, false othervise
 */
template < class T >
bool operator <= ( const ptr_vector < T > & first, const ptr_vector < T > & second ) {
	return ! ( first > second );
}

/**
 * \brief
 * Specialisation of greater than or equal operator for pointer vector.
 *
 * \tparam T the type of values inside the vector
 *
 * \param first the first compared value
 * \param second the second compared value
 *
 * \return true if the first value is bigger or equal to the second, false othervise
 */
template < class T >
bool operator >= ( const ptr_vector < T > & first, const ptr_vector < T > & second ) {
	return ! ( first < second );
}

} /* namespace ext */

#endif /* __PTR_VECTOR_HPP_ */
