diff options
Diffstat (limited to 'absl/time/duration.cc')
-rw-r--r-- | absl/time/duration.cc | 121 |
1 files changed, 75 insertions, 46 deletions
diff --git a/absl/time/duration.cc b/absl/time/duration.cc index f0182559..d0f1aadb 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc @@ -67,7 +67,9 @@ #include <string> #include "absl/base/casts.h" +#include "absl/base/macros.h" #include "absl/numeric/int128.h" +#include "absl/strings/strip.h" #include "absl/time/time.h" namespace absl { @@ -800,23 +802,27 @@ namespace { // A helper for ParseDuration() that parses a leading number from the given // string and stores the result in *int_part/*frac_part/*frac_scale. The // given string pointer is modified to point to the first unconsumed char. -bool ConsumeDurationNumber(const char** dpp, int64_t* int_part, +bool ConsumeDurationNumber(const char** dpp, const char* ep, 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) { + for (; *dpp != ep; *dpp += 1) { const int d = **dpp - '0'; // contiguous digits + if (d < 0 || 10 <= d) break; + 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) { + if (*dpp == ep || **dpp != '.') return !int_part_empty; + + for (*dpp += 1; *dpp != ep; *dpp += 1) { const int d = **dpp - '0'; // contiguous digits + if (d < 0 || 10 <= d) break; if (*frac_scale <= kint64max / 10) { *frac_part *= 10; *frac_part += d; @@ -830,32 +836,56 @@ bool ConsumeDurationNumber(const char** dpp, int64_t* int_part, // ns, us, ms, s, m, h) from the given string and stores the resulting unit // in "*unit". The given string pointer is modified to point to the first // unconsumed char. -bool ConsumeDurationUnit(const char** start, Duration* unit) { - const char *s = *start; - bool ok = true; - if (strncmp(s, "ns", 2) == 0) { - s += 2; - *unit = Nanoseconds(1); - } else if (strncmp(s, "us", 2) == 0) { - s += 2; - *unit = Microseconds(1); - } else if (strncmp(s, "ms", 2) == 0) { - s += 2; - *unit = Milliseconds(1); - } else if (strncmp(s, "s", 1) == 0) { - s += 1; - *unit = Seconds(1); - } else if (strncmp(s, "m", 1) == 0) { - s += 1; - *unit = Minutes(1); - } else if (strncmp(s, "h", 1) == 0) { - s += 1; - *unit = Hours(1); - } else { - ok = false; +bool ConsumeDurationUnit(const char** start, const char* end, Duration* unit) { + size_t size = end - *start; + switch (size) { + case 0: + return false; + default: + switch (**start) { + case 'n': + if (*(*start + 1) == 's') { + *start += 2; + *unit = Nanoseconds(1); + return true; + } + break; + case 'u': + if (*(*start + 1) == 's') { + *start += 2; + *unit = Microseconds(1); + return true; + } + break; + case 'm': + if (*(*start + 1) == 's') { + *start += 2; + *unit = Milliseconds(1); + return true; + } + break; + default: + break; + } + ABSL_FALLTHROUGH_INTENDED; + case 1: + switch (**start) { + case 's': + *unit = Seconds(1); + *start += 1; + return true; + case 'm': + *unit = Minutes(1); + *start += 1; + return true; + case 'h': + *unit = Hours(1); + *start += 1; + return true; + default: + return false; + } } - *start = s; - return ok; } } // namespace @@ -865,39 +895,38 @@ bool ConsumeDurationUnit(const char** start, Duration* unit) { // a possibly signed sequence of decimal numbers, each with optional // fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". // Valid time units are "ns", "us" "ms", "s", "m", "h". -bool ParseDuration(const std::string& dur_string, Duration* d) { - const char* start = dur_string.c_str(); +bool ParseDuration(absl::string_view dur_sv, Duration* d) { int sign = 1; - - if (*start == '-' || *start == '+') { - sign = *start == '-' ? -1 : 1; - ++start; - } - - // Can't parse a duration from an empty string. - if (*start == '\0') { - return false; + if (absl::ConsumePrefix(&dur_sv, "-")) { + sign = -1; + } else { + absl::ConsumePrefix(&dur_sv, "+"); } + if (dur_sv.empty()) return false; // Special case for a string of "0". - if (*start == '0' && *(start + 1) == '\0') { + if (dur_sv == "0") { *d = ZeroDuration(); return true; } - if (strcmp(start, "inf") == 0) { + if (dur_sv == "inf") { *d = sign * InfiniteDuration(); return true; } + const char* start = dur_sv.data(); + const char* end = start + dur_sv.size(); + Duration dur; - while (*start != '\0') { + while (start != end) { int64_t int_part; int64_t frac_part; int64_t frac_scale; Duration unit; - if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) || - !ConsumeDurationUnit(&start, &unit)) { + if (!ConsumeDurationNumber(&start, end, &int_part, &frac_part, + &frac_scale) || + !ConsumeDurationUnit(&start, end, &unit)) { return false; } if (int_part != 0) dur += sign * int_part * unit; @@ -908,7 +937,7 @@ bool ParseDuration(const std::string& dur_string, Duration* d) { } bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) { - return ParseDuration(std::string(text), dst); + return ParseDuration(text, dst); } std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); } |