about summary refs log tree commit diff
path: root/absl/time/duration.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/time/duration.cc')
-rw-r--r--absl/time/duration.cc121
1 files changed, 75 insertions, 46 deletions
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index f01825599de0..d0f1aadbf225 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); }