Skip to content

Commit 8a4eafd

Browse files
committed
- strToInt benchmark and more optimization
- warnmsg macro in CppUnit
1 parent bf74a4b commit 8a4eafd

5 files changed

Lines changed: 145 additions & 119 deletions

File tree

CHANGELOG

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
This is the changelog file for the POCO C++ Libraries.
22

33

4-
Release 1.5.0 (2012-09-??)
4+
Release 1.5.0 (2012-10-01)
55
==========================
66

77
- added JSON
@@ -43,6 +43,8 @@ Release 1.5.0 (2012-09-??)
4343
- fixed SF#307 Detect the SQL driver type at run time
4444
- added VS 2012 Projects/Solutions
4545
- enhanced and accelerated numeric parsing for integers and floats
46+
- fixed SF#590 Segfault on FreeBSD when stack size not rounded
47+
- added warn function and warnmsg macro in CppUnit
4648

4749
Release 1.4.4p1 (2012-??-??)
4850
============================

CppUnit/include/CppUnit/TestCase.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,9 @@ class CppUnit_API TestCase: public Test
162162
long lineNumber = CppUnitException::CPPUNIT_UNKNOWNLINENUMBER,
163163
const std::string& fileName = CppUnitException::CPPUNIT_UNKNOWNFILENAME);
164164

165-
void warn(const std::string& message = "",
166-
long lineNumber = CppUnitException::CPPUNIT_UNKNOWNLINENUMBER,
167-
const std::string& fileName = CppUnitException::CPPUNIT_UNKNOWNFILENAME);
165+
void warn(const std::string& message = "",
166+
long lineNumber = CppUnitException::CPPUNIT_UNKNOWNLINENUMBER,
167+
const std::string& fileName = CppUnitException::CPPUNIT_UNKNOWNFILENAME);
168168

169169

170170
private:
@@ -247,6 +247,9 @@ inline std::string TestCase::toString()
247247
#define failmsg(msg) \
248248
(this->fail(msg, __LINE__, __FILE__))
249249

250+
#define warnmsg(msg) \
251+
(this->fail(msg, __LINE__, __FILE__))
252+
250253

251254
} // namespace CppUnit
252255

Foundation/include/Poco/NumericString.h

