123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- //
- // NumericString.h
- //
- // Library: Foundation
- // Package: Core
- // Module: NumericString
- //
- // Numeric string utility functions.
- //
- // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
- // and Contributors.
- //
- // SPDX-License-Identifier: BSL-1.0
- //
- #ifndef Foundation_NumericString_INCLUDED
- #define Foundation_NumericString_INCLUDED
- #include "Poco/Foundation.h"
- #include "Poco/Buffer.h"
- #include "Poco/FPEnvironment.h"
- #ifdef min
- #undef min
- #endif
- #ifdef max
- #undef max
- #endif
- #include <limits>
- #include <cmath>
- #include <cctype>
- #if !defined(POCO_NO_LOCALE)
- #include <locale>
- #endif
- // binary numbers are supported, thus 64 (bits) + 1 (string terminating zero)
- #define POCO_MAX_INT_STRING_LEN 65
- // value from strtod.cc (double_conversion::kMaxSignificantDecimalDigits)
- #define POCO_MAX_FLT_STRING_LEN 780
- #define POCO_FLT_INF "inf"
- #define POCO_FLT_NAN "nan"
- #define POCO_FLT_EXP 'e'
- namespace Poco {
- inline char decimalSeparator()
- /// Returns decimal separator from global locale or
- /// default '.' for platforms where locale is unavailable.
- {
- #if !defined(POCO_NO_LOCALE)
- return std::use_facet<std::numpunct<char> >(std::locale()).decimal_point();
- #else
- return '.';
- #endif
- }
- inline char thousandSeparator()
- /// Returns thousand separator from global locale or
- /// default ',' for platforms where locale is unavailable.
- {
- #if !defined(POCO_NO_LOCALE)
- return std::use_facet<std::numpunct<char> >(std::locale()).thousands_sep();
- #else
- return ',';
- #endif
- }
- //
- // String to Number Conversions
- //
- template <typename I>
- bool strToInt(const char* pStr, I& result, short base, char thSep = ',')
- /// Converts zero-terminated character array to integer number;
- /// Thousand separators are recognized for base10 and current locale;
- /// it is silently skipped but not verified for correct positioning.
- /// Function returns true if successful. If parsing was unsuccessful,
- /// the return value is false with the result value undetermined.
- {
- if (!pStr) return false;
- while (std::isspace(*pStr)) ++pStr;
- if (*pStr == '\0') return false;
- short sign = 1;
- if ((base == 10) && (*pStr == '-'))
- {
- // Unsigned types can't be negative so abort parsing
- if (std::numeric_limits<I>::min() >= 0) return false;
- sign = -1;
- ++pStr;
- }
- else if (*pStr == '+') ++pStr;
- // parser states:
- const char STATE_SIGNIFICANT_DIGITS = 1;
- char state = 0;
-
- result = 0;
- I limitCheck = std::numeric_limits<I>::max() / base;
- for (; *pStr != '\0'; ++pStr)
- {
- switch (*pStr)
- {
- case '0':
- if (state < STATE_SIGNIFICANT_DIGITS) break;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7':
- if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
- if (result > limitCheck) return false;
- result = result * base + (*pStr - '0');
- break;
- case '8': case '9':
- if ((base == 10) || (base == 0x10))
- {
- if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
- if (result > limitCheck) return false;
- result = result * base + (*pStr - '0');
- }
- else return false;
- break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- if (base != 0x10) return false;
- if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
- if (result > limitCheck) return false;
- result = result * base + (10 + *pStr - 'a');
- break;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- if (base != 0x10) return false;
- if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
- if (result > limitCheck) return false;
- result = result * base + (10 + *pStr - 'A');
- break;
- case '.':
- if ((base == 10) && (thSep == '.')) break;
- else return false;
- case ',':
- if ((base == 10) && (thSep == ',')) break;
- else return false;
- case ' ':
- if ((base == 10) && (thSep == ' ')) break;
- // fallthrough
- default:
- return false;
- }
- }
- if ((sign < 0) && (base == 10)) result *= sign;
- return true;
- }
- template <typename I>
- bool strToInt(const std::string& str, I& result, short base, char thSep = ',')
- /// Converts string to integer number;
- /// This is a wrapper function, for details see see the
- /// bool strToInt(const char*, I&, short, char) implementation.
- {
- return strToInt(str.c_str(), result, base, thSep);
- }
- //
- // Number to String Conversions
- //
- namespace Impl {
- class Ptr
- /// Utility char pointer wrapper class.
- /// Class ensures increment/decrement remain within boundaries.
- {
- public:
- Ptr(char* ptr, std::size_t offset): _beg(ptr), _cur(ptr), _end(ptr + offset)
- {
- }
-
- char*& operator ++ () // prefix
- {
- checkBounds(_cur + 1);
- return ++_cur;
- }
- char* operator ++ (int) // postfix
- {
- checkBounds(_cur + 1);
- char* tmp = _cur++;
- return tmp;
- }
-
- char*& operator -- () // prefix
- {
- checkBounds(_cur - 1);
- return --_cur;
- }
- char* operator -- (int) // postfix
- {
- checkBounds(_cur - 1);
- char* tmp = _cur--;
- return tmp;
- }
- char*& operator += (int incr)
- {
- checkBounds(_cur + incr);
- return _cur += incr;
- }
- char*& operator -= (int decr)
- {
- checkBounds(_cur - decr);
- return _cur -= decr;
- }
- operator char* () const
- {
- return _cur;
- }
- std::size_t span() const
- {
- return _end - _beg;
- }
- private:
- void checkBounds(char* ptr)
- {
- if (ptr > _end) throw RangeException();
- }
- const char* _beg;
- char* _cur;
- const char* _end;
- };
- } // namespace Impl
- template <typename T>
- bool intToStr(T value,
- unsigned short base,
- char* result,
- std::size_t& size,
- bool prefix = false,
- int width = -1,
- char fill = ' ',
- char thSep = 0)
- /// Converts integer to string. Numeric bases from binary to hexadecimal are supported.
- /// If width is non-zero, it pads the return value with fill character to the specified width.
- /// When padding is zero character ('0'), it is prepended to the number itself; all other
- /// paddings are prepended to the formatted result with minus sign or base prefix included
- /// If prefix is true and base is octal or hexadecimal, respective prefix ('0' for octal,
- /// "0x" for hexadecimal) is prepended. For all other bases, prefix argument is ignored.
- /// Formatted string has at least [width] total length.
- {
- if (base < 2 || base > 0x10)
- {
- *result = '\0';
- return false;
- }
- Impl::Ptr ptr(result, size);
- int thCount = 0;
- T tmpVal;
- do
- {
- tmpVal = value;
- value /= base;
- *ptr++ = "FEDCBA9876543210123456789ABCDEF"[15 + (tmpVal - value * base)];
- if (thSep && (base == 10) && (++thCount == 3))
- {
- *ptr++ = thSep;
- thCount = 0;
- }
- } while (value);
- if ('0' == fill)
- {
- if (tmpVal < 0) --width;
- if (prefix && base == 010) --width;
- if (prefix && base == 0x10) width -= 2;
- while ((ptr - result) < width) *ptr++ = fill;
- }
- if (prefix && base == 010) *ptr++ = '0';
- else if (prefix && base == 0x10)
- {
- *ptr++ = 'x';
- *ptr++ = '0';
- }
- if (tmpVal < 0) *ptr++ = '-';
- if ('0' != fill)
- {
- while ((ptr - result) < width) *ptr++ = fill;
- }
- size = ptr - result;
- poco_assert_dbg (size <= ptr.span());
- poco_assert_dbg ((-1 == width) || (size >= std::size_t(width)));
- *ptr-- = '\0';
- char* ptrr = result;
- char tmp;
- while(ptrr < ptr)
- {
- tmp = *ptr;
- *ptr-- = *ptrr;
- *ptrr++ = tmp;
- }
- return true;
- }
- template <typename T>
- bool uIntToStr(T value,
- unsigned short base,
- char* result,
- std::size_t& size,
- bool prefix = false,
- int width = -1,
- char fill = ' ',
- char thSep = 0)
- /// Converts unsigned integer to string. Numeric bases from binary to hexadecimal are supported.
- /// If width is non-zero, it pads the return value with fill character to the specified width.
- /// When padding is zero character ('0'), it is prepended to the number itself; all other
- /// paddings are prepended to the formatted result with minus sign or base prefix included
- /// If prefix is true and base is octal or hexadecimal, respective prefix ('0' for octal,
- /// "0x" for hexadecimal) is prepended. For all other bases, prefix argument is ignored.
- /// Formatted string has at least [width] total length.
- {
- if (base < 2 || base > 0x10)
- {
- *result = '\0';
- return false;
- }
-
- Impl::Ptr ptr(result, size);
- int thCount = 0;
- T tmpVal;
- do
- {
- tmpVal = value;
- value /= base;
- *ptr++ = "FEDCBA9876543210123456789ABCDEF"[15 + (tmpVal - value * base)];
- if (thSep && (base == 10) && (++thCount == 3))
- {
- *ptr++ = thSep;
- thCount = 0;
- }
- } while (value);
-
- if ('0' == fill)
- {
- if (prefix && base == 010) --width;
- if (prefix && base == 0x10) width -= 2;
- while ((ptr - result) < width) *ptr++ = fill;
- }
-
- if (prefix && base == 010) *ptr++ = '0';
- else if (prefix && base == 0x10)
- {
- *ptr++ = 'x';
- *ptr++ = '0';
- }
-
- if ('0' != fill)
- {
- while ((ptr - result) < width) *ptr++ = fill;
- }
-
- size = ptr - result;
- poco_assert_dbg (size <= ptr.span());
- poco_assert_dbg ((-1 == width) || (size >= std::size_t(width)));
- *ptr-- = '\0';
-
- char* ptrr = result;
- char tmp;
- while(ptrr < ptr)
- {
- tmp = *ptr;
- *ptr-- = *ptrr;
- *ptrr++ = tmp;
- }
-
- return true;
- }
- template <typename T>
- bool intToStr (T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0)
- /// Converts integer to string; This is a wrapper function, for details see see the
- /// bool intToStr(T, unsigned short, char*, int, int, char, char) implementation.
- {
- char res[POCO_MAX_INT_STRING_LEN] = {0};
- std::size_t size = POCO_MAX_INT_STRING_LEN;
- bool ret = intToStr(number, base, res, size, prefix, width, fill, thSep);
- result.assign(res, size);
- return ret;
- }
-
-
- template <typename T>
- bool uIntToStr (T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0)
- /// Converts unsigned integer to string; This is a wrapper function, for details see see the
- /// bool uIntToStr(T, unsigned short, char*, int, int, char, char) implementation.
- {
- char res[POCO_MAX_INT_STRING_LEN] = {0};
- std::size_t size = POCO_MAX_INT_STRING_LEN;
- bool ret = uIntToStr(number, base, res, size, prefix, width, fill, thSep);
- result.assign(res, size);
- return ret;
- }
- //
- // Wrappers for double-conversion library (http://code.google.com/p/double-conversion/).
- //
- // Library is the implementation of the algorithm described in Florian Loitsch's paper:
- // http://florian.loitsch.com/publications/dtoa-pldi2010.pdf
- //
- Foundation_API void floatToStr(char* buffer,
- int bufferSize,
- float value,
- int lowDec = -std::numeric_limits<float>::digits10,
- int highDec = std::numeric_limits<float>::digits10);
- /// Converts a float value to string. Converted string must be shorter than bufferSize.
- /// Conversion is done by computing the shortest string of digits that correctly represents
- /// the input number. Depending on lowDec and highDec values, the function returns
- /// decimal or exponential representation.
- Foundation_API void floatToFixedStr(char* buffer,
- int bufferSize,
- float value,
- int precision);
- /// Converts a float value to string. Converted string must be shorter than bufferSize.
- /// Computes a decimal representation with a fixed number of digits after the
- /// decimal point.
- Foundation_API std::string& floatToStr(std::string& str,
- float value,
- int precision = -1,
- int width = 0,
- char thSep = 0,
- char decSep = 0);
- /// Converts a float value, assigns it to the supplied string and returns the reference.
- /// This function calls floatToStr(char*, int, float, int, int) and formats the result according to
- /// precision (total number of digits after the decimal point, -1 means ignore precision argument)
- /// and width (total length of formatted string).
- Foundation_API std::string& floatToFixedStr(std::string& str,
- float value,
- int precision,
- int width = 0,
- char thSep = 0,
- char decSep = 0);
- /// Converts a float value, assigns it to the supplied string and returns the reference.
- /// This function calls floatToFixedStr(char*, int, float, int) and formats the result according to
- /// precision (total number of digits after the decimal point) and width (total length of formatted string).
- Foundation_API void doubleToStr(char* buffer,
- int bufferSize,
- double value,
- int lowDec = -std::numeric_limits<double>::digits10,
- int highDec = std::numeric_limits<double>::digits10);
- /// Converts a double value to string. Converted string must be shorter than bufferSize.
- /// Conversion is done by computing the shortest string of digits that correctly represents
- /// the input number. Depending on lowDec and highDec values, the function returns
- /// decimal or exponential representation.
- Foundation_API void doubleToFixedStr(char* buffer,
- int bufferSize,
- double value,
- int precision);
- /// Converts a double value to string. Converted string must be shorter than bufferSize.
- /// Computes a decimal representation with a fixed number of digits after the
- /// decimal point.
- Foundation_API std::string& doubleToStr(std::string& str,
- double value,
- int precision = -1,
- int width = 0,
- char thSep = 0,
- char decSep = 0);
- /// Converts a double value, assigns it to the supplied string and returns the reference.
- /// This function calls doubleToStr(char*, int, double, int, int) and formats the result according to
- /// precision (total number of digits after the decimal point, -1 means ignore precision argument)
- /// and width (total length of formatted string).
- Foundation_API std::string& doubleToFixedStr(std::string& str,
- double value,
- int precision = -1,
- int width = 0,
- char thSep = 0,
- char decSep = 0);
- /// Converts a double value, assigns it to the supplied string and returns the reference.
- /// This function calls doubleToFixedStr(char*, int, double, int) and formats the result according to
- /// precision (total number of digits after the decimal point) and width (total length of formatted string).
- Foundation_API float strToFloat(const char* str);
- /// Converts the string of characters into single-precision floating point number.
- /// Function uses double_convesrion::DoubleToStringConverter to do the conversion.
- Foundation_API bool strToFloat(const std::string&, float& result, char decSep = '.', char thSep = ',');
- /// Converts the string of characters into single-precision floating point number.
- /// The conversion result is assigned to the result parameter.
- /// If decimal separator and/or thousand separator are different from defaults, they should be
- /// supplied to ensure proper conversion.
- ///
- /// Returns true if successful, false otherwise.
- Foundation_API double strToDouble(const char* str);
- /// Converts the string of characters into double-precision floating point number.
- Foundation_API bool strToDouble(const std::string& str, double& result, char decSep = '.', char thSep = ',');
- /// Converts the string of characters into double-precision floating point number.
- /// The conversion result is assigned to the result parameter.
- /// If decimal separator and/or thousand separator are different from defaults, they should be
- /// supplied to ensure proper conversion.
- ///
- /// Returns true if successful, false otherwise.
- } // namespace Poco
- #endif // Foundation_NumericString_INCLUDED
|