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

Proposed by Paul J. Lucas
Status: Merged
Approved by: Matthias Brantner
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 Approve
Paul J. Lucas Approve
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.
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Paul J. Lucas (paul-lucas) :
review: Approve
Revision history for this message
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!

Revision history for this message
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.

Revision history for this message
Matthias Brantner (matthias-brantner) :
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
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
=== modified file 'src/util/string_util.cpp'
--- src/util/string_util.cpp 2013-01-07 14:49:20 +0000
+++ src/util/string_util.cpp 2013-01-10 23:41:23 +0000
@@ -21,6 +21,7 @@
21#include "ascii_util.h"21#include "ascii_util.h"
22#include "cxx_util.h"22#include "cxx_util.h"
23#include "string_util.h"23#include "string_util.h"
24#include "zorbatypes/zstring.h"
2425
25#ifdef WIN3226#ifdef WIN32
26namespace std {27namespace std {
@@ -55,67 +56,73 @@
5556
56///////////////////////////////////////////////////////////////////////////////57///////////////////////////////////////////////////////////////////////////////
5758
58#define ENABLE_CLIPPING 059static void check_errno( char const *buf, char const *end ) {
59
60template<typename T>
61static void check_parse_number( char const *s, char *end, T *result ) {
62 if ( errno == ERANGE ) {60 if ( errno == ERANGE ) {
63 if ( result ) {61 zstring const s( buf, end );
64#if ENABLE_CLIPPING62 throw std::range_error(
65 if ( *ascii::trim_start_whitespace( s ) == '-' )63 BUILD_STRING( '"', s, "\": number too big/small" )
66 *result = numeric_limits<T>::min();64 );
67 else
68 *result = numeric_limits<T>::max();
69#endif /* ENABLE_CLIPPING */
70 } else
71 throw std::range_error(
72 BUILD_STRING( '"', s, "\": number too big/small" )
73 );
74 }65 }
75 if ( end == s )66}
76 throw std::invalid_argument( BUILD_STRING( '"', s, "\": no digits" ) );67
77 for ( ; *end; ++end ) // remaining characters, if any, ...68static void check_parse_number( char const *buf, char const *end,
78 if ( !ascii::is_space( *end ) ) // ... may only be whitespace69 bool check_trailing_chars ) {
79 throw std::invalid_argument(70 if ( end == buf )
80 BUILD_STRING( '"', *end, "\": invalid character" )71 throw std::invalid_argument( BUILD_STRING( '"', buf, "\": no digits" ) );
81 );72 if ( check_trailing_chars )
82}73 for ( ; *end; ++end ) // remaining characters, if any, ...
8374 if ( !ascii::is_space( *end ) ) // ... may only be whitespace
84double atod( char const *s ) {75 throw std::invalid_argument(
85 char *end;76 BUILD_STRING( '"', *end, "\": invalid character" )
86 errno = 0;77 );
87 double result = std::strtod( s, &end );78}
88 check_parse_number( s, end, &result );79
89 return result;80#define ATON_PREAMBLE() \
90}81 bool check_trailing_chars; \
9182 char const *pc; \
92float atof( char const *s ) {83 if ( end ) { \
93 char *end;84 check_trailing_chars = false; \
94 errno = 0;85 } else { \
95 float result = std::strtof( s, &end );86 end = &pc; \
96 check_parse_number( s, end, &result );87 check_trailing_chars = true; \
97 return result;88 } \
98}89 errno = 0
9990
100long long atoll( char const *s ) {91///////////////////////////////////////////////////////////////////////////////
101 char *end;92
102 errno = 0;93double atod( char const *buf, char const **end ) {
103 long long const result = std::strtoll( s, &end, 10 );94 ATON_PREAMBLE();
104 check_parse_number( s, end, static_cast<long long*>( nullptr ) );95 double const result = std::strtod( buf, (char**)end );
105 return result;96 check_parse_number( buf, *end, check_trailing_chars );
106}97 return result;
10798}
108unsigned long long atoull( char const *s ) {99
100float atof( char const *buf, char const **end ) {
101 ATON_PREAMBLE();
102 float const result = std::strtof( buf, (char**)end );
103 check_parse_number( buf, *end, check_trailing_chars );
104 return result;
105}
106
107long long atoll( char const *buf, char const **end ) {
108 ATON_PREAMBLE();
109 long long const result = std::strtoll( buf, (char**)end, 10 );
110 check_errno( buf, *end );
111 check_parse_number( buf, *end, check_trailing_chars );
112 return result;
113}
114
115unsigned long long atoull( char const *buf, char const **end ) {
116 ATON_PREAMBLE();
109 //117 //
110 // We have to check for '-' ourselves since strtoull(3) allows it (oddly).118 // We have to check for '-' ourselves since strtoull(3) allows it (oddly).
111 //119 //
112 s = ascii::trim_start_whitespace( s );120 buf = ascii::trim_start_whitespace( buf );
113 bool const minus = *s == '-';121 bool const minus = *buf == '-';
114122
115 char *end;123 unsigned long long const result = std::strtoull( buf, (char**)end, 10 );
116 errno = 0;124 check_errno( buf, *end );
117 unsigned long long const result = std::strtoull( s, &end, 10 );125 check_parse_number( buf, *end, check_trailing_chars );
118 check_parse_number( s, end, static_cast<unsigned long long*>( nullptr ) );
119126
120 if ( minus && result ) {127 if ( minus && result ) {
121 //128 //
@@ -123,7 +130,7 @@
123 // Hence, this allows "-0" and treats it as "0".130 // Hence, this allows "-0" and treats it as "0".
124 //131 //
125 throw std::invalid_argument(132 throw std::invalid_argument(
126 "\"-\": invalid character for unsigned integer"133 "'-': invalid character for unsigned integer"
127 );134 );
128 }135 }
129 return result;136 return result;
130137
=== modified file 'src/util/string_util.h'
--- src/util/string_util.h 2013-01-07 14:49:20 +0000
+++ src/util/string_util.h 2013-01-10 23:41:23 +0000
@@ -408,61 +408,76 @@
408/**408/**
409 * Parses the given string for a \c double.409 * Parses the given string for a \c double.
410 *410 *
411 * @param s The null-terminated C string to parse. Leading and trailing411 * @param buf The null-terminated C string to parse. Leading and trailing
412 * whitespace is ignored.412 * whitespace is ignored.
413 * @param end If not \c null, this is set to point to the character after the
414 * last numeric character parsed; if \c null, characters past the last numeric
415 * character may only be whitespace.
413 * @return Returns the \c double value.416 * @return Returns the \c double value.
414 * @throws invalid_argument if \a s contains characters other than digits or417 * @throws invalid_argument if \a buf contains characters other than digits or
415 * leading/trailing whitespace, or contains no digits at all.418 * leading/trailing whitespace, or contains no digits at all.
416 * @throws range_error if the number overflows/underflows.419 * @throws range_error if the number overflows/underflows.
417 */420 */
418double atod( char const *s );421double atod( char const *buf, char const **end = nullptr );
419422
420/**423/**
421 * Parses the given string for a \c float.424 * Parses the given string for a \c float.
422 *425 *
423 * @param s The null-terminated C string to parse. Leading and trailing426 * @param buf The null-terminated C string to parse. Leading and trailing
424 * whitespace is ignored.427 * whitespace is ignored.
428 * @param end If not \c null, this is set to point to the character after the
429 * last numeric character parsed; if \c null, characters past the last numeric
430 * character may only be whitespace.
425 * @return Returns the \c float value.431 * @return Returns the \c float value.
426 * @throws invalid_argument if \a s contains characters other than digits or432 * @throws invalid_argument if \a buf contains characters other than digits or
427 * leading/trailing whitespace, or contains no digits at all.433 * leading/trailing whitespace, or contains no digits at all.
428 * @throws range_error if the number overflows/underflows.434 * @throws range_error if the number overflows/underflows.
429 */435 */
430float atof( char const *s );436float atof( char const *buf, char const **end = nullptr );
431437
432/**438/**
433 * Parses the given string for a <code>long lomg</code>.439 * Parses the given string for a <code>long lomg</code>.
434 *440 *
435 * @param s The null-terminated C string to parse. Leading and trailing441 * @param buf The null-terminated C string to parse. Leading and trailing
436 * whitespace is ignored.442 * whitespace is ignored.
443 * @param end If not \c null, this is set to point to the character after the
444 * last numeric character parsed; if \c null, characters past the last numeric
445 * character may only be whitespace.
437 * @return Returns the <code>long long</code> value.446 * @return Returns the <code>long long</code> value.
438 * @throws invalid_argument if \a s contains characters other than digits or447 * @throws invalid_argument if \a buf contains characters other than digits or
439 * leading/trailing whitespace, or contains no digits at all.448 * leading/trailing whitespace, or contains no digits at all.
440 * @throws range_error if the number overflows/underflows.449 * @throws range_error if the number overflows/underflows.
441 */450 */
442long long atoll( char const *s );451long long atoll( char const *buf, char const **end = nullptr );
443452
444/**453/**
445 * Parses the given string for an <code>unsigned long lomg</code>.454 * Parses the given string for an <code>unsigned long lomg</code>.
446 *455 *
447 * @param s The null-terminated C string to parse. Leading and trailing456 * @param buf The null-terminated C string to parse. Leading and trailing
448 * whitespace is ignored.457 * whitespace is ignored.
458 * @param end If not \c null, this is set to point to the character after the
459 * last numeric character parsed; if \c null, characters past the last numeric
460 * character may only be whitespace.
449 * @return Returns the <code>unsigned long long</code> value.461 * @return Returns the <code>unsigned long long</code> value.
450 * @throws invalid_argument if \a s contains characters other than digits or462 * @throws invalid_argument if \a buf contains characters other than digits or
451 * leading/trailing whitespace, or contains no digits at all.463 * leading/trailing whitespace, or contains no digits at all.
452 * @throws range_error if the number overflows/underflows.464 * @throws range_error if the number overflows/underflows.
453 */465 */
454unsigned long long atoull( char const *s );466unsigned long long atoull( char const *buf, char const **end = nullptr );
455467
456/**468/**
457 * Parses the given string for a C++ signed integral type.469 * Parses the given string for a C++ signed integral type.
458 *470 *
459 * @tparam IntegralType The C++ signed integral type to parse for.471 * @tparam IntegralType The C++ signed integral type to parse for.
460 * @param s The null-terminated C string to parse. Leading and trailing472 * @param buf The null-terminated C string to parse. Leading and trailing
461 * whitespace is ignored.473 * whitespace is ignored.
474 * @param end If not \c null, this is set to point to the character after the
475 * last numeric character parsed; if \c null, characters past the last numeric
476 * character may only be whitespace.
462 * @return Returns the \c IntegralType value.477 * @return Returns the \c IntegralType value.
463 * @throws invalid_argument if \a s contains characters other than digits or478 * @throws invalid_argument if \a buf contains characters other than digits, a
464 * leading/trailing whitespace, or contains no digits at all.479 * sign, or leading/trailing whitespace, or contains no digits at all.
465 * @throws range_error if the number overflows/underflows.480 * @throws range_error if the number is either too small or too big.
466 */481 */
467template<typename IntegralType> inline482template<typename IntegralType> inline
468//483//
@@ -473,8 +488,8 @@
473typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value488typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
474 && ZORBA_TR1_NS::is_signed<IntegralType>::value,489 && ZORBA_TR1_NS::is_signed<IntegralType>::value,
475 IntegralType>::type490 IntegralType>::type
476aton( char const *s ) {491aton( char const *buf, char const **end = nullptr ) {
477 long long const result = atoll( s );492 long long const result = atoll( buf, end );
478 if ( result < std::numeric_limits<IntegralType>::min() ||493 if ( result < std::numeric_limits<IntegralType>::min() ||
479 result > std::numeric_limits<IntegralType>::max() )494 result > std::numeric_limits<IntegralType>::max() )
480 throw std::range_error(495 throw std::range_error(
@@ -484,60 +499,137 @@
484}499}
485500
486/**501/**
502 * Parses the given string for a C++ signed integral type.
503 *
504 * @tparam IntegralType The C++ signed integral type to parse for.
505 * @param buf The null-terminated C string to parse. Leading and trailing
506 * whitespace is ignored.
507 * @param low The lower acceptable bound.
508 * @param high the higher acceptable bound.
509 * @param end If not \c null, this is set to point to the character after the
510 * last numeric character parsed; if \c null, characters past the last numeric
511 * character may only be whitespace.
512 * @return Returns the \c IntegralType value.
513 * @throws invalid_argument if \a buf contains characters other than digits, a
514 * sign, or leading/trailing whitespace, or contains no digits at all.
515 * @throws range_error if the number is either too small or too big.
516 */
517template<typename IntegralType> inline
518//
519// Note that the is_integral shouldn't be needed since is_signed means "is a
520// signed integral type", but Microsoft's implementation is broken and returns
521// true for floating point types as well.
522//
523typename std::enable_if<ZORBA_TR1_NS::is_integral<IntegralType>::value
524 && ZORBA_TR1_NS::is_signed<IntegralType>::value,
525 IntegralType>::type
526aton( char const *buf, IntegralType low, IntegralType high,
527 char const **end = nullptr ) {
528 long long const result = atoll( buf, end );
529 if ( result < low || result > high )
530 throw std::range_error(
531 BUILD_STRING(
532 '"', result, "\": number not in range ", low, '-', high
533 )
534 );
535 return static_cast<IntegralType>( result );
536}
537
538/**
487 * Parses the given string for a C++ unsigned integral types.539 * Parses the given string for a C++ unsigned integral types.
488 *540 *
489 * @tparam IntegralType The C++ unsigned integral type to parse for.541 * @tparam IntegralType The C++ unsigned integral type to parse for.
490 * @param s The null-terminated C string to parse. Leading and trailing542 * @param buf The null-terminated C string to parse. Leading and trailing
491 * whitespace is ignored.543 * whitespace is ignored.
544 * @param end If not \c null, this is set to point to the character after the
545 * last numeric character parsed; if \c null, characters past the last numeric
546 * character may only be whitespace.
492 * @return Returns the \c IntegralType value.547 * @return Returns the \c IntegralType value.
493 * @throws invalid_argument if \a s contains characters other than digits or548 * @throws invalid_argument if \a buf contains characters other than digits, a
494 * leading/trailing whitespace, or contains no digits at all.549 * sign, or leading/trailing whitespace, or contains no digits at all.
495 * @throws range_error if the number overflows/underflows.550 * @throws range_error if the number is either too small or too big.
496 */551 */
497template<typename IntegralType> inline552template<typename IntegralType> inline
498typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,553typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
499 IntegralType>::type554 IntegralType>::type
500aton( char const *s ) {555aton( char const *buf, char const **end = nullptr ) {
501 unsigned long long const result = atoull( s );556 unsigned long long const result = atoull( buf, end );
502 if ( result > std::numeric_limits<IntegralType>::max() )557 if ( result > std::numeric_limits<IntegralType>::max() )
503 throw std::range_error( BUILD_STRING( '"', result, "\": number too big" ) );558 throw std::range_error( BUILD_STRING( '"', result, "\": number too big" ) );
504 return static_cast<IntegralType>( result );559 return static_cast<IntegralType>( result );
505}560}
506561
507/**562/**
563 * Parses the given string for a C++ unsigned integral types.
564 *
565 * @tparam IntegralType The C++ unsigned integral type to parse for.
566 * @param buf The null-terminated C string to parse. Leading and trailing
567 * whitespace is ignored.
568 * @param low The lower acceptable bound.
569 * @param high the higher acceptable bound.
570 * @param end If not \c null, this is set to point to the character after the
571 * last numeric character parsed; if \c null, characters past the last numeric
572 * character may only be whitespace.
573 * @return Returns the \c IntegralType value.
574 * @throws invalid_argument if \a buf contains characters other than digits or
575 * leading/trailing whitespace, or contains no digits at all.
576 * @throws range_error if the number is either too small or too big.
577 */
578template<typename IntegralType> inline
579typename std::enable_if<ZORBA_TR1_NS::is_unsigned<IntegralType>::value,
580 IntegralType>::type
581aton( char const *buf, IntegralType low, IntegralType high,
582 char const **end = nullptr ) {
583 unsigned long long const result = atoull( buf, end );
584 if ( result < low || result > high )
585 throw std::range_error(
586 BUILD_STRING(
587 '"', result, "\": number not in range ", low, '-', high
588 )
589 );
590 return static_cast<IntegralType>( result );
591}
592
593/**
508 * Parses the given string for a C++ \c double type.594 * Parses the given string for a C++ \c double type.
509 *595 *
510 * @param s The null-terminated C string to parse. Leading and trailing596 * @param buf The null-terminated C string to parse. Leading and trailing
511 * whitespace is ignored.597 * whitespace is ignored.
598 * @param end If not \c null, this is set to point to the character after the
599 * last numeric character parsed; if \c null, characters past the last numeric
600 * character may only be whitespace.
512 * @return Returns the \c double value.601 * @return Returns the \c double value.
513 * @throws invalid_argument if \a s contains characters other than those for a602 * @throws invalid_argument if \a buf contains characters other than those for
514 * valid \c double value or leading/trailing whitespace, or contains no digits603 * a valid \c double value or leading/trailing whitespace, or contains no
515 * at all.604 * digits at all.
516 * @throws range_error if the number overflows/underflows.605 * @throws range_error if the number overflows/underflows.
517 */606 */
518template<typename NumericType> inline607template<typename NumericType> inline
519typename std::enable_if<ZORBA_TR1_NS::is_same<NumericType,double>::value,608typename std::enable_if<ZORBA_TR1_NS::is_same<NumericType,double>::value,
520 NumericType>::type609 NumericType>::type
521aton( char const *s ) {610aton( char const *buf, char const **end = nullptr ) {
522 return atod( s );611 return atod( buf, end );
523}612}
524613
525/**614/**
526 * Parses the given string for a C++ \c float type.615 * Parses the given string for a C++ \c float type.
527 *616 *
528 * @param s The null-terminated C string to parse. Leading and trailing617 * @param buf The null-terminated C string to parse. Leading and trailing
529 * whitespace is ignored.618 * whitespace is ignored.
619 * @param end If not \c null, this is set to point to the character after the
620 * last numeric character parsed; if \c null, characters past the last numeric
621 * character may only be whitespace.
530 * @return Returns the \c float value.622 * @return Returns the \c float value.
531 * @throws invalid_argument if \a s contains characters other than those for a623 * @throws invalid_argument if \a buf contains characters other than those for
532 * valid \c float value or leading/trailing whitespace, or contains no digits624 * a valid \c float value or leading/trailing whitespace, or contains no digits
533 * at all.625 * at all.
534 * @throws range_error if the number overflows/underflows.626 * @throws range_error if the number overflows/underflows.
535 */627 */
536template<typename NumericType> inline628template<typename NumericType> inline
537typename std::enable_if<ZORBA_TR1_NS::is_same<NumericType,float>::value,629typename std::enable_if<ZORBA_TR1_NS::is_same<NumericType,float>::value,
538 NumericType>::type630 NumericType>::type
539aton( char const *s ) {631aton( char const *buf, char const **end = nullptr ) {
540 return atof( s );632 return atof( buf, end );
541}633}
542634
543////////// To-string conversion ////////////////////////////////////////////////635////////// To-string conversion ////////////////////////////////////////////////

Subscribers

People subscribed via source and target branches