Merge lp:~paul-lucas/zorba/pjl-misc into lp:zorba

Proposed by Paul J. Lucas on 2013-04-16
Status: Merged
Approved by: Matthias Brantner on 2013-04-16
Approved revision: 11180
Merged at revision: 11376
Proposed branch: lp:~paul-lucas/zorba/pjl-misc
Merge into: lp:zorba
Diff against target: 770 lines (+469/-143)
6 files modified
src/unit_tests/CMakeLists.txt (+1/-0)
src/unit_tests/test_ato_.cpp (+106/-0)
src/unit_tests/unit_test_list.h (+1/-0)
src/unit_tests/unit_tests.cpp (+1/-0)
src/util/string_util.cpp (+55/-9)
src/util/string_util.h (+305/-134)
To merge this branch: bzr merge lp:~paul-lucas/zorba/pjl-misc
Reviewer Review Type Date Requested Status
Matthias Brantner 2013-04-16 Approve on 2013-04-16
Paul J. Lucas Approve on 2013-04-16
Review via email: mp+159064@code.launchpad.net

Commit message

1. Added atoll( char const *buf, char const *end, char const **last );
2. Added more aton() functions.
3. Fixed handling of integer overflow.

Description of the change

1. Added atoll( char const *buf, char const *end, char const **last );
2. Added more aton() functions.
3. Fixed handling of integer overflow.

To post a comment you must log in.
Paul J. Lucas (paul-lucas) :
review: Approve
Zorba Build Bot (zorba-buildbot) wrote :

The attempt to merge lp:~paul-lucas/zorba/pjl-misc into lp:zorba failed. Below is the output from the failed tests.

CMake Error at /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake:275 (message):
  Validation queue job pjl-misc-2013-04-16T02-57-42.841Z is finished. The
  final status was:

  4 tests did not succeed - changes not commited.

Error in read script: /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake

Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job pjl-misc-2013-04-16T03-53-40.529Z is finished. The final status was:

All tests succeeded!

Zorba Build Bot (zorba-buildbot) wrote :

Voting does not meet specified criteria. Required: Approve > 1, Disapprove < 1, Needs Fixing < 1, Pending < 1, Needs Information < 1, Resubmit < 1. Got: 1 Approve.

lp:~paul-lucas/zorba/pjl-misc updated on 2013-04-16
11178. By Paul J. Lucas on 2013-04-16

Added test.

11179. By Paul J. Lucas on 2013-04-16

Merge from trunk.

11180. By Paul J. Lucas on 2013-04-16

Removed unnecessary #include.

review: Approve
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job pjl-misc-2013-04-16T20-02-45.412Z is finished. The final status was:

