/*--------------------------------------------------------------------------
  Project:  Manual 2D Library - m2d
  File:     inlines.h

  Copyright (C)2007-2009 Nintendo  All Rights Reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law. They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Revision: $
 *-------------------------------------------------------------------------*/

/*
 * Defines small inline utility functions
 */


#ifndef NTMV_M2D_INLINES_H_
#define NTMV_M2D_INLINES_H_


#include <nitro/types.h>
#include <nnsys/misc.h>

namespace ntmv
{
namespace m2d
{

#ifdef NW4R_COMPILER_WITH_W64
typedef __w64 unsigned long IntPtr;
typedef __w64 signed long PtrDiff;
#else
typedef unsigned long IntPtr;
typedef signed long PtrDiff;
#endif

    /*-------------------------------------------------------------------------*
      Name:         Abs

      Description:  Returns the argument's absolute value.

      Arguments:    a

      Returns:      Returns the absolute value of a
     *-------------------------------------------------------------------------*/
    template <typename T>
    inline T
    Abs(T a)
    {
        return (a < 0) ? static_cast<T>(-a) : a;
    }
    
    /*-------------------------------------------------------------------------*
      Name:         Min

      Description:  Returns the smaller of two compared values.

      Arguments:    a, b:   Values to be compared

      Returns:      Returns the smaller of a and b
     *-------------------------------------------------------------------------*/
    template <typename T>
    inline T
    Min(T a, T b)
    {
        return (a > b) ? b: a;
    }



    /*-------------------------------------------------------------------------*
      Name:         Max

      Description:  Returns the larger of two compared values.

      Arguments:    a, b:   Values to be compared

      Returns:      Returns the larger of a and b
     *-------------------------------------------------------------------------*/
    template <typename T>
    inline T
    Max(T a, T b)
    {
        return (a < b) ? b: a;
    }


    /*-------------------------------------------------------------------------*
      Name:         Clamp

      Description:  Returns a value between low and high.

      Arguments:    x:      Values to be compared
                    low:    Minimum value
                    high:   Maximum value

      Returns:      If x < low, low. If x > high, high. Otherwise x.
     *-------------------------------------------------------------------------*/
    template <typename T>
    inline T
    Clamp(T x, T low, T high)
    {
        return (x > high) ? high : ( (x < low) ? low : x );
    }



    /*-------------------------------------------------------------------------*
      Name:         RoundUp

      Description:  Rounds x up to a multiple of base.

      Arguments:    x:      Number to be rounded up.
                    base:   Value used as the basis for rounding up.
                            Must be a power of 2.

      Returns:      Returns the value resulting from rounding x up to a multiple of base.
     *-------------------------------------------------------------------------*/
    template <typename ValueT> ValueT RoundUp(ValueT x, unsigned int base);

    template <typename ValueT>
    inline void*
    RoundUp(ValueT* x, unsigned int base)
    {
        IntPtr value = reinterpret_cast<IntPtr>(x);
        IntPtr rounded = (value + (base - 1)) & ~(base - 1);
        
        return reinterpret_cast<void*>(rounded);
    }

    template <typename ValueT>
    inline const void*
    RoundUp(const ValueT* x, unsigned int base)
    {
        IntPtr value = reinterpret_cast<IntPtr>(x);
        IntPtr rounded = (value + (base - 1)) & ~(base - 1);
        
        return reinterpret_cast<const void*>(rounded);
    }

    template <typename ValueT>
    inline ValueT
    RoundUp(ValueT x, unsigned int base)
    {
        return static_cast<ValueT>( (x + (base - 1)) & ~(base - 1) );
    }


    /*-------------------------------------------------------------------------*
      Name:         RoundDown

      Description:  Rounds x down to a multiple of base.

      Arguments:    x:      Number to be rounded down.
                    base:   Value used as the basis for rounding down. Must be a power of 2.

      Returns:      Returns the value resulting from rounding x down to a multiple of base.
     *-------------------------------------------------------------------------*/
    template <typename ValueT> ValueT RoundDown(ValueT x, unsigned int base);

    template <typename ValueT>
    inline void*
    RoundDown(ValueT* x, unsigned int base)
    {
        IntPtr value = reinterpret_cast<IntPtr>(x);
        IntPtr rounded = value  & ~(base - 1);

        return reinterpret_cast<void*>(rounded);
    }

    template <typename ValueT>
    inline const void*
    RoundDown(const ValueT* x, unsigned int base)
    {
        IntPtr value = reinterpret_cast<IntPtr>(x);
        IntPtr rounded = value  & ~(base - 1);

        return reinterpret_cast<const void*>(rounded);
    }

    template <typename ValueT>
    inline ValueT
    RoundDown(ValueT x, unsigned int base)
    {
        return static_cast<ValueT>( x & ~(base - 1) );
    }


    /*-------------------------------------------------------------------------*
      Name:         DivUp

      Description:  Divides x by y and rounds up to the nearest integer.

      Arguments:    x:  Number to be divided.
                    y:  Number to divide by.

      Returns:      Returns the result of dividing x by y and rounding up to the nearest integer.
     *-------------------------------------------------------------------------*/
     inline int
     DivUp(int x, int y)
     {
        return (x + (y-1)) / y;
     }

