fix(strToInt): overflows #3580

This commit is contained in:
Alex Fabijanic
2022-06-22 23:13:39 +02:00
parent 6a97657df8
commit 284a141432
3 changed files with 281 additions and 208 deletions

View File

@@ -33,8 +33,6 @@
#if !defined(POCO_NO_LOCALE) #if !defined(POCO_NO_LOCALE)
#include <locale> #include <locale>
#endif #endif
#include <iostream>
#include <iomanip>
#if defined(POCO_NOINTMAX) #if defined(POCO_NOINTMAX)
typedef Poco::UInt64 uintmax_t; typedef Poco::UInt64 uintmax_t;
typedef Poco::Int64 intmax_t; typedef Poco::Int64 intmax_t;
@@ -113,6 +111,46 @@ inline bool isIntOverflow(From val)
} }
template<typename R, typename F, typename S>
bool safeMultiply(R& result, F f, S s)
{
if ((f == 0) || (s==0))
{
result = 0;
return true;
}
if (f > 0)
{
if (s > 0)
{
if (f > (std::numeric_limits<R>::max() / s))
return false;
}
else
{
if (s < (std::numeric_limits<R>::min() / f))
return false;
}
}
else
{
if (s > 0)
{
if (f < (std::numeric_limits<R>::min() / s))
return false;
}
else
{
if (s < (std::numeric_limits<R>::max() / f))
return false;
}
}
result = f * s;
return true;
}
template <typename F, typename T> template <typename F, typename T>
inline T& isSafeIntCast(F from) inline T& isSafeIntCast(F from)
/// Returns true if it is safe to cast /// Returns true if it is safe to cast
@@ -125,7 +163,7 @@ inline T& isSafeIntCast(F from)
template <typename F, typename T> template <typename F, typename T>
inline T& safeIntCast(F from, T& to) inline T& safeIntCast(F from, T& to)
/// Returns csted value if it is safe /// Returns cast value if it is safe
/// to cast integer from F to T, /// to cast integer from F to T,
/// otherwise throws BadCastException. /// otherwise throws BadCastException.
{ {
@@ -191,49 +229,34 @@ bool strToInt(const char* pStr, I& outResult, short base, char thSep = ',')
// numbers are parsed as unsigned, for negative numbers the sign is applied after parsing // numbers are parsed as unsigned, for negative numbers the sign is applied after parsing
// overflow is checked in every parse step // overflow is checked in every parse step
uintmax_t limitCheck = negative ? -std::numeric_limits<I>::min() : std::numeric_limits<I>::max(); uintmax_t limitCheck = std::numeric_limits<I>::max();
I result = 0; if (negative) ++limitCheck;
uintmax_t result = 0;
unsigned char add = 0;
for (; *pStr != '\0'; ++pStr) for (; *pStr != '\0'; ++pStr)
{ {
if (result > (limitCheck / base)) return false; if (result > (limitCheck / base)) return false;
if (!safeMultiply(result, result, base)) return false;
switch (*pStr) switch (*pStr)
{ {
case '0': case '1': case '2': case '3': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7': case '4': case '5': case '6': case '7':
{ add = (*pStr - '0');
unsigned char add = (*pStr - '0');
if ((limitCheck - result) < add) return false;
result = result * base + add;
}
break; break;
case '8': case '9': case '8': case '9':
if ((base == 10) || (base == 0x10)) if ((base == 10) || (base == 0x10)) add = (*pStr - '0');
{
unsigned char add = (*pStr - '0');
if ((limitCheck - result) < add) return false;
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 (base != 0x10) return false;
unsigned char add = (*pStr - 'a'); add = (*pStr - 'a') + 10;
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 (base != 0x10) return false;
unsigned char add = (*pStr - 'A'); add = (*pStr - 'A') + 10;
if ((limitCheck - result) < add) return false;
result = result * base + (10 + add);
}
break; break;
case '.': case '.':
@@ -250,6 +273,8 @@ bool strToInt(const char* pStr, I& outResult, short base, char thSep = ',')
default: default:
return false; return false;
} }
if ((limitCheck - static_cast<uintmax_t>(result)) < add) return false;
result += add;
} }
if (negative && (base == 10)) if (negative && (base == 10))

View File

@@ -70,6 +70,7 @@ using Poco::MemoryInputStream;
using Poco::Stopwatch; using Poco::Stopwatch;
using Poco::RangeException; using Poco::RangeException;
using Poco::isIntOverflow; using Poco::isIntOverflow;
using Poco::safeMultiply;
using Poco::isSafeIntCast; using Poco::isSafeIntCast;
using Poco::safeIntCast; using Poco::safeIntCast;
using Poco::FPEnvironment; using Poco::FPEnvironment;
@@ -915,121 +916,6 @@ void StringTest::testNumericLocale()
} }
void StringTest::benchmarkStrToInt()
{
Poco::Stopwatch sw;
std::string num = "123456789";
int res;
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res);
sw.stop();
std::cout << "parseStream Number: " << res << std::endl;
double timeStream = sw.elapsed() / 1000.0;
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res = std::strtol(num.c_str(), &pC, 10);
sw.stop();
std::cout << "std::strtol Number: " << res << std::endl;
double timeStrtol = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res, 10);
sw.stop();
std::cout << "strToInt Number: " << res << std::endl;
double timeStrToInt = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d", &res);
sw.stop();
std::cout << "sscanf Number: " << res << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
int graph;
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) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl;
}
void StringTest::benchmarkStrToFloat()
{
Poco::Stopwatch sw;
std::string num = "1.0372157551632929e-112";
std::cout << "The Number: " << num << std::endl;
double res;
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res);
sw.stop();
std::cout << "parseStream Number: " << std::setprecision(std::numeric_limits<double>::digits10) << res << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard strtod
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res = std::strtod(num.c_str(), &pC);
sw.stop();
std::cout << "std::strtod Number: " << res << std::endl;
double timeStdStrtod = sw.elapsed() / 1000.0;
// POCO Way
sw.restart();
char ou = 0;
for (int i = 0; i < 1000000; ++i) strToDouble(num, res, ou);
sw.stop();
std::cout << "strToDouble Number: " << res << std::endl;
double timeStrToDouble = sw.elapsed() / 1000.0;
// standard sscanf
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%lf", &res);
sw.stop();
std::cout << "sscanf Number: " << res << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
// double-conversion Strtod
sw.restart();
for (int i = 0; i < 1000000; ++i) strToDouble(num.c_str());
sw.stop();
std::cout << "Strtod Number: " << res << std::endl;
double timeStrtod = sw.elapsed() / 1000.0;
int graph;
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) << "std::strtod:\t" << std::setw(10) << std::setfill(' ') << timeStdStrtod << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStdStrtod) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToDouble) << '\t' ;
graph = (int) (timeStream / timeStrToDouble); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "StrtoD:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtod) << '\t' ;
graph = (int) (timeStream / timeStrtod); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::testIntToString() void StringTest::testIntToString()
{ {
//intToStr(T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0) //intToStr(T number, unsigned short base, std::string& result, bool prefix = false, int width = -1, char fill = ' ', char thSep = 0)
@@ -1325,6 +1211,15 @@ void StringTest::testNumericStringLimit()
numericStringLowerLimit<int16_t, int8_t>(); numericStringLowerLimit<int16_t, int8_t>();
numericStringLowerLimit<int32_t, int16_t>(); numericStringLowerLimit<int32_t, int16_t>();
numericStringLowerLimit<int64_t, int32_t>(); numericStringLowerLimit<int64_t, int32_t>();
multiplyOverflow<int8_t>();
multiplyOverflow<uint8_t>();
multiplyOverflow<int16_t>();
multiplyOverflow<uint16_t>();
multiplyOverflow<int32_t>();
multiplyOverflow<uint32_t>();
multiplyOverflow<int64_t>();
multiplyOverflow<uint64_t>();
} }
@@ -1348,63 +1243,6 @@ void formatSprintf(double value, std::string& str)
} }
void StringTest::benchmarkFloatToStr()
{
Poco::Stopwatch sw;
double val = 1.0372157551632929e-112;
std::cout << "The Number: " << std::setprecision(std::numeric_limits<double>::digits10) << val << std::endl;
std::string str;
sw.start();
for (int i = 0; i < 1000000; ++i) formatStream(val, str);
sw.stop();
std::cout << "formatStream Number: " << str << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard sprintf
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) formatSprintf(val, str);
sw.stop();
std::cout << "std::sprintf Number: " << str << std::endl;
double timeSprintf = sw.elapsed() / 1000.0;
// POCO Way (via double-conversion)
// no padding
sw.restart();
char buffer[POCO_MAX_FLT_STRING_LEN];
for (int i = 0; i < 1000000; ++i) doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, val);
sw.stop();
std::cout << "doubleToStr(char) Number: " << buffer << std::endl;
double timeDoubleToStrChar = sw.elapsed() / 1000.0;
// with padding
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) doubleToStr(str, val);
sw.stop();
std::cout << "doubleToStr(std::string) Number: " << str << std::endl;
double timeDoubleToStrString = sw.elapsed() / 1000.0;
int graph;
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) << "sprintf:\t" << std::setw(10) << std::setfill(' ') << timeSprintf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeSprintf) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrChar) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrString) << '\t' ;
graph = (int) (timeStream / timeDoubleToStrString); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::testJSONString() void StringTest::testJSONString()
{ {
assertTrue (toJSON("\\", false) == "\\\\"); assertTrue (toJSON("\\", false) == "\\\\");
@@ -1471,6 +1309,201 @@ void StringTest::testJSONString()
} }
void StringTest::conversionBenchmarks()
{
std::cout << std::endl << "===================" << std::endl;
benchmarkFloatToStr();
std::cout << "===================" << std::endl << std::endl;
std::cout << "===================" << std::endl;
benchmarkStrToFloat();
std::cout << "===================" << std::endl << std::endl;
std::cout << "===================" << std::endl;
benchmarkStrToInt();
std::cout << "===================" << std::endl << std::endl;
}
void StringTest::benchmarkFloatToStr()
{
Poco::Stopwatch sw;
double val = 1.0372157551632929e-112;
std::cout << "The Number: " << std::setprecision(std::numeric_limits<double>::digits10) << val << std::endl;
std::string str;
sw.start();
for (int i = 0; i < 1000000; ++i) formatStream(val, str);
sw.stop();
std::cout << "formatStream Number: " << str << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard sprintf
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) formatSprintf(val, str);
sw.stop();
std::cout << "std::sprintf Number: " << str << std::endl;
double timeSprintf = sw.elapsed() / 1000.0;
// POCO Way (via double-conversion)
// no padding
sw.restart();
char buffer[POCO_MAX_FLT_STRING_LEN];
for (int i = 0; i < 1000000; ++i) doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, val);
sw.stop();
std::cout << "doubleToStr(char) Number: " << buffer << std::endl;
double timeDoubleToStrChar = sw.elapsed() / 1000.0;
// with padding
str = "";
sw.restart();
for (int i = 0; i < 1000000; ++i) doubleToStr(str, val);
sw.stop();
std::cout << "doubleToStr(std::string) Number: " << str << std::endl;
double timeDoubleToStrString = sw.elapsed() / 1000.0;
int graph;
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) << "sprintf:\t" << std::setw(10) << std::setfill(' ') << timeSprintf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeSprintf) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrChar) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeDoubleToStrString) << '\t' ;
graph = (int) (timeStream / timeDoubleToStrString); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::benchmarkStrToInt()
{
Poco::Stopwatch sw;
std::string num = "123456789";
int res[4] = {};
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res[0]);
sw.stop();
std::cout << "parseStream Number: " << res[0] << std::endl;
double timeStream = sw.elapsed() / 1000.0;
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res[1] = std::strtol(num.c_str(), &pC, 10);
sw.stop();
std::cout << "std::strtol Number: " << res[1] << std::endl;
double timeStrtol = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res[2], 10);
sw.stop();
std::cout << "strToInt Number: " << res[2] << std::endl;
double timeStrToInt = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d", &res[3]);
sw.stop();
std::cout << "sscanf Number: " << res[3] << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
assertEqual (res[0], res[1]);
assertEqual (res[1], res[2]);
assertEqual (res[2], res[3]);
int graph;
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) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '|';
std::cout << std::endl;
}
void StringTest::benchmarkStrToFloat()
{
double res[5] = {};
Poco::Stopwatch sw;
std::string num = "1.0372157551632929e-112";
std::cout << "The Number: " << num << std::endl;
sw.start();
for (int i = 0; i < 1000000; ++i) parseStream(num, res[0]);
sw.stop();
std::cout << "parseStream Number: " << std::setprecision(std::numeric_limits<double>::digits10) << res[0] << std::endl;
double timeStream = sw.elapsed() / 1000.0;
// standard strtod
char* pC = 0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res[1] = std::strtod(num.c_str(), &pC);
sw.stop();
std::cout << "std::strtod Number: " << res[1] << std::endl;
double timeStdStrtod = sw.elapsed() / 1000.0;
// POCO Way
sw.restart();
char ou = 0;
for (int i = 0; i < 1000000; ++i) strToDouble(num, res[2], ou);
sw.stop();
std::cout << "Poco::strToDouble(const string&, double&) Number: " << res[2] << std::endl;
double timeStrToDouble = sw.elapsed() / 1000.0;
sw.restart();
for (int i = 0; i < 1000000; ++i) res[3] = strToDouble(num.c_str());
sw.stop();
std::cout << "Poco::strToDouble(const char*) Number: " << res[3] << std::endl;
double timeStrtoD = sw.elapsed() / 1000.0;
// standard sscanf
sw.restart();
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%lf", &res[4]);
sw.stop();
std::cout << "sscanf Number: " << res[4] << std::endl;
double timeScanf = sw.elapsed() / 1000.0;
assertEqual (res[0], res[1]);
assertEqual (res[1], res[2]);
assertEqual (res[2], res[3]);
assertEqual (res[3], res[4]);
int graph;
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) << "std::strtod:\t" << std::setw(10) << std::setfill(' ') << timeStdStrtod << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStdStrtod) << '\t' ;
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::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToDouble) << '\t' ;
graph = (int) (timeStream / timeStrToDouble); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "strToDouble:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtoD) << '\t' ;
graph = (int) (timeStream / timeStrtoD); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '#';
std::cout << std::endl;
}
void StringTest::setUp() void StringTest::setUp()
{ {
} }
@@ -1510,12 +1543,10 @@ CppUnit::Test* StringTest::suite()
CppUnit_addTest(pSuite, StringTest, testNumericStringLimit); 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, benchmarkStrToInt);
CppUnit_addTest(pSuite, StringTest, testIntToString); CppUnit_addTest(pSuite, StringTest, testIntToString);
CppUnit_addTest(pSuite, StringTest, testFloatToString); CppUnit_addTest(pSuite, StringTest, testFloatToString);
//CppUnit_addTest(pSuite, StringTest, benchmarkFloatToStr);
CppUnit_addTest(pSuite, StringTest, testJSONString); CppUnit_addTest(pSuite, StringTest, testJSONString);
CppUnit_addTest(pSuite, StringTest, conversionBenchmarks);
return pSuite; return pSuite;
} }

