From cbfd0f0fe53d9d3495a3d607311d984fec37e692 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 12 May 2020 15:05:26 -0700 Subject: Export of internal Abseil changes -- 6a60bc6c79a3069f49986c2567dd51d2792f8ec1 by Abseil Team : Internal cleanup PiperOrigin-RevId: 311210039 -- a1049de1dd9071efa3a3dda1c3f25ab578b23e27 by Laramie Leavitt : Internal change PiperOrigin-RevId: 311188627 -- c2ccddd1cd89ef9d79c35bbe9e1813164db27031 by Matt Kulukundis : 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 : Eliminate public method absl::Flag::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 : Internal change PiperOrigin-RevId: 310757743 -- f091f77a13ce9481218cb356f8b4ceb49c1530f9 by Jorg Brown : Change #include of to from absl/strings/cord.h PiperOrigin-RevId: 310657413 -- 39419418af6be4ac9b9204ebe2c7a92a6c3a0bc9 by Derek Mauro : Internal change PiperOrigin-RevId: 310615554 GitOrigin-RevId: 6a60bc6c79a3069f49986c2567dd51d2792f8ec1 Change-Id: I57dd35424269d67740272c4f88b2de54d8022cb2 --- absl/base/BUILD.bazel | 14 +++ absl/base/internal/unique_small_name_test.cc | 77 ++++++++++++++++ absl/base/optimization.h | 26 ++++++ absl/flags/internal/commandlineflag.h | 5 +- absl/flags/internal/commandlineflag_test.cc | 20 ++-- absl/flags/internal/flag.h | 1 + absl/flags/internal/private_handle_accessor.cc | 5 + absl/flags/internal/private_handle_accessor.h | 3 + absl/flags/internal/type_erased.cc | 8 -- absl/flags/internal/type_erased.h | 11 --- absl/random/internal/BUILD.bazel | 13 +-- absl/strings/cord.cc | 1 + absl/strings/cord.h | 2 +- absl/strings/substitute.h | 13 ++- absl/synchronization/mutex.h | 7 +- absl/time/duration.cc | 121 +++++++++++++++---------- absl/time/format.cc | 68 ++++++++------ absl/time/time.h | 12 +-- 18 files changed, 280 insertions(+), 127 deletions(-) create mode 100644 absl/base/internal/unique_small_name_test.cc (limited to 'absl') diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 816e592b..76122dab 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -777,3 +777,17 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "unique_small_name_test", + size = "small", + srcs = ["internal/unique_small_name_test.cc"], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + linkstatic = 1, + deps = [ + ":core_headers", + "//absl/strings", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/absl/base/internal/unique_small_name_test.cc b/absl/base/internal/unique_small_name_test.cc new file mode 100644 index 00000000..ff8c2b3f --- /dev/null +++ b/absl/base/internal/unique_small_name_test.cc @@ -0,0 +1,77 @@ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gtest/gtest.h" +#include "absl/base/optimization.h" +#include "absl/strings/string_view.h" + +// This test by itself does not do anything fancy, but it serves as binary I can +// query in shell test. + +namespace { + +template +void DoNotOptimize(const T& var) { +#ifdef __GNUC__ + asm volatile("" : "+m"(const_cast(var))); +#else + std::cout << (void*)&var; +#endif +} + +int very_long_int_variable_name ABSL_INTERNAL_UNIQUE_SMALL_NAME() = 0; +char very_long_str_variable_name[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = "abc"; + +TEST(UniqueSmallName, NonAutomaticVar) { + EXPECT_EQ(very_long_int_variable_name, 0); + EXPECT_EQ(absl::string_view(very_long_str_variable_name), "abc"); +} + +int VeryLongFreeFunctionName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); + +TEST(UniqueSmallName, FreeFunction) { + DoNotOptimize(&VeryLongFreeFunctionName); + + EXPECT_EQ(VeryLongFreeFunctionName(), 456); +} + +int VeryLongFreeFunctionName() { return 456; } + +struct VeryLongStructName { + explicit VeryLongStructName(int i); + + int VeryLongMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); + + static int VeryLongStaticMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); + + private: + int fld; +}; + +TEST(UniqueSmallName, Struct) { + VeryLongStructName var(10); + + DoNotOptimize(var); + DoNotOptimize(&VeryLongStructName::VeryLongMethodName); + DoNotOptimize(&VeryLongStructName::VeryLongStaticMethodName); + + EXPECT_EQ(var.VeryLongMethodName(), 10); + EXPECT_EQ(VeryLongStructName::VeryLongStaticMethodName(), 123); +} + +VeryLongStructName::VeryLongStructName(int i) : fld(i) {} +int VeryLongStructName::VeryLongMethodName() { return fld; } +int VeryLongStructName::VeryLongStaticMethodName() { return 123; } + +} // namespace diff --git a/absl/base/optimization.h b/absl/base/optimization.h index 1541d7a8..92bf9cd3 100644 --- a/absl/base/optimization.h +++ b/absl/base/optimization.h @@ -212,4 +212,30 @@ } while (0) #endif +// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond) +// This macro forces small unique name on a static file level symbols like +// static local variables or static functions. This is intended to be used in +// macro definitions to optimize the cost of generated code. Do NOT use it on +// symbols exported from translation unit since it may casue a link time +// conflict. +// +// Example: +// +// #define MY_MACRO(txt) +// namespace { +// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt; +// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); +// const char* VeryVeryLongFuncName() { return txt; } +// } +// + +#if defined(__GNUC__) +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \ + asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__)) +#else +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() +#endif + #endif // ABSL_BASE_OPTIMIZATION_H_ diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h index 2d3b794d..0a7197b7 100644 --- a/absl/flags/internal/commandlineflag.h +++ b/absl/flags/internal/commandlineflag.h @@ -128,7 +128,6 @@ class CommandLineFlag { virtual std::string Help() const = 0; // Returns true iff this object corresponds to retired flag. virtual bool IsRetired() const; - virtual bool IsSpecifiedOnCommandLine() const = 0; virtual std::string DefaultValue() const = 0; virtual std::string CurrentValue() const = 0; @@ -167,6 +166,10 @@ class CommandLineFlag { // the dst based on the current flag's value. virtual void Read(void* dst) const = 0; + // To be deleted. Used to return true if flag's current value originated from + // command line. + virtual bool IsSpecifiedOnCommandLine() const = 0; + // Validates supplied value usign validator or parseflag routine virtual bool ValidateInputValue(absl::string_view value) const = 0; diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/internal/commandlineflag_test.cc index 54d50fff..0b5aea37 100644 --- a/absl/flags/internal/commandlineflag_test.cc +++ b/absl/flags/internal/commandlineflag_test.cc @@ -121,42 +121,48 @@ TEST_F(CommandLineFlagTest, TestParseFromCurrentValue) { std::string err; auto* flag_01 = flags::FindCommandLineFlag("int_flag"); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( flag_01, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123); EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'"); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( flag_01, "A1", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123); EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'"); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16); - EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_FALSE( + flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, &err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11); - EXPECT_TRUE(flag_01->IsSpecifiedOnCommandLine()); + EXPECT_TRUE(flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index b060199e..146c3efc 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -624,6 +624,7 @@ class Flag { absl::string_view Name() const { return impl_.Name(); } std::string Filename() const { return impl_.Filename(); } std::string Help() const { return impl_.Help(); } + // Do not use. To be removed. bool IsSpecifiedOnCommandLine() const { return impl_.IsSpecifiedOnCommandLine(); } diff --git a/absl/flags/internal/private_handle_accessor.cc b/absl/flags/internal/private_handle_accessor.cc index ec5776bb..64fe3166 100644 --- a/absl/flags/internal/private_handle_accessor.cc +++ b/absl/flags/internal/private_handle_accessor.cc @@ -28,6 +28,11 @@ std::unique_ptr PrivateHandleAccessor::SaveState( return flag->SaveState(); } +bool PrivateHandleAccessor::IsSpecifiedOnCommandLine( + const CommandLineFlag& flag) { + return flag.IsSpecifiedOnCommandLine(); +} + bool PrivateHandleAccessor::ValidateInputValue(const CommandLineFlag& flag, absl::string_view value) { return flag.ValidateInputValue(value); diff --git a/absl/flags/internal/private_handle_accessor.h b/absl/flags/internal/private_handle_accessor.h index fbb4409c..40591de4 100644 --- a/absl/flags/internal/private_handle_accessor.h +++ b/absl/flags/internal/private_handle_accessor.h @@ -33,6 +33,9 @@ class PrivateHandleAccessor { // Access to CommandLineFlag::SaveState. static std::unique_ptr SaveState(CommandLineFlag* flag); + // Access to CommandLineFlag::IsSpecifiedOnCommandLine. + static bool IsSpecifiedOnCommandLine(const CommandLineFlag& flag); + // Access to CommandLineFlag::ValidateInputValue. static bool ValidateInputValue(const CommandLineFlag& flag, absl::string_view value); diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc index 3cfc9b2d..c13fb9b0 100644 --- a/absl/flags/internal/type_erased.cc +++ b/absl/flags/internal/type_erased.cc @@ -81,14 +81,6 @@ bool IsValidFlagValue(absl::string_view name, absl::string_view value) { // -------------------------------------------------------------------- -bool SpecifiedOnCommandLine(absl::string_view name) { - CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); - if (flag != nullptr && !flag->IsRetired()) { - return flag->IsSpecifiedOnCommandLine(); - } - return false; -} - } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h index ffe319ba..b43a0ff7 100644 --- a/absl/flags/internal/type_erased.h +++ b/absl/flags/internal/type_erased.h @@ -55,17 +55,6 @@ bool IsValidFlagValue(absl::string_view name, absl::string_view value); //----------------------------------------------------------------------------- -// Returns true iff a flag named "name" was specified on the command line -// (either directly, or via one of --flagfile or --fromenv or --tryfromenv). -// -// Any non-command-line modification of the flag does not affect the -// result of this function. So for example, if a flag was passed on -// the command line but then reset via SET_FLAGS_DEFAULT, this -// function will still return true. -bool SpecifiedOnCommandLine(absl::string_view name); - -//----------------------------------------------------------------------------- - // If a flag with specified "name" exists and has type T, store // its current value in *dst and return true. Else return false // without touching *dst. T must obey all of the requirements for diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index 1c9dabb5..dc452816 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel @@ -37,9 +37,6 @@ cc_library( hdrs = ["traits.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/random:__pkg__", - ], deps = ["//absl/base:config"], ) @@ -48,9 +45,6 @@ cc_library( hdrs = ["distribution_caller.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/random:__pkg__", - ], deps = ["//absl/base:config"], ) @@ -76,9 +70,6 @@ cc_library( ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/random:__pkg__", - ], deps = ["//absl/base:config"], ) @@ -517,9 +508,6 @@ cc_library( name = "mock_overload_set", testonly = 1, hdrs = ["mock_overload_set.h"], - visibility = [ - "//absl/random:__pkg__", - ], deps = [ "//absl/random:mocking_bit_gen", "@com_google_googletest//:gtest", @@ -669,6 +657,7 @@ cc_library( deps = [ ":platform", ":randen_engine", + "//absl/base:config", "//absl/base:core_headers", "//absl/base:raw_logging_internal", ], diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 0403cc6e..1ddd6aec 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 86ae76fd..3be8d7d8 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -65,7 +65,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 92c47236..c6da4dc6 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h @@ -120,7 +120,9 @@ class Arg { // representation. However, we can't really know, so we make the caller decide // what to do. Arg(char value) // NOLINT(runtime/explicit) - : piece_(scratch_, 1) { scratch_[0] = value; } + : piece_(scratch_, 1) { + scratch_[0] = value; + } Arg(short value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} @@ -203,10 +205,11 @@ constexpr const char* SkipNumber(const char* format) { } constexpr int PlaceholderBitmask(const char* format) { - return !*format ? 0 : *format != '$' - ? PlaceholderBitmask(format + 1) - : (CalculateOneBit(format + 1) | - PlaceholderBitmask(SkipNumber(format + 1))); + return !*format + ? 0 + : *format != '$' ? PlaceholderBitmask(format + 1) + : (CalculateOneBit(format + 1) | + PlaceholderBitmask(SkipNumber(format + 1))); } #endif // ABSL_BAD_CALL_IF diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 961ff52b..876698ca 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h @@ -769,6 +769,8 @@ class Condition { // class CondVar { public: + // A `CondVar` allocated on the heap or on the stack can use the this + // constructor. CondVar(); ~CondVar(); @@ -900,9 +902,11 @@ class ABSL_SCOPED_LOCKABLE ReleasableMutexLock { }; #ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX + inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {} #else + inline Mutex::Mutex() : mu_(0) { ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); } @@ -910,7 +914,8 @@ inline Mutex::Mutex() : mu_(0) { inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {} inline CondVar::CondVar() : cv_(0) {} -#endif + +#endif // ABSL_INTERNAL_USE_NONPROD_MUTEX // static template 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 #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 + #include #include +#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); // ============================================================================ -- cgit v1.2.3