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

Proposed by Paul J. Lucas on 2013-01-10
Status: Merged
Approved by: Matthias Brantner on 2013-01-11
Approved revision: 11029
Merged at revision: 11177
Proposed branch: lp:~paul-lucas/zorba/pjl-misc
Merge into: lp:zorba
Diff against target: 412 lines (+190/-91)
2 files modified
src/util/string_util.cpp (+63/-56)
src/util/string_util.h (+127/-35)
To merge this branch: bzr merge lp:~paul-lucas/zorba/pjl-misc
Reviewer Review Type Date Requested Status
Matthias Brantner 2013-01-11 Approve on 2013-01-11
Paul J. Lucas Approve on 2013-01-11
Review via email: mp+142815@code.launchpad.net

Commit message

aton() enhancement.

Description of the change

aton() enhancement.

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

Validation queue job pjl-misc-2013-01-10T23-45-42.555Z 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. Got: 1 Approve.

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

Validation queue job pjl-misc-2013-01-11T00-34-37.392Z 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/util/string_util.cpp'
2--- src/util/string_util.cpp 2013-01-07 14:49:20 +0000
3+++ src/util/string_util.cpp 2013-01-10 23:41:23 +0000
4@@ -21,6 +21,7 @@
5 #include "ascii_util.h"
6 #include "cxx_util.h"
7 #include "string_util.h"
8+#include "zorbatypes/zstring.h"
9
10 #ifdef WIN32
11 namespace std {
12@@ -55,67 +56,73 @@
13
14 ///////////////////////////////////////////////////////////////////////////////
15
16-#define ENABLE_CLIPPING 0
17-
18-template<typename T>
19-static void check_parse_number( char const *s, char *end, T *result ) {
20+static void check_errno( char const *buf, char const *end ) {
21 if ( errno == ERANGE ) {
22- if ( result ) {
23-#if ENABLE_CLIPPING
24- if ( *ascii::trim_start_whitespace( s ) == '-' )
25- *result = numeric_limits<T>::min();
26- else
27- *result = numeric_limits<T>::max();
28-#endif /* ENABLE_CLIPPING */
29- } else
30- throw std::range_error(
31- BUILD_STRING( '"', s, "\": number too big/small" )
32- );
33+ zstring const s( buf, end );
34+ throw std::range_error(
35+ BUILD_STRING( '"', s, "\": number too big/small" )
36+ );
37 }
38- if ( end == s )
39- throw std::invalid_argument( BUILD_STRING( '"', s, "\": no digits" ) );
40- for ( ; *end; ++end ) // remaining characters, if any, ...
41- if ( !ascii::is_space( *end ) ) // ... may only be whitespace
42- throw std::invalid_argument(
43- BUILD_STRING( '"', *end, "\": invalid character" )
44- );
45-}
46-
47-double atod( char const *s ) {
48- char *end;
49- errno = 0;
50- double result = std::strtod( s, &end );
51- check_parse_number( s, end, &result );
52- return result;
53-}
54-
55-float atof( char const *s ) {
56- char *end;
57- errno = 0;
58- float result = std::strtof( s, &end );
59- check_parse_number( s, end, &result );
60- return result;
61-}
62-
63-long long atoll( char const *s ) {
64- char *end;
65- errno = 0;
66- long long const result = std::strtoll( s, &end, 10 );
67- check_parse_number( s, end, static_cast<long long*>( nullptr ) );
68- return result;
69-}
70-
71-unsigned long long atoull( char const *s ) {
72+}
73+
74+static void check_parse_number( char const *buf, char const *end,
75+ bool check_trailing_chars ) {
76+ if ( end == buf )
77+ throw std::invalid_argument( BUILD_STRING( '"', buf, "\": no digits" ) );
78+ if ( check_trailing_chars )
79+ for ( ; *end; ++end ) // remaining characters, if any, ...
80+ if ( !ascii::is_space( *end ) ) // ... may only be whitespace
81+ throw std::invalid_argument(
82+ BUILD_STRING( '"', *end, "\": invalid character" )
83+ );
84+}
85+
86+#define ATON_PREAMBLE() \
87+ bool check_trailing_chars; \
88+ char const *pc; \
89+ if ( end ) { \
90+ check_trailing_chars = false; \
91+ } else { \
92+ end = &pc; \
93+ check_trailing_chars = true; \
94+ } \
95+ errno = 0
96+
97+///////////////////////////////////////////////////////////////////////////////
98+
99+double atod( char const *buf, char const **end ) {
100+ ATON_PREAMBLE();
101+ double const result = std::strtod( buf, (char**)end );
102+ check_parse_number( buf, *end, check_trailing_chars );
103+ return result;
104+}
105+
106+float atof( char const *buf, char const **end ) {
107+ ATON_PREAMBLE();
108+ float const result = std::strtof( buf, (char**)end );
109+ check_parse_number( buf, *end, check_trailing_chars );
110+ return result;
111+}
112+
113+long long atoll( char const *buf, char const **end ) {
114+ ATON_PREAMBLE();
115+ long long const result = std::strtoll( buf, (char**)end, 10 );
116+ check_errno( buf, *end );
117+ check_parse_number( buf, *end, check_trailing_chars );
118+ return result;
119+}
120+
121+unsigned long long atoull( char const *buf, char const **end ) {
122+ ATON_PREAMBLE();
123 //
124 // We have to check for '-' ourselves since strtoull(3) allows it (oddly).
125 //
126- s = ascii::trim_start_whitespace( s );
127- bool const minus = *s == '-';
128+ buf = ascii::trim_start_whitespace( buf );
129+ bool const minus = *buf == '-';
130
131- char *end;
132- errno = 0;
133- unsigned long long const result = std::strtoull( s, &end, 10 );
134- check_parse_number( s, end, static_cast<unsigned long long*>( nullptr ) );
135+ unsigned long long const result = std::strtoull( buf, (char**)end, 10 );
136+ check_errno( buf, *end );
137+ check_parse_number( buf, *end, check_trailing_chars );
138
139 if ( minus && result ) {
140 //
141@@ -123,7 +130,7 @@
142 // Hence, this allows "-0" and treats it as "0".
143 //
144 throw std::invalid_argument(
145- "\"-\": invalid character for unsigned integer"
146+ "'-': invalid character for unsigned integer"
147 );
148 }
149 return result;
150
151=== modified file 'src/util/string_util.h'
152--- src/util/string_util.h 2013-01-07 14:49:20 +0000
153+++ src/util/string_util.h 2013-01-10 23:41:23 +0000
154@@ -408,61 +408,76 @@
155 /**
156 * Parses the given string for a \c double.
157 *
158- * @param s The null-terminated C string to parse. Leading and trailing
159+ * @param buf The null-terminated C string to parse. Leading and trailing
160 * whitespace is ignored.
161+ * @param end If not \c null, this is set to point to the character after the
162+ * last numeric character parsed; if \c null, characters past the last numeric
163+ * character may only be whitespace.
164 * @return Returns the \c double value.
165- * @throws invalid_argument if \a s contains characters other than digits or
166+ * @throws invalid_argument if \a buf contains characters other than digits or
167 * leading/trailing whitespace, or contains no digits at all.
168 * @throws range_error if the number overflows/underflows.
169 */
170-double atod( char const *s );
171+double atod( char const *buf, char const **end = nullptr );
172
173 /**
174 * Parses the given string for a \c float.
175 *
176- * @param s The null-terminated C string to parse. Leading and trailing
177+ * @param buf The null-terminated C string to parse. Leading and trailing
178 * whitespace is ignored.
179+ * @param end If not \c null, this is set to point to the character after the
180+ * last numeric character parsed; if \c null, characters past the last numeric
181+ * character may only be whitespace.
182 * @return Returns the \c float value.
183- * @throws invalid_argument if \a s contains characters other than digits or
184+ * @throws invalid_argument if \a buf contains characters other than digits or
185 * leading/trailing whitespace, or contains no digits at all.
186 * @throws range_error if the number overflows/underflows.
187 */
188-float atof( char const *s );
189+float atof( char const *buf, char const **end = nullptr );
190
191 /**
192 * Parses the given string for a <code>long lomg</code>.
193 *
194- * @param s The null-terminated C string to parse. Leading and trailing
195+ * @param buf The null-terminated C string to parse. Leading and trailing
196 * whitespace is ignored.
197+ * @param end If not \c null, this is set to point to the character after the
198+ * last numeric character parsed; if \c null, characters past the last numeric
199+ * character may only be whitespace.
200 * @return Returns the <code>long long</code> value.
201- * @throws invalid_argument if \a s contains characters other than digits or
202+ * @throws invalid_argument if \a buf contains characters other than digits or
203 * leading/trailing whitespace, or contains no digits at all.
204 * @throws range_error if the number overflows/underflows.
205 */
206-long long atoll( char const *s );
207+long long atoll( char const *buf, char const **end = nullptr );
208
209 /**
210 * Parses the given string for an <code>unsigned long lomg</code>.
211 *
212- * @param s The null-terminated C string to parse. Leading and trailing
213+ * @param buf The null-terminated C string to parse. Leading and trailing
214 * whitespace is ignored.
215+ * @param end If not \c null, this is set to point to the character after the
216+ * last numeric character parsed; if \c null, characters past the last numeric
217+ * character may only be whitespace.
218 * @return Returns the <code>unsigned long long</code> value.
219- * @throws invalid_argument if \a s contains characters other than digits or
220+ * @throws invalid_argument if \a buf contains characters other than digits or
221 * leading/trailing whitespace, or contains no digits at all.
222 * @throws range_error if the number overflows/underflows.
223 */
224-unsigned long long atoull( char const *s );
225+unsigned long long atoull( char const *buf, char const **end = nullptr );
226
227 /**
228 * Parses the given string for a C++ signed integral type.
229 *
230 * @tparam IntegralType The C++ signed integral type to parse for.
231- * @param s The null-terminated C string to parse. Leading and trailing
232+ * @param buf The null-terminated C string to parse. Leading and trailing
233 * whitespace is ignored.
234+ * @param end If not \c null, this is set to point to the character after the
235+ * last numeric character parsed; if \c null, characters past the last numeric
236+ * character may only be whitespace.
237 * @return Returns the \c IntegralType value.
238- * @throws invalid_argument if \a s contains characters other than digits or
239- * leading/trailing whitespace, or contains no digits at all.
240- * @throws range_error if the number overflows/underflows.
241+ * @throws invalid_argument if \a buf contains characters other than digits, a
242+ * sign, or leading/trailing whitespace, or contains no digits at all.
243+ * @throws range_error if the number is either too small or too big.
244 */
245 template<typename IntegralType> inline
246 //
247@@ -473,8 +488,8 @@
248 typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
249 && ZORBA_TR1_NS::is_signed<IntegralType>::value,
250 IntegralType>::type
251-aton( char const *s ) {
252- long long const result = atoll( s );
253+aton( char const *buf, char const **end = nullptr ) {
254+ long long const result = atoll( buf, end );
255 if ( result < std::numeric_limits<IntegralType>::min() ||
256 result > std::numeric_limits<IntegralType>::max() )
257 throw std::range_error(
258@@ -484,60 +499,137 @@
259 }
260
261 /**
262+ * Parses the given string for a C++ signed integral type.
263+ *
264+ * @tparam IntegralType The C++ signed integral type to parse for.
265+ * @param buf The null-terminated C string to parse. Leading and trailing
266+ * whitespace is ignored.
267+ * @param low The lower acceptable bound.
268+ * @param high the higher acceptable bound.
269+ * @param end If not \c null, this is set to point to the character after the
270+ * last numeric character parsed; if \c null, characters past the last numeric
271+ * character may only be whitespace.
272+ * @return Returns the \c IntegralType value.
273+ * @throws invalid_argument if \a buf contains characters other than digits, a
274+ * sign, or leading/trailing whitespace, or contains no digits at all.
275+ * @throws range_error if the number is either too small or too big.
276+ */
277+template<typename IntegralType> inline
278+//
279+// Note that the is_integral shouldn't be needed since is_signed means "is a
280+// signed integral type", but Microsoft's implementation is broken and returns
281+// true for floating point types as well.
282+//
283+typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
284+ && ZORBA_TR1_NS::is_signed<IntegralType>::value,
285+ IntegralType>::type
286+aton( char const *buf, IntegralType low, IntegralType high,
287+ char const **end = nullptr ) {
288+ long long const result = atoll( buf, end );
289+ if ( result < low || result > high )
290+ throw std::range_error(
291+ BUILD_STRING(
292+ '"', result, "\": number not in range ", low, '-', high
293+ )
294+ );
295+ return static_cast<IntegralType>( result );
296+}
297+
298+/**
299 * Parses the given string for a C++ unsigned integral types.
300 *
301 * @tparam IntegralType The C++ unsigned integral type to parse for.
302- * @param s The null-terminated C string to parse. Leading and trailing
303+ * @param buf The null-terminated C string to parse. Leading and trailing
304 * whitespace is ignored.
305+ * @param end If not \c null, this is set to point to the character after the
306+ * last numeric character parsed; if \c null, characters past the last numeric
307+ * character may only be whitespace.
308 * @return Returns the \c IntegralType value.
309- * @throws invalid_argument if \a s contains characters other than digits or
310- * leading/trailing whitespace, or contains no digits at all.
311- * @throws range_error if the number overflows/underflows.
312+ * @throws invalid_argument if \a buf contains characters other than digits, a
313+ * sign, or leading/trailing whitespace, or contains no digits at all.
314+ * @throws range_error if the number is either too small or too big.
315 */
316 template<typename IntegralType> inline
317 typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
318 IntegralType>::type
319-aton( char const *s ) {
320- unsigned long long const result = atoull( s );
321+aton( char const *buf, char const **end = nullptr ) {
322+ unsigned long long const result = atoull( buf, end );
323 if ( result > std::numeric_limits<IntegralType>::max() )
324 throw std::range_error( BUILD_STRING( '"', result, "\": number too big" ) );
325 return static_cast<IntegralType>( result );
326 }
327
328 /**
329+ * Parses the given string for a C++ unsigned integral types.
330+ *
331+ * @tparam IntegralType The C++ unsigned integral type to parse for.
332+ * @param buf The null-terminated C string to parse. Leading and trailing
333+ * whitespace is ignored.
334+ * @param low The lower acceptable bound.
335+ * @param high the higher acceptable bound.
336+ * @param end If not \c null, this is set to point to the character after the
337+ * last numeric character parsed; if \c null, characters past the last numeric
338+ * character may only be whitespace.
339+ * @return Returns the \c IntegralType value.
340+ * @throws invalid_argument if \a buf contains characters other than digits or
341+ * leading/trailing whitespace, or contains no digits at all.
342+ * @throws range_error if the number is either too small or too big.
343+ */
344+template<typename IntegralType> inline
345+typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
346+ IntegralType>::type
347+aton( char const *buf, IntegralType low, IntegralType high,
348+ char const **end = nullptr ) {
349+ unsigned long long const result = atoull( buf, end );
350+ if ( result < low || result > high )
351+ throw std::range_error(
352+ BUILD_STRING(
353+ '"', result, "\": number not in range ", low, '-', high
354+ )
355+ );
356+ return static_cast<IntegralType>( result );
357+}
358+
359+/**
360 * Parses the given string for a C++ \c double type.
361 *
362- * @param s The null-terminated C string to parse. Leading and trailing
363+ * @param buf The null-terminated C string to parse. Leading and trailing
364 * whitespace is ignored.
365+ * @param end If not \c null, this is set to point to the character after the
366+ * last numeric character parsed; if \c null, characters past the last numeric
367+ * character may only be whitespace.
368 * @return Returns the \c double value.
369- * @throws invalid_argument if \a s contains characters other than those for a
370- * valid \c double value or leading/trailing whitespace, or contains no digits
371- * at all.
372+ * @throws invalid_argument if \a buf contains characters other than those for
373+ * a valid \c double value or leading/trailing whitespace, or contains no
374+ * digits at all.
375 * @throws range_error if the number overflows/underflows.
376 */
377 template<typename NumericType> inline
378 typename std::enable_if<ZORBA_TR1_NS::is_same<NumericType,double>::value,
379 NumericType>::type
380-aton( char const *s ) {
381- return atod( s );
382+aton( char const *buf, char const **end = nullptr ) {
383+ return atod( buf, end );
384 }
385
386 /**
387 * Parses the given string for a C++ \c float type.
388 *
389- * @param s The null-terminated C string to parse. Leading and trailing
390+ * @param buf The null-terminated C string to parse. Leading and trailing
391 * whitespace is ignored.
392+ * @param end If not \c null, this is set to point to the character after the
393+ * last numeric character parsed; if \c null, characters past the last numeric
394+ * character may only be whitespace.
395 * @return Returns the \c float value.
396- * @throws invalid_argument if \a s contains characters other than those for a
397- * valid \c float value or leading/trailing whitespace, or contains no digits
398+ * @throws invalid_argument if \a buf contains characters other than those for
399+ * a valid \c float value or leading/trailing whitespace, or contains no digits
400 * at all.
401 * @throws range_error if the number overflows/underflows.
402 */
403 template<typename NumericType> inline
404 typename std::enable_if<ZORBA_TR1_NS::is_same<NumericType,float>::value,
405 NumericType>::type
406-aton( char const *s ) {
407- return atof( s );
408+aton( char const *buf, char const **end = nullptr ) {
409+ return atof( buf, end );
410 }
411
412 ////////// To-string conversion ////////////////////////////////////////////////

Subscribers

People subscribed via source and target branches