1 #ifndef NUMBERTOSTRING_H 2 #define NUMBERTOSTRING_H 3 4 #include <limits> 5 #include "JSONDebug.h" 6 #ifdef JSON_LESS_MEMORY 7 #include "JSONMemory.h" 8 #endif 9 #include "JSONSharedString.h" 10 #include <cstdio> 11 #ifdef JSON_STRICT 12 #include <cmath> 13 #endif 14 template <unsigned int GETLENSIZE> 15 struct getLenSize{ 16 char tmp[GETLENSIZE == 16]; // compile time assertion 17 enum {GETLEN = 41}; 18 }; 19 20 template<> 21 struct getLenSize<1>{ 22 enum {GETLEN = 5}; 23 }; 24 25 template <> 26 struct getLenSize<2>{ 27 enum {GETLEN = 7}; 28 }; 29 30 template <> 31 struct getLenSize<4>{ 32 enum {GETLEN = 12}; 33 }; 34 35 template <> 36 struct getLenSize<8>{ 37 enum {GETLEN = 22}; 38 }; 39 40 static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_pure; 41 static inline bool _floatsAreEqual(const json_number & one, const json_number & two) json_nothrow { 42 return (one > two) ? (one - two) < JSON_FLOAT_THRESHHOLD : (one - two) > -JSON_FLOAT_THRESHHOLD; 43 } 44 45 #ifdef JSON_LESS_MEMORY 46 #define num_str_result s.ptr 47 #endif 48 49 class NumberToString { 50 public: 51 template<typename T> 52 static json_string _itoa(T val) json_nothrow { 53 #ifdef JSON_LESS_MEMORY 54 json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN); 55 #else 56 json_char num_str_result[getLenSize<sizeof(T)>::GETLEN]; 57 #endif 58 num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator 59 json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2]; 60 bool negative; 61 62 START_MEM_SCOPE 63 long value = (long)val; 64 //first thing, check if it's negative, if so, make it positive 65 if (value < 0){ 66 value = -value; 67 negative = true; 68 } else { 69 negative = false; 70 } 71 72 //create the string 73 do { 74 *runner-- = (json_char)(value % 10) + JSON_TEXT('0'); 75 } while(value /= 10); 76 END_MEM_SCOPE 77 78 //if it's negative, add the negation 79 if (negative){ 80 *runner = JSON_TEXT('-'); 81 return json_string(runner); 82 } 83 return json_string(runner + 1); 84 } 85 86 #ifndef JSON_LIBRARY 87 template<typename T> 88 static json_string _uitoa(T val) json_nothrow { 89 #ifdef JSON_LESS_MEMORY 90 json_auto<json_char> s(getLenSize<sizeof(T)>::GETLEN); 91 #else 92 json_char num_str_result[getLenSize<sizeof(T)>::GETLEN]; 93 #endif 94 num_str_result[getLenSize<sizeof(T)>::GETLEN - 1] = JSON_TEXT('\0'); //null terminator 95 json_char * runner = &num_str_result[getLenSize<sizeof(T)>::GETLEN - 2]; 96 97 //create the string 98 START_MEM_SCOPE 99 unsigned long value = (unsigned long)val; 100 do { 101 *runner-- = (json_char)(value % 10) + JSON_TEXT('0'); 102 } while(value /= 10); 103 END_MEM_SCOPE 104 105 return json_string(runner + 1); 106 } 107 #endif 108 109 #ifdef JSON_ISO_STRICT 110 #define EXTRA_LONG 111 #define FLOAT_STRING "%f" 112 #define LFLOAT_STRING L"%f" 113 #else 114 #define EXTRA_LONG long 115 #define FLOAT_STRING "%Lf" 116 #define LFLOAT_STRING L"%Lf" 117 #endif 118 119 static json_string _ftoa(json_number value) json_nothrow { 120 #ifndef JSON_LIBRARY 121 //ScopeCoverage(_ftoa_coverage, 6); 122 if (json_unlikely(value >= 0.0 && _floatsAreEqual(value, (json_number)((unsigned EXTRA_LONG long)value)))){ 123 return _uitoa<unsigned EXTRA_LONG long>((unsigned EXTRA_LONG long)value); 124 } else 125 #else 126 //ScopeCoverage(_ftoa_coverage, 5); 127 #endif 128 if (json_unlikely(_floatsAreEqual(value, (json_number)((long EXTRA_LONG)value)))){ 129 return _itoa<long EXTRA_LONG>((long EXTRA_LONG)value); 130 } 131 132 #ifdef JSON_LESS_MEMORY 133 json_auto<json_char> s(64); 134 #else 135 json_char num_str_result[64]; 136 #endif 137 #ifdef JSON_UNICODE 138 std::swprintf(num_str_result, 63, LFLOAT_STRING, (EXTRA_LONG double)value); 139 #else 140 //Thanks to Salvor Hardin for this Visual C++ fix 141 #ifdef _MSC_VER 142 _snprintf_s(num_str_result, 63, 63, FLOAT_STRING, (EXTRA_LONG double)value); //yes, 63 appears twice using _snprintf_s() 143 #else 144 snprintf(num_str_result, 63, FLOAT_STRING, (EXTRA_LONG double)value); 145 #endif 146 #endif 147 //strip the trailing zeros 148 for(json_char * pos = &num_str_result[0]; *pos; ++pos){ 149 if (json_unlikely(*pos == '.')){ //only care about after the decimal 150 for(json_char * runner = pos + 1; *runner; ++runner){ 151 if (json_likely(*runner != JSON_TEXT('0'))){ 152 pos = runner + 1; //have to go to the end 1.0001 153 } 154 } 155 *pos = JSON_TEXT('\0'); 156 break; 157 } 158 } 159 return json_string(num_str_result); 160 } 161 162 #if defined(JSON_SAFE) || defined(JSON_DEBUG) 163 static bool isNumeric(const json_string & str) json_nothrow { 164 const json_char * p = str.c_str(); 165 bool decimal = false; 166 bool scientific = false; 167 168 #ifdef JSON_STRICT 169 bool leadingzero = false; 170 #endif 171 172 //first letter is weird 173 switch(*p){ 174 case JSON_TEXT('\0'): 175 return false; 176 #ifndef JSON_STRICT 177 case JSON_TEXT('.'): 178 decimal = true; 179 break; 180 case JSON_TEXT('+'): 181 #endif 182 case JSON_TEXT('-'): 183 switch (*(p + 1)){ 184 case JSON_TEXT('.'): 185 case JSON_TEXT('e'): 186 case JSON_TEXT('E'): 187 case JSON_TEXT('\0'): 188 return false; 189 case JSON_TEXT('0'): 190 #ifdef JSON_STRICT 191 switch(*(p + 2)){ 192 case JSON_TEXT('.'): 193 case JSON_TEXT('e'): 194 case JSON_TEXT('E'): 195 leadingzero = false; 196 break; 197 case JSON_TEXT('\0'): 198 return true; 199 default: 200 leadingzero = true; 201 break; 202 } 203 #endif 204 ++p; 205 break; 206 default: 207 break; 208 } 209 break; 210 case JSON_TEXT('1'): 211 case JSON_TEXT('2'): 212 case JSON_TEXT('3'): 213 case JSON_TEXT('4'): 214 case JSON_TEXT('5'): 215 case JSON_TEXT('6'): 216 case JSON_TEXT('7'): 217 case JSON_TEXT('8'): 218 case JSON_TEXT('9'): 219 break; 220 case JSON_TEXT('0'): 221 ++p; 222 #ifdef JSON_STRICT 223 leadingzero = true; 224 #endif 225 switch(*p){ 226 case JSON_TEXT('.'): 227 decimal = true; 228 break; 229 case JSON_TEXT('e'): 230 case JSON_TEXT('E'): 231 #ifdef JSON_STRICT 232 leadingzero = false; //not leading, just a zero 233 #endif 234 scientific = true; 235 ++p; 236 switch(*p){ 237 case JSON_TEXT('\0'): 238 return false; 239 case JSON_TEXT('-'): 240 case JSON_TEXT('+'): 241 #ifndef JSON_STRICT 242 case JSON_TEXT('0'): //cant have a leading zero in scrict 243 #endif 244 case JSON_TEXT('1'): 245 case JSON_TEXT('2'): 246 case JSON_TEXT('3'): 247 case JSON_TEXT('4'): 248 case JSON_TEXT('5'): 249 case JSON_TEXT('6'): 250 case JSON_TEXT('7'): 251 case JSON_TEXT('8'): 252 case JSON_TEXT('9'): 253 break; 254 default: 255 return false; 256 } 257 break; 258 #ifndef JSON_STRICT 259 case JSON_TEXT('x'): 260 return (str.find_first_not_of(JSON_TEXT("0123456789ABCDEFabcdef"), 2) == json_string::npos); 261 case JSON_TEXT('1'): 262 case JSON_TEXT('2'): 263 case JSON_TEXT('3'): 264 case JSON_TEXT('4'): 265 case JSON_TEXT('5'): 266 case JSON_TEXT('6'): 267 case JSON_TEXT('7'): 268 return (str.find_first_not_of(JSON_TEXT("01234567"), 1) == json_string::npos); 269 #endif 270 case JSON_TEXT('\0'): //just 0 271 return true; 272 default: 273 return false; 274 } 275 break; 276 default: 277 return false; 278 } 279 ++p; 280 281 //next digits 282 while (*p){ 283 switch(*p){ 284 case JSON_TEXT('.'): 285 if (json_unlikely(decimal)){ 286 return false; //multiple decimals 287 } 288 289 if (json_unlikely(scientific)){ 290 return false; 291 } 292 decimal = true; 293 break; 294 case JSON_TEXT('e'): 295 case JSON_TEXT('E'): 296 if (json_unlikely(scientific)){ 297 return false; 298 } 299 scientific = true; 300 ++p; 301 switch(*p){ 302 case JSON_TEXT('\0'): 303 return false; 304 case JSON_TEXT('-'): 305 case JSON_TEXT('+'): 306 if (!isdigit(*(p + 1))){ 307 return false; 308 } 309 310 #ifdef JSON_STRICT 311 if (*(p + 1) == JSON_TEXT('0')){ //no leading zeros on scientific notations 312 return false; 313 } 314 #endif 315 break; 316 #ifndef JSON_STRICT 317 case JSON_TEXT('0'): //cant have a leading zero in scrict 318 #endif 319 case JSON_TEXT('1'): 320 case JSON_TEXT('2'): 321 case JSON_TEXT('3'): 322 case JSON_TEXT('4'): 323 case JSON_TEXT('5'): 324 case JSON_TEXT('6'): 325 case JSON_TEXT('7'): 326 case JSON_TEXT('8'): 327 case JSON_TEXT('9'): 328 break; 329 default: 330 return false; 331 } 332 break; 333 case JSON_TEXT('0'): 334 case JSON_TEXT('1'): 335 case JSON_TEXT('2'): 336 case JSON_TEXT('3'): 337 case JSON_TEXT('4'): 338 case JSON_TEXT('5'): 339 case JSON_TEXT('6'): 340 case JSON_TEXT('7'): 341 case JSON_TEXT('8'): 342 case JSON_TEXT('9'): 343 break; 344 default: 345 return false; 346 } 347 ++p; 348 } 349 #ifdef JSON_STRICT 350 if (leadingzero && !decimal){ 351 return false; 352 } 353 #endif 354 return true; 355 } 356 #endif 357 358 #ifdef JSON_STRICT 359 //much faster because no octal or hex support 360 static json_number _atof (const json_char * num){ 361 json_number sign = (json_number)1.0; 362 363 //sign 364 if (*num==JSON_TEXT('-')){ 365 sign = -1.0; 366 ++num; 367 } else { 368 } 369 370 //skip leading zero if one 371 #if defined(JSON_SAFE) || defined(JSON_DEBUG) 372 bool _leadingzeros = *num == JSON_TEXT('0'); 373 bool _leadingdigits = false; 374 #endif 375 if (*num == JSON_TEXT('0')){ 376 ++num; 377 } 378 #ifdef JSON_STRICT 379 else if (json_likely(*num < JSON_TEXT('1') || *num > JSON_TEXT('9'))){ 380 return std::numeric_limits<json_number>::signaling_NaN(); 381 } 382 #endif 383 384 JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("multiple leading zeros"), return std::numeric_limits<json_number>::signaling_NaN(); ); 385 386 // Number 387 json_number n = (json_number)0.0; 388 if (json_likely(*num >= JSON_TEXT('1') && *num <= JSON_TEXT('9'))){ 389 #if defined(JSON_SAFE) || defined(JSON_DEBUG) 390 _leadingdigits = true; 391 #endif 392 do { 393 n = (n * 10.0) + (*num++ - JSON_TEXT('0')); 394 } while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9')); 395 } else { 396 JSON_ASSERT_SAFE( 397 (*num) == JSON_TEXT('.') || //.xxx 398 (*num) == JSON_TEXT('e') || //0Exxx 399 (*num) == JSON_TEXT('E') || //0exxx 400 (*num) == JSON_TEXT('\0') //end of the number, just zero 401 , JSON_TEXT("first digit not a number, e, period, or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); ); 402 } 403 404 // Fractional part 405 json_number scale = (json_number)0.0; 406 if (*num == JSON_TEXT('.')) { 407 JSON_ASSERT_SAFE(_leadingzeros || _leadingdigits, JSON_TEXT("period without leading anything"), return std::numeric_limits<json_number>::signaling_NaN(); ); 408 ++num; 409 for(; *num >= JSON_TEXT('0') && *num <= JSON_TEXT('9');){ 410 n = (n * 10.0) + (*num++ - JSON_TEXT('0')); 411 --scale; 412 }; 413 } else { 414 JSON_ASSERT_SAFE(!_leadingzeros || n == 0, JSON_TEXT("leading zero on an int"), return std::numeric_limits<json_number>::signaling_NaN(); ); 415 JSON_ASSERT_SAFE( 416 (*num) == JSON_TEXT('e') || //0Exxx 417 (*num) == JSON_TEXT('E') || //0exxx 418 (*num) == JSON_TEXT('\0') //end of the number, just zero 419 , JSON_TEXT("next char not an e or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); ); 420 } 421 422 // Exponent 423 int subscale = 0, signsubscale = 1; 424 if (json_unlikely(*num == JSON_TEXT('e') || *num == JSON_TEXT('E'))){ 425 ++num; 426 switch(*num){ 427 case JSON_TEXT('+'): 428 ++num; 429 break; 430 case JSON_TEXT('-'): 431 signsubscale = -1; 432 ++num; 433 JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("negative cant be followed by leading zero even after E"), return std::numeric_limits<json_number>::signaling_NaN(); ); 434 break; 435 default: 436 break; 437 } 438 JSON_ASSERT_SAFE(*num != JSON_TEXT('\0'), JSON_TEXT("no exponent for scientific notation"), return std::numeric_limits<json_number>::signaling_NaN(); ); 439 while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9')){ 440 subscale=(subscale * 10) + (*num++ - JSON_TEXT('0')); 441 } 442 } 443 444 JSON_ASSERT_SAFE(*num == JSON_TEXT('\0'), JSON_TEXT("done with number, not at terminator"), return std::numeric_limits<json_number>::signaling_NaN(); ); 445 return sign * n * pow((json_number)10.0, scale + subscale * signsubscale); // number = +/- number.fraction * 10^+/- exponent 446 } 447 #endif 448 }; 449 450 #endif 451