Lines changed: 57 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -57,138 +57,106 @@ namespace Poco {
5757

5858

5959
inline char decimalSeparator()
60-
/// Returns decimal separator from global locale or
61-
/// default '.' for platforms where locale is unavailable.
60+
/// Returns decimal separator from global locale or
61+
/// default '.' for platforms where locale is unavailable.
6262
{
6363
#if !defined(POCO_NO_LOCALE)
64-
return std::use_facet<std::numpunct<char> >(std::locale()).decimal_point();
64+
return std::use_facet<std::numpunct<char> >(std::locale()).decimal_point();
6565
#else
66-
return '.';
66+
return '.';
6767
#endif
6868
}
6969

7070

7171
inline char thousandSeparator()
72-
/// Returns thousand separator from global locale or
73-
/// default ',' for platforms where locale is unavailable.
72+
/// Returns thousand separator from global locale or
73+
/// default ',' for platforms where locale is unavailable.
7474
{
7575
#if !defined(POCO_NO_LOCALE)
76-
return std::use_facet<std::numpunct<char> >(std::locale()).thousands_sep();
76+
return std::use_facet<std::numpunct<char> >(std::locale()).thousands_sep();
7777
#else
78-
return ',';
78+
return ',';
7979
#endif
8080
}
8181

8282

8383
template <typename I>
84-
bool strToInt(const char* pStr, I& result, short base = -1)
85-
/// Converts zero-terminated array to integer number;
86-
/// If base is equal to -1, this functin will try to determine
87-
/// the numeric base (using '0' prefix for octal, '0x' for
88-
/// hexadecimal and no prefix for decimal).
89-
/// Thousand separators are recognized for base10 and the locale
90-
/// and silently skipped but not verified for correct positioning.
91-
/// Returns true if succesful. If parsing was unsuccesful,
92-
/// the return value is false with result value undetermined.
84+
bool strToInt(const char* pStr, I& result, short base)
85+
/// Converts zero-terminated character array to integer number;
86+
/// Thousand separators are recognized for base10 and current locale;
87+
/// it is silently skipped but not verified for correct positioning.
88+
/// Function returns true if succesful. If parsing was unsuccesful,
89+
/// the return value is false with the result value undetermined.
9390
{
94-
if (!std::numeric_limits<I>::is_integer) return false;
95-
96-
if (!pStr || (pStr && *pStr == '\0')) return false;
97-
while ((*pStr != '\0') && (*pStr == ' ')) ++pStr;
91+
if (!pStr) return false;
92+
while (*pStr == ' ') ++pStr;
9893
if (*pStr == '\0') return false;
99-
100-
char sign = 1;
101-
102-
if (*pStr == '-')
94+
I sign = 1;
95+
if ((base == 10) && (*pStr == '-'))
10396
{
104-
++pStr;
10597
sign = -1;
106-
}
107-
else if (*pStr == '+') ++pStr;
108-
if (*pStr == '\0') return false;
109-
110-
result = 0;
111-
112-
if (*pStr == '0')
113-
{
114-
while ((*pStr != '\0') && (*pStr == '0')) ++pStr;
115-
if (*pStr == '\0')
116-
{
117-
result = 0;
118-
return true;
119-
}
120-
121-
if ((*pStr == 'x') || (*pStr == 'X'))
122-
{
123-
base = 0x10;
124-
++pStr;
125-
if (*pStr == '\0') return false;
126-
}
127-
else if (base == -1) base = 010;
128-
}
129-
else if (base == -1) base = 10;
130-
131-
while ((*pStr == '0'))
132-
{
133-
if (*pStr != '\0')
134-
{
135-
result = 0;
136-
return true;
137-
}
13898
++pStr;
13999
}
140-
if (*pStr == '\0') return false;
100+
else if (*pStr == '+') ++pStr;
141101

102+
// parser states:
103+
const char STATE_SIGNIFICANT_DIGITS = 1;
104+
char state = 0;
142105
const char thSep = thousandSeparator();
143-
bool allowDigits = true;
106+
107+
result = 0;
108+
I limitCheck = std::numeric_limits<I>::max() / base;
144109
for (; *pStr != '\0'; ++pStr)
145110
{
146111
switch (*pStr)
147112
{
148-
case '0': case '1': case '2': case '3': case '4':
113+
case 'x': case 'X':
114+
if (base != 0x10) return false;
115+
116+
case '0':
117+
if (state < STATE_SIGNIFICANT_DIGITS) break;
118+
119+
case '1': case '2': case '3': case '4':
149120
case '5': case '6': case '7':
150-
if (allowDigits)
151-
{
152-
if (result > (std::numeric_limits<I>::max() / base)) return false;
153-
result = result * base + (*pStr - '0');
154-
}
155-
else return false;
121+
if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
122+
if (result > limitCheck) return false;
123+
result = result * base + (*pStr - '0');
124+
156125
break;
157126

158127
case '8': case '9':
159-
if (allowDigits && (base == 10 || base == 16))
128+
if ((base == 10) || (base == 0x10))
160129
{
161-
if (result > (std::numeric_limits<I>::max() / base)) return false;
130+
if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
131+
if (result > limitCheck) return false;
162132
result = result * base + (*pStr - '0');
163133
}
164134
else return false;
135+
165136
break;
166137

167138
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
168-
if (allowDigits && base == 16)
169-
{
170-
if (result > (std::numeric_limits<I>::max() / base)) return false;
171-
result = result * base + (10 + *pStr - 'a');
172-
}
173-
else return false;
139+
if (base != 0x10) return false;
140+
if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
141+
if (result > limitCheck) return false;
142+
result = result * base + (10 + *pStr - 'a');
143+
174144
break;
175145

176146
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
177-
if (allowDigits && base == 16)
178-
{
179-
if (result > (std::numeric_limits<I>::max() / base)) return false;
180-
result = result * base + (10 + *pStr - 'A');
181-
}
182-
else
183-
return false;
147+
if (base != 0x10) return false;
148+
149+
if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
150+
if (result > limitCheck) return false;
151+
result = result * base + (10 + *pStr - 'A');
152+
184153
break;
185154

186155
case 'U':
187156
case 'u':
188157
case 'L':
189158
case 'l':
190-
allowDigits = false;
191-
break;
159+
goto done;
192160

193161
case '.':
194162
if ((base == 10) && (thSep == '.')) break;
@@ -199,23 +167,23 @@ bool strToInt(const char* pStr, I& result, short base = -1)
199167
else return false;
200168

201169
case ' ':
202-
if (base == 10) break;
203-
else return false;
170+
if ((base == 10) && (thSep == ' ')) break;
171+
goto done;
204172

205173
default:
206174
return false;
207175
}
208176
}
209177

210-
if ((base == 10) && (std::numeric_limits<I>::is_signed))
211-
result *= sign;
178+
done:
179+
if ((sign < 0) && (base == 10)) result *= sign;
212180

213181
return true;
214182
}
215183

216184

217185
template <typename I>
218-
bool strToInt(const std::string& str, I& result, short base = -1)
186+
bool strToInt(const std::string& str, I& result, short base)
219187
/// Converts string to integer number;
220188
/// This is a wrapper function, for details see see the
221189
/// bool strToInt(const char*, I&, short&) implementation.

Foundation/testsuite/src/StringTest.cpp

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -564,24 +564,63 @@ void StringTest::testNumericLocale()
564564
} catch (std::runtime_error& ex)
565565
{
566566
std::cout << ex.what() << std::endl;
567-
warn ("Locale not found, skipping test");
567+
warnmsg ("Locale not found, skipping test");
568568
}
569569
#endif
570570
}
571571

