summaryrefslogtreecommitdiff
path: root/absl/time
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2020-05-12 15:05:26 -0700
committerGravatar Andy Getz <durandal@google.com>2020-05-12 21:04:49 -0400
commitcbfd0f0fe53d9d3495a3d607311d984fec37e692 (patch)
treea781b9fde3fafa8265b6e7a3b8fa063194ed9c3c /absl/time
parentc45d1c09d517e145d722e00deea9be6c8be8dd57 (diff)
Export of internal Abseil changes
-- 6a60bc6c79a3069f49986c2567dd51d2792f8ec1 by Abseil Team <absl-team@google.com>: Internal cleanup PiperOrigin-RevId: 311210039 -- a1049de1dd9071efa3a3dda1c3f25ab578b23e27 by Laramie Leavitt <lar@google.com>: Internal change PiperOrigin-RevId: 311188627 -- c2ccddd1cd89ef9d79c35bbe9e1813164db27031 by Matt Kulukundis <kfm@google.com>: Migrate time parsing/formatting to string_view. - make a copy before handing to cctz but handle local cases without PiperOrigin-RevId: 311009254 -- d91d0cd68f3672a727ff76ee43f2da5226673d60 by Gennadiy Rozental <rogeeff@google.com>: Eliminate public method absl::Flag<T>::IsSpecfiedOnCommandLine. This interface was never intended to be supported. Prefer to react to the current value of flag. PiperOrigin-RevId: 310991916 -- 8ad41e7ec24f43598ed232545314117802e7895c by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 310757743 -- f091f77a13ce9481218cb356f8b4ceb49c1530f9 by Jorg Brown <jorg@google.com>: Change #include of <iostream> to <iosfwd> from absl/strings/cord.h PiperOrigin-RevId: 310657413 -- 39419418af6be4ac9b9204ebe2c7a92a6c3a0bc9 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 310615554 GitOrigin-RevId: 6a60bc6c79a3069f49986c2567dd51d2792f8ec1 Change-Id: I57dd35424269d67740272c4f88b2de54d8022cb2
Diffstat (limited to 'absl/time')
-rw-r--r--absl/time/duration.cc121
-rw-r--r--absl/time/format.cc68
-rw-r--r--absl/time/time.h12
3 files changed, 120 insertions, 81 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); }
diff --git a/absl/time/format.cc b/absl/time/format.cc
index ee088f33..228940ed 100644
--- a/absl/time/format.cc
+++ b/absl/time/format.cc
@@ -13,9 +13,12 @@
// limitations under the License.
#include <string.h>
+
#include <cctype>
#include <cstdint>
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "absl/time/time.h"
@@ -71,12 +74,12 @@ absl::Time Join(const cctz_parts& parts) {
} // namespace
-std::string FormatTime(const std::string& format, absl::Time t,
+std::string FormatTime(absl::string_view format, absl::Time t,
absl::TimeZone tz) {
- if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
- if (t == absl::InfinitePast()) return kInfinitePastStr;
+ if (t == absl::InfiniteFuture()) return std::string(kInfiniteFutureStr);
+ if (t == absl::InfinitePast()) return std::string(kInfinitePastStr);
const auto parts = Split(t);
- return cctz::detail::format(format, parts.sec, parts.fem,
+ return cctz::detail::format(std::string(format), parts.sec, parts.fem,
cctz::time_zone(tz));
}
@@ -88,42 +91,50 @@ std::string FormatTime(absl::Time t) {
return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
}
-bool ParseTime(const std::string& format, const std::string& input,
+bool ParseTime(absl::string_view format, absl::string_view input,
absl::Time* time, std::string* err) {
return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
}
// If the input string does not contain an explicit UTC offset, interpret
// the fields with respect to the given TimeZone.
-bool ParseTime(const std::string& format, const std::string& input,
+bool ParseTime(absl::string_view format, absl::string_view input,
absl::TimeZone tz, absl::Time* time, std::string* err) {
- const char* data = input.c_str();
- while (std::isspace(*data)) ++data;
-
- size_t inf_size = strlen(kInfiniteFutureStr);
- if (strncmp(data, kInfiniteFutureStr, inf_size) == 0) {
- const char* new_data = data + inf_size;
- while (std::isspace(*new_data)) ++new_data;
- if (*new_data == '\0') {
- *time = InfiniteFuture();
- return true;
+ auto strip_leading_space = [](absl::string_view* sv) {
+ while (!sv->empty()) {
+ if (!std::isspace(sv->front())) return;
+ sv->remove_prefix(1);
}
- }
-
- inf_size = strlen(kInfinitePastStr);
- if (strncmp(data, kInfinitePastStr, inf_size) == 0) {
- const char* new_data = data + inf_size;
- while (std::isspace(*new_data)) ++new_data;
- if (*new_data == '\0') {
- *time = InfinitePast();
- return true;
+ };
+
+ // Portable toolchains means we don't get nice constexpr here.
+ struct Literal {
+ const char* name;
+ size_t size;
+ absl::Time value;
+ };
+ static Literal literals[] = {
+ {kInfiniteFutureStr, strlen(kInfiniteFutureStr), InfiniteFuture()},
+ {kInfinitePastStr, strlen(kInfinitePastStr), InfinitePast()},
+ };
+ strip_leading_space(&input);
+ for (const auto& lit : literals) {
+ if (absl::StartsWith(input, absl::string_view(lit.name, lit.size))) {
+ absl::string_view tail = input;
+ tail.remove_prefix(lit.size);
+ strip_leading_space(&tail);
+ if (tail.empty()) {
+ *time = lit.value;
+ return true;
+ }
}
}
std::string error;
cctz_parts parts;
- const bool b = cctz::detail::parse(format, input, cctz::time_zone(tz),
- &parts.sec, &parts.fem, &error);
+ const bool b =
+ cctz::detail::parse(std::string(format), std::string(input),
+ cctz::time_zone(tz), &parts.sec, &parts.fem, &error);
if (b) {
*time = Join(parts);
} else if (err != nullptr) {
@@ -134,8 +145,7 @@ bool ParseTime(const std::string& format, const std::string& input,
// Functions required to support absl::Time flags.
bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
- return absl::ParseTime(RFC3339_full, std::string(text), absl::UTCTimeZone(),
- t, error);
+ return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
}
std::string AbslUnparseFlag(absl::Time t) {
diff --git a/absl/time/time.h b/absl/time/time.h
index 152f3ff8..b456a13e 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -545,7 +545,7 @@ inline std::ostream& operator<<(std::ostream& os, Duration d) {
// suffix. The valid suffixes are "ns", "us" "ms", "s", "m", and "h".
// Simple examples include "300ms", "-1.5h", and "2h45m". Parses "0" as
// `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
-bool ParseDuration(const std::string& dur_string, Duration* d);
+bool ParseDuration(absl::string_view dur_string, Duration* d);
// Support for flag values of type Duration. Duration flags must be specified
// in a format that is valid input for absl::ParseDuration().
@@ -1021,13 +1021,13 @@ class TimeZone {
// Loads the named zone. May perform I/O on the initial load of the named
// zone. If the name is invalid, or some other kind of error occurs, returns
// `false` and `*tz` is set to the UTC time zone.
-inline bool LoadTimeZone(const std::string& name, TimeZone* tz) {
+inline bool LoadTimeZone(absl::string_view name, TimeZone* tz) {
if (name == "localtime") {
*tz = TimeZone(time_internal::cctz::local_time_zone());
return true;
}
time_internal::cctz::time_zone cz;
- const bool b = time_internal::cctz::load_time_zone(name, &cz);
+ const bool b = time_internal::cctz::load_time_zone(std::string(name), &cz);
*tz = TimeZone(cz);
return b;
}
@@ -1252,7 +1252,7 @@ ABSL_DLL extern const char
// `absl::InfinitePast()`, the returned string will be exactly "infinite-past".
// In both cases the given format string and `absl::TimeZone` are ignored.
//
-std::string FormatTime(const std::string& format, Time t, TimeZone tz);
+std::string FormatTime(absl::string_view format, Time t, TimeZone tz);
// Convenience functions that format the given time using the RFC3339_full
// format. The first overload uses the provided TimeZone, while the second
@@ -1313,7 +1313,7 @@ inline std::ostream& operator<<(std::ostream& os, Time t) {
// If the input string is "infinite-past", the returned `absl::Time` will be
// `absl::InfinitePast()` and `true` will be returned.
//
-bool ParseTime(const std::string& format, const std::string& input, Time* time,
+bool ParseTime(absl::string_view format, absl::string_view input, Time* time,
std::string* err);
// Like ParseTime() above, but if the format string does not contain a UTC
@@ -1323,7 +1323,7 @@ bool ParseTime(const std::string& format, const std::string& input, Time* time,
// of ambiguity or non-existence, in which case the "pre" time (as defined
// by TimeZone::TimeInfo) is returned. For these reasons we recommend that
// all date/time strings include a UTC offset so they're context independent.
-bool ParseTime(const std::string& format, const std::string& input, TimeZone tz,
+bool ParseTime(absl::string_view format, absl::string_view input, TimeZone tz,
Time* time, std::string* err);
// ============================================================================