2012-05-29 13:31:11 +00:00
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# ifndef UTILS_H
# define UTILS_H
//-------------------------------------------------------------------------------------------------
// includes
//-------------------------------------------------------------------------------------------------
# include "nel/misc/types_nl.h"
# include "nel/misc/common.h"
# include "nel/misc/debug.h"
# include "nel/misc/sstring.h"
# include <list>
//-------------------------------------------------------------------------------------------------
// UTILITY FUNCTIONS
//-------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline std : : string capitalize ( const std : : string & s )
{
if ( s . empty ( ) )
return s ;
return NLMISC : : toUpper ( s . substr ( 0 , 1 ) ) + NLMISC : : toLower ( s . substr ( 1 , std : : string : : npos ) ) ;
}
inline ucstring capitalize ( const ucstring & s )
{
if ( s . empty ( ) )
return s ;
return NLMISC : : toUpper ( s . substr ( 0 , 1 ) ) + NLMISC : : toLower ( s . substr ( 1 , std : : string : : npos ) ) ;
}
//-------------------------------------------------------------------------------------------------
// HANDY MACROS - For forcing the pre-preprocessor to evaluate concatenation operations nicely
//-------------------------------------------------------------------------------------------------
// a Few examples:
// ---------------
//
// #define TOTO TATA
// MACRO_CONCAT(a,TOTO) => aTOTO
// MACRO_CONCAT2(a,TOTO) => aTATA
// MACRO_TOTXT(TOTO) => "TOTO"
// MACRO_TOTXT2(TOTO) => "TATA"
//
/// MACRO_CONCAT(a,__LINE__) => a__LINE__
// MACRO_CONCAT2(a,__LINE__) => a123
// MACRO_TOTXT(__LINE__) => "__LINE__"
// MACRO_TOTXT2(__LINE__) => "123"
//
// __FILE_LINE__ => "utils.h:123:"
# define MACRO_CONCAT(a,b) a##b
# define MACRO_CONCAT2(a,b) CONCAT(a,b)
# define MACRO_TOTXT(a) #a
# define MACRO_TOTXT2(a) TOTXT(a)
# define __FILE_LINE__ __FILE__ ":"TOTXT2(__LINE__)":"
//-------------------------------------------------------------------------------------------------
// LOGGING / DEBUGGING MACROS
//-------------------------------------------------------------------------------------------------
# ifdef NL_DEBUG
# define DEBUG_STOP nlstop;
# define nlassertd(a) nlassert(a)
# else
# define DEBUG_STOP \
std : : string stack ; \
NLMISC : : getCallStack ( stack ) ; \
std : : vector < std : : string > contexts ; \
NLMISC : : explode ( stack , std : : string ( " \n " ) , contexts ) ; \
nldebug ( " Dumping callstack : " ) ; \
for ( uint i = 0 ; i < contexts . size ( ) ; + + i ) \
nldebug ( " %3u : %s " , i , contexts [ i ] . c_str ( ) ) ;
# define nlassertd(a) if (0) { } else { }
# endif
// the following set of definess can be undefined and re-defined to add user code to execute
// systematically when GIVEUP, DROP or BOMB macros are triggered
// eg #define ON_BOMB logError(__FILE__,__LINE__,msg);
# define ON_GIVEUP
# define ON_DROP
# define ON_BOMB
// info and warning macros
# define INFO(msg) nlinfo((NLMISC::CSString()<<msg).c_str());
# define WARN(msg) nlwarning((NLMISC::CSString()<<msg).c_str());
// unconditional abort macros
# define STOP(msg) { WARN(msg) DEBUG_STOP }
# define GIVEUP(msg,action) { INFO(msg) { ON_GIVEUP; } { action; } }
# define DROP(msg,action) { WARN(msg) { ON_DROP; } { action; } }
# define BOMB(msg,action) { STOP(msg) { ON_BOMB; } { action; } }
// conditional warn and abort macros
# define GIVEUP_IF(condition,msg,action) if (!(condition));else GIVEUP(msg,action)
# define WARN_IF(condition,msg) if (!(condition));else WARN(msg)
# define DROP_IF(condition,msg,action) if (!(condition));else DROP(msg,action)
# define BOMB_IF(condition,msg,action) if (!(condition));else BOMB(msg,action)
# define STOP_IF(condition,msg) if (!(condition));else STOP(msg)
// testing for variable value changes
# define ON_CHANGE(type,var,code)\
class __COnChange # # var \
{ \
public : \
const type & _Var ; \
const type _OldVal ; \
__COnChange # # var ( const type & var ) : _Var ( var ) , _OldVal ( var ) { } \
~ __COnChange # # var ( ) { if ( _OldVal ! = _Var ) { code ; } } \
} \
__onChange # # __LINE__ ( var ) ;
# define ON_CHANGE_ASSERT(type,var) ON_CHANGE(type,var,nlerror("Variable "#var" changed from %s to %s",NLMISC::toString(_OldVal).c_str(),NLMISC::toString(_Var).c_str()))
//-------------------------------------------------------------------------------------------------
// A handy 'nldebug', 'nlinfo' & 'nlwarning' override system
//-------------------------------------------------------------------------------------------------
//
// The system includes a set of object classes
// To override one or more of the standard NeL log channels one simply instantiates the appropriate class
// with the new log channel as a parameter.
// The log channel in question will revert to its previous value on destruction of the override object
//
// Usage Example:
//
// void doSomething()
// {
// nlinfo("bla");
// nlwarning("bla");
// }
//
// NLMISC_COMMAND(bla,"bla","bla")
// {
// CNLLogOverride(&log);
// doSomething();
// return true;
// }
//
//-------------------------------------------------------------------------------------------------
//class CNLDebugOverride
//{
//public:
// CNLDebugOverride(NLMISC::CLog *debugLog)
// {
// nlassert(debugLog!=NULL);
// _OldValue=NLMISC::DebugLog;
// nlassert(_OldValue!=NULL);
// NLMISC::INelContext::getInstance().setDebugLog(debugLog);
// }
// ~CNLDebugOverride()
// {
// NLMISC::INelContext::getInstance().setDebugLog(_OldValue);
// }
//private:
// // prohibit copy
// CNLDebugOverride(const CNLDebugOverride&);
// NLMISC::CLog *_OldValue;
//};
//
////-------------------------------------------------------------------------------------------------
//
//class CNLInfoOverride
//{
//public:
// CNLInfoOverride(NLMISC::CLog *infoLog)
// {
// nlassert(infoLog!=NULL);
// _OldValue=NLMISC::InfoLog;
// nlassert(_OldValue!=NULL);
// NLMISC::INelContext::getInstance().setInfoLog(infoLog);
// }
// ~CNLInfoOverride()
// {
// NLMISC::INelContext::getInstance().setInfoLog(_OldValue);
// }
//private:
// // prohibit copy
// CNLInfoOverride(const CNLInfoOverride&);
// NLMISC::CLog *_OldValue;
//};
//
////-------------------------------------------------------------------------------------------------
//
//class CNLWarningOverride
//{
//public:
// CNLWarningOverride(NLMISC::CLog *warningLog)
// {
// nlassert(warningLog!=NULL);
// _OldValue=NLMISC::WarningLog;
// nlassert(_OldValue!=NULL);
// NLMISC::INelContext::getInstance().setWarningLog(warningLog);
// }
// ~CNLWarningOverride()
// {
// NLMISC::INelContext::getInstance().setWarningLog(_OldValue);
// }
//private:
// // prohibit copy
// CNLWarningOverride(const CNLWarningOverride&);
// NLMISC::CLog *_OldValue;
//};
//
////-------------------------------------------------------------------------------------------------
//
//class CNLLogOverride
//{
//public:
// CNLLogOverride(NLMISC::CLog *commonLog): _DebugLog(commonLog), _InfoLog(commonLog), _WarningLog(commonLog) {}
//
//private:
// CNLDebugOverride _DebugLog;
// CNLInfoOverride _InfoLog;
// CNLWarningOverride _WarningLog;
//};
//
//
////-------------------------------------------------------------------------------------------------
//
//class CNLSmartLogOverride
//{
//public:
// CNLSmartLogOverride(NLMISC::CLog *commonLog):
// _DebugLog(commonLog==NLMISC::InfoLog?NLMISC::DebugLog:commonLog),
// _InfoLog(commonLog),
// _WarningLog(commonLog==NLMISC::InfoLog?NLMISC::WarningLog:commonLog)
// {}
//
//private:
// CNLDebugOverride _DebugLog;
// CNLInfoOverride _InfoLog;
// CNLWarningOverride _WarningLog;
//};
//-------------------------------------------------------------------------------------------------
// A Little CallStack system
//-------------------------------------------------------------------------------------------------
// example:
// void traceTest2(int i)
// {
// CSTRACE;
// if (i<2)
// traceTest2(++i);
// else
// SHOW_CALLSTACK;
// }
//
// void traceTest()
// {
// CSTRACE_MSG("foo");
// traceTest2(0);
// {
// int i=0;
// CSTRACE_VAR(int,i);
// CSTRACE_VAL(int,i);
// i=1;
// SHOW_CALLSTACK;
// }
// WARN_CALLSTACK;
// }
//
// output:
// INF 3980: >>test.cpp:21: Call Stack:
// INF 3980: >>test.cpp:17
// INF 3980: >>test.cpp:17
// INF 3980: >>test.cpp:17
// INF 3980: >>test.cpp:26: foo
// INF 3980:
// INF 3980: >>test.cpp:33: Call Stack:
// INF 3980: >>test.cpp:31: i=[0]
// INF 3980: >>test.cpp:30: i=>[1]
// INF 3980: >>test.cpp:26: foo
// INF 3980:
// WRN 3980: >>test.cpp:35: Call Stack:
// WRN 3980: >>test.cpp:26: foo
// WRN 3980:
//-------------------------------------------------------------------------------------------------
// A Little CallStack system - MACROS
//-------------------------------------------------------------------------------------------------
// CSTRACE - displays source file and line number
// CSTRACE_MSG(msg) - as with trace but with additional simple text message eg TRACE_MSG("hello world")
// CSTRACE_VAL(type,name) - displays a value (calculated at the moment that the trace is created)
// CSTRACE_VAR(type,name) - displays the value of the given variable at the moment that callstack is displayed
// SHOW_CALLSTACK - displays the callstack using NLMISC::InfoLog
// WARN_CALLSTACK - displays the callstack using NLMISC::WarningLog
# define CSTRACE\
class __CCallStackEntry # # __LINE__ : public ICallStackEntry \
{ \
public : \
virtual void displayEntry ( NLMISC : : CLog & log ) const \
{ \
log . displayNL ( " >> " __FILE__ " :%d " , __LINE__ ) ; \
} \
} \
__callStackEntry # # __LINE__ ;
# define CSTRACE_MSG(msg)\
class __CCallStackEntry # # __LINE__ : public ICallStackEntry \
{ \
public : \
virtual void displayEntry ( NLMISC : : CLog & log ) const \
{ \
log . displayNL ( " >> " __FILE__ " :%d: %s " , __LINE__ , msg ) ; \
} \
} \
__callStackEntry # # __LINE__ ;
# define CSTRACE_VAL(type,var)\
class __TraceVal_ # # var : public ICallStackEntry \
{ \
public : \
__TraceVal_ # # var ( const type & var ) : _Val ( var ) \
{ \
} \
virtual void displayEntry ( NLMISC : : CLog & log ) const \
{ \
log . displayNL ( " >> " __FILE__ " :%d: %s=[%s] " , __LINE__ , # var , NLMISC : : toString ( _Val ) . c_str ( ) ) ; \
} \
const type _Val ; \
} \
__traceVal_ # # var ( var ) ;
# define CSTRACE_VAR(type,var)\
class __TraceVar_ # # var : public ICallStackEntry \
{ \
public : \
__TraceVar_ # # var ( const type & var ) : _Var ( var ) \
{ \
} \
virtual void displayEntry ( NLMISC : : CLog & log ) const \
{ \
log . displayNL ( " >> " __FILE__ " :%d: %s=>[%s] " , __LINE__ , # var , NLMISC : : toString ( _Var ) . c_str ( ) ) ; \
} \
const type & _Var ; \
} \
__traceVar_ # # var ( var ) ;
# define SHOW_CALLSTACK { CSTRACE_MSG("Call Stack:"); CCallStackSingleton::display(NLMISC::InfoLog); }
# define WARN_CALLSTACK { CSTRACE_MSG("Call Stack:"); CCallStackSingleton::display(NLMISC::WarningLog); }
//-------------------------------------------------------------------------------------------------
// A Little CallStack system - Private stack entry base class
//-------------------------------------------------------------------------------------------------
class ICallStackEntry
{
public :
ICallStackEntry ( ) ;
virtual ~ ICallStackEntry ( ) ;
void displayStack ( NLMISC : : CLog & log ) const ;
virtual void displayEntry ( NLMISC : : CLog & log ) const = 0 ;
private :
ICallStackEntry * _Next ;
} ;
//-------------------------------------------------------------------------------------------------
// A Little CallStack system - Public Singleton Class
//-------------------------------------------------------------------------------------------------
class CCallStackSingleton
{
public :
static ICallStackEntry * getTopStackEntry ( ) ;
static void setTopStackEntry ( ICallStackEntry * newEntry ) ;
static void display ( NLMISC : : CLog * log = NLMISC : : InfoLog ) ;
private :
// this is a singleton so prohibit public construction
CCallStackSingleton ( ) { }
// encapsulation of a variable to make it a singleton
static ICallStackEntry * & topStackEntry ( ) ;
} ;
//-------------------------------------------------------------------------------------------------
// A Little CallStack system - Public Singleton inlines
//-------------------------------------------------------------------------------------------------
inline ICallStackEntry * CCallStackSingleton : : getTopStackEntry ( )
{
return topStackEntry ( ) ;
}
inline void CCallStackSingleton : : setTopStackEntry ( ICallStackEntry * newEntry )
{
topStackEntry ( ) = newEntry ;
}
inline void CCallStackSingleton : : display ( NLMISC : : CLog * log )
{
nlassert ( log ! = NULL ) ;
getTopStackEntry ( ) - > displayStack ( * log ) ;
log - > displayNL ( " " ) ;
}
inline ICallStackEntry * & CCallStackSingleton : : topStackEntry ( )
{
static ICallStackEntry * stackEntry = NULL ;
return stackEntry ;
}
//-------------------------------------------------------------------------------------------------
// A Little CallStack system - Private stack entry base inlines
//-------------------------------------------------------------------------------------------------
inline ICallStackEntry : : ICallStackEntry ( )
{
// add self to the call stack
_Next = CCallStackSingleton : : getTopStackEntry ( ) ;
CCallStackSingleton : : setTopStackEntry ( this ) ;
}
inline ICallStackEntry : : ~ ICallStackEntry ( )
{
// if this object is in the call stack then pop items off the top of the stack
// until this object is no longer in the stack
while ( _Next ! = this )
{
// get a pointer to the top object on the call stack
ICallStackEntry * entry = CCallStackSingleton : : getTopStackEntry ( ) ;
nlassertd ( entry ! = NULL ) ;
// pop the object off the callstack
CCallStackSingleton : : setTopStackEntry ( entry - > _Next ) ;
// mark object as no longer in callstack
entry - > _Next = entry ;
}
}
inline void ICallStackEntry : : displayStack ( NLMISC : : CLog & log ) const
{
// stop recursing when we reach a NULL object
// (this is implemented in this way in order to ximplify call code)
if ( this = = NULL )
return ;
// display this entry
displayEntry ( log ) ;
// recurse through call stack
_Next - > displayStack ( log ) ;
}
//-------------------------------------------------------------------------------------------------
// HANDY Utility methods...
//-------------------------------------------------------------------------------------------------
inline NLMISC : : CVectorSString & operator < < ( NLMISC : : CVectorSString & vect , const NLMISC : : CSString s )
{
vect . push_back ( s ) ;
return vect ;
}
template < class T > inline T & vectAppend ( std : : vector < T > & vect )
{
vect . resize ( vect . size ( ) + 1 ) ;
return vect . back ( ) ;
}
template < class T0 , class T1 > inline void vectInsert ( std : : vector < T0 > & vect , const T1 & value )
{
for ( uint32 i = 0 ; i < vect . size ( ) ; + + i )
if ( vect [ i ] = = value )
return ;
vect . push_back ( value ) ;
}
template < class T > inline T & listAppend ( std : : list < T > & list )
{
list . resize ( list . size ( ) + 1 ) ;
return list . back ( ) ;
}
inline NLMISC : : CSString popString ( NLMISC : : IStream & stream )
{
std : : string s ;
stream . serial ( s ) ;
return s ;
}
inline sint32 popSint ( NLMISC : : IStream & stream )
{
sint32 val ;
stream . serial ( val ) ;
return val ;
}
inline uint32 popUint ( NLMISC : : IStream & stream )
{
uint32 val ;
stream . serial ( val ) ;
return val ;
}
inline bool popBool ( NLMISC : : IStream & stream )
{
bool val ;
stream . serial ( val ) ;
return val ;
}
template < class T > inline void pushToStream ( NLMISC : : IStream & stream , const T & value )
{
stream . serial ( const_cast < T & > ( value ) ) ;
}
inline void pushToStream ( NLMISC : : IStream & stream , const char * txt )
{
std : : string s ( txt ) ;
stream . serial ( s ) ;
}
//-------------------------------------------------------------------------------------------------
// HANDY IPtr and IConstPtr CLASSES
//-------------------------------------------------------------------------------------------------
// This class gives a base that can be specialised in order to make pointer encapsulation classes
// it offers the basic standard methods that you have to define every time in the normal way...
template < class C >
class IPtr
{
public :
IPtr ( ) { _Ptr = NULL ; }
IPtr ( C * p ) { operator = ( p ) ; }
IPtr & operator = ( C * p ) { _Ptr = p ; return * this ; }
IPtr & operator = ( IPtr & other ) { _Ptr = other . _Ptr ; return * this ; }
IPtr & operator + + ( ) { + + _Ptr ; return * this ; }
IPtr & operator - - ( ) { - - _Ptr ; return * this ; }
const C * operator - > ( ) const { return _Ptr ; }
const C & operator * ( ) const { return * _Ptr ; }
operator C const * ( ) const { return _Ptr ; }
C * operator - > ( ) { return _Ptr ; }
C & operator * ( ) { return * _Ptr ; }
operator C * ( ) { return _Ptr ; }
bool operator = = ( const IPtr & other ) const { return _Ptr = = other . _Ptr ; }
bool operator ! = ( const IPtr & other ) const { return _Ptr ! = other . _Ptr ; }
bool operator = = ( const C * p ) const { return _Ptr = = p ; }
bool operator ! = ( const C * p ) const { return _Ptr ! = p ; }
private :
C * _Ptr ;
} ;
template < class C >
class IConstPtr
{
public :
IConstPtr ( ) { _Ptr = NULL ; }
IConstPtr ( const C * p ) { operator = ( p ) ; }
IConstPtr & operator = ( const C * p ) { _Ptr = p ; return * this ; }
IConstPtr & operator = ( const IConstPtr & other ) { _Ptr = other . _Ptr ; return * this ; }
IConstPtr & operator + + ( ) { + + _Ptr ; return * this ; }
IConstPtr & operator - - ( ) { - - _Ptr ; return * this ; }
const C * operator - > ( ) const { return _Ptr ; }
const C & operator * ( ) const { return * _Ptr ; }
operator C const * ( ) const { return _Ptr ; }
bool operator = = ( const IConstPtr & other ) const { return _Ptr = = other . _Ptr ; }
bool operator ! = ( const IConstPtr & other ) const { return _Ptr ! = other . _Ptr ; }
bool operator = = ( const C * p ) const { return _Ptr = = p ; }
bool operator ! = ( const C * p ) const { return _Ptr ! = p ; }
private :
C const * _Ptr ;
} ;
//-------------------------------------------------------------------------------------------------
// HANDY cleanPath() method for cleaning file system paths
//-------------------------------------------------------------------------------------------------
// Clean a path performing the following operations:
// - convert '\\' characters to '/'
// - replace '//' strings in the middle of the path with '/'
// - remove '.' directory entries
// - colapse '..' directory entries (removing parent entries)
// - append a final '/' (optionally)
//
// examples:
// - a:/bcd/efg/ => a:/bcd/efg/ (no change)
// - a:\bcd\efg => a:/bcd/efg/
// - \bcd\\efg => /bcd/efg/
// - \\bcd\efg => //bcd/efg/
// - \bcd\.\efg => /bcd/efg/
// - \bcd\..\efg => /efg/
// - bcd\..\efg => efg/
// - bcd\..\..\efg => ../efg/
// - \bcd\..\..\efg => /efg/ (NOTE: the redundant '..' entry is lost due to leading '\')
//
NLMISC : : CSString cleanPath ( const NLMISC : : CSString & path , bool addTrailingSlash ) ;
template < class T >
struct TTypeLimits
{
static T max ( ) ;
static T min ( ) ;
static T floor ( T value ) ;
} ;
template < >
struct TTypeLimits < uint8 >
{
static uint8 max ( ) { return ( uint8 ) 0xff ; }
static uint8 min ( ) { return 0 ; }
enum
{
IsSigned = 0 ,
IsInteger = 1 ,
} ;
static uint8 floor ( uint8 value ) { return value ; }
} ;
template < >
struct TTypeLimits < uint16 >
{
static uint16 max ( ) { return ( uint16 ) 0xffff ; }
static uint16 min ( ) { return 0 ; }
enum
{
IsSigned = 0 ,
IsInteger = 1 ,
} ;
static uint16 floor ( uint16 value ) { return value ; }
} ;
template < >
struct TTypeLimits < uint32 >
{
static uint32 max ( ) { return 0xffffffffu ; }
static uint32 min ( ) { return 0 ; }
enum
{
IsSigned = 0 ,
IsInteger = 1 ,
} ;
static uint32 floor ( uint32 value ) { return value ; }
} ;
/*
# ifdef NL_OS_WINDOWS
template < >
struct TTypeLimits < unsigned int > : public TTypeLimits < uint32 >
{
} ;
# endif
*/
template < >
struct TTypeLimits < uint64 >
{
static uint64 max ( ) { return UINT64_CONSTANT ( 0xffffffffffffffff ) ; }
static uint64 min ( ) { return 0 ; }
enum
{
IsSigned = 0 ,
IsInteger = 1 ,
} ;
static uint64 floor ( uint64 value ) { return value ; }
} ;
template < >
struct TTypeLimits < sint8 >
{
static sint8 max ( ) { return ( sint8 ) 0x7f ; }
static sint8 min ( ) { return ( sint8 ) 0x80 ; }
enum
{
IsSigned = 1 ,
IsInteger = 1 ,
} ;
static sint8 floor ( sint8 value ) { return value ; }
} ;
template < >
struct TTypeLimits < sint16 >
{
static sint16 max ( ) { return ( sint16 ) 0x7fff ; }
static sint16 min ( ) { return ( sint16 ) 0x8000 ; }
enum
{
IsSigned = 1 ,
IsInteger = 1 ,
} ;
static sint16 floor ( sint16 value ) { return value ; }
} ;
template < >
struct TTypeLimits < sint32 >
{
static sint32 max ( ) { return ( sint32 ) 0x7fffffff ; }
static sint32 min ( ) { return ( sint32 ) 0x80000000 ; }
enum
{
IsSigned = 1 ,
IsInteger = 1 ,
} ;
static sint32 floor ( sint32 value ) { return value ; }
} ;
/*#ifdef NL_OS_WINDOWS
template < >
struct TTypeLimits < int > : public TTypeLimits < sint32 >
{
} ;
# endif* /
template < >
struct TTypeLimits < sint64 >
{
static sint64 max ( ) { return SINT64_CONSTANT ( 0x7fffffffffffffff ) ; }
static sint64 min ( ) { return SINT64_CONSTANT ( 0x8000000000000000 ) ; }
enum
{
IsSigned = 1 ,
IsInteger = 1 ,
} ;
static sint64 floor ( sint64 value ) { return value ; }
} ;
template < >
struct TTypeLimits < float >
{
static float max ( ) { return FLT_MAX ; }
static float min ( ) { return FLT_MIN ; }
enum
{
IsSigned = 1 ,
IsInteger = 0 ,
} ;
static float floor ( float f ) { return f < 0 ? ( float ) : : ceil ( f ) : ( float ) : : floor ( f ) ; }
} ;
template < >
struct TTypeLimits < double >
{
static double max ( ) { return DBL_MAX ; }
static double min ( ) { return DBL_MIN ; }
enum
{
IsSigned = 1 ,
IsInteger = 0 ,
} ;
static double floor ( double d ) { return d < 0 ? : : ceil ( d ) : : : floor ( d ) ; }
} ;
template < class T , class U >
inline T checkedCast ( U val )
{
typedef TTypeLimits < U > TLimitIn ;
typedef TTypeLimits < T > TLimitOut ;
// Only allow checked cast to integer type !
nlctassert ( TLimitOut : : IsInteger ) ;
T dest = ( T ) val ;
U check = ( U ) dest ;
if ( val < 0 )
{
BOMB_IF ( check ! = TLimitIn : : floor ( val ) , " checkedCast : Value " < < val < < " exceed the negative capacity of " < < typeid ( T ) . name ( ) < < " clamping at min value " , return TLimitOut : : min ( ) ) ;
}
else
{
BOMB_IF ( check ! = TLimitIn : : floor ( val ) , " checkedCast : Value " < < val < < " exceed the positive capacity of " < < typeid ( T ) . name ( ) < < " clamping at max value " , return TLimitOut : : max ( ) ) ;
}
return T ( dest ) ;
}
//-------------------------------------------------------------------------------------------------
# endif