/*****************************************************************************
 * $Id: gfx_funcs.hh,v 1.32 2006/11/18 22:05:26 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Various small functions: function macros, inline functions, template functions.
 * @remarks	Include this before gfx_types.hh.
 *          Writing "inline" in template functions does increase speed (gcc 3.4).
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#ifndef GFX_FUNCS_HH
#define GFX_FUNCS_HH 1

namespace gfx {

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// function macros ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

// Min()/Max() is strongly recommended and faster if either arg is a computation,
// but requires both args to be the same type.
// Macro MIN()/MAX() lets the compiler automatically convert args of different types,
// but be warned: has the well-known side-effect of compiling each arg twice!
template<typename T> inline T Min( T a, T b ) { return (a < b) ? a : b; }
template<typename T> inline T Max( T a, T b ) { return (a > b) ? a : b; }
#ifndef MIN
#define MIN(A,B) ( ((A) < (B)) ? (A) : (B) )
#endif
#ifndef MAX
#define MAX(A,B) ( ((A) > (B)) ? (A) : (B) )
#endif

// Uses overloaded abs() from <cmath>.
#define ABS(X) abs((X))

#ifndef STREQ
#define STREQ(A,B) ( strcmp((A),(B)) == 0 )
#endif
#ifndef STRNE
#define STRNE(A,B) ( strcmp((A),(B)) != 0 )
#endif
#ifndef STREMPTY
#define STREMPTY(S) ( ((S) == NULL) || ((S)[0] == '\0') )
#endif
#ifndef MEMEQ
#define MEMEQ(S1,S2,LEN) ( memcmp((S1),(S2),(LEN)) == 0 )
#endif
#ifndef MENNE
#define MEMNE(S1,S2,LEN) ( memcmp((S1),(S2),(LEN)) != 0 )
#endif
#define ELEMS(ARRAY) ((uint)( sizeof((ARRAY)) / sizeof((ARRAY)[0]) ))

// Read/write 32-bits by pointer portably.
#define READ_UINT32( PTR )       ( (*reinterpret_cast<uint32*>((PTR))) )
#define WRITE_UINT32( PTR, VAL ) ( (*reinterpret_cast<uint32*>((PTR))) = (VAL) )
#define COPY_UINT32( DEST, SRC ) ( (*reinterpret_cast<uint32*>((DEST))) = (*reinterpret_cast<const uint32*>((SRC))) )

/// True if axis is 0,1,2.
#define CHECK_AXIS( AXIS ) ( ((uint)(AXIS)) < 3 )

/// True if matrix index is in range 0..15.
#define CHECK_MATRIX_IDX( IDX ) ( ((IDX) & ~15) == 0 )

/// Nullifying a pointer after deleting can avoid memory corruption.
#define DELETE_NULL( OBJ )			delete   (OBJ), (OBJ) = NULL
#define DELETE_ARR_NULL( OBJ )		delete[] (OBJ), (OBJ) = NULL

/// Helper for correctly writing operator<() for STL container.
/// bool operator<( const C& a, const C& b )
/// {
///     RETURN_LT_TRUE_GT_FALSE( a.m1, b.m2 )
///     RETURN_LT_TRUE_GT_FALSE( a.m2, b.m3 )
///     return false;  // equal
/// }
#define RETURN_LT_TRUE_GT_FALSE( X, Y )			\
{												\
	if ( (X) < (Y) ) return true;				\
	if ( (Y) < (X) ) return false;				\
}

/// Pass address of bit-field struct.
/// CLEAR_BIT_FIELD( &mBits );
#define CLEAR_BIT_FIELD( BIT_FIELD_PTR ) ( *(reinterpret_cast<unsigned int*>( (BIT_FIELD_PTR) )) = 0 )

/// @def BUSY_BEGIN
/// A busy flag is used to prevent possible infinite recursion
/// in case function A calls B and B calls A.
#ifndef BUSY_BEGIN
#define BUSY_BEGIN  static int busy = 0; if ( busy ) return; ++busy;
#define BUSY_BEGIN_ASSERT static int busy = 0; ASSERT_OR_RETURN( ! busy ); ++busy;
#define BUSY_END	--busy;
#endif // BUSY_BEGIN

/// @def IF_ONCE
// IF_ONCE
// {
// }
#define IF_ONCE  static int once; if ( !once++ )

/// @def likely
/// Give branch hint to compiler.
#if __GNUC__ >= 3
#define likely(x)	__builtin_expect((x),1)
#define unlikely(x)	__builtin_expect((x),0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#define EX(x) likely((x))	///< abbrev for expected
#define UX(x) unlikely((x))	///< abbrev for unexpected

/// @def PACKMEMB
/// Tell compiler to pack a struct member.
#if __GNUC__
#define PACKMEMB __attribute__ ((packed))
#else
#define PACKMEMB
#endif

/// @def UNUSED
/// Tell compiler a var is unused.
#if GCC_VERSION > 0 && GCC_VERSION >= 30100 // if gcc-3.1 or later
#define UNUSED __attribute__ ((unused))
#else
#define UNUSED
#endif

/// Macros that only expand code according to a #define
#if DEBUG
#define DEBUG_CODE( CODE ) CODE
#else
#define DEBUG_CODE( CODE )
#endif

#if DEBUG == 2
#define DEBUG2_CODE( CODE ) CODE // pedantic excruciatingly slow debug code
#else
#define DEBUG2_CODE( CODE )
#endif

#if DEBUG && VERBOSE
#define DEBUG_VERBOSE_CODE( CODE ) CODE
#else
#define DEBUG_VERBOSE_CODE( CODE )
#endif

// To mark where code needs implementing.
#define UNIMPLEMENTED() ASSERT(0)

// C++ stream field formatting.
#if GCC_VERSION > 0 && GCC_VERSION < 30000
#define GFX_OMANIP_FIELD(CHARS) std::setw(CHARS)
#else
#define GFX_OMANIP_FIELD(CHARS) std::setw(CHARS) << std::right
#endif

// Prevent copying an object.  Put these in the private section of a class.
// The copy methods are prototypes without definitions, so usage causes a linker error.
#define PREVENT_COPYING( CLASS )                    \
private:                                            \
    CLASS( const CLASS& );                          \
    CLASS& operator=( const CLASS& );

// These are essentially comment to indicate a class is copyable.
#define COPYABLE( CLASS )          // means class is copyable by user-defined copying methods
#define COPYABLE_DEFAULT( CLASS )  // means class is copyable by compiler-generated copying methods

////////////////////////////////////////////////////////////////////////////////
/////////////////////////// inline functions ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/// Clear memory
static inline void
CLEAR( void* p, uint n )
{
	memset( p, 0, n );
}

/// Force a value negative.  Opposite of absolute.
static inline int         NEG( int         x ) { return (x < 0) ? x : -x; }
static inline long int    NEG( long int    x ) { return (x < 0) ? x : -x; }
static inline float       NEG( float       x ) { return (x < 0) ? x : -x; }
static inline double      NEG( double      x ) { return (x < 0) ? x : -x; }
static inline long double NEG( long double x ) { return (x < 0) ? x : -x; }

static inline bool
IfPow2( int n )
{
	// Trick: result is 0 if n is a power of 2.
    return (n & (n-1)) == 0;
}

////////////////////////////////////////////////////////////////////////////////
///////////////////////// template functions ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------------------
// Array template functions:
// - NewArray() applies to CREATING NEW arrays.
// - InitArray(), CopyArray() apply to EXISTING arrays
//------------------------------------------------------------------------------

#define DeleteArray( OBJ ) delete[] (OBJ), (OBJ) = NULL

////////////////////////////////////////////////////////////////////////////////
/// @brief Helper template function to copy an array into another.
/// Applies to existing arrays.
template<typename T>
inline void
CopyArray( T* dest, const T* src, const uint elemCnt )
{
	memcpy( dest, src, elemCnt * sizeof(T) );
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Helper template function to initialize (assign) an array.
/// Applies to an existing array.
/// ######################################################
/// ## DO NOT PASS sizeof(array) WHICH IS A BYTE COUNT! ##
/// ## Use the macro ELEMS(ARRAY).                      ##
/// ######################################################
template<typename T>
inline void
InitArray( T* arr, const uint elemCnt, T val )
{
	for ( uint i = 0; i < elemCnt; ++i ) arr[i] = val;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Helper template function to create a new copy of an existing array.
/// Applies to a new array.  Array should be freed using delete[].
template<typename T>
inline T*
NewArray( const T* src, const uint elemCnt )
{
	T* copy = new T[elemCnt];
	CopyArray<T>( copy, src, elemCnt );
	return copy;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Helper template function to create a new array and initialize all elements.
/// Applies to a new array.  Array should be freed using delete[].
template<typename T>
inline T*
NewArray( const uint elemCnt, T val )
{
	T* arr = new T[elemCnt];
	InitArray<T>( arr, elemCnt, val );
	return arr;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Template class for temporary arrays.
/// The array is automatically reallocated to handle Get() requests.
/// Instantiate only one global object for each type (multiple objects would waste memory).
/// Unlike a STL vector, reallocation doesn't copy values.
template<typename T>
class TempArray
{
public:
	TempArray( void )
	{
		mElems = 500;
		mArray = new T[mElems];
	}

	/// @param elems Initial amount of elements.
	TempArray( uint elems )
	{
		mElems = elems;
		mArray = new T[mElems];
	}

	~TempArray()
	{
		delete [] mArray;
	}

	/// @return A temporary array with at least this amount of elements.
	T* Get( uint elems )
	{
		if ( EX(elems < mElems) )
		{
			// The existing array is sufficient.
			return mArray;
		}
		else
		{
			// Allocate a new larger array.
			delete [] mArray;
			mElems = elems << 1;	// extra to reduce reallocations
			mArray = new T[mElems];
			return mArray;
		}
	}

private:
	T*		mArray;
	uint	mElems;
};

/*****************************************************************************
 * Little helpers.
 *****************************************************************************/
template<typename T>
inline bool
IfInRect( T x, T y, T xmax, T ymax )
{
	return    x >= 0
           && y >= 0
           && x <= xmax
           && y <= ymax;
}
template<typename T>
inline bool
IfInRect( T x, T y, T xmin, T ymin, T xmax, T ymax )
{
	return    x >= xmin
           && y >= ymin
           && x <= xmax
           && y <= ymax;
}

/*****************************************************************************
 * Swap.
 *****************************************************************************/
template<typename T>
inline void
Swap( T& a, T& b )
{
	T a2 = a;
	a = b;
	b = a2;
}

} // namespace gfx

#endif // GFX_FUNCS_HH
