diff options
author | Abseil Team <absl-team@google.com> | 2019-10-31T18·37-0700 |
---|---|---|
committer | vslashg <gfalcon@google.com> | 2019-10-31T19·15-0400 |
commit | 846e5dbedac123d12455adcfe6f53c8b5dcbfeef (patch) | |
tree | f895af106adf8c4fb1e80b6f65d84d117e20a1c1 /absl/flags/flag.h | |
parent | 83880e3d8ce512461c290782b541a623e50e39ef (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.h | 70 |
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 // |