Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / ryzom / common / src / game_share / utils.h
blobeb527162fb05c3919d1e69e01ed7133c171da692
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #ifndef UTILS_H
23 #define UTILS_H
26 //-------------------------------------------------------------------------------------------------
27 // includes
28 //-------------------------------------------------------------------------------------------------
30 #include "nel/misc/types_nl.h"
31 #include "nel/misc/common.h"
32 #include "nel/misc/debug.h"
33 #include "nel/misc/sstring.h"
35 #include <list>
37 //-------------------------------------------------------------------------------------------------
38 // UTILITY FUNCTIONS
39 //-------------------------------------------------------------------------------------------------
41 //-----------------------------------------------------------------------------
42 inline std::string capitalize(const std::string & s)
44 if ( s.empty() )
45 return s;
47 std::string res;
48 res.reserve(4);
49 ptrdiff_t i = 0;
50 NLMISC::appendToUpper(res, s, i);
51 return res + NLMISC::toLower(s.substr(i));
54 inline ucstring capitalize(const ucstring & s)
56 if ( s.empty() )
57 return s;
59 // return NLMISC::toUpper( s.substr(0,1) ) + NLMISC::toLower( s.substr(1,std::string::npos) );
60 return ucstring::makeFromUtf8(capitalize(s.toUtf8()));
64 //-------------------------------------------------------------------------------------------------
65 // HANDY MACROS - For forcing the pre-preprocessor to evaluate concatenation operations nicely
66 //-------------------------------------------------------------------------------------------------
68 // a Few examples:
69 // ---------------
71 // #define TOTO TATA
72 // MACRO_CONCAT(a,TOTO) => aTOTO
73 // MACRO_CONCAT2(a,TOTO) => aTATA
74 // MACRO_TOTXT(TOTO) => "TOTO"
75 // MACRO_TOTXT2(TOTO) => "TATA"
77 /// MACRO_CONCAT(a,__LINE__) => a__LINE__
78 // MACRO_CONCAT2(a,__LINE__) => a123
79 // MACRO_TOTXT(__LINE__) => "__LINE__"
80 // MACRO_TOTXT2(__LINE__) => "123"
82 // __FILE_LINE__ => "utils.h:123:"
84 #define MACRO_CONCAT(a,b) a##b
85 #define MACRO_CONCAT2(a,b) CONCAT(a,b)
86 #define MACRO_TOTXT(a) #a
87 #define MACRO_TOTXT2(a) TOTXT(a)
88 #define __FILE_LINE__ __FILE__ ":" TOTXT2(__LINE__) ":"
91 //-------------------------------------------------------------------------------------------------
92 // LOGGING / DEBUGGING MACROS
93 //-------------------------------------------------------------------------------------------------
95 #ifdef NL_DEBUG
96 #define DEBUG_STOP nlstop;
97 #define nlassertd(a) nlassert(a)
98 #else
99 #define DEBUG_STOP \
100 std::string stack; \
101 NLMISC::getCallStack(stack); \
102 std::vector<std::string> contexts;\
103 NLMISC::explode(stack, std::string("\n"), contexts);\
104 nldebug("Dumping callstack :"); \
105 for (uint i=0; i<contexts.size(); ++i) \
106 nldebug(" %3u : %s", i, contexts[i].c_str());
107 #define nlassertd(a) if (0) { } else { }
108 #endif
110 // the following set of definess can be undefined and re-defined to add user code to execute
111 // systematically when GIVEUP, DROP or BOMB macros are triggered
112 // eg #define ON_BOMB logError(__FILE__,__LINE__,msg);
113 #define ON_GIVEUP
114 #define ON_DROP
115 #define ON_BOMB
117 // info and warning macros
118 #define INFO(msg) nlinfo((NLMISC::CSString()<<msg).c_str());
119 #define WARN(msg) nlwarning((NLMISC::CSString()<<msg).c_str());
121 // unconditional abort macros
122 #define STOP(msg) { WARN(msg) DEBUG_STOP }
123 #define GIVEUP(msg,action) { INFO(msg) { ON_GIVEUP; } { action; } }
124 #define DROP(msg,action) { WARN(msg) { ON_DROP; } { action; } }
125 #define BOMB(msg,action) { STOP(msg) { ON_BOMB; } { action; } }
127 // conditional warn and abort macros
128 #define GIVEUP_IF(condition,msg,action) if (!(condition));else GIVEUP(msg,action)
129 #define WARN_IF(condition,msg) if (!(condition));else WARN(msg)
130 #define DROP_IF(condition,msg,action) if (!(condition));else DROP(msg,action)
131 #define BOMB_IF(condition,msg,action) if (!(condition));else BOMB(msg,action); do { nlassume(condition); } while (0)
132 #define STOP_IF(condition,msg) if (!(condition));else STOP(msg); do { nlassume(condition); } while (0)
134 // testing for variable value changes
135 #define ON_CHANGE(type,var,code)\
136 class __COnChange##var\
138 public:\
139 const type& _Var;\
140 const type _OldVal;\
141 __COnChange##var(const type& var): _Var(var), _OldVal(var) {}\
142 ~__COnChange##var() { if(_OldVal!=_Var) { code; } }\
144 __onChange##__LINE__(var);
146 #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()))
149 //-------------------------------------------------------------------------------------------------
150 // A handy 'nldebug', 'nlinfo' & 'nlwarning' override system
151 //-------------------------------------------------------------------------------------------------
153 // The system includes a set of object classes
154 // To override one or more of the standard NeL log channels one simply instantiates the appropriate class
155 // with the new log channel as a parameter.
156 // The log channel in question will revert to its previous value on destruction of the override object
158 // Usage Example:
160 // void doSomething()
161 // {
162 // nlinfo("bla");
163 // nlwarning("bla");
164 // }
166 // NLMISC_COMMAND(bla,"bla","bla")
167 // {
168 // CNLLogOverride(&log);
169 // doSomething();
170 // return true;
171 // }
174 //-------------------------------------------------------------------------------------------------
176 //class CNLDebugOverride
178 //public:
179 // CNLDebugOverride(NLMISC::CLog *debugLog)
180 // {
181 // nlassert(debugLog!=NULL);
182 // _OldValue=NLMISC::DebugLog;
183 // nlassert(_OldValue!=NULL);
184 // NLMISC::INelContext::getInstance().setDebugLog(debugLog);
185 // }
186 // ~CNLDebugOverride()
187 // {
188 // NLMISC::INelContext::getInstance().setDebugLog(_OldValue);
189 // }
190 //private:
191 // // prohibit copy
192 // CNLDebugOverride(const CNLDebugOverride&);
193 // NLMISC::CLog *_OldValue;
194 //};
196 ////-------------------------------------------------------------------------------------------------
198 //class CNLInfoOverride
200 //public:
201 // CNLInfoOverride(NLMISC::CLog *infoLog)
202 // {
203 // nlassert(infoLog!=NULL);
204 // _OldValue=NLMISC::InfoLog;
205 // nlassert(_OldValue!=NULL);
206 // NLMISC::INelContext::getInstance().setInfoLog(infoLog);
207 // }
208 // ~CNLInfoOverride()
209 // {
210 // NLMISC::INelContext::getInstance().setInfoLog(_OldValue);
211 // }
212 //private:
213 // // prohibit copy
214 // CNLInfoOverride(const CNLInfoOverride&);
215 // NLMISC::CLog *_OldValue;
216 //};
218 ////-------------------------------------------------------------------------------------------------
220 //class CNLWarningOverride
222 //public:
223 // CNLWarningOverride(NLMISC::CLog *warningLog)
224 // {
225 // nlassert(warningLog!=NULL);
226 // _OldValue=NLMISC::WarningLog;
227 // nlassert(_OldValue!=NULL);
228 // NLMISC::INelContext::getInstance().setWarningLog(warningLog);
229 // }
230 // ~CNLWarningOverride()
231 // {
232 // NLMISC::INelContext::getInstance().setWarningLog(_OldValue);
233 // }
234 //private:
235 // // prohibit copy
236 // CNLWarningOverride(const CNLWarningOverride&);
237 // NLMISC::CLog *_OldValue;
238 //};
240 ////-------------------------------------------------------------------------------------------------
242 //class CNLLogOverride
244 //public:
245 // CNLLogOverride(NLMISC::CLog *commonLog): _DebugLog(commonLog), _InfoLog(commonLog), _WarningLog(commonLog) {}
247 //private:
248 // CNLDebugOverride _DebugLog;
249 // CNLInfoOverride _InfoLog;
250 // CNLWarningOverride _WarningLog;
251 //};
254 ////-------------------------------------------------------------------------------------------------
256 //class CNLSmartLogOverride
258 //public:
259 // CNLSmartLogOverride(NLMISC::CLog *commonLog):
260 // _DebugLog(commonLog==NLMISC::InfoLog?NLMISC::DebugLog:commonLog),
261 // _InfoLog(commonLog),
262 // _WarningLog(commonLog==NLMISC::InfoLog?NLMISC::WarningLog:commonLog)
263 // {}
265 //private:
266 // CNLDebugOverride _DebugLog;
267 // CNLInfoOverride _InfoLog;
268 // CNLWarningOverride _WarningLog;
269 //};
272 //-------------------------------------------------------------------------------------------------
273 // A Little CallStack system
274 //-------------------------------------------------------------------------------------------------
275 // example:
276 // void traceTest2(int i)
277 // {
278 // CSTRACE;
279 // if (i<2)
280 // traceTest2(++i);
281 // else
282 // SHOW_CALLSTACK;
283 // }
285 // void traceTest()
286 // {
287 // CSTRACE_MSG("foo");
288 // traceTest2(0);
289 // {
290 // int i=0;
291 // CSTRACE_VAR(int,i);
292 // CSTRACE_VAL(int,i);
293 // i=1;
294 // SHOW_CALLSTACK;
295 // }
296 // WARN_CALLSTACK;
297 // }
299 // output:
300 // INF 3980: >>test.cpp:21: Call Stack:
301 // INF 3980: >>test.cpp:17
302 // INF 3980: >>test.cpp:17
303 // INF 3980: >>test.cpp:17
304 // INF 3980: >>test.cpp:26: foo
305 // INF 3980:
306 // INF 3980: >>test.cpp:33: Call Stack:
307 // INF 3980: >>test.cpp:31: i=[0]
308 // INF 3980: >>test.cpp:30: i=>[1]
309 // INF 3980: >>test.cpp:26: foo
310 // INF 3980:
311 // WRN 3980: >>test.cpp:35: Call Stack:
312 // WRN 3980: >>test.cpp:26: foo
313 // WRN 3980:
316 //-------------------------------------------------------------------------------------------------
317 // A Little CallStack system - MACROS
318 //-------------------------------------------------------------------------------------------------
319 // CSTRACE - displays source file and line number
320 // CSTRACE_MSG(msg) - as with trace but with additional simple text message eg TRACE_MSG("hello world")
321 // CSTRACE_VAL(type,name) - displays a value (calculated at the moment that the trace is created)
322 // CSTRACE_VAR(type,name) - displays the value of the given variable at the moment that callstack is displayed
323 // SHOW_CALLSTACK - displays the callstack using NLMISC::InfoLog
324 // WARN_CALLSTACK - displays the callstack using NLMISC::WarningLog
326 #define CSTRACE\
327 class __CCallStackEntry##__LINE__: public ICallStackEntry\
329 public:\
330 virtual void displayEntry(NLMISC::CLog& log) const\
332 log.displayNL(">>" __FILE__ ":%d", __LINE__);\
335 __callStackEntry##__LINE__;
337 #define CSTRACE_MSG(msg)\
338 class __CCallStackEntry##__LINE__: public ICallStackEntry\
340 public:\
341 virtual void displayEntry(NLMISC::CLog& log) const\
343 log.displayNL(">>" __FILE__ ":%d: %s", __LINE__,msg);\
346 __callStackEntry##__LINE__;
348 #define CSTRACE_VAL(type,var)\
349 class __TraceVal_##var: public ICallStackEntry\
351 public:\
352 __TraceVal_##var(const type& var): _Val(var) \
355 virtual void displayEntry(NLMISC::CLog& log) const\
357 log.displayNL(">>" __FILE__ ":%d: %s=[%s]", __LINE__, #var, NLMISC::toString(_Val).c_str());\
359 const type _Val;\
361 __traceVal_##var(var);
363 #define CSTRACE_VAR(type,var)\
364 class __TraceVar_##var: public ICallStackEntry\
366 public:\
367 __TraceVar_##var(const type& var): _Var(var) \
370 virtual void displayEntry(NLMISC::CLog& log) const\
372 log.displayNL(">>" __FILE__ ":%d: %s=>[%s]", __LINE__, #var, NLMISC::toString(_Var).c_str());\
374 const type& _Var;\
376 __traceVar_##var(var);
378 #define SHOW_CALLSTACK { CSTRACE_MSG("Call Stack:"); CCallStackSingleton::display(NLMISC::InfoLog); }
379 #define WARN_CALLSTACK { CSTRACE_MSG("Call Stack:"); CCallStackSingleton::display(NLMISC::WarningLog); }
382 //-------------------------------------------------------------------------------------------------
383 // A Little CallStack system - Private stack entry base class
384 //-------------------------------------------------------------------------------------------------
386 class ICallStackEntry
388 public:
389 ICallStackEntry();
390 virtual ~ICallStackEntry();
391 void displayStack(NLMISC::CLog& log) const;
393 virtual void displayEntry(NLMISC::CLog& log) const=0;
395 private:
396 ICallStackEntry* _Next;
400 //-------------------------------------------------------------------------------------------------
401 // A Little CallStack system - Public Singleton Class
402 //-------------------------------------------------------------------------------------------------
404 class CCallStackSingleton
406 public:
407 static ICallStackEntry* getTopStackEntry();
408 static void setTopStackEntry(ICallStackEntry* newEntry);
409 static void display(NLMISC::CLog *log=NLMISC::InfoLog);
411 private:
412 // this is a singleton so prohibit public construction
413 CCallStackSingleton() {}
415 // encapsulation of a variable to make it a singleton
416 static ICallStackEntry*& topStackEntry();
420 //-------------------------------------------------------------------------------------------------
421 // A Little CallStack system - Public Singleton inlines
422 //-------------------------------------------------------------------------------------------------
424 inline ICallStackEntry* CCallStackSingleton::getTopStackEntry()
426 return topStackEntry();
429 inline void CCallStackSingleton::setTopStackEntry(ICallStackEntry* newEntry)
431 topStackEntry()= newEntry;
434 inline void CCallStackSingleton::display(NLMISC::CLog *log)
436 nlassert(log!=NULL);
437 ICallStackEntry *entry = getTopStackEntry();
438 if (entry) entry->displayStack(*log);
439 log->displayNL("");
442 inline ICallStackEntry*& CCallStackSingleton::topStackEntry()
444 static ICallStackEntry* stackEntry=NULL;
445 return stackEntry;
449 //-------------------------------------------------------------------------------------------------
450 // A Little CallStack system - Private stack entry base inlines
451 //-------------------------------------------------------------------------------------------------
453 inline ICallStackEntry::ICallStackEntry()
455 // add self to the call stack
456 _Next=CCallStackSingleton::getTopStackEntry();
457 CCallStackSingleton::setTopStackEntry(this);
460 inline ICallStackEntry::~ICallStackEntry()
462 // if this object is in the call stack then pop items off the top of the stack
463 // until this object is no longer in the stack
464 while (_Next!=this)
466 // get a pointer to the top object on the call stack
467 ICallStackEntry* entry= CCallStackSingleton::getTopStackEntry();
468 nlassertd(entry!=NULL);
470 // pop the object off the callstack
471 CCallStackSingleton::setTopStackEntry(entry->_Next);
473 // mark object as no longer in callstack
474 entry->_Next=entry;
478 inline void ICallStackEntry::displayStack(NLMISC::CLog& log) const
480 // stop recursing when we reach a NULL object
481 // (this is implemented in this way in order to simplify call code)
483 // display this entry
484 displayEntry(log);
486 // recurse through call stack
487 if (_Next) _Next->displayStack(log);
491 //-------------------------------------------------------------------------------------------------
492 // HANDY Utility methods...
493 //-------------------------------------------------------------------------------------------------
495 inline NLMISC::CVectorSString& operator<<(NLMISC::CVectorSString& vect,const NLMISC::CSString s)
497 vect.push_back(s);
498 return vect;
502 template<class T> inline T& vectAppend(std::vector<T>& vect)
504 vect.resize(vect.size()+1);
505 return vect.back();
507 template<class T0,class T1> inline void vectInsert(std::vector<T0>& vect,const T1& value)
509 for (uint32 i=0;i<vect.size();++i)
510 if (vect[i]== value)
511 return;
513 vect.push_back(value);
516 template<class T> inline T& listAppend(std::list<T>& list)
518 list.resize(list.size()+1);
519 return list.back();
522 inline NLMISC::CSString popString(NLMISC::IStream& stream)
524 std::string s;
525 stream.serial(s);
526 return s;
529 inline sint32 popSint(NLMISC::IStream& stream)
531 sint32 val;
532 stream.serial(val);
533 return val;
536 inline uint32 popUint(NLMISC::IStream& stream)
538 uint32 val;
539 stream.serial(val);
540 return val;
543 inline bool popBool(NLMISC::IStream& stream)
545 bool val;
546 stream.serial(val);
547 return val;
550 template<class T> inline void pushToStream(NLMISC::IStream& stream,const T& value)
552 stream.serial(const_cast<T&>(value));
555 inline void pushToStream(NLMISC::IStream& stream,const char* txt)
557 std::string s(txt);
558 stream.serial(s);
561 //-------------------------------------------------------------------------------------------------
562 // HANDY IPtr and IConstPtr CLASSES
563 //-------------------------------------------------------------------------------------------------
564 // This class gives a base that can be specialised in order to make pointer encapsulation classes
565 // it offers the basic standard methods that you have to define every time in the normal way...
567 template <class C>
568 class IPtr
570 public:
571 IPtr() { _Ptr= NULL; }
572 IPtr(C* p) { operator=(p); }
573 IPtr& operator=(C* p) { _Ptr=p; return *this; }
574 IPtr& operator=(IPtr& other) { _Ptr=other._Ptr; return *this; }
575 IPtr& operator++() { ++_Ptr; return *this; }
576 IPtr& operator--() { --_Ptr; return *this; }
577 const C* operator->() const { return _Ptr; }
578 const C& operator*() const { return *_Ptr; }
579 operator C const *() const { return _Ptr; }
580 C* operator->() { return _Ptr; }
581 C& operator*() { return *_Ptr; }
582 operator C*() { return _Ptr; }
583 bool operator==(const IPtr& other) const { return _Ptr==other._Ptr; }
584 bool operator!=(const IPtr& other) const { return _Ptr!=other._Ptr; }
585 bool operator==(const C* p) const { return _Ptr==p; }
586 bool operator!=(const C* p) const { return _Ptr!=p; }
587 private:
588 C * _Ptr;
592 template <class C>
593 class IConstPtr
595 public:
596 IConstPtr() { _Ptr= NULL; }
597 IConstPtr(const C* p) { operator=(p); }
598 IConstPtr& operator=(const C* p) { _Ptr=p; return *this; }
599 IConstPtr& operator=(const IConstPtr& other) { _Ptr=other._Ptr; return *this; }
600 IConstPtr& operator++() { ++_Ptr; return *this; }
601 IConstPtr& operator--() { --_Ptr; return *this; }
602 const C* operator->() const { return _Ptr; }
603 const C& operator*() const { return *_Ptr; }
604 operator C const *() const { return _Ptr; }
605 bool operator==(const IConstPtr& other) const { return _Ptr==other._Ptr; }
606 bool operator!=(const IConstPtr& other) const { return _Ptr!=other._Ptr; }
607 bool operator==(const C* p) const { return _Ptr==p; }
608 bool operator!=(const C* p) const { return _Ptr!=p; }
609 private:
610 C const * _Ptr;
614 //-------------------------------------------------------------------------------------------------
615 // HANDY cleanPath() method for cleaning file system paths
616 //-------------------------------------------------------------------------------------------------
618 // Clean a path performing the following operations:
619 // - convert '\\' characters to '/'
620 // - replace '//' strings in the middle of the path with '/'
621 // - remove '.' directory entries
622 // - colapse '..' directory entries (removing parent entries)
623 // - append a final '/' (optionally)
625 // examples:
626 // - a:/bcd/efg/ => a:/bcd/efg/ (no change)
627 // - a:\bcd\efg => a:/bcd/efg/
628 // - \bcd\\efg => /bcd/efg/
629 // - \\bcd\efg => //bcd/efg/
630 // - \bcd\.\efg => /bcd/efg/
631 // - \bcd\..\efg => /efg/
632 // - bcd\..\efg => efg/
633 // - bcd\..\..\efg => ../efg/
634 // - \bcd\..\..\efg => /efg/ (NOTE: the redundant '..' entry is lost due to leading '\')
636 NLMISC::CSString cleanPath(const NLMISC::CSString& path,bool addTrailingSlash);
639 template <class T>
640 struct TTypeLimits
642 static T max();
643 static T min();
644 static T floor(T value);
647 template <>
648 struct TTypeLimits<uint8>
650 static uint8 max() { return (uint8)0xff; }
651 static uint8 min() { return 0; }
652 enum
654 IsSigned = 0,
655 IsInteger = 1,
657 static uint8 floor(uint8 value) { return value; }
659 template <>
660 struct TTypeLimits<uint16>
662 static uint16 max() { return (uint16)0xffff; }
663 static uint16 min() { return 0; }
664 enum
666 IsSigned = 0,
667 IsInteger = 1,
669 static uint16 floor(uint16 value) { return value; }
671 template <>
672 struct TTypeLimits<uint32>
674 static uint32 max() { return 0xffffffffu; }
675 static uint32 min() { return 0; }
676 enum
678 IsSigned = 0,
679 IsInteger = 1,
681 static uint32 floor(uint32 value) { return value; }
683 template <>
684 struct TTypeLimits<uint64>
686 static uint64 max() { return UINT64_CONSTANT(0xffffffffffffffff); }
687 static uint64 min() { return 0; }
688 enum
690 IsSigned = 0,
691 IsInteger = 1,
693 static uint64 floor(uint64 value) { return value; }
696 template <>
697 struct TTypeLimits<sint8>
699 static sint8 max() { return (sint8)0x7f; }
700 static sint8 min() { return (sint8)0x80; }
701 enum
703 IsSigned = 1,
704 IsInteger = 1,
706 static sint8 floor(sint8 value) { return value; }
708 template <>
709 struct TTypeLimits<sint16>
711 static sint16 max() { return (sint16)0x7fff; }
712 static sint16 min() { return (sint16)0x8000; }
713 enum
715 IsSigned = 1,
716 IsInteger = 1,
718 static sint16 floor(sint16 value) { return value; }
720 template <>
721 struct TTypeLimits<sint32>
723 static sint32 max() { return (sint32)0x7fffffff; }
724 static sint32 min() { return (sint32)0x80000000; }
725 enum
727 IsSigned = 1,
728 IsInteger = 1,
730 static sint32 floor(sint32 value) { return value; }
733 template <>
734 struct TTypeLimits<sint64>
736 static sint64 max() { return SINT64_CONSTANT(0x7fffffffffffffff); }
737 static sint64 min() { return SINT64_CONSTANT(0x8000000000000000); }
738 enum
740 IsSigned = 1,
741 IsInteger = 1,
743 static sint64 floor(sint64 value) { return value; }
746 template <>
747 struct TTypeLimits<float>
749 static float max() { return FLT_MAX; }
750 static float min() { return FLT_MIN; }
751 enum
753 IsSigned = 1,
754 IsInteger = 0,
756 static float floor(float f) { return f < 0 ? (float)::ceil(f) : (float)::floor(f); }
758 template <>
759 struct TTypeLimits<double>
761 static double max() { return DBL_MAX; }
762 static double min() { return DBL_MIN; }
763 enum
765 IsSigned = 1,
766 IsInteger = 0,
768 static double floor(double d) { return d < 0 ? ::ceil(d) : ::floor(d); }
773 template <class T, class U>
774 inline T checkedCast(U val)
776 typedef TTypeLimits<U> TLimitIn;
777 typedef TTypeLimits<T> TLimitOut;
779 // Only allow checked cast to integer type !
780 nlctassert(TLimitOut::IsInteger);
782 T dest = (T) val;
783 U check = (U) dest;
785 if (val < 0)
787 BOMB_IF(check != TLimitIn::floor(val), "checkedCast : Value "<<val<<" exceed the negative capacity of "<<typeid(T).name()<<" clamping at min value", return TLimitOut::min());
789 else
791 BOMB_IF(check != TLimitIn::floor(val), "checkedCast : Value "<<val<<" exceed the positive capacity of "<<typeid(T).name()<<" clamping at max value", return TLimitOut::max());
794 return T(dest);
798 //-------------------------------------------------------------------------------------------------
799 #endif