From 4167eab063636a1fadcd571e0a762ff67d742c25 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 29 Sep 2021 09:40:33 -0700 Subject: Export of internal Abseil changes -- 506fa3e10b3d8399ad937c32ecea26d1ad4e62bb by Abseil Team : Disable ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE when GCC < 8.2.0 is used with libc++ PiperOrigin-RevId: 399707056 -- 656b7c7cee87f46a4bc7953618796f82da08e62c by Derek Mauro : Remove the MSVC flag implementation from flag.h to help clarify that methods on absl::Flag are not part of the public API PiperOrigin-RevId: 399584678 -- a92a9bc156303bc663b84c4b704891ec8f67e333 by Abseil Team : Get rid of MemcpyIfAllowed while continuing to suppress erroneous warnings PiperOrigin-RevId: 399468864 -- 5f9a66895f707ba001fb51b88c0c6025f8c872a3 by Abseil Team : Use feature testing to check for availability of invoke_result. Feature testing should be available by C++20, which removes invoke_result. https://en.cppreference.com/w/cpp/feature_test PiperOrigin-RevId: 399447373 -- 946c0a502b4499dbfcabf1ab93ddde0048288fb4 by CJ Johnson : Add rvalue-reference qualifier to the Commit method on ConstructionTransaction PiperOrigin-RevId: 399442206 -- 726a4d036eff49aeb6fd0ca2b1775699b6844395 by Greg Falcon : Internal change PiperOrigin-RevId: 399441870 -- 1df6d3f659b88dbac13c3d8e13db23bb3844ece2 by Abseil Team : Clang-format whitespace changes PiperOrigin-RevId: 399281271 -- 4a828cde95a07421d699ebac775b37810624214f by Derek Mauro : Internal change PiperOrigin-RevId: 399234071 -- e520c72b34ba2f98668c889139001f8276243d31 by Greg Falcon : Import of CCTZ from GitHub. PiperOrigin-RevId: 399233662 GitOrigin-RevId: 506fa3e10b3d8399ad937c32ecea26d1ad4e62bb Change-Id: I92b9176d2387c08eb167f9268efa78b55b8e09c2 --- absl/flags/BUILD.bazel | 1 + absl/flags/CMakeLists.txt | 1 + absl/flags/flag.h | 96 +------------------------------ absl/flags/internal/flag_msvc.inc | 116 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 95 deletions(-) create mode 100644 absl/flags/internal/flag_msvc.inc (limited to 'absl/flags') diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index c178b86b..7957c6dd 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel @@ -217,6 +217,7 @@ cc_library( name = "flag", srcs = [ "flag.cc", + "internal/flag_msvc.inc", ], hdrs = [ "declare.h", diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 956f70f8..7f3298e9 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt @@ -202,6 +202,7 @@ absl_cc_library( HDRS "declare.h" "flag.h" + "internal/flag_msvc.inc" COPTS ${ABSL_DEFAULT_COPTS} LINKOPTS diff --git a/absl/flags/flag.h b/absl/flags/flag.h index 14209e7b..1a7e4d4d 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -71,101 +71,7 @@ ABSL_NAMESPACE_BEGIN template using Flag = flags_internal::Flag; #else -// 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(); -} // namespace flags_internal - -template -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 char* filename, - const flags_internal::HelpGenFunc help_gen, - const flags_internal::FlagDfltGenFunc default_value_gen) - : name_(name), - filename_(filename), - help_gen_(help_gen), - default_value_gen_(default_value_gen), - inited_(false), - impl_(nullptr) {} -#endif - - flags_internal::Flag& GetImpl() const { - if (!inited_.load(std::memory_order_acquire)) { - absl::MutexLock l(flags_internal::GetGlobalConstructionGuard()); - - if (inited_.load(std::memory_order_acquire)) { - return *impl_; - } - - impl_ = new flags_internal::Flag( - name_, filename_, - {flags_internal::FlagHelpMsg(help_gen_), - flags_internal::FlagHelpKind::kGenFunc}, - {flags_internal::FlagDefaultSrc(default_value_gen_), - flags_internal::FlagDefaultKind::kGenFunc}); - inited_.store(true, std::memory_order_release); - } - - return *impl_; - } - - // Public methods of `absl::Flag` 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 IsSpecifiedOnCommandLine() const { - return GetImpl().IsSpecifiedOnCommandLine(); - } - std::string Filename() const { return GetImpl().Filename(); } - std::string DefaultValue() const { return GetImpl().DefaultValue(); } - std::string CurrentValue() const { return GetImpl().CurrentValue(); } - template - inline bool IsOfType() const { - return GetImpl().template IsOfType(); - } - T Get() const { - return flags_internal::FlagImplPeer::InvokeGet(GetImpl()); - } - void Set(const T& v) { - flags_internal::FlagImplPeer::InvokeSet(GetImpl(), v); - } - void InvokeCallback() { GetImpl().InvokeCallback(); } - - const CommandLineFlag& Reflect() const { - return flags_internal::FlagImplPeer::InvokeReflect(GetImpl()); - } - - // The data members are logically private, but they need to be public for - // this to be an aggregate type. - const char* name_; - const char* filename_; - const flags_internal::HelpGenFunc help_gen_; - const flags_internal::FlagDfltGenFunc default_value_gen_; - - mutable std::atomic inited_; - mutable flags_internal::Flag* impl_; -}; +#include "absl/flags/internal/flag_msvc.inc" #endif // GetFlag() diff --git a/absl/flags/internal/flag_msvc.inc b/absl/flags/internal/flag_msvc.inc new file mode 100644 index 00000000..c31bd27f --- /dev/null +++ b/absl/flags/internal/flag_msvc.inc @@ -0,0 +1,116 @@ +// +// Copyright 2021 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Do not include this file directly. +// Include absl/flags/flag.h instead. + +// 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(); +} // namespace flags_internal + +// Public methods of `absl::Flag` are NOT part of the Abseil Flags API. +// See https://abseil.io/docs/cpp/guides/flags +template +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 char* filename, + const flags_internal::HelpGenFunc help_gen, + const flags_internal::FlagDfltGenFunc default_value_gen) + : name_(name), + filename_(filename), + help_gen_(help_gen), + default_value_gen_(default_value_gen), + inited_(false), + impl_(nullptr) {} +#endif + + flags_internal::Flag& GetImpl() const { + if (!inited_.load(std::memory_order_acquire)) { + absl::MutexLock l(flags_internal::GetGlobalConstructionGuard()); + + if (inited_.load(std::memory_order_acquire)) { + return *impl_; + } + + impl_ = new flags_internal::Flag( + name_, filename_, + {flags_internal::FlagHelpMsg(help_gen_), + flags_internal::FlagHelpKind::kGenFunc}, + {flags_internal::FlagDefaultSrc(default_value_gen_), + flags_internal::FlagDefaultKind::kGenFunc}); + inited_.store(true, std::memory_order_release); + } + + return *impl_; + } + + // Public methods of `absl::Flag` 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 IsSpecifiedOnCommandLine() const { + return GetImpl().IsSpecifiedOnCommandLine(); + } + std::string Filename() const { return GetImpl().Filename(); } + std::string DefaultValue() const { return GetImpl().DefaultValue(); } + std::string CurrentValue() const { return GetImpl().CurrentValue(); } + template + inline bool IsOfType() const { + return GetImpl().template IsOfType(); + } + T Get() const { + return flags_internal::FlagImplPeer::InvokeGet(GetImpl()); + } + void Set(const T& v) { + flags_internal::FlagImplPeer::InvokeSet(GetImpl(), v); + } + void InvokeCallback() { GetImpl().InvokeCallback(); } + + const CommandLineFlag& Reflect() const { + return flags_internal::FlagImplPeer::InvokeReflect(GetImpl()); + } + + // The data members are logically private, but they need to be public for + // this to be an aggregate type. + const char* name_; + const char* filename_; + const flags_internal::HelpGenFunc help_gen_; + const flags_internal::FlagDfltGenFunc default_value_gen_; + + mutable std::atomic inited_; + mutable flags_internal::Flag* impl_; +}; -- cgit v1.2.3