1// tStandard.h 
2// 
3// Tacent functions and types that are standard across all platforms. Includes global functions like itoa which are not 
4// available on some platforms, but are common enough that they should be. 
5// 
6// Copyright (c) 2004-2006, 2015, 2017, 2020 Tristan Grimmer. 
7// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
8// granted, provided that the above copyright notice and this permission notice appear in all copies. 
9// 
10// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
11// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
12// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
13// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
14// PERFORMANCE OF THIS SOFTWARE. 
15 
16#pragma once 
17#include <string.h> 
18#include <ctype.h> 
19#include <stdlib.h> 
20#include <stdarg.h> 
21#include <math.h> 
22#include "Foundation/tPlatform.h" 
23#include "Foundation/tAssert.h" 
24#pragma warning (disable: 4996) 
25#pragma warning (disable: 4146) 
26#pragma warning (disable: 4307) 
27#define tNumElements(arr) int(sizeof(arr)/sizeof(*arr)) 
28 
29 
30namespace tStd 
31
32 
33// The 3 XOR trick is slower in most cases so we'll use a standard swap. 
34template<typename T> inline void tSwap(T& a, T& b) { T t = a; a = b; b = t; } 
35inline void* tMemcpy(void* dest, const void* src, int numBytes) { return memcpy(dest, src, numBytes); } 
36inline void* tMemset(void* dest, uint8 val, int numBytes) { return memset(dest, val, numBytes); } 
37inline void* tMemchr(void* data, uint8 val, int numBytes) { return memchr(data, val, numBytes); } 
38inline const void* tMemchr(const void* data, uint8 val, int numBytes) { return memchr(data, val, numBytes); } 
39inline int tMemcmp(const void* a, const void* b, int numBytes) { return memcmp(a, b, numBytes); } 
40 
41// This one is new but handy, Searches for memory sequence needle of length needleNumBytes in haystack of length 
42// haystackNumBytes. Returns nullptr if whole needle not found or a pointer to the first found needle otherwise. 
43void* tMemmem(void* haystack, int haystackNumBytes, void* needle, int needleNumBytes); 
44inline const void* tMemmem(const void* haystack, int haystackNumBytes, const void* needle, int needleNumBytes) { return tMemmem(haystack, haystackNumBytes, needle, needleNumBytes); } 
45 
46// For character strings we support regular 8 bit characters (ASCII) and full unicode via UTF8. We do not support either 
47// USC2 or UTF16. The CT (Compile-Time) strlen variant below can compute the string length at compile-time for constant 
48// string literals. 
49const int tCharInvalid = 0xFF
50inline int tStrcmp(const char* a, const char* b) { tAssert(a && b); return strcmp(a, b); } 
51inline int tStrncmp(const char* a, const char* b, int n) { tAssert(a && b && n >= 0); return strncmp(a, b, n); } 
52#if defined(PLATFORM_WINDOWS) 
53inline int tStricmp(const char* a, const char* b) { tAssert(a && b); return stricmp(a, b); } 
54inline int tStrnicmp(const char* a, const char* b, int n) { tAssert(a && b && n >= 0); return strnicmp(a, b, n); } 
55#else 
56inline int tStricmp(const char* a, const char* b) { tAssert(a && b); return strcasecmp(a, b); } 
57inline int tStrnicmp(const char* a, const char* b, int n) { tAssert(a && b && n >= 0); return strncasecmp(a, b, n); } 
58#endif 
59inline int tStrlen(const char* s) { tAssert(s); return int(strlen(s)); } 
60inline constexpr int tStrlenCT(const char* s) { return *s ? 1 + tStrlenCT(s + 1) : 0; } 
61inline char* tStrcpy(char* dst, const char* src) { tAssert(dst && src); return strcpy(dst, src); } 
62inline char* tStrncpy(char* dst, const char* src, int n) { tAssert(dst && src && n >= 0); return strncpy(dst, src, n); } 
63inline char* tStrchr(const char* s, int c) { tAssert(s && c >= 0 && c < 0x100); return (char*)strchr(s, c); } 
64inline char* tStrstr(const char* s, const char* r) { tAssert(s && r); return (char*)strstr(s, r); } 
65inline char* tStrcat(char* s, const char* r) { tAssert(s && r); return (char*)strcat(s, r); } 
66 
67#if defined(PLATFORM_WINDOWS) 
68inline char* tStrupr(char* s) { tAssert(s); return _strupr(s); } 
69inline char* tStrlwr(char* s) { tAssert(s); return _strlwr(s); } 
70#else 
71inline char* tStrupr(char* s) { tAssert(s); char* c = s; while (*c) { *c = toupper(*c); c++; } return s; } 
72inline char* tStrlwr(char* s) { tAssert(s); char* c = s; while (*c) { *c = tolower(*c); c++; } return s; } 
73#endif 
74 
75// For these conversion calls, unknown digit characters for the supplied base are ignored. If base is not E [2, 36], the 
76// base in which to interpret the string is determined by passing a prefix in the string. Base 10 is used if no specific 
77// prefix is found. Base prefixes in use: 
78// 
79// Base 16 prefixes: x X 0x 0X # 
80// Base 10 prefixes: d D 0d 0D 
81// Base 8 prefixes: o O 0o 0O @ 
82// Base 4 prefixes: n N 0n 0N (N for Nybble) 
83// Base 2 prefixes: b B 0b 0B ! 
84// 
85// Negative/positive symbol may only be used with base 10 strings: eg. "d-769" or just "-769". The behaviour follows 
86// this recipe: If the base is invalid (not between 2 and 36) the first and maybe second characters are examined to 
87// determine base. Next, invalid characters are removed (implementation may just ignore them). Invalid characters 
88// include + and - for non base 10. Finally the conversion is performed. Valid digits for base 36 are 0-9, a-z, and A-Z. 
89// In all string-to-int functions, 0 is returned if there is no conversion. This can happen if all characters are 
90// invalid, the passed in string is null, or the passed in string is empty. 
91// 
92// If base is E (1, 36] AND a prefix is supplied, the supplied base is used. Using the prefix instead would be 
93// ambiguous. For example, "0x" is a valid base 36 number but "0x" is also a prefix. If you supply a prefix it must 
94// match the base or you will get undefined results. eg "0xff" or "xff" with base=36 interprets the 'x', correctly, as 
95// 33. "0xff" with base=16 works too because 'x' is an invalid hex digit and gets ignored. The '0' is leading so also 
96// does not interfere. The same behaviour holds for all prefixes and bases. Finally, don't pass a base-34 number in with 
97// the base set to -1, although that shouldn't happen anyways. 
98template <typename IntegralType> IntegralType tStrtoiT(const char*, int base = -1); 
99inline int32 tStrtoi32(const char* s, int base = -1) { return tStrtoiT<int32>(s, base); } 
100inline uint32 tStrtoui32(const char* s, int base = -1) { return tStrtoiT<uint32>(s, base); } 
101inline int64 tStrtoi64(const char* s, int base = -1) { return tStrtoiT<int64>(s, base); } 
102inline uint64 tStrtoui64(const char* s, int base = -1) { return tStrtoiT<uint64>(s, base); } 
103inline int tStrtoui(const char* s, int base = -1) { return tStrtoui32(s, base); } 
104inline int tStrtoi(const char* s, int base = -1) { return tStrtoi32(s, base); } 
105inline int tAtoi(const char* s) /* Base 10 only. Use tStrtoi for arbitrary base. */ { return tStrtoi32(s, 10); } 
106 
107template <typename IntegralType> bool tStrtoiTStrict(const char* str, IntegralType& val, int base = -1); 
108inline bool tStrtoi32Strict(const char* s, int32& Int32Value, int base = -1) { return tStrtoiTStrict<int32>(s, Int32Value, base); } 
109inline bool tStrtoui32Strict(const char* s, uint32& UInt32Value, int base = -1) { return tStrtoiTStrict<uint32>(s, UInt32Value, base); } 
110inline bool tStrtoi64Strict(const char* s, int64& Int64Value, int base = -1) { return tStrtoiTStrict<int64>(s, Int64Value, base); } 
111inline bool tStrtoui64Strict(const char* s, uint64& UInt64Value, int base = -1) { return tStrtoiTStrict<uint64>(s, UInt64Value, base); } 
112inline bool tStrtouiStrict(const char* s, uint32& IntValue, int base = -1) { return tStrtoui32Strict(s, IntValue, base); } 
113inline bool tStrtoiStrict(const char* s, int& IntValue, int base = -1) { return tStrtoi32Strict(s, IntValue, base); } 
114inline bool tAtoiStrict(const char* s, int& IntValue) { return tStrtoi32Strict(s, IntValue, 10); } 
115 
116// These are both base 10 only. They return 0.0 (or 0.0f) if there is no conversion. They also handle converting a 
117// possible binary representation in he string. If the string contains a hash(#) and the next 8 or 16 digits are valid 
118// hex digits, thay are interpreted as the binary IEEE floating point rep directly. This stops 'wobble' when serializing 
119// and deserializing from disk multiple times as would be present in the approximate base 10 representations. 
120float tStrtof(const char*); 
121double tStrtod(const char*); 
122 
123// These are both base 10 only. They return 0.0 if there is no conversion. 
124inline float tAtof(const char* s) { return tStrtof(s); } 
125inline double tAtod(const char* s) { return tStrtod(s); } 
126 
127// String to bool. Case insensitive. Interprets "true", "t", "yes", "y", "on", "enable", "enabled", "1", "+", and 
128// strings that represent non-zero integers as boolean true. Otherwise false. 
129bool tStrtob(const char*); 
130 
131// Here are the functions for going from integral types to strings. strSize (as opposed to length) must include 
132// enough room for the terminating null. strSize should be the full size of the passed-in str buffer. The resulting 
133// string, if letter characters are called for (bases > 10) will be capital, not lower case. Base must be E [2, 36]. 
134// Conversion problems boil down to passing null str, strSize being too small, and specifying an out-of-bounds base. 
135// Returns false in these cases, and true on success. The int-to-string functions are mainly available to handle 
136// arbitrary base E (1, 36] since tsPrintf only handles octal, decimal, and hex. Floating point conversions to 
137// strings should be handled by the tPrintf-style functions due to their superior formatting specifiers. 
138template <typename IntegralType> bool tItostrT(IntegralType value, char* str, int strSize, int base = 10); 
139inline bool tItostr(int32 value, char* str, int strSize, int base = 10) { return tItostrT<int32>(value, str, strSize, base); } 
140inline bool tItostr(int64 value, char* str, int strSize, int base = 10) { return tItostrT<int64>(value, str, strSize, base); } 
141inline bool tItostr(uint32 value, char* str, int strSize, int base = 10) { return tItostrT<uint32>(value, str, strSize, base); } 
142inline bool tItostr(uint64 value, char* str, int strSize, int base = 10) { return tItostrT<uint64>(value, str, strSize, base); } 
143inline bool tItoa(int32 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); } 
144inline bool tItoa(int64 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); } 
145inline bool tItoa(uint32 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); } 
146inline bool tItoa(uint64 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); } 
147 
148inline bool tIsspace(char c) { return isspace(int(c)) ? true : false; } 
149inline bool tIsdigit(char c) { return isdigit(int(c)) ? true : false; } 
150inline bool tIsbdigit(char c) { return ((c == '0') || (c == '1')) ? true : false; } 
151inline bool tIsodigit(char c) { return ((c >= '0') && (c <= '7')) ? true : false; } 
152inline bool tIsxdigit(char c) { return isxdigit(int(c)) ? true : false; } 
153inline bool tIsalpha(char c) { return isalpha(int(c)) ? true : false; } 
154inline bool tIscntrl(char c) { return iscntrl(int(c)) ? true : false; } 
155inline bool tIsalnum(char c) { return isalnum(int(c)) ? true : false; } 
156inline bool tIsprint(char c) { return isprint(int(c)) ? true : false; } 
157inline bool tIspunct(char c) { return ispunct(int(c)) ? true : false; } 
158inline bool tIslower(char c) { return islower(int(c)) ? true : false; } 
159inline bool tIsupper(char c) { return isupper(int(c)) ? true : false; } 
160inline bool tIsHexDigit(char d) { return ((d >= 'a' && d <= 'f')||(d >= 'A' && d <= 'F')||(d >= '0' && d <= '9')); } 
161 
162inline char tChrlwr(char c) { return tIslower(c) ? c : c + ('a' - 'A'); } 
163inline char tChrupr(char c) { return tIsupper(c) ? c : c - ('a' - 'A'); } 
164void tStrrev(char* begin, char* end); 
165 
166 
167// NAN means not a number. P for positive. N for negative. I for indefinite. S for signaling. Q for quiet. 
168enum class tFloatType 
169
170 NORM, // A normal floating point value (normalized or denormalized). Must be first type. 
171 FIRST_SPECIAL
172 FIRST_NAN = FIRST_SPECIAL
173 PSNAN = FIRST_NAN, // Positive Signaling Not-A-Number. This must be the first NAN type. 
174 NSNAN, // Negative Signaling Not-A-Number. 
175 PQNAN, // Positive non-signaling (quiet) Not-A-Number (QNAN). 
176 NQNAN, // Negative non-signaling (quiet) Not-A-Number (QNAN). Must be the last NAN type. 
177 IQNAN, // Indefinite QNAN. For AMD64 processors only a single NQNAN is used for Indefinite.  
178 LAST_NAN = IQNAN
179 PINF, // Positive INFinity. 
180 NINF, // Negative INFinity. 
181 LAST_SPECIAL = NINF 
182}; 
183tFloatType tGetFloatType(float); // Single precision get float type. 
184tFloatType tGetFloatType(double); // Double precision get float type. 
185inline bool tIsNAN(float v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_NAN)) && (int(t) <= int(tFloatType::LAST_NAN))) ? true : false; } 
186inline bool tIsNAN(double v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_NAN)) && (int(t) <= int(tFloatType::LAST_NAN))) ? true : false; } 
187inline bool tIsSpecial(float v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_SPECIAL)) && (int(t) <= int(tFloatType::LAST_SPECIAL))) ? true : false; } 
188inline bool tIsSpecial(double v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_SPECIAL)) && (int(t) <= int(tFloatType::LAST_SPECIAL))) ? true : false; } 
189inline float tFrexp(float arg, int* exp) { return frexpf(arg, exp); } 
190 
191// Examples of non-NORM float types. These are only examples as in many cases there are multiple bitpatterns for the 
192// same tFloatType. For example a PSNAN can have any bitpattern between 0x7F800001 and 0x7FBFFFFF (inclusive). 
193// P for positive. N for negative. Q for quiet. S for signalling. 
194inline float tFloatPSNAN() { union LU { float Nan; uint32 B; } v; v.B = 0x7F800001; return v.Nan; } 
195inline float tFloatNSNAN() { union LU { float Nan; uint32 B; } v; v.B = 0xFF800001; return v.Nan; } 
196inline float tFloatPQNAN() { union LU { float Nan; uint32 B; } v; v.B = 0x7FC00000; return v.Nan; } 
197inline float tFloatIQNAN() { union LU { float Nan; uint32 B; } v; v.B = 0xFFC00000; return v.Nan; } 
198inline float tFloatNQNAN() { union LU { float Nan; uint32 B; } v; v.B = 0xFFC00001; return v.Nan; } 
199inline float tFloatPINF() { union LU { float Inf; uint32 B; } v; v.B = 0x7F800000; return v.Inf; } 
200inline float tFloatNINF() { union LU { float Inf; uint32 B; } v; v.B = 0xFF800000; return v.Inf; } 
201 
202inline double tDoublePSNAN() { union LU { double Nan; uint64 B; } v; v.B = 0x7FF0000000000001ULL; return v.Nan; } 
203inline double tDoubleNSNAN() { union LU { double Nan; uint64 B; } v; v.B = 0xFFF0000000000001ULL; return v.Nan; } 
204inline double tDoublePQNAN() { union LU { double Nan; uint64 B; } v; v.B = 0x7FF8000000000000ULL; return v.Nan; } 
205inline double tDoubleIQNAN() { union LU { double Nan; uint64 B; } v; v.B = 0xFFF8000000000000ULL; return v.Nan; } 
206inline double tDoubleNQNAN() { union LU { double Nan; uint64 B; } v; v.B = 0xFFF8000000000001ULL; return v.Nan; } 
207inline double tDoublePINF() { union LU { double Inf; uint64 B; } v; v.B = 0x7FF0000000000000ULL; return v.Inf; } 
208inline double tDoubleNINF() { union LU { double Inf; uint64 B; } v; v.B = 0xFFF0000000000000ULL; return v.Inf; } 
209 
210// These ASCII separators may be used for things like replacing characters in strings for subsequent manipulation. 
211const char SeparatorSub = 26; // 0x1A 
212const char SeparatorFile = 28; // 0x1C 
213const char SeparatorGroup = 29; // 0x1D 
214const char SeparatorRecord = 30; // 0x1E 
215const char SeparatorUnit = 31; // 0x1F 
216 
217const char SeparatorA = SeparatorUnit
218const char SeparatorB = SeparatorRecord
219const char SeparatorC = SeparatorGroup
220const char SeparatorD = SeparatorFile
221const char SeparatorE = SeparatorSub
222 
223extern const char* SeparatorSubStr
224extern const char* SeparatorFileStr
225extern const char* SeparatorGroupStr
226extern const char* SeparatorRecordStr
227extern const char* SeparatorUnitStr
228 
229extern const char* SeparatorAStr
230extern const char* SeparatorBStr
231extern const char* SeparatorCStr
232extern const char* SeparatorDStr
233extern const char* SeparatorEStr
234 
235 
236
237 
238 
239// Implementation below this line. 
240 
241 
242template<typename IntegralType> inline IntegralType tStd::tStrtoiT(const char* str, int base
243
244 if (!str || (*str == '\0')) 
245 return IntegralType(0); 
246 
247 int len = tStrlen(str); 
248 const char* start = str
249 const char* end = str + len - 1
250 
251 if ((base < 2) || (base > 36)) 
252 base = -1
253 
254 if (base == -1
255
256 // Base is -1. Need to determine based on prefix. 
257 if ((len > 1) && (*start == '0')) 
258 start++; 
259 
260 if ((*start == 'x') || (*start == 'X') || (*start == '#')) 
261 base = 16
262 else if ((*start == 'd') || (*start == 'D')) 
263 base = 10
264 else if ((*start == 'o') || (*start == 'O') || (*start == '@')) 
265 base = 8
266 else if ((*start == 'n') || (*start == 'N')) 
267 base = 4
268 else if ((*start == 'b') || (*start == 'B') || (*start == '!')) 
269 base = 2
270 
271 if (base == -1
272 base = 10
273 else 
274 start++; 
275
276 
277 IntegralType val = 0
278 IntegralType colVal = 1
279 for (const char* curr = end; curr >= start; curr--) 
280
281 if ((*curr == '-') && (base == 10)) 
282
283 val = -val
284 continue
285
286 
287 int digVal = -1
288 if (*curr >= '0' && *curr <= '9'
289 digVal = *curr - '0'
290 else if (*curr >= 'a' && *curr <= 'z'
291 digVal = 10 + (*curr - 'a'); 
292 else if (*curr >= 'A' && *curr <= 'Z'
293 digVal = 10 + (*curr - 'A'); 
294 
295 if ((digVal == -1) || (digVal > base-1)) 
296 continue
297 
298 val += IntegralType(digVal)*colVal
299 colVal *= IntegralType(base); 
300
301 
302 return val
303
304 
305 
306template<typename IntegralType> inline bool tStd::tStrtoiTStrict(const char* str, IntegralType& val, int base
307
308 val = 0
309 if (!str || (*str == '\0')) 
310 return false
311 
312 int len = tStrlen(str); 
313 const char* start = str
314 const char* end = str + len - 1
315 bool negate = false
316 
317 // If the number starts with a '-', before the base modifier, it should be applied 
318 if((*start == '-')) 
319
320 negate = true
321 start++; 
322
323 
324 if ((base < 2) || (base > 36)) 
325 base = -1
326 
327 if (base == -1
328
329 // Base is -1. Need to determine based on prefix. 
330 if ((len > 1) && (*start == '0')) 
331 start++; 
332 
333 if ((*start == 'x') || (*start == 'X') || (*start == '#')) 
334 base = 16
335 else if ((*start == 'd') || (*start == 'D')) 
336 base = 10
337 else if ((*start == 'o') || (*start == 'O') || (*start == '@')) 
338 base = 8
339 else if ((*start == 'n') || (*start == 'N')) 
340 base = 4
341 else if ((*start == 'b') || (*start == 'B') || (*start == '!')) 
342 base = 2
343 
344 if (base == -1
345 base = 10
346 else 
347 start++; 
348
349 
350 IntegralType colVal = 1
351 for (const char* curr = end; curr >= start; curr--) 
352
353 if ((curr == start) && (*curr == '-')) 
354
355 // a '-' after the base specifier or a double minus in base 10 is an error 
356 if(negate || base != 10
357
358 val = 0
359 return false
360
361 
362 val = -val
363 continue
364
365 
366 int digVal = -1
367 if (*curr >= '0' && *curr <= '9'
368 digVal = *curr - '0'
369 else if (*curr >= 'a' && *curr <= 'z'
370 digVal = 10 + (*curr - 'a'); 
371 else if (*curr >= 'A' && *curr <= 'Z'
372 digVal = 10 + (*curr - 'A'); 
373 
374 if ((digVal == -1) || (digVal > base-1)) 
375
376 val = 0
377 return false
378
379 
380 val += IntegralType(digVal)*colVal
381 colVal *= IntegralType(base); 
382
383 
384 if(negate
385 val = -val
386 
387 return true
388
389 
390 
391template<typename IntegralType> inline bool tStd::tItostrT(IntegralType value, char* str, int strSize, int base
392
393 if (!str || strSize <= 0
394 return false
395 
396 static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
397 
398 // Validate base. 
399 if ((base < 2) || (base > sizeof(digits)/sizeof(*digits))) 
400 return false
401 
402 // Take care of sign. 
403 IntegralType sign = value
404 if (value < 0
405 value = -value
406 
407 // Conversion. Number is reversed. 
408 char* s = str
409 int numWritten = 0
410 int remainder
411 IntegralType quotient
412 do 
413
414 remainder = value % base
415 tAssert((remainder < base) && (remainder >= 0)); 
416 quotient = value / base
417 if (numWritten < strSize
418 *s++ = digits[remainder]; 
419 else 
420 return false
421 numWritten++; 
422 } while ((value = quotient)); 
423 
424 if (sign < 0
425
426 if (numWritten < strSize
427 *s++='-'
428 else 
429 return false
430
431 
432 if (numWritten < strSize
433 *s = '\0'
434 else 
435 return false
436 
437 tStrrev(str, s-1); 
438 return true
439
440 
441 
442inline tStd::tFloatType tStd::tGetFloatType(float v
443
444 uint32 b = *((uint32*)&v); 
445  
446 if ((b >= 0x7F800001) && (b <= 0x7FBFFFFF)) 
447 return tFloatType::PSNAN
448 
449 if ((b >= 0xFF800001) && (b <= 0xFFBFFFFF)) 
450 return tFloatType::NSNAN
451 
452 if ((b >= 0x7FC00000) && (b <= 0x7FFFFFFF)) 
453 return tFloatType::PQNAN
454 
455 if (b == 0xFFC00000
456 return tFloatType::IQNAN
457 
458 if ((b >= 0xFFC00001) && (b <= 0xFFFFFFFF)) 
459 return tFloatType::NQNAN
460 
461 if (b == 0x7F800000
462 return tFloatType::PINF
463 
464 if (b == 0xFF800000
465 return tFloatType::NINF
466 
467 return tFloatType::NORM
468
469 
470 
471inline tStd::tFloatType tStd::tGetFloatType(double v
472
473 uint64 b = *((uint64*)&v); 
474 
475 if ((b >= 0x7FF0000000000001ULL) && (b <= 0x7FF7FFFFFFFFFFFFULL)) 
476 return tFloatType::PSNAN
477 
478 if ((b >= 0xFFF0000000000001ULL) && (b <= 0xFFF7FFFFFFFFFFFFULL)) 
479 return tFloatType::NSNAN
480 
481 if ((b >= 0x7FF8000000000000ULL) && (b <= 0x7FFFFFFFFFFFFFFFULL)) 
482 return tFloatType::PQNAN
483 
484 if (b == 0xFFF8000000000000ULL
485 return tFloatType::IQNAN
486 
487 if ((b >= 0xFFF8000000000001ULL) && (b <= 0xFFFFFFFFFFFFFFFFULL)) 
488 return tFloatType::NQNAN
489 
490 if (b == 0x7FF0000000000000ULL
491 return tFloatType::PINF
492 
493 if (b == 0xFFF0000000000000ULL
494 return tFloatType::NINF
495 
496 return tFloatType::NORM
497
498