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