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 |   |
30 | namespace tStd  |
31 | {  |
32 |   |
33 | // The 3 XOR trick is slower in most cases so we'll use a standard swap.  |
34 | template<typename T> inline void tSwap(T& a, T& b) { T t = a; a = b; b = t; }  |
35 | inline void* tMemcpy(void* dest, const void* src, int numBytes) { return memcpy(dest, src, numBytes); }  |
36 | inline void* tMemset(void* dest, uint8 val, int numBytes) { return memset(dest, val, numBytes); }  |
37 | inline void* tMemchr(void* data, uint8 val, int numBytes) { return memchr(data, val, numBytes); }  |
38 | inline const void* tMemchr(const void* data, uint8 val, int numBytes) { return memchr(data, val, numBytes); }  |
39 | inline 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.  |
43 | void* tMemmem(void* haystack, int haystackNumBytes, void* needle, int needleNumBytes);  |
44 | inline 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.  |
49 | const int tCharInvalid = 0xFF;  |
50 | inline int tStrcmp(const char* a, const char* b) { tAssert(a && b); return strcmp(a, b); }  |
51 | inline 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)  |
53 | inline int tStricmp(const char* a, const char* b) { tAssert(a && b); return stricmp(a, b); }  |
54 | inline int tStrnicmp(const char* a, const char* b, int n) { tAssert(a && b && n >= 0); return strnicmp(a, b, n); }  |
55 | #else  |
56 | inline int tStricmp(const char* a, const char* b) { tAssert(a && b); return strcasecmp(a, b); }  |
57 | inline int tStrnicmp(const char* a, const char* b, int n) { tAssert(a && b && n >= 0); return strncasecmp(a, b, n); }  |
58 | #endif  |
59 | inline int tStrlen(const char* s) { tAssert(s); return int(strlen(s)); }  |
60 | inline constexpr int tStrlenCT(const char* s) { return *s ? 1 + tStrlenCT(s + 1) : 0; }  |
61 | inline char* tStrcpy(char* dst, const char* src) { tAssert(dst && src); return strcpy(dst, src); }  |
62 | inline char* tStrncpy(char* dst, const char* src, int n) { tAssert(dst && src && n >= 0); return strncpy(dst, src, n); }  |
63 | inline char* tStrchr(const char* s, int c) { tAssert(s && c >= 0 && c < 0x100); return (char*)strchr(s, c); }  |
64 | inline char* tStrstr(const char* s, const char* r) { tAssert(s && r); return (char*)strstr(s, r); }  |
65 | inline char* tStrcat(char* s, const char* r) { tAssert(s && r); return (char*)strcat(s, r); }  |
66 |   |
67 | #if defined(PLATFORM_WINDOWS)  |
68 | inline char* tStrupr(char* s) { tAssert(s); return _strupr(s); }  |
69 | inline char* tStrlwr(char* s) { tAssert(s); return _strlwr(s); }  |
70 | #else  |
71 | inline char* tStrupr(char* s) { tAssert(s); char* c = s; while (*c) { *c = toupper(*c); c++; } return s; }  |
72 | inline 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.  |
98 | template <typename IntegralType> IntegralType tStrtoiT(const char*, int base = -1);  |
99 | inline int32 tStrtoi32(const char* s, int base = -1) { return tStrtoiT<int32>(s, base); }  |
100 | inline uint32 tStrtoui32(const char* s, int base = -1) { return tStrtoiT<uint32>(s, base); }  |
101 | inline int64 tStrtoi64(const char* s, int base = -1) { return tStrtoiT<int64>(s, base); }  |
102 | inline uint64 tStrtoui64(const char* s, int base = -1) { return tStrtoiT<uint64>(s, base); }  |
103 | inline int tStrtoui(const char* s, int base = -1) { return tStrtoui32(s, base); }  |
104 | inline int tStrtoi(const char* s, int base = -1) { return tStrtoi32(s, base); }  |
105 | inline int tAtoi(const char* s) /* Base 10 only. Use tStrtoi for arbitrary base. */ { return tStrtoi32(s, 10); }  |
106 |   |
107 | template <typename IntegralType> bool tStrtoiTStrict(const char* str, IntegralType& val, int base = -1);  |
108 | inline bool tStrtoi32Strict(const char* s, int32& Int32Value, int base = -1) { return tStrtoiTStrict<int32>(s, Int32Value, base); }  |
109 | inline bool tStrtoui32Strict(const char* s, uint32& UInt32Value, int base = -1) { return tStrtoiTStrict<uint32>(s, UInt32Value, base); }  |
110 | inline bool tStrtoi64Strict(const char* s, int64& Int64Value, int base = -1) { return tStrtoiTStrict<int64>(s, Int64Value, base); }  |
111 | inline bool tStrtoui64Strict(const char* s, uint64& UInt64Value, int base = -1) { return tStrtoiTStrict<uint64>(s, UInt64Value, base); }  |
112 | inline bool tStrtouiStrict(const char* s, uint32& IntValue, int base = -1) { return tStrtoui32Strict(s, IntValue, base); }  |
113 | inline bool tStrtoiStrict(const char* s, int& IntValue, int base = -1) { return tStrtoi32Strict(s, IntValue, base); }  |
114 | inline 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.  |
120 | float tStrtof(const char*);  |
121 | double tStrtod(const char*);  |
122 |   |
123 | // These are both base 10 only. They return 0.0 if there is no conversion.  |
124 | inline float tAtof(const char* s) { return tStrtof(s); }  |
125 | inline 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.  |
129 | bool 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.  |
138 | template <typename IntegralType> bool tItostrT(IntegralType value, char* str, int strSize, int base = 10);  |
139 | inline bool tItostr(int32 value, char* str, int strSize, int base = 10) { return tItostrT<int32>(value, str, strSize, base); }  |
140 | inline bool tItostr(int64 value, char* str, int strSize, int base = 10) { return tItostrT<int64>(value, str, strSize, base); }  |
141 | inline bool tItostr(uint32 value, char* str, int strSize, int base = 10) { return tItostrT<uint32>(value, str, strSize, base); }  |
142 | inline bool tItostr(uint64 value, char* str, int strSize, int base = 10) { return tItostrT<uint64>(value, str, strSize, base); }  |
143 | inline bool tItoa(int32 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); }  |
144 | inline bool tItoa(int64 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); }  |
145 | inline bool tItoa(uint32 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); }  |
146 | inline bool tItoa(uint64 value, char* str, int strSize, int base = 10) { return tItostr(value, str, strSize, base); }  |
147 |   |
148 | inline bool tIsspace(char c) { return isspace(int(c)) ? true : false; }  |
149 | inline bool tIsdigit(char c) { return isdigit(int(c)) ? true : false; }  |
150 | inline bool tIsbdigit(char c) { return ((c == '0') || (c == '1')) ? true : false; }  |
151 | inline bool tIsodigit(char c) { return ((c >= '0') && (c <= '7')) ? true : false; }  |
152 | inline bool tIsxdigit(char c) { return isxdigit(int(c)) ? true : false; }  |
153 | inline bool tIsalpha(char c) { return isalpha(int(c)) ? true : false; }  |
154 | inline bool tIscntrl(char c) { return iscntrl(int(c)) ? true : false; }  |
155 | inline bool tIsalnum(char c) { return isalnum(int(c)) ? true : false; }  |
156 | inline bool tIsprint(char c) { return isprint(int(c)) ? true : false; }  |
157 | inline bool tIspunct(char c) { return ispunct(int(c)) ? true : false; }  |
158 | inline bool tIslower(char c) { return islower(int(c)) ? true : false; }  |
159 | inline bool tIsupper(char c) { return isupper(int(c)) ? true : false; }  |
160 | inline bool tIsHexDigit(char d) { return ((d >= 'a' && d <= 'f')||(d >= 'A' && d <= 'F')||(d >= '0' && d <= '9')); }  |
161 |   |
162 | inline char tChrlwr(char c) { return tIslower(c) ? c : c + ('a' - 'A'); }  |
163 | inline char tChrupr(char c) { return tIsupper(c) ? c : c - ('a' - 'A'); }  |
164 | void 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.  |
168 | enum 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 | };  |
183 | tFloatType tGetFloatType(float); // Single precision get float type.  |
184 | tFloatType tGetFloatType(double); // Double precision get float type.  |
185 | inline bool tIsNAN(float v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_NAN)) && (int(t) <= int(tFloatType::LAST_NAN))) ? true : false; }  |
186 | inline bool tIsNAN(double v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_NAN)) && (int(t) <= int(tFloatType::LAST_NAN))) ? true : false; }  |
187 | inline bool tIsSpecial(float v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_SPECIAL)) && (int(t) <= int(tFloatType::LAST_SPECIAL))) ? true : false; }  |
188 | inline bool tIsSpecial(double v) { tFloatType t = tGetFloatType(v); return ((int(t) >= int(tFloatType::FIRST_SPECIAL)) && (int(t) <= int(tFloatType::LAST_SPECIAL))) ? true : false; }  |
189 | inline 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.  |
194 | inline float tFloatPSNAN() { union LU { float Nan; uint32 B; } v; v.B = 0x7F800001; return v.Nan; }  |
195 | inline float tFloatNSNAN() { union LU { float Nan; uint32 B; } v; v.B = 0xFF800001; return v.Nan; }  |
196 | inline float tFloatPQNAN() { union LU { float Nan; uint32 B; } v; v.B = 0x7FC00000; return v.Nan; }  |
197 | inline float tFloatIQNAN() { union LU { float Nan; uint32 B; } v; v.B = 0xFFC00000; return v.Nan; }  |
198 | inline float tFloatNQNAN() { union LU { float Nan; uint32 B; } v; v.B = 0xFFC00001; return v.Nan; }  |
199 | inline float tFloatPINF() { union LU { float Inf; uint32 B; } v; v.B = 0x7F800000; return v.Inf; }  |
200 | inline float tFloatNINF() { union LU { float Inf; uint32 B; } v; v.B = 0xFF800000; return v.Inf; }  |
201 |   |
202 | inline double tDoublePSNAN() { union LU { double Nan; uint64 B; } v; v.B = 0x7FF0000000000001ULL; return v.Nan; }  |
203 | inline double tDoubleNSNAN() { union LU { double Nan; uint64 B; } v; v.B = 0xFFF0000000000001ULL; return v.Nan; }  |
204 | inline double tDoublePQNAN() { union LU { double Nan; uint64 B; } v; v.B = 0x7FF8000000000000ULL; return v.Nan; }  |
205 | inline double tDoubleIQNAN() { union LU { double Nan; uint64 B; } v; v.B = 0xFFF8000000000000ULL; return v.Nan; }  |
206 | inline double tDoubleNQNAN() { union LU { double Nan; uint64 B; } v; v.B = 0xFFF8000000000001ULL; return v.Nan; }  |
207 | inline double tDoublePINF() { union LU { double Inf; uint64 B; } v; v.B = 0x7FF0000000000000ULL; return v.Inf; }  |
208 | inline 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.  |
211 | const char SeparatorSub = 26; // 0x1A  |
212 | const char SeparatorFile = 28; // 0x1C  |
213 | const char SeparatorGroup = 29; // 0x1D  |
214 | const char SeparatorRecord = 30; // 0x1E  |
215 | const char SeparatorUnit = 31; // 0x1F  |
216 |   |
217 | const char SeparatorA = SeparatorUnit;  |
218 | const char SeparatorB = SeparatorRecord;  |
219 | const char SeparatorC = SeparatorGroup;  |
220 | const char SeparatorD = SeparatorFile;  |
221 | const char SeparatorE = SeparatorSub;  |
222 |   |
223 | extern const char* SeparatorSubStr;  |
224 | extern const char* SeparatorFileStr;  |
225 | extern const char* SeparatorGroupStr;  |
226 | extern const char* SeparatorRecordStr;  |
227 | extern const char* SeparatorUnitStr;  |
228 |   |
229 | extern const char* SeparatorAStr;  |
230 | extern const char* SeparatorBStr;  |
231 | extern const char* SeparatorCStr;  |
232 | extern const char* SeparatorDStr;  |
233 | extern const char* SeparatorEStr;  |
234 |   |
235 |   |
236 | }  |
237 |   |
238 |   |
239 | // Implementation below this line.  |
240 |   |
241 |   |
242 | template<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 |   |
306 | template<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 |   |
391 | template<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 |   |
442 | inline 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 |   |
471 | inline 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 | |