1 //
2 // NumericString.h
3 //
4 // Library: Foundation
5 // Package: Core
6 // Module: NumericString
7 //
8 // Numeric string utility functions.
9 //
10 // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
11 // and Contributors.
12 //
13 // SPDX-License-Identifier: BSL-1.0
14 //
15
16
17 #ifndef Foundation_NumericString_INCLUDED
18 #define Foundation_NumericString_INCLUDED
19
20
21 #include "Poco/Foundation.h"
22 #include "Poco/Buffer.h"
23 #include "Poco/FPEnvironment.h"
24 #ifdef min
25 #undef min
26 #endif
27 #ifdef max
28 #undef max
29 #endif
30 #include <limits>
31 #include <cmath>
32 #include <cctype>
33 #if !defined(POCO_NO_LOCALE)
34 #include <locale>
35 #endif
36
37 #if defined(POCO_NOINTMAX)
38 typedef Poco::UInt64 uintmax_t;
39 typedef Poco::Int64 intmax_t;
40 #endif
41 #if !defined (INTMAX_MAX)
42 #define INTMAX_MAX std::numeric_limits<intmax_t>::max()
43 #endif
44 #ifdef POCO_COMPILER_MSVC
45 #pragma warning(push)
46 #pragma warning(disable : 4146)
47 #endif // POCO_COMPILER_MSVC
48
49
50 // binary numbers are supported, thus 64 (bits) + 1 (string terminating zero)
51 #define POCO_MAX_INT_STRING_LEN 65
52 // value from strtod.cc (double_conversion::kMaxSignificantDecimalDigits)
53 #define POCO_MAX_FLT_STRING_LEN 780
54
55 #define POCO_FLT_INF "inf"
56 #define POCO_FLT_NAN "nan"
57 #define POCO_FLT_EXP 'e'
58
59
60 namespace Poco {
61
62
63 namespace Impl {
64
65 template<bool SIGNED, typename T>
66 class IsNegativeImpl;
67
68 template<typename T>
69 class IsNegativeImpl<true, T>
70 {
71 public:
operator()72 bool operator()(T x) { return x < 0; }
73 };
74
75 template<typename T>
76 class IsNegativeImpl<false, T>
77 {
78 public:
operator()79 bool operator()(T) { return false; }
80 };
81
82 }
83
84
85 template<typename T>
isNegative(T x)86 inline bool isNegative(T x)
87 {
88 using namespace Impl;
89 return IsNegativeImpl<std::numeric_limits<T>::is_signed, T>()(x);
90 }
91
92
93 template<typename To, typename From>
isIntOverflow(From val)94 inline bool isIntOverflow(From val)
95 {
96 poco_assert_dbg (std::numeric_limits<From>::is_integer);
97 poco_assert_dbg (std::numeric_limits<To>::is_integer);
98 bool ret;
99 if (std::numeric_limits<To>::is_signed)
100 {
101 ret = (!std::numeric_limits<From>::is_signed &&
102 (uintmax_t)val > (uintmax_t)INTMAX_MAX) ||
103 (intmax_t)val < (intmax_t)std::numeric_limits<To>::min() ||
104 (intmax_t)val > (intmax_t)std::numeric_limits<To>::max();
105 }
106 else
107 {
108 ret = isNegative(val) ||
109 (uintmax_t)val > (uintmax_t)std::numeric_limits<To>::max();
110 }
111 return ret;
112 }
113
114
115 template <typename F, typename T>
isSafeIntCast(F from)116 inline T& isSafeIntCast(F from)
117 /// Returns true if it is safe to cast
118 /// integer from F to T.
119 {
120 if (!isIntOverflow<T, F>(from)) return true;
121 return false;
122 }
123
124
125 template <typename F, typename T>
safeIntCast(F from,T & to)126 inline T& safeIntCast(F from, T& to)
127 /// Returns csted value if it is safe
128 /// to cast integer from F to T,
129 /// otherwise throws BadCastException.
130 {
131 if (!isIntOverflow<T, F>(from))
132 {
133 to = static_cast<T>(from);
134 return to;
135 }
136 throw BadCastException("safeIntCast: Integer overflow");
137 }
138
decimalSeparator()139 inline char decimalSeparator()
140 /// Returns decimal separator from global locale or
141 /// default '.' for platforms where locale is unavailable.
142 {
143 #if !defined(POCO_NO_LOCALE)
144 return std::use_facet<std::numpunct<char>>(std::locale()).decimal_point();
145 #else
146 return '.';
147 #endif
148 }
149
150
thousandSeparator()151 inline char thousandSeparator()
152 /// Returns thousand separator from global locale or
153 /// default ',' for platforms where locale is unavailable.
154 {
155 #if !defined(POCO_NO_LOCALE)
156 return std::use_facet<std::numpunct<char>>(std::locale()).thousands_sep();
157 #else
158 return ',';
159 #endif
160 }
161
162
163 //
164 // String to Number Conversions
165 //
166
167 template <typename I>
168 bool strToInt(const char* pStr, I& outResult, short base, char thSep = ',')
169 /// Converts zero-terminated character array to integer number;
170 /// Thousand separators are recognized for base10 and current locale;
171 /// they are silently skipped and not verified for correct positioning.
172 /// It is not allowed to convert a negative number to unsigned integer.
173 ///
174 /// Function returns true if successful. If parsing was unsuccessful,
175 /// the return value is false with the result value undetermined.
176 {
177 poco_assert_dbg (base == 2 || base == 8 || base == 10 || base == 16);
178
179 if (!pStr) return false;
180 while (std::isspace(*pStr)) ++pStr;
181 if (*pStr == '\0') return false;
182 bool negative = false;
183 if ((base == 10) && (*pStr == '-'))
184 {
185 if (!std::numeric_limits<I>::is_signed) return false;
186 negative = true;
187 ++pStr;
188 }
189 else if (*pStr == '+') ++pStr;
190
191 // all numbers are parsed as positive; the sign
192 // for negative numbers is adjusted after parsing
193 uintmax_t limitCheck = std::numeric_limits<I>::max();
194 if (negative)
195 {
196 poco_assert_dbg(std::numeric_limits<I>::is_signed);
197 // to cover the entire range, (-min > max) has to be
198 // taken into account;
199 // to avoid overflow for the largest int size,
200 // we resort to FPEnvironment::copySign() (ie. floating-point)
201 if (sizeof(I) == sizeof(intmax_t))
202 limitCheck = static_cast<uintmax_t>(FPEnvironment::copySign(static_cast<double>(std::numeric_limits<I>::min()), 1));
203 else
204 {
205 intmax_t i = std::numeric_limits<I>::min();
206 limitCheck = -i;
207 }
208 }
209
210 uintmax_t result = 0;
211 for (; *pStr != '\0'; ++pStr)
212 {
213 if (result > (limitCheck / base)) return false;
214 switch (*pStr)
215 {
216 case '0': case '1': case '2': case '3':
217 case '4': case '5': case '6': case '7':
218 {
219 char add = (*pStr - '0');
220 if ((limitCheck - result) < add) return false;
221 result = result * base + add;
222 }
223 break;
224
225 case '8': case '9':
226 if ((base == 10) || (base == 0x10))
227 {
228 char add = (*pStr - '0');
229 if ((limitCheck - result) < add) return false;
230 result = result * base + add;
231 }
232 else return false;
233
234 break;
235
236 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
237 {
238 if (base != 0x10) return false;
239 char add = (*pStr - 'a');
240 if ((limitCheck - result) < add) return false;
241 result = result * base + (10 + add);
242 }
243 break;
244
245 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
246 {
247 if (base != 0x10) return false;
248 char add = (*pStr - 'A');
249 if ((limitCheck - result) < add) return false;
250 result = result * base + (10 + add);
251 }
252 break;
253
254 case '.':
255 if ((base == 10) && (thSep == '.')) break;
256 else return false;
257
258 case ',':
259 if ((base == 10) && (thSep == ',')) break;
260 else return false;
261
262 case ' ':
263 if ((base == 10) && (thSep == ' ')) break;
264
265 default:
266 return false;
267 }
268 }
269
270 if (negative && (base == 10))
271 {
272 poco_assert_dbg(std::numeric_limits<I>::is_signed);
273 intmax_t i;
274 if (sizeof(I) == sizeof(intmax_t))
275 i = static_cast<intmax_t>(FPEnvironment::copySign(static_cast<double>(result), -1));
276 else
277 i = static_cast<intmax_t>(-result);
278 if (isIntOverflow<I>(i)) return false;
279 outResult = static_cast<I>(i);
280 }
281 else
282 {
283 if (isIntOverflow<I>(result)) return false;
284 outResult = static_cast<I>(result);
285 }
286
287 return true;
288 }
289
290
291 template <typename I>
292 bool strToInt(const std::string& str, I& result, short base, char thSep = ',')
293 /// Converts string to integer number;
294 /// This is a wrapper function, for details see see the
295 /// bool strToInt(const char*, I&, short, char) implementation.
296 {
297 return strToInt(str.c_str(), result, base, thSep);
298 }
299
300
301 //
302 // Number to String Conversions
303 //
304
305 namespace Impl {
306
307 class Ptr
308 /// Utility char pointer wrapper class.
309 /// Class ensures increment/decrement remain within boundaries.
310 {
311 public:
Ptr(char * ptr,std::size_t offset)312 Ptr(char* ptr, std::size_t offset): _beg(ptr), _cur(ptr), _end(ptr + offset)
313 {
314 }
315
316 char*& operator ++ () // prefix
317 {
318 checkBounds(_cur + 1);
319 return ++_cur;
320 }
321
322 char* operator ++ (int) // postfix
323 {
324 checkBounds(_cur + 1);
325 char* tmp = _cur++;
326 return tmp;
327 }
328
329 char*& operator -- () // prefix
330 {
331 checkBounds(_cur - 1);
332 return --_cur;
333 }
334
335 char* operator -- (int) // postfix
336 {
337 checkBounds(_cur - 1);
338 char* tmp = _cur--;
339 return tmp;
340 }
341
342 char*& operator += (int incr)
343 {
344 checkBounds(_cur + incr);
345 return _cur += incr;
346 }
347
348 char*& operator -= (int decr)
349 {
350 checkBounds(_cur - decr);
351 return _cur -= decr;
352 }
353
354 operator char* () const
355 {
356 return _cur;
357 }
358
span()359 std::size_t span() const
360 {
361 return _end - _beg;
362 }
363
364 private:
checkBounds(char * ptr)365 void checkBounds(char* ptr)
366 {
367 if (ptr > _end) throw RangeException();
368 }
369
370 const char* _beg;
371 char* _cur;
372 const char* _end;
373 };
374
375 } // namespace Impl
376
377
378 template <typename T>
379 bool intToStr(T value,
380 unsigned short base,
381 char* result,
382 std::size_t& size,
383 bool prefix = false,
384 int width = -1,
385 char fill = ' ',
386 char thSep = 0)
387 /// Converts integer to string. Numeric bases from binary to hexadecimal are supported.
388 /// If width is non-zero, it pads the return value with fill character to the specified width.
389 /// When padding is zero character ('0'), it is prepended to the number itself; all other
390 /// paddings are prepended to the formatted result with minus sign or base prefix included
391 /// If prefix is true and base is octal or hexadecimal, respective prefix ('0' for octal,
392 /// "0x" for hexadecimal) is prepended. For all other bases, prefix argument is ignored.
393 /// Formatted string has at least [width] total length.
394 {
395 if (base < 2 || base > 0x10)
396 {
397 *result = '\0';
398 return false;
399 }
400
401 Impl::Ptr ptr(result, size);
402 int thCount = 0;
403 T tmpVal;
404 do
405 {
406 tmpVal = value;
407 value /= base;
408 *ptr++ = "FEDCBA9876543210123456789ABCDEF"[15 + (tmpVal - value * base)];
409 if (thSep && (base == 10) && (++thCount == 3))
410 {
411 *ptr++ = thSep;
412 thCount = 0;
413 }
414 } while (value);
415
416 if ('0' == fill)
417 {
418 if (tmpVal < 0) --width;
419 if (prefix && base == 010) --width;
420 if (prefix && base == 0x10) width -= 2;
421 while ((ptr - result) < width) *ptr++ = fill;
422 }
423
424 if (prefix && base == 010) *ptr++ = '0';
425 else if (prefix && base == 0x10)
426 {
427 *ptr++ = 'x';
428 *ptr++ = '0';
429 }
430
431 if (tmpVal < 0) *ptr++ = '-';
432
433 if ('0' != fill)
434 {
435 while ((ptr - result) < width) *ptr++ = fill;
436 }
437
438 size = ptr - result;
439 poco_assert_dbg (size <= ptr.span());
440 poco_assert_dbg ((-1 == width) || (size >= size_t(width)));
441 *ptr-- = '\0';
442
443 char* ptrr = result;
444 char tmp;
445 while(ptrr < ptr)
446 {
447 tmp = *ptr;
448 *ptr-- = *ptrr;
449 *ptrr++ = tmp;
450 }
451
452 return true;
453 }
454
455
456 template <typename T>
457 bool uIntToStr(T value,
458 unsigned short base,
459 char* result,
460 std::size_t& size,
461 bool prefix = false,
462 int width = -1,
463 char fill = ' ',
464 char thSep = 0)
465 /// Converts unsigned integer to string. Numeric bases from binary to hexadecimal are supported.
466 /// If width is non-zero, it pads the return value with fill character to the specified width.
467 /// When padding is zero character ('0'), it is prepended to the number itself; all other
468 /// paddings are prepended to the formatted result with minus sign or base prefix included
469 /// If prefix is true and base is octal or hexadecimal, respective prefix ('0' for octal,
470 /// "0x" for hexadecimal) is prepended. For all other bases, prefix argument is ignored.
471 /// Formatted string has at least [width] total length.
472 {
473 if (base < 2 || base > 0x10)
474 {
475 *result = '\0';
476 return false;
477 }
478
479 Impl::Ptr ptr(result, size);
480 int thCount = 0;
481 T tmpVal;
482 do
483 {
484 tmpVal = value;
485 value /= base;
486 *ptr++ = "FEDCBA9876543210123456789ABCDEF"[15 + (tmpVal - value * base)];
487 if (thSep && (base == 10) && (++thCount == 3))
488 {
489 *ptr++ = thSep;
490 thCount = 0;
491 }
492 } while (value);
493
494 if ('0' == fill)
495 {
496 if (prefix && base == 010) --width;
497 if (prefix && base == 0x10) width -= 2;
498 while ((ptr - result) < width) *ptr++ = fill;
499 }
500
501 if (prefix && base == 010) *ptr++ = '0';
502 else if (prefix && base == 0x10)
503 {
504 *ptr++ = 'x';
505 *ptr++ = '0';
506 }
507
508 if ('0' != fill)
509 {
510 while ((ptr - result) < width) *ptr++ = fill;
511 }
512
513 size = ptr - result;
514 poco_assert_dbg (size <= ptr.span());
515 poco_assert_dbg ((-1 == width) || (size >= size_t(width)));
516 *ptr-- = '\0';
517
518 char* ptrr = result;
519 char tmp;
520 while(ptrr < ptr)
521 {
522 tmp = *ptr;
523 *ptr-- = *ptrr;
524 *ptrr++ = tmp;
525 }
526
527 return true;
528 }
529
530
531 template <typename T>
532 bool intToStr (T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0)
533 /// Converts integer to string; This is a wrapper function, for details see see the
534 /// bool intToStr(T, unsigned short, char*, int, int, char, char) implementation.
535 {
536 char res[POCO_MAX_INT_STRING_LEN] = {0};
537 std::size_t size = POCO_MAX_INT_STRING_LEN;
538 bool ret = intToStr(number, base, res, size, prefix, width, fill, thSep);
539 result.assign(res, size);
540 return ret;
541 }
542
543
544 template <typename T>
545 bool uIntToStr (T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0)
546 /// Converts unsigned integer to string; This is a wrapper function, for details see see the
547 /// bool uIntToStr(T, unsigned short, char*, int, int, char, char) implementation.
548 {
549 char res[POCO_MAX_INT_STRING_LEN] = {0};
550 std::size_t size = POCO_MAX_INT_STRING_LEN;
551 bool ret = uIntToStr(number, base, res, size, prefix, width, fill, thSep);
552 result.assign(res, size);
553 return ret;
554 }
555
556
557 //
558 // Wrappers for double-conversion library (http://code.google.com/p/double-conversion/).
559 //
560 // Library is the implementation of the algorithm described in Florian Loitsch's paper:
561 // http://florian.loitsch.com/publications/dtoa-pldi2010.pdf
562 //
563
564
565 Foundation_API void floatToStr(char* buffer,
566 int bufferSize,
567 float value,
568 int lowDec = -std::numeric_limits<float>::digits10,
569 int highDec = std::numeric_limits<float>::digits10);
570 /// Converts a float value to string. Converted string must be shorter than bufferSize.
571 /// Conversion is done by computing the shortest string of digits that correctly represents
572 /// the input number. Depending on lowDec and highDec values, the function returns
573 /// decimal or exponential representation.
574
575 Foundation_API void floatToFixedStr(char* buffer,
576 int bufferSize,
577 float value,
578 int precision);
579 /// Converts a float value to string. Converted string must be shorter than bufferSize.
580 /// Computes a decimal representation with a fixed number of digits after the
581 /// decimal point.
582
583
584 Foundation_API std::string& floatToStr(std::string& str,
585 float value,
586 int precision = -1,
587 int width = 0,
588 char thSep = 0,
589 char decSep = 0);
590 /// Converts a float value, assigns it to the supplied string and returns the reference.
591 /// This function calls floatToStr(char*, int, float, int, int) and formats the result according to
592 /// precision (total number of digits after the decimal point, -1 means ignore precision argument)
593 /// and width (total length of formatted string).
594
595
596 Foundation_API std::string& floatToFixedStr(std::string& str,
597 float value,
598 int precision,
599 int width = 0,
600 char thSep = 0,
601 char decSep = 0);
602 /// Converts a float value, assigns it to the supplied string and returns the reference.
603 /// This function calls floatToFixedStr(char*, int, float, int) and formats the result according to
604 /// precision (total number of digits after the decimal point) and width (total length of formatted string).
605
606
607 Foundation_API void doubleToStr(char* buffer,
608 int bufferSize,
609 double value,
610 int lowDec = -std::numeric_limits<double>::digits10,
611 int highDec = std::numeric_limits<double>::digits10);
612 /// Converts a double value to string. Converted string must be shorter than bufferSize.
613 /// Conversion is done by computing the shortest string of digits that correctly represents
614 /// the input number. Depending on lowDec and highDec values, the function returns
615 /// decimal or exponential representation.
616
617
618 Foundation_API void doubleToFixedStr(char* buffer,
619 int bufferSize,
620 double value,
621 int precision);
622 /// Converts a double value to string. Converted string must be shorter than bufferSize.
623 /// Computes a decimal representation with a fixed number of digits after the
624 /// decimal point.
625
626
627 Foundation_API std::string& doubleToStr(std::string& str,
628 double value,
629 int precision = -1,
630 int width = 0,
631 char thSep = 0,
632 char decSep = 0);
633 /// Converts a double value, assigns it to the supplied string and returns the reference.
634 /// This function calls doubleToStr(char*, int, double, int, int) and formats the result according to
635 /// precision (total number of digits after the decimal point, -1 means ignore precision argument)
636 /// and width (total length of formatted string).
637
638
639 Foundation_API std::string& doubleToFixedStr(std::string& str,
640 double value,
641 int precision = -1,
642 int width = 0,
643 char thSep = 0,
644 char decSep = 0);
645 /// Converts a double value, assigns it to the supplied string and returns the reference.
646 /// This function calls doubleToFixedStr(char*, int, double, int) and formats the result according to
647 /// precision (total number of digits after the decimal point) and width (total length of formatted string).
648
649
650 Foundation_API float strToFloat(const char* str,
651 const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
652 /// Converts the string of characters into single-precision floating point number.
653 /// Function uses double_conversion::DoubleToStringConverter to do the conversion.
654
655
656 Foundation_API bool strToFloat(const std::string&, float& result,
657 char decSep = '.', char thSep = ',',
658 const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
659 /// Converts the string of characters into single-precision floating point number.
660 /// The conversion result is assigned to the result parameter.
661 /// If decimal separator and/or thousand separator are different from defaults, they should be
662 /// supplied to ensure proper conversion.
663 ///
664 /// Returns true if successful, false otherwise.
665
666
667 Foundation_API double strToDouble(const char* str,
668 const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
669 /// Converts the string of characters into double-precision floating point number.
670
671
672 Foundation_API bool strToDouble(const std::string& str, double& result,
673 char decSep = '.', char thSep = ',',
674 const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
675 /// Converts the string of characters into double-precision floating point number.
676 /// The conversion result is assigned to the result parameter.
677 /// If decimal separator and/or thousand separator are different from defaults, they should be
678 /// supplied to ensure proper conversion.
679 ///
680 /// Returns true if successful, false otherwise.
681
682
683 } // namespace Poco
684
685
686 #ifdef POCO_COMPILER_MSVC
687 #pragma warning(pop)
688 #endif // POCO_COMPILER_MSVC
689
690
691 #endif // Foundation_NumericString_INCLUDED
692