    /*-------------------------------------------------------------------------*
      Name:         BitExtract

      Description:  Extracts a partial bit string from a bit string.

      Arguments:    bits:   Original bit string
                    pos:    Position of the lowest order bit of the bit string to be extracted from bits
                    len:    Bit length to be extracted

      Returns:      Returns the extracted bit string.
     *-------------------------------------------------------------------------*/
    template <typename OutputT>
    inline OutputT
    BitExtract(OutputT bits, int pos, int len=1)
    {
        const OutputT mask = static_cast<OutputT>( ( 1UL << len ) - 1 );
        return static_cast<OutputT>( (bits >> pos) & mask );
    }


    /*-------------------------------------------------------------------------*
      Name:         ReverseEndian

      Description:  Reverses endianness.

      Arguments:    x:      Number to be reversed.

      Returns:      Reverses the endianness of x and returns the result.
     *-------------------------------------------------------------------------*/
    inline u32
    ReverseEndian( u32 x )
    {
        return static_cast<u32>(
            BitExtract( x,  0, 8 ) << 24 |
            BitExtract( x,  8, 8 ) << 16 |
            BitExtract( x, 16, 8 ) <<  8 |
            BitExtract( x, 24, 8 ) <<  0
        );
    }

    inline s32
    ReverseEndian( s32 x )
    {
        return static_cast<s32>(
            BitExtract( x,  0, 8 ) << 24 |
            BitExtract( x,  8, 8 ) << 16 |
            BitExtract( x, 16, 8 ) <<  8 |
            BitExtract( x, 24, 8 ) <<  0
        );
    }

    inline u16
    ReverseEndian( u16 x )
    {
        return static_cast<u16>(
            BitExtract( x,  0, 8 ) << 8 |
            BitExtract( x,  8, 8 ) << 0
        );
    }

    inline s16
    ReverseEndian( s16 x )
    {
        return static_cast<s16>(
            BitExtract( x,  0, 8 ) << 8 |
            BitExtract( x,  8, 8 ) << 0
        );
    }

    /*-------------------------------------------------------------------------*
      Name:         GetIntPtr

      Description:  Casts from pointer to IntPtr.

      Arguments:    ptr     Pointer

      Returns:      Returns the value of ptr cast to IntPtr.
     *-------------------------------------------------------------------------*/
    inline IntPtr
    GetIntPtr( const void* ptr )
    {
        return reinterpret_cast<IntPtr>( ptr );
    }


    /*-------------------------------------------------------------------------*
      Name:         GetOffsetFromPtr

      Description:  Get the offset values for two pointer addresses as long integers.

      Arguments:    start   Start address
                    end     End address

      Returns:      Returns the offset value for the two pointers.
     *-------------------------------------------------------------------------*/
    inline PtrDiff
    GetOffsetFromPtr( const void* start, const void* end )
    {
        return static_cast<PtrDiff>(GetIntPtr(end) - GetIntPtr(start));
    }


    /*-------------------------------------------------------------------------*
      Name:         AddOffsetToPtr

      Description:  Add the offset value to the pointer.

      Arguments:    ptr     Pointer
                    offset  Offset value

      Returns:      Returns the address of ptr with offset applied as the same type of pointer as the argument.
     *-------------------------------------------------------------------------*/
    template <typename T>
    inline void*
    AddOffsetToPtr( void* ptr, T offset )
    {
        return reinterpret_cast<void*>( GetIntPtr(ptr) + offset );
    }
    template <typename T>
    inline const void*
    AddOffsetToPtr( const void* ptr, T offset )
    {
        return reinterpret_cast<const void*>( GetIntPtr(ptr) + offset );
    }

    inline void*
    AddU32ToPtr( void* ptr, u32 offset )
    {
        return AddOffsetToPtr( ptr, offset );
    }
    inline const void*
    AddU32ToPtr( const void* ptr, u32 offset )
    {
        return AddOffsetToPtr( ptr, offset );
    }

    /*-------------------------------------------------------------------------*
      Name:         ComparePtr

      Description:  Compares two pointer addresses.

      Arguments:    a   comparison source pointer
                    b   comparison target pointer

      Returns:      > 0: If the address pointed by 'a' is larger than the address pointed by 'b'
                    = 0: If the address pointed by 'a' and the address pointed by 'b' are equal
                    < 0: If the address pointed by 'a' is smaller than the address pointed by 'b'
     *-------------------------------------------------------------------------*/
    inline int
    ComparePtr( const void* a, const void* b )
    {
        return static_cast<int>( GetIntPtr( a ) - GetIntPtr( b ) );
    }

    /*-------------------------------------------------------------------------*
      Name:         NonCopyable

      Description:  Class indicating that copying is forbidden
     *-------------------------------------------------------------------------*/
    class NonCopyable
    {
      protected:
        NonCopyable() {}
        ~NonCopyable() {}
      private:
        NonCopyable( const NonCopyable& );
        const NonCopyable& operator=( const NonCopyable& );
    };

}   // namespace m2d
}   // namespace ntmv

#endif //  NTMV_M2D_INLINES_H_
