versadac  1
versadac - Scalable Recorder Firmware
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 
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  char temp_str_result[64];
137  int i = 0;
138  #endif
139  #ifdef JSON_UNICODE
140  //std::swprintf(num_str_result, 63, LFLOAT_STRING, (EXTRA_LONG double)value);
141  /* eurotherm patch for wide char support in vxworks kernel mode */
142  snprintf(temp_str_result, 63, FLOAT_STRING, (EXTRA_LONG double)value);
143  while( temp_str_result[i] != '\0' && i < 63)
144  {
145  num_str_result[i] = (wchar_t)temp_str_result[i];
146  i++;
147  }
148  num_str_result[i] = '\0';
149  #else
150  //Thanks to Salvor Hardin for this Visual C++ fix
151  #ifdef _MSC_VER
152  _snprintf_s(num_str_result, 63, 63, FLOAT_STRING, (EXTRA_LONG double)value); //yes, 63 appears twice using _snprintf_s()
153  #else
154  snprintf(num_str_result, 63, FLOAT_STRING, (EXTRA_LONG double)value);
155  #endif
156  #endif
157  //strip the trailing zeros
158  for(json_char * pos = &num_str_result[0]; *pos; ++pos){
159  if (json_unlikely(*pos == '.')){ //only care about after the decimal
160  for(json_char * runner = pos + 1; *runner; ++runner){
161  if (json_likely(*runner != JSON_TEXT('0'))){
162  pos = runner + 1; //have to go to the end 1.0001
163  }
164  }
165  *pos = JSON_TEXT('\0');
166  break;
167  }
168  }
169  return json_string(num_str_result);
170  }
171 
172  #if defined(JSON_SAFE) || defined(JSON_DEBUG)
173  static bool isNumeric(const json_string & str) json_nothrow {
174  const json_char * p = str.c_str();
175  bool decimal = false;
176  bool scientific = false;
177 
178  #ifdef JSON_STRICT
179  bool leadingzero = false;
180  #endif
181 
182  //first letter is weird
183  switch(*p){
184  case JSON_TEXT('\0'):
185  return false;
186  #ifndef JSON_STRICT
187  case JSON_TEXT('.'):
188  decimal = true;
189  break;
190  case JSON_TEXT('+'):
191  #endif
192  case JSON_TEXT('-'):
193  switch (*(p + 1)){
194  case JSON_TEXT('.'):
195  case JSON_TEXT('e'):
196  case JSON_TEXT('E'):
197  case JSON_TEXT('\0'):
198  return false;
199  case JSON_TEXT('0'):
200  #ifdef JSON_STRICT
201  switch(*(p + 2)){
202  case JSON_TEXT('.'):
203  case JSON_TEXT('e'):
204  case JSON_TEXT('E'):
205  leadingzero = false;
206  break;
207  case JSON_TEXT('\0'):
208  return true;
209  default:
210  leadingzero = true;
211  break;
212  }
213  #endif
214  ++p;
215  break;
216  default:
217  break;
218  }
219  break;
220  case JSON_TEXT('1'):
221  case JSON_TEXT('2'):
222  case JSON_TEXT('3'):
223  case JSON_TEXT('4'):
224  case JSON_TEXT('5'):
225  case JSON_TEXT('6'):
226  case JSON_TEXT('7'):
227  case JSON_TEXT('8'):
228  case JSON_TEXT('9'):
229  break;
230  case JSON_TEXT('0'):
231  ++p;
232  #ifdef JSON_STRICT
233  leadingzero = true;
234  #endif
235  switch(*p){
236  case JSON_TEXT('.'):
237  decimal = true;
238  break;
239  case JSON_TEXT('e'):
240  case JSON_TEXT('E'):
241  #ifdef JSON_STRICT
242  leadingzero = false; //not leading, just a zero
243  #endif
244  scientific = true;
245  ++p;
246  switch(*p){
247  case JSON_TEXT('\0'):
248  return false;
249  case JSON_TEXT('-'):
250  case JSON_TEXT('+'):
251  #ifndef JSON_STRICT
252  case JSON_TEXT('0'): //cant have a leading zero in scrict
253  #endif
254  case JSON_TEXT('1'):
255  case JSON_TEXT('2'):
256  case JSON_TEXT('3'):
257  case JSON_TEXT('4'):
258  case JSON_TEXT('5'):
259  case JSON_TEXT('6'):
260  case JSON_TEXT('7'):
261  case JSON_TEXT('8'):
262  case JSON_TEXT('9'):
263  break;
264  default:
265  return false;
266  }
267  break;
268  #ifndef JSON_STRICT
269  case JSON_TEXT('x'):
270  return (str.find_first_not_of(JSON_TEXT("0123456789ABCDEFabcdef"), 2) == json_string::npos);
271  case JSON_TEXT('1'):
272  case JSON_TEXT('2'):
273  case JSON_TEXT('3'):
274  case JSON_TEXT('4'):
275  case JSON_TEXT('5'):
276  case JSON_TEXT('6'):
277  case JSON_TEXT('7'):
278  return (str.find_first_not_of(JSON_TEXT("01234567"), 1) == json_string::npos);
279  #endif
280  case JSON_TEXT('\0'): //just 0
281  return true;
282  default:
283  return false;
284  }
285  break;
286  default:
287  return false;
288  }
289  ++p;
290 
291  //next digits
292  while (*p){
293  switch(*p){
294  case JSON_TEXT('.'):
295  if (json_unlikely(decimal)){
296  return false; //multiple decimals
297  }
298 
299  if (json_unlikely(scientific)){
300  return false;
301  }
302  decimal = true;
303  break;
304  case JSON_TEXT('e'):
305  case JSON_TEXT('E'):
306  if (json_unlikely(scientific)){
307  return false;
308  }
309  scientific = true;
310  ++p;
311  switch(*p){
312  case JSON_TEXT('\0'):
313  return false;
314  case JSON_TEXT('-'):
315  case JSON_TEXT('+'):
316  if (!isdigit(*(p + 1))){
317  return false;
318  }
319 
320  #ifdef JSON_STRICT
321  if (*(p + 1) == JSON_TEXT('0')){ //no leading zeros on scientific notations
322  return false;
323  }
324  #endif
325  break;
326  #ifndef JSON_STRICT
327  case JSON_TEXT('0'): //cant have a leading zero in scrict
328  #endif
329  case JSON_TEXT('1'):
330  case JSON_TEXT('2'):
331  case JSON_TEXT('3'):
332  case JSON_TEXT('4'):
333  case JSON_TEXT('5'):
334  case JSON_TEXT('6'):
335  case JSON_TEXT('7'):
336  case JSON_TEXT('8'):
337  case JSON_TEXT('9'):
338  break;
339  default:
340  return false;
341  }
342  break;
343  case JSON_TEXT('0'):
344  case JSON_TEXT('1'):
345  case JSON_TEXT('2'):
346  case JSON_TEXT('3'):
347  case JSON_TEXT('4'):
348  case JSON_TEXT('5'):
349  case JSON_TEXT('6'):
350  case JSON_TEXT('7'):
351  case JSON_TEXT('8'):
352  case JSON_TEXT('9'):
353  break;
354  default:
355  return false;
356  }
357  ++p;
358  }
359  #ifdef JSON_STRICT
360  if (leadingzero && !decimal){
361  return false;
362  }
363  #endif
364  return true;
365  }
366  #endif
367 
368  #ifdef JSON_STRICT
369  //much faster because no octal or hex support
370  static json_number _atof (const json_char * num){
371  json_number sign = (json_number)1.0;
372 
373  //sign
374  if (*num==JSON_TEXT('-')){
375  sign = -1.0;
376  ++num;
377  } else {
378  }
379 
380  //skip leading zero if one
381  #if defined(JSON_SAFE) || defined(JSON_DEBUG)
382  bool _leadingzeros = *num == JSON_TEXT('0');
383  bool _leadingdigits = false;
384  #endif
385  if (*num == JSON_TEXT('0')){
386  ++num;
387  }
388  #ifdef JSON_STRICT
389  else if (json_likely(*num < JSON_TEXT('1') || *num > JSON_TEXT('9'))){
390  return std::numeric_limits<json_number>::signaling_NaN();
391  }
392  #endif
393 
394  JSON_ASSERT_SAFE(*num != JSON_TEXT('0'), JSON_TEXT("multiple leading zeros"), return std::numeric_limits<json_number>::signaling_NaN(); );
395 
396  // Number
397  json_number n = (json_number)0.0;
398  if (json_likely(*num >= JSON_TEXT('1') && *num <= JSON_TEXT('9'))){
399  #if defined(JSON_SAFE) || defined(JSON_DEBUG)
400  _leadingdigits = true;
401  #endif
402  do {
403  n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
404  } while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9'));
405  } else {
406  JSON_ASSERT_SAFE(
407  (*num) == JSON_TEXT('.') || //.xxx
408  (*num) == JSON_TEXT('e') || //0Exxx
409  (*num) == JSON_TEXT('E') || //0exxx
410  (*num) == JSON_TEXT('\0') //end of the number, just zero
411  , JSON_TEXT("first digit not a number, e, period, or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
412  }
413 
414  // Fractional part
415  json_number scale = (json_number)0.0;
416  if (*num == JSON_TEXT('.')) {
417  JSON_ASSERT_SAFE(_leadingzeros || _leadingdigits, JSON_TEXT("period without leading anything"), return std::numeric_limits<json_number>::signaling_NaN(); );
418  ++num;
419  for(; *num >= JSON_TEXT('0') && *num <= JSON_TEXT('9');){
420  n = (n * 10.0) + (*num++ - JSON_TEXT('0'));
421  --scale;
422  };
423  } else {
424  JSON_ASSERT_SAFE(!_leadingzeros || n == 0, JSON_TEXT("leading zero on an int"), return std::numeric_limits<json_number>::signaling_NaN(); );
425  JSON_ASSERT_SAFE(
426  (*num) == JSON_TEXT('e') || //0Exxx
427  (*num) == JSON_TEXT('E') || //0exxx
428  (*num) == JSON_TEXT('\0') //end of the number, just zero
429  , JSON_TEXT("next char not an e or terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
430  }
431 
432  // Exponent
433  int subscale = 0, signsubscale = 1;
434  if (json_unlikely(*num == JSON_TEXT('e') || *num == JSON_TEXT('E'))){
435  ++num;
436  switch(*num){
437  case JSON_TEXT('+'):
438  ++num;
439  break;
440  case JSON_TEXT('-'):
441  signsubscale = -1;
442  ++num;
443  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(); );
444  break;
445  default:
446  break;
447  }
448  JSON_ASSERT_SAFE(*num != JSON_TEXT('\0'), JSON_TEXT("no exponent for scientific notation"), return std::numeric_limits<json_number>::signaling_NaN(); );
449  while (*num >= JSON_TEXT('0') && *num <= JSON_TEXT('9')){
450  subscale=(subscale * 10) + (*num++ - JSON_TEXT('0'));
451  }
452  }
453 
454  JSON_ASSERT_SAFE(*num == JSON_TEXT('\0'), JSON_TEXT("done with number, not at terminator"), return std::numeric_limits<json_number>::signaling_NaN(); );
455  return sign * n * pow((json_number)10.0, scale + subscale * signsubscale); // number = +/- number.fraction * 10^+/- exponent
456  }
457  #endif
458 };
459 
460 #endif
Definition: NumberToString.h:49
Definition: NumberToString.h:15
Definition: JSONMemory.h:140
Definition: StringTest.h:22