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-10-31T18·37-0700
committervslashg <gfalcon@google.com>2019-10-31T19·15-0400
commit846e5dbedac123d12455adcfe6f53c8b5dcbfeef (patch)
treef895af106adf8c4fb1e80b6f65d84d117e20a1c1 /absl/flags/flag.h
parent83880e3d8ce512461c290782b541a623e50e39ef (diff)
Export of internal Abseil changes
--
90ecacd2a3db96ee64ef23af37a80fad404e2b32 by Gennadiy Rozental <rogeeff@google.com>:

Fixes MSVC regression by making MSVC version of class Flag into an aggregate type.

PiperOrigin-RevId: 277767054

--
018f3b040df51d91a988fa146fee163721e605e9 by Abseil Team <absl-team@google.com>:

Change libstdc++ lacking std::unique_ptr check from a gcc version check to based on feature macros.

PiperOrigin-RevId: 277736042

--
475844775ae343e2414318f08549ee3fa6676a8d by CJ Johnson <johnsoncj@google.com>:

Pass allocator_type through allocator_traits before extracting the typedefs

PiperOrigin-RevId: 277730393

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

Convert the Waiter::Init() method to the default constructor and define
a destructor for the Waiter class.

Use placement new and delete with Waiter objects.

PiperOrigin-RevId: 277728823

--
1ba6edf421dd2dfe13c55970a03c99592cb6677d by Derek Mauro <dmauro@google.com>:

Use lowercase spelling for include of dbghelp.h
When cross-compiling under MinGW this is important

PiperOrigin-RevId: 277629783

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

Don't use atomic ops on waiter and wakeup counts in WIN32 waiter mode.

Port the new CONDVAR waiter mode code in CL 277366017 to the WIN32
waiter mode.

PiperOrigin-RevId: 277603611

--
833106542e61fa0832900adf3c1b2afc6890b94b by Abseil Team <absl-team@google.com>:

Add the PerThreadSem::Destroy() method.

For ABSL_WAITER_MODE_CONDVAR or ABSL_WAITER_MODE_SEM,
PerThreadSem::Destroy() is used to destroy the pthread mutex and
condition variable or the POSIX semaphore.
PiperOrigin-RevId: 277586675

--
7814da4a59106cf1e0e4db1a31b9592ebbd2094b by Samuel Benzaquen <sbenza@google.com>:

Enable the assertion in the iterator's operator* and operator->

PiperOrigin-RevId: 277563401
GitOrigin-RevId: 90ecacd2a3db96ee64ef23af37a80fad404e2b32
Change-Id: Ib19be3680da74f0b94055c9039115ec6bcaea7b0
Diffstat (limited to 'absl/flags/flag.h')
-rw-r--r--absl/flags/flag.h70
1 files changed, 50 insertions, 20 deletions
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index c0060b449a82..356ddb616072 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -67,17 +67,20 @@ namespace absl {
 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.
+// MSVC debug builds do not implement initialization with constexpr constructors
+// correctly. To work around this we add a 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 constructor and virtual methods,
+// all the data members are public 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
+// initialized. 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.
+// This solution is based on a recomendation here:
+// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html?childToView=648454#comment-648454
 
 namespace flags_internal {
 absl::Mutex* GetGlobalConstructionGuard();
@@ -86,16 +89,23 @@ absl::Mutex* GetGlobalConstructionGuard();
 template <typename T>
 class Flag {
  public:
+  // No constructor and destructor to ensure this is an aggregate type.
+  // Visual Studio 2015 still requires the constructor for class to be
+  // constexpr initializable.
+#if _MSC_VER <= 1900
   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)
+                 const flags_internal::InitialValGenFunc initial_value_gen,
+                 bool, void*)
       : name_(name),
         help_gen_(help_gen),
         filename_(filename),
         marshalling_op_(marshalling_op),
         initial_value_gen_(initial_value_gen),
-        inited_(false) {}
+        inited_(false),
+        impl_(nullptr) {}
+#endif
 
   flags_internal::Flag<T>* GetImpl() const {
     if (!inited_.load(std::memory_order_acquire)) {
@@ -113,7 +123,8 @@ class Flag {
     return impl_;
   }
 
-  // absl::Flag API
+  // 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(); }
@@ -126,9 +137,9 @@ class Flag {
   std::string Filename() const { return GetImpl()->Filename(); }
   std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
   std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
-  template <typename T1>
+  template <typename U>
   inline bool IsOfType() const {
-    return GetImpl()->template IsOfType<T1>();
+    return GetImpl()->template IsOfType<U>();
   }
   T Get() const { return GetImpl()->Get(); }
   bool AtomicGet(T* v) const { return GetImpl()->AtomicGet(v); }
@@ -138,7 +149,8 @@ class Flag {
   }
   void InvokeCallback() { GetImpl()->InvokeCallback(); }
 
- private:
+  // The data members are logically private, but they need to be public for
+  // this to be an aggregate type.
   const char* name_;
   const flags_internal::HelpGenFunc help_gen_;
   const char* filename_;
@@ -146,7 +158,7 @@ class Flag {
   const flags_internal::InitialValGenFunc initial_value_gen_;
 
   mutable std::atomic<bool> inited_;
-  mutable flags_internal::Flag<T>* impl_ = nullptr;
+  mutable flags_internal::Flag<T>* impl_;
 };
 #endif
 
@@ -310,17 +322,35 @@ void SetFlag(absl::Flag<T>* flag, const V& v) {
 // 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_CONST_INIT absl::Flag<Type> FLAGS_##name{                    \
       ABSL_FLAG_IMPL_FLAGNAME(#name), &AbslFlagsWrapHelp##name,     \
       ABSL_FLAG_IMPL_FILENAME(),                                    \
       &absl::flags_internal::FlagMarshallingOps<Type>,              \
-      &AbslFlagsInitFlag##name);                                    \
+      &AbslFlagsInitFlag##name};                                    \
+  extern bool FLAGS_no##name;                                       \
+  bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
+#else
+// MSVC version uses aggregate initialization.
+#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),                               \
+      &AbslFlagsWrapHelp##name,                                     \
+      ABSL_FLAG_IMPL_FILENAME(),                                    \
+      &absl::flags_internal::FlagMarshallingOps<Type>,              \
+      &AbslFlagsInitFlag##name,                                     \
+      false,                                                        \
+      nullptr};                                                     \
   extern bool FLAGS_no##name;                                       \
   bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
+#endif
 
 // ABSL_RETIRED_FLAG
 //