/******************************************************************************/
/* ARRAYS - INLINE CODE *******************************************************/
/******************************************************************************/

#ifndef _H_EBCL_INLINE_ARRAYS
#define _H_EBCL_INLINE_ARRAYS
#include <ebcl/Arrays.hh>
namespace ebcl {


/*= T_Array ==================================================================*/

template< typename T >
inline T_Array< T >::T_Array( ) noexcept
	: T_Array( DEFAULT_GROWTH( ) )
{ }

template< typename T >
inline T_Array< T >::T_Array(
		const uint32_t growth ) noexcept
	: data_( nullptr ) , capacity_( 0 ) , size_( 0 ) , growth_( growth )
{
	assert( growth > 0 );
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T_Array< T >::T_Array(
		T_Array< T > const& source ) noexcept
	: capacity_( source.capacity_ ) , size_( source.size_ ) ,
		growth_( source.growth_ )
{
	if ( capacity_ != 0 ) {
		data_ = ( T* )::operator new ( capacity_ * sizeof( T ) );
		if ( std::is_class< T >( ) ) {
			for ( uint32_t i = 0 ; i < size_ ; i ++ ) {
				::new ( ( char* ) &( data_[ i ] ) ) T( source[ i ] );
			}
		} else {
			memcpy( data_ , source.data_ , source.size_ * sizeof( T ) );
		}
	} else {
		data_ = nullptr;
	}
}

template< typename T >
inline T_Array< T >& T_Array< T >::operator= (
		T_Array< T > const& other ) noexcept
{
	free( );
	capacity_ = other.capacity_;
	data_ = ( T* )::operator new ( sizeof( T ) * capacity_ );
	size_ = other.size_;
	growth_ = other.growth_;
	if ( std::is_class< T >( ) ) {
		for ( uint32_t i = 0 ; i < size_ ; i ++ ) {
			::new ( ( char* ) &( data_[ i ] ) )T( other[ i ] );
		}
	} else if ( size_ ) {
		memcpy( data_ , other.data_ , size_ * sizeof( T ) );
	}
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T_Array< T >::T_Array(
		T_Array< T >&& source ) noexcept
	: T_Array( 1 )
{
	swap( *this , source );
	source.clear( );
}

template< typename T >
inline T_Array< T >& T_Array< T >::operator=(
		T_Array< T >&& other ) noexcept
{
	swap( *this , other );
	other.clear( );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void swap( T_Array< T >& lhs ,
		T_Array< T >& rhs ) noexcept
{
	using std::swap;
	swap( lhs.data_ , rhs.data_ );
	swap( lhs.capacity_ , rhs.capacity_ );
	swap( lhs.size_ , rhs.size_ );
	swap( lhs.growth_ , rhs.growth_ );
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T_Array< T >::~T_Array( )
{
	free( );
}

template< typename T >
inline T_Array< T >& T_Array< T >::clear( ) noexcept
{
	if ( std::is_class< T >( ) ) {
		for ( uint32_t i = 0 ; i < size_ ; i ++ ) {
			data_[ i ].~T( );
		}
	}
	size_ = 0;
	return *this;
}

template< typename T >
inline T_Array< T >& T_Array< T >::free( ) noexcept
{
	clear( );
	::operator delete ( (void*) data_ );
	data_ = nullptr;
	capacity_ = 0;
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline uint32_t T_Array< T >::capacity( ) const noexcept
{
	return capacity_;
}

template< typename T >
inline uint32_t T_Array< T >::size( ) const noexcept
{
	return size_;
}

template< typename T >
inline uint32_t T_Array< T >::growth( ) const noexcept
{
	return growth_;
}

template< typename T >
inline bool T_Array< T >::empty( ) const noexcept
{
	return size_ != 0;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T_Array< T >& T_Array< T >::ensureCapacity(
		const uint32_t capacity ) noexcept
{
	if ( capacity_ < capacity ) {
		const uint32_t mod( capacity % growth_ );
		const uint32_t nCap( capacity + ( mod == 0 ? 0 : ( growth_ - mod ) ) );
		T* const nData = ( T* )::operator new ( sizeof( T ) * nCap );
		if ( std::is_class< T >( ) ) {
			for ( uint32_t i = 0 ; i < size_ ; i ++ ) {
				::new ( reinterpret_cast< char* >( &nData[ i ] ) )
					T( std::move( data_[ i ] ) );
				data_[ i ].~T( );
			}
		} else {
			memcpy( nData , data_ , size_ * sizeof( T ) );
		}
		::operator delete ( (void*) data_ );
		capacity_ = nCap;
		data_ = nData;
	}
	return *this;
}

template< typename T >
template< typename Q , typename >
inline T_Array< T >& T_Array< T >::resize(
		const uint32_t size )
{
	if ( size > size_ ) {
		ensureCapacity( size );
		for ( auto i = size_ ; i < size_ ; i ++ ) {
			::new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( );
		}
	}
	size_ = size;
	return *this;
}

template< typename T >
template< typename Q , typename >
inline T_Array< T >& T_Array< T >::resize(
		const uint32_t size ,
		T const& value )
{
	if ( size > size_ ) {
		ensureCapacity( size );
		for ( auto i = size_ ; i < size_ ; i ++ ) {
			::new ( reinterpret_cast< char* >( &data_[ i ] ) ) T( value );
		}
	}
	size_ = size;
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T& T_Array< T >::operator[] (
		const uint32_t index ) noexcept
{
	assert( index < size_ );
	return data_[ index ];
}

template< typename T >
inline T const& T_Array< T >::operator[] (
		const uint32_t index ) const noexcept
{
	assert( index < size_ );
	return data_[ index ];
}

template< typename T >
inline T& T_Array< T >::last( ) noexcept
{
	assert( !empty( ) );
	return data_[ size_ - 1 ];
}

template< typename T >
inline T const& T_Array< T >::last( ) const noexcept
{
	assert( !empty( ) );
	return data_[ size_ - 1 ];
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline int32_t T_Array< T >::indexOf(
		T const& item ) const noexcept
{
	for ( uint32_t i = 0 ; i < size_ ; i ++ ) {
		if ( data_[ i ] == item ) {
			return i;
		}
	}
	return -1;
}

template< typename T >
inline bool T_Array< T >::contains(
		T const& item ) const noexcept
{
	return indexOf( item ) != -1;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline uint32_t T_Array< T >::add(
		T const& item ) noexcept
{
	ensureCapacity( size_ + 1 );
	::new ( ( char* ) &( data_[ size_ ] ) ) T( item );
	return size_ ++;
}

template< typename T >
inline uint32_t T_Array< T >::add(
		T&& item ) noexcept
{
	ensureCapacity( size_ + 1 );
	::new ( ( char* ) &( data_[ size_ ] ) ) T( std::move( item ) );
	return size_ ++;
}

/*----------------------------------------------------------------------------*/

template< typename T >
template< typename... Args >
inline T& T_Array< T >::addNew(
		Args&& ... args )
{
	ensureCapacity( size_ + 1 );
	::new ( ( char* ) &( data_[ size_ ] ) ) T( std::forward< Args >( args ) ... );
	return data_[ size_ ++ ];
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T_Array< T >& T_Array< T >::addAll(
		T_Array< T > const& other ) noexcept
{
	ensureCapacity( size_ + other.size_ );
	if ( std::is_class< T >( ) ) {
		for ( uint32_t i = 0 ; i < other.size_ ; i ++ ) {
			::new ( ( char* ) &( data_[ size_ + i ] ) ) T( other.data_[ i ] );
		}
	} else if ( other.size_ ) {
		memcpy( data_ + size_ , other.data_ , sizeof( T ) * other.size_ );
	}
	size_ += other.size_;
	return *this;
}

template< typename T >
inline T_Array< T >& T_Array< T >::addAll(
		T_Array< T >&& other ) noexcept
{
	ensureCapacity( size_ + other.size_ );
	if ( std::is_class< T >( ) ) {
		for ( uint32_t i = 0 ; i < other.size_ ; i ++ ) {
			::new ( ( char* ) &( data_[ size_ + i ] ) ) T( std::move( other.data_[ i ] ) );
		}
	} else if ( other.size_ ) {
		memcpy( data_ + size_ , other.data_ , sizeof( T ) * other.size_ );
	}
	size_ += other.size_;
	other.size_ = 0;
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T_Array< T >& T_Array< T >::operator<< (
		T const& item ) noexcept
{
	add( item );
	return *this;
}

template< typename T >
inline T_Array< T >& T_Array< T >::operator<< (
		T&& item ) noexcept
{
	add( std::move( item ) );
	return *this;
}

template< typename T >
inline T_Array< T >& T_Array< T >::operator<< (
		T_Array< T > const& other ) noexcept
{
	addAll( other );
	return *this;
}

template< typename T >
inline T_Array< T >& T_Array< T >::operator<< (
		T_Array< T >&& other ) noexcept
{
	addAll( std::move( other ) );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_Array< T >::insert(
		const uint32_t index ,
		T const& item ) noexcept
{
	if ( std::is_class< T >( ) ) {
		using std::swap;
		const auto last( add( item ) );
		for ( uint32_t i = index ; i < last ; i ++ ) {
			swap( data_[ i ] , data_[ last ] );
		}
	} else {
		ensureCapacity( size_ + 1 );
		if ( index < size_ ) {
			memmove( &data_[ index + 1 ] , &data_[ index ] ,
				sizeof( T ) * ( size_ - index ) );
		}
		data_[ index ] = item;
		size_ ++;
	}
}

template< typename T >
inline void T_Array< T >::insert(
		const uint32_t index ,
		T&& item ) noexcept
{
	if ( std::is_class< T >( ) ) {
		using std::swap;
		const auto last( add( std::move( item ) ) );
		for ( uint32_t i = index ; i < last ; i ++ ) {
			swap( data_[ i ] , data_[ last ] );
		}
	} else {
		insert( index , (T const&) item );
	}
}

template< typename T >
template< typename... Args >
inline T& T_Array< T >::insertNew(
		const uint32_t index ,
		Args&& ... args )
{
	using std::swap;
	addNew( std::forward< Args >( args ) ... );
	const auto last( size_ - 1 );
	for ( uint32_t i = index ; i < last ; i ++ ) {
		swap( data_[ i ] , data_[ last ] );
	}
	return data_[ index ];
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_Array< T >::remove(
		const uint32_t index ) noexcept
{
	assert( index < size_ );
	if ( index != size_ - 1 ) {
		if ( std::is_class< T >( ) ) {
			for ( auto i = index ; i < size_ - 1 ; i ++ ) {
				data_[ i ] = std::move( data_[ i + 1 ] );
			}
		} else {
			memmove( &data_[ index ] , &data_[ index + 1 ] ,
				( size_ - ( index + 1 ) ) * sizeof( T ) );
		}
	}
	data_[ size_ - 1 ].~T( );
	size_ --;
}

template< typename T >
inline void T_Array< T >::removeSwap(
		const uint32_t index ) noexcept
{
	assert( index < size_ );
	if ( index != size_ - 1 ) {
		data_[ index ] = std::move( data_[ size_ - 1 ] );
	}
	data_[ size_ - 1 ].~T( );
	size_ --;
}

template< typename T >
inline void T_Array< T >::removeLast( ) noexcept
{
	assert( size_ );
	data_[ size_ - 1 ].~T( );
	size_ --;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_Array< T >::sort(
		F_Comparator< T > cmp ) noexcept
{
	sort( 0 , size_ , std::move( cmp ) );
}

template< typename T >
inline void T_Array< T >::sort(
		const uint32_t first ,
		const uint32_t items ,
		F_Comparator< T > cmp ) noexcept
{
	if ( items != 0 ) {
		assert( first < size_ );
		assert( first + items <= size_ );
		Sort( &data_[ first ] , items , std::move( cmp ) );
	}
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T_Array< T > T_Array< T >::copyRange(
		const uint32_t first ,
		const uint32_t last ) const noexcept
{
	if ( first >= size_ || last < first ) {
		return T_Array< T >( 1 );
	}

	// FIXME use memcpy when !std::is_class< T >
	const auto l( std::min( last , size_ - 1 ) );
	T_Array< T > output( growth_ );
	output.ensureCapacity( l - first + 1 );
	for ( uint32_t i = first ; i <= l ; i ++ ) {
		output.add( data_[ i ] );
	}
	return output;
}

template< typename T >
inline T_Array< T > T_Array< T >::moveRange(
		const uint32_t first ,
		const uint32_t last ) noexcept
{
	if ( first >= size_ || last < first ) {
		return T_Array< T >( 1 );
	}

	// FIXME use memcpy when !std::is_class< T >
	const auto l( std::min( last , size_ - 1 ) );
	T_Array< T > output( growth_ );
	output.ensureCapacity( l - first + 1 );
	for ( uint32_t i = first ; i <= l ; i ++ ) {
		output.add( std::move( data_[ i ] ) );
	}
	return output;
}

/*----------------------------------------------------------------------------*/

#define M_ITER_( NAME ) typename T_Array< T >::T_ ##NAME

template< typename T >
inline M_ITER_( ConstIterator ) T_Array< T >::begin( ) const noexcept
{
	return T_ConstIterator( *this , 0 );
}

template< typename T >
inline M_ITER_( ConstIterator ) T_Array< T >::end( ) const noexcept
{
	return T_ConstIterator( *this , size_ );
}

template< typename T >
inline M_ITER_( Iterator ) T_Array< T >::begin( ) noexcept
{
	return T_Iterator( *this , 0 );
}

template< typename T >
inline M_ITER_( Iterator ) T_Array< T >::end( ) noexcept
{
	return T_Iterator( *this , size_ );
}

template< typename T >
inline M_ITER_( ConstReverseIterator ) T_Array< T >::rbegin( ) const noexcept
{
	return T_ConstReverseIterator( *this , 0 );
}

template< typename T >
inline M_ITER_( ConstReverseIterator ) T_Array< T >::rend( ) const noexcept
{
	return T_ConstReverseIterator( *this , size_ );
}

template< typename T >
inline M_ITER_( ReverseIterator ) T_Array< T >::rbegin( ) noexcept
{
	return T_ReverseIterator( *this , size_ - 1 );
}

template< typename T >
inline M_ITER_( ReverseIterator ) T_Array< T >::rend( ) noexcept
{
	return T_ReverseIterator( *this , -1 );
}

template< typename T >
inline M_ITER_( ConstIterator ) T_Array< T >::cbegin( ) const noexcept
{
	return T_ConstIterator( *this , 0 );
}

template< typename T >
inline M_ITER_( ConstIterator ) T_Array< T >::cend( ) const noexcept
{
	return T_ConstIterator( *this , size_ );
}

template< typename T >
inline M_ITER_( ConstReverseIterator ) T_Array< T >::crbegin( ) const noexcept
{
	return T_ConstReverseIterator( *this , 0 );
}

template< typename T >
inline M_ITER_( ConstReverseIterator ) T_Array< T >::crend( ) const noexcept
{
	return T_ConstReverseIterator( *this , size_ );
}

#undef M_ITER_


/*= T_Array::T_Iterator_ =====================================================*/

#define M_HDR_ template< typename T > template< ptrdiff_t D >
#define M_CNAME_ T_Array< T >::T_Iterator_< D >
#define M_CNAME_T_ typename T_Array< T >::template T_Iterator_< D >

/*----------------------------------------------------------------------------*/

M_HDR_ inline M_CNAME_::T_Iterator_(
		T_Array< T >& array ,
		const ptrdiff_t pos ) noexcept
	: array_( &array ) , pos_( pos )
{ }

M_HDR_ inline M_CNAME_::T_Iterator_( ) noexcept
	: array_( nullptr ) , pos_( 0 )
{ }

M_HDR_ inline M_CNAME_::T_Iterator_(
		T_Iterator_ const& other ) noexcept
	: array_( other.array_ ) , pos_( other.pos_ )
{ }

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator=(
		T_Iterator_ const& other ) noexcept
{
	array_ = other.array_;
	pos_ = other.pos_;
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , ptrdiff_t D>
inline void swap(
		M_CNAME_T_& lhs ,
		M_CNAME_T_& rhs ) noexcept
{
	std::swap( lhs.array_ , rhs.array_ );
	std::swap( lhs.pos_ , rhs.pos_ );
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline bool M_CNAME_::operator==(
		T_Iterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ == other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator!=(
		T_Iterator_ const& other ) const noexcept
{
	return array_ != other.array_ || pos_ != other.pos_;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline bool M_CNAME_::operator <(
		T_Iterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ < other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator<=(
		T_Iterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ <= other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator >(
		T_Iterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ > other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator>=(
		T_Iterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ >= other.pos_;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline T& M_CNAME_::operator*( ) const noexcept
{
	assert( valid( ) );
	return (*array_)[ pos_ ];
}

M_HDR_ inline T* M_CNAME_::operator->( ) const noexcept
{
	assert( valid( ) );
	return &((*array_)[ pos_ ]);
}

M_HDR_ inline T& M_CNAME_::operator[](
		const ptrdiff_t pos ) const noexcept
{
	const auto idx( pos + pos_ );
	assert( array_ && idx >= 0 && idx < array_->size( ) );
	return (*array_)[ idx ];
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator++ () noexcept
{
	assert( valid( ) );
	pos_ += D;
	return *this;
}

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator++ (int) noexcept
{
	assert( valid( ) );
	auto copy( *this );
	pos_ += D;
	return copy;
}

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator-- () noexcept
{
	assert( valid( ) );
	pos_ -= D;
	return *this;
}

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator-- (int) noexcept
{
	assert( valid( ) );
	auto copy( *this );
	pos_ -= D;
	return copy;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator +(
		const ptrdiff_t value ) const noexcept
{
	auto copy( *this );
	copy += value;
	return copy;
}

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator -(
		const ptrdiff_t value ) const noexcept
{
	auto copy( *this );
	copy -= value;
	return copy;
}

M_HDR_ inline ptrdiff_t M_CNAME_::operator -(
		M_CNAME_T_ const& other ) const noexcept
{
	assert( array_ && array_ == other.array_ );
	return pos_ - other.pos_;
}

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator +=(
		const ptrdiff_t value ) noexcept
{
	assert( valid( ) );
	pos_ = std::min( ptrdiff_t( array_->size( ) ) ,
		std::max( ptrdiff_t( -1 ) , pos_ + value * D ) );
	return *this;
}

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator -=(
		const ptrdiff_t value ) noexcept
{
	assert( valid( ) );
	pos_ = std::min( ptrdiff_t( array_->size( ) ) ,
		std::max( ptrdiff_t( -1 ) , pos_ - value * D ) );
	return *this;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline bool M_CNAME_::valid( ) const noexcept
{
	return array_ && pos_ >= 0 && pos_ < array_->size( );
}

M_HDR_ inline T_Array< T >* M_CNAME_::target( ) const noexcept
{
	return array_;
}

M_HDR_ inline ptrdiff_t M_CNAME_::pos( ) const noexcept
{
	return pos_;
}

/*----------------------------------------------------------------------------*/

#undef M_HDR_
#undef M_CNAME_
#undef M_CNAME_T_


/*= T_Array::T_ConstIterator_ ================================================*/

#define M_HDR_ template< typename T > template< ptrdiff_t D >
#define M_CNAME_ T_Array< T >::T_ConstIterator_< D >
#define M_CNAME_T_ typename T_Array< T >::template T_ConstIterator_< D >

/*----------------------------------------------------------------------------*/

M_HDR_ inline M_CNAME_::T_ConstIterator_(
		T_Array< T > const& array ,
		const ptrdiff_t pos ) noexcept
	: array_( &array ) , pos_( pos )
{ }

M_HDR_ inline M_CNAME_::T_ConstIterator_( ) noexcept
	: array_( nullptr ) , pos_( 0 )
{ }

M_HDR_ inline M_CNAME_::T_ConstIterator_(
		T_ConstIterator_ const& other ) noexcept
	: array_( other.array_ ) , pos_( other.pos_ )
{ }

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator=(
		T_ConstIterator_ const& other ) noexcept
{
	array_ = other.array_;
	pos_ = other.pos_;
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , ptrdiff_t D>
inline void swap(
		M_CNAME_T_& lhs ,
		M_CNAME_T_& rhs ) noexcept
{
	std::swap( lhs.array_ , rhs.array_ );
	std::swap( lhs.pos_ , rhs.pos_ );
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline bool M_CNAME_::operator==(
		T_ConstIterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ == other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator!=(
		T_ConstIterator_ const& other ) const noexcept
{
	return array_ != other.array_ || pos_ != other.pos_;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline bool M_CNAME_::operator <(
		T_ConstIterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ < other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator<=(
		T_ConstIterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ <= other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator >(
		T_ConstIterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ > other.pos_;
}

M_HDR_ inline bool M_CNAME_::operator>=(
		T_ConstIterator_ const& other ) const noexcept
{
	return array_ == other.array_ && pos_ >= other.pos_;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline T const& M_CNAME_::operator*( ) const noexcept
{
	assert( valid( ) );
	return (*array_)[ pos_ ];
}

M_HDR_ inline T const* M_CNAME_::operator->( ) const noexcept
{
	assert( valid( ) );
	return &((*array_)[ pos_ ]);
}

M_HDR_ inline T const& M_CNAME_::operator[](
		const ptrdiff_t pos ) const noexcept
{
	const auto idx( pos + pos_ );
	assert( array_ && idx >= 0 && idx < array_->size( ) );
	return (*array_)[ idx ];
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator++ () noexcept
{
	assert( valid( ) );
	pos_ += D;
	return *this;
}

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator++ (int) noexcept
{
	assert( valid( ) );
	auto copy( *this );
	pos_ += D;
	return copy;
}

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator-- () noexcept
{
	assert( valid( ) );
	pos_ -= D;
	return *this;
}

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator-- (int) noexcept
{
	assert( valid( ) );
	auto copy( *this );
	pos_ -= D;
	return copy;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator +(
		const ptrdiff_t value ) const noexcept
{
	auto copy( *this );
	copy += value;
	return copy;
}

M_HDR_ inline M_CNAME_T_ M_CNAME_::operator -(
		const ptrdiff_t value ) const noexcept
{
	auto copy( *this );
	copy -= value;
	return copy;
}

M_HDR_ inline ptrdiff_t M_CNAME_::operator -(
		M_CNAME_T_ const& other ) const noexcept
{
	assert( array_ && array_ == other.array_ );
	return pos_ - other.pos_;
}

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator +=(
		const ptrdiff_t value ) noexcept
{
	assert( valid( ) );
	pos_ = std::min( ptrdiff_t( array_->size( ) ) ,
		std::max( ptrdiff_t( -1 ) , pos_ + value * D ) );
	return *this;
}

M_HDR_ inline M_CNAME_T_& M_CNAME_::operator -=(
		const ptrdiff_t value ) noexcept
{
	assert( valid( ) );
	pos_ = std::min( ptrdiff_t( array_->size( ) ) ,
		std::max( ptrdiff_t( -1 ) , pos_ - value * D ) );
	return *this;
}

/*----------------------------------------------------------------------------*/

M_HDR_ inline bool M_CNAME_::valid( ) const noexcept
{
	return array_ && pos_ >= 0 && pos_ < array_->size( );
}

M_HDR_ inline T_Array< T >* M_CNAME_::target( ) const noexcept
{
	return array_;
}

M_HDR_ inline ptrdiff_t M_CNAME_::pos( ) const noexcept
{
	return pos_;
}

/*----------------------------------------------------------------------------*/

#undef M_HDR_
#undef M_CNAME_
#undef M_CNAME_T_

/*= T_StaticArray ============================================================*/

template< typename T , uint32_t S >
inline T_StaticArray< T , S >::T_StaticArray( ) noexcept
	: size_( 0 )
{ }

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline T_StaticArray< T , S >::T_StaticArray(
		T_Self const& source ) noexcept
	: size_( source.size_ )
{
	if ( std::is_class< T >( ) ) {
		for ( auto i = 0u ; i < size_ ; i ++ ) {
			::new ( (char*) &storage_[ i ] ) T( source[ i ] );
		}
	} else {
		std::memcpy( &storage_ , &source.storage_ ,
				size_ * sizeof( T_Storage_ ) );
	}
}

template< typename T , uint32_t S >
inline T_StaticArray< T , S >& T_StaticArray< T , S >::operator= (
		T_Self const& source ) noexcept
{
	clear( );
	size_ = source.size_;
	if ( std::is_class< T >( ) ) {
		for ( auto i = 0u ; i < size_ ; i ++ ) {
			::new ( (char*) &storage_[ i ] ) T( source[ i ] );
		}
	} else {
		std::memcpy( &storage_ , &source.storage_ ,
				size_ * sizeof( T_Storage_ ) );
	}
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline T_StaticArray< T , S >::T_StaticArray(
		T_Self&& source ) noexcept
	: size_( source.size_ )
{
	if ( std::is_class< T >( ) ) {
		for ( auto i = 0u ; i < size_ ; i ++ ) {
			::new ( (char*) &storage_[ i ] ) T( std::move( source[ i ] ) );
		}
	} else {
		std::memcpy( &storage_ , &source.storage_ ,
				size_ * sizeof( T_Storage_ ) );
	}
	source.clear( );
}

template< typename T , uint32_t S >
inline T_StaticArray< T , S >& T_StaticArray< T , S >::operator= (
		T_Self&& source ) noexcept
{
	clear( );
	size_ = source.size_;
	if ( std::is_class< T >( ) ) {
		for ( auto i = 0u ; i < size_ ; i ++ ) {
			::new ( (char*) &storage_[ i ] ) T( std::move( source[ i ] ) );
		}
	} else {
		std::memcpy( &storage_ , &source.storage_ ,
				size_ * sizeof( T_Storage_ ) );
	}
	source.clear( );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline T_StaticArray< T , S >::~T_StaticArray( ) noexcept
{
	clear( );
}

template< typename T , uint32_t S >
inline T_StaticArray< T , S >& T_StaticArray< T , S >::clear( ) noexcept
{
	for ( auto i = 0u ; i < size_ ; i ++ ) {
		reinterpret_cast< T* >( &storage_[ i ] )->T::~T( );
	}
	size_ = 0;
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
void swap(
		T_StaticArray< T , S >& lhs ,
		T_StaticArray< T , S >& rhs ) noexcept
{
	using T_ = T_StaticArray< T , S >;

	if ( lhs.size( ) && rhs.size( ) ) {
		T_ temp( std::move( rhs ) );
		rhs = std::move( lhs );
		lhs = std::move( temp );
	} else if ( lhs.size( ) || rhs.size( ) ) {
		T_& empty( lhs.size( ) ? rhs : lhs );
		T_& notEmpty( lhs.size( ) ? lhs : rhs );
		empty = std::move( notEmpty );
	}
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline constexpr uint32_t T_StaticArray< T , S >::capacity( ) const noexcept
{
	return S;
}

template< typename T , uint32_t S >
inline uint32_t T_StaticArray< T , S >::size( ) const noexcept
{
	return size_;
}

template< typename T , uint32_t S >
inline bool T_StaticArray< T , S >::empty( ) const noexcept
{
	return size_ != 0;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline T& T_StaticArray< T , S >::operator[] (
		const uint32_t index ) noexcept
{
	assert( index < size_ );
	return *reinterpret_cast< T* >( &storage_[ index ] );
}

template< typename T , uint32_t S >
inline T const& T_StaticArray< T , S >::operator[] (
		const uint32_t index ) const noexcept
{
	assert( index < size_ );
	return *reinterpret_cast< T const* >( &storage_[ index ] );
}

template< typename T , uint32_t S >
inline T& T_StaticArray< T , S >::last( ) noexcept
{
	assert( !empty( ) );
	return *reinterpret_cast< T* >( &storage_[ size_ - 1 ] );
}

template< typename T , uint32_t S >
inline T const& T_StaticArray< T , S >::last( ) const noexcept
{
	assert( !empty( ) );
	return *reinterpret_cast< T const* >( &storage_[ size_ - 1 ] );
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline int32_t T_StaticArray< T , S >::indexOf(
		T const& item ) const noexcept
{
	for ( auto i = 0u ; i < size_ ; i ++ ) {
		if ( (*this)[ i ] == item ) {
			return i;
		}
	}
	return -1;
}

template< typename T , uint32_t S >
inline bool T_StaticArray< T , S >::contains(
		T const& item ) const noexcept
{
	return indexOf( item ) != -1;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline uint32_t T_StaticArray< T , S >::add(
		T&& item ) noexcept
{
	assert( size_ < S );
	const auto index( size_ ++ );
	::new ( (char*) &storage_[ index ] ) T( std::move( item ) );
	return index;
}

template< typename T , uint32_t S >
inline uint32_t T_StaticArray< T , S >::add(
		T const& item ) noexcept
{
	assert( size_ < S );
	const auto index( size_ ++ );
	::new ( (char*) &storage_[ index ] ) T( item );
	return index;
}

template< typename T , uint32_t S >
template< typename... Args >
inline T& T_StaticArray< T , S >::addNew(
		Args&& ... args )
{
	assert( size_ < S );
	const auto index( size_ ++ );
	::new ( (char*) &storage_[ index ] ) T( std::forward< Args >( args ) ... );
	return (*this)[ index ];
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
T_StaticArray< T , S >& T_StaticArray< T , S >::addAll(
		T_Self const& other ) noexcept
{
	assert( size_ + other.size_ <= S );
	if ( std::is_class< T >( ) ) {
		for ( auto i = 0u ; i < other.size_ ; i ++ , size_ ++ ) {
			::new ( (char*) &storage_[ size_ ] ) T( other[ i ] );
		}
	} else {
		memcpy( &storage_[ size_ ] , &other.storage_[ 0 ] ,
				other.size_ * sizeof( T_Storage_ ) );
		size_ += other.size_;
	}
	return *this;
}

template< typename T , uint32_t S >
T_StaticArray< T , S >& T_StaticArray< T , S >::addAll(
		T_Self&& other ) noexcept
{
	assert( size_ + other.size_ <= S );
	if ( std::is_class< T >( ) ) {
		for ( auto i = 0u ; i < other.size_ ; i ++ , size_ ++ ) {
			::new ( (char*) &storage_[ size_ ] ) T( std::move( other[ i ] ) );
		}
	} else {
		memcpy( &storage_[ size_ ] , &other.storage_[ 0 ] ,
				other.size_ * sizeof( T_Storage_ ) );
		size_ += other.size_;
	}
	other.clear( );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline T_StaticArray< T , S >& T_StaticArray< T , S >::operator<< (
		T const& item ) noexcept
{
	add( item );
	return *this;
}

template< typename T , uint32_t S >
inline T_StaticArray< T , S >& T_StaticArray< T , S >::operator<< (
		T&& item ) noexcept
{
	add( std::move( item ) );
	return *this;
}

template< typename T , uint32_t S >
inline T_StaticArray< T , S >& T_StaticArray< T , S >::operator<< (
		T_Self const& other ) noexcept
{
	addAll( other );
	return *this;
}

template< typename T , uint32_t S >
inline T_StaticArray< T , S >& T_StaticArray< T , S >::operator<< (
		T_Self&& other ) noexcept
{
	addAll( std::move( other ) );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline void T_StaticArray< T , S >::insert(
		const uint32_t index ,
		T&& item ) noexcept
{
	assert( size_ < S );
	if ( std::is_class< T >( ) ) {
		const auto last( add( std::move( item ) ) );
		for ( uint32_t i = index ; i < last ; i ++ ) {
			using std::swap;
			swap( (*this)[ i ] , (*this)[ last ] );
		}
	} else {
		insert( index , (T const&) item );
	}
}

template< typename T , uint32_t S >
inline void T_StaticArray< T , S >::insert(
		const uint32_t index ,
		T const& item ) noexcept
{
	assert( size_ < S );
	if ( std::is_class< T >( ) ) {
		const auto last( add( item ) );
		for ( uint32_t i = index ; i < last ; i ++ ) {
			using std::swap;
			swap( (*this)[ i ] , (*this)[ last ] );
		}
	} else {
		if ( index < size_ ) {
			memmove( &storage_[ index + 1 ] , &storage_[ index ] ,
				sizeof( T_Storage_ ) * ( size_ - index ) );
		}
		*reinterpret_cast< T* >( &storage_[ index ] ) = item;
		size_ ++;
	}
}

template< typename T , uint32_t S >
template< typename... Args >
inline T& T_StaticArray< T , S >::insertNew(
		const uint32_t index ,
		Args&& ... args )
{
	addNew( std::forward< Args >( args ) ... );
	const auto last( size_ - 1 );
	for ( uint32_t i = index ; i < last ; i ++ ) {
		swap( (*this)[ i ] , (*this)[ last ] );
	}
	return (*this)[ index ];
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline void T_StaticArray< T , S >::remove(
		const uint32_t index ) noexcept
{
	assert( index < size_ );
	if ( index != size_ - 1 ) {
		if ( std::is_class< T >( ) ) {
			for ( auto i = index ; i < size_ - 1 ; i ++ ) {
				(*this)[ i ] = std::move( (*this)[ i + 1 ] );
			}
		} else {
			memmove( &storage_[ index ] , &storage_[ index + 1 ] ,
				( size_ - ( index + 1 ) ) * sizeof( T_Storage_ ) );
		}
	}
	(*this)[ size_ - 1 ].~T( );
	size_ --;
}

template< typename T , uint32_t S >
inline void T_StaticArray< T , S >::removeSwap(
		const uint32_t index ) noexcept
{
	assert( index < size_ );
	if ( index != size_ - 1 ) {
		(*this)[ index ] = std::move( (*this)[ size_ - 1 ] );
	}
	(*this)[ size_ - 1 ].~T( );
	size_ --;
}

template< typename T , uint32_t S >
inline void T_StaticArray< T , S >::removeLast( ) noexcept
{
	assert( size_ );
	(*this)[ size_ - 1 ].~T( );
	size_ --;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline void T_StaticArray< T , S >::sort(
		const F_Comparator< T > cmp ) noexcept
{
	sort( 0 , size_ , cmp );
}

template< typename T , uint32_t S >
inline void T_StaticArray< T , S >::sort(
		const uint32_t first ,
		const uint32_t items ,
		const F_Comparator< T > cmp ) noexcept
{
	if ( items != 0 ) {
		assert( first < size_ );
		assert( first + items <= size_ );
		Sort( &(*this)[ first ] , items , cmp );
	}
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S >
inline T_StaticArray< T , S > T_StaticArray< T , S >::copyRange(
		const uint32_t first ,
		const uint32_t last ) const noexcept
{
	if ( first >= size_ || last < first ) {
		return T_StaticArray< T , S >( );
	}

	const auto l( std::min( last , size_ - 1 ) );
	T_StaticArray< T , S > output;
	// FIXME use memcpy when !std::is_class< T >
	for ( uint32_t i = first ; i <= l ; i ++ ) {
		output.add( (*this)[ i ] );
	}
	return output;
}

template< typename T , uint32_t S >
inline T_StaticArray< T , S > T_StaticArray< T , S >::moveRange(
		const uint32_t first ,
		const uint32_t last ) noexcept
{
	if ( first >= size_ || last < first ) {
		return T_StaticArray< T , S >( );
	}

	const auto l( std::min( last , size_ - 1 ) );
	T_StaticArray< T , S > output;
	for ( uint32_t i = first ; i <= l ; i ++ ) {
		output.add( std::move( (*this)[ i ] ) );
	}
	return output;
}


/*= T_MultiArray ============================================================-*/

template< typename T >
inline void swap( T_MultiArray< T >& lhs , T_MultiArray< T >& rhs )
{
	using std::swap;
	swap( lhs.meta_ , rhs.meta_ );
	swap( lhs.values_ , rhs.values_ );
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_MultiArray< T >::next( )
{
	const auto sz( meta_.size( ) );
	const auto first( ( sz == 0 ) ? 0 : ( meta_[ sz - 2 ] + meta_[ sz - 1 ] ) );
	meta_ << first << 0;
}

template< typename T >
inline void T_MultiArray< T >::add( T value )
{
	if ( meta_.size( ) == 0 ) {
		meta_ << 0 << 1;
	} else {
		meta_[ meta_.size( ) - 1 ] ++;
	}
	values_ << value;
}

template< typename T >
template<
	typename Q ,
	typename... Args ,
	typename >
inline Q& T_MultiArray< T >::addNew( Args&& ... args )
{
	if ( meta_.size( ) == 0 ) {
		meta_ << 0 << 1;
	} else {
		meta_[ meta_.size( ) - 1 ] ++;
	}
	return values_.addNew( std::forward< Args >( args ) ... );
}

template< typename T >
inline void T_MultiArray< T >::copyFrom( T_Array< T > const& source )
{
	values_.addAll( source );
	if ( meta_.size( ) == 0 ) {
		meta_ << 0 << source.size( );
	} else {
		meta_[ meta_.size( ) - 1 ] += source.size( );
	}
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline uint32_t T_MultiArray< T >::size( ) const
{
	return meta_.size( ) >> 1;
}

template< typename T >
inline uint32_t T_MultiArray< T >::firstOf( uint32_t item ) const
{
	return meta_[ item * 2 ];
}

template< typename T >
inline uint32_t T_MultiArray< T >::sizeOf( uint32_t item ) const
{
	return meta_[ item * 2 + 1 ];
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T const& T_MultiArray< T >::get( uint32_t item , uint32_t sub ) const
{
	assert( sub < meta_[ item * 2 + 1 ] );
	return values_[ meta_[ item * 2 ] + sub ];
}

template< typename T >
inline T& T_MultiArray< T >::get( uint32_t item , uint32_t sub )
{
	assert( sub < meta_[ item * 2 + 1 ] );
	return values_[ meta_[ item * 2 ] + sub ];
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline T const& T_MultiArray< T >::operator[] ( uint32_t index ) const
{
	return values_[ index ];
}

template< typename T >
inline T& T_MultiArray< T >::operator[] ( uint32_t index )
{
	return values_[ index ];
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline bool T_MultiArray< T >::contains( uint32_t index , T const& value ) const
{
	const auto first( firstOf( index ) );
	const auto end( first + sizeOf( index ) );
	for ( uint32_t i = first ; i < end ; i ++ ) {
		if ( values_[ i ] == value ) {
			return true;
		}
	}
	return false;
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_MultiArray< T >::clear( )
{
	meta_.clear( );
	values_.clear( );
}

template< typename T >
inline void T_MultiArray< T >::free( )
{
	meta_.free( );
	values_.free( );
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_MultiArray< T >::copyFrom( uint32_t index )
{
	copyFrom( *this , index );
}

template< typename T >
inline void T_MultiArray< T >::copyFrom(
					T_MultiArray< T > const& other , uint32_t index )
{
	const auto size( other.sizeOf( index ) );
	if ( size == 0 ) {
		return;
	}

	const auto first( other.firstOf( index ) );
	T const* ptr( &( other[ first ] ) );
	for ( uint32_t i = 0 ; i < size ; i ++ , ptr ++ ) {
		values_ << *ptr;
	}
	if ( meta_.size( ) == 0 ) {
		meta_ << 0 << size;
	} else {
		meta_[ meta_.size( ) - 1 ] += size;
	}
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_MultiArray< T >::copyUnique( uint32_t index )
{
	copyUnique( *this , index );
}

template< typename T >
inline void T_MultiArray< T >::copyUnique( T_MultiArray< T > const& other , uint32_t index )
{
	const auto oSize( other.sizeOf( index ) );
	if ( oSize == 0 ) {
		return;
	}

	const auto ms( meta_.size( ) );
	const auto tSize( ms == 0 ? 0 : meta_[ ms - 1 ] );
	const auto tFirst( ms == 0 ? 0 : meta_[ ms - 2 ] );

	const auto oFirst( other.firstOf( index ) );
	T const* ptr( &( other[ oFirst ] ) );

	uint32_t added = 0;
	for ( uint32_t i = 0 ; i < oSize ; i ++ , ptr ++ ) {
		bool found = false;
		if ( tSize != 0 ) {
			T const* pCheck( &values_[ tFirst ] );
			for ( uint32_t j = 0 ; j < tSize ; j ++ , pCheck ++ ) {
				if ( *pCheck == *ptr ) {
					found = true;
					break;
				}
			}
		}
		if ( !found ) {
			values_ << *ptr;
			added ++;
		}
	}
	if ( ms == 0 ) {
		meta_ << 0 << added;
	} else {
		meta_[ ms - 1 ] += added;
	}
}

/*----------------------------------------------------------------------------*/

template< typename T >
inline void T_MultiArray< T >::sort( uint32_t index , F_Comparator< T > cmp )
{
	values_.sort( meta_[ index * 2 ] , meta_[ index * 2 + 1 ] , cmp );
}


/*= T_AutoArray ==============================================================*/

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >::T_AutoArray( ) noexcept
	: array_( )
{ }

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >::T_AutoArray(
		T_Self const& source ) noexcept
	: array_( source.array_ )
{ }

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::operator =(
		T_Self const& source ) noexcept
{
	array_ = source.array_;
	return *this;
}

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >::T_AutoArray(
		T_Self&& source ) noexcept
	: array_( std::move( source.array_ ) )
{ }

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::operator =(
		T_Self&& source ) noexcept
{
	array_ = std::move( source.array_ );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline void swap(
		T_AutoArray< T , S , G >& lhs ,
		T_AutoArray< T , S , G >& rhs ) noexcept
{
	swap( lhs.array_ , rhs.array_ );
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::clear( ) noexcept
{
	if ( isStatic( ) ) {
		static_( ).clear( );
	} else {
		dynamic_( ).clear( );
	}
	return *this;
}

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::free( ) noexcept
{
	array_ = T_Static_( );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline uint32_t T_AutoArray< T , S , G >::capacity( ) const noexcept
{
	return isStatic( ) ? S : dynamic_( ).capacity( );
}

template< typename T , uint32_t S , uint32_t G >
inline uint32_t T_AutoArray< T , S , G >::size( ) const noexcept
{
	return isStatic( ) ? static_( ).size( ) : dynamic_( ).size( );
}

template< typename T , uint32_t S , uint32_t G >
inline constexpr uint32_t T_AutoArray< T , S , G >::growth( ) const noexcept
{
	return G;
}

template< typename T , uint32_t S , uint32_t G >
inline bool T_AutoArray< T , S , G >::isStatic( ) const noexcept
{
	return array_.template hasType< T_Static_ >( );
}

template< typename T , uint32_t S , uint32_t G >
inline bool T_AutoArray< T , S , G >::empty( ) const noexcept
{
	return size( ) != 0;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::ensureCapacity(
		const uint32_t capacity ) noexcept
{
	if ( capacity > S ) {
		if ( isStatic( ) ) {
			convertToDynamic_( capacity );
		} else {
			dynamic_( ).ensureCapacity( capacity );
		}
	}
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline T& T_AutoArray< T , S , G >::operator[] (
		const uint32_t index ) noexcept
{
	return isStatic( ) ? static_( )[ index ] : dynamic_( )[ index ];
}

template< typename T , uint32_t S , uint32_t G >
inline T const& T_AutoArray< T , S , G >::operator[] (
		const uint32_t index ) const noexcept
{
	return isStatic( ) ? static_( )[ index ] : dynamic_( )[ index ];
}

template< typename T , uint32_t S , uint32_t G >
inline T& T_AutoArray< T , S , G >::last( ) noexcept
{
	assert( !empty( ) );
	return (*this)[ size( ) - 1 ];
}

template< typename T , uint32_t S , uint32_t G >
inline T const& T_AutoArray< T , S , G >::last( ) const noexcept
{
	assert( !empty( ) );
	return (*this)[ size( ) - 1 ];
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline int32_t T_AutoArray< T , S , G >::indexOf(
		T const& item ) const noexcept
{
	return isStatic( )
		? static_( ).indexOf( item )
		: dynamic_( ).indexOf( item );
}

template< typename T , uint32_t S , uint32_t G >
inline bool T_AutoArray< T , S , G >::contains(
		T const& item ) const noexcept
{
	return indexOf( item ) != -1;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline uint32_t T_AutoArray< T , S , G >::add(
		T const& item ) noexcept
{
	ensureCapacity( size( ) + 1 );
	return isStatic( ) ? static_( ).add( item ) : dynamic_( ).add( item );
}

template< typename T , uint32_t S , uint32_t G >
inline uint32_t T_AutoArray< T , S , G >::add(
		T&& item ) noexcept
{
	ensureCapacity( size( ) + 1 );
	return isStatic( )
		? static_( ).add( std::move( item ) )
		: dynamic_( ).add( std::move( item ) );
}

template< typename T , uint32_t S , uint32_t G >
template< typename... Args >
inline T& T_AutoArray< T , S , G >::addNew(
		Args&& ... args )
{
	ensureCapacity( size( ) + 1 );
	return isStatic( )
		? static_( ).addNew( std::forward< Args >( args ) ... )
		: dynamic_( ).addNew( std::forward< Args >( args ) ... );
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::addAll(
		T_Self const& other ) noexcept
{
	const auto osz( other.size( ) );
	if ( !osz ) {
		return *this;
	}

	// Try using container's native addAll() if we can
	const auto inisz( size( ) );
	const bool tst( isStatic( ) );
	const bool ost( other.isStatic( ) );
	if ( tst == ost && ( !tst || inisz + osz <= S ) ) {
		if ( tst ) {
			static_( ).addAll( other.static_( ) );
		} else {
			dynamic_( ).addAll( other.dynamic_( ) );
		}
		return *this;
	}

	// Otherwise we need to add manually.
	ensureCapacity( inisz + osz );
	if ( isStatic( ) ) {
		for ( uint32_t i = 0 ; i < osz ; i ++ ) {
			static_( ).add( other[ i ] );
		}
	} else {
		for ( uint32_t i = 0 ; i < osz ; i ++ ) {
			dynamic_( ).add( other[ i ] );
		}
	}

	return *this;
}

template< typename T , uint32_t S , uint32_t G >
inline T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::addAll(
		T_Self&& other ) noexcept
{
	const auto osz( other.size( ) );
	if ( !osz ) {
		return *this;
	}

	// Try using container's native addAll() if we can
	const auto inisz( size( ) );
	const bool tst( isStatic( ) );
	const bool ost( other.isStatic( ) );
	if ( tst == ost && ( !tst || inisz + osz <= S ) ) {
		if ( tst ) {
			static_( ).addAll( std::move( other.static_( ) ) );
		} else {
			dynamic_( ).addAll( std::move( other.dynamic_( ) ) );
		}
		return *this;
	}

	// Otherwise we need to add manually.
	ensureCapacity( inisz + osz );
	if ( isStatic( ) ) {
		for ( uint32_t i = 0 ; i < osz ; i ++ ) {
			static_( ).add( std::move( other[ i ] ) );
		}
	} else {
		for ( uint32_t i = 0 ; i < osz ; i ++ ) {
			dynamic_( ).add( std::move( other[ i ] ) );
		}
	}
	other.free( );

	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline void T_AutoArray< T , S , G >::insert(
		const uint32_t index ,
		T const& item ) noexcept
{
	ensureCapacity( size( ) + 1 );
	return isStatic( )
		? static_( ).insert( index , item )
		: dynamic_( ).insert( index , item );
}

template< typename T , uint32_t S , uint32_t G >
inline void T_AutoArray< T , S , G >::insert(
		const uint32_t index ,
		T&& item ) noexcept
{
	ensureCapacity( size( ) + 1 );
	return isStatic( )
		? static_( ).insert( index , std::move( item ) )
		: dynamic_( ).insert( index , std::move( item ) );
}

template< typename T , uint32_t S , uint32_t G >
template< typename... Args >
inline T& T_AutoArray< T , S , G >::insertNew(
		const uint32_t index ,
		Args&& ... args )
{
	ensureCapacity( size( ) + 1 );
	return isStatic( )
		? static_( ).insertNew( index , std::forward< Args >( args ) ... )
		: dynamic_( ).insertNew( index , std::forward< Args >( args ) ... );
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline void T_AutoArray< T , S , G >::remove(
		const uint32_t index ) noexcept
{
	isStatic( )
		? static_( ).remove( index )
		: dynamic_( ).remove( index );
}

template< typename T , uint32_t S , uint32_t G >
inline void T_AutoArray< T , S , G >::removeSwap(
		const uint32_t index ) noexcept
{
	isStatic( )
		? static_( ).removeSwap( index )
		: dynamic_( ).removeSwap( index );
}

template< typename T , uint32_t S , uint32_t G >
inline void T_AutoArray< T , S , G >::removeLast( ) noexcept
{
	assert( !empty( ) );
	remove( size( ) - 1 );
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
void T_AutoArray< T , S , G >::sort(
		F_Comparator< T > cmp ) noexcept
{
	sort( 0 , size( ) , std::move( cmp ) );
}

template< typename T , uint32_t S , uint32_t G >
void T_AutoArray< T , S , G >::sort(
		const uint32_t first ,
		const uint32_t items ,
		F_Comparator< T > cmp ) noexcept
{
	if ( isStatic( ) ) {
		static_( ).sort( first , items , std::move( cmp ) );
	} else {
		dynamic_( ).sort( first , items , std::move( cmp ) );
	}
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
T_AutoArray< T , S , G > T_AutoArray< T , S , G >::copyRange(
		const uint32_t first ,
		const uint32_t last ) const noexcept
{
	// XXX: this uses manual calls to underlying add() methods; it could
	// be optimised, but I'm not sure it's necessary to do so.

	auto const sz( size( ) );
	if ( first >= sz || last < first ) {
		return T_Self( );
	}

	const auto l( std::min( last , sz - 1 ) );
	T_Self nd;
	nd.ensureCapacity( l - first + 1 );
	if ( isStatic( ) ) {
		T_Static_ const& src( static_( ) );
		T_Static_& dst( nd.static_( ) );
		for ( auto i = first ; i <= l ; i ++ ) {
			dst.add( src[ i ] );
		}
	} else if ( nd.isStatic( ) ) {
		T_Dynamic_ const& src( dynamic_( ) );
		T_Static_& dst( nd.static_( ) );
		for ( auto i = first ; i <= l ; i ++ ) {
			dst.add( src[ i ] );
		}
	} else {
		T_Dynamic_ const& src( dynamic_( ) );
		T_Dynamic_& dst( nd.dynamic_( ) );
		for ( auto i = first ; i <= l ; i ++ ) {
			dst.add( src[ i ] );
		}
	}
	return nd;
}

template< typename T , uint32_t S , uint32_t G >
T_AutoArray< T , S , G > T_AutoArray< T , S , G >::moveRange(
		const uint32_t first ,
		const uint32_t last ) noexcept
{
	// XXX: this uses manual calls to underlying add() methods; it could
	// be optimised, but I'm not sure it's necessary to do so.

	auto const sz( size( ) );
	if ( first >= sz || last < first ) {
		return T_Self( );
	}

	const auto l( std::min( last , sz - 1 ) );
	T_Self nd;
	nd.ensureCapacity( l - first + 1 );
	if ( isStatic( ) ) {
		T_Static_& src( static_( ) );
		T_Static_& dst( nd.static_( ) );
		for ( auto i = first ; i <= l ; i ++ ) {
			dst.add( std::move( src[ i ] ) );
		}
	} else if ( nd.isStatic( ) ) {
		T_Dynamic_& src( dynamic_( ) );
		T_Static_& dst( nd.static_( ) );
		for ( auto i = first ; i <= l ; i ++ ) {
			dst.add( std::move( src[ i ] ) );
		}
	} else {
		T_Dynamic_& src( dynamic_( ) );
		T_Dynamic_& dst( nd.dynamic_( ) );
		for ( auto i = first ; i <= l ; i ++ ) {
			dst.add( std::move( src[ i ] ) );
		}
	}
	return nd;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
void T_AutoArray< T , S , G >::convertToDynamic_(
		const uint32_t capacity ) noexcept
{
	assert( isStatic( ) );
	T_Static_& s( static_( ) );
	T_Dynamic_ d{ G };
	d.ensureCapacity( std::max( s.capacity( ) , capacity ) );
	auto const sz( s.size( ) );
	for ( auto i = 0u ; i < sz ; i ++ ) {
		d.add( std::move( s[ i ] ) );
	}
	array_ = std::move( d );
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::operator<< (
		T const& item ) noexcept
{
	add( item );
	return *this;
}

template< typename T , uint32_t S , uint32_t G >
T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::operator<< (
		T&& item ) noexcept
{
	add( std::move( item ) );
	return *this;
}

template< typename T , uint32_t S , uint32_t G >
T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::operator<< (
		T_Self const& other ) noexcept
{
	addAll( other );
	return *this;
}

template< typename T , uint32_t S , uint32_t G >
T_AutoArray< T , S , G >& T_AutoArray< T , S , G >::operator<< (
		T_Self&& other ) noexcept
{
	addAll( std::move( other ) );
	return *this;
}

/*----------------------------------------------------------------------------*/

template< typename T , uint32_t S , uint32_t G >
inline T_StaticArray< T , S >& T_AutoArray< T , S , G >::static_( ) noexcept
{
	return array_.template value< T_Static_ >( );
}

template< typename T , uint32_t S , uint32_t G >
inline T_StaticArray< T , S > const& T_AutoArray< T , S , G >::static_( ) const noexcept
{
	return array_.template value< T_Static_ >( );
}

template< typename T , uint32_t S , uint32_t G >
inline T_Array< T >& T_AutoArray< T , S , G >::dynamic_( ) noexcept
{
	return array_.template value< T_Dynamic_ >( );
}

template< typename T , uint32_t S , uint32_t G >
inline T_Array< T > const& T_AutoArray< T , S , G >::dynamic_( ) const noexcept
{
	return array_.template value< T_Dynamic_ >( );
}


} // namespace
#endif // _H_EBCL_INLINE_ARRAYS