// ------------------------------------------------------------------------
/*
	author: Jaap Suter
   
	Copyright (C) Electronic Arts Canada Inc. 2002.  All rights reserved.	
*/
// ------------------------------------------------------------------------

/*! \file */

#ifndef REVEAL_TYPE_TRAITS_H
#define REVEAL_TYPE_TRAITS_H

#include <assert.h>

namespace Reveal {
    namespace TypeTraits {

// ------------------------------------------------------------------------
/*!
	\brief Compile-time meta-function that tests whether or not a type is
		   floating point (float or double).
    \param T type you want to check;
	\return ::value member true if T is floating point, false otherwise;
*/
// ------------------------------------------------------------------------
template< class T    > struct IsFloatingPoint		   { enum { value = false }; };

//! Implementation: Specialization for built-in floats
template<>			   struct IsFloatingPoint< float  >{ enum { value = true  }; };

//! Implementation: Specialization for built-in doubles
template<>			   struct IsFloatingPoint< double >{ enum { value = true  }; };

// ------------------------------------------------------------------------
/*!
	\brief Compile-time meta-function that tests whether or not a type is
		   the void type.
    \param T type you want to check;
	\return ::value member true if T is void, false otherwise;
*/
// ------------------------------------------------------------------------
template < class    T > struct IsVoid			{ enum { value = false }; };
template <>				struct IsVoid< void >	{ enum { value = true  }; };


// ------------------------------------------------------------------------
/*!
	\brief Compile-time meta-function that tests whether or not a type is
		   integral.
    \param T type you want to check;
	\return ::value member true if T is integral, false otherwise;
*/
// ------------------------------------------------------------------------
template< class   T > struct IsIntegral				   { enum { value = false }; };

//! Implementation: Specialization for unsigned short;
template<>			  struct IsIntegral< unsigned short  >{ enum { value = true  }; };

//! Implementation: Specialization for unsigned long;
template<>			  struct IsIntegral< unsigned long   >{ enum { value = true  }; };

//! Implementation: Specialization for unsigned int;
template<>			  struct IsIntegral< unsigned int    >{ enum { value = true  }; };

//! Implementation: Specialization for unsigned char;
template<>			  struct IsIntegral< unsigned char   >{ enum { value = true  }; };

//! Implementation: Specialization for signed short;
template<>			  struct IsIntegral<   signed short  >{ enum { value = true  }; };

//! Implementation: Specialization for signed long;
template<>			  struct IsIntegral<   signed long   >{ enum { value = true  }; };

//! Implementation: Specialization for signed int;
template<>			  struct IsIntegral<   signed int    >{ enum { value = true  }; };

//! Implementation: Specialization for signed char;
template<>			  struct IsIntegral<   signed char   >{ enum { value = true  }; };

//! Implementation: Specialization for char;
template<>			  struct IsIntegral<          char   >{ enum { value = true  }; };

// ------------------------------------------------------------------------
/*!
	\brief Converts a boolean to a type;
*/
// ------------------------------------------------------------------------
template < bool b >
struct BoolToType
{
	enum { value = b };
};


// ------------------------------------------------------------------------
/*!
	\brief Returns true if two types are the same;
	\note Uses SFINAE
*/
// ------------------------------------------------------------------------
struct No { char m; };
struct Yes { char m[2]; };

template < class A >
Yes IsSameImpl( A*, A* );

No IsSameImpl( ... );

template < class A, class B >
struct IsSame 
{ 
	enum { value = (sizeof( IsSameImpl( (A*)0, (B*)0 ) ) == sizeof( Yes )) }; 
};

template < bool Condition, class A, class B >
struct MetaIf
{
	typedef A type;
};

template < class A, class B >
struct MetaIf< false, A, B >
{
	typedef B type;
};

} // Namespace TypeTraits
} // Namespace Reveal

#endif
