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