| Index: third_party/protobuf/src/google/protobuf/util/time_util.cc
|
| diff --git a/third_party/protobuf/src/google/protobuf/util/time_util.cc b/third_party/protobuf/src/google/protobuf/util/time_util.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c782d691a874bbf075fabba91d431cc84e925ff4
|
| --- /dev/null
|
| +++ b/third_party/protobuf/src/google/protobuf/util/time_util.cc
|
| @@ -0,0 +1,525 @@
|
| +// Protocol Buffers - Google's data interchange format
|
| +// Copyright 2008 Google Inc. All rights reserved.
|
| +// https://developers.google.com/protocol-buffers/
|
| +//
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following disclaimer
|
| +// in the documentation and/or other materials provided with the
|
| +// distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived from
|
| +// this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +
|
| +#include <google/protobuf/util/time_util.h>
|
| +
|
| +#include <google/protobuf/stubs/time.h>
|
| +#include <google/protobuf/stubs/int128.h>
|
| +#include <google/protobuf/stubs/strutil.h>
|
| +#include <google/protobuf/stubs/stringprintf.h>
|
| +#include <google/protobuf/duration.pb.h>
|
| +#include <google/protobuf/timestamp.pb.h>
|
| +
|
| +namespace google {
|
| +namespace protobuf {
|
| +namespace util {
|
| +
|
| +using google::protobuf::Timestamp;
|
| +using google::protobuf::Duration;
|
| +
|
| +namespace {
|
| +static const int kNanosPerSecond = 1000000000;
|
| +static const int kMicrosPerSecond = 1000000;
|
| +static const int kMillisPerSecond = 1000;
|
| +static const int kNanosPerMillisecond = 1000000;
|
| +static const int kMicrosPerMillisecond = 1000;
|
| +static const int kNanosPerMicrosecond = 1000;
|
| +static const int kSecondsPerMinute = 60; // Note that we ignore leap seconds.
|
| +static const int kSecondsPerHour = 3600;
|
| +static const char kTimestampFormat[] = "%E4Y-%m-%dT%H:%M:%S";
|
| +
|
| +template <typename T>
|
| +T CreateNormalized(int64 seconds, int64 nanos);
|
| +
|
| +template <>
|
| +Timestamp CreateNormalized(int64 seconds, int64 nanos) {
|
| + // Make sure nanos is in the range.
|
| + if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
|
| + seconds += nanos / kNanosPerSecond;
|
| + nanos = nanos % kNanosPerSecond;
|
| + }
|
| + // For Timestamp nanos should be in the range [0, 999999999]
|
| + if (nanos < 0) {
|
| + seconds -= 1;
|
| + nanos += kNanosPerSecond;
|
| + }
|
| + GOOGLE_DCHECK(seconds >= TimeUtil::kTimestampMinSeconds &&
|
| + seconds <= TimeUtil::kTimestampMaxSeconds);
|
| + Timestamp result;
|
| + result.set_seconds(seconds);
|
| + result.set_nanos(static_cast<int32>(nanos));
|
| + return result;
|
| +}
|
| +
|
| +template <>
|
| +Duration CreateNormalized(int64 seconds, int64 nanos) {
|
| + // Make sure nanos is in the range.
|
| + if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
|
| + seconds += nanos / kNanosPerSecond;
|
| + nanos = nanos % kNanosPerSecond;
|
| + }
|
| + // nanos should have the same sign as seconds.
|
| + if (seconds < 0 && nanos > 0) {
|
| + seconds += 1;
|
| + nanos -= kNanosPerSecond;
|
| + } else if (seconds > 0 && nanos < 0) {
|
| + seconds -= 1;
|
| + nanos += kNanosPerSecond;
|
| + }
|
| + GOOGLE_DCHECK(seconds >= TimeUtil::kDurationMinSeconds &&
|
| + seconds <= TimeUtil::kDurationMaxSeconds);
|
| + Duration result;
|
| + result.set_seconds(seconds);
|
| + result.set_nanos(static_cast<int32>(nanos));
|
| + return result;
|
| +}
|
| +
|
| +// Format nanoseconds with either 3, 6, or 9 digits depending on the required
|
| +// precision to represent the exact value.
|
| +string FormatNanos(int32 nanos) {
|
| + if (nanos % kNanosPerMillisecond == 0) {
|
| + return StringPrintf("%03d", nanos / kNanosPerMillisecond);
|
| + } else if (nanos % kNanosPerMicrosecond == 0) {
|
| + return StringPrintf("%06d", nanos / kNanosPerMicrosecond);
|
| + } else {
|
| + return StringPrintf("%09d", nanos);
|
| + }
|
| +}
|
| +
|
| +string FormatTime(int64 seconds, int32 nanos) {
|
| + return ::google::protobuf::internal::FormatTime(seconds, nanos);
|
| +}
|
| +
|
| +bool ParseTime(const string& value, int64* seconds, int32* nanos) {
|
| + return ::google::protobuf::internal::ParseTime(value, seconds, nanos);
|
| +}
|
| +
|
| +void CurrentTime(int64* seconds, int32* nanos) {
|
| + return ::google::protobuf::internal::GetCurrentTime(seconds, nanos);
|
| +}
|
| +
|
| +// Truncates the remainder part after division.
|
| +int64 RoundTowardZero(int64 value, int64 divider) {
|
| + int64 result = value / divider;
|
| + int64 remainder = value % divider;
|
| + // Before C++11, the sign of the remainder is implementation dependent if
|
| + // any of the operands is negative. Here we try to enforce C++11's "rounded
|
| + // toward zero" semantics. For example, for (-5) / 2 an implementation may
|
| + // give -3 as the result with the remainder being 1. This function ensures
|
| + // we always return -2 (closer to zero) regardless of the implementation.
|
| + if (result < 0 && remainder > 0) {
|
| + return result + 1;
|
| + } else {
|
| + return result;
|
| + }
|
| +}
|
| +} // namespace
|
| +
|
| +string TimeUtil::ToString(const Timestamp& timestamp) {
|
| + return FormatTime(timestamp.seconds(), timestamp.nanos());
|
| +}
|
| +
|
| +bool TimeUtil::FromString(const string& value, Timestamp* timestamp) {
|
| + int64 seconds;
|
| + int32 nanos;
|
| + if (!ParseTime(value, &seconds, &nanos)) {
|
| + return false;
|
| + }
|
| + *timestamp = CreateNormalized<Timestamp>(seconds, nanos);
|
| + return true;
|
| +}
|
| +
|
| +Timestamp TimeUtil::GetCurrentTime() {
|
| + int64 seconds;
|
| + int32 nanos;
|
| + CurrentTime(&seconds, &nanos);
|
| + return CreateNormalized<Timestamp>(seconds, nanos);
|
| +}
|
| +
|
| +Timestamp TimeUtil::GetEpoch() { return Timestamp(); }
|
| +
|
| +string TimeUtil::ToString(const Duration& duration) {
|
| + string result;
|
| + int64 seconds = duration.seconds();
|
| + int32 nanos = duration.nanos();
|
| + if (seconds < 0 || nanos < 0) {
|
| + result += "-";
|
| + seconds = -seconds;
|
| + nanos = -nanos;
|
| + }
|
| + result += StringPrintf("%" GOOGLE_LL_FORMAT "d", seconds);
|
| + if (nanos != 0) {
|
| + result += "." + FormatNanos(nanos);
|
| + }
|
| + result += "s";
|
| + return result;
|
| +}
|
| +
|
| +static int64 Pow(int64 x, int y) {
|
| + int64 result = 1;
|
| + for (int i = 0; i < y; ++i) {
|
| + result *= x;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +bool TimeUtil::FromString(const string& value, Duration* duration) {
|
| + if (value.length() <= 1 || value[value.length() - 1] != 's') {
|
| + return false;
|
| + }
|
| + bool negative = (value[0] == '-');
|
| + int sign_length = (negative ? 1 : 0);
|
| + // Parse the duration value as two integers rather than a float value
|
| + // to avoid precision loss.
|
| + string seconds_part, nanos_part;
|
| + size_t pos = value.find_last_of(".");
|
| + if (pos == string::npos) {
|
| + seconds_part = value.substr(sign_length, value.length() - 1 - sign_length);
|
| + nanos_part = "0";
|
| + } else {
|
| + seconds_part = value.substr(sign_length, pos - sign_length);
|
| + nanos_part = value.substr(pos + 1, value.length() - pos - 2);
|
| + }
|
| + char* end;
|
| + int64 seconds = strto64(seconds_part.c_str(), &end, 10);
|
| + if (end != seconds_part.c_str() + seconds_part.length()) {
|
| + return false;
|
| + }
|
| + int64 nanos = strto64(nanos_part.c_str(), &end, 10);
|
| + if (end != nanos_part.c_str() + nanos_part.length()) {
|
| + return false;
|
| + }
|
| + nanos = nanos * Pow(10, 9 - nanos_part.length());
|
| + if (negative) {
|
| + // If a Duration is negative, both seconds and nanos should be negative.
|
| + seconds = -seconds;
|
| + nanos = -nanos;
|
| + }
|
| + duration->set_seconds(seconds);
|
| + duration->set_nanos(static_cast<int32>(nanos));
|
| + return true;
|
| +}
|
| +
|
| +Duration TimeUtil::NanosecondsToDuration(int64 nanos) {
|
| + return CreateNormalized<Duration>(nanos / kNanosPerSecond,
|
| + nanos % kNanosPerSecond);
|
| +}
|
| +
|
| +Duration TimeUtil::MicrosecondsToDuration(int64 micros) {
|
| + return CreateNormalized<Duration>(
|
| + micros / kMicrosPerSecond,
|
| + (micros % kMicrosPerSecond) * kNanosPerMicrosecond);
|
| +}
|
| +
|
| +Duration TimeUtil::MillisecondsToDuration(int64 millis) {
|
| + return CreateNormalized<Duration>(
|
| + millis / kMillisPerSecond,
|
| + (millis % kMillisPerSecond) * kNanosPerMillisecond);
|
| +}
|
| +
|
| +Duration TimeUtil::SecondsToDuration(int64 seconds) {
|
| + return CreateNormalized<Duration>(seconds, 0);
|
| +}
|
| +
|
| +Duration TimeUtil::MinutesToDuration(int64 minutes) {
|
| + return CreateNormalized<Duration>(minutes * kSecondsPerMinute, 0);
|
| +}
|
| +
|
| +Duration TimeUtil::HoursToDuration(int64 hours) {
|
| + return CreateNormalized<Duration>(hours * kSecondsPerHour, 0);
|
| +}
|
| +
|
| +int64 TimeUtil::DurationToNanoseconds(const Duration& duration) {
|
| + return duration.seconds() * kNanosPerSecond + duration.nanos();
|
| +}
|
| +
|
| +int64 TimeUtil::DurationToMicroseconds(const Duration& duration) {
|
| + return duration.seconds() * kMicrosPerSecond +
|
| + RoundTowardZero(duration.nanos(), kNanosPerMicrosecond);
|
| +}
|
| +
|
| +int64 TimeUtil::DurationToMilliseconds(const Duration& duration) {
|
| + return duration.seconds() * kMillisPerSecond +
|
| + RoundTowardZero(duration.nanos(), kNanosPerMillisecond);
|
| +}
|
| +
|
| +int64 TimeUtil::DurationToSeconds(const Duration& duration) {
|
| + return duration.seconds();
|
| +}
|
| +
|
| +int64 TimeUtil::DurationToMinutes(const Duration& duration) {
|
| + return RoundTowardZero(duration.seconds(), kSecondsPerMinute);
|
| +}
|
| +
|
| +int64 TimeUtil::DurationToHours(const Duration& duration) {
|
| + return RoundTowardZero(duration.seconds(), kSecondsPerHour);
|
| +}
|
| +
|
| +Timestamp TimeUtil::NanosecondsToTimestamp(int64 nanos) {
|
| + return CreateNormalized<Timestamp>(nanos / kNanosPerSecond,
|
| + nanos % kNanosPerSecond);
|
| +}
|
| +
|
| +Timestamp TimeUtil::MicrosecondsToTimestamp(int64 micros) {
|
| + return CreateNormalized<Timestamp>(
|
| + micros / kMicrosPerSecond,
|
| + micros % kMicrosPerSecond * kNanosPerMicrosecond);
|
| +}
|
| +
|
| +Timestamp TimeUtil::MillisecondsToTimestamp(int64 millis) {
|
| + return CreateNormalized<Timestamp>(
|
| + millis / kMillisPerSecond,
|
| + millis % kMillisPerSecond * kNanosPerMillisecond);
|
| +}
|
| +
|
| +Timestamp TimeUtil::SecondsToTimestamp(int64 seconds) {
|
| + return CreateNormalized<Timestamp>(seconds, 0);
|
| +}
|
| +
|
| +int64 TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) {
|
| + return timestamp.seconds() * kNanosPerSecond + timestamp.nanos();
|
| +}
|
| +
|
| +int64 TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) {
|
| + return timestamp.seconds() * kMicrosPerSecond +
|
| + RoundTowardZero(timestamp.nanos(), kNanosPerMicrosecond);
|
| +}
|
| +
|
| +int64 TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) {
|
| + return timestamp.seconds() * kMillisPerSecond +
|
| + RoundTowardZero(timestamp.nanos(), kNanosPerMillisecond);
|
| +}
|
| +
|
| +int64 TimeUtil::TimestampToSeconds(const Timestamp& timestamp) {
|
| + return timestamp.seconds();
|
| +}
|
| +
|
| +Timestamp TimeUtil::TimeTToTimestamp(time_t value) {
|
| + return CreateNormalized<Timestamp>(static_cast<int64>(value), 0);
|
| +}
|
| +
|
| +time_t TimeUtil::TimestampToTimeT(const Timestamp& value) {
|
| + return static_cast<time_t>(value.seconds());
|
| +}
|
| +
|
| +Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) {
|
| + return CreateNormalized<Timestamp>(value.tv_sec,
|
| + value.tv_usec * kNanosPerMicrosecond);
|
| +}
|
| +
|
| +timeval TimeUtil::TimestampToTimeval(const Timestamp& value) {
|
| + timeval result;
|
| + result.tv_sec = value.seconds();
|
| + result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond);
|
| + return result;
|
| +}
|
| +
|
| +Duration TimeUtil::TimevalToDuration(const timeval& value) {
|
| + return CreateNormalized<Duration>(value.tv_sec,
|
| + value.tv_usec * kNanosPerMicrosecond);
|
| +}
|
| +
|
| +timeval TimeUtil::DurationToTimeval(const Duration& value) {
|
| + timeval result;
|
| + result.tv_sec = value.seconds();
|
| + result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond);
|
| + // timeval.tv_usec's range is [0, 1000000)
|
| + if (result.tv_usec < 0) {
|
| + result.tv_sec -= 1;
|
| + result.tv_usec += kMicrosPerSecond;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +} // namespace util
|
| +} // namespace protobuf
|
| +
|
| +
|
| +namespace protobuf {
|
| +namespace {
|
| +using google::protobuf::util::kNanosPerSecond;
|
| +using google::protobuf::util::CreateNormalized;
|
| +
|
| +// Convert a Timestamp to uint128.
|
| +void ToUint128(const Timestamp& value, uint128* result, bool* negative) {
|
| + if (value.seconds() < 0) {
|
| + *negative = true;
|
| + *result = static_cast<uint64>(-value.seconds());
|
| + *result = *result * kNanosPerSecond - static_cast<uint32>(value.nanos());
|
| + } else {
|
| + *negative = false;
|
| + *result = static_cast<uint64>(value.seconds());
|
| + *result = *result * kNanosPerSecond + static_cast<uint32>(value.nanos());
|
| + }
|
| +}
|
| +
|
| +// Convert a Duration to uint128.
|
| +void ToUint128(const Duration& value, uint128* result, bool* negative) {
|
| + if (value.seconds() < 0 || value.nanos() < 0) {
|
| + *negative = true;
|
| + *result = static_cast<uint64>(-value.seconds());
|
| + *result = *result * kNanosPerSecond + static_cast<uint32>(-value.nanos());
|
| + } else {
|
| + *negative = false;
|
| + *result = static_cast<uint64>(value.seconds());
|
| + *result = *result * kNanosPerSecond + static_cast<uint32>(value.nanos());
|
| + }
|
| +}
|
| +
|
| +void ToTimestamp(const uint128& value, bool negative, Timestamp* timestamp) {
|
| + int64 seconds = static_cast<int64>(Uint128Low64(value / kNanosPerSecond));
|
| + int32 nanos = static_cast<int32>(Uint128Low64(value % kNanosPerSecond));
|
| + if (negative) {
|
| + seconds = -seconds;
|
| + nanos = -nanos;
|
| + if (nanos < 0) {
|
| + nanos += kNanosPerSecond;
|
| + seconds -= 1;
|
| + }
|
| + }
|
| + timestamp->set_seconds(seconds);
|
| + timestamp->set_nanos(nanos);
|
| +}
|
| +
|
| +void ToDuration(const uint128& value, bool negative, Duration* duration) {
|
| + int64 seconds = static_cast<int64>(Uint128Low64(value / kNanosPerSecond));
|
| + int32 nanos = static_cast<int32>(Uint128Low64(value % kNanosPerSecond));
|
| + if (negative) {
|
| + seconds = -seconds;
|
| + nanos = -nanos;
|
| + }
|
| + duration->set_seconds(seconds);
|
| + duration->set_nanos(nanos);
|
| +}
|
| +} // namespace
|
| +
|
| +Duration& operator+=(Duration& d1, const Duration& d2) {
|
| + d1 = CreateNormalized<Duration>(d1.seconds() + d2.seconds(),
|
| + d1.nanos() + d2.nanos());
|
| + return d1;
|
| +}
|
| +
|
| +Duration& operator-=(Duration& d1, const Duration& d2) { // NOLINT
|
| + d1 = CreateNormalized<Duration>(d1.seconds() - d2.seconds(),
|
| + d1.nanos() - d2.nanos());
|
| + return d1;
|
| +}
|
| +
|
| +Duration& operator*=(Duration& d, int64 r) { // NOLINT
|
| + bool negative;
|
| + uint128 value;
|
| + ToUint128(d, &value, &negative);
|
| + if (r > 0) {
|
| + value *= static_cast<uint64>(r);
|
| + } else {
|
| + negative = !negative;
|
| + value *= static_cast<uint64>(-r);
|
| + }
|
| + ToDuration(value, negative, &d);
|
| + return d;
|
| +}
|
| +
|
| +Duration& operator*=(Duration& d, double r) { // NOLINT
|
| + double result = (d.seconds() * 1.0 + 1.0 * d.nanos() / kNanosPerSecond) * r;
|
| + int64 seconds = static_cast<int64>(result);
|
| + int32 nanos = static_cast<int32>((result - seconds) * kNanosPerSecond);
|
| + // Note that we normalize here not just because nanos can have a different
|
| + // sign from seconds but also that nanos can be any arbitrary value when
|
| + // overflow happens (i.e., the result is a much larger value than what
|
| + // int64 can represent).
|
| + d = CreateNormalized<Duration>(seconds, nanos);
|
| + return d;
|
| +}
|
| +
|
| +Duration& operator/=(Duration& d, int64 r) { // NOLINT
|
| + bool negative;
|
| + uint128 value;
|
| + ToUint128(d, &value, &negative);
|
| + if (r > 0) {
|
| + value /= static_cast<uint64>(r);
|
| + } else {
|
| + negative = !negative;
|
| + value /= static_cast<uint64>(-r);
|
| + }
|
| + ToDuration(value, negative, &d);
|
| + return d;
|
| +}
|
| +
|
| +Duration& operator/=(Duration& d, double r) { // NOLINT
|
| + return d *= 1.0 / r;
|
| +}
|
| +
|
| +Duration& operator%=(Duration& d1, const Duration& d2) { // NOLINT
|
| + bool negative1, negative2;
|
| + uint128 value1, value2;
|
| + ToUint128(d1, &value1, &negative1);
|
| + ToUint128(d2, &value2, &negative2);
|
| + uint128 result = value1 % value2;
|
| + // When negative values are involved in division, we round the division
|
| + // result towards zero. With this semantics, sign of the remainder is the
|
| + // same as the dividend. For example:
|
| + // -5 / 10 = 0, -5 % 10 = -5
|
| + // -5 / (-10) = 0, -5 % (-10) = -5
|
| + // 5 / (-10) = 0, 5 % (-10) = 5
|
| + ToDuration(result, negative1, &d1);
|
| + return d1;
|
| +}
|
| +
|
| +int64 operator/(const Duration& d1, const Duration& d2) {
|
| + bool negative1, negative2;
|
| + uint128 value1, value2;
|
| + ToUint128(d1, &value1, &negative1);
|
| + ToUint128(d2, &value2, &negative2);
|
| + int64 result = Uint128Low64(value1 / value2);
|
| + if (negative1 != negative2) {
|
| + result = -result;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +Timestamp& operator+=(Timestamp& t, const Duration& d) { // NOLINT
|
| + t = CreateNormalized<Timestamp>(t.seconds() + d.seconds(),
|
| + t.nanos() + d.nanos());
|
| + return t;
|
| +}
|
| +
|
| +Timestamp& operator-=(Timestamp& t, const Duration& d) { // NOLINT
|
| + t = CreateNormalized<Timestamp>(t.seconds() - d.seconds(),
|
| + t.nanos() - d.nanos());
|
| + return t;
|
| +}
|
| +
|
| +Duration operator-(const Timestamp& t1, const Timestamp& t2) {
|
| + return CreateNormalized<Duration>(t1.seconds() - t2.seconds(),
|
| + t1.nanos() - t2.nanos());
|
| +}
|
| +} // namespace protobuf
|
| +
|
| +} // namespace google
|
|
|