diff --git a/CMake/README.md b/CMake/README.md index 04d5df3..8f73475 100644 --- a/CMake/README.md +++ b/CMake/README.md
@@ -93,7 +93,7 @@ absl::memory absl::meta absl::numeric -absl::random +absl::random_random absl::strings absl::synchronization absl::time
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 816e592..76122da 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel
@@ -777,3 +777,17 @@ "@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 0000000..ff8c2b3 --- /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 <class T> +void DoNotOptimize(const T& var) { +#ifdef __GNUC__ + asm volatile("" : "+m"(const_cast<T&>(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 1541d7a..92bf9cd 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 2d3b794..0a7197b 100644 --- a/absl/flags/internal/commandlineflag.h +++ b/absl/flags/internal/commandlineflag.h
@@ -128,7 +128,6 @@ 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 @@ // 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 54d50ff..0b5aea3 100644 --- a/absl/flags/internal/commandlineflag_test.cc +++ b/absl/flags/internal/commandlineflag_test.cc
@@ -121,42 +121,48 @@ 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 f53f484..146c3ef 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h
@@ -40,6 +40,30 @@ namespace absl { ABSL_NAMESPACE_BEGIN + +// Forward declaration of absl::Flag<T> public API. +namespace flags_internal { +template <typename T> +class Flag; +} // namespace flags_internal + +#if defined(_MSC_VER) && !defined(__clang__) +template <typename T> +class Flag; +#else +template <typename T> +using Flag = flags_internal::Flag<T>; +#endif + +template <typename T> +ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag); + +template <typename T> +void SetFlag(absl::Flag<T>* flag, const T& v); + +template <typename T, typename V> +void SetFlag(absl::Flag<T>* flag, const V& v); + namespace flags_internal { /////////////////////////////////////////////////////////////////////////////// @@ -596,6 +620,33 @@ flags_internal::StorageKind<T>(), default_arg), value_() {} + // CommandLineFlag interface + 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(); + } + std::string DefaultValue() const { return impl_.DefaultValue(); } + std::string CurrentValue() const { return impl_.CurrentValue(); } + + private: + template <typename U, bool do_register> + friend class FlagRegistrar; + +#if !defined(_MSC_VER) || defined(__clang__) + template <typename U> + friend U absl::GetFlag(const flags_internal::Flag<U>& flag); + template <typename U> + friend void absl::SetFlag(flags_internal::Flag<U>* flag, const U& v); + template <typename U, typename V> + friend void absl::SetFlag(flags_internal::Flag<U>* flag, const V& v); +#else + template <typename U> + friend class absl::Flag; +#endif + T Get() const { // See implementation notes in CommandLineFlag::Get(). union U { @@ -617,20 +668,6 @@ impl_.Write(&v); } - // CommandLineFlag interface - absl::string_view Name() const { return impl_.Name(); } - std::string Filename() const { return impl_.Filename(); } - std::string Help() const { return impl_.Help(); } - bool IsSpecifiedOnCommandLine() const { - return impl_.IsSpecifiedOnCommandLine(); - } - std::string DefaultValue() const { return impl_.DefaultValue(); } - std::string CurrentValue() const { return impl_.CurrentValue(); } - - private: - template <typename U, bool do_register> - friend class FlagRegistrar; - // Flag's data // The implementation depends on value_ field to be placed exactly after the // impl_ field, so that impl_ can figure out the offset to the value and
diff --git a/absl/flags/internal/parse.h b/absl/flags/internal/parse.h index 03e8a07..d259be7 100644 --- a/absl/flags/internal/parse.h +++ b/absl/flags/internal/parse.h
@@ -44,6 +44,13 @@ UsageFlagsAction usage_flag_act, OnUndefinedFlag on_undef_flag); +// -------------------------------------------------------------------- +// Inspect original command line + +// Returns true if flag with specified name was either present on the original +// command line or specified in flag file present on the original command line. +bool WasPresentOnCommandLine(absl::string_view flag_name); + } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl
diff --git a/absl/flags/internal/private_handle_accessor.cc b/absl/flags/internal/private_handle_accessor.cc index ec5776b..64fe316 100644 --- a/absl/flags/internal/private_handle_accessor.cc +++ b/absl/flags/internal/private_handle_accessor.cc
@@ -28,6 +28,11 @@ 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 fbb4409..40591de 100644 --- a/absl/flags/internal/private_handle_accessor.h +++ b/absl/flags/internal/private_handle_accessor.h
@@ -33,6 +33,9 @@ // Access to CommandLineFlag::SaveState. static std::unique_ptr<FlagStateInterface> 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 3cfc9b2..c13fb9b 100644 --- a/absl/flags/internal/type_erased.cc +++ b/absl/flags/internal/type_erased.cc
@@ -81,14 +81,6 @@ // -------------------------------------------------------------------- -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 ffe319b..b43a0ff 100644 --- a/absl/flags/internal/type_erased.h +++ b/absl/flags/internal/type_erased.h
@@ -55,17 +55,6 @@ //----------------------------------------------------------------------------- -// 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/flags/parse.cc b/absl/flags/parse.cc index 66a28a9..2e8f03b 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc
@@ -67,6 +67,22 @@ ABSL_CONST_INIT bool tryfromenv_needs_processing ABSL_GUARDED_BY(processing_checks_guard) = false; +ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit); +ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags + ABSL_GUARDED_BY(specified_flags_guard) = nullptr; + +struct SpecifiedFlagsCompare { + bool operator()(const CommandLineFlag* a, const CommandLineFlag* b) const { + return a->Name() < b->Name(); + } + bool operator()(const CommandLineFlag* a, absl::string_view b) const { + return a->Name() < b; + } + bool operator()(absl::string_view a, const CommandLineFlag* b) const { + return a < b->Name(); + } +}; + } // namespace } // namespace flags_internal ABSL_NAMESPACE_END @@ -577,6 +593,17 @@ // -------------------------------------------------------------------- +bool WasPresentOnCommandLine(absl::string_view flag_name) { + absl::MutexLock l(&specified_flags_guard); + ABSL_INTERNAL_CHECK(specified_flags != nullptr, + "ParseCommandLine is not invoked yet"); + + return std::binary_search(specified_flags->begin(), specified_flags->end(), + flag_name, SpecifiedFlagsCompare{}); +} + +// -------------------------------------------------------------------- + std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], ArgvListAction arg_list_act, UsageFlagsAction usage_flag_act, @@ -607,6 +634,13 @@ } output_args.push_back(argv[0]); + absl::MutexLock l(&specified_flags_guard); + if (specified_flags == nullptr) { + specified_flags = new std::vector<const CommandLineFlag*>; + } else { + specified_flags->clear(); + } + // Iterate through the list of the input arguments. First level are arguments // originated from argc/argv. Following levels are arguments originated from // recursive parsing of flagfile(s). @@ -702,6 +736,8 @@ flag, value, SET_FLAGS_VALUE, kCommandLine, &error)) { flags_internal::ReportUsageError(error, true); success = false; + } else { + specified_flags->push_back(flag); } } @@ -753,6 +789,10 @@ } } + // Trim and sort the vector. + specified_flags->shrink_to_fit(); + std::sort(specified_flags->begin(), specified_flags->end(), + SpecifiedFlagsCompare{}); return output_args; }
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc index 065f757..e6a53ae 100644 --- a/absl/flags/parse_test.cc +++ b/absl/flags/parse_test.cc
@@ -869,4 +869,26 @@ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3); } +// -------------------------------------------------------------------- + +TEST_F(ParseTest, WasPresentOnCommandLine) { + const char* in_args1[] = { + "testbin", "arg1", "--bool_flag", + "--int_flag=211", "arg2", "--double_flag=1.1", + "--string_flag", "asd", "--", + "--some_flag", "arg4", + }; + + InvokeParse(in_args1); + + EXPECT_TRUE(flags::WasPresentOnCommandLine("bool_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("int_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("double_flag")); + EXPECT_TRUE(flags::WasPresentOnCommandLine("string_flag")); + EXPECT_FALSE(flags::WasPresentOnCommandLine("some_flag")); + EXPECT_FALSE(flags::WasPresentOnCommandLine("another_flag")); +} + +// -------------------------------------------------------------------- + } // namespace
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index 1c9dabb..dc45281 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel
@@ -37,9 +37,6 @@ hdrs = ["traits.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/random:__pkg__", - ], deps = ["//absl/base:config"], ) @@ -48,9 +45,6 @@ hdrs = ["distribution_caller.h"], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/random:__pkg__", - ], deps = ["//absl/base:config"], ) @@ -76,9 +70,6 @@ ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/random:__pkg__", - ], deps = ["//absl/base:config"], ) @@ -517,9 +508,6 @@ 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 @@ 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 0403cc6..1ddd6ae 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc
@@ -20,6 +20,7 @@ #include <cstdio> #include <cstdlib> #include <iomanip> +#include <iostream> #include <limits> #include <ostream> #include <sstream>
diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 86ae76f..3be8d7d 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h
@@ -65,7 +65,7 @@ #include <cstddef> #include <cstdint> #include <cstring> -#include <iostream> +#include <iosfwd> #include <iterator> #include <string> #include <type_traits>
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 964f25f..02646ad 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc
@@ -302,7 +302,7 @@ return ConvertFloatImpl(static_cast<double>(v), conv, sink); default: - return false; + ABSL_INTERNAL_ASSUME(false); } if (conv.is_basic()) { @@ -321,7 +321,6 @@ inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { - if (conv.conversion_char() != FormatConversionCharInternal::s) return false; if (conv.is_basic()) { sink->Append(v); return true; @@ -366,7 +365,6 @@ // ==================== Raw pointers ==================== ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { - if (conv.conversion_char() != FormatConversionCharInternal::p) return {false}; if (!v.value) { sink->Append("(nil)"); return {true};
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h index 9a1e5ef..8f79948 100644 --- a/absl/strings/internal/str_format/arg.h +++ b/absl/strings/internal/str_format/arg.h
@@ -86,10 +86,6 @@ StringConvertResult FormatConvertImpl(const AbslCord& value, FormatConversionSpecImpl conv, FormatSinkImpl* sink) { - if (conv.conversion_char() != FormatConversionCharInternal::s) { - return {false}; - } - bool is_left = conv.has_left_flag(); size_t space_remaining = 0; @@ -249,6 +245,15 @@ } }; +template <typename Arg> +constexpr FormatConversionCharSet ArgumentToConv() { + return absl::str_format_internal::ExtractCharSet( + decltype(str_format_internal::FormatConvertImpl( + std::declval<const Arg&>(), + std::declval<const FormatConversionSpecImpl&>(), + std::declval<FormatSinkImpl*>())){}); +} + // A type-erased handle to a format argument. class FormatArgImpl { private: @@ -411,9 +416,13 @@ return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), std::is_enum<T>()); } - + if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(), + spec.conversion_char()))) { + return false; + } return str_format_internal::FormatConvertImpl( - Manager<T>::Value(arg), spec, static_cast<FormatSinkImpl*>(out)) + Manager<T>::Value(arg), spec, + static_cast<FormatSinkImpl*>(out)) .value; }
diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h index 73ef05f..424c51f 100644 --- a/absl/strings/internal/str_format/checker.h +++ b/absl/strings/internal/str_format/checker.h
@@ -24,15 +24,6 @@ return b && AllOf(t...); } -template <typename Arg> -constexpr FormatConversionCharSet ArgumentToConv() { - return absl::str_format_internal::ExtractCharSet( - decltype(str_format_internal::FormatConvertImpl( - std::declval<const Arg&>(), - std::declval<const FormatConversionSpecImpl&>(), - std::declval<FormatSinkImpl*>())){}); -} - #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER constexpr bool ContainsChar(const char* chars, char c) {
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index ce78a02..36e7064 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h
@@ -327,12 +327,16 @@ static_cast<uint64_t>(FormatConversionCharSetUnion(rest...))); } +constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) { + return uint64_t{1} << (1 + static_cast<uint8_t>(c)); +} + constexpr uint64_t FormatConversionCharToConvInt(char conv) { return -#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ - conv == #c[0] ? (uint64_t{1} << (1 + static_cast<uint8_t>( \ - FormatConversionCharInternal::c))) \ - : +#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ + conv == #c[0] \ + ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \ + : ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) #undef ABSL_INTERNAL_CHAR_SET_CASE conv == '*' @@ -406,6 +410,11 @@ static_cast<uint64_t>(c); } +// Checks whether all the characters in `c` are contained in `set` +constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) { + return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0; +} + // Return capacity - used, clipped to a minimum of 0. inline size_t Excess(size_t used, size_t capacity) { return used < capacity ? capacity - used : 0;
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h index 92c4723..c6da4dc 100644 --- a/absl/strings/substitute.h +++ b/absl/strings/substitute.h
@@ -120,7 +120,9 @@ // 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 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/strings/testdata/getline-1.txt b/absl/strings/testdata/getline-1.txt deleted file mode 100644 index 19b9097..0000000 --- a/absl/strings/testdata/getline-1.txt +++ /dev/null
@@ -1,3 +0,0 @@ -alpha - -beta gamma
diff --git a/absl/strings/testdata/getline-2.txt b/absl/strings/testdata/getline-2.txt deleted file mode 100644 index d6842d8..0000000 --- a/absl/strings/testdata/getline-2.txt +++ /dev/null
@@ -1 +0,0 @@ -one.two.three
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 961ff52..876698c 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h
@@ -769,6 +769,8 @@ // class CondVar { public: + // A `CondVar` allocated on the heap or on the stack can use the this + // constructor. CondVar(); ~CondVar(); @@ -900,9 +902,11 @@ }; #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 constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {} inline CondVar::CondVar() : cv_(0) {} -#endif + +#endif // ABSL_INTERNAL_USE_NONPROD_MUTEX // static template <typename T>
diff --git a/absl/time/duration.cc b/absl/time/duration.cc index f018255..d0f1aad 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 @@ // 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 @@ // 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 @@ // 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; + if (absl::ConsumePrefix(&dur_sv, "-")) { + sign = -1; + } else { + absl::ConsumePrefix(&dur_sv, "+"); } - - // Can't parse a duration from an empty string. - if (*start == '\0') { - return false; - } + 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 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 ee088f3..228940e 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 @@ } // 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 @@ 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 @@ // 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 152f3ff..b456a13 100644 --- a/absl/time/time.h +++ b/absl/time/time.h
@@ -545,7 +545,7 @@ // 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 @@ // 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::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 @@ // 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 @@ // 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); // ============================================================================