#pragma once

#include <cassert>


namespace lm
{


// 複数引数対応のmin,max.
template<typename T> inline T (min)( const T& a , const T& b )                           { return a < b ? a : b ;                                        }
template<typename T> inline T (min)( const T& a , const T& b , const T& c )              { return (lm::min)( (lm::min)( a , b ) , c ) ;                  }
template<typename T> inline T (min)( const T& a , const T& b , const T& c , const T& d ) { return (lm::min)( (lm::min)( a , b ) , (lm::min)( c , d ) ) ; }
template<typename T> inline T (max)( const T& a , const T& b )                           { return a > b ? a : b ;                                        }
template<typename T> inline T (max)( const T& a , const T& b , const T& c )              { return (lm::max)( (lm::max)( a , b ) , c ) ;                  }
template<typename T> inline T (max)( const T& a , const T& b , const T& c , const T& d ) { return (lm::max)( (lm::max)( a , b ) , (lm::max)( c , d ) ) ; }


// 値の範囲を制限する
template<typename T> inline T clamp( const T& i_min , const T& i_value , const T& i_max ) 
{
	assert( i_min <= i_max );

	return (lm::min)( (lm::max)( i_min , i_value ) , i_max );
}

template<typename T> inline T clamp_abs( const T& i_value , const T& i_range )
{
	assert( i_range >= T(0) );

	return clamp( -i_range , i_value , i_range );
}

template<typename T> inline T clamp_01( const T& i_value )
{
	return clamp( T(0) , i_value , T(1) );
}

template<typename T> inline T& get_pair( const T& value , const T& pair_a , const T& pair_b )
{
	assert( value == pair_a || value == pair_b );

	return value == pair_a ? pair_b : pair_a;
}


template<typename T> inline T pow2( const T& v ) { return v * v ;             }
template<typename T> inline T pow3( const T& v ) { return v * v * v ;         }
template<typename T> inline T pow4( const T& v ) { return pow2( v * v ) ;     }
template<typename T> inline T pow5( const T& v ) { return pow2( v * v ) * v ; }
template<typename T> inline T pow6( const T& v ) { return pow3( v * v ) ;     }
template<typename T> inline T pow7( const T& v ) { return pow3( v * v ) * v ; }
template<typename T> inline T pow8( const T& v ) { return pow4( v * v ) ;     }


template<typename T> inline T gcd( T a , T b )
{
	if( b > a ) (std::swap)( a , b );
	while( ( a = a % b ) != 0 ) (std::swap)( b , a );
	return b;
}

template<typename T> inline T lcm( const T& a , const T& b )
{
	return a * b / gcd( a , b );
}


}