All tests succeeded!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/unit_tests/CMakeLists.txt'
2--- src/unit_tests/CMakeLists.txt 2013-03-21 00:54:36 +0000
3+++ src/unit_tests/CMakeLists.txt 2013-04-16 18:41:25 +0000
4@@ -14,6 +14,7 @@
5
6 SET(UNIT_TEST_SRCS
7 instantiate_string.cpp
8+ test_ato_.cpp
9 test_base64.cpp
10 test_base64_streambuf.cpp
11 test_hashmaps.cpp
12
13=== added file 'src/unit_tests/test_ato_.cpp'
14--- src/unit_tests/test_ato_.cpp 1970-01-01 00:00:00 +0000
15+++ src/unit_tests/test_ato_.cpp 2013-04-16 18:41:25 +0000
16@@ -0,0 +1,106 @@
17+/*
18+ * Copyright 2006-2008 The FLWOR Foundation.
19+ *
20+ * Licensed under the Apache License, Version 2.0 (the "License");
21+ * you may not use this file except in compliance with the License.
22+ * You may obtain a copy of the License at
23+ *
24+ * http://www.apache.org/licenses/LICENSE-2.0
25+ *
26+ * Unless required by applicable law or agreed to in writing, software
27+ * distributed under the License is distributed on an "AS IS" BASIS,
28+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29+ * See the License for the specific language governing permissions and
30+ * limitations under the License.
31+ */
32+
33+#include "stdafx.h"
34+#include <iostream>
35+#include <stdexcept>
36+#include <string>
37+
38+#include "util/cxx_util.h"
39+#include "util/string_util.h"
40+
41+using namespace std;
42+using namespace zorba;
43+
44+///////////////////////////////////////////////////////////////////////////////
45+
46+static int failures;
47+
48+static bool assert_true( int no, char const *expr, int line, bool result ) {
49+ if ( !result ) {
50+ cout << '#' << no << " FAILED, line " << line << ": " << expr << endl;
51+ ++failures;
52+ }
53+ return result;
54+}
55+
56+static void print_exception( int no, char const *expr, int line,
57+ std::exception const &e ) {
58+ assert_true( no, expr, line, false );
59+ cout << "+ exception: " << e.what() << endl;
60+}
61+
62+#define ASSERT_TRUE( NO, EXPR ) assert_true( NO, #EXPR, __LINE__, !!(EXPR) )
63+
64+#define ASSERT_NO_EXCEPTION( NO, EXPR ) \
65+ try { EXPR; } \
66+ catch ( exception const &e ) { print_exception( NO, #EXPR, __LINE__, e ); } \
67+ catch ( ... ) { assert_true( NO, #EXPR, __LINE__, false ); }
68+
69+#define ASSERT_EXCEPTION( NO, EXPR, EXCEPTION ) \
70+ try { EXPR; assert_true( NO, #EXPR, __LINE__, false ); } \
71+ catch ( EXCEPTION const& ) { } \
72+ catch ( ... ) { assert_true( NO, #EXPR, __LINE__, false ); }
73+
74+///////////////////////////////////////////////////////////////////////////////}
75+
76+static void test_atoll( int no, string const &s ) {
77+ char const *last;
78+ ASSERT_EXCEPTION(
79+ no, ztd::atoll( s.data(), s.data() + s.size(), &last ), range_error
80+ );
81+}
82+
83+static void test_atoull( int no, string const &s ) {
84+ char const *last;
85+ ASSERT_EXCEPTION(
86+ no, ztd::atoull( s.data(), s.data() + s.size(), &last ), range_error
87+ );
88+}
89+
90+///////////////////////////////////////////////////////////////////////////////
91+
92+namespace zorba {
93+namespace UnitTests {
94+
95+int test_ato_( int, char*[] ) {
96+ ascii::itoa_buf_type buf;
97+ string s;
98+ int test_no = 0;
99+
100+ // test overflow
101+ s = ascii::itoa( numeric_limits<long long>::max(), buf );
102+ s += '0';
103+ test_atoll( test_no++, s );
104+
105+ // test underflow
106+ s = ascii::itoa( numeric_limits<long long>::min(), buf );
107+ s += '0';
108+ test_atoll( test_no++, s );
109+
110+ // test overflow
111+ s = ascii::itoa( numeric_limits<unsigned long long>::max(), buf );
112+ s += '0';
113+ test_atoull( test_no++, s );
114+
115+ cout << failures << " test(s) failed\n";
116+ return failures ? 1 : 0;
117+}
118+
119+} // namespace UnitTests
120+} // namespace zorba
121+
122+/* vim:set et sw=2 ts=2: */
123
124=== modified file 'src/unit_tests/unit_test_list.h'
125--- src/unit_tests/unit_test_list.h 2013-03-21 00:54:36 +0000
126+++ src/unit_tests/unit_test_list.h 2013-04-16 18:41:25 +0000
127@@ -28,6 +28,7 @@
128
129 int runDebuggerProtocolTest(int argc, char* argv[]);
130
131+ int test_ato_( int, char*[] );
132 int test_base64( int, char*[] );
133 int test_base64_streambuf( int, char*[] );
134 int test_hashmaps( int argc, char* argv[] );
135
136=== modified file 'src/unit_tests/unit_tests.cpp'
137--- src/unit_tests/unit_tests.cpp 2013-03-21 00:54:36 +0000
138+++ src/unit_tests/unit_tests.cpp 2013-04-16 18:41:25 +0000
139@@ -37,6 +37,7 @@
140 */
141 void initializeTestList()
142 {
143+ libunittests["ato"] = test_ato_;
144 libunittests["base64"] = test_base64;
145 libunittests["base64_streambuf"] = test_base64_streambuf;
146
147
148=== modified file 'src/util/string_util.cpp'
149--- src/util/string_util.cpp 2013-03-31 15:53:11 +0000
150+++ src/util/string_util.cpp 2013-04-16 18:41:25 +0000
151@@ -56,14 +56,15 @@
152
153 ///////////////////////////////////////////////////////////////////////////////
154
155-static void too_big_or_small( char const *buf, char const *last ) {
156+static void throw_range_error( char const *buf, char const *last ) {
157+ errno = ERANGE;
158 zstring const s( buf, last );
159 throw std::range_error( BUILD_STRING( '"', s, "\": number too big/small" ) );
160 }
161
162 inline void check_errno( char const *buf, char const *last ) {
163 if ( errno == ERANGE )
164- too_big_or_small( buf, last );
165+ throw_range_error( buf, last );
166 }
167
168 static void check_trailing_chars_impl( char const *last ) {
169@@ -149,20 +150,65 @@
170 return result;
171 }
172
173+long long atoll( char const *buf, char const *end, char const **last ) {
174+ aton_context const ctx( last );
175+ long long n = 0;
176+ char const *s0 = ascii::trim_start_whitespace( buf, end - buf );
177+ char const *s = s0;
178+
179+ if ( s < end ) {
180+ bool minus = false;
181+ switch ( *s ) {
182+ case '-':
183+ minus = true;
184+ // no break;
185+ case '+':
186+ s0 = ++s;
187+ break;
188+ }
189+ for ( ; s < end && ascii::is_digit( *s ); ++s ) {
190+ long long const n_prev = n;
191+ n *= 10;
192+ if ( n / 10 != n_prev ) // see <http://stackoverflow.com/q/199333/99089>
193+ throw_range_error( buf, end );
194+ n += *s - '0';
195+ if ( n < n_prev )
196+ throw_range_error( buf, end );
197+ }
198+ if ( s == s0 )
199+ s = buf;
200+ else if ( minus )
201+ n = -n;
202+ }
203+
204+ *last = s;
205+ check_parse_number( buf, *last, ctx.check_trailing_chars() );
206+ return n;
207+}
208+
209 unsigned long long atoull( char const *buf, char const *end,
210 char const **last ) {
211 aton_context const ctx( last );
212 unsigned long long n = 0;
213- char const *s = ascii::trim_start_whitespace( buf, end - buf );
214+ char const *s0 = ascii::trim_start_whitespace( buf, end - buf );
215+ char const *s = s0;
216
217- for ( ; s < end && ascii::is_digit( *s ); ++s ) {
218- unsigned long long const n_prev = n;
219- n = n * 10 + *s - '0';
220- if ( n < n_prev ) {
221- errno = ERANGE;
222- too_big_or_small( buf, end );
223+ if ( s < end ) {
224+ if ( *s == '+' )
225+ s0 = ++s;
226+ for ( ; s < end && ascii::is_digit( *s ); ++s ) {
227+ unsigned long long const n_prev = n;
228+ n *= 10;
229+ if ( n / 10 != n_prev ) // see <http://stackoverflow.com/q/199333/99089>
230+ throw_range_error( buf, end );
231+ n += *s - '0';
232+ if ( n < n_prev )
233+ throw_range_error( buf, end );
234 }
235+ if ( s == s0 )
236+ s = buf;
237 }
238+
239 *last = s;
240 check_parse_number( buf, *last, ctx.check_trailing_chars() );
241 return n;
242
243=== modified file 'src/util/string_util.h'
244--- src/util/string_util.h 2013-03-26 00:25:41 +0000
245+++ src/util/string_util.h 2013-04-16 18:41:25 +0000
246@@ -414,13 +414,17 @@
247 * Parses the given string for a \c double.
248 *
249 * @param buf The null-terminated C string to parse. Leading and trailing
250- * whitespace is ignored.
251+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
252+ * \c - sign, followed by a sequence of decimal digits optionally containing a
253+ * single single \c . (decimal-point), optionally followed by an exponent
254+ * consisting of an \c e or \c E followed by an optional \c + or \c - sign
255+ * followed by a sequence of decimal digits.
256 * @param last If not \c null, this is set to point to the character after the
257 * last numeric character parsed; if \c null, characters past the last numeric
258 * character may only be whitespace.
259 * @return Returns the \c double value.
260- * @throws invalid_argument if \a buf contains characters other than digits or
261- * leading/trailing whitespace, or contains no digits at all.
262+ * @throws invalid_argument if \a buf contains characters other than as
263+ * described or contains no digits at all.
264 * @throws range_error if the number overflows/underflows.
265 */
266 double atod( char const *buf, char const **last = nullptr );
267@@ -429,13 +433,17 @@
268 * Parses the given string for a \c float.
269 *
270 * @param buf The null-terminated C string to parse. Leading and trailing
271- * whitespace is ignored.
272+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
273+ * \c - sign, followed by a sequence of decimal digits optionally containing a
274+ * single single \c . (decimal-point), optionally followed by an exponent
275+ * consisting of an \c e or \c E followed by an optional \c + or \c - sign
276+ * followed by a sequence of decimal digits.
277 * @param last If not \c null, this is set to point to the character after the
278 * last numeric character parsed; if \c null, characters past the last numeric
279 * character may only be whitespace.
280 * @return Returns the \c float value.
281- * @throws invalid_argument if \a buf contains characters other than digits or
282- * leading/trailing whitespace, or contains no digits at all.
283+ * @throws invalid_argument if \a buf contains characters other than as
284+ * described or contains no digits at all.
285 * @throws range_error if the number overflows/underflows.
286 */
287 float atof( char const *buf, char const **last = nullptr );
288@@ -444,28 +452,47 @@
289 * Parses the given string for a <code>long long</code>.
290 *
291 * @param buf The null-terminated C string to parse. Leading and trailing
292- * whitespace is ignored.
293+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
294+ * \c - sign, followed by a sequence of decimal digits.
295 * @param last If not \c null, this is set to point to the character after the
296 * last numeric character parsed; if \c null, characters past the last numeric
297 * character may only be whitespace.
298 * @return Returns the <code>long long</code> value.
299- * @throws invalid_argument if \a buf contains characters other than digits or
300- * leading/trailing whitespace, or contains no digits at all.
301+ * @throws invalid_argument if \a buf contains characters other than as
302+ * described or contains no digits at all.
303 * @throws range_error if the number overflows/underflows.
304 */
305 long long atoll( char const *buf, char const **last = nullptr );
306
307 /**
308+ * Parses the given string for a <code>long long</code>.
309+ *
310+ * @param buf The C string to parse; it need not be null-terminated. Leading
311+ * and trailing whitespace is ignored. After any leading whitespace, there may
312+ * be a \c + or \c - sign, followed by a sequence of decimal digits.
313+ * @param end A pointer to one past the last character to parse.
314+ * @param last If not \c null, this is set to point to the character after the
315+ * last numeric character parsed; if \c null, characters past the last numeric
316+ * character may only be whitespace.
317+ * @return Returns the <code>long long</code> value.
318+ * @throws invalid_argument if \a buf contains characters other than as
319+ * described or contains no digits at all.
320+ * @throws range_error if the number overflows.
321+ */
322+long long atoll( char const *buf, char const *end, char const **last );
323+
324+/**
325 * Parses the given string for an <code>unsigned long long</code>.
326 *
327 * @param buf The null-terminated C string to parse. Leading and trailing
328- * whitespace is ignored.
329+ * whitespace is ignored. After any leading whitespace, there may be a \c +
330+ * sign, followed by a sequence of decimal digits.
331 * @param last If not \c null, this is set to point to the character after the
332 * last numeric character parsed; if \c null, characters past the last numeric
333 * character may only be whitespace.
334 * @return Returns the <code>unsigned long long</code> value.
335- * @throws invalid_argument if \a buf contains characters other than digits or
336- * leading/trailing whitespace, or contains no digits at all.
337+ * @throws invalid_argument if \a buf contains characters other than as
338+ * described or contains no digits at all.
339 * @throws range_error if the number overflows.
340 */
341 unsigned long long atoull( char const *buf, char const **last = nullptr );
342@@ -474,14 +501,15 @@
343 * Parses the given string for an <code>unsigned long long</code>.
344 *
345 * @param buf The C string to parse; it need not be null-terminated. Leading
346- * and trailing whitespace is ignored.
347+ * and trailing whitespace is ignored. After any leading whitespace, there may
348+ * be a \c + sign, followed by a sequence of decimal digits.
349 * @param end A pointer to one past the last character to parse.
350 * @param last If not \c null, this is set to point to the character after the
351 * last numeric character parsed; if \c null, characters past the last numeric
352 * character may only be whitespace.
353 * @return Returns the <code>unsigned long long</code> value.
354- * @throws invalid_argument if \a buf contains characters other than digits or
355- * leading/trailing whitespace, or contains no digits at all.
356+ * @throws invalid_argument if \a buf contains characters other than as
357+ * described or contains no digits at all.
358 * @throws range_error if the number overflows.
359 */
360 unsigned long long atoull( char const *buf, char const *end,
361@@ -492,117 +520,254 @@
362 *
363 * @tparam IntegralType The C++ signed integral type to parse for.
364 * @param buf The null-terminated C string to parse. Leading and trailing
365- * whitespace is ignored.
366- * @param last If not \c null, this is set to point to the character after the
367- * last numeric character parsed; if \c null, characters past the last numeric
368- * character may only be whitespace.
369- * @return Returns the \c IntegralType value.
370- * @throws invalid_argument if \a buf contains characters other than digits, a
371- * sign, or leading/trailing whitespace, or contains no digits at all.
372- * @throws range_error if the number is either too small or too big.
373- */
374-template<typename IntegralType> inline
375-//
376-// Note that the is_integral shouldn't be needed since is_signed means "is a
377-// signed integral type", but Microsoft's implementation is broken and returns
378-// true for floating point types as well.
379-//
380-typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
381- && ZORBA_TR1_NS::is_signed<IntegralType>::value,
382- IntegralType>::type
383-aton( char const *buf, char const **last = nullptr ) {
384- long long const result = atoll( buf, last );
385- if ( result < std::numeric_limits<IntegralType>::min() ||
386- result > std::numeric_limits<IntegralType>::max() )
387- throw std::range_error(
388- BUILD_STRING( '"', result, "\": number too big/small" )
389- );
390- return static_cast<IntegralType>( result );
391-}
392-
393-/**
394- * Parses the given string for a C++ signed integral type.
395- *
396- * @tparam IntegralType The C++ signed integral type to parse for.
397- * @param buf The null-terminated C string to parse. Leading and trailing
398- * whitespace is ignored.
399- * @param low The lower acceptable bound.
400- * @param high the higher acceptable bound.
401- * @param last If not \c null, this is set to point to the character after the
402- * last numeric character parsed; if \c null, characters past the last numeric
403- * character may only be whitespace.
404- * @return Returns the \c IntegralType value.
405- * @throws invalid_argument if \a buf contains characters other than digits, a
406- * sign, or leading/trailing whitespace, or contains no digits at all.
407- * @throws range_error if the number is either too small or too big.
408- */
409-template<typename IntegralType> inline
410-//
411-// Note that the is_integral shouldn't be needed since is_signed means "is a
412-// signed integral type", but Microsoft's implementation is broken and returns
413-// true for floating point types as well.
414-//
415-typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
416- && ZORBA_TR1_NS::is_signed<IntegralType>::value,
417- IntegralType>::type
418-aton( char const *buf, IntegralType low, IntegralType high,
419- char const **last = nullptr ) {
420- long long const result = atoll( buf, last );
421- if ( result < low || result > high )
422- throw std::range_error(
423- BUILD_STRING(
424- '"', result, "\": number not in range ", low, '-', high
425- )
426- );
427- return static_cast<IntegralType>( result );
428-}
429-
430-/**
431- * Parses the given string for a C++ unsigned integral types.
432- *
433- * @tparam IntegralType The C++ unsigned integral type to parse for.
434- * @param buf The null-terminated C string to parse. Leading and trailing
435- * whitespace is ignored.
436- * @param last If not \c null, this is set to point to the character after the
437- * last numeric character parsed; if \c null, characters past the last numeric
438- * character may only be whitespace.
439- * @return Returns the \c IntegralType value.
440- * @throws invalid_argument if \a buf contains characters other than digits, a
441- * sign, or leading/trailing whitespace, or contains no digits at all.
442- * @throws range_error if the number is either too small or too big.
443- */
444-template<typename IntegralType> inline
445-typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
446- IntegralType>::type
447-aton( char const *buf, char const **last = nullptr ) {
448- unsigned long long const result = atoull( buf, last );
449- if ( result > std::numeric_limits<IntegralType>::max() )
450- throw std::range_error( BUILD_STRING( '"', result, "\": number too big" ) );
451- return static_cast<IntegralType>( result );
452-}
453-
454-/**
455- * Parses the given string for a C++ unsigned integral types.
456- *
457- * @tparam IntegralType The C++ unsigned integral type to parse for.
458- * @param buf The null-terminated C string to parse. Leading and trailing
459- * whitespace is ignored.
460- * @param low The lower acceptable bound.
461- * @param high the higher acceptable bound.
462- * @param last If not \c null, this is set to point to the character after the
463- * last numeric character parsed; if \c null, characters past the last numeric
464- * character may only be whitespace.
465- * @return Returns the \c IntegralType value.
466- * @throws invalid_argument if \a buf contains characters other than digits or
467- * leading/trailing whitespace, or contains no digits at all.
468- * @throws range_error if the number is either too small or too big.
469- */
470-template<typename IntegralType> inline
471-typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
472- IntegralType>::type
473-aton( char const *buf, IntegralType low, IntegralType high,
474- char const **last = nullptr ) {
475- unsigned long long const result = atoull( buf, last );
476+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
477+ * \c - sign, followed by a sequence of decimal digits.
478+ * @param last If not \c null, this is set to point to the character after the
479+ * last numeric character parsed; if \c null, characters past the last numeric
480+ * character may only be whitespace.
481+ * @return Returns the \c IntegralType value.
482+ * @throws invalid_argument if \a buf contains characters other than as
483+ * described or contains no digits at all.
484+ * @throws range_error if the number is either too small or too big.
485+ */
486+template<typename IntegralType> inline
487+//
488+// Note that the is_integral shouldn't be needed since is_signed means "is a
489+// signed integral type", but Microsoft's implementation is broken and returns
490+// true for floating point types as well.
491+//
492+typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
493+ && ZORBA_TR1_NS::is_signed<IntegralType>::value,
494+ IntegralType>::type
495+aton( char const *buf, char const **last = nullptr ) {
496+ long long const result = atoll( buf, last );
497+ if ( result < std::numeric_limits<IntegralType>::min() ||
498+ result > std::numeric_limits<IntegralType>::max() )
499+ throw std::range_error(
500+ BUILD_STRING( '"', result, "\": number too big/small" )
501+ );
502+ return static_cast<IntegralType>( result );
503+}
504+
505+/**
506+ * Parses the given string for a C++ signed integral type.
507+ *
508+ * @tparam IntegralType The C++ signed integral type to parse for.
509+ * @param buf The null-terminated C string to parse. Leading and trailing
510+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
511+ * \c - sign, followed by a sequence of decimal digits.
512+ * @param low The lower acceptable bound.
513+ * @param high the higher acceptable bound.
514+ * @param last If not \c null, this is set to point to the character after the
515+ * last numeric character parsed; if \c null, characters past the last numeric
516+ * character may only be whitespace.
517+ * @return Returns the \c IntegralType value.
518+ * @throws invalid_argument if \a buf contains characters other than as
519+ * described or contains no digits at all.
520+ * @throws range_error if the number is either too small or too big.
521+ */
522+template<typename IntegralType> inline
523+//
524+// Note that the is_integral shouldn't be needed since is_signed means "is a
525+// signed integral type", but Microsoft's implementation is broken and returns
526+// true for floating point types as well.
527+//
528+typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
529+ && ZORBA_TR1_NS::is_signed<IntegralType>::value,
530+ IntegralType>::type
531+aton( char const *buf, IntegralType low, IntegralType high,
532+ char const **last = nullptr ) {
533+ long long const result = atoll( buf, last );
534+ if ( result < low || result > high )
535+ throw std::range_error(
536+ BUILD_STRING(
537+ '"', result, "\": number not in range ", low, '-', high
538+ )
539+ );
540+ return static_cast<IntegralType>( result );
541+}
542+
543+/**
544+ * Parses the given string for a C++ signed integral type.
545+ *
546+ * @tparam IntegralType The C++ signed integral type to parse for.
547+ * @param buf The C string to parse; it need not be null-terminated. Leading
548+ * and trailing whitespace is ignored. After any leading whitespace, there may
549+ * be a \c + or \c - sign, followed by a sequence of decimal digits.
550+ * @param end A pointer to one past the last character to parse.
551+ * @param last If not \c null, this is set to point to the character after the
552+ * last numeric character parsed; if \c null, characters past the last numeric
553+ * character may only be whitespace.
554+ * @return Returns the \c IntegralType value.
555+ * @throws invalid_argument if \a buf contains characters other than as
556+ * described or contains no digits at all.
557+ * @throws range_error if the number is either too small or too big.
558+ */
559+template<typename IntegralType> inline
560+//
561+// Note that the is_integral shouldn't be needed since is_signed means "is a
562+// signed integral type", but Microsoft's implementation is broken and returns
563+// true for floating point types as well.
564+//
565+typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
566+ && ZORBA_TR1_NS::is_signed<IntegralType>::value,
567+ IntegralType>::type
568+aton( char const *buf, char const *end, char const **last = nullptr ) {
569+ long long const result = atoll( buf, end, last );
570+ if ( result < std::numeric_limits<IntegralType>::min() ||
571+ result > std::numeric_limits<IntegralType>::max() )
572+ throw std::range_error(
573+ BUILD_STRING( '"', result, "\": number too big/small" )
574+ );
575+ return static_cast<IntegralType>( result );
576+}
577+
578+/**
579+ * Parses the given string for a C++ signed integral type.
580+ *
581+ * @tparam IntegralType The C++ signed integral type to parse for.
582+ * @param buf The null-terminated C string to parse. Leading and trailing
583+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
584+ * \c - sign, followed by a sequence of decimal digits.
585+ * @param end A pointer to one past the last character to parse.
586+ * @param low The lower acceptable bound.
587+ * @param high the higher acceptable bound.
588+ * @param last If not \c null, this is set to point to the character after the
589+ * last numeric character parsed; if \c null, characters past the last numeric
590+ * character may only be whitespace.
591+ * @return Returns the \c IntegralType value.
592+ * @throws invalid_argument if \a buf contains characters other than as
593+ * described or contains no digits at all.
594+ * @throws range_error if the number is either too small or too big.
595+ */
596+template<typename IntegralType> inline
597+//
598+// Note that the is_integral shouldn't be needed since is_signed means "is a
599+// signed integral type", but Microsoft's implementation is broken and returns
600+// true for floating point types as well.
601+//
602+typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
603+ && ZORBA_TR1_NS::is_signed<IntegralType>::value,
604+ IntegralType>::type
605+aton( char const *buf, char const *end, IntegralType low, IntegralType high,
606+ char const **last = nullptr ) {
607+ long long const result = atoll( buf, end, last );
608+ if ( result < low || result > high )
609+ throw std::range_error(
610+ BUILD_STRING(
611+ '"', result, "\": number not in range ", low, '-', high
612+ )
613+ );
614+ return static_cast<IntegralType>( result );
615+}
616+
617+/**
618+ * Parses the given string for a C++ unsigned integral types.
619+ *
620+ * @tparam IntegralType The C++ unsigned integral type to parse for.
621+ * @param buf The null-terminated C string to parse. Leading and trailing
622+ * whitespace is ignored. After any leading whitespace, there may be a \c +
623+ * sign, followed by a sequence of decimal digits.
624+ * @param last If not \c null, this is set to point to the character after the
625+ * last numeric character parsed; if \c null, characters past the last numeric
626+ * character may only be whitespace.
627+ * @return Returns the \c IntegralType value.
628+ * @throws invalid_argument if \a buf contains characters other than as
629+ * described or contains no digits at all.
630+ * @throws range_error if the number is either too small or too big.
631+ */
632+template<typename IntegralType> inline
633+typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
634+ IntegralType>::type
635+aton( char const *buf, char const **last = nullptr ) {
636+ unsigned long long const result = atoull( buf, last );
637+ if ( result > std::numeric_limits<IntegralType>::max() )
638+ throw std::range_error( BUILD_STRING( '"', result, "\": number too big" ) );
639+ return static_cast<IntegralType>( result );
640+}
641+
642+/**
643+ * Parses the given string for a C++ unsigned integral types.
644+ *
645+ * @tparam IntegralType The C++ unsigned integral type to parse for.
646+ * @param buf The null-terminated C string to parse. Leading and trailing
647+ * whitespace is ignored. After any leading whitespace, there may be a \c +
648+ * sign, followed by a sequence of decimal digits.
649+ * @param low The lower acceptable bound.
650+ * @param high the higher acceptable bound.
651+ * @param last If not \c null, this is set to point to the character after the
652+ * last numeric character parsed; if \c null, characters past the last numeric
653+ * character may only be whitespace.
654+ * @return Returns the \c IntegralType value.
655+ * @throws invalid_argument if \a buf contains characters other than as
656+ * described or contains no digits at all.
657+ * @throws range_error if the number is either too small or too big.
658+ */
659+template<typename IntegralType> inline
660+typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
661+ IntegralType>::type
662+aton( char const *buf, IntegralType low, IntegralType high,
663+ char const **last = nullptr ) {
664+ unsigned long long const result = atoull( buf, last );
665+ if ( result < low || result > high )
666+ throw std::range_error(
667+ BUILD_STRING(
668+ '"', result, "\": number not in range ", low, '-', high
669+ )
670+ );
671+ return static_cast<IntegralType>( result );
672+}
673+
674+/**
675+ * Parses the given string for a C++ unsigned integral types.
676+ *
677+ * @tparam IntegralType The C++ unsigned integral type to parse for.
678+ * @param buf The C string to parse; it need not be null-terminated. Leading
679+ * and trailing whitespace is ignored. After any leading whitespace, there may
680+ * be a \c + sign, followed by a sequence of decimal digits.
681+ * @param end A pointer to one past the last character to parse.
682+ * @param last If not \c null, this is set to point to the character after the
683+ * last numeric character parsed; if \c null, characters past the last numeric
684+ * character may only be whitespace.
685+ * @return Returns the \c IntegralType value.
686+ * @throws invalid_argument if \a buf contains characters other than as
687+ * described or contains no digits at all.
688+ * @throws range_error if the number is either too small or too big.
689+ */
690+template<typename IntegralType> inline
691+typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
692+ IntegralType>::type
693+aton( char const *buf, char const *end, char const **last = nullptr ) {
694+ unsigned long long const result = atoull( buf, end, last );
695+ if ( result > std::numeric_limits<IntegralType>::max() )
696+ throw std::range_error( BUILD_STRING( '"', result, "\": number too big" ) );
697+ return static_cast<IntegralType>( result );
698+}
699+
700+/**
701+ * Parses the given string for a C++ unsigned integral types.
702+ *
703+ * @tparam IntegralType The C++ unsigned integral type to parse for.
704+ * @param buf The C string to parse; it need not be null-terminated. Leading
705+ * and trailing whitespace is ignored. After any leading whitespace, there may
706+ * be a \c + sign, followed by a sequence of decimal digits.
707+ * @param end A pointer to one past the last character to parse.
708+ * @param low The lower acceptable bound.
709+ * @param high the higher acceptable bound.
710+ * @param last If not \c null, this is set to point to the character after the
711+ * last numeric character parsed; if \c null, characters past the last numeric
712+ * character may only be whitespace.
713+ * @return Returns the \c IntegralType value.
714+ * @throws invalid_argument if \a buf contains characters other than as
715+ * described or contains no digits at all.
716+ * @throws range_error if the number is either too small or too big.
717+ */
718+template<typename IntegralType> inline
719+typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
720+ IntegralType>::type
721+aton( char const *buf, char const *end, IntegralType low, IntegralType high,
722+ char const **last = nullptr ) {
723+ unsigned long long const result = atoull( buf, end, last );
724 if ( result < low || result > high )
725 throw std::range_error(
726 BUILD_STRING(
727@@ -616,14 +781,17 @@
728 * Parses the given string for a C++ \c double type.
729 *
730 * @param buf The null-terminated C string to parse. Leading and trailing
731- * whitespace is ignored.
732+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
733+ * \c - sign, followed by a sequence of decimal digits optionally containing a
734+ * single single \c . (decimal-point), optionally followed by an exponent
735+ * consisting of an \c e or \c E followed by an optional \c + or \c - sign
736+ * followed by a sequence of decimal digits.
737 * @param last If not \c null, this is set to point to the character after the
738 * last numeric character parsed; if \c null, characters past the last numeric
739 * character may only be whitespace.
740 * @return Returns the \c double value.
741- * @throws invalid_argument if \a buf contains characters other than those for
742- * a valid \c double value or leading/trailing whitespace, or contains no
743- * digits at all.
744+ * @throws invalid_argument if \a buf contains characters other than as
745+ * described or contains no digits at all.
746 * @throws range_error if the number overflows/underflows.
747 */
748 template<typename NumericType> inline
749@@ -637,14 +805,17 @@
750 * Parses the given string for a C++ \c float type.
751 *
752 * @param buf The null-terminated C string to parse. Leading and trailing
753- * whitespace is ignored.
754+ * whitespace is ignored. After any leading whitespace, there may be a \c + or
755+ * \c - sign, followed by a sequence of decimal digits optionally containing a
756+ * single single \c . (decimal-point), optionally followed by an exponent
757+ * consisting of an \c e or \c E followed by an optional \c + or \c - sign
758+ * followed by a sequence of decimal digits.
759 * @param last If not \c null, this is set to point to the character after the
760 * last numeric character parsed; if \c null, characters past the last numeric
761 * character may only be whitespace.
762 * @return Returns the \c float value.
763- * @throws invalid_argument if \a buf contains characters other than those for
764- * a valid \c float value or leading/trailing whitespace, or contains no digits
765- * at all.
766+ * @throws invalid_argument if \a buf contains characters other than as
767+ * described or contains no digits at all.
768 * @throws range_error if the number overflows/underflows.
769 */
770 template<typename NumericType> inline

Subscribers

People subscribed via source and target branches