// Ryzom - MMORPG Framework
// 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 .
#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
//-------------------------------------------------------------------------------------------------
// 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 contexts;\
NLMISC::explode(stack, std::string("\n"), contexts);\
nldebug("Dumping callstack :"); \
for (uint i=0; i>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);
ICallStackEntry *entry = getTopStackEntry();
if (entry) entry->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 simplify call code)
// display this entry
displayEntry(log);
// recurse through call stack
if (_Next) _Next->displayStack(log);
}
//-------------------------------------------------------------------------------------------------
// HANDY Utility methods...
//-------------------------------------------------------------------------------------------------
inline NLMISC::CVectorSString& operator<<(NLMISC::CVectorSString& vect,const NLMISC::CSString s)
{
vect.push_back(s);
return vect;
}
template inline T& vectAppend(std::vector& vect)
{
vect.resize(vect.size()+1);
return vect.back();
}
template inline void vectInsert(std::vector& vect,const T1& value)
{
for (uint32 i=0;i inline T& listAppend(std::list& 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 inline void pushToStream(NLMISC::IStream& stream,const T& value)
{
stream.serial(const_cast(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 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 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
struct TTypeLimits
{
static T max();
static T min();
static T floor(T value);
};
template <>
struct TTypeLimits
{
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
{
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
{
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 : public TTypeLimits
{
};
#endif
*/
template <>
struct TTypeLimits
{
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
{
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
{
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
{
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 : public TTypeLimits
{
};
#endif*/
template <>
struct TTypeLimits
{
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
{
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
{
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
inline T checkedCast(U val)
{
typedef TTypeLimits TLimitIn;
typedef TTypeLimits 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 "<