about summary refs log tree commit diff
path: root/absl/flags/flag.h
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/flag.h')
-rw-r--r--absl/flags/flag.h142
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
 //