572572

573-
bool parseStream(const std::string& s, double& value)
573+
void StringTest::benchmarkStrToInt()
574574
{
575-
MemoryInputStream istr(s.data(), s.size());
576-
#if !defined(POCO_NO_LOCALE)
577-
istr.imbue(std::locale::classic());
578-
#endif
579-
istr >> value;
580-
return istr.eof() && !istr.fail();
575+
Poco::Stopwatch sw;
576+
int number = 123456789;
577+
std::string num = "123456789";
578+
int res;
579+
sw.start();
580+
for (int i = 0; i < 1000000; ++i) parseStream(num, res);
581+
sw.stop();
582+
std::cout << "parseStream Number: " << res << std::endl;
583+
double timeStream = sw.elapsed() / 1000.0;
584+
585+
char* pC = 0;
586+
sw.restart();
587+
for (int i = 0; i < 1000000; ++i) res = std::strtol(num.c_str(), &pC, 10);
588+
sw.stop();
589+
std::cout << "std::strtol Number: " << res << std::endl;
590+
double timeStrtol = sw.elapsed() / 1000.0;
591+
592+
sw.restart();
593+
for (int i = 0; i < 1000000; ++i) strToInt(num.c_str(), res, 10);
594+
sw.stop();
595+
std::cout << "strToInt Number: " << res << std::endl;
596+
double timeStrToInt = sw.elapsed() / 1000.0;
597+
598+
sw.restart();
599+
for (int i = 0; i < 1000000; ++i) std::sscanf(num.c_str(), "%d%c", &res);
600+
sw.stop();
601+
std::cout << "sscanf Number: " << res << std::endl;
602+
double timeScanf = sw.elapsed() / 1000.0;
603+
604+
int graph;
605+
std::cout << std::endl << "Timing and speedup relative to I/O stream:" << std::endl << std::endl;
606+
std::cout << std::setw(14) << "Stream:\t" << std::setw(10) << std::setfill(' ') << timeStream << "[ms]" << std::endl;
607+
608+
std::cout << std::setw(14) << "std::strtol:\t" << std::setw(10) << std::setfill(' ') << timeStrtol << "[ms]" <<
609+
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrtol) << '\t' ;
610+
graph = (int) (timeStream / timeStrtol); for (int i = 0; i < graph; ++i) std::cout << '|';
611+
612+
std::cout << std::endl << std::setw(14) << "strToInt:\t" << std::setw(10) << std::setfill(' ') << timeStrToInt << "[ms]" <<
613+
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeStrToInt) << '\t' ;
614+
graph = (int) (timeStream / timeStrToInt); for (int i = 0; i < graph; ++i) std::cout << '|';
615+
616+
std::cout << std::endl << std::setw(14) << "std::sscanf:\t" << std::setw(10) << std::setfill(' ') << timeScanf << "[ms]" <<
617+
std::setw(10) << std::setfill(' ') << "Speedup: " << (timeStream / timeScanf) << '\t' ;
618+
graph = (int) (timeStream / timeScanf); for (int i = 0; i < graph; ++i) std::cout << '|';
619+
std::cout << std::endl;
581620
}
582621

583622

584-
void StringTest::benchmark()
623+
void StringTest::benchmarkStrToFloat()
585624
{
586625
Poco::Stopwatch sw;
587626
double number = 1.23456e-123;
@@ -599,7 +638,7 @@ void StringTest::benchmark()
599638
sw.stop();
600639
std::cout << "std::strtod Number: " << res << std::endl;
601640
double timeStrtod = sw.elapsed() / 1000.0;
602-
641+
603642
sw.restart();
604643
char ou = 0;
605644
for (int i = 0; i < 1000000; ++i) strToFloat(num.c_str(), res, ou);
@@ -662,7 +701,8 @@ CppUnit::Test* StringTest::suite()
662701
CppUnit_addTest(pSuite, StringTest, testStringToFloat);
663702
CppUnit_addTest(pSuite, StringTest, testStringToFloatError);
664703
CppUnit_addTest(pSuite, StringTest, testNumericLocale);
665-
CppUnit_addTest(pSuite, StringTest, benchmark);
704+
//CppUnit_addTest(pSuite, StringTest, benchmarkStrToFloat);
705+
//CppUnit_addTest(pSuite, StringTest, benchmarkStrToInt);
666706

667707
return pSuite;
668708
}

0 commit comments

Comments
 (0)