diff options
Diffstat (limited to 'absl/flags/internal')
-rw-r--r-- | absl/flags/internal/commandlineflag.cc | 15 | ||||
-rw-r--r-- | absl/flags/internal/commandlineflag.h | 46 | ||||
-rw-r--r-- | absl/flags/internal/commandlineflag_test.cc | 3 | ||||
-rw-r--r-- | absl/flags/internal/flag.cc | 61 | ||||
-rw-r--r-- | absl/flags/internal/flag.h | 99 | ||||
-rw-r--r-- | absl/flags/internal/registry.cc | 12 | ||||
-rw-r--r-- | absl/flags/internal/type_erased.cc | 4 | ||||
-rw-r--r-- | absl/flags/internal/type_erased.h | 2 | ||||
-rw-r--r-- | absl/flags/internal/usage.cc | 32 |
9 files changed, 173 insertions, 101 deletions
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc index 90765a3eb6f3..de588c13166b 100644 --- a/absl/flags/internal/commandlineflag.cc +++ b/absl/flags/internal/commandlineflag.cc @@ -22,7 +22,20 @@ namespace flags_internal { FlagStateInterface::~FlagStateInterface() {} bool CommandLineFlag::IsRetired() const { return false; } -bool CommandLineFlag::IsAbseilFlag() const { return true; } + +FlagFastTypeId PrivateHandleInterface::TypeId(const CommandLineFlag& flag) { + return flag.TypeId(); +} + +std::unique_ptr<FlagStateInterface> PrivateHandleInterface::SaveState( + CommandLineFlag* flag) { + return flag->SaveState(); +} + +bool PrivateHandleInterface::ValidateInputValue(const CommandLineFlag& flag, + absl::string_view value) { + return flag.ValidateInputValue(value); +} } // namespace flags_internal ABSL_NAMESPACE_END diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h index ef992f7f478d..f807fb9ab650 100644 --- a/absl/flags/internal/commandlineflag.h +++ b/absl/flags/internal/commandlineflag.h @@ -93,7 +93,7 @@ class CommandLineFlag { // Attempts to retrieve the flag value. Returns value on success, // absl::nullopt otherwise. template <typename T> - absl::optional<T> Get() const { + absl::optional<T> TryGet() const { if (IsRetired() || !IsOfType<T>()) { return absl::nullopt; } @@ -130,29 +130,14 @@ class CommandLineFlag { virtual absl::string_view Name() const = 0; // Returns name of the file where this flag is defined. virtual std::string Filename() const = 0; - // Returns name of the flag's value type for some built-in types or empty - // string. - virtual absl::string_view Typename() 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; - // Returns true iff this is a handle to an Abseil Flag. - virtual bool IsAbseilFlag() const; - // Returns id of the flag's value type. - virtual FlagFastTypeId TypeId() const = 0; - virtual bool IsModified() const = 0; virtual bool IsSpecifiedOnCommandLine() const = 0; virtual std::string DefaultValue() const = 0; virtual std::string CurrentValue() const = 0; - // Interfaces to operate on validators. - virtual bool ValidateInputValue(absl::string_view value) 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; - // 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 @@ -174,9 +159,38 @@ class CommandLineFlag { ~CommandLineFlag() = default; private: + friend class PrivateHandleInterface; + + // 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; + + // Interfaces to operate on validators. + // Validates supplied value usign validator or parseflag routine + virtual bool ValidateInputValue(absl::string_view value) const = 0; +}; + +// This class serves as a trampoline to access private methods of +// CommandLineFlag. This class is intended for use exclusively internally inside +// of the Abseil Flags implementation +class PrivateHandleInterface { + public: + // Access to CommandLineFlag::TypeId. + static FlagFastTypeId TypeId(const CommandLineFlag& flag); + + // Access to CommandLineFlag::SaveState. + static std::unique_ptr<FlagStateInterface> SaveState(CommandLineFlag* flag); + + // Access to CommandLineFlag::ValidateInputValue. + static bool ValidateInputValue(const CommandLineFlag& flag, + absl::string_view value); }; // This macro is the "source of truth" for the list of supported flag built-in diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/internal/commandlineflag_test.cc index c1142b7c5720..c31679f95e7a 100644 --- a/absl/flags/internal/commandlineflag_test.cc +++ b/absl/flags/internal/commandlineflag_test.cc @@ -67,7 +67,6 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) { ASSERT_TRUE(flag_01); EXPECT_EQ(flag_01->Name(), "int_flag"); EXPECT_EQ(flag_01->Help(), "int_flag help"); - EXPECT_EQ(flag_01->Typename(), ""); EXPECT_TRUE(!flag_01->IsRetired()); EXPECT_TRUE(flag_01->IsOfType<int>()); EXPECT_TRUE( @@ -80,7 +79,6 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) { ASSERT_TRUE(flag_02); EXPECT_EQ(flag_02->Name(), "string_flag"); EXPECT_EQ(flag_02->Help(), "string_flag help"); - EXPECT_EQ(flag_02->Typename(), ""); EXPECT_TRUE(!flag_02->IsRetired()); EXPECT_TRUE(flag_02->IsOfType<std::string>()); EXPECT_TRUE( @@ -93,7 +91,6 @@ TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) { ASSERT_TRUE(flag_03); EXPECT_EQ(flag_03->Name(), "bool_retired_flag"); EXPECT_EQ(flag_03->Help(), ""); - EXPECT_EQ(flag_03->Typename(), ""); EXPECT_TRUE(flag_03->IsRetired()); EXPECT_TRUE(flag_03->IsOfType<bool>()); EXPECT_EQ(flag_03->Filename(), "RETIRED"); diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index 089567f7ae50..8f0777fa1dc1 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc @@ -139,19 +139,43 @@ void DynValueDeleter::operator()(void* ptr) const { void FlagImpl::Init() { new (&data_guard_) absl::Mutex; - // At this point the default_value_ always points to gen_func. + auto def_kind = static_cast<FlagDefaultKind>(def_kind_); + switch (ValueStorageKind()) { case FlagValueStorageKind::kAlignedBuffer: + // For this storage kind the default_value_ always points to gen_func + // during initialization. + assert(def_kind == FlagDefaultKind::kGenFunc); (*default_value_.gen_func)(AlignedBufferValue()); break; case FlagValueStorageKind::kOneWordAtomic: { alignas(int64_t) std::array<char, sizeof(int64_t)> buf{}; - (*default_value_.gen_func)(buf.data()); - auto value = absl::bit_cast<int64_t>(buf); - OneWordValue().store(value, std::memory_order_release); + switch (def_kind) { + case FlagDefaultKind::kOneWord: + std::memcpy(buf.data(), &default_value_.one_word, + sizeof(default_value_.one_word)); + break; + case FlagDefaultKind::kFloat: + std::memcpy(buf.data(), &default_value_.float_value, + sizeof(default_value_.float_value)); + break; + case FlagDefaultKind::kDouble: + std::memcpy(buf.data(), &default_value_.double_value, + sizeof(default_value_.double_value)); + break; + default: + assert(def_kind == FlagDefaultKind::kGenFunc); + (*default_value_.gen_func)(buf.data()); + break; + } + OneWordValue().store(absl::bit_cast<int64_t>(buf), + std::memory_order_release); break; } case FlagValueStorageKind::kTwoWordsAtomic: { + // For this storage kind the default_value_ always points to gen_func + // during initialization. + assert(def_kind == FlagDefaultKind::kGenFunc); alignas(AlignedTwoWords) std::array<char, sizeof(AlignedTwoWords)> buf{}; (*default_value_.gen_func)(buf.data()); auto atomic_value = absl::bit_cast<AlignedTwoWords>(buf); @@ -196,11 +220,23 @@ void FlagImpl::AssertValidType(FlagFastTypeId rhs_type_id, std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const { void* res = nullptr; - if (DefaultKind() == FlagDefaultKind::kDynamicValue) { - res = flags_internal::Clone(op_, default_value_.dynamic_value); - } else { - res = flags_internal::Alloc(op_); - (*default_value_.gen_func)(res); + switch (DefaultKind()) { + case FlagDefaultKind::kDynamicValue: + res = flags_internal::Clone(op_, default_value_.dynamic_value); + break; + case FlagDefaultKind::kGenFunc: + res = flags_internal::Alloc(op_); + (*default_value_.gen_func)(res); + break; + case FlagDefaultKind::kOneWord: + res = flags_internal::Clone(op_, &default_value_.one_word); + break; + case FlagDefaultKind::kFloat: + res = flags_internal::Clone(op_, &default_value_.float_value); + break; + case FlagDefaultKind::kDouble: + res = flags_internal::Clone(op_, &default_value_.double_value); + break; } return {res, DynValueDeleter{op_}}; } @@ -235,8 +271,6 @@ std::string FlagImpl::Filename() const { return flags_internal::GetUsageConfig().normalize_filename(filename_); } -absl::string_view FlagImpl::Typename() const { return ""; } - std::string FlagImpl::Help() const { return HelpSourceKind() == FlagHelpKind::kLiteral ? help_.literal : help_.gen_func(); @@ -246,11 +280,6 @@ FlagFastTypeId FlagImpl::TypeId() const { return flags_internal::FastTypeId(op_); } -bool FlagImpl::IsModified() const { - absl::MutexLock l(DataGuard()); - return modified_; -} - bool FlagImpl::IsSpecifiedOnCommandLine() const { absl::MutexLock l(DataGuard()); return on_command_line_; diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index 6da25aa9454a..b2208824508d 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -206,12 +206,72 @@ using FlagDfltGenFunc = void (*)(void*); union FlagDefaultSrc { constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg) : gen_func(gen_func_arg) {} + template <typename T> + constexpr explicit FlagDefaultSrc(T one_word_value) + : one_word(static_cast<int64_t>(one_word_value)) {} + constexpr explicit FlagDefaultSrc(float f) : float_value(f) {} + constexpr explicit FlagDefaultSrc(double d) : double_value(d) {} void* dynamic_value; FlagDfltGenFunc gen_func; + int64_t one_word; + float float_value; + double double_value; +}; + +enum class FlagDefaultKind : uint8_t { + kDynamicValue = 0, + kGenFunc = 1, + kOneWord = 2, + kFloat = 3, + kDouble = 4 +}; + +struct FlagDefaultArg { + FlagDefaultSrc source; + FlagDefaultKind kind; }; -enum class FlagDefaultKind : uint8_t { kDynamicValue = 0, kGenFunc = 1 }; +// This struct and corresponding overload to InitDefaultValue are used to +// facilitate usage of {} as default value in ABSL_FLAG macro. +// TODO(rogeeff): Fix handling types with explicit constructors. +struct EmptyBraces {}; + +template <typename T> +constexpr T InitDefaultValue(T t) { + return t; +} + +template <typename T> +constexpr T InitDefaultValue(EmptyBraces) { + return T{}; +} + +template <typename ValueT, typename GenT, + typename std::enable_if<std::is_integral<ValueT>::value, int>::type = + (GenT{}, 0)> +constexpr FlagDefaultArg DefaultArg(int) { + return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kOneWord}; +} + +template <typename ValueT, typename GenT, + typename std::enable_if<std::is_same<ValueT, float>::value, + int>::type = (GenT{}, 0)> +constexpr FlagDefaultArg DefaultArg(int) { + return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kFloat}; +} + +template <typename ValueT, typename GenT, + typename std::enable_if<std::is_same<ValueT, double>::value, + int>::type = (GenT{}, 0)> +constexpr FlagDefaultArg DefaultArg(int) { + return {FlagDefaultSrc(GenT{}.value), FlagDefaultKind::kDouble}; +} + +template <typename ValueT, typename GenT> +constexpr FlagDefaultArg DefaultArg(char) { + return {FlagDefaultSrc(&GenT::Gen), FlagDefaultKind::kGenFunc}; +} /////////////////////////////////////////////////////////////////////////////// // Flag current value auxiliary structs. @@ -356,19 +416,19 @@ class FlagImpl final : public flags_internal::CommandLineFlag { public: constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op, FlagHelpArg help, FlagValueStorageKind value_kind, - FlagDfltGenFunc default_value_gen) + FlagDefaultArg default_arg) : name_(name), filename_(filename), op_(op), help_(help.source), help_source_kind_(static_cast<uint8_t>(help.kind)), value_storage_kind_(static_cast<uint8_t>(value_kind)), - def_kind_(static_cast<uint8_t>(FlagDefaultKind::kGenFunc)), + def_kind_(static_cast<uint8_t>(default_arg.kind)), modified_(false), on_command_line_(false), counter_(0), callback_(nullptr), - default_value_(default_value_gen), + default_value_(default_arg.source), data_guard_{} {} // Constant access methods @@ -444,10 +504,8 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // CommandLineFlag interface implementation absl::string_view Name() const override; std::string Filename() const override; - absl::string_view Typename() const override; std::string Help() const override; FlagFastTypeId TypeId() const override; - bool IsModified() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); bool IsSpecifiedOnCommandLine() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); std::string DefaultValue() const override ABSL_LOCKS_EXCLUDED(*DataGuard()); @@ -492,9 +550,10 @@ class FlagImpl final : public flags_internal::CommandLineFlag { // Mutable flag's state (guarded by `data_guard_`). - // If def_kind_ == kDynamicValue, default_value_ holds a dynamically allocated - // value. - uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard()); + // def_kind_ is not guard by DataGuard() since it is accessed in Init without + // locks. If necessary we can decrease number of bits used to 2 by folding + // one_word storage cases. + uint8_t def_kind_ : 3; // Has this flag's value been modified? bool modified_ : 1 ABSL_GUARDED_BY(*DataGuard()); // Has this flag been specified on command line. @@ -530,10 +589,10 @@ class FlagImpl final : public flags_internal::CommandLineFlag { template <typename T> class Flag { public: - constexpr Flag(const char* name, const char* filename, const FlagHelpArg help, - const FlagDfltGenFunc default_value_gen) + constexpr Flag(const char* name, const char* filename, FlagHelpArg help, + const FlagDefaultArg default_arg) : impl_(name, filename, &FlagOps<T>, help, - flags_internal::StorageKind<T>(), default_value_gen), + flags_internal::StorageKind<T>(), default_arg), value_() {} T Get() const { @@ -560,9 +619,7 @@ class Flag { // CommandLineFlag interface absl::string_view Name() const { return impl_.Name(); } std::string Filename() const { return impl_.Filename(); } - absl::string_view Typename() const { return ""; } std::string Help() const { return impl_.Help(); } - bool IsModified() const { return impl_.IsModified(); } bool IsSpecifiedOnCommandLine() const { return impl_.IsSpecifiedOnCommandLine(); } @@ -662,20 +719,6 @@ class FlagRegistrar { Flag<T>* flag_; // Flag being registered (not owned). }; -// This struct and corresponding overload to MakeDefaultValue are used to -// facilitate usage of {} as default value in ABSL_FLAG macro. -struct EmptyBraces {}; - -template <typename T> -void MakeFromDefaultValue(void* dst, T t) { - new (dst) T(std::move(t)); -} - -template <typename T> -void MakeFromDefaultValue(void* dst, EmptyBraces) { - new (dst) T{}; -} - } // namespace flags_internal ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc index eb619c7086ad..62b5b40d88b8 100644 --- a/absl/flags/internal/registry.cc +++ b/absl/flags/internal/registry.cc @@ -127,14 +127,13 @@ void FlagRegistry::RegisterFlag(CommandLineFlag* flag) { (flag->IsRetired() ? old_flag->Filename() : flag->Filename()), "'."), true); - } else if (flag->TypeId() != old_flag->TypeId()) { + } else if (flags_internal::PrivateHandleInterface::TypeId(*flag) != + flags_internal::PrivateHandleInterface::TypeId(*old_flag)) { flags_internal::ReportUsageError( absl::StrCat("Flag '", flag->Name(), "' was defined more than once but with " "differing types. Defined in files '", - old_flag->Filename(), "' and '", flag->Filename(), - "' with types '", old_flag->Typename(), "' and '", - flag->Typename(), "', respectively."), + old_flag->Filename(), "' and '", flag->Filename(), "'."), true); } else if (old_flag->IsRetired()) { // Retired flag can just be deleted. @@ -206,7 +205,8 @@ class FlagSaverImpl { void SaveFromRegistry() { assert(backup_registry_.empty()); // call only once! flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) { - if (auto flag_state = flag->SaveState()) { + if (auto flag_state = + flags_internal::PrivateHandleInterface::SaveState(flag)) { backup_registry_.emplace_back(std::move(flag_state)); } }); @@ -290,11 +290,9 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag { private: absl::string_view Name() const override { return name_; } std::string Filename() const override { return "RETIRED"; } - absl::string_view Typename() const override { return ""; } FlagFastTypeId TypeId() const override { return type_id_; } std::string Help() const override { return ""; } bool IsRetired() const override { return true; } - bool IsModified() const override { return false; } bool IsSpecifiedOnCommandLine() const override { return false; } std::string DefaultValue() const override { return ""; } std::string CurrentValue() const override { return ""; } diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc index 75b4cdf891a8..5038625be761 100644 --- a/absl/flags/internal/type_erased.cc +++ b/absl/flags/internal/type_erased.cc @@ -72,7 +72,9 @@ bool IsValidFlagValue(absl::string_view name, absl::string_view value) { CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); return flag != nullptr && - (flag->IsRetired() || flag->ValidateInputValue(value)); + (flag->IsRetired() || + flags_internal::PrivateHandleInterface::ValidateInputValue(*flag, + value)); } // -------------------------------------------------------------------- diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h index 188429c77129..ffe319bad945 100644 --- a/absl/flags/internal/type_erased.h +++ b/absl/flags/internal/type_erased.h @@ -75,7 +75,7 @@ inline bool GetByName(absl::string_view name, T* dst) { CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name); if (!flag) return false; - if (auto val = flag->Get<T>()) { + if (auto val = flag->TryGet<T>()) { *dst = *val; return true; } diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc index a9a5cba94de8..9d856c87a6c0 100644 --- a/absl/flags/internal/usage.cc +++ b/absl/flags/internal/usage.cc @@ -54,27 +54,6 @@ ABSL_NAMESPACE_BEGIN namespace flags_internal { namespace { -absl::string_view TypenameForHelp(const flags_internal::CommandLineFlag& flag) { - // Only report names of v1 built-in types -#define HANDLE_V1_BUILTIN_TYPE(t) \ - if (flag.IsOfType<t>()) { \ - return #t; \ - } - - HANDLE_V1_BUILTIN_TYPE(bool); - HANDLE_V1_BUILTIN_TYPE(int32_t); - HANDLE_V1_BUILTIN_TYPE(int64_t); - HANDLE_V1_BUILTIN_TYPE(uint64_t); - HANDLE_V1_BUILTIN_TYPE(double); -#undef HANDLE_V1_BUILTIN_TYPE - - if (flag.IsOfType<std::string>()) { - return "string"; - } - - return ""; -} - // This class is used to emit an XML element with `tag` and `text`. // It adds opening and closing tags and escapes special characters in the text. // For example: @@ -212,23 +191,20 @@ void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag, // Flag help. printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true); - // Flag data type (for V1 flags only). - if (!flag.IsAbseilFlag() && !flag.IsRetired()) { - printer.Write(absl::StrCat("type: ", TypenameForHelp(flag), ";")); - } - // The listed default value will be the actual default from the flag // definition in the originating source file, unless the value has // subsequently been modified using SetCommandLineOption() with mode // SET_FLAGS_DEFAULT. std::string dflt_val = flag.DefaultValue(); + std::string curr_val = flag.CurrentValue(); + bool is_modified = curr_val != dflt_val; + if (flag.IsOfType<std::string>()) { dflt_val = absl::StrCat("\"", dflt_val, "\""); } printer.Write(absl::StrCat("default: ", dflt_val, ";")); - if (flag.IsModified()) { - std::string curr_val = flag.CurrentValue(); + if (is_modified) { if (flag.IsOfType<std::string>()) { curr_val = absl::StrCat("\"", curr_val, "\""); } |