#pragma once

namespace lm
{

template<typename T>
class tuple2
{
public:
	enum { NUM_ELEMENTS = 2 };


public:
	T x , y ;
	
	
public:
	tuple2(void)                     : x(     ), y(     ) {}
	tuple2(const T& _x, const T& _y) : x(_x   ), y(_y   ) {}
	tuple2(const tuple2<T>& t)       : x(t.x  ), y(t.y  ) {}
	tuple2(const T* _v)              : x(_v[0]), y(_v[1]) {}


	// 要素型が異なるtupleへのキャスト
	template<typename U>
	operator tuple2<U>(void) const
	{
		return tuple2<U>( static_cast<U>(x) , static_cast<U>(y) );
	}


	T*       v(void)       { return &x; }
	const T* v(void) const { return &x; }

	T&       operator[]( size_t idx )       { return v()[ idx ]; }
	const T& operator[]( size_t idx ) const { return v()[ idx ]; }
	
	T&       at( size_t idx );
	const T& at( size_t idx ) const;
	
	void set( const tuple2<T>& src );
	void set( const T* _v );
	void set( const T& _x, const T& _y );
	tuple2<T>& operator=( const tuple2<T>& t );

	void get( tuple2<T>& dst ) const;
	void get( T* _v ) const;
	void get( T& _x, T& _y ) const;
	
	bool equals( const tuple2<T>& t ) const;
	bool equals( const T* v ) const;
	bool equals( const T& _x, const T& _y ) const;
	bool operator==( const tuple2<T>& t ) const;
	bool operator!=( const tuple2<T>& t ) const;
};


typedef tuple2<double>        tuple2d;
typedef tuple2<float>         tuple2f;
typedef tuple2<int>           tuple2i;
typedef tuple2<unsigned int>  tuple2ui;
typedef tuple2<long>          tuple2l;
typedef tuple2<unsigned long> tuple2ul;


// tuple implements

template<typename T> inline
T& tuple2<T>::at( size_t idx )
{
	assert( idx < NUM_ELEMENTS );
	return v()[ idx ];
}
template<typename T> inline
const T& tuple2<T>::at( size_t idx ) const
{
	assert( idx < NUM_ELEMENTS );
	return v()[ idx ];
}


template<typename T> inline
void tuple2<T>::set( const tuple2<T>& src )
{
	set( src.x , src.y );
}
template<typename T> inline
void tuple2<T>::set( const T* _v )
{
	set( _v[0] , _v[1] );
}
template<typename T> inline
void tuple2<T>::set( const T& _x, const T& _y )
{
	x = _x ;  y = _y ;
}
template<typename T> inline
tuple2<T>& tuple2<T>::operator=( const tuple2<T>& t )
{
	set( t );
	return (*this);
}

	
template<typename T> inline
void tuple2<T>::get( tuple2<T>& dst ) const
{
	dst = *this;
}
template<typename T> inline
void tuple2<T>::get( T* _v ) const
{
	get( _v[0] , _v[1] );
}
template<typename T> inline
void tuple2<T>::get( T& _x, T& _y ) const
{
	_x = this->x ;  _y = this->y ;
}


template<typename T> inline
bool tuple2<T>::equals( const tuple2<T>& t ) const
{
	return equals( t.x , t.y );
}
template<typename T> inline
bool tuple2<T>::equals( const T* v ) const
{
	return equals( v[0] , v[1] );
}
template<typename T> inline
bool tuple2<T>::equals( const T& _x, const T& _y ) const
{
	return ( x == _x && y == _y );
}
template<typename T> inline
bool tuple2<T>::operator==( const tuple2<T>& t ) const
{
	return equals( t );
}
template<typename T> inline
bool tuple2<T>::operator!=( const tuple2<T>& t ) const
{
	return !equals( t );
}


}
