mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-16 18:56:52 +02:00
backport NumericString from develop (fixes #2250)
This commit is contained in:
@@ -69,16 +69,16 @@ protected:
|
|||||||
FPEnvironmentImpl& operator = (const FPEnvironmentImpl& env);
|
FPEnvironmentImpl& operator = (const FPEnvironmentImpl& env);
|
||||||
void keepCurrentImpl();
|
void keepCurrentImpl();
|
||||||
static void clearFlagsImpl();
|
static void clearFlagsImpl();
|
||||||
static bool isFlagImpl(FlagImpl flag);
|
static bool isFlagImpl(FlagImpl flag);
|
||||||
static void setRoundingModeImpl(RoundingModeImpl mode);
|
static void setRoundingModeImpl(RoundingModeImpl mode);
|
||||||
static RoundingModeImpl getRoundingModeImpl();
|
static RoundingModeImpl getRoundingModeImpl();
|
||||||
static bool isInfiniteImpl(float value);
|
static bool isInfiniteImpl(float value);
|
||||||
static bool isInfiniteImpl(double value);
|
static bool isInfiniteImpl(double value);
|
||||||
static bool isInfiniteImpl(long double value);
|
static bool isInfiniteImpl(long double value);
|
||||||
static bool isNaNImpl(float value);
|
static bool isNaNImpl(float value);
|
||||||
static bool isNaNImpl(double value);
|
static bool isNaNImpl(double value);
|
||||||
static bool isNaNImpl(long double value);
|
static bool isNaNImpl(long double value);
|
||||||
static float copySignImpl(float target, float source);
|
static float copySignImpl(float target, float source);
|
||||||
static double copySignImpl(double target, double source);
|
static double copySignImpl(double target, double source);
|
||||||
static long double copySignImpl(long double target, long double source);
|
static long double copySignImpl(long double target, long double source);
|
||||||
|
|
||||||
|
@@ -34,6 +34,20 @@
|
|||||||
#include <locale>
|
#include <locale>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef uintmax_t
|
||||||
|
typedef Poco::UInt64 uintmax_t;
|
||||||
|
#endif
|
||||||
|
#ifndef intmax_t
|
||||||
|
typedef Poco::Int64 intmax_t;
|
||||||
|
#endif
|
||||||
|
#if !defined (INTMAX_MAX)
|
||||||
|
#define INTMAX_MAX std::numeric_limits<intmax_t>::max()
|
||||||
|
#endif
|
||||||
|
#ifdef POCO_COMPILER_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4146)
|
||||||
|
#endif // POCO_COMPILER_MSVC
|
||||||
|
|
||||||
|
|
||||||
// binary numbers are supported, thus 64 (bits) + 1 (string terminating zero)
|
// binary numbers are supported, thus 64 (bits) + 1 (string terminating zero)
|
||||||
#define POCO_MAX_INT_STRING_LEN 65
|
#define POCO_MAX_INT_STRING_LEN 65
|
||||||
@@ -48,6 +62,82 @@
|
|||||||
namespace Poco {
|
namespace Poco {
|
||||||
|
|
||||||
|
|
||||||
|
namespace Impl {
|
||||||
|
|
||||||
|
template<bool SIGNED, typename T>
|
||||||
|
class IsNegativeImpl;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class IsNegativeImpl<true, T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool operator()(T x) { return x < 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class IsNegativeImpl<false, T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool operator()(T) { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline bool isNegative(T x)
|
||||||
|
{
|
||||||
|
using namespace Impl;
|
||||||
|
return IsNegativeImpl<std::numeric_limits<T>::is_signed, T>()(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename To, typename From>
|
||||||
|
inline bool isIntOverflow(From val)
|
||||||
|
{
|
||||||
|
poco_assert_dbg (std::numeric_limits<From>::is_integer);
|
||||||
|
poco_assert_dbg (std::numeric_limits<To>::is_integer);
|
||||||
|
bool ret;
|
||||||
|
if (std::numeric_limits<To>::is_signed)
|
||||||
|
{
|
||||||
|
ret = (!std::numeric_limits<From>::is_signed &&
|
||||||
|
(::uintmax_t)val > (::uintmax_t)INTMAX_MAX) ||
|
||||||
|
(::intmax_t)val < (::intmax_t)std::numeric_limits<To>::min() ||
|
||||||
|
(::intmax_t)val > (::intmax_t)std::numeric_limits<To>::max();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = isNegative(val) ||
|
||||||
|
(::uintmax_t)val > (::uintmax_t)std::numeric_limits<To>::max();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename F, typename T>
|
||||||
|
inline T& isSafeIntCast(F from)
|
||||||
|
/// Returns true if it is safe to cast
|
||||||
|
/// integer from F to T.
|
||||||
|
{
|
||||||
|
if (!isIntOverflow<T, F>(from)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename F, typename T>
|
||||||
|
inline T& safeIntCast(F from, T& to)
|
||||||
|
/// Returns csted value if it is safe
|
||||||
|
/// to cast integer from F to T,
|
||||||
|
/// otherwise throws BadCastException.
|
||||||
|
{
|
||||||
|
if (!isIntOverflow<T, F>(from))
|
||||||
|
{
|
||||||
|
to = static_cast<T>(from);
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
throw BadCastException("safeIntCast: Integer overflow");
|
||||||
|
}
|
||||||
|
|
||||||
inline char decimalSeparator()
|
inline char decimalSeparator()
|
||||||
/// Returns decimal separator from global locale or
|
/// Returns decimal separator from global locale or
|
||||||
/// default '.' for platforms where locale is unavailable.
|
/// default '.' for platforms where locale is unavailable.
|
||||||
@@ -77,72 +167,90 @@ inline char thousandSeparator()
|
|||||||
//
|
//
|
||||||
|
|
||||||
template <typename I>
|
template <typename I>
|
||||||
bool strToInt(const char* pStr, I& result, short base, char thSep = ',')
|
bool strToInt(const char* pStr, I& outResult, short base, char thSep = ',')
|
||||||
/// Converts zero-terminated character array to integer number;
|
/// Converts zero-terminated character array to integer number;
|
||||||
/// Thousand separators are recognized for base10 and current locale;
|
/// Thousand separators are recognized for base10 and current locale;
|
||||||
/// it is silently skipped but not verified for correct positioning.
|
/// they are silently skipped and not verified for correct positioning.
|
||||||
|
/// It is not allowed to convert a negative number to unsigned integer.
|
||||||
|
///
|
||||||
/// Function returns true if successful. If parsing was unsuccessful,
|
/// Function returns true if successful. If parsing was unsuccessful,
|
||||||
/// the return value is false with the result value undetermined.
|
/// the return value is false with the result value undetermined.
|
||||||
{
|
{
|
||||||
|
poco_assert_dbg (base == 2 || base == 8 || base == 10 || base == 16);
|
||||||
|
|
||||||
if (!pStr) return false;
|
if (!pStr) return false;
|
||||||
while (std::isspace(*pStr)) ++pStr;
|
while (std::isspace(*pStr)) ++pStr;
|
||||||
if (*pStr == '\0') return false;
|
if (*pStr == '\0') return false;
|
||||||
short sign = 1;
|
bool negative = false;
|
||||||
if ((base == 10) && (*pStr == '-'))
|
if ((base == 10) && (*pStr == '-'))
|
||||||
{
|
{
|
||||||
// Unsigned types can't be negative so abort parsing
|
if (!std::numeric_limits<I>::is_signed) return false;
|
||||||
if (std::numeric_limits<I>::min() >= 0) return false;
|
negative = true;
|
||||||
sign = -1;
|
|
||||||
++pStr;
|
++pStr;
|
||||||
}
|
}
|
||||||
else if (*pStr == '+') ++pStr;
|
else if (*pStr == '+') ++pStr;
|
||||||
|
|
||||||
// parser states:
|
// all numbers are parsed as positive; the sign
|
||||||
const char STATE_SIGNIFICANT_DIGITS = 1;
|
// for negative numbers is adjusted after parsing
|
||||||
char state = 0;
|
::uintmax_t limitCheck = std::numeric_limits<I>::max();
|
||||||
|
if (negative)
|
||||||
result = 0;
|
{
|
||||||
I limitCheck = std::numeric_limits<I>::max() / base;
|
poco_assert_dbg(std::numeric_limits<I>::is_signed);
|
||||||
|
// to cover the entire range, (-min > max) has to be
|
||||||
|
// taken into account;
|
||||||
|
// to avoid overflow for the largest int size,
|
||||||
|
// we resort to FPEnvironment::copySign() (ie. floating-point)
|
||||||
|
if (sizeof(I) == sizeof(::intmax_t))
|
||||||
|
limitCheck = static_cast<::uintmax_t>(FPEnvironment::copySign(static_cast<double>(std::numeric_limits<I>::min()), 1));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
::intmax_t i = std::numeric_limits<I>::min();
|
||||||
|
limitCheck = -i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::uintmax_t result = 0;
|
||||||
for (; *pStr != '\0'; ++pStr)
|
for (; *pStr != '\0'; ++pStr)
|
||||||
{
|
{
|
||||||
|
if (result > (limitCheck / base)) return false;
|
||||||
switch (*pStr)
|
switch (*pStr)
|
||||||
{
|
{
|
||||||
case '0':
|
case '0': case '1': case '2': case '3':
|
||||||
if (state < STATE_SIGNIFICANT_DIGITS) break;
|
case '4': case '5': case '6': case '7':
|
||||||
|
{
|
||||||
case '1': case '2': case '3': case '4':
|
char add = (*pStr - '0');
|
||||||
case '5': case '6': case '7':
|
if ((limitCheck - result) < add) return false;
|
||||||
if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
|
result = result * base + add;
|
||||||
if (result > limitCheck) return false;
|
}
|
||||||
result = result * base + (*pStr - '0');
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '8': case '9':
|
case '8': case '9':
|
||||||
if ((base == 10) || (base == 0x10))
|
if ((base == 10) || (base == 0x10))
|
||||||
{
|
{
|
||||||
if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
|
char add = (*pStr - '0');
|
||||||
if (result > limitCheck) return false;
|
if ((limitCheck - result) < add) return false;
|
||||||
result = result * base + (*pStr - '0');
|
result = result * base + add;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
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 (base != 0x10) return false;
|
||||||
if (result > limitCheck) return false;
|
char add = (*pStr - 'a');
|
||||||
result = result * base + (10 + *pStr - 'a');
|
if ((limitCheck - result) < add) return false;
|
||||||
|
result = result * base + (10 + add);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
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 (base != 0x10) return false;
|
||||||
if (result > limitCheck) return false;
|
char add = (*pStr - 'A');
|
||||||
result = result * base + (10 + *pStr - 'A');
|
if ((limitCheck - result) < add) return false;
|
||||||
|
result = result * base + (10 + add);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
@@ -155,14 +263,28 @@ bool strToInt(const char* pStr, I& result, short base, char thSep = ',')
|
|||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
if ((base == 10) && (thSep == ' ')) break;
|
if ((base == 10) && (thSep == ' ')) break;
|
||||||
// fallthrough
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sign < 0) && (base == 10)) result *= sign;
|
if (negative && (base == 10))
|
||||||
|
{
|
||||||
|
poco_assert_dbg(std::numeric_limits<I>::is_signed);
|
||||||
|
::intmax_t i;
|
||||||
|
if (sizeof(I) == sizeof(::intmax_t))
|
||||||
|
i = static_cast<::intmax_t>(FPEnvironment::copySign(static_cast<double>(result), -1));
|
||||||
|
else
|
||||||
|
i = static_cast<::intmax_t>(-result);
|
||||||
|
if (isIntOverflow<I>(i)) return false;
|
||||||
|
outResult = static_cast<I>(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isIntOverflow<I>(result)) return false;
|
||||||
|
outResult = static_cast<I>(result);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -268,7 +390,7 @@ bool intToStr(T value,
|
|||||||
/// If width is non-zero, it pads the return value with fill character to the specified width.
|
/// 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
|
/// 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
|
/// 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,
|
/// 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.
|
/// "0x" for hexadecimal) is prepended. For all other bases, prefix argument is ignored.
|
||||||
/// Formatted string has at least [width] total length.
|
/// Formatted string has at least [width] total length.
|
||||||
{
|
{
|
||||||
@@ -317,7 +439,7 @@ bool intToStr(T value,
|
|||||||
|
|
||||||
size = ptr - result;
|
size = ptr - result;
|
||||||
poco_assert_dbg (size <= ptr.span());
|
poco_assert_dbg (size <= ptr.span());
|
||||||
poco_assert_dbg ((-1 == width) || (size >= std::size_t(width)));
|
poco_assert_dbg ((-1 == width) || (size >= size_t(width)));
|
||||||
*ptr-- = '\0';
|
*ptr-- = '\0';
|
||||||
|
|
||||||
char* ptrr = result;
|
char* ptrr = result;
|
||||||
@@ -392,7 +514,7 @@ bool uIntToStr(T value,
|
|||||||
|
|
||||||
size = ptr - result;
|
size = ptr - result;
|
||||||
poco_assert_dbg (size <= ptr.span());
|
poco_assert_dbg (size <= ptr.span());
|
||||||
poco_assert_dbg ((-1 == width) || (size >= std::size_t(width)));
|
poco_assert_dbg ((-1 == width) || (size >= size_t(width)));
|
||||||
*ptr-- = '\0';
|
*ptr-- = '\0';
|
||||||
|
|
||||||
char* ptrr = result;
|
char* ptrr = result;
|
||||||
@@ -469,7 +591,7 @@ Foundation_API std::string& floatToStr(std::string& str,
|
|||||||
char decSep = 0);
|
char decSep = 0);
|
||||||
/// Converts a float value, assigns it to the supplied string and returns the reference.
|
/// 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
|
/// 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)
|
/// precision (total number of digits after the decimal point, -1 means ignore precision argument)
|
||||||
/// and width (total length of formatted string).
|
/// and width (total length of formatted string).
|
||||||
|
|
||||||
|
|
||||||
@@ -512,7 +634,7 @@ Foundation_API std::string& doubleToStr(std::string& str,
|
|||||||
char decSep = 0);
|
char decSep = 0);
|
||||||
/// Converts a double value, assigns it to the supplied string and returns the reference.
|
/// 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
|
/// 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)
|
/// precision (total number of digits after the decimal point, -1 means ignore precision argument)
|
||||||
/// and width (total length of formatted string).
|
/// and width (total length of formatted string).
|
||||||
|
|
||||||
|
|
||||||
@@ -527,34 +649,45 @@ Foundation_API std::string& doubleToFixedStr(std::string& str,
|
|||||||
/// precision (total number of digits after the decimal point) and width (total length of formatted string).
|
/// precision (total number of digits after the decimal point) and width (total length of formatted string).
|
||||||
|
|
||||||
|
|
||||||
Foundation_API float strToFloat(const char* str);
|
Foundation_API float strToFloat(const char* str,
|
||||||
|
const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
|
||||||
/// Converts the string of characters into single-precision floating point number.
|
/// Converts the string of characters into single-precision floating point number.
|
||||||
/// Function uses double_convesrion::DoubleToStringConverter to do the conversion.
|
/// Function uses double_conversion::DoubleToStringConverter to do the conversion.
|
||||||
|
|
||||||
|
|
||||||
Foundation_API bool strToFloat(const std::string&, float& result, char decSep = '.', char thSep = ',');
|
Foundation_API bool strToFloat(const std::string&, float& result,
|
||||||
|
char decSep = '.', char thSep = ',',
|
||||||
|
const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
|
||||||
/// Converts the string of characters into single-precision floating point number.
|
/// Converts the string of characters into single-precision floating point number.
|
||||||
/// The conversion result is assigned to the result parameter.
|
/// The conversion result is assigned to the result parameter.
|
||||||
/// If decimal separator and/or thousand separator are different from defaults, they should be
|
/// If decimal separator and/or thousand separator are different from defaults, they should be
|
||||||
/// supplied to ensure proper conversion.
|
/// supplied to ensure proper conversion.
|
||||||
///
|
///
|
||||||
/// Returns true if successful, false otherwise.
|
/// Returns true if successful, false otherwise.
|
||||||
|
|
||||||
|
|
||||||
Foundation_API double strToDouble(const char* str);
|
Foundation_API double strToDouble(const char* str,
|
||||||
|
const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
|
||||||
/// Converts the string of characters into double-precision floating point number.
|
/// 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 = ',');
|
Foundation_API bool strToDouble(const std::string& str, double& result,
|
||||||
|
char decSep = '.', char thSep = ',',
|
||||||
|
const char* inf = POCO_FLT_INF, const char* nan = POCO_FLT_NAN);
|
||||||
/// Converts the string of characters into double-precision floating point number.
|
/// Converts the string of characters into double-precision floating point number.
|
||||||
/// The conversion result is assigned to the result parameter.
|
/// The conversion result is assigned to the result parameter.
|
||||||
/// If decimal separator and/or thousand separator are different from defaults, they should be
|
/// If decimal separator and/or thousand separator are different from defaults, they should be
|
||||||
/// supplied to ensure proper conversion.
|
/// supplied to ensure proper conversion.
|
||||||
///
|
///
|
||||||
/// Returns true if successful, false otherwise.
|
/// Returns true if successful, false otherwise.
|
||||||
|
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef POCO_COMPILER_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // POCO_COMPILER_MSVC
|
||||||
|
|
||||||
|
|
||||||
#endif // Foundation_NumericString_INCLUDED
|
#endif // Foundation_NumericString_INCLUDED
|
||||||
|
@@ -627,6 +627,22 @@ S cat(const S& delim, const It& begin, const It& end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
bool startsWith(const S& str, const S& prefix)
|
||||||
|
/// Tests whether the string starts with the given prefix.
|
||||||
|
{
|
||||||
|
return str.size() >= prefix.size() && equal(prefix.begin(), prefix.end(), str.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
bool endsWith(const S& str, const S& suffix)
|
||||||
|
/// Tests whether the string ends with the given suffix.
|
||||||
|
{
|
||||||
|
return str.size() >= suffix.size() && equal(suffix.rbegin(), suffix.rend(), str.rbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// case-insensitive string equality
|
// case-insensitive string equality
|
||||||
//
|
//
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
|
|
||||||
// +++ double conversion +++
|
// +++ double conversion +++
|
||||||
|
#define double_conversion poco_double_conversion // don't collide with standalone double_conversion library
|
||||||
#define UNREACHABLE poco_bugcheck
|
#define UNREACHABLE poco_bugcheck
|
||||||
#define UNIMPLEMENTED poco_bugcheck
|
#define UNIMPLEMENTED poco_bugcheck
|
||||||
#include "diy-fp.cc"
|
#include "diy-fp.cc"
|
||||||
@@ -57,11 +58,7 @@ void pad(std::string& str, int precision, int width, char prefix = ' ', char dec
|
|||||||
std::string::size_type frac = str.length() - decSepPos - 1;
|
std::string::size_type frac = str.length() - decSepPos - 1;
|
||||||
|
|
||||||
std::string::size_type ePos = str.find_first_of("eE");
|
std::string::size_type ePos = str.find_first_of("eE");
|
||||||
#ifndef POCO_ENABLE_CPP11
|
|
||||||
std::auto_ptr<std::string> eStr;
|
std::auto_ptr<std::string> eStr;
|
||||||
#else
|
|
||||||
std::unique_ptr<std::string> eStr;
|
|
||||||
#endif // POCO_ENABLE_CPP11
|
|
||||||
if (ePos != std::string::npos)
|
if (ePos != std::string::npos)
|
||||||
{
|
{
|
||||||
eStr.reset(new std::string(str.substr(ePos, std::string::npos)));
|
eStr.reset(new std::string(str.substr(ePos, std::string::npos)));
|
||||||
@@ -72,9 +69,46 @@ void pad(std::string& str, int precision, int width, char prefix = ' ', char dec
|
|||||||
if (frac != precision)
|
if (frac != precision)
|
||||||
{
|
{
|
||||||
if (frac < precision)
|
if (frac < precision)
|
||||||
|
{
|
||||||
str.append(precision - frac, '0');
|
str.append(precision - frac, '0');
|
||||||
else if ((frac > precision) && (decSepPos != std::string::npos))
|
}
|
||||||
|
else if ((frac > precision) && (decSepPos != std::string::npos))
|
||||||
|
{
|
||||||
|
int pos = static_cast<int>(decSepPos) + 1 + precision;
|
||||||
|
if (str[pos] >= '5') // we must round up
|
||||||
|
{
|
||||||
|
char carry = 0;
|
||||||
|
if(str[--pos] == '9')
|
||||||
|
{
|
||||||
|
str[pos] = '0';
|
||||||
|
carry = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++str[pos];
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
while (--pos >= 0)
|
||||||
|
{
|
||||||
|
if(str[pos] == decSep) continue;
|
||||||
|
if(carry)
|
||||||
|
{
|
||||||
|
if((str[pos] + carry) <= '9')
|
||||||
|
{
|
||||||
|
++str[pos];
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str[pos] = '0';
|
||||||
|
carry = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (carry) str.insert(str.begin(), 1, '1');
|
||||||
|
}
|
||||||
str = str.substr(0, decSepPos + 1 + precision);
|
str = str.substr(0, decSepPos + 1 + precision);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eStr.get()) str += *eStr;
|
if (eStr.get()) str += *eStr;
|
||||||
@@ -211,7 +245,8 @@ void doubleToFixedStr(char* buffer, int bufferSize, double value, int precision)
|
|||||||
StringBuilder builder(buffer, bufferSize);
|
StringBuilder builder(buffer, bufferSize);
|
||||||
int flags = DoubleToStringConverter::UNIQUE_ZERO |
|
int flags = DoubleToStringConverter::UNIQUE_ZERO |
|
||||||
DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
|
DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
|
||||||
DoubleToStringConverter dc(flags, POCO_FLT_INF, POCO_FLT_NAN, POCO_FLT_EXP, -std::numeric_limits<double>::digits10, std::numeric_limits<double>::digits10, 0, 0);
|
DoubleToStringConverter dc(flags, POCO_FLT_INF, POCO_FLT_NAN, POCO_FLT_EXP,
|
||||||
|
-std::numeric_limits<double>::digits10, std::numeric_limits<double>::digits10, 0, 0);
|
||||||
dc.ToFixed(value, precision, &builder);
|
dc.ToFixed(value, precision, &builder);
|
||||||
builder.Finalize();
|
builder.Finalize();
|
||||||
}
|
}
|
||||||
@@ -255,32 +290,32 @@ std::string& doubleToFixedStr(std::string& str, double value, int precision, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float strToFloat(const char* str)
|
float strToFloat(const char* str, const char* inf, const char* nan)
|
||||||
{
|
{
|
||||||
using namespace double_conversion;
|
using namespace double_conversion;
|
||||||
|
|
||||||
int processed;
|
int processed;
|
||||||
int flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
|
int flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
|
||||||
StringToDoubleConverter::ALLOW_TRAILING_SPACES;
|
StringToDoubleConverter::ALLOW_TRAILING_SPACES;
|
||||||
StringToDoubleConverter converter(flags, 0.0, Single::NaN(), POCO_FLT_INF, POCO_FLT_NAN);
|
StringToDoubleConverter converter(flags, 0.0, Single::NaN(), inf, nan);
|
||||||
float result = converter.StringToFloat(str, static_cast<int>(strlen(str)), &processed);
|
float result = converter.StringToFloat(str, static_cast<int>(strlen(str)), &processed);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
double strToDouble(const char* str)
|
double strToDouble(const char* str, const char* inf, const char* nan)
|
||||||
{
|
{
|
||||||
using namespace double_conversion;
|
using namespace double_conversion;
|
||||||
int processed;
|
int processed;
|
||||||
int flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
|
int flags = StringToDoubleConverter::ALLOW_LEADING_SPACES |
|
||||||
StringToDoubleConverter::ALLOW_TRAILING_SPACES;
|
StringToDoubleConverter::ALLOW_TRAILING_SPACES;
|
||||||
StringToDoubleConverter converter(flags, 0.0, Double::NaN(), POCO_FLT_INF, POCO_FLT_NAN);
|
StringToDoubleConverter converter(flags, 0.0, Double::NaN(), inf, nan);
|
||||||
double result = converter.StringToDouble(str, static_cast<int>(strlen(str)), &processed);
|
double result = converter.StringToDouble(str, static_cast<int>(strlen(str)), &processed);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool strToFloat(const std::string& str, float& result, char decSep, char thSep)
|
bool strToFloat(const std::string& str, float& result, char decSep, char thSep, const char* inf, const char* nan)
|
||||||
{
|
{
|
||||||
using namespace double_conversion;
|
using namespace double_conversion;
|
||||||
|
|
||||||
@@ -289,13 +324,13 @@ bool strToFloat(const std::string& str, float& result, char decSep, char thSep)
|
|||||||
removeInPlace(tmp, thSep);
|
removeInPlace(tmp, thSep);
|
||||||
removeInPlace(tmp, 'f');
|
removeInPlace(tmp, 'f');
|
||||||
replaceInPlace(tmp, decSep, '.');
|
replaceInPlace(tmp, decSep, '.');
|
||||||
result = strToFloat(tmp.c_str());
|
result = strToFloat(tmp.c_str(), inf, nan);
|
||||||
return !FPEnvironment::isInfinite(result) &&
|
return !FPEnvironment::isInfinite(result) &&
|
||||||
!FPEnvironment::isNaN(result);
|
!FPEnvironment::isNaN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool strToDouble(const std::string& str, double& result, char decSep, char thSep)
|
bool strToDouble(const std::string& str, double& result, char decSep, char thSep, const char* inf, const char* nan)
|
||||||
{
|
{
|
||||||
if (str.empty()) return false;
|
if (str.empty()) return false;
|
||||||
|
|
||||||
@@ -306,10 +341,10 @@ bool strToDouble(const std::string& str, double& result, char decSep, char thSep
|
|||||||
removeInPlace(tmp, thSep);
|
removeInPlace(tmp, thSep);
|
||||||
replaceInPlace(tmp, decSep, '.');
|
replaceInPlace(tmp, decSep, '.');
|
||||||
removeInPlace(tmp, 'f');
|
removeInPlace(tmp, 'f');
|
||||||
result = strToDouble(tmp.c_str());
|
result = strToDouble(tmp.c_str(), inf, nan);
|
||||||
return !FPEnvironment::isInfinite(result) &&
|
return !FPEnvironment::isInfinite(result) &&
|
||||||
!FPEnvironment::isNaN(result);
|
!FPEnvironment::isNaN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
@@ -9,20 +9,22 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "StringTest.h"
|
#include "StringTest.h"
|
||||||
#include "CppUnit/TestCaller.h"
|
#include "Poco/CppUnit/TestCaller.h"
|
||||||
#include "CppUnit/TestSuite.h"
|
#include "Poco/CppUnit/TestSuite.h"
|
||||||
#include "Poco/String.h"
|
#include "Poco/String.h"
|
||||||
|
#include "Poco/JSONString.h"
|
||||||
#include "Poco/Format.h"
|
#include "Poco/Format.h"
|
||||||
#include "Poco/MemoryStream.h"
|
#include "Poco/MemoryStream.h"
|
||||||
#include "Poco/Stopwatch.h"
|
#include "Poco/Stopwatch.h"
|
||||||
|
#include "Poco/FPEnvironment.h"
|
||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
#include "Poco/JSONString.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <climits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
using Poco::trimLeft;
|
using Poco::trimLeft;
|
||||||
@@ -45,6 +47,8 @@ using Poco::replaceInPlace;
|
|||||||
using Poco::remove;
|
using Poco::remove;
|
||||||
using Poco::removeInPlace;
|
using Poco::removeInPlace;
|
||||||
using Poco::cat;
|
using Poco::cat;
|
||||||
|
using Poco::startsWith;
|
||||||
|
using Poco::endsWith;
|
||||||
using Poco::strToInt;
|
using Poco::strToInt;
|
||||||
using Poco::strToFloat;
|
using Poco::strToFloat;
|
||||||
using Poco::strToDouble;
|
using Poco::strToDouble;
|
||||||
@@ -55,14 +59,18 @@ using Poco::doubleToStr;
|
|||||||
using Poco::thousandSeparator;
|
using Poco::thousandSeparator;
|
||||||
using Poco::decimalSeparator;
|
using Poco::decimalSeparator;
|
||||||
using Poco::format;
|
using Poco::format;
|
||||||
|
using Poco::toJSON;
|
||||||
using Poco::CILess;
|
using Poco::CILess;
|
||||||
using Poco::MemoryInputStream;
|
using Poco::MemoryInputStream;
|
||||||
using Poco::Stopwatch;
|
using Poco::Stopwatch;
|
||||||
using Poco::RangeException;
|
using Poco::RangeException;
|
||||||
using Poco::toJSON;
|
using Poco::isIntOverflow;
|
||||||
|
using Poco::isSafeIntCast;
|
||||||
|
using Poco::safeIntCast;
|
||||||
|
using Poco::FPEnvironment;
|
||||||
|
|
||||||
|
|
||||||
StringTest::StringTest(const std::string& name): CppUnit::TestCase(name)
|
StringTest::StringTest(const std::string& rName): CppUnit::TestCase(rName)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +278,7 @@ void StringTest::testIcompare()
|
|||||||
assertTrue (icompare(ss1, 2, 2, ss2, 1, 3) < 0);
|
assertTrue (icompare(ss1, 2, 2, ss2, 1, 3) < 0);
|
||||||
assertTrue (icompare(ss1, 2, 2, ss2, 1, 2) == 0);
|
assertTrue (icompare(ss1, 2, 2, ss2, 1, 2) == 0);
|
||||||
assertTrue (icompare(ss3, 1, 3, ss1, 2, 3) > 0);
|
assertTrue (icompare(ss3, 1, 3, ss1, 2, 3) > 0);
|
||||||
|
|
||||||
assertTrue (icompare(s1, s2.c_str()) == 0);
|
assertTrue (icompare(s1, s2.c_str()) == 0);
|
||||||
assertTrue (icompare(s1, s3.c_str()) < 0);
|
assertTrue (icompare(s1, s3.c_str()) < 0);
|
||||||
assertTrue (icompare(s1, s4.c_str()) < 0);
|
assertTrue (icompare(s1, s4.c_str()) < 0);
|
||||||
@@ -279,12 +287,12 @@ void StringTest::testIcompare()
|
|||||||
assertTrue (icompare(s2, s4.c_str()) < 0);
|
assertTrue (icompare(s2, s4.c_str()) < 0);
|
||||||
assertTrue (icompare(s1, s5.c_str()) > 0);
|
assertTrue (icompare(s1, s5.c_str()) > 0);
|
||||||
assertTrue (icompare(s5, s4.c_str()) < 0);
|
assertTrue (icompare(s5, s4.c_str()) < 0);
|
||||||
|
|
||||||
assertTrue (icompare(ss1, 2, 3, "aaa") == 0);
|
assertTrue (icompare(ss1, 2, 3, "aaa") == 0);
|
||||||
assertTrue (icompare(ss1, 2, 2, "aaa") < 0);
|
assertTrue (icompare(ss1, 2, 2, "aaa") < 0);
|
||||||
assertTrue (icompare(ss1, 2, 3, "AAA") == 0);
|
assertTrue (icompare(ss1, 2, 3, "AAA") == 0);
|
||||||
assertTrue (icompare(ss1, 2, 2, "bb") < 0);
|
assertTrue (icompare(ss1, 2, 2, "bb") < 0);
|
||||||
|
|
||||||
assertTrue (icompare(ss1, 2, "aaa") > 0);
|
assertTrue (icompare(ss1, 2, "aaa") > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +301,7 @@ void StringTest::testCILessThan()
|
|||||||
{
|
{
|
||||||
typedef std::map<std::string, int, CILess> CIMapType;
|
typedef std::map<std::string, int, CILess> CIMapType;
|
||||||
CIMapType ciMap;
|
CIMapType ciMap;
|
||||||
|
|
||||||
ciMap["z"] = 1;
|
ciMap["z"] = 1;
|
||||||
ciMap["b"] = 2;
|
ciMap["b"] = 2;
|
||||||
ciMap["A"] = 3;
|
ciMap["A"] = 3;
|
||||||
@@ -307,7 +315,7 @@ void StringTest::testCILessThan()
|
|||||||
assertTrue (it->second == 4);
|
assertTrue (it->second == 4);
|
||||||
|
|
||||||
typedef std::set<std::string, CILess> CISetType;
|
typedef std::set<std::string, CILess> CISetType;
|
||||||
|
|
||||||
CISetType ciSet;
|
CISetType ciSet;
|
||||||
ciSet.insert("z");
|
ciSet.insert("z");
|
||||||
ciSet.insert("b");
|
ciSet.insert("b");
|
||||||
@@ -344,7 +352,7 @@ void StringTest::testTranslateInPlace()
|
|||||||
void StringTest::testReplace()
|
void StringTest::testReplace()
|
||||||
{
|
{
|
||||||
std::string s("aabbccdd");
|
std::string s("aabbccdd");
|
||||||
|
|
||||||
assertTrue (replace(s, std::string("aa"), std::string("xx")) == "xxbbccdd");
|
assertTrue (replace(s, std::string("aa"), std::string("xx")) == "xxbbccdd");
|
||||||
assertTrue (replace(s, std::string("bb"), std::string("xx")) == "aaxxccdd");
|
assertTrue (replace(s, std::string("bb"), std::string("xx")) == "aaxxccdd");
|
||||||
assertTrue (replace(s, std::string("dd"), std::string("xx")) == "aabbccxx");
|
assertTrue (replace(s, std::string("dd"), std::string("xx")) == "aabbccxx");
|
||||||
@@ -363,7 +371,7 @@ void StringTest::testReplace()
|
|||||||
assertTrue (replace(s, "b", "") == "aaccdd");
|
assertTrue (replace(s, "b", "") == "aaccdd");
|
||||||
assertTrue (replace(s, "ee", "xx") == "aabbccdd");
|
assertTrue (replace(s, "ee", "xx") == "aabbccdd");
|
||||||
assertTrue (replace(s, "dd", "") == "aabbcc");
|
assertTrue (replace(s, "dd", "") == "aabbcc");
|
||||||
|
|
||||||
s = "aabbaabb";
|
s = "aabbaabb";
|
||||||
assertTrue (replace(s, std::string("aa"), std::string("")) == "bbbb");
|
assertTrue (replace(s, std::string("aa"), std::string("")) == "bbbb");
|
||||||
assertTrue (replace(s, std::string("a"), std::string("")) == "bbbb");
|
assertTrue (replace(s, std::string("a"), std::string("")) == "bbbb");
|
||||||
@@ -378,7 +386,7 @@ void StringTest::testReplace()
|
|||||||
assertTrue (replace(s, "a", "x") == "xxbbxxbb");
|
assertTrue (replace(s, "a", "x") == "xxbbxxbb");
|
||||||
assertTrue (replace(s, "a", "xx") == "xxxxbbxxxxbb");
|
assertTrue (replace(s, "a", "xx") == "xxxxbbxxxxbb");
|
||||||
assertTrue (replace(s, "aa", "xxx") == "xxxbbxxxbb");
|
assertTrue (replace(s, "aa", "xxx") == "xxxbbxxxbb");
|
||||||
|
|
||||||
assertTrue (replace(s, "aa", "xx", 2) == "aabbxxbb");
|
assertTrue (replace(s, "aa", "xx", 2) == "aabbxxbb");
|
||||||
assertTrue (replace(s, 'a', 'x', 2) == "aabbxxbb");
|
assertTrue (replace(s, 'a', 'x', 2) == "aabbxxbb");
|
||||||
assertTrue (remove(s, 'a', 2) == "aabbbb");
|
assertTrue (remove(s, 'a', 2) == "aabbbb");
|
||||||
@@ -420,7 +428,7 @@ void StringTest::testCat()
|
|||||||
assertTrue (cat(s1, s2, s3, s4) == "onetwothreefour");
|
assertTrue (cat(s1, s2, s3, s4) == "onetwothreefour");
|
||||||
assertTrue (cat(s1, s2, s3, s4, s5) == "onetwothreefourfive");
|
assertTrue (cat(s1, s2, s3, s4, s5) == "onetwothreefourfive");
|
||||||
assertTrue (cat(s1, s2, s3, s4, s5, s6) == "onetwothreefourfivesix");
|
assertTrue (cat(s1, s2, s3, s4, s5, s6) == "onetwothreefourfivesix");
|
||||||
|
|
||||||
std::vector<std::string> vec;
|
std::vector<std::string> vec;
|
||||||
assertTrue (cat(std::string(), vec.begin(), vec.end()) == "");
|
assertTrue (cat(std::string(), vec.begin(), vec.end()) == "");
|
||||||
assertTrue (cat(std::string(","), vec.begin(), vec.end()) == "");
|
assertTrue (cat(std::string(","), vec.begin(), vec.end()) == "");
|
||||||
@@ -433,6 +441,55 @@ void StringTest::testCat()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StringTest::testStartsWith()
|
||||||
|
{
|
||||||
|
std::string s1("o");
|
||||||
|
|
||||||
|
assertTrue (startsWith(s1, std::string("o")));
|
||||||
|
assertTrue (startsWith(s1, std::string("")));
|
||||||
|
|
||||||
|
assertTrue (!startsWith(s1, std::string("O")));
|
||||||
|
assertTrue (!startsWith(s1, std::string("1")));
|
||||||
|
|
||||||
|
std::string s2("");
|
||||||
|
|
||||||
|
assertTrue (startsWith(s2, std::string("")));
|
||||||
|
|
||||||
|
assertTrue (!startsWith(s2, std::string("o")));
|
||||||
|
|
||||||
|
std::string s3("oO");
|
||||||
|
|
||||||
|
assertTrue (startsWith(s3, std::string("o")));
|
||||||
|
|
||||||
|
assertTrue (!startsWith(s3, std::string(" o")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StringTest::testEndsWith()
|
||||||
|
{
|
||||||
|
std::string s1("o");
|
||||||
|
|
||||||
|
assertTrue (endsWith(s1, std::string("o")));
|
||||||
|
assertTrue (endsWith(s1, std::string("")));
|
||||||
|
|
||||||
|
assertTrue (!endsWith(s1, std::string("O")));
|
||||||
|
assertTrue (!endsWith(s1, std::string("1")));
|
||||||
|
|
||||||
|
|
||||||
|
std::string s2("");
|
||||||
|
|
||||||
|
assertTrue (endsWith(s2, std::string("")));
|
||||||
|
|
||||||
|
assertTrue (!endsWith(s2, std::string("o")));
|
||||||
|
|
||||||
|
std::string s3("Oo");
|
||||||
|
|
||||||
|
assertTrue (endsWith(s3, std::string("o")));
|
||||||
|
|
||||||
|
assertTrue (!endsWith(s3, std::string("o ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void StringTest::testStringToInt()
|
void StringTest::testStringToInt()
|
||||||
{
|
{
|
||||||
//gcc on Mac emits warnings that cannot be suppressed
|
//gcc on Mac emits warnings that cannot be suppressed
|
||||||
@@ -518,7 +575,7 @@ void StringTest::testStringToFloat()
|
|||||||
float d = 12e34f;
|
float d = 12e34f;
|
||||||
assertTrue (strToFloat(format("12e34", ds), result, ds, ts));
|
assertTrue (strToFloat(format("12e34", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01e34);
|
assertEqualDelta(d, result, 0.01e34);
|
||||||
|
|
||||||
d = 1.234e30f;
|
d = 1.234e30f;
|
||||||
assertTrue (strToFloat(format("1%c234e30", ds), result, ds, ts));
|
assertTrue (strToFloat(format("1%c234e30", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
@@ -531,7 +588,7 @@ void StringTest::testStringToFloat()
|
|||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
assertTrue (strToFloat(format("-12%c34", ds), result, ds, ts));
|
assertTrue (strToFloat(format("-12%c34", ds), result, ds, ts));
|
||||||
assertEqualDelta(-12.34, result, 0.01);
|
assertEqualDelta(-12.34, result, 0.01);
|
||||||
|
|
||||||
assertTrue (strToFloat(format(" 12%c34", ds), result, ds, ts));
|
assertTrue (strToFloat(format(" 12%c34", ds), result, ds, ts));
|
||||||
assertEqualDelta(12.34, result, 0.01);
|
assertEqualDelta(12.34, result, 0.01);
|
||||||
assertTrue (strToFloat(format("12%c34 ", ds), result, ds, ts));
|
assertTrue (strToFloat(format("12%c34 ", ds), result, ds, ts));
|
||||||
@@ -540,6 +597,23 @@ void StringTest::testStringToFloat()
|
|||||||
assertEqualDelta(12.34, result, 0.01);
|
assertEqualDelta(12.34, result, 0.01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToFloat("nan")));
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToFloat("xNaNy")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToFloat("inf")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToFloat("-inf")));
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToFloat("infinity")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToFloat("infinity", "infinity")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToFloat("-infinity", "infinity")));
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToFloat("Inf")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToFloat("Inf", "Inf")));
|
||||||
|
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToFloat("inf")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToFloat("-inf")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToFloat("infinity", "infinity")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToFloat("-infinity", "infinity")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToFloat("Inf")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToFloat("Inf", "Inf")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -619,23 +693,23 @@ void StringTest::testStringToDouble()
|
|||||||
double d = 12e34;
|
double d = 12e34;
|
||||||
assertTrue (strToDouble(format("12e34", ds), result, ds, ts));
|
assertTrue (strToDouble(format("12e34", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01e34);
|
assertEqualDelta(d, result, 0.01e34);
|
||||||
|
|
||||||
d = 1.234e100;
|
d = 1.234e100;
|
||||||
assertTrue (strToDouble(format("1%c234e100", ds), result, ds, ts));
|
assertTrue (strToDouble(format("1%c234e100", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
assertTrue (strToDouble(format("1%c234E+100", ds), result, ds, ts));
|
assertTrue (strToDouble(format("1%c234E+100", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
|
|
||||||
d = 1.234e-100;
|
d = 1.234e-100;
|
||||||
assertTrue (strToDouble(format("1%c234E-100", ds), result, ds, ts));
|
assertTrue (strToDouble(format("1%c234E-100", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
|
|
||||||
d = -1.234e100;
|
d = -1.234e100;
|
||||||
assertTrue (strToDouble(format("-1%c234e+100", ds), result, ds, ts));
|
assertTrue (strToDouble(format("-1%c234e+100", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
assertTrue (strToDouble(format("-1%c234E100", ds), result, ds, ts));
|
assertTrue (strToDouble(format("-1%c234E100", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
|
|
||||||
d = 1.234e-100;
|
d = 1.234e-100;
|
||||||
assertTrue (strToDouble(format(" 1%c234e-100 ", ds), result, ds, ts));
|
assertTrue (strToDouble(format(" 1%c234e-100 ", ds), result, ds, ts));
|
||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
@@ -672,7 +746,7 @@ void StringTest::testStringToDouble()
|
|||||||
assertEqualDelta(d, result, 0.01);
|
assertEqualDelta(d, result, 0.01);
|
||||||
assertTrue (strToDouble(format("-12%c34", ds), result, ds, ts));
|
assertTrue (strToDouble(format("-12%c34", ds), result, ds, ts));
|
||||||
assertEqualDelta(-12.34, result, 0.01);
|
assertEqualDelta(-12.34, result, 0.01);
|
||||||
|
|
||||||
assertTrue (strToDouble(format(" 12%c34", ds), result, ds, ts));
|
assertTrue (strToDouble(format(" 12%c34", ds), result, ds, ts));
|
||||||
assertEqualDelta(12.34, result, 0.01);
|
assertEqualDelta(12.34, result, 0.01);
|
||||||
assertTrue (strToDouble(format("12%c34 ", ds), result, ds, ts));
|
assertTrue (strToDouble(format("12%c34 ", ds), result, ds, ts));
|
||||||
@@ -681,9 +755,50 @@ void StringTest::testStringToDouble()
|
|||||||
assertEqualDelta(12.34, result, 0.01);
|
assertEqualDelta(12.34, result, 0.01);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToDouble("nan")));
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToDouble("xNaNy")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToDouble("inf")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToDouble("-inf")));
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToDouble("infinity")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToDouble("infinity", "infinity")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToDouble("-infinity", "infinity")));
|
||||||
|
assertTrue (FPEnvironment::isNaN(strToDouble("Inf")));
|
||||||
|
assertTrue (!FPEnvironment::isNaN(strToDouble("Inf", "Inf")));
|
||||||
|
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToDouble("inf")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToDouble("-inf")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToDouble("infinity", "infinity")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToDouble("-infinity", "infinity")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToDouble("Inf")));
|
||||||
|
assertTrue (FPEnvironment::isInfinite(strToDouble("Inf", "Inf")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StringTest::testNumericStringPadding()
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
assertTrue (floatToStr(str, 0.999f, 2, 4) == "1.00");
|
||||||
|
assertTrue (floatToStr(str, 0.945f, 2, 4) == "0.95");
|
||||||
|
assertTrue (floatToStr(str, 0.944f, 2, 4) == "0.94");
|
||||||
|
assertTrue (floatToStr(str, 12.45f, 2, 5) == "12.45");
|
||||||
|
assertTrue (floatToStr(str, 12.45f, 1, 4) == "12.5");
|
||||||
|
assertTrue (floatToStr(str, 12.45f, 2, 6) == " 12.45");
|
||||||
|
assertTrue (floatToStr(str, 12.455f, 3, 7) == " 12.455");
|
||||||
|
assertTrue (floatToStr(str, 12.455f, 2, 6) == " 12.46");
|
||||||
|
assertTrue (floatToStr(str, 1.23556E-16f, 2, 6) == "1.24e-16");
|
||||||
|
|
||||||
|
assertTrue (doubleToStr(str, 0.999, 2, 4) == "1.00");
|
||||||
|
assertTrue (doubleToStr(str, 0.945, 2, 4) == "0.95");
|
||||||
|
assertTrue (doubleToStr(str, 0.944, 2, 4) == "0.94");
|
||||||
|
assertTrue (doubleToStr(str, 12.45, 2, 5) == "12.45");
|
||||||
|
assertTrue (doubleToStr(str, 12.45, 1, 4) == "12.5");
|
||||||
|
assertTrue (doubleToStr(str, 12.45, 2, 6) == " 12.45");
|
||||||
|
assertTrue (doubleToStr(str, 12.455, 3, 7) == " 12.455");
|
||||||
|
assertTrue (doubleToStr(str, 12.455, 2, 6) == " 12.46");
|
||||||
|
assertTrue (doubleToStr(str, 1.23556E-16, 2, 6) == "1.24e-16");
|
||||||
|
}
|
||||||
|
|
||||||
void StringTest::testStringToFloatError()
|
void StringTest::testStringToFloatError()
|
||||||
{
|
{
|
||||||
char ds = decimalSeparator();
|
char ds = decimalSeparator();
|
||||||
@@ -782,13 +897,13 @@ void StringTest::benchmarkStrToInt()
|
|||||||
sw.stop();
|
sw.stop();
|
||||||
std::cout << "std::strtol Number: " << res << std::endl;
|
std::cout << "std::strtol Number: " << res << std::endl;
|
||||||
double timeStrtol = sw.elapsed() / 1000.0;
|
double timeStrtol = sw.elapsed() / 1000.0;
|
||||||
|
|
||||||
sw.restart();
|
sw.restart();
|
||||||
for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res, 10);
|
for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res, 10);
|
||||||
sw.stop();
|
sw.stop();
|
||||||
std::cout << "strToInt Number: " << res << std::endl;
|
std::cout << "strToInt Number: " << res << std::endl;
|
||||||
double timeStrToInt = sw.elapsed() / 1000.0;
|
double timeStrToInt = sw.elapsed() / 1000.0;
|
||||||
|
|
||||||
sw.restart();
|
sw.restart();
|
||||||
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d", &res);
|
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d", &res);
|
||||||
sw.stop();
|
sw.stop();
|
||||||
@@ -799,11 +914,11 @@ void StringTest::benchmarkStrToInt()
|
|||||||
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
|
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
|
||||||
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << timeStream << "[ms]" << std::endl;
|
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << timeStream << "[ms]" << std::endl;
|
||||||
|
|
||||||
std::cout << std::setw(14) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
|
std::cout << std::setw(14) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
|
||||||
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
|
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
|
||||||
graph = (int) (timeStream / timeStrtol); for (int i = 0; i < graph; ++i) std::cout << '|';
|
graph = (int) (timeStream / timeStrtol); for (int i = 0; i < graph; ++i) std::cout << '|';
|
||||||
|
|
||||||
std::cout << std::endl << std::setw(14) << "strToInt:\t" << std::setw(10) << std::setfill(' ') << timeStrToInt << "[ms]" <<
|
std::cout << std::endl << std::setw(14) << "strToInt:\t" << std::setw(10) << std::setfill(' ') << timeStrToInt << "[ms]" <<
|
||||||
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
|
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
|
||||||
graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
|
graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
|
||||||
|
|
||||||
@@ -841,7 +956,7 @@ void StringTest::benchmarkStrToFloat()
|
|||||||
sw.stop();
|
sw.stop();
|
||||||
std::cout << "strToDouble Number: " << res << std::endl;
|
std::cout << "strToDouble Number: " << res << std::endl;
|
||||||
double timeStrToDouble = sw.elapsed() / 1000.0;
|
double timeStrToDouble = sw.elapsed() / 1000.0;
|
||||||
|
|
||||||
// standard sscanf
|
// standard sscanf
|
||||||
sw.restart();
|
sw.restart();
|
||||||
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%lf", &res);
|
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%lf", &res);
|
||||||
@@ -860,11 +975,11 @@ void StringTest::benchmarkStrToFloat()
|
|||||||
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
|
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
|
||||||
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
|
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
|
||||||
|
|
||||||
std::cout << std::setw(14) << "std::strtod:\t" << std::setw(10) << std::setfill(' ') << timeStdStrtod << "[ms]" <<
|
std::cout << std::setw(14) << "std::strtod:\t" << std::setw(10) << std::setfill(' ') << timeStdStrtod << "[ms]" <<
|
||||||
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStdStrtod) << '\t' ;
|
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStdStrtod) << '\t' ;
|
||||||
graph = (int) (timeStream / timeStdStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
|
graph = (int) (timeStream / timeStdStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
|
||||||
|
|
||||||
std::cout << std::endl << std::setw(14) << "strToDouble:\t" << std::setw(10) << std::setfill(' ') << timeStrToDouble << "[ms]" <<
|
std::cout << std::endl << std::setw(14) << "strToDouble:\t" << std::setw(10) << std::setfill(' ') << timeStrToDouble << "[ms]" <<
|
||||||
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToDouble) << '\t' ;
|
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToDouble) << '\t' ;
|
||||||
graph = (int) (timeStream / timeStrToDouble); for (int i = 0; i < graph; ++i) std::cout << '#';
|
graph = (int) (timeStream / timeStrToDouble); for (int i = 0; i < graph; ++i) std::cout << '#';
|
||||||
|
|
||||||
@@ -983,13 +1098,13 @@ void StringTest::testFloatToString()
|
|||||||
{
|
{
|
||||||
double val = 1.03721575516329e-112;
|
double val = 1.03721575516329e-112;
|
||||||
std::string str;
|
std::string str;
|
||||||
|
|
||||||
assertTrue (doubleToStr(str, val, 14, 21) == "1.03721575516329e-112");
|
assertTrue (doubleToStr(str, val, 14, 21) == "1.03721575516329e-112");
|
||||||
assertTrue (doubleToStr(str, val, 14, 22) == " 1.03721575516329e-112");
|
assertTrue (doubleToStr(str, val, 14, 22) == " 1.03721575516329e-112");
|
||||||
val = -val;
|
val = -val;
|
||||||
assertTrue (doubleToStr(str, val, 14, 22) == "-1.03721575516329e-112");
|
assertTrue (doubleToStr(str, val, 14, 22) == "-1.03721575516329e-112");
|
||||||
assertTrue (doubleToStr(str, val, 14, 23) == " -1.03721575516329e-112");
|
assertTrue (doubleToStr(str, val, 14, 23) == " -1.03721575516329e-112");
|
||||||
|
|
||||||
val = -10372157551632.9;
|
val = -10372157551632.9;
|
||||||
assertTrue (doubleToStr(str, val, 1, 21, ',') == "-10,372,157,551,632.9");
|
assertTrue (doubleToStr(str, val, 1, 21, ',') == "-10,372,157,551,632.9");
|
||||||
assertTrue (doubleToStr(str, val, 1, 22, ',') == " -10,372,157,551,632.9");
|
assertTrue (doubleToStr(str, val, 1, 22, ',') == " -10,372,157,551,632.9");
|
||||||
@@ -1004,6 +1119,182 @@ void StringTest::testFloatToString()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StringTest::testNumericStringLimit()
|
||||||
|
{
|
||||||
|
char c = 0, t = -1;
|
||||||
|
assertTrue(!isIntOverflow<char>(c));
|
||||||
|
assertTrue(safeIntCast<char>(c, t) == c);
|
||||||
|
assertTrue(t == c);
|
||||||
|
|
||||||
|
short s = SHRT_MAX;
|
||||||
|
assertTrue(isIntOverflow<char>(s));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(s, t);
|
||||||
|
fail("cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
|
||||||
|
s = SHRT_MIN;
|
||||||
|
assertTrue(isIntOverflow<char>(s));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(s, t);
|
||||||
|
fail("short => char cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
|
||||||
|
signed char sc = 0, st = -1;
|
||||||
|
assertTrue(!isIntOverflow<signed char>(sc));
|
||||||
|
assertTrue(safeIntCast<char>(sc, st) == sc);
|
||||||
|
assertTrue(st == sc);
|
||||||
|
|
||||||
|
short ss = SHRT_MAX;
|
||||||
|
assertTrue(isIntOverflow<signed char>(ss));
|
||||||
|
assertTrue(isIntOverflow<char>(ss));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(ss, st);
|
||||||
|
fail("short => signed char cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
|
||||||
|
ss = SHRT_MIN;
|
||||||
|
assertTrue(isIntOverflow<signed char>(ss));
|
||||||
|
assertTrue(isIntOverflow<char>(ss));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(ss, st);
|
||||||
|
fail("short => signed char cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
|
||||||
|
assertTrue(safeIntCast<signed char>(sc, st) == c);
|
||||||
|
assertTrue(st == sc);
|
||||||
|
|
||||||
|
unsigned char uc = 0, ut = -1;
|
||||||
|
assertTrue(!isIntOverflow<unsigned char>(uc));
|
||||||
|
assertTrue(safeIntCast<char>(uc, ut) == uc);
|
||||||
|
assertTrue(ut == uc);
|
||||||
|
|
||||||
|
ss = SHRT_MAX;
|
||||||
|
assertTrue(isIntOverflow<unsigned char>(ss));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(ss, st);
|
||||||
|
fail("cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
|
||||||
|
ss = -1;
|
||||||
|
assertTrue(isIntOverflow<unsigned char>(ss));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(ss, uc);
|
||||||
|
fail("unsigned short => unsigned char cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
assertTrue(!isIntOverflow<int>(i));
|
||||||
|
assertTrue(!isIntOverflow<unsigned>(i));
|
||||||
|
i = -1;
|
||||||
|
unsigned int ti = -1;
|
||||||
|
assertTrue(isIntOverflow<unsigned>(i));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(i, ti);
|
||||||
|
fail("unsigned int => int cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
|
||||||
|
if (sizeof(long) > sizeof(int))
|
||||||
|
{
|
||||||
|
long l = LONG_MAX;
|
||||||
|
assertTrue(isIntOverflow<int>(l));
|
||||||
|
l = -1L;
|
||||||
|
assertTrue(isIntOverflow<unsigned>(l));
|
||||||
|
i = -1;
|
||||||
|
assertTrue(!isIntOverflow<long>(i));
|
||||||
|
long tl = 0;
|
||||||
|
assertTrue(safeIntCast(i, tl) == i);
|
||||||
|
unsigned long ul = ULONG_MAX, tul = 0;
|
||||||
|
assertTrue(isIntOverflow<long>(ul));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(ul, tl);
|
||||||
|
fail("unsigned long => long cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
assertTrue(!isIntOverflow<unsigned long>(ul));
|
||||||
|
tl = 0;
|
||||||
|
assertTrue(safeIntCast(ul, tul) == ul);
|
||||||
|
l = LONG_MIN;
|
||||||
|
assertTrue(isIntOverflow<unsigned long>(l));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
safeIntCast(l, ul);
|
||||||
|
fail("unsigned long => long cast must fail");
|
||||||
|
}
|
||||||
|
catch(Poco::BadCastException&){}
|
||||||
|
ul = LONG_MAX;
|
||||||
|
assertTrue(!isIntOverflow<long>(ul));
|
||||||
|
assertTrue(safeIntCast(ul, l) == ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
numericStringLimitSameSign<unsigned short, unsigned char>();
|
||||||
|
numericStringLimitSameSign<short, char>();
|
||||||
|
numericStringLimitSameSign<unsigned int, unsigned short>();
|
||||||
|
numericStringLimitSameSign<int, short>();
|
||||||
|
|
||||||
|
if (sizeof(long) > sizeof(int))
|
||||||
|
{
|
||||||
|
numericStringLimitSameSign<unsigned long, unsigned int>();
|
||||||
|
numericStringLimitSameSign<long, int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
numericStringLowerLimit<short, char>();
|
||||||
|
numericStringLowerLimit<int, short>();
|
||||||
|
|
||||||
|
if (sizeof(long) > sizeof(int))
|
||||||
|
{
|
||||||
|
numericStringLowerLimit<Poco::Int64, Poco::Int32>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef POCO_ENABLE_CPP11
|
||||||
|
assertTrue(!isIntOverflow<int8_t>(0));
|
||||||
|
assertTrue(isIntOverflow<int8_t>(std::numeric_limits<int16_t>::max()));
|
||||||
|
assertTrue(isIntOverflow<int8_t>(std::numeric_limits<int16_t>::min()));
|
||||||
|
assertTrue(!isIntOverflow<uint8_t>(0));
|
||||||
|
assertTrue(isIntOverflow<uint8_t>(std::numeric_limits<int16_t>::max()));
|
||||||
|
assertTrue(isIntOverflow<uint8_t>(-1));
|
||||||
|
assertTrue(!isIntOverflow<int32_t>(0));
|
||||||
|
assertTrue(isIntOverflow<int32_t>(std::numeric_limits<int64_t>::max()));
|
||||||
|
assertTrue(!isIntOverflow<uint32_t>(0));
|
||||||
|
assertTrue(isIntOverflow<uint32_t>(-1));
|
||||||
|
assertTrue(isIntOverflow<uint32_t>(-1L));
|
||||||
|
assertTrue(isIntOverflow<uint32_t>(-1LL));
|
||||||
|
assertTrue(!isIntOverflow<int64_t>(-1));
|
||||||
|
assertTrue(isIntOverflow<int64_t>(std::numeric_limits<uint64_t>::max()));
|
||||||
|
assertTrue(!isIntOverflow<uint64_t>(std::numeric_limits<uint64_t>::max()));
|
||||||
|
assertTrue(isIntOverflow<uint64_t>(std::numeric_limits<int64_t>::min()));
|
||||||
|
assertTrue(!isIntOverflow<uint64_t>(std::numeric_limits<uint64_t>::min()));
|
||||||
|
assertTrue(!isIntOverflow<int64_t>(std::numeric_limits<int64_t>::max()));
|
||||||
|
|
||||||
|
numericStringLimitSameSign<uint16_t, uint8_t>();
|
||||||
|
numericStringLimitSameSign<int16_t, int8_t>();
|
||||||
|
numericStringLimitSameSign<uint32_t, uint16_t>();
|
||||||
|
numericStringLimitSameSign<int32_t, int16_t>();
|
||||||
|
numericStringLimitSameSign<uint64_t, uint32_t>();
|
||||||
|
numericStringLimitSameSign<int64_t, int32_t>();
|
||||||
|
|
||||||
|
numericStringLowerLimit<int16_t, int8_t>();
|
||||||
|
numericStringLowerLimit<int32_t, int16_t>();
|
||||||
|
numericStringLowerLimit<int64_t, int32_t>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void formatStream(double value, std::string& str)
|
void formatStream(double value, std::string& str)
|
||||||
{
|
{
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
@@ -1043,7 +1334,7 @@ void StringTest::benchmarkFloatToStr()
|
|||||||
sw.stop();
|
sw.stop();
|
||||||
std::cout << "std::sprintf Number: " << str << std::endl;
|
std::cout << "std::sprintf Number: " << str << std::endl;
|
||||||
double timeSprintf = sw.elapsed() / 1000.0;
|
double timeSprintf = sw.elapsed() / 1000.0;
|
||||||
|
|
||||||
// POCO Way (via double-conversion)
|
// POCO Way (via double-conversion)
|
||||||
// no padding
|
// no padding
|
||||||
sw.restart();
|
sw.restart();
|
||||||
@@ -1053,7 +1344,7 @@ void StringTest::benchmarkFloatToStr()
|
|||||||
std::cout << "doubleToStr(char) Number: " << buffer << std::endl;
|
std::cout << "doubleToStr(char) Number: " << buffer << std::endl;
|
||||||
double timeDoubleToStrChar = sw.elapsed() / 1000.0;
|
double timeDoubleToStrChar = sw.elapsed() / 1000.0;
|
||||||
|
|
||||||
// with padding
|
// with padding
|
||||||
str = "";
|
str = "";
|
||||||
sw.restart();
|
sw.restart();
|
||||||
for (int i = 0; i < 1000000; ++i) doubleToStr(str, val);
|
for (int i = 0; i < 1000000; ++i) doubleToStr(str, val);
|
||||||
@@ -1064,16 +1355,16 @@ void StringTest::benchmarkFloatToStr()
|
|||||||
int graph;
|
int graph;
|
||||||
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
|
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
|
||||||
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
|
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << std::setprecision(4) << timeStream << "[ms]" << std::endl;
|
||||||
|
|
||||||
std::cout << std::setw(14) << "sprintf:\t" << std::setw(10) << std::setfill(' ') << timeSprintf << "[ms]" <<
|
std::cout << std::setw(14) << "sprintf:\t" << std::setw(10) << std::setfill(' ') << timeSprintf << "[ms]" <<
|
||||||
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeSprintf) << '\t' ;
|
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeSprintf) << '\t' ;
|
||||||
graph = (int) (timeStream / timeSprintf); for (int i = 0; i < graph; ++i) std::cout << '#';
|
graph = (int) (timeStream / timeSprintf); for (int i = 0; i < graph; ++i) std::cout << '#';
|
||||||
|
|
||||||
std::cout << std::endl << std::setw(14) << "doubleToChar:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrChar << "[ms]" <<
|
std::cout << std::endl << std::setw(14) << "doubleToChar:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrChar << "[ms]" <<
|
||||||
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrChar) << '\t' ;
|
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrChar) << '\t' ;
|
||||||
graph = (int) (timeStream / timeDoubleToStrChar); for (int i = 0; i < graph; ++i) std::cout << '#';
|
graph = (int) (timeStream / timeDoubleToStrChar); for (int i = 0; i < graph; ++i) std::cout << '#';
|
||||||
|
|
||||||
std::cout << std::endl << std::setw(14) << "doubleToString:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrString << "[ms]" <<
|
std::cout << std::endl << std::setw(14) << "doubleToString:\t" << std::setw(10) << std::setfill(' ') << timeDoubleToStrString << "[ms]" <<
|
||||||
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrString) << '\t' ;
|
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrString) << '\t' ;
|
||||||
graph = (int) (timeStream / timeDoubleToStrString); for (int i = 0; i < graph; ++i) std::cout << '#';
|
graph = (int) (timeStream / timeDoubleToStrString); for (int i = 0; i < graph; ++i) std::cout << '#';
|
||||||
|
|
||||||
@@ -1178,9 +1469,13 @@ CppUnit::Test* StringTest::suite()
|
|||||||
CppUnit_addTest(pSuite, StringTest, testReplace);
|
CppUnit_addTest(pSuite, StringTest, testReplace);
|
||||||
CppUnit_addTest(pSuite, StringTest, testReplaceInPlace);
|
CppUnit_addTest(pSuite, StringTest, testReplaceInPlace);
|
||||||
CppUnit_addTest(pSuite, StringTest, testCat);
|
CppUnit_addTest(pSuite, StringTest, testCat);
|
||||||
|
CppUnit_addTest(pSuite, StringTest, testStartsWith);
|
||||||
|
CppUnit_addTest(pSuite, StringTest, testEndsWith);
|
||||||
CppUnit_addTest(pSuite, StringTest, testStringToInt);
|
CppUnit_addTest(pSuite, StringTest, testStringToInt);
|
||||||
CppUnit_addTest(pSuite, StringTest, testStringToFloat);
|
CppUnit_addTest(pSuite, StringTest, testStringToFloat);
|
||||||
CppUnit_addTest(pSuite, StringTest, testStringToDouble);
|
CppUnit_addTest(pSuite, StringTest, testStringToDouble);
|
||||||
|
CppUnit_addTest(pSuite, StringTest, testNumericStringPadding);
|
||||||
|
CppUnit_addTest(pSuite, StringTest, testNumericStringLimit);
|
||||||
CppUnit_addTest(pSuite, StringTest, testStringToFloatError);
|
CppUnit_addTest(pSuite, StringTest, testStringToFloatError);
|
||||||
CppUnit_addTest(pSuite, StringTest, testNumericLocale);
|
CppUnit_addTest(pSuite, StringTest, testNumericLocale);
|
||||||
//CppUnit_addTest(pSuite, StringTest, benchmarkStrToFloat);
|
//CppUnit_addTest(pSuite, StringTest, benchmarkStrToFloat);
|
||||||
|
@@ -15,9 +15,10 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/Foundation.h"
|
#include "Poco/Foundation.h"
|
||||||
#include "CppUnit/TestCase.h"
|
#include "Poco/CppUnit/TestCase.h"
|
||||||
#include "Poco/NumericString.h"
|
#include "Poco/NumericString.h"
|
||||||
#include "Poco/MemoryStream.h"
|
#include "Poco/MemoryStream.h"
|
||||||
|
#include "Poco/NumberFormatter.h"
|
||||||
|
|
||||||
|
|
||||||
class StringTest: public CppUnit::TestCase
|
class StringTest: public CppUnit::TestCase
|
||||||
@@ -42,10 +43,14 @@ public:
|
|||||||
void testReplace();
|
void testReplace();
|
||||||
void testReplaceInPlace();
|
void testReplaceInPlace();
|
||||||
void testCat();
|
void testCat();
|
||||||
|
void testStartsWith();
|
||||||
|
void testEndsWith();
|
||||||
|
|
||||||
void testStringToInt();
|
void testStringToInt();
|
||||||
void testStringToFloat();
|
void testStringToFloat();
|
||||||
void testStringToDouble();
|
void testStringToDouble();
|
||||||
|
void testNumericStringPadding();
|
||||||
|
void testNumericStringLimit();
|
||||||
void testStringToFloatError();
|
void testStringToFloatError();
|
||||||
void testNumericLocale();
|
void testNumericLocale();
|
||||||
void benchmarkStrToFloat();
|
void benchmarkStrToFloat();
|
||||||
@@ -91,6 +96,53 @@ private:
|
|||||||
assertTrue (Poco::strToInt("000", result, 010)); assertTrue (result == 0);
|
assertTrue (Poco::strToInt("000", result, 010)); assertTrue (result == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Larger, typename Smaller>
|
||||||
|
void numericStringLimitSameSign()
|
||||||
|
{
|
||||||
|
Larger l = std::numeric_limits<Smaller>::max();
|
||||||
|
std::string str = Poco::NumberFormatter::format(l);
|
||||||
|
|
||||||
|
Smaller s;
|
||||||
|
assertTrue(Poco::strToInt<Smaller>(str, s, 10));
|
||||||
|
assertTrue(s == std::numeric_limits<Smaller>::max());
|
||||||
|
++l; str = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(str, s, 10));
|
||||||
|
++l; str = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(str, s, 10));
|
||||||
|
++l; str = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(str, s, 10));
|
||||||
|
++l; str = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(str, s, 10));
|
||||||
|
++l; str = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(str, s, 10));
|
||||||
|
++l; str = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(str, s, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Larger, typename Smaller>
|
||||||
|
void numericStringLowerLimit()
|
||||||
|
{
|
||||||
|
Larger l = std::numeric_limits<Smaller>::min();
|
||||||
|
std::string val = Poco::NumberFormatter::format(l);
|
||||||
|
Smaller s = -1;
|
||||||
|
assertFalse(s == std::numeric_limits<Smaller>::min());
|
||||||
|
assertTrue(Poco::strToInt<Smaller>(val, s, 10));
|
||||||
|
assertTrue (s == std::numeric_limits<Smaller>::min());
|
||||||
|
assertTrue(s == std::numeric_limits<Smaller>::min());
|
||||||
|
--l; val = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
|
||||||
|
--l; val = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
|
||||||
|
--l; val = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
|
||||||
|
--l; val = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
|
||||||
|
--l; val = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
|
||||||
|
--l; val = Poco::NumberFormatter::format(l);
|
||||||
|
assertFalse(Poco::strToInt<Smaller>(val, s, 10));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool parseStream(const std::string& s, T& value)
|
bool parseStream(const std::string& s, T& value)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user