View File

@@ -19,6 +19,7 @@
#include "Poco/NumericString.h" #include "Poco/NumericString.h"
#include "Poco/MemoryStream.h" #include "Poco/MemoryStream.h"
#include "Poco/NumberFormatter.h" #include "Poco/NumberFormatter.h"
#include <limits>
class StringTest: public CppUnit::TestCase class StringTest: public CppUnit::TestCase
@@ -53,12 +54,14 @@ public:
void testNumericStringLimit(); void testNumericStringLimit();
void testStringToFloatError(); void testStringToFloatError();
void testNumericLocale(); void testNumericLocale();
void benchmarkStrToFloat();
void benchmarkStrToInt();
void testIntToString(); void testIntToString();
void testFloatToString(); void testFloatToString();
void conversionBenchmarks();
void benchmarkFloatToStr(); void benchmarkFloatToStr();
void benchmarkStrToFloat();
void benchmarkStrToInt();
void testJSONString(); void testJSONString();
@@ -128,7 +131,6 @@ private:
assertFalse(s == std::numeric_limits<Smaller>::min()); assertFalse(s == std::numeric_limits<Smaller>::min());
assertTrue(Poco::strToInt<Smaller>(val, s, 10)); assertTrue(Poco::strToInt<Smaller>(val, s, 10));
assertTrue (s == std::numeric_limits<Smaller>::min()); assertTrue (s == std::numeric_limits<Smaller>::min());
assertTrue(s == std::numeric_limits<Smaller>::min());
--l; val = Poco::NumberFormatter::format(l); --l; val = Poco::NumberFormatter::format(l);
assertFalse(Poco::strToInt<Smaller>(val, s, 10)); assertFalse(Poco::strToInt<Smaller>(val, s, 10));
--l; val = Poco::NumberFormatter::format(l); --l; val = Poco::NumberFormatter::format(l);
@@ -143,6 +145,21 @@ private:
assertFalse(Poco::strToInt<Smaller>(val, s, 10)); assertFalse(Poco::strToInt<Smaller>(val, s, 10));
} }
template <typename T>
void multiplyOverflow()
{
T m = static_cast<T>(10);
T t = 0;
T f = std::numeric_limits<T>::max()/m;
assertTrue (Poco::safeMultiply(t, f, m));
f += 1;
assertFalse (Poco::safeMultiply(t, f, m));
f = std::numeric_limits<T>::min()/m;
assertTrue (Poco::safeMultiply(t, f, m));
f -= 1;
assertFalse (Poco::safeMultiply(t, f, m));
}
template <typename T> template <typename T>
bool parseStream(const std::string& s, T& value) bool parseStream(const std::string& s, T& value)
{ {