about summary refs log tree commit diff
path: root/absl/flags/flag.h
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2019-08-23T18·38-0700
committerXiaoyi Zhang <zhangxy@google.com>2019-08-23T18·48-0400
commit2d2d7fbc283315b676159716376e739d3d23ed94 (patch)
tree6530edfdc7591c4f89d0aa48442cc6d452c47735 /absl/flags/flag.h
parent0302d1e5fa4fcdd1763b7d1bb3212943b1ae911d (diff)
Export of internal Abseil changes
--
d6748c733a70cd74ad9b76a0c9cd6b3fe2cecacf by Xiaoyi Zhang <zhangxy@google.com>:

Remove empty block, to address alerts reported in
https://github.com/abseil/abseil-cpp/issues/368.

PiperOrigin-RevId: 265099887

--
232e2036b5668d6d1296b881f9347756d84541ee by Derek Mauro <dmauro@google.com>:

Make the Linux Bazel CI scripts test with the exception mode explicitly set.

PiperOrigin-RevId: 265092105

--
942a40696c2c9b833be03e92d22a6ede7bccb6d4 by Xiaoyi Zhang <zhangxy@google.com>:

Import https://github.com/abseil/abseil-cpp/pull/372.
Suppress the unused variable warning on GCC, i.e. "-Wunused-variable".

PiperOrigin-RevId: 265063925

--
7ef90796b52cbdc260afc77cf47206f9356471d0 by Xiaoyi Zhang <zhangxy@google.com>:

Add quotes to `ABSL_COMMON_INCLUDE_DIRS` since it's a list and may contain a
`;`. This addresses https://github.com/abseil/abseil-cpp/issues/373.

PiperOrigin-RevId: 265059077

--
43f3ae742e00b83672ad6c5bc5b17fdb8f9fe6fe by Gennadiy Rozental <rogeeff@google.com>:

Internal re-organization

PiperOrigin-RevId: 264913945

--
6a2adf9c08ee1d98cc6b2855a676345c6495294a by Andy Soffer <asoffer@google.com>:

Publicly expose type names for uniform interval tags as in, for example, absl::IntervalClosedClosedTag, and add equality comparison operators.

PiperOrigin-RevId: 264861162

--
3c90c6e05fd61d56b419cd2d39dab8f17b8711b8 by Abseil Team <absl-team@google.com>:

Add validity check on returned frame pointer.

PiperOrigin-RevId: 264858823

--
2db87e0cfa0c6bea7ba81684b834cb8a73b7d748 by Gennadiy Rozental <rogeeff@google.com>:

Add MUST_USE_RESULT attribute to absl::GetFlag to prevent accidental misuse.

