diff options
Diffstat (limited to 'absl/flags')
-rw-r--r-- | absl/flags/flag.h | 61 | ||||
-rw-r--r-- | absl/flags/flag_test.cc | 67 | ||||
-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 |
11 files changed, 240 insertions, 162 deletions
diff --git a/absl/flags/flag.h b/absl/flags/flag.h index 194a9d314fc5..8dd1b9be7af8 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -118,11 +118,12 @@ class Flag { return impl_; } - impl_ = - new flags_internal::Flag<T>(name_, filename_, - {flags_internal::FlagHelpMsg(help_gen_), - flags_internal::FlagHelpKind::kGenFunc}, - default_value_gen_); + impl_ = new flags_internal::Flag<T>( + name_, filename_, + {flags_internal::FlagHelpMsg(help_gen_), + flags_internal::FlagHelpKind::kGenFunc}, + {flags_internal::FlagDefaultSrc(default_value_gen_), + flags_internal::FlagDefaultKind::kGenFunc}); inited_.store(true, std::memory_order_release); } @@ -132,14 +133,12 @@ class Flag { // 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(); } - bool IsAbseilFlag() const { return GetImpl()->IsAbseilFlag(); } 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(); } - absl::string_view Typename() const { return GetImpl()->Typename(); } std::string Filename() const { return GetImpl()->Filename(); } std::string DefaultValue() const { return GetImpl()->DefaultValue(); } std::string CurrentValue() const { return GetImpl()->CurrentValue(); } @@ -311,9 +310,12 @@ ABSL_NAMESPACE_END static std::string NonConst() { return ABSL_FLAG_IMPL_FLAGHELP(txt); } \ } -#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ - static void AbslFlagsInitFlag##name(void* dst) { \ - absl::flags_internal::MakeFromDefaultValue<Type>(dst, default_value); \ +#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \ + struct AbslFlagDefaultGenFor##name { \ + Type value = absl::flags_internal::InitDefaultValue<Type>(default_value); \ + static void Gen(void* p) { \ + new (p) Type(AbslFlagDefaultGenFor##name{}.value); \ + } \ } // ABSL_FLAG_IMPL @@ -322,29 +324,30 @@ ABSL_NAMESPACE_END // 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), \ - &AbslFlagsInitFlag##name}; \ - 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::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 = \ 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, &AbslFlagsInitFlag##name}; \ - 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(), \ + &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 diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 6fa178f1f0b9..015b1fc9dc5d 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -128,26 +128,27 @@ constexpr flags::FlagHelpArg help_arg{flags::FlagHelpMsg("literal help"), using String = std::string; -#define DEFINE_CONSTRUCTED_FLAG(T) \ - constexpr flags::Flag<T> f1##T("f1", "file", help_arg, &TestMakeDflt<T>); \ - ABSL_CONST_INIT flags::Flag<T> f2##T( \ - "f2", "file", \ - {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ - &TestMakeDflt<T>) - -#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T); - -DEFINE_CONSTRUCTED_FLAG(bool); -DEFINE_CONSTRUCTED_FLAG(int16_t); -DEFINE_CONSTRUCTED_FLAG(uint16_t); -DEFINE_CONSTRUCTED_FLAG(int32_t); -DEFINE_CONSTRUCTED_FLAG(uint32_t); -DEFINE_CONSTRUCTED_FLAG(int64_t); -DEFINE_CONSTRUCTED_FLAG(uint64_t); -DEFINE_CONSTRUCTED_FLAG(float); -DEFINE_CONSTRUCTED_FLAG(double); -DEFINE_CONSTRUCTED_FLAG(String); -DEFINE_CONSTRUCTED_FLAG(UDT); +#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \ + constexpr flags::FlagDefaultArg f1default##T{ \ + flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \ + constexpr flags::Flag<T> f1##T("f1", "file", help_arg, f1default##T); \ + ABSL_CONST_INIT flags::Flag<T> f2##T( \ + "f2", "file", \ + {flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \ + flags::FlagDefaultArg{flags::FlagDefaultSrc(&TestMakeDflt<T>), \ + flags::FlagDefaultKind::kGenFunc}) + +DEFINE_CONSTRUCTED_FLAG(bool, true, kOneWord); +DEFINE_CONSTRUCTED_FLAG(int16_t, 1, kOneWord); +DEFINE_CONSTRUCTED_FLAG(uint16_t, 2, kOneWord); +DEFINE_CONSTRUCTED_FLAG(int32_t, 3, kOneWord); +DEFINE_CONSTRUCTED_FLAG(uint32_t, 4, kOneWord); +DEFINE_CONSTRUCTED_FLAG(int64_t, 5, kOneWord); +DEFINE_CONSTRUCTED_FLAG(uint64_t, 6, kOneWord); +DEFINE_CONSTRUCTED_FLAG(float, 7.8, kFloat); +DEFINE_CONSTRUCTED_FLAG(double, 9.10, kDouble); +DEFINE_CONSTRUCTED_FLAG(String, &TestMakeDflt<String>, kGenFunc); +DEFINE_CONSTRUCTED_FLAG(UDT, &TestMakeDflt<UDT>, kGenFunc); template <typename T> bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>* f2) { @@ -164,6 +165,8 @@ bool TestConstructionFor(const flags::Flag<T>& f1, flags::Flag<T>* f2) { return true; } +#define TEST_CONSTRUCTED_FLAG(T) TestConstructionFor(f1##T, &f2##T); + TEST_F(FlagTest, TestConstruction) { TEST_CONSTRUCTED_FLAG(bool); TEST_CONSTRUCTED_FLAG(int16_t); @@ -443,29 +446,29 @@ TEST_F(FlagTest, TestGetSet) { TEST_F(FlagTest, TestGetViaReflection) { auto* handle = flags::FindCommandLineFlag("test_flag_01"); - EXPECT_EQ(*handle->Get<bool>(), true); + EXPECT_EQ(*handle->TryGet<bool>(), true); handle = flags::FindCommandLineFlag("test_flag_02"); - EXPECT_EQ(*handle->Get<int>(), 1234); + EXPECT_EQ(*handle->TryGet<int>(), 1234); handle = flags::FindCommandLineFlag("test_flag_03"); - EXPECT_EQ(*handle->Get<int16_t>(), -34); + EXPECT_EQ(*handle->TryGet<int16_t>(), -34); handle = flags::FindCommandLineFlag("test_flag_04"); - EXPECT_EQ(*handle->Get<uint16_t>(), 189); + EXPECT_EQ(*handle->TryGet<uint16_t>(), 189); handle = flags::FindCommandLineFlag("test_flag_05"); - EXPECT_EQ(*handle->Get<int32_t>(), 10765); + EXPECT_EQ(*handle->TryGet<int32_t>(), 10765); handle = flags::FindCommandLineFlag("test_flag_06"); - EXPECT_EQ(*handle->Get<uint32_t>(), 40000); + EXPECT_EQ(*handle->TryGet<uint32_t>(), 40000); handle = flags::FindCommandLineFlag("test_flag_07"); - EXPECT_EQ(*handle->Get<int64_t>(), -1234567); + EXPECT_EQ(*handle->TryGet<int64_t>(), -1234567); handle = flags::FindCommandLineFlag("test_flag_08"); - EXPECT_EQ(*handle->Get<uint64_t>(), 9876543); + EXPECT_EQ(*handle->TryGet<uint64_t>(), 9876543); handle = flags::FindCommandLineFlag("test_flag_09"); - EXPECT_NEAR(*handle->Get<double>(), -9.876e-50, 1e-55); + EXPECT_NEAR(*handle->TryGet<double>(), -9.876e-50, 1e-55); handle = flags::FindCommandLineFlag("test_flag_10"); - EXPECT_NEAR(*handle->Get<float>(), 1.234e12f, 1e5f); + EXPECT_NEAR(*handle->TryGet<float>(), 1.234e12f, 1e5f); handle = flags::FindCommandLineFlag("test_flag_11"); - EXPECT_EQ(*handle->Get<std::string>(), ""); + EXPECT_EQ(*handle->TryGet<std::string>(), ""); handle = flags::FindCommandLineFlag("test_flag_12"); - EXPECT_EQ(*handle->Get<absl::Duration>(), absl::Minutes(10)); + EXPECT_EQ(*handle->TryGet<absl::Duration>(), absl::Minutes(10)); } // -------------------------------------------------------------------- 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, "\""); } |