From ae0cef35ae5a7bfd873fb87babdd4900cbdb073c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 22 Nov 2017 07:42:54 -0800 Subject: Changes imported from Abseil "staging" branch: - 55c7dd8ad1570b4e6ce2103ed4d4b6becdea0d96 Remove line continuations which require CMake >= 3.0. Al... by Jon Cohen - ee66ad72a90259d6286bbfea7241ed976bb0f6fb Change absl::ParseDuration() to avoid double. This allow... by Abseil Team - 89cf4cd49d8ff25cb3d29f06b2090029a2024e89 Internal change by Gennadiy Rozental - cdb5879bf6aaf6bbd2ad1fe4a2b144bbdf0389c7 Internal change by Gennadiy Rozental - e7b29d11bf24a63bf7637689ada8be7d619844fc Internal change by Gennadiy Rozental - 2d4fc08d5d64a7760ad6230eccdb5b8014c2b0c3 Update the exception-safety testing framework. by Jon Cohen GitOrigin-RevId: 55c7dd8ad1570b4e6ce2103ed4d4b6becdea0d96 Change-Id: I6b560cbc4570dfc5aa9a2f90e84d69904df7eac5 --- absl/time/duration.cc | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) (limited to 'absl/time/duration.cc') diff --git a/absl/time/duration.cc b/absl/time/duration.cc index f5081955d3bd..5e4f93136cdb 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc @@ -672,7 +672,7 @@ namespace { char* Format64(char* ep, int width, int64_t v) { do { --width; - *--ep = "0123456789"[v % 10]; + *--ep = '0' + (v % 10); // contiguous digits } while (v /= 10); while (--width >= 0) *--ep = '0'; // zero pad return ep; @@ -782,15 +782,32 @@ std::string FormatDuration(Duration d) { namespace { // A helper for ParseDuration() that parses a leading number from the given -// std::string and stores the result in *n. The given std::string pointer is modified -// to point to the first unconsumed char. -bool ConsumeDurationNumber(const char** start, double* n) { - const char* s = *start; - char* end = nullptr; - errno = 0; - *n = strtod(s, &end); - *start = end; - return !std::isspace(*s) && errno == 0 && end != s && *n >= 0; +// std::string and stores the result in *int_part/*frac_part/*frac_scale. The +// given std::string pointer is modified to point to the first unconsumed char. +bool ConsumeDurationNumber(const char** dpp, int64_t* int_part, + int64_t* frac_part, int64_t* frac_scale) { + *int_part = 0; + *frac_part = 0; + *frac_scale = 1; // invariant: *frac_part < *frac_scale + const char* start = *dpp; + for (; std::isdigit(**dpp); *dpp += 1) { + const int d = **dpp - '0'; // contiguous digits + if (*int_part > kint64max / 10) return false; + *int_part *= 10; + if (*int_part > kint64max - d) return false; + *int_part += d; + } + const bool int_part_empty = (*dpp == start); + if (**dpp != '.') return !int_part_empty; + for (*dpp += 1; std::isdigit(**dpp); *dpp += 1) { + const int d = **dpp - '0'; // contiguous digits + if (*frac_scale <= kint64max / 10) { + *frac_part *= 10; + *frac_part += d; + *frac_scale *= 10; + } + } + return !int_part_empty || *frac_scale != 1; } // A helper for ParseDuration() that parses a leading unit designator (e.g., @@ -859,13 +876,16 @@ bool ParseDuration(const std::string& dur_string, Duration* d) { Duration dur; while (*start != '\0') { - double n = 0; + int64_t int_part; + int64_t frac_part; + int64_t frac_scale; Duration unit; - if (!ConsumeDurationNumber(&start, &n) || + if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) || !ConsumeDurationUnit(&start, &unit)) { return false; } - dur += sign * n * unit; + if (int_part != 0) dur += sign * int_part * unit; + if (frac_part != 0) dur += sign * frac_part * unit / frac_scale; } *d = dur; return true; -- cgit 1.4.1