PiperOrigin-RevId: 264782762
GitOrigin-RevId: d6748c733a70cd74ad9b76a0c9cd6b3fe2cecacf
Change-Id: I169e9c5358e4f63000c1255e806d26b8afecf5ff
Diffstat (limited to 'absl/flags/flag.h')
-rw-r--r--absl/flags/flag.h106
1 files changed, 104 insertions, 2 deletions
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 36c771cf49b1..881f8502ef01 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -63,8 +63,100 @@ namespace absl {
 //      ABSL_FLAG(int, count, 0, "Count of items to process");
 //
 // No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
+#if !defined(_MSC_VER)
 template <typename T>
 using Flag = flags_internal::Flag<T>;
+#else
+// MSVC debug builds do not implement constexpr correctly for classes with
+// virtual methods. To work around this we adding level of indirection, so that
+// the class `absl::Flag` contains an `internal::Flag*` (instead of being an
+// alias to that class) and dynamically allocates an instance when necessary.
+// We also forward all calls to internal::Flag methods via trampoline methods.
+// In this setup the `absl::Flag` class does not have virtual methods and thus
+// MSVC is able to initialize it at link time. To deal with multiple threads
+// accessing the flag for the first time concurrently we use an atomic boolean
+// indicating if flag object is constructed. We also employ the double-checked
+// locking pattern where the second level of protection is a global Mutex, so
+// if two threads attempt to construct the flag concurrently only one wins.
+
+namespace flags_internal {
+void LockGlobalConstructionGuard();
+void UnlockGlobalConstructionGuard();
+}  // namespace flags_internal
+
+template <typename T>
+class Flag {
+ public:
+  constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
+                 const char* filename,
+                 const flags_internal::FlagMarshallingOpFn marshalling_op,
+                 const flags_internal::InitialValGenFunc initial_value_gen)
+      : name_(name),
+        help_gen_(help_gen),
+        filename_(filename),
+        marshalling_op_(marshalling_op),
+        initial_value_gen_(initial_value_gen),
+        inited_(false) {}
+
+  flags_internal::Flag<T>* GetImpl() const {
+    if (!inited_.load(std::memory_order_acquire)) {
+      flags_internal::LockGlobalConstructionGuard();
+
+      if (inited_.load(std::memory_order_acquire)) {
+        return impl_;
+      }
+
+      impl_ = new flags_internal::Flag<T>(name_, help_gen_, filename_,
+                                          marshalling_op_, initial_value_gen_);
+      inited_.store(true, std::memory_order_release);
+
+      flags_internal::UnlockGlobalConstructionGuard();
+    }
+
+    return impl_;
+  }
+
+  // absl::Flag API
+  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(); }
+  void SetModified(bool is_modified) { GetImpl()->SetModified(is_modified); }
+  bool IsSpecifiedOnCommandLine() const {
+    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(); }
+  bool HasValidatorFn() const { return GetImpl()->HasValidatorFn(); }
+  bool InvokeValidator(const void* value) const {
+    return GetImpl()->InvokeValidator(value);
+  }
+  template <typename T>
+  inline bool IsOfType() const {
+    return GetImpl()->IsOftype<T>();
+  }
+  T Get() const { return GetImpl()->Get(); }
+  bool AtomicGet(T* v) const { return GetImpl()->AtomicGet(v); }
+  void Set(const T& v) { GetImpl()->Set(v); }
+  void SetCallback(const flags_internal::FlagCallback mutation_callback) {
+    GetImpl()->SetCallback(mutation_callback);
+  }
+  void InvokeCallback() { GetImpl()->InvokeCallback(); }
+
+ private:
+  const char* name_;
+  const flags_internal::HelpGenFunc help_gen_;
+  const char* filename_;
+  const flags_internal::FlagMarshallingOpFn marshalling_op_;
+  const flags_internal::InitialValGenFunc initial_value_gen_;
+
+  mutable std::atomic<bool> inited_;
+  mutable flags_internal::Flag<T>* impl_ = nullptr;
+};
+#endif
 
 // GetFlag()
 //
@@ -83,7 +175,7 @@ using Flag = flags_internal::Flag<T>;
 //   // FLAGS_firstname is a Flag of type `std::string`
 //   std::string first_name = absl::GetFlag(FLAGS_firstname);
 template <typename T>
-T GetFlag(const absl::Flag<T>& flag) {
+ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) {
 #define ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE(BIT) \
   static_assert(                                    \
       !std::is_same<T, BIT>::value,                 \
@@ -96,7 +188,7 @@ T GetFlag(const absl::Flag<T>& flag) {
 
 // Overload for `GetFlag()` for types that support lock-free reads.
 #define ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT(T) \
-  extern T GetFlag(const absl::Flag<T>& flag);
+  ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
 ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT)
 #undef ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT
 
@@ -184,13 +276,23 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
 #if ABSL_FLAGS_STRIP_NAMES
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
 #define ABSL_FLAG_IMPL_FILENAME() ""
+#if !defined(_MSC_VER)
 #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
+#else
 #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
 #define ABSL_FLAG_IMPL_FILENAME() __FILE__
+#if !defined(_MSC_VER)
 #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
 #endif
 
 // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP