diff options
author | Abseil Team <absl-team@google.com> | 2019-08-23T18·38-0700 |
---|---|---|
committer | Xiaoyi Zhang <zhangxy@google.com> | 2019-08-23T18·48-0400 |
commit | 2d2d7fbc283315b676159716376e739d3d23ed94 (patch) | |
tree | 6530edfdc7591c4f89d0aa48442cc6d452c47735 /absl/flags/flag.h | |
parent | 0302d1e5fa4fcdd1763b7d1bb3212943b1ae911d (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.h | 106 |
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 |