diff options
Diffstat (limited to 'absl/flags/flag.h')
-rw-r--r-- | absl/flags/flag.h | 142 |
1 files changed, 75 insertions, 67 deletions
diff --git a/absl/flags/flag.h b/absl/flags/flag.h index ca7d581fce71..90dc2894df54 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -33,14 +33,11 @@ #include <type_traits> #include "absl/base/attributes.h" -#include "absl/base/casts.h" #include "absl/base/config.h" +#include "absl/base/optimization.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" #include "absl/strings/string_view.h" namespace absl { @@ -111,12 +108,12 @@ class Flag { 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 +125,30 @@ class Flag { 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(); } + + const CommandLineFlag& Reflect() const { return GetImpl().Reflect(); } // The data members are logically private, but they need to be public for // this to be an aggregate type. @@ -205,6 +204,21 @@ void SetFlag(absl::Flag<T>* flag, const V& v) { flag->Set(value); } +// GetFlagReflectionHandle() +// +// Returns the reflection handle corresponding to specified Abseil Flag +// instance. Use this handle to access flag's reflection information, like name, +// location, default value etc. +// +// Example: +// +// std::string = absl::GetFlagReflectionHandle(FLAGS_count).DefaultValue(); + +template <typename T> +const CommandLineFlag& GetFlagReflectionHandle(const absl::Flag<T>& f) { + return f.Reflect(); +} + ABSL_NAMESPACE_END } // namespace absl @@ -265,27 +279,29 @@ ABSL_NAMESPACE_END // ----------------------------------------------------------------------------- // 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 +317,24 @@ ABSL_NAMESPACE_END // 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 +342,23 @@ ABSL_NAMESPACE_END 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 // |