diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index a5c9bc0..ccd409f 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake
@@ -135,7 +135,6 @@ "random/exponential_distribution.h" "random/gaussian_distribution.cc" "random/gaussian_distribution.h" - "random/internal/distributions.h" "random/internal/distribution_caller.h" "random/internal/fast_uniform_bits.h" "random/internal/fastmath.h"
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index 3681082..2d6f799 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel
@@ -27,28 +27,18 @@ licenses(["notice"]) # Apache 2.0 cc_library( - name = "flag_internal", - srcs = [ - "internal/flag.cc", - ], + name = "path_util", hdrs = [ - "internal/flag.h", + "internal/path_util.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = ["//absl/base:__subpackages__"], + visibility = [ + "//absl/flags:__pkg__", + ], deps = [ - ":config", - ":handle", - ":marshalling", - ":registry", - "//absl/base", "//absl/base:config", - "//absl/base:core_headers", - "//absl/memory", - "//absl/meta:type_traits", "//absl/strings", - "//absl/synchronization", ], ) @@ -75,22 +65,6 @@ ) cc_library( - name = "path_util", - hdrs = [ - "internal/path_util.h", - ], - copts = ABSL_DEFAULT_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/flags:__pkg__", - ], - deps = [ - "//absl/base:config", - "//absl/strings", - ], -) - -cc_library( name = "config", srcs = [ "usage_config.cc", @@ -131,23 +105,33 @@ ) cc_library( - name = "handle", - srcs = [ - "internal/commandlineflag.cc", - ], + name = "commandlineflag_internal", hdrs = [ "internal/commandlineflag.h", ], copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, - visibility = [ - "//absl/flags:__pkg__", - ], + visibility = ["//visibility:private"], deps = [ "//absl/base:config", "//absl/base:core_headers", "//absl/base:fast_type_id", "//absl/strings", + ], +) + +cc_library( + name = "commandlineflag", + srcs = [ + "commandlineflag.cc", + ], + hdrs = [ + "commandlineflag.h", + ], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":commandlineflag_internal", "//absl/types:optional", ], ) @@ -165,7 +149,7 @@ visibility = [ "//absl/flags:__pkg__", ], - deps = [":handle"], + deps = [":commandlineflag"], ) cc_library( @@ -184,8 +168,9 @@ "//absl/flags:__pkg__", ], deps = [ + ":commandlineflag", + ":commandlineflag_internal", ":config", - ":handle", ":private_handle_accessor", "//absl/base:config", "//absl/base:core_headers", @@ -196,6 +181,32 @@ ) cc_library( + name = "flag_internal", + srcs = [ + "internal/flag.cc", + ], + hdrs = [ + "internal/flag.h", + ], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = ["//absl/base:__subpackages__"], + deps = [ + ":commandlineflag", + ":config", + ":marshalling", + ":registry", + "//absl/base", + "//absl/base:config", + "//absl/base:core_headers", + "//absl/memory", + "//absl/meta:type_traits", + "//absl/strings", + "//absl/synchronization", + ], +) + +cc_library( name = "flag", srcs = [ "flag.cc", @@ -209,7 +220,6 @@ deps = [ ":config", ":flag_internal", - ":handle", ":marshalling", ":registry", "//absl/base", @@ -233,10 +243,10 @@ "//absl/flags:__pkg__", ], deps = [ + ":commandlineflag", ":config", ":flag", ":flag_internal", - ":handle", ":path_util", ":private_handle_accessor", ":program_name", @@ -276,10 +286,10 @@ copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ + ":commandlineflag", ":config", ":flag", ":flag_internal", - ":handle", ":private_handle_accessor", ":program_name", ":registry", @@ -299,14 +309,14 @@ name = "commandlineflag_test", size = "small", srcs = [ - "internal/commandlineflag_test.cc", + "commandlineflag_test.cc", ], copts = ABSL_TEST_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ + ":commandlineflag", ":config", ":flag", - ":handle", ":private_handle_accessor", ":registry", "//absl/memory", @@ -342,7 +352,6 @@ ":config", ":flag", ":flag_internal", - ":handle", ":registry", "//absl/base:core_headers", "//absl/base:malloc_internal", @@ -384,20 +393,6 @@ ) cc_test( - name = "path_util_test", - size = "small", - srcs = [ - "internal/path_util_test.cc", - ], - copts = ABSL_TEST_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - ":path_util", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( name = "parse_test", size = "small", srcs = [ @@ -418,6 +413,20 @@ ) cc_test( + name = "path_util_test", + size = "small", + srcs = [ + "internal/path_util_test.cc", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":path_util", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( name = "program_name_test", size = "small", srcs = [ @@ -442,7 +451,6 @@ linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":flag", - ":handle", ":marshalling", ":registry", "//absl/memory",
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index e6b17c9..6ecf3b4 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt
@@ -17,24 +17,16 @@ # Internal-only target, do not depend on directly. absl_cc_library( NAME - flags_internal - SRCS - "internal/flag.cc" + flags_path_util HDRS - "internal/flag.h" + "internal/path_util.h" COPTS ${ABSL_DEFAULT_COPTS} LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS - absl::base absl::config - absl::flags_config - absl::flags_handle - absl::flags_marshalling - absl::flags_registry - absl::synchronization - absl::meta + absl::strings PUBLIC ) @@ -59,22 +51,6 @@ PUBLIC ) -# Internal-only target, do not depend on directly. -absl_cc_library( - NAME - flags_path_util - HDRS - "internal/path_util.h" - COPTS - ${ABSL_DEFAULT_COPTS} - LINKOPTS - ${ABSL_DEFAULT_LINKOPTS} - DEPS - absl::config - absl::strings - PUBLIC -) - absl_cc_library( NAME flags_config @@ -118,9 +94,7 @@ # Internal-only target, do not depend on directly. absl_cc_library( NAME - flags_handle - SRCS - "internal/commandlineflag.cc" + flags_commandlineflag_internal HDRS "internal/commandlineflag.h" COPTS @@ -129,12 +103,25 @@ ${ABSL_DEFAULT_LINKOPTS} DEPS absl::config - absl::fast_type_id absl::core_headers - absl::optional - absl::raw_logging_internal + absl::fast_type_id absl::strings - absl::synchronization +) + +absl_cc_library( + NAME + flags_commandlineflag + SRCS + "commandlineflag.cc" + HDRS + "commandlineflag.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::flags_commandlineflag_internal + absl::optional ) # Internal-only target, do not depend on directly. @@ -150,7 +137,7 @@ LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS - absl::flags_handle + absl::flags_commandlineflag ) # Internal-only target, do not depend on directly. @@ -169,8 +156,8 @@ ${ABSL_DEFAULT_LINKOPTS} DEPS absl::config + absl::flags_commandlineflag absl::flags_config - absl::flags_handle absl::flags_private_handle_accessor absl::core_headers absl::raw_logging_internal @@ -178,6 +165,29 @@ absl::synchronization ) +# Internal-only target, do not depend on directly. +absl_cc_library( + NAME + flags_internal + SRCS + "internal/flag.cc" + HDRS + "internal/flag.h" + COPTS + ${ABSL_DEFAULT_COPTS} + LINKOPTS + ${ABSL_DEFAULT_LINKOPTS} + DEPS + absl::base + absl::config + absl::flags_config + absl::flags_marshalling + absl::flags_registry + absl::synchronization + absl::meta + PUBLIC +) + absl_cc_library( NAME flags @@ -192,8 +202,8 @@ ${ABSL_DEFAULT_LINKOPTS} DEPS absl::config + absl::flags_commandlineflag absl::flags_config - absl::flags_handle absl::flags_internal absl::flags_marshalling absl::flags_registry @@ -218,10 +228,10 @@ absl::config absl::flags_config absl::flags - absl::flags_handle - absl::flags_private_handle_accessor + absl::flags_commandlineflag absl::flags_internal absl::flags_path_util + absl::flags_private_handle_accessor absl::flags_program_name absl::flags_registry absl::strings @@ -264,9 +274,9 @@ absl::core_headers absl::flags_config absl::flags - absl::flags_handle - absl::flags_private_handle_accessor + absl::flags_commandlineflag absl::flags_internal + absl::flags_private_handle_accessor absl::flags_program_name absl::flags_registry absl::flags_usage @@ -281,13 +291,13 @@ NAME flags_commandlineflag_test SRCS - "internal/commandlineflag_test.cc" + "commandlineflag_test.cc" COPTS ${ABSL_TEST_COPTS} DEPS absl::flags + absl::flags_commandlineflag absl::flags_config - absl::flags_handle absl::flags_private_handle_accessor absl::flags_registry absl::memory @@ -319,7 +329,6 @@ absl::core_headers absl::flags absl::flags_config - absl::flags_handle absl::flags_internal absl::flags_registry absl::strings @@ -391,7 +400,6 @@ ${ABSL_TEST_COPTS} DEPS absl::flags - absl::flags_handle absl::flags_marshalling absl::flags_registry absl::memory
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/commandlineflag.cc similarity index 89% rename from absl/flags/internal/commandlineflag.cc rename to absl/flags/commandlineflag.cc index 8411243..cea5723 100644 --- a/absl/flags/internal/commandlineflag.cc +++ b/absl/flags/commandlineflag.cc
@@ -13,21 +13,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/commandlineflag.h" namespace absl { ABSL_NAMESPACE_BEGIN -namespace flags_internal { - -FlagStateInterface::~FlagStateInterface() {} bool CommandLineFlag::IsRetired() const { return false; } - bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) { return ParseFrom(value, flags_internal::SET_FLAGS_VALUE, - flags_internal::kProgrammaticChange, error); + flags_internal::kProgrammaticChange, *error); } +namespace flags_internal { +FlagStateInterface::~FlagStateInterface() {} } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl
diff --git a/absl/flags/commandlineflag.h b/absl/flags/commandlineflag.h new file mode 100644 index 0000000..43055d0 --- /dev/null +++ b/absl/flags/commandlineflag.h
@@ -0,0 +1,190 @@ +// +// 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. +// +// ----------------------------------------------------------------------------- +// File: commandlineflag.h +// ----------------------------------------------------------------------------- +// +// This header file defines the `CommandLineFlag`, which acts as a type-erased +// handle for accessing metadata about the Abseil Flag in question. +// +// Because an actual Abseil flag is of an unspecified type, you should not +// manipulate or interact directly with objects of that type. Instead, use the +// CommandLineFlag type as an intermediary. +#ifndef ABSL_FLAGS_COMMANDLINEFLAG_H_ +#define ABSL_FLAGS_COMMANDLINEFLAG_H_ + +#include "absl/flags/internal/commandlineflag.h" +#include "absl/types/optional.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace flags_internal { +class PrivateHandleAccessor; +} // namespace flags_internal + +// CommandLineFlag +// +// This type acts as a type-erased handle for an instance of an Abseil Flag and +// holds reflection information pertaining to that flag. Use CommandLineFlag to +// access a flag's name, location, help string etc. +// +// To obtain an absl::CommandLineFlag, invoke `absl::FindCommandLineFlag()` +// passing it the flag name string. +// +// Example: +// +// // Obtain reflection handle for a flag named "flagname". +// const absl::CommandLineFlag* my_flag_data = +// absl::FindCommandLineFlag("flagname"); +// +// // Now you can get flag info from that reflection handle. +// std::string flag_location = my_flag_data->Filename(); +// ... +class CommandLineFlag { + public: + constexpr CommandLineFlag() = default; + + // Not copyable/assignable. + CommandLineFlag(const CommandLineFlag&) = delete; + CommandLineFlag& operator=(const CommandLineFlag&) = delete; + + // absl::CommandLineFlag::IsOfType() + // + // Return true iff flag has type T. + template <typename T> + inline bool IsOfType() const { + return TypeId() == base_internal::FastTypeId<T>(); + } + + // absl::CommandLineFlag::TryGet() + // + // Attempts to retrieve the flag value. Returns value on success, + // absl::nullopt otherwise. + template <typename T> + absl::optional<T> TryGet() const { + if (IsRetired() || !IsOfType<T>()) { + return absl::nullopt; + } + + // Implementation notes: + // + // We are wrapping a union around the value of `T` to serve three purposes: + // + // 1. `U.value` has correct size and alignment for a value of type `T` + // 2. The `U.value` constructor is not invoked since U's constructor does + // not do it explicitly. + // 3. The `U.value` destructor is invoked since U's destructor does it + // explicitly. This makes `U` a kind of RAII wrapper around non default + // constructible value of T, which is destructed when we leave the + // scope. We do need to destroy U.value, which is constructed by + // CommandLineFlag::Read even though we left it in a moved-from state + // after std::move. + // + // All of this serves to avoid requiring `T` being default constructible. + union U { + T value; + U() {} + ~U() { value.~T(); } + }; + U u; + + Read(&u.value); + return std::move(u.value); + } + + // absl::CommandLineFlag::Name() + // + // Returns name of this flag. + virtual absl::string_view Name() const = 0; + + // absl::CommandLineFlag::Filename() + // + // Returns name of the file where this flag is defined. + virtual std::string Filename() const = 0; + + // absl::CommandLineFlag::Help() + // + // Returns help message associated with this flag. + virtual std::string Help() const = 0; + + // absl::CommandLineFlag::IsRetired() + // + // Returns true iff this object corresponds to retired flag. + virtual bool IsRetired() const; + + // absl::CommandLineFlag::DefaultValue() + // + // Returns the default value for this flag. + virtual std::string DefaultValue() const = 0; + + // absl::CommandLineFlag::CurrentValue() + // + // Returns the current value for this flag. + virtual std::string CurrentValue() const = 0; + + // absl::CommandLineFlag::ParseFrom() + // + // Sets the value of the flag based on specified string `value`. If the flag + // was successfully set to new value, it returns true. Otherwise, sets `error` + // to indicate the error, leaves the flag unchanged, and returns false. + bool ParseFrom(absl::string_view value, std::string* error); + + protected: + ~CommandLineFlag() = default; + + private: + friend class flags_internal::PrivateHandleAccessor; + + // Sets the value of the flag based on specified string `value`. If the flag + // was successfully set to new value, it returns true. Otherwise, sets `error` + // to indicate the error, leaves the flag unchanged, and returns false. There + // are three ways to set the flag's value: + // * Update the current flag value + // * Update the flag's default value + // * Update the current flag value if it was never set before + // The mode is selected based on `set_mode` parameter. + virtual bool ParseFrom(absl::string_view value, + flags_internal::FlagSettingMode set_mode, + flags_internal::ValueSource source, + std::string& error) = 0; + + // Returns id of the flag's value type. + virtual flags_internal::FlagFastTypeId TypeId() const = 0; + + // Interface to save flag to some persistent state. Returns current flag state + // or nullptr if flag does not support saving and restoring a state. + virtual std::unique_ptr<flags_internal::FlagStateInterface> SaveState() = 0; + + // Copy-construct a new value of the flag's type in a memory referenced by + // 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; + + // Checks that flags default value can be converted to string and back to the + // flag's value type. + virtual void CheckDefaultValueParsingRoundtrip() const = 0; +}; + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_FLAGS_COMMANDLINEFLAG_H_
diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/commandlineflag_test.cc similarity index 79% rename from absl/flags/internal/commandlineflag_test.cc rename to absl/flags/commandlineflag_test.cc index 0b5aea3..4b9718e 100644 --- a/absl/flags/internal/commandlineflag_test.cc +++ b/absl/flags/commandlineflag_test.cc
@@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/commandlineflag.h" #include <memory> #include <string> @@ -70,9 +70,10 @@ EXPECT_EQ(flag_01->Help(), "int_flag help"); EXPECT_TRUE(!flag_01->IsRetired()); EXPECT_TRUE(flag_01->IsOfType<int>()); - EXPECT_TRUE( - absl::EndsWith(flag_01->Filename(), - "absl/flags/internal/commandlineflag_test.cc")) + EXPECT_TRUE(!flag_01->IsOfType<bool>()); + EXPECT_TRUE(!flag_01->IsOfType<std::string>()); + EXPECT_TRUE(absl::EndsWith(flag_01->Filename(), + "absl/flags/commandlineflag_test.cc")) << flag_01->Filename(); auto* flag_02 = flags::FindCommandLineFlag("string_flag"); @@ -82,9 +83,10 @@ EXPECT_EQ(flag_02->Help(), "string_flag help"); EXPECT_TRUE(!flag_02->IsRetired()); EXPECT_TRUE(flag_02->IsOfType<std::string>()); - EXPECT_TRUE( - absl::EndsWith(flag_02->Filename(), - "absl/flags/internal/commandlineflag_test.cc")) + EXPECT_TRUE(!flag_02->IsOfType<bool>()); + EXPECT_TRUE(!flag_02->IsOfType<int>()); + EXPECT_TRUE(absl::EndsWith(flag_02->Filename(), + "absl/flags/commandlineflag_test.cc")) << flag_02->Filename(); auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag"); @@ -94,6 +96,8 @@ EXPECT_EQ(flag_03->Help(), ""); EXPECT_TRUE(flag_03->IsRetired()); EXPECT_TRUE(flag_03->IsOfType<bool>()); + EXPECT_TRUE(!flag_03->IsOfType<int>()); + EXPECT_TRUE(!flag_03->IsOfType<std::string>()); EXPECT_EQ(flag_03->Filename(), "RETIRED"); } @@ -125,57 +129,57 @@ flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); + *flag_01, "11", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11); EXPECT_FALSE( flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, - &err)); + *flag_01, "-123", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123); EXPECT_FALSE( flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( - flag_01, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, - &err)); + *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( flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( - flag_01, "A1", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); + *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( flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, - &err)); + *flag_01, "0x10", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16); EXPECT_FALSE( flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, &err)); + *flag_01, "011", flags::SET_FLAGS_VALUE, flags::kCommandLine, err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11); EXPECT_TRUE(flags::PrivateHandleAccessor::IsSpecifiedOnCommandLine(*flag_01)); EXPECT_TRUE(!flags::PrivateHandleAccessor::ParseFrom( - flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); + *flag_01, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err)); EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'"); auto* flag_02 = flags::FindCommandLineFlag("string_flag"); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, - &err)); + *flag_02, "xyz", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz"); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_02, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, &err)); + *flag_02, "", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, err)); EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), ""); } @@ -187,15 +191,15 @@ auto* flag_01 = flags::FindCommandLineFlag("int_flag"); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange, - &err)); + *flag_01, "111", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(flag_01->DefaultValue(), "111"); auto* flag_02 = flags::FindCommandLineFlag("string_flag"); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange, - &err)); + *flag_02, "abc", flags::SET_FLAGS_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(flag_02->DefaultValue(), "abc"); } @@ -207,25 +211,25 @@ auto* flag_01 = flags::FindCommandLineFlag("int_flag"); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, - &err)) + *flag_01, "22", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, + err)) << err; EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, - &err)); + *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22); // EXPECT_EQ(err, "ERROR: int_flag is already set to 22"); // Reset back to default value EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "201", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, - &err)); + *flag_01, "201", flags::SET_FLAGS_VALUE, flags::kProgrammaticChange, + err)); EXPECT_TRUE(flags::PrivateHandleAccessor::ParseFrom( - flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, - &err)); + *flag_01, "33", flags::SET_FLAG_IF_DEFAULT, flags::kProgrammaticChange, + err)); EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201); // EXPECT_EQ(err, "ERROR: int_flag is already set to 201"); }
diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc index f7a457b..531df12 100644 --- a/absl/flags/flag.cc +++ b/absl/flags/flag.cc
@@ -16,8 +16,6 @@ #include "absl/flags/flag.h" #include "absl/base/config.h" -#include "absl/flags/internal/commandlineflag.h" -#include "absl/flags/internal/flag.h" namespace absl { ABSL_NAMESPACE_BEGIN
diff --git a/absl/flags/flag.h b/absl/flags/flag.h index ca7d581..dd36e6c 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h
@@ -37,7 +37,6 @@ #include "absl/base/config.h" #include "absl/flags/config.h" #include "absl/flags/declare.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/registry.h" #include "absl/flags/marshalling.h" @@ -111,12 +110,12 @@ impl_(nullptr) {} #endif - flags_internal::Flag<T>* GetImpl() const { + flags_internal::Flag<T>& GetImpl() const { if (!inited_.load(std::memory_order_acquire)) { absl::MutexLock l(flags_internal::GetGlobalConstructionGuard()); if (inited_.load(std::memory_order_acquire)) { - return impl_; + return *impl_; } impl_ = new flags_internal::Flag<T>( @@ -128,28 +127,28 @@ inited_.store(true, std::memory_order_release); } - return impl_; + return *impl_; } // Public methods of `absl::Flag<T>` are NOT part of the Abseil Flags API. // See https://abseil.io/docs/cpp/guides/flags - bool IsRetired() const { return GetImpl()->IsRetired(); } - absl::string_view Name() const { return GetImpl()->Name(); } - std::string Help() const { return GetImpl()->Help(); } - bool IsModified() const { return GetImpl()->IsModified(); } + bool IsRetired() const { return GetImpl().IsRetired(); } + absl::string_view Name() const { return GetImpl().Name(); } + std::string Help() const { return GetImpl().Help(); } + bool IsModified() const { return GetImpl().IsModified(); } bool IsSpecifiedOnCommandLine() const { - return GetImpl()->IsSpecifiedOnCommandLine(); + return GetImpl().IsSpecifiedOnCommandLine(); } - std::string Filename() const { return GetImpl()->Filename(); } - std::string DefaultValue() const { return GetImpl()->DefaultValue(); } - std::string CurrentValue() const { return GetImpl()->CurrentValue(); } + std::string Filename() const { return GetImpl().Filename(); } + std::string DefaultValue() const { return GetImpl().DefaultValue(); } + std::string CurrentValue() const { return GetImpl().CurrentValue(); } template <typename U> inline bool IsOfType() const { - return GetImpl()->template IsOfType<U>(); + return GetImpl().template IsOfType<U>(); } - T Get() const { return GetImpl()->Get(); } - void Set(const T& v) { GetImpl()->Set(v); } - void InvokeCallback() { GetImpl()->InvokeCallback(); } + T Get() const { return GetImpl().Get(); } + void Set(const T& v) { GetImpl().Set(v); } + void InvokeCallback() { GetImpl().InvokeCallback(); } // The data members are logically private, but they need to be public for // this to be an aggregate type. @@ -265,27 +264,29 @@ // ----------------------------------------------------------------------------- // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES +#if !defined(_MSC_VER) || defined(__clang__) +#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag +#define ABSL_FLAG_IMPL_HELP_ARG(name) \ + absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>( \ + FLAGS_help_storage_##name) +#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) \ + absl::flags_internal::DefaultArg<Type, AbslFlagDefaultGenFor##name>(0) +#else +#define ABSL_FLAG_IMPL_FLAG_PTR(flag) flag.GetImpl() +#define ABSL_FLAG_IMPL_HELP_ARG(name) &AbslFlagHelpGenFor##name::NonConst +#define ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name) &AbslFlagDefaultGenFor##name::Gen +#endif #if ABSL_FLAGS_STRIP_NAMES #define ABSL_FLAG_IMPL_FLAGNAME(txt) "" #define ABSL_FLAG_IMPL_FILENAME() "" -#if !defined(_MSC_VER) || defined(__clang__) #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar<T, false>(&flag) -#else -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar<T, false>(flag.GetImpl()) -#endif + absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag)) #else #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt #define ABSL_FLAG_IMPL_FILENAME() __FILE__ -#if !defined(_MSC_VER) || defined(__clang__) #define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar<T, true>(&flag) -#else -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar<T, true>(flag.GetImpl()) -#endif + absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag)) #endif // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP @@ -301,15 +302,24 @@ // between the two via the call to HelpArg in absl::Flag instantiation below. // If help message expression is constexpr evaluable compiler will optimize // away this whole struct. -#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \ - struct AbslFlagHelpGenFor##name { \ - template <typename T = void> \ - static constexpr const char* Const() { \ - return absl::flags_internal::HelpConstexprWrap( \ - ABSL_FLAG_IMPL_FLAGHELP(txt)); \ - } \ - static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \ - } +// TODO(rogeeff): place these generated structs into local namespace and apply +// ABSL_INTERNAL_UNIQUE_SHORT_NAME. +// TODO(rogeeff): Apply __attribute__((nodebug)) to FLAGS_help_storage_##name +#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \ + struct AbslFlagHelpGenFor##name { \ + /* The expression is run in the caller as part of the */ \ + /* default value argument. That keeps temporaries alive */ \ + /* long enough for NonConst to work correctly. */ \ + static constexpr absl::string_view Value( \ + absl::string_view v = ABSL_FLAG_IMPL_FLAGHELP(txt)) { \ + return v; \ + } \ + static std::string NonConst() { return std::string(Value()); } \ + }; \ + constexpr auto FLAGS_help_storage_##name ABSL_INTERNAL_UNIQUE_SMALL_NAME() \ + ABSL_ATTRIBUTE_SECTION_VARIABLE(flags_help_cold) = \ + absl::flags_internal::HelpStringAsArray<AbslFlagHelpGenFor##name>( \ + 0); #define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ struct AbslFlagDefaultGenFor##name { \ @@ -317,40 +327,23 @@ static void Gen(void* p) { \ new (p) Type(AbslFlagDefaultGenFor##name{}.value); \ } \ - } + }; // ABSL_FLAG_IMPL // // Note: Name of registrar object is not arbitrary. It is used to "grab" // global name for FLAGS_no<flag_name> symbol, thus preventing the possibility // of defining two flags with names foo and nofoo. -#if !defined(_MSC_VER) || defined(__clang__) - -#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ - namespace absl /* block flags in namespaces */ {} \ - ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value); \ - ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help); \ - ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{ \ - ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ - absl::flags_internal::HelpArg<AbslFlagHelpGenFor##name>(0), \ - absl::flags_internal::DefaultArg<Type, AbslFlagDefaultGenFor##name>(0)}; \ - extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \ - absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \ +#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ + namespace absl /* block flags in namespaces */ {} \ + ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ + ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \ + ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{ \ + ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ + ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \ + extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \ + absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \ ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) -#else -// MSVC version uses aggregate initialization. We also do not try to -// optimize away help wrapper. -#define ABSL_FLAG_IMPL(Type, name, default_value, help) \ - namespace absl /* block flags in namespaces */ {} \ - ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value); \ - ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help); \ - ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{ \ - ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \ - &AbslFlagHelpGenFor##name::NonConst, &AbslFlagDefaultGenFor##name::Gen}; \ - extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \ - absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \ - ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name) -#endif // ABSL_RETIRED_FLAG //
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 416a31e..58a0799 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc
@@ -26,7 +26,6 @@ #include "absl/base/attributes.h" #include "absl/flags/config.h" #include "absl/flags/declare.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/registry.h" #include "absl/flags/usage_config.h" @@ -151,21 +150,21 @@ DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc); template <typename T> -bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>* f2) { +bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>& f2) { EXPECT_EQ(f1.Name(), "f1"); EXPECT_EQ(f1.Help(), "literal help"); EXPECT_EQ(f1.Filename(), "file"); flags::FlagRegistrar<T, false>(f2).OnUpdate(TestCallback); - EXPECT_EQ(f2->Name(), "f2"); - EXPECT_EQ(f2->Help(), "dynamic help"); - EXPECT_EQ(f2->Filename(), "file"); + EXPECT_EQ(f2.Name(), "f2"); + EXPECT_EQ(f2.Help(), "dynamic help"); + EXPECT_EQ(f2.Filename(), "file"); return true; } -#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T); +#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, f2##T); TEST_F(FlagTest, TestConstruction) { TEST_CONSTRUCTED_FLAG(bool);
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h index fa05020..3c14978 100644 --- a/absl/flags/internal/commandlineflag.h +++ b/absl/flags/internal/commandlineflag.h
@@ -23,7 +23,6 @@ #include "absl/base/internal/fast_type_id.h" #include "absl/base/macros.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -67,117 +66,6 @@ virtual void Restore() const = 0; }; -// Holds all information for a flag. -class CommandLineFlag { - public: - constexpr CommandLineFlag() = default; - - // Not copyable/assignable. - CommandLineFlag(const CommandLineFlag&) = delete; - CommandLineFlag& operator=(const CommandLineFlag&) = delete; - - // Non-polymorphic access methods. - - // Return true iff flag has type T. - template <typename T> - inline bool IsOfType() const { - return TypeId() == base_internal::FastTypeId<T>(); - } - - // Attempts to retrieve the flag value. Returns value on success, - // absl::nullopt otherwise. - template <typename T> - absl::optional<T> TryGet() const { - if (IsRetired() || !IsOfType<T>()) { - return absl::nullopt; - } - - // Implementation notes: - // - // We are wrapping a union around the value of `T` to serve three purposes: - // - // 1. `U.value` has correct size and alignment for a value of type `T` - // 2. The `U.value` constructor is not invoked since U's constructor does - // not do it explicitly. - // 3. The `U.value` destructor is invoked since U's destructor does it - // explicitly. This makes `U` a kind of RAII wrapper around non default - // constructible value of T, which is destructed when we leave the - // scope. We do need to destroy U.value, which is constructed by - // CommandLineFlag::Read even though we left it in a moved-from state - // after std::move. - // - // All of this serves to avoid requiring `T` being default constructible. - union U { - T value; - U() {} - ~U() { value.~T(); } - }; - U u; - - Read(&u.value); - return std::move(u.value); - } - - // Polymorphic access methods - - // Returns name of this flag. - virtual absl::string_view Name() const = 0; - // Returns name of the file where this flag is defined. - virtual std::string Filename() const = 0; - // Returns help message associated with this flag. - virtual std::string Help() const = 0; - // Returns true iff this object corresponds to retired flag. - virtual bool IsRetired() const; - virtual std::string DefaultValue() const = 0; - virtual std::string CurrentValue() const = 0; - - // Sets the value of the flag based on specified string `value`. If the flag - // was successfully set to new value, it returns true. Otherwise, sets `error` - // to indicate the error, leaves the flag unchanged, and returns false. - bool ParseFrom(absl::string_view value, std::string* error); - - protected: - ~CommandLineFlag() = default; - - private: - friend class PrivateHandleAccessor; - - // Sets the value of the flag based on specified string `value`. If the flag - // was successfully set to new value, it returns true. Otherwise, sets `error` - // to indicate the error, leaves the flag unchanged, and returns false. There - // are three ways to set the flag's value: - // * Update the current flag value - // * Update the flag's default value - // * Update the current flag value if it was never set before - // The mode is selected based on `set_mode` parameter. - virtual bool ParseFrom(absl::string_view value, - flags_internal::FlagSettingMode set_mode, - flags_internal::ValueSource source, - std::string* error) = 0; - - // Returns id of the flag's value type. - virtual FlagFastTypeId TypeId() const = 0; - - // Interface to save flag to some persistent state. Returns current flag state - // or nullptr if flag does not support saving and restoring a state. - virtual std::unique_ptr<FlagStateInterface> SaveState() = 0; - - // Copy-construct a new value of the flag's type in a memory referenced by - // 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; - - // Checks that flags default value can be converted to string and back to the - // flag's value type. - virtual void CheckDefaultValueParsingRoundtrip() const = 0; -}; - } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index 96c026d..ee97424 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc
@@ -29,7 +29,6 @@ #include "absl/base/config.h" #include "absl/base/const_init.h" #include "absl/base/optimization.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/usage_config.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" @@ -63,14 +62,14 @@ // need to acquire these locks themselves. class MutexRelock { public: - explicit MutexRelock(absl::Mutex* mu) : mu_(mu) { mu_->Unlock(); } - ~MutexRelock() { mu_->Lock(); } + explicit MutexRelock(absl::Mutex& mu) : mu_(mu) { mu_.Unlock(); } + ~MutexRelock() { mu_.Lock(); } MutexRelock(const MutexRelock&) = delete; MutexRelock& operator=(const MutexRelock&) = delete; private: - absl::Mutex* mu_; + absl::Mutex& mu_; }; } // namespace @@ -83,7 +82,7 @@ class FlagState : public flags_internal::FlagStateInterface { public: template <typename V> - FlagState(FlagImpl* flag_impl, const V& v, bool modified, + FlagState(FlagImpl& flag_impl, const V& v, bool modified, bool on_command_line, int64_t counter) : flag_impl_(flag_impl), value_(v), @@ -92,9 +91,9 @@ counter_(counter) {} ~FlagState() override { - if (flag_impl_->ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer) + if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer) return; - flags_internal::Delete(flag_impl_->op_, value_.heap_allocated); + flags_internal::Delete(flag_impl_.op_, value_.heap_allocated); } private: @@ -102,15 +101,15 @@ // Restores the flag to the saved state. void Restore() const override { - if (!flag_impl_->RestoreState(*this)) return; + if (!flag_impl_.RestoreState(*this)) return; - ABSL_INTERNAL_LOG( - INFO, absl::StrCat("Restore saved value of ", flag_impl_->Name(), - " to: ", flag_impl_->CurrentValue())); + ABSL_INTERNAL_LOG(INFO, + absl::StrCat("Restore saved value of ", flag_impl_.Name(), + " to: ", flag_impl_.CurrentValue())); } // Flag and saved flag data. - FlagImpl* flag_impl_; + FlagImpl& flag_impl_; union SavedValue { explicit SavedValue(void* v) : heap_allocated(v) {} explicit SavedValue(int64_t v) : one_word(v) {} @@ -327,7 +326,7 @@ // and it also can be different by the time the callback invocation is // completed. Requires that *primary_lock be held in exclusive mode; it may be // released and reacquired by the implementation. - MutexRelock relock(DataGuard()); + MutexRelock relock(*DataGuard()); absl::MutexLock lock(&callback_->guard); cb(); } @@ -340,17 +339,17 @@ switch (ValueStorageKind()) { case FlagValueStorageKind::kAlignedBuffer: { return absl::make_unique<FlagState>( - this, flags_internal::Clone(op_, AlignedBufferValue()), modified, + *this, flags_internal::Clone(op_, AlignedBufferValue()), modified, on_command_line, counter_); } case FlagValueStorageKind::kOneWordAtomic: { return absl::make_unique<FlagState>( - this, OneWordValue().load(std::memory_order_acquire), modified, + *this, OneWordValue().load(std::memory_order_acquire), modified, on_command_line, counter_); } case FlagValueStorageKind::kTwoWordsAtomic: { return absl::make_unique<FlagState>( - this, TwoWordsValue().load(std::memory_order_acquire), modified, + *this, TwoWordsValue().load(std::memory_order_acquire), modified, on_command_line, counter_); } } @@ -411,14 +410,14 @@ // parsed value. In case if any error is encountered in either step, the error // message is stored in 'err' std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse( - absl::string_view value, std::string* err) const { + absl::string_view value, std::string& err) const { std::unique_ptr<void, DynValueDeleter> tentative_value = MakeInitValue(); std::string parse_err; if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) { absl::string_view err_sep = parse_err.empty() ? "" : "; "; - *err = absl::StrCat("Illegal value '", value, "' specified for flag '", - Name(), "'", err_sep, parse_err); + err = absl::StrCat("Illegal value '", value, "' specified for flag '", + Name(), "'", err_sep, parse_err); return nullptr; } @@ -474,7 +473,7 @@ // * Update the current flag value if it was never set before // The mode is selected based on 'set_mode' parameter. bool FlagImpl::ParseFrom(absl::string_view value, FlagSettingMode set_mode, - ValueSource source, std::string* err) { + ValueSource source, std::string& err) { absl::MutexLock l(DataGuard()); switch (set_mode) {
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index e374ecd..e188580 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h
@@ -28,8 +28,8 @@ #include "absl/base/call_once.h" #include "absl/base/config.h" #include "absl/base/thread_annotations.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/registry.h" #include "absl/flags/marshalling.h" #include "absl/memory/memory.h" @@ -168,6 +168,28 @@ // cases. using HelpGenFunc = std::string (*)(); +template <size_t N> +struct FixedCharArray { + char value[N]; + + template <size_t... I> + static constexpr FixedCharArray<N> FromLiteralString( + absl::string_view str, absl::index_sequence<I...>) { + return (void)str, FixedCharArray<N>({{str[I]..., '\0'}}); + } +}; + +template <typename Gen, size_t N = Gen::Value().size()> +constexpr FixedCharArray<N + 1> HelpStringAsArray(int) { + return FixedCharArray<N + 1>::FromLiteralString( + Gen::Value(), absl::make_index_sequence<N>{}); +} + +template <typename Gen> +constexpr std::false_type HelpStringAsArray(char) { + return std::false_type{}; +} + union FlagHelpMsg { constexpr explicit FlagHelpMsg(const char* help_msg) : literal(help_msg) {} constexpr explicit FlagHelpMsg(HelpGenFunc help_gen) : gen_func(help_gen) {} @@ -185,40 +207,28 @@ extern const char kStrippedFlagHelp[]; -// HelpConstexprWrap is used by struct AbslFlagHelpGenFor##name generated by -// ABSL_FLAG macro. It is only used to silence the compiler in the case where -// help message expression is not constexpr and does not have type const char*. -// If help message expression is indeed constexpr const char* HelpConstexprWrap -// is just a trivial identity function. -template <typename T> -const char* HelpConstexprWrap(const T&) { - return nullptr; -} -constexpr const char* HelpConstexprWrap(const char* p) { return p; } -constexpr const char* HelpConstexprWrap(char* p) { return p; } - // These two HelpArg overloads allows us to select at compile time one of two // way to pass Help argument to absl::Flag. We'll be passing -// AbslFlagHelpGenFor##name as T and integer 0 as a single argument to prefer -// first overload if possible. If T::Const is evaluatable on constexpr -// context (see non template int parameter below) we'll choose first overload. -// In this case the help message expression is immediately evaluated and is used -// to construct the absl::Flag. No additionl code is generated by ABSL_FLAG. -// Otherwise SFINAE kicks in and first overload is dropped from the +// AbslFlagHelpGenFor##name as Gen and integer 0 as a single argument to prefer +// first overload if possible. If help message is evaluatable on constexpr +// context We'll be able to make FixedCharArray out of it and we'll choose first +// overload. In this case the help message expression is immediately evaluated +// and is used to construct the absl::Flag. No additionl code is generated by +// ABSL_FLAG Otherwise SFINAE kicks in and first overload is dropped from the // consideration, in which case the second overload will be used. The second // overload does not attempt to evaluate the help message expression // immediately and instead delays the evaluation by returing the function // pointer (&T::NonConst) genering the help message when necessary. This is // evaluatable in constexpr context, but the cost is an extra function being // generated in the ABSL_FLAG code. -template <typename T, int = (T::Const(), 1)> -constexpr FlagHelpArg HelpArg(int) { - return {FlagHelpMsg(T::Const()), FlagHelpKind::kLiteral}; +template <typename Gen, size_t N> +constexpr FlagHelpArg HelpArg(const FixedCharArray<N>& value) { + return {FlagHelpMsg(value.value), FlagHelpKind::kLiteral}; } -template <typename T> -constexpr FlagHelpArg HelpArg(char) { - return {FlagHelpMsg(&T::NonConst), FlagHelpKind::kGenFunc}; +template <typename Gen> +constexpr FlagHelpArg HelpArg(std::false_type) { + return {FlagHelpMsg(&Gen::NonConst), FlagHelpKind::kGenFunc}; } /////////////////////////////////////////////////////////////////////////////// @@ -364,31 +374,31 @@ template <typename T> struct FlagValue<T, FlagValueStorageKind::kAlignedBuffer> { - bool Get(T*) const { return false; } + bool Get(T&) const { return false; } alignas(T) char value[sizeof(T)]; }; template <typename T> struct FlagValue<T, FlagValueStorageKind::kOneWordAtomic> : FlagOneWordValue { - bool Get(T* dst) const { + bool Get(T& dst) const { int64_t one_word_val = value.load(std::memory_order_acquire); if (ABSL_PREDICT_FALSE(one_word_val == UninitializedFlagValue())) { return false; } - std::memcpy(dst, static_cast<const void*>(&one_word_val), sizeof(T)); + std::memcpy(&dst, static_cast<const void*>(&one_word_val), sizeof(T)); return true; } }; template <typename T> struct FlagValue<T, FlagValueStorageKind::kTwoWordsAtomic> : FlagTwoWordsValue { - bool Get(T* dst) const { + bool Get(T& dst) const { AlignedTwoWords two_words_val = value.load(std::memory_order_acquire); if (ABSL_PREDICT_FALSE(!two_words_val.IsInitialized())) { return false; } - std::memcpy(dst, static_cast<const void*>(&two_words_val), sizeof(T)); + std::memcpy(&dst, static_cast<const void*>(&two_words_val), sizeof(T)); return true; } }; @@ -419,7 +429,7 @@ class FlagState; -class FlagImpl final : public flags_internal::CommandLineFlag { +class FlagImpl final : public CommandLineFlag { public: constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op, FlagHelpArg help, FlagValueStorageKind value_kind, @@ -492,7 +502,7 @@ // Attempts to parse supplied `value` string. If parsing is successful, // returns new value. Otherwise returns nullptr. std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value, - std::string* err) const + std::string& err) const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); // Stores the flag value based on the pointer to the source. void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); @@ -534,7 +544,7 @@ ABSL_LOCKS_EXCLUDED(*DataGuard()); bool ParseFrom(absl::string_view value, FlagSettingMode set_mode, - ValueSource source, std::string* error) override + ValueSource source, std::string& error) override ABSL_LOCKS_EXCLUDED(*DataGuard()); // Immutable flag's state. @@ -641,7 +651,7 @@ impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>); #endif - if (!value_.Get(&u.value)) impl_.Read(&u.value); + if (!value_.Get(u.value)) impl_.Read(&u.value); return std::move(u.value); } void Set(const T& v) { @@ -720,12 +730,12 @@ template <typename T, bool do_register> class FlagRegistrar { public: - explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) { - if (do_register) flags_internal::RegisterCommandLineFlag(&flag_->impl_); + explicit FlagRegistrar(Flag<T>& flag) : flag_(flag) { + if (do_register) flags_internal::RegisterCommandLineFlag(flag_.impl_); } FlagRegistrar OnUpdate(FlagCallbackFunc cb) && { - flag_->impl_.SetCallback(cb); + flag_.impl_.SetCallback(cb); return *this; } @@ -735,7 +745,7 @@ operator FlagRegistrarEmpty() const { return {}; } // NOLINT private: - Flag<T>* flag_; // Flag being registered (not owned). + Flag<T>& flag_; // Flag being registered (not owned). }; } // namespace flags_internal
diff --git a/absl/flags/internal/private_handle_accessor.cc b/absl/flags/internal/private_handle_accessor.cc index 64fe316..24b4913 100644 --- a/absl/flags/internal/private_handle_accessor.cc +++ b/absl/flags/internal/private_handle_accessor.cc
@@ -24,8 +24,8 @@ } std::unique_ptr<FlagStateInterface> PrivateHandleAccessor::SaveState( - CommandLineFlag* flag) { - return flag->SaveState(); + CommandLineFlag& flag) { + return flag.SaveState(); } bool PrivateHandleAccessor::IsSpecifiedOnCommandLine( @@ -43,12 +43,12 @@ flag.CheckDefaultValueParsingRoundtrip(); } -bool PrivateHandleAccessor::ParseFrom(CommandLineFlag* flag, +bool PrivateHandleAccessor::ParseFrom(CommandLineFlag& flag, absl::string_view value, flags_internal::FlagSettingMode set_mode, flags_internal::ValueSource source, - std::string* error) { - return flag->ParseFrom(value, set_mode, source, error); + std::string& error) { + return flag.ParseFrom(value, set_mode, source, error); } } // namespace flags_internal
diff --git a/absl/flags/internal/private_handle_accessor.h b/absl/flags/internal/private_handle_accessor.h index 40591de..9a327a0 100644 --- a/absl/flags/internal/private_handle_accessor.h +++ b/absl/flags/internal/private_handle_accessor.h
@@ -16,7 +16,7 @@ #ifndef ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_ #define ABSL_FLAGS_INTERNAL_PRIVATE_HANDLE_ACCESSOR_H_ -#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/commandlineflag.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -31,7 +31,7 @@ static FlagFastTypeId TypeId(const CommandLineFlag& flag); // Access to CommandLineFlag::SaveState. - static std::unique_ptr<FlagStateInterface> SaveState(CommandLineFlag* flag); + static std::unique_ptr<FlagStateInterface> SaveState(CommandLineFlag& flag); // Access to CommandLineFlag::IsSpecifiedOnCommandLine. static bool IsSpecifiedOnCommandLine(const CommandLineFlag& flag); @@ -43,9 +43,9 @@ // Access to CommandLineFlag::CheckDefaultValueParsingRoundtrip. static void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag); - static bool ParseFrom(CommandLineFlag* flag, absl::string_view value, + static bool ParseFrom(CommandLineFlag& flag, absl::string_view value, flags_internal::FlagSettingMode set_mode, - flags_internal::ValueSource source, std::string* error); + flags_internal::ValueSource source, std::string& error); }; } // namespace flags_internal
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc index 3b941f0..4bcebfa 100644 --- a/absl/flags/internal/registry.cc +++ b/absl/flags/internal/registry.cc
@@ -28,7 +28,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/thread_annotations.h" -#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/usage_config.h" #include "absl/strings/str_cat.h" @@ -60,8 +60,8 @@ FlagRegistry() = default; ~FlagRegistry() = default; - // Store a flag in this registry. Takes ownership of *flag. - void RegisterFlag(CommandLineFlag* flag); + // Store a flag in this registry. Takes ownership of *flag. + void RegisterFlag(CommandLineFlag& flag); void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); } void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); } @@ -74,12 +74,12 @@ // found or not retired. Does not emit a warning. CommandLineFlag* FindRetiredFlagLocked(absl::string_view name); - static FlagRegistry* GlobalRegistry(); // returns a singleton registry + static FlagRegistry& GlobalRegistry(); // returns a singleton registry private: friend class FlagSaverImpl; // reads all the flags in order to copy them friend void ForEachFlagUnlocked( - std::function<void(CommandLineFlag*)> visitor); + std::function<void(CommandLineFlag&)> visitor); // The map from name to flag, for FindFlagLocked(). using FlagMap = std::map<absl::string_view, CommandLineFlag*>; @@ -94,64 +94,62 @@ FlagRegistry& operator=(const FlagRegistry&); }; -FlagRegistry* FlagRegistry::GlobalRegistry() { +FlagRegistry& FlagRegistry::GlobalRegistry() { static FlagRegistry* global_registry = new FlagRegistry; - return global_registry; + return *global_registry; } namespace { class FlagRegistryLock { public: - explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); } - ~FlagRegistryLock() { fr_->Unlock(); } + explicit FlagRegistryLock(FlagRegistry& fr) : fr_(fr) { fr_.Lock(); } + ~FlagRegistryLock() { fr_.Unlock(); } private: - FlagRegistry* const fr_; + FlagRegistry& fr_; }; -void DestroyRetiredFlag(CommandLineFlag* flag); +void DestroyRetiredFlag(CommandLineFlag& flag); + } // namespace -void FlagRegistry::RegisterFlag(CommandLineFlag* flag) { - FlagRegistryLock registry_lock(this); +void FlagRegistry::RegisterFlag(CommandLineFlag& flag) { + FlagRegistryLock registry_lock(*this); std::pair<FlagIterator, bool> ins = - flags_.insert(FlagMap::value_type(flag->Name(), flag)); + flags_.insert(FlagMap::value_type(flag.Name(), &flag)); if (ins.second == false) { // means the name was already in the map - CommandLineFlag* old_flag = ins.first->second; - if (flag->IsRetired() != old_flag->IsRetired()) { + CommandLineFlag& old_flag = *ins.first->second; + if (flag.IsRetired() != old_flag.IsRetired()) { // All registrations must agree on the 'retired' flag. flags_internal::ReportUsageError( absl::StrCat( - "Retired flag '", flag->Name(), - "' was defined normally in file '", - (flag->IsRetired() ? old_flag->Filename() : flag->Filename()), - "'."), + "Retired flag '", flag.Name(), "' was defined normally in file '", + (flag.IsRetired() ? old_flag.Filename() : flag.Filename()), "'."), true); - } else if (flags_internal::PrivateHandleAccessor::TypeId(*flag) != - flags_internal::PrivateHandleAccessor::TypeId(*old_flag)) { + } else if (flags_internal::PrivateHandleAccessor::TypeId(flag) != + flags_internal::PrivateHandleAccessor::TypeId(old_flag)) { flags_internal::ReportUsageError( - absl::StrCat("Flag '", flag->Name(), + absl::StrCat("Flag '", flag.Name(), "' was defined more than once but with " "differing types. Defined in files '", - old_flag->Filename(), "' and '", flag->Filename(), "'."), + old_flag.Filename(), "' and '", flag.Filename(), "'."), true); - } else if (old_flag->IsRetired()) { + } else if (old_flag.IsRetired()) { // Retired flag can just be deleted. DestroyRetiredFlag(flag); return; - } else if (old_flag->Filename() != flag->Filename()) { + } else if (old_flag.Filename() != flag.Filename()) { flags_internal::ReportUsageError( - absl::StrCat("Flag '", flag->Name(), + absl::StrCat("Flag '", flag.Name(), "' was defined more than once (in files '", - old_flag->Filename(), "' and '", flag->Filename(), - "')."), + old_flag.Filename(), "' and '", flag.Filename(), "')."), true); } else { flags_internal::ReportUsageError( absl::StrCat( - "Something wrong with flag '", flag->Name(), "' in file '", - flag->Filename(), "'. One possibility: file '", flag->Filename(), + "Something wrong with flag '", flag.Name(), "' in file '", + flag.Filename(), "'. One possibility: file '", flag.Filename(), "' is being linked both statically and dynamically into this " "executable. e.g. some files listed as srcs to a test and also " "listed as srcs of some shared lib deps of the same test."), @@ -205,7 +203,7 @@ // It's an error to call this more than once. void SaveFromRegistry() { assert(backup_registry_.empty()); // call only once! - flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) { + flags_internal::ForEachFlag([&](CommandLineFlag& flag) { if (auto flag_state = flags_internal::PrivateHandleAccessor::SaveState(flag)) { backup_registry_.emplace_back(std::move(flag_state)); @@ -243,39 +241,39 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) { if (name.empty()) return nullptr; - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); + FlagRegistry& registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); - return registry->FindFlagLocked(name); + return registry.FindFlagLocked(name); } CommandLineFlag* FindRetiredFlag(absl::string_view name) { - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); + FlagRegistry& registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); - return registry->FindRetiredFlagLocked(name); + return registry.FindRetiredFlagLocked(name); } // -------------------------------------------------------------------- -void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor) { - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); - for (FlagRegistry::FlagConstIterator i = registry->flags_.begin(); - i != registry->flags_.end(); ++i) { - visitor(i->second); +void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor) { + FlagRegistry& registry = FlagRegistry::GlobalRegistry(); + for (FlagRegistry::FlagConstIterator i = registry.flags_.begin(); + i != registry.flags_.end(); ++i) { + visitor(*i->second); } } -void ForEachFlag(std::function<void(CommandLineFlag*)> visitor) { - FlagRegistry* const registry = FlagRegistry::GlobalRegistry(); +void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) { + FlagRegistry& registry = FlagRegistry::GlobalRegistry(); FlagRegistryLock frl(registry); ForEachFlagUnlocked(visitor); } // -------------------------------------------------------------------- -bool RegisterCommandLineFlag(CommandLineFlag* flag) { - FlagRegistry::GlobalRegistry()->RegisterFlag(flag); +bool RegisterCommandLineFlag(CommandLineFlag& flag) { + FlagRegistry::GlobalRegistry().RegisterFlag(flag); return true; } @@ -283,7 +281,7 @@ namespace { -class RetiredFlagObj final : public flags_internal::CommandLineFlag { +class RetiredFlagObj final : public CommandLineFlag { public: constexpr RetiredFlagObj(const char* name, FlagFastTypeId type_id) : name_(name), type_id_(type_id) {} @@ -306,7 +304,7 @@ } bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode, - flags_internal::ValueSource, std::string*) override { + flags_internal::ValueSource, std::string&) override { return false; } @@ -319,16 +317,16 @@ const FlagFastTypeId type_id_; }; -void DestroyRetiredFlag(flags_internal::CommandLineFlag* flag) { - assert(flag->IsRetired()); - delete static_cast<RetiredFlagObj*>(flag); +void DestroyRetiredFlag(CommandLineFlag& flag) { + assert(flag.IsRetired()); + delete static_cast<RetiredFlagObj*>(&flag); } } // namespace bool Retire(const char* name, FlagFastTypeId type_id) { auto* flag = new flags_internal::RetiredFlagObj(name, type_id); - FlagRegistry::GlobalRegistry()->RegisterFlag(flag); + FlagRegistry::GlobalRegistry().RegisterFlag(*flag); return true; }
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h index af8ed6b..a118865 100644 --- a/absl/flags/internal/registry.h +++ b/absl/flags/internal/registry.h
@@ -30,6 +30,8 @@ namespace absl { ABSL_NAMESPACE_BEGIN +class CommandLineFlag; + namespace flags_internal { CommandLineFlag* FindCommandLineFlag(absl::string_view name); @@ -37,14 +39,14 @@ // Executes specified visitor for each non-retired flag in the registry. // Requires the caller hold the registry lock. -void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor); +void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor); // Executes specified visitor for each non-retired flag in the registry. While // callback are executed, the registry is locked and can't be changed. -void ForEachFlag(std::function<void(CommandLineFlag*)> visitor); +void ForEachFlag(std::function<void(CommandLineFlag&)> visitor); //----------------------------------------------------------------------------- -bool RegisterCommandLineFlag(CommandLineFlag*); +bool RegisterCommandLineFlag(CommandLineFlag&); //----------------------------------------------------------------------------- // Retired registrations:
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc index c13fb9b..b2523b2 100644 --- a/absl/flags/internal/type_erased.cc +++ b/absl/flags/internal/type_erased.cc
@@ -21,7 +21,7 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" -#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/internal/private_handle_accessor.h" #include "absl/flags/internal/registry.h" #include "absl/flags/usage_config.h" @@ -58,7 +58,7 @@ std::string error; if (!flags_internal::PrivateHandleAccessor::ParseFrom( - flag, value, set_mode, kProgrammaticChange, &error)) { + *flag, value, set_mode, kProgrammaticChange, error)) { // Errors here are all of the form: the provided name was a recognized // flag, but the value was invalid (bad type, or validation failed). flags_internal::ReportUsageError(error, false);
diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h index b43a0ff..fd9663e 100644 --- a/absl/flags/internal/type_erased.h +++ b/absl/flags/internal/type_erased.h
@@ -19,7 +19,7 @@ #include <string> #include "absl/base/config.h" -#include "absl/flags/internal/commandlineflag.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/internal/registry.h" #include "absl/strings/string_view.h"
diff --git a/absl/flags/internal/type_erased_test.cc b/absl/flags/internal/type_erased_test.cc index 4ce5981..bb0ff23 100644 --- a/absl/flags/internal/type_erased_test.cc +++ b/absl/flags/internal/type_erased_test.cc
@@ -20,7 +20,6 @@ #include "gtest/gtest.h" #include "absl/flags/flag.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/registry.h" #include "absl/flags/marshalling.h" #include "absl/memory/memory.h"
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc index 10accc4..2a2231a 100644 --- a/absl/flags/internal/usage.cc +++ b/absl/flags/internal/usage.cc
@@ -23,8 +23,8 @@ #include <vector> #include "absl/base/config.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/flag.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/path_util.h" #include "absl/flags/internal/private_handle_accessor.h" @@ -107,8 +107,8 @@ public: // Pretty printer holds on to the std::ostream& reference to direct an output // to that stream. - FlagHelpPrettyPrinter(int max_line_len, std::ostream* out) - : out_(*out), + FlagHelpPrettyPrinter(int max_line_len, std::ostream& out) + : out_(out), max_line_len_(max_line_len), line_len_(0), first_line_(true) {} @@ -182,8 +182,7 @@ bool first_line_; }; -void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag, - std::ostream* out) { +void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) { FlagHelpPrettyPrinter printer(80, out); // Max line length is 80. // Flag name. @@ -245,30 +244,28 @@ // This map is used to output matching flags grouped by package and file // name. std::map<std::string, - std::map<std::string, - std::vector<const flags_internal::CommandLineFlag*>>> + std::map<std::string, std::vector<const absl::CommandLineFlag*>>> matching_flags; - flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) { - std::string flag_filename = flag->Filename(); + flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) { + std::string flag_filename = flag.Filename(); // Ignore retired flags. - if (flag->IsRetired()) return; + if (flag.IsRetired()) return; // If the flag has been stripped, pretend that it doesn't exist. - if (flag->Help() == flags_internal::kStrippedFlagHelp) return; + if (flag.Help() == flags_internal::kStrippedFlagHelp) return; // Make sure flag satisfies the filter if (!filter_cb || !filter_cb(flag_filename)) return; matching_flags[std::string(flags_internal::Package(flag_filename))] [flag_filename] - .push_back(flag); + .push_back(&flag); }); - absl::string_view - package_separator; // controls blank lines between packages. - absl::string_view file_separator; // controls blank lines between files. + absl::string_view package_separator; // controls blank lines between packages + absl::string_view file_separator; // controls blank lines between files for (const auto& package : matching_flags) { if (format == HelpFormat::kHumanReadable) { out << package_separator; @@ -303,10 +300,10 @@ // -------------------------------------------------------------------- // Produces the help message describing specific flag. -void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag, +void FlagHelp(std::ostream& out, const CommandLineFlag& flag, HelpFormat format) { if (format == HelpFormat::kHumanReadable) - flags_internal::FlagHelpHumanReadable(flag, &out); + flags_internal::FlagHelpHumanReadable(flag, out); } // --------------------------------------------------------------------
diff --git a/absl/flags/internal/usage.h b/absl/flags/internal/usage.h index 6b080fd..0c62dc4 100644 --- a/absl/flags/internal/usage.h +++ b/absl/flags/internal/usage.h
@@ -20,8 +20,8 @@ #include <string> #include "absl/base/config.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/declare.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/strings/string_view.h" // -------------------------------------------------------------------- @@ -37,7 +37,7 @@ }; // Outputs the help message describing specific flag. -void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag, +void FlagHelp(std::ostream& out, const CommandLineFlag& flag, HelpFormat format = HelpFormat::kHumanReadable); // Produces the help messages for all flags matching the filter. A flag matches
diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc index 09baae8..81f9ceb 100644 --- a/absl/flags/marshalling.cc +++ b/absl/flags/marshalling.cc
@@ -74,15 +74,16 @@ } template <typename IntType> -inline bool ParseFlagImpl(absl::string_view text, IntType* dst) { +inline bool ParseFlagImpl(absl::string_view text, IntType& dst) { text = absl::StripAsciiWhitespace(text); - return absl::numbers_internal::safe_strtoi_base(text, dst, NumericBase(text)); + return absl::numbers_internal::safe_strtoi_base(text, &dst, + NumericBase(text)); } bool AbslParseFlag(absl::string_view text, short* dst, std::string*) { int val; - if (!ParseFlagImpl(text, &val)) return false; + if (!ParseFlagImpl(text, val)) return false; if (static_cast<short>(val) != val) // worked, but number out of range return false; *dst = static_cast<short>(val); @@ -91,7 +92,7 @@ bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) { unsigned int val; - if (!ParseFlagImpl(text, &val)) return false; + if (!ParseFlagImpl(text, val)) return false; if (static_cast<unsigned short>(val) != val) // worked, but number out of range return false; @@ -100,28 +101,28 @@ } bool AbslParseFlag(absl::string_view text, int* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, unsigned int* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, unsigned long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, long long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } bool AbslParseFlag(absl::string_view text, unsigned long long* dst, std::string*) { - return ParseFlagImpl(text, dst); + return ParseFlagImpl(text, *dst); } // --------------------------------------------------------------------
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc index fbf4267..1530078 100644 --- a/absl/flags/parse.cc +++ b/absl/flags/parse.cc
@@ -34,9 +34,9 @@ #include "absl/base/config.h" #include "absl/base/const_init.h" #include "absl/base/thread_annotations.h" +#include "absl/flags/commandlineflag.h" #include "absl/flags/config.h" #include "absl/flags/flag.h" -#include "absl/flags/internal/commandlineflag.h" #include "absl/flags/internal/flag.h" #include "absl/flags/internal/parse.h" #include "absl/flags/internal/private_handle_accessor.h" @@ -222,7 +222,7 @@ // Reads the environment variable with name `name` and stores results in // `value`. If variable is not present in environment returns false, otherwise // returns true. -bool GetEnvVar(const char* var_name, std::string* var_value) { +bool GetEnvVar(const char* var_name, std::string& var_value) { #ifdef _WIN32 char buf[1024]; auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf)); @@ -234,14 +234,14 @@ return false; } - *var_value = std::string(buf, get_res); + var_value = std::string(buf, get_res); #else const char* val = ::getenv(var_name); if (val == nullptr) { return false; } - *var_value = val; + var_value = val; #endif return true; @@ -306,17 +306,17 @@ // back. void CheckDefaultValuesParsingRoundtrip() { #ifndef NDEBUG - flags_internal::ForEachFlag([&](CommandLineFlag* flag) { - if (flag->IsRetired()) return; + flags_internal::ForEachFlag([&](CommandLineFlag& flag) { + if (flag.IsRetired()) return; #define ABSL_FLAGS_INTERNAL_IGNORE_TYPE(T, _) \ - if (flag->IsOfType<T>()) return; + if (flag.IsOfType<T>()) return; ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(ABSL_FLAGS_INTERNAL_IGNORE_TYPE) #undef ABSL_FLAGS_INTERNAL_IGNORE_TYPE flags_internal::PrivateHandleAccessor::CheckDefaultValueParsingRoundtrip( - *flag); + flag); }); #endif } @@ -329,13 +329,13 @@ // the first flagfile in the input list are processed before the second flagfile // etc. bool ReadFlagfiles(const std::vector<std::string>& flagfiles, - std::vector<ArgsList>* input_args) { + std::vector<ArgsList>& input_args) { bool success = true; for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) { ArgsList al; if (al.ReadFromFlagfile(*it)) { - input_args->push_back(al); + input_args.push_back(al); } else { success = false; } @@ -350,7 +350,7 @@ // `flag_name` is a string from the input flag_names list. If successful we // append a single ArgList at the end of the input_args. bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names, - std::vector<ArgsList>* input_args, + std::vector<ArgsList>& input_args, bool fail_on_absent_in_env) { bool success = true; std::vector<std::string> args; @@ -371,7 +371,7 @@ const std::string envname = absl::StrCat("FLAGS_", flag_name); std::string envval; - if (!GetEnvVar(envname.c_str(), &envval)) { + if (!GetEnvVar(envname.c_str(), envval)) { if (fail_on_absent_in_env) { flags_internal::ReportUsageError( absl::StrCat(envname, " not found in environment"), true); @@ -386,7 +386,7 @@ } if (success) { - input_args->emplace_back(args); + input_args.emplace_back(args); } return success; @@ -396,8 +396,8 @@ // Returns success status, which is true if were able to handle all generator // flags (flagfile, fromenv, tryfromemv) successfully. -bool HandleGeneratorFlags(std::vector<ArgsList>* input_args, - std::vector<std::string>* flagfile_value) { +bool HandleGeneratorFlags(std::vector<ArgsList>& input_args, + std::vector<std::string>& flagfile_value) { bool success = true; absl::MutexLock l(&flags_internal::processing_checks_guard); @@ -422,9 +422,9 @@ if (flags_internal::flagfile_needs_processing) { auto flagfiles = absl::GetFlag(FLAGS_flagfile); - if (input_args->size() == 1) { - flagfile_value->insert(flagfile_value->end(), flagfiles.begin(), - flagfiles.end()); + if (input_args.size() == 1) { + flagfile_value.insert(flagfile_value.end(), flagfiles.begin(), + flagfiles.end()); } success &= ReadFlagfiles(flagfiles, input_args); @@ -647,7 +647,7 @@ bool success = true; while (!input_args.empty()) { // 10. First we process the built-in generator flags. - success &= HandleGeneratorFlags(&input_args, &flagfile_value); + success &= HandleGeneratorFlags(input_args, flagfile_value); // 30. Select top-most (most recent) arguments list. If it is empty drop it // and re-try. @@ -733,7 +733,7 @@ std::string error; if (!flags_internal::PrivateHandleAccessor::ParseFrom( - flag, value, SET_FLAGS_VALUE, kCommandLine, &error)) { + *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) { flags_internal::ReportUsageError(error, true); success = false; } else {
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc index e6a53ae..aea068e 100644 --- a/absl/flags/parse_test.cc +++ b/absl/flags/parse_test.cc
@@ -171,8 +171,8 @@ // temporary directory location. This way we can test inclusion of one flagfile // from another flagfile. const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd, - std::string* flagfile_flag) { - *flagfile_flag = "--flagfile="; + std::string& flagfile_flag) { + flagfile_flag = "--flagfile="; absl::string_view separator; for (const auto& flagfile_data : ffd) { std::string flagfile_name = @@ -183,11 +183,11 @@ flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n"; } - absl::StrAppend(flagfile_flag, separator, flagfile_name); + absl::StrAppend(&flagfile_flag, separator, flagfile_name); separator = ","; } - return flagfile_flag->c_str(); + return flagfile_flag.c_str(); } } // namespace @@ -588,14 +588,14 @@ const char* in_args1[] = { "testbin", GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args1, -1, 0.1, "q2w2 ", true); const char* in_args2[] = { "testbin", GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args2, 100, 0.1, "q2w2 ", false); } @@ -609,7 +609,7 @@ "testbin", GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}, {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args1, -1, 0.1, "q2w2 ", true); } @@ -622,7 +622,7 @@ const char* in_args1[] = { "testbin", "--int_flag=3", GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}}, - &flagfile_flag), + flagfile_flag), "-double_flag=0.2"}; TestParse(in_args1, -1, 0.2, "q2w2 ", true); } @@ -640,7 +640,7 @@ const char* in_args1[] = { "testbin", GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}}, - &flagfile_flag), + flagfile_flag), }; TestParse(in_args1, 100, 0.1, "q2w2 ", false); } @@ -657,7 +657,7 @@ const char* in_args1[] = { "testbin", GetFlagfileFlag({{"parse_test.ff4", - absl::MakeConstSpan(ff4_data)}}, &flagfile_flag), + absl::MakeConstSpan(ff4_data)}}, flagfile_flag), }; EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args1), "Unknown command line flag 'unknown_flag'"); @@ -669,7 +669,7 @@ const char* in_args2[] = { "testbin", GetFlagfileFlag({{"parse_test.ff5", - absl::MakeConstSpan(ff5_data)}}, &flagfile_flag), + absl::MakeConstSpan(ff5_data)}}, flagfile_flag), }; EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args2), "Unknown command line flag 'int_flag 10'"); @@ -681,7 +681,7 @@ const char* in_args3[] = { "testbin", GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}}, - &flagfile_flag), + flagfile_flag), }; EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3), "Flagfile can't contain position arguments or --"); @@ -702,7 +702,7 @@ const char* in_args5[] = { "testbin", GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}}, - &flagfile_flag), + flagfile_flag), }; EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args5), "Unexpected line in the flagfile .*: \\*bin\\*");
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel index 9ba75b5..4b804c8 100644 --- a/absl/random/BUILD.bazel +++ b/absl/random/BUILD.bazel
@@ -69,7 +69,7 @@ "//absl/base:config", "//absl/base:core_headers", "//absl/meta:type_traits", - "//absl/random/internal:distributions", + "//absl/random/internal:distribution_caller", "//absl/random/internal:fast_uniform_bits", "//absl/random/internal:fastmath", "//absl/random/internal:generate_real", @@ -78,7 +78,6 @@ "//absl/random/internal:uniform_helper", "//absl/random/internal:wide_multiply", "//absl/strings", - "//absl/types:span", ], )
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt index ec616dd..85a2ea3 100644 --- a/absl/random/CMakeLists.txt +++ b/absl/random/CMakeLists.txt
@@ -183,7 +183,7 @@ absl::config absl::core_headers absl::random_internal_generate_real - absl::random_internal_distributions + absl::random_internal_distribution_caller absl::random_internal_fast_uniform_bits absl::random_internal_fastmath absl::random_internal_iostream_state_saver @@ -191,7 +191,6 @@ absl::random_internal_uniform_helper absl::random_internal_wide_multiply absl::strings - absl::span absl::type_traits ) @@ -539,27 +538,6 @@ # Internal-only target, do not depend on directly. absl_cc_library( NAME - random_internal_distributions - HDRS - "internal/distributions.h" - COPTS - ${ABSL_DEFAULT_COPTS} - LINKOPTS - ${ABSL_DEFAULT_LINKOPTS} - DEPS - absl::random_internal_distribution_caller - absl::random_internal_fast_uniform_bits - absl::random_internal_fastmath - absl::random_internal_traits - absl::random_internal_uniform_helper - absl::span - absl::strings - absl::type_traits -) - -# Internal-only target, do not depend on directly. -absl_cc_library( - NAME random_internal_fast_uniform_bits HDRS "internal/fast_uniform_bits.h" @@ -745,7 +723,6 @@ absl::random_internal_salted_seed_seq absl::random_internal_seed_material absl::span - absl::strings absl::type_traits ) @@ -1174,9 +1151,7 @@ LINKOPTS ${ABSL_DEFAULT_LINKOPTS} DEPS - absl::core_headers - absl::random_internal_fast_uniform_bits - absl::random_internal_iostream_state_saver + absl::config absl::random_internal_traits absl::type_traits )
diff --git a/absl/random/distributions.h b/absl/random/distributions.h index 8680f6a..6775c5d 100644 --- a/absl/random/distributions.h +++ b/absl/random/distributions.h
@@ -57,7 +57,7 @@ #include "absl/random/beta_distribution.h" #include "absl/random/exponential_distribution.h" #include "absl/random/gaussian_distribution.h" -#include "absl/random/internal/distributions.h" // IWYU pragma: export +#include "absl/random/internal/distribution_caller.h" // IWYU pragma: export #include "absl/random/internal/uniform_helper.h" // IWYU pragma: export #include "absl/random/log_uniform_int_distribution.h" #include "absl/random/poisson_distribution.h"
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index 85d1fb8..813d926 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel
@@ -49,21 +49,6 @@ ) cc_library( - name = "distributions", - hdrs = ["distributions.h"], - copts = ABSL_DEFAULT_COPTS, - linkopts = ABSL_DEFAULT_LINKOPTS, - deps = [ - ":distribution_caller", - ":traits", - ":uniform_helper", - "//absl/base", - "//absl/meta:type_traits", - "//absl/strings", - ], -) - -cc_library( name = "fast_uniform_bits", hdrs = [ "fast_uniform_bits.h", @@ -221,7 +206,6 @@ ":seed_material", "//absl/base:core_headers", "//absl/meta:type_traits", - "//absl/strings", "//absl/types:optional", "//absl/types:span", ], @@ -672,6 +656,8 @@ copts = ABSL_DEFAULT_COPTS, linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ + ":traits", + "//absl/base:config", "//absl/meta:type_traits", ], )
diff --git a/absl/random/internal/distributions.h b/absl/random/internal/distributions.h deleted file mode 100644 index d7e3c01..0000000 --- a/absl/random/internal/distributions.h +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2019 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. - -#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_ -#define ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_ - -#include <type_traits> - -#include "absl/meta/type_traits.h" -#include "absl/random/internal/distribution_caller.h" -#include "absl/random/internal/traits.h" -#include "absl/random/internal/uniform_helper.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace random_internal { - -// In the absence of an explicitly provided return-type, the template -// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on -// the data-types of the endpoint-arguments {A lo, B hi}. -// -// Given endpoints {A lo, B hi}, one of {A, B} will be chosen as the -// return-type, if one type can be implicitly converted into the other, in a -// lossless way. The template "is_widening_convertible" implements the -// compile-time logic for deciding if such a conversion is possible. -// -// If no such conversion between {A, B} exists, then the overload for -// absl::Uniform() will be discarded, and the call will be ill-formed. -// Return-type for absl::Uniform() when the return-type is inferred. -template <typename A, typename B> -using uniform_inferred_return_t = - absl::enable_if_t<absl::disjunction<is_widening_convertible<A, B>, - is_widening_convertible<B, A>>::value, - typename std::conditional< - is_widening_convertible<A, B>::value, B, A>::type>; - -} // namespace random_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
diff --git a/absl/random/internal/uniform_helper.h b/absl/random/internal/uniform_helper.h index 663107c..5b2afec 100644 --- a/absl/random/internal/uniform_helper.h +++ b/absl/random/internal/uniform_helper.h
@@ -19,10 +19,13 @@ #include <limits> #include <type_traits> +#include "absl/base/config.h" #include "absl/meta/type_traits.h" +#include "absl/random/internal/traits.h" namespace absl { ABSL_NAMESPACE_BEGIN + template <typename IntType> class uniform_int_distribution; @@ -58,6 +61,26 @@ : public random_internal::TagTypeCompare<IntervalOpenOpenTag> {}; namespace random_internal { + +// In the absence of an explicitly provided return-type, the template +// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on +// the data-types of the endpoint-arguments {A lo, B hi}. +// +// Given endpoints {A lo, B hi}, one of {A, B} will be chosen as the +// return-type, if one type can be implicitly converted into the other, in a +// lossless way. The template "is_widening_convertible" implements the +// compile-time logic for deciding if such a conversion is possible. +// +// If no such conversion between {A, B} exists, then the overload for +// absl::Uniform() will be discarded, and the call will be ill-formed. +// Return-type for absl::Uniform() when the return-type is inferred. +template <typename A, typename B> +using uniform_inferred_return_t = + absl::enable_if_t<absl::disjunction<is_widening_convertible<A, B>, + is_widening_convertible<B, A>>::value, + typename std::conditional< + is_widening_convertible<A, B>::value, B, A>::type>; + // The functions // uniform_lower_bound(tag, a, b) // and @@ -149,12 +172,19 @@ return std::nextafter(b, (std::numeric_limits<FloatType>::max)()); } +// UniformDistribution selects either absl::uniform_int_distribution +// or absl::uniform_real_distribution depending on the NumType parameter. template <typename NumType> using UniformDistribution = typename std::conditional<std::is_integral<NumType>::value, absl::uniform_int_distribution<NumType>, absl::uniform_real_distribution<NumType>>::type; +// UniformDistributionWrapper is used as the underlying distribution type +// by the absl::Uniform template function. It selects the proper Abseil +// uniform distribution and provides constructor overloads that match the +// expected parameter order as well as adjusting distribtuion bounds based +// on the tag. template <typename NumType> struct UniformDistributionWrapper : public UniformDistribution<NumType> { template <typename TagType>
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index 1ddd6ae..68f5398 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc
@@ -705,6 +705,37 @@ } } +template <typename T, Cord::EnableIfString<T>> +Cord::Cord(T&& src) { + if ( + // String is short: copy data to avoid external block overhead. + src.size() <= kMaxBytesToCopy || + // String is wasteful: copy data to avoid pinning too much unused memory. + src.size() < src.capacity() / 2 + ) { + if (src.size() <= InlineRep::kMaxInline) { + contents_.set_data(src.data(), src.size(), false); + } else { + contents_.set_tree(NewTree(src.data(), src.size(), 0)); + } + } else { + struct StringReleaser { + void operator()(absl::string_view /* data */) {} + std::string data; + }; + const absl::string_view original_data = src; + CordRepExternal* rep = + static_cast<CordRepExternal*>(absl::cord_internal::NewExternalRep( + original_data, StringReleaser{std::move(src)})); + // Moving src may have invalidated its data pointer, so adjust it. + rep->base = + static_cast<StringReleaser*>(GetExternalReleaser(rep))->data.data(); + contents_.set_tree(rep); + } +} + +template Cord::Cord(std::string&& src); + // The destruction code is separate so that the compiler can determine // that it does not need to call the destructor on a moved-from Cord. void Cord::DestroyCordSlow() { @@ -742,6 +773,18 @@ return *this; } +template <typename T, Cord::EnableIfString<T>> +Cord& Cord::operator=(T&& src) { + if (src.size() <= kMaxBytesToCopy) { + *this = absl::string_view(src); + } else { + *this = Cord(std::move(src)); + } + return *this; +} + +template Cord& Cord::operator=(std::string&& src); + // TODO(sanjay): Move to Cord::InlineRep section of file. For now, // we keep it here to make diffs easier. void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) { @@ -853,6 +896,17 @@ void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); } +template <typename T, Cord::EnableIfString<T>> +void Cord::Append(T&& src) { + if (src.size() <= kMaxBytesToCopy) { + Append(absl::string_view(src)); + } else { + Append(Cord(std::move(src))); + } +} + +template void Cord::Append(std::string&& src); + void Cord::Prepend(const Cord& src) { CordRep* src_tree = src.contents_.tree(); if (src_tree != nullptr) { @@ -882,6 +936,17 @@ } } +template <typename T, Cord::EnableIfString<T>> +inline void Cord::Prepend(T&& src) { + if (src.size() <= kMaxBytesToCopy) { + Prepend(absl::string_view(src)); + } else { + Prepend(Cord(std::move(src))); + } +} + +template void Cord::Prepend(std::string&& src); + static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { if (n >= node->length) return nullptr; if (n == 0) return Ref(node);
diff --git a/absl/strings/cord.h b/absl/strings/cord.h index 3be8d7d..dc98745 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h
@@ -147,11 +147,8 @@ // Creates a Cord from a `std::string&&` rvalue. These constructors are // templated to avoid ambiguities for types that are convertible to both // `absl::string_view` and `std::string`, such as `const char*`. - // - // Note that these functions reserve the right to use the `string&&`'s - // memory and that they will do so in the future. template <typename T, EnableIfString<T> = 0> - explicit Cord(T&& src) : Cord(absl::string_view(src)) {} + explicit Cord(T&& src); template <typename T, EnableIfString<T> = 0> Cord& operator=(T&& src); @@ -1048,11 +1045,8 @@ return *this; } -template <typename T, Cord::EnableIfString<T>> -inline Cord& Cord::operator=(T&& src) { - *this = absl::string_view(src); - return *this; -} +extern template Cord::Cord(std::string&& src); +extern template Cord& Cord::operator=(std::string&& src); inline size_t Cord::size() const { // Length is 1st field in str.rep_ @@ -1098,19 +1092,8 @@ contents_.AppendArray(src.data(), src.size()); } -template <typename T, Cord::EnableIfString<T>> -inline void Cord::Append(T&& src) { - // Note that this function reserves the right to reuse the `string&&`'s - // memory and that it will do so in the future. - Append(absl::string_view(src)); -} - -template <typename T, Cord::EnableIfString<T>> -inline void Cord::Prepend(T&& src) { - // Note that this function reserves the right to reuse the `string&&`'s - // memory and that it will do so in the future. - Prepend(absl::string_view(src)); -} +extern template void Cord::Append(std::string&& src); +extern template void Cord::Prepend(std::string&& src); inline int Cord::Compare(const Cord& rhs) const { if (!contents_.is_tree() && !rhs.contents_.is_tree()) {
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc index 49a6884..22cfef6 100644 --- a/absl/strings/str_format_test.cc +++ b/absl/strings/str_format_test.cc
@@ -8,6 +8,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/strings/cord.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" @@ -353,6 +354,7 @@ EXPECT_EQ(StrFormat("%s", "C"), "C"); EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++"); EXPECT_EQ(StrFormat("%s", string_view("view")), "view"); + EXPECT_EQ(StrFormat("%s", absl::Cord("cord")), "cord"); // Integral Conversion // These format integral types: char, int, long, uint64_t, etc. EXPECT_EQ(StrFormat("%d", char{10}), "10");
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h index d4ea90e..b33e0c0 100644 --- a/absl/time/internal/cctz/include/cctz/time_zone.h +++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -292,6 +292,7 @@ // - %E#f - Fractional seconds with # digits of precision // - %E*f - Fractional seconds with full precision (a literal '*') // - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) +// - %ET - The RFC3339 "date-time" separator "T" // // Note that %E0S behaves like %S, and %E0f produces no characters. In // contrast %E*f always produces at least one digit, which may be '0'. @@ -321,7 +322,7 @@ // returns the corresponding time_point. Uses strftime()-like formatting // options, with the same extensions as cctz::format(), but with the // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez -// and %E*z also accept the same inputs. +// and %E*z also accept the same inputs. %ET accepts either 'T' or 't'. // // %Y consumes as many numeric characters as it can, so the matching data // should always be terminated with a non-numeric. %E4Y always consumes
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc index a402760..4e39188 100644 --- a/absl/time/internal/cctz/src/cctz_benchmark.cc +++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -97,8 +97,8 @@ } BENCHMARK(BM_PrevWeekday); -const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; -const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; +const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez"; +const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z"; const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; @@ -991,12 +991,12 @@ BENCHMARK(BM_Time_FromCivilDay0_Libc); const char* const kFormats[] = { - RFC1123_full, // 0 - RFC1123_no_wday, // 1 - RFC3339_full, // 2 - RFC3339_sec, // 3 - "%Y-%m-%dT%H:%M:%S", // 4 - "%Y-%m-%d", // 5 + RFC1123_full, // 0 + RFC1123_no_wday, // 1 + RFC3339_full, // 2 + RFC3339_sec, // 3 + "%Y-%m-%d%ET%H:%M:%S", // 4 + "%Y-%m-%d", // 5 }; const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc index 179975e..a442863 100644 --- a/absl/time/internal/cctz/src/time_zone_format.cc +++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -290,6 +290,7 @@ // - %E#S - Seconds with # digits of fractional precision // - %E*S - Seconds with full fractional precision (a literal '*') // - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) +// - %ET - The RFC3339 "date-time" separator "T" // // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are // handled internally for performance reasons. strftime(3) is slow due to @@ -448,7 +449,14 @@ if (*cur != 'E' || ++cur == end) continue; // Format our extensions. - if (*cur == 'z') { + if (*cur == 'T') { + // Formats %ET. + if (cur - 2 != pending) { + FormatTM(&result, std::string(pending, cur - 2), tm); + } + result.append("T"); + pending = ++cur; + } else if (*cur == 'z') { // Formats %Ez. if (cur - 2 != pending) { FormatTM(&result, std::string(pending, cur - 2), tm); @@ -551,7 +559,7 @@ } else { dp = nullptr; } - } else if (first == 'Z') { // Zulu + } else if (first == 'Z' || first == 'z') { // Zulu *offset = 0; } else { dp = nullptr; @@ -607,7 +615,7 @@ // Uses strptime(3) to parse the given input. Supports the same extended // format specifiers as format(), although %E#S and %E*S are treated // identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept -// the same inputs. +// the same inputs. %ET accepts either 'T' or 't'. // // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are // handled internally so that we can normally avoid strptime() altogether @@ -742,6 +750,15 @@ data = (*data == '%' ? data + 1 : nullptr); continue; case 'E': + if (fmt[0] == 'T') { + if (*data == 'T' || *data == 't') { + ++data; + ++fmt; + } else { + data = nullptr; + } + continue; + } if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) { data = ParseOffset(data, ":", &offset); if (data != nullptr) saw_offset = true;
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc index 87382e1..13a4227 100644 --- a/absl/time/internal/cctz/src/time_zone_format_test.cc +++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -48,8 +48,8 @@ EXPECT_STREQ(zone, al.abbr); \ } while (0) -const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; -const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; +const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez"; +const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z"; const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; @@ -1379,10 +1379,20 @@ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp)); ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC"); - // Check that %Ez also accepts "Z" as a synonym for "+00:00". + // Check that %ET also accepts "t". time_point<chrono::nanoseconds> tp2; - EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp2)); + EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2)); EXPECT_EQ(tp, tp2); + + // Check that %Ez also accepts "Z" as a synonym for "+00:00". + time_point<chrono::nanoseconds> tp3; + EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3)); + EXPECT_EQ(tp, tp3); + + // Check that %Ez also accepts "z" as a synonym for "+00:00". + time_point<chrono::nanoseconds> tp4; + EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4)); + EXPECT_EQ(tp, tp4); } TEST(Parse, MaxRange) {
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc index 0b0c1a3..8f7ab15 100644 --- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc +++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -933,7 +933,7 @@ // NOTE: Run this with -ftrapv to detect overflow problems. TEST(MakeTime, SysSecondsLimits) { - const char RFC3339[] = "%Y-%m-%dT%H:%M:%S%Ez"; + const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; const time_zone utc = utc_time_zone(); const time_zone east = fixed_time_zone(chrono::hours(14)); const time_zone west = fixed_time_zone(-chrono::hours(14));