Jamoma API  0.6.0.a19
NumberToString.h
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