Export of internal Abseil changes
-- 00f5301405423005d9129935c05f20155536cc1a by CJ Johnson <johnsoncj@google.com>: Removes usage of std::aligned_storage from Abseil implementation details PiperOrigin-RevId: 296492301 -- fc11d15f91764612fba080669d2381dc181df52b by Abseil Team <absl-team@google.com>: Fix absl::bind_front documentation. PiperOrigin-RevId: 296482945 -- 0164c595c129c46bf21ae74eba5399a1da5f140b by Gennadiy Rozental <rogeeff@google.com>: Automated g4 rollback of changelist 296320700. PiperOrigin-RevId: 296439968 -- 1eb295700758ca0894d872b2de7c675b4ad679af by Abseil Team <absl-team@google.com>: Removes duplicate comments. PiperOrigin-RevId: 296433214 -- c30c01caae02d2fa4ef783d988de6bebb9757c39 by Derek Mauro <dmauro@google.com>: Merge GitHub #621: Add RISCV support to GetProgramCounter() Fixes #621 PiperOrigin-RevId: 296351174 -- 95d4498167596fd7543e025bdfe9a8da9e2ca3c8 by Abseil Team <absl-team@google.com>: Automated g4 rollback of changelist 296320700. PiperOrigin-RevId: 296348701 -- b193f0543e0cec54dddb2ed51f45dc489c8d06d5 by Gennadiy Rozental <rogeeff@google.com>: Change TryParse interface to return managed value. In addition introduce companion StoreValue routine which consumes pointer to source value and stores the value inside of FlagImpl. In a follow up CL we will change StoreValue implementation to behave differently depending on "value storage kind". We also rename default_src_ to default_value_. PiperOrigin-RevId: 296320700 -- 57e942b485d12912a0a8d0d0b35fa2a62847020f by Derek Mauro <dmauro@google.com>: Merge GitHub #622 * Add missing #ifdef conditionals for ABSL_HAVE_VDSO_SUPPORT PiperOrigin-RevId: 296272830 GitOrigin-RevId: 00f5301405423005d9129935c05f20155536cc1a Change-Id: I1b05eeaf1280f95fb0a2c5f3654995a87c792893
This commit is contained in:
		
							parent
							
								
									2a5633fc07
								
							
						
					
					
						commit
						b69c7d880c
					
				
					 16 changed files with 131 additions and 135 deletions
				
			
		|  | @ -328,17 +328,15 @@ TEST(ThrowingValueTest, NonThrowingDelete) { | |||
|   UnsetCountdown(); | ||||
| } | ||||
| 
 | ||||
| using Storage = | ||||
|     absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>; | ||||
| 
 | ||||
| TEST(ThrowingValueTest, NonThrowingPlacementDelete) { | ||||
|   constexpr int kArrayLen = 2; | ||||
|   // We intentionally create extra space to store the tag allocated by placement
 | ||||
|   // new[].
 | ||||
|   constexpr int kStorageLen = 4; | ||||
| 
 | ||||
|   Storage buf; | ||||
|   Storage array_buf[kStorageLen]; | ||||
|   alignas(ThrowingValue<>) unsigned char buf[sizeof(ThrowingValue<>)]; | ||||
|   alignas(ThrowingValue<>) unsigned char | ||||
|       array_buf[sizeof(ThrowingValue<>[kStorageLen])]; | ||||
|   auto* placed = new (&buf) ThrowingValue<>(1); | ||||
|   auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen]; | ||||
| 
 | ||||
|  | @ -902,12 +900,12 @@ TEST(ConstructorTrackerTest, CreatedAfter) { | |||
| } | ||||
| 
 | ||||
| TEST(ConstructorTrackerTest, NotDestroyedAfter) { | ||||
|   absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage; | ||||
|   alignas(Tracked) unsigned char storage[sizeof(Tracked)]; | ||||
|   EXPECT_NONFATAL_FAILURE( | ||||
|       { | ||||
|         exceptions_internal::ConstructorTracker ct( | ||||
|             exceptions_internal::countdown); | ||||
|         new (&storage) Tracked; | ||||
|         new (&storage) Tracked(); | ||||
|       }, | ||||
|       "not destroyed"); | ||||
| } | ||||
|  | @ -924,11 +922,11 @@ TEST(ConstructorTrackerTest, DestroyedTwice) { | |||
| 
 | ||||
| TEST(ConstructorTrackerTest, ConstructedTwice) { | ||||
|   exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); | ||||
|   absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage; | ||||
|   alignas(Tracked) unsigned char storage[sizeof(Tracked)]; | ||||
|   EXPECT_NONFATAL_FAILURE( | ||||
|       { | ||||
|         new (&storage) Tracked; | ||||
|         new (&storage) Tracked; | ||||
|         new (&storage) Tracked(); | ||||
|         new (&storage) Tracked(); | ||||
|         reinterpret_cast<Tracked*>(&storage)->~Tracked(); | ||||
|       }, | ||||
|       "re-constructed"); | ||||
|  |  | |||
|  | @ -220,16 +220,17 @@ struct LowLevelAlloc::Arena { | |||
| }; | ||||
| 
 | ||||
| namespace { | ||||
| using ArenaStorage = std::aligned_storage<sizeof(LowLevelAlloc::Arena), | ||||
|                                           alignof(LowLevelAlloc::Arena)>::type; | ||||
| 
 | ||||
| // Static storage space for the lazily-constructed, default global arena
 | ||||
| // instances.  We require this space because the whole point of LowLevelAlloc
 | ||||
| // is to avoid relying on malloc/new.
 | ||||
| ArenaStorage default_arena_storage; | ||||
| ArenaStorage unhooked_arena_storage; | ||||
| alignas(LowLevelAlloc::Arena) unsigned char default_arena_storage[sizeof( | ||||
|     LowLevelAlloc::Arena)]; | ||||
| alignas(LowLevelAlloc::Arena) unsigned char unhooked_arena_storage[sizeof( | ||||
|     LowLevelAlloc::Arena)]; | ||||
| #ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING | ||||
| ArenaStorage unhooked_async_sig_safe_arena_storage; | ||||
| alignas( | ||||
|     LowLevelAlloc::Arena) unsigned char unhooked_async_sig_safe_arena_storage | ||||
|     [sizeof(LowLevelAlloc::Arena)]; | ||||
| #endif | ||||
| 
 | ||||
| // We must use LowLevelCallOnce here to construct the global arenas, rather than
 | ||||
|  |  | |||
|  | @ -123,14 +123,6 @@ | |||
| // compiler flags passed by the end user.  For more info, see
 | ||||
| // https://abseil.io/about/design/dropin-types.
 | ||||
| 
 | ||||
| // A value of 2 means to detect the C++ version being used to compile Abseil,
 | ||||
| // and use an alias only if a working std::optional is available.  This option
 | ||||
| // should not be used when your program is not built from source -- for example,
 | ||||
| // if you are distributing Abseil in a binary package manager -- since in mode
 | ||||
| // 2, absl::optional will name a different template class, with a different
 | ||||
| // mangled name and binary layout, depending on the compiler flags passed by the
 | ||||
| // end user.
 | ||||
| //
 | ||||
| // User code should not inspect this macro.  To check in the preprocessor if
 | ||||
| // absl::optional is a typedef of std::optional, use the feature macro
 | ||||
| // ABSL_USES_STD_OPTIONAL.
 | ||||
|  |  | |||
|  | @ -604,19 +604,16 @@ TEST(FixedArrayTest, Fill) { | |||
|   empty.fill(fill_val); | ||||
| } | ||||
| 
 | ||||
| // TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x
 | ||||
| #ifndef __GNUC__ | ||||
| TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) { | ||||
|   using T = char; | ||||
|   constexpr auto capacity = 10; | ||||
|   using FixedArrType = absl::FixedArray<T, capacity>; | ||||
|   using FixedArrBuffType = | ||||
|       absl::aligned_storage_t<sizeof(FixedArrType), alignof(FixedArrType)>; | ||||
|   constexpr auto scrubbed_bits = 0x95; | ||||
|   constexpr auto length = capacity / 2; | ||||
| 
 | ||||
|   FixedArrBuffType buff; | ||||
|   std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType)); | ||||
|   alignas(FixedArrType) unsigned char buff[sizeof(FixedArrType)]; | ||||
|   std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrType)); | ||||
| 
 | ||||
|   FixedArrType* arr = | ||||
|       ::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length); | ||||
|  |  | |||
|  | @ -56,7 +56,7 @@ class node_handle_base { | |||
|  public: | ||||
|   using allocator_type = Alloc; | ||||
| 
 | ||||
|   constexpr node_handle_base() {} | ||||
|   constexpr node_handle_base() = default; | ||||
|   node_handle_base(node_handle_base&& other) noexcept { | ||||
|     *this = std::move(other); | ||||
|   } | ||||
|  | @ -109,9 +109,8 @@ class node_handle_base { | |||
|   allocator_type* alloc() { return std::addressof(*alloc_); } | ||||
| 
 | ||||
|  private: | ||||
|   absl::optional<allocator_type> alloc_; | ||||
|   mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)> | ||||
|       slot_space_; | ||||
|   absl::optional<allocator_type> alloc_ = {}; | ||||
|   alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {}; | ||||
| }; | ||||
| 
 | ||||
| // For sets.
 | ||||
|  |  | |||
|  | @ -1067,8 +1067,7 @@ class raw_hash_set { | |||
|   template <class... Args, typename std::enable_if< | ||||
|                                !IsDecomposable<Args...>::value, int>::type = 0> | ||||
|   std::pair<iterator, bool> emplace(Args&&... args) { | ||||
|     typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type | ||||
|         raw; | ||||
|     alignas(slot_type) unsigned char raw[sizeof(slot_type)]; | ||||
|     slot_type* slot = reinterpret_cast<slot_type*>(&raw); | ||||
| 
 | ||||
|     PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...); | ||||
|  | @ -1556,8 +1555,7 @@ class raw_hash_set { | |||
|     //       mark target as FULL
 | ||||
|     //       repeat procedure for current slot with moved from element (target)
 | ||||
|     ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_); | ||||
|     typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type | ||||
|         raw; | ||||
|     alignas(slot_type) unsigned char raw[sizeof(slot_type)]; | ||||
|     size_t total_probe_length = 0; | ||||
|     slot_type* slot = reinterpret_cast<slot_type*>(&raw); | ||||
|     for (size_t i = 0; i != capacity_; ++i) { | ||||
|  |  | |||
|  | @ -202,9 +202,9 @@ static void **NextStackFrame(void **old_fp, const void *uc) { | |||
|       } else { | ||||
|         num_push_instructions = 0; | ||||
|       } | ||||
| #else
 | ||||
| #else  // ABSL_HAVE_VDSO_SUPPORT
 | ||||
|       num_push_instructions = 0; | ||||
| #endif
 | ||||
| #endif  // ABSL_HAVE_VDSO_SUPPORT
 | ||||
|     } | ||||
|     if (num_push_instructions != 0 && kernel_rt_sigreturn_address != nullptr && | ||||
|         old_fp[1] == kernel_rt_sigreturn_address) { | ||||
|  |  | |||
|  | @ -121,13 +121,21 @@ void FlagImpl::AssertValidType(FlagStaticTypeId type_id) const { | |||
| std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const { | ||||
|   void* res = nullptr; | ||||
|   if (DefaultKind() == FlagDefaultKind::kDynamicValue) { | ||||
|     res = flags_internal::Clone(op_, default_src_.dynamic_value); | ||||
|     res = flags_internal::Clone(op_, default_value_.dynamic_value); | ||||
|   } else { | ||||
|     res = (*default_src_.gen_func)(); | ||||
|     res = (*default_value_.gen_func)(); | ||||
|   } | ||||
|   return {res, DynValueDeleter{op_}}; | ||||
| } | ||||
| 
 | ||||
| void FlagImpl::StoreValue(const void* src) { | ||||
|   flags_internal::Copy(op_, src, value_.dynamic); | ||||
|   StoreAtomic(); | ||||
|   modified_ = true; | ||||
|   ++counter_; | ||||
|   InvokeCallback(); | ||||
| } | ||||
| 
 | ||||
| absl::string_view FlagImpl::Name() const { return name_; } | ||||
| 
 | ||||
| std::string FlagImpl::Filename() const { | ||||
|  | @ -220,23 +228,19 @@ bool FlagImpl::RestoreState(const void* value, bool modified, | |||
| // argument. If parsing successful, this function replaces the dst with newly
 | ||||
| // parsed value. In case if any error is encountered in either step, the error
 | ||||
| // message is stored in 'err'
 | ||||
| bool FlagImpl::TryParse(void** dst, absl::string_view value, | ||||
|                         std::string* err) const { | ||||
|   auto tentative_value = MakeInitValue(); | ||||
| std::unique_ptr<void, DynValueDeleter> FlagImpl::TryParse( | ||||
|     absl::string_view value, std::string* err) const { | ||||
|   std::unique_ptr<void, DynValueDeleter> tentative_value = MakeInitValue(); | ||||
| 
 | ||||
|   std::string parse_err; | ||||
|   if (!flags_internal::Parse(op_, value, tentative_value.get(), &parse_err)) { | ||||
|     absl::string_view err_sep = parse_err.empty() ? "" : "; "; | ||||
|     *err = absl::StrCat("Illegal value '", value, "' specified for flag '", | ||||
|                         Name(), "'", err_sep, parse_err); | ||||
|     return false; | ||||
|     return nullptr; | ||||
|   } | ||||
| 
 | ||||
|   void* old_val = *dst; | ||||
|   *dst = tentative_value.release(); | ||||
|   tentative_value.reset(old_val); | ||||
| 
 | ||||
|   return true; | ||||
|   return tentative_value; | ||||
| } | ||||
| 
 | ||||
| void FlagImpl::Read(void* dst) const { | ||||
|  | @ -266,22 +270,17 @@ void FlagImpl::Write(const void* src) { | |||
|   absl::MutexLock l(DataGuard()); | ||||
| 
 | ||||
|   if (ShouldValidateFlagValue(flags_internal::StaticTypeId(op_))) { | ||||
|     void* obj = flags_internal::Clone(op_, src); | ||||
|     std::unique_ptr<void, DynValueDeleter> obj{flags_internal::Clone(op_, src), | ||||
|                                                DynValueDeleter{op_}}; | ||||
|     std::string ignored_error; | ||||
|     std::string src_as_str = flags_internal::Unparse(op_, src); | ||||
|     if (!flags_internal::Parse(op_, src_as_str, obj, &ignored_error)) { | ||||
|     if (!flags_internal::Parse(op_, src_as_str, obj.get(), &ignored_error)) { | ||||
|       ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", Name(), | ||||
|                                             "' to invalid value ", src_as_str)); | ||||
|     } | ||||
|     flags_internal::Delete(op_, obj); | ||||
|   } | ||||
| 
 | ||||
|   modified_ = true; | ||||
|   counter_++; | ||||
|   flags_internal::Copy(op_, src, value_.dynamic); | ||||
| 
 | ||||
|   StoreAtomic(); | ||||
|   InvokeCallback(); | ||||
|   StoreValue(src); | ||||
| } | ||||
| 
 | ||||
| // Sets the value of the flag based on specified string `value`. If the flag
 | ||||
|  | @ -299,11 +298,10 @@ bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode, | |||
|   switch (set_mode) { | ||||
|     case SET_FLAGS_VALUE: { | ||||
|       // set or modify the flag's value
 | ||||
|       if (!TryParse(&value_.dynamic, value, err)) return false; | ||||
|       modified_ = true; | ||||
|       counter_++; | ||||
|       StoreAtomic(); | ||||
|       InvokeCallback(); | ||||
|       auto tentative_value = TryParse(value, err); | ||||
|       if (!tentative_value) return false; | ||||
| 
 | ||||
|       StoreValue(tentative_value.get()); | ||||
| 
 | ||||
|       if (source == kCommandLine) { | ||||
|         on_command_line_ = true; | ||||
|  | @ -312,13 +310,7 @@ bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode, | |||
|     } | ||||
|     case SET_FLAG_IF_DEFAULT: { | ||||
|       // set the flag's value, but only if it hasn't been set by someone else
 | ||||
|       if (!modified_) { | ||||
|         if (!TryParse(&value_.dynamic, value, err)) return false; | ||||
|         modified_ = true; | ||||
|         counter_++; | ||||
|         StoreAtomic(); | ||||
|         InvokeCallback(); | ||||
|       } else { | ||||
|       if (modified_) { | ||||
|         // TODO(rogeeff): review and fix this semantic. Currently we do not fail
 | ||||
|         // in this case if flag is modified. This is misleading since the flag's
 | ||||
|         // value is not updated even though we return true.
 | ||||
|  | @ -327,28 +319,29 @@ bool FlagImpl::SetFromString(absl::string_view value, FlagSettingMode set_mode, | |||
|         // return false;
 | ||||
|         return true; | ||||
|       } | ||||
|       auto tentative_value = TryParse(value, err); | ||||
|       if (!tentative_value) return false; | ||||
| 
 | ||||
|       StoreValue(tentative_value.get()); | ||||
|       break; | ||||
|     } | ||||
|     case SET_FLAGS_DEFAULT: { | ||||
|       if (DefaultKind() == FlagDefaultKind::kDynamicValue) { | ||||
|         if (!TryParse(&default_src_.dynamic_value, value, err)) { | ||||
|           return false; | ||||
|         } | ||||
|       } else { | ||||
|         void* new_default_val = nullptr; | ||||
|         if (!TryParse(&new_default_val, value, err)) { | ||||
|           return false; | ||||
|         } | ||||
|       auto tentative_value = TryParse(value, err); | ||||
|       if (!tentative_value) return false; | ||||
| 
 | ||||
|         default_src_.dynamic_value = new_default_val; | ||||
|       if (DefaultKind() == FlagDefaultKind::kDynamicValue) { | ||||
|         void* old_value = default_value_.dynamic_value; | ||||
|         default_value_.dynamic_value = tentative_value.release(); | ||||
|         tentative_value.reset(old_value); | ||||
|       } else { | ||||
|         default_value_.dynamic_value = tentative_value.release(); | ||||
|         def_kind_ = static_cast<uint8_t>(FlagDefaultKind::kDynamicValue); | ||||
|       } | ||||
| 
 | ||||
|       if (!modified_) { | ||||
|         // Need to set both default value *and* current, in this case
 | ||||
|         flags_internal::Copy(op_, default_src_.dynamic_value, value_.dynamic); | ||||
|         StoreAtomic(); | ||||
|         InvokeCallback(); | ||||
|         StoreValue(default_value_.dynamic_value); | ||||
|         modified_ = false; | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|  |  | |||
|  | @ -363,7 +363,7 @@ struct DynValueDeleter { | |||
|     if (op != nullptr) Delete(op, ptr); | ||||
|   } | ||||
| 
 | ||||
|   const FlagOpFn op; | ||||
|   FlagOpFn op; | ||||
| }; | ||||
| 
 | ||||
| class FlagImpl { | ||||
|  | @ -380,7 +380,7 @@ class FlagImpl { | |||
|         on_command_line_(false), | ||||
|         counter_(0), | ||||
|         callback_(nullptr), | ||||
|         default_src_(default_value_gen), | ||||
|         default_value_(default_value_gen), | ||||
|         data_guard_{} {} | ||||
| 
 | ||||
|   // Constant access methods
 | ||||
|  | @ -392,10 +392,6 @@ class FlagImpl { | |||
|   std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(*DataGuard()); | ||||
|   std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(*DataGuard()); | ||||
|   void Read(void* dst) const ABSL_LOCKS_EXCLUDED(*DataGuard()); | ||||
|   // Attempts to parse supplied `value` std::string. If parsing is successful, then
 | ||||
|   // it replaces `dst` with the new value.
 | ||||
|   bool TryParse(void** dst, absl::string_view value, std::string* err) const | ||||
|       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); | ||||
| 
 | ||||
|   template <typename T, typename std::enable_if< | ||||
|                             !IsAtomicFlagTypeTrait<T>::value, int>::type = 0> | ||||
|  | @ -466,8 +462,15 @@ class FlagImpl { | |||
|   // Returns heap allocated value of type T initialized with default value.
 | ||||
|   std::unique_ptr<void, DynValueDeleter> MakeInitValue() const | ||||
|       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); | ||||
|   // Lazy initialization of the Flag's data.
 | ||||
|   // Flag initialization called via absl::call_once.
 | ||||
|   void Init(); | ||||
|   // Attempts to parse supplied `value` std::string. If parsing is successful,
 | ||||
|   // returns new value. Otherwsie returns nullptr.
 | ||||
|   std::unique_ptr<void, DynValueDeleter> TryParse(absl::string_view value, | ||||
|                                                   std::string* err) const | ||||
|       ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); | ||||
|   // Stores the flag value based on the pointer to the source.
 | ||||
|   void StoreValue(const void* src) ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); | ||||
| 
 | ||||
|   FlagHelpKind HelpSourceKind() const { | ||||
|     return static_cast<FlagHelpKind>(help_source_kind_); | ||||
|  | @ -511,7 +514,7 @@ class FlagImpl { | |||
| 
 | ||||
|   // Mutable flag's state (guarded by `data_guard_`).
 | ||||
| 
 | ||||
|   // If def_kind_ == kDynamicValue, default_src_ holds a dynamically allocated
 | ||||
|   // If def_kind_ == kDynamicValue, default_value_ holds a dynamically allocated
 | ||||
|   // value.
 | ||||
|   uint8_t def_kind_ : 1 ABSL_GUARDED_BY(*DataGuard()); | ||||
|   // Has this flag's value been modified?
 | ||||
|  | @ -527,7 +530,7 @@ class FlagImpl { | |||
|   // value specified in ABSL_FLAG or pointer to the dynamically set default
 | ||||
|   // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish
 | ||||
|   // these two cases.
 | ||||
|   FlagDefaultSrc default_src_ ABSL_GUARDED_BY(*DataGuard()); | ||||
|   FlagDefaultSrc default_value_ ABSL_GUARDED_BY(*DataGuard()); | ||||
|   // Current Flag Value
 | ||||
|   FlagValue value_; | ||||
| 
 | ||||
|  | @ -542,8 +545,8 @@ class FlagImpl { | |||
| }; | ||||
| 
 | ||||
| ///////////////////////////////////////////////////////////////////////////////
 | ||||
| // The "unspecified" implementation of Flag object parameterized by the
 | ||||
| // flag's value type.
 | ||||
| // The Flag object parameterized by the flag's value type. This class implements
 | ||||
| // flag reflection handle interface.
 | ||||
| 
 | ||||
| template <typename T> | ||||
| class Flag final : public flags_internal::CommandLineFlag { | ||||
|  |  | |||
|  | @ -119,6 +119,13 @@ TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_DEFAULT) { | |||
|   EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101", | ||||
|                                                   flags::SET_FLAGS_DEFAULT)); | ||||
| 
 | ||||
|   // Set it again to ensure that resetting logic is covered.
 | ||||
|   EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "102", | ||||
|                                                   flags::SET_FLAGS_DEFAULT)); | ||||
| 
 | ||||
|   EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "103", | ||||
|                                                   flags::SET_FLAGS_DEFAULT)); | ||||
| 
 | ||||
|   EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh", | ||||
|                                                   flags::SET_FLAGS_DEFAULT)); | ||||
|   EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh"); | ||||
|  |  | |||
|  | @ -38,9 +38,7 @@ ABSL_NAMESPACE_BEGIN | |||
| 
 | ||||
| // bind_front()
 | ||||
| //
 | ||||
| // Binds the first N arguments of an invocable object and stores them by value,
 | ||||
| // except types of `std::reference_wrapper` which are 'unwound' and stored by
 | ||||
| // reference.
 | ||||
| // Binds the first N arguments of an invocable object and stores them by value.
 | ||||
| //
 | ||||
| // Like `std::bind()`, `absl::bind_front()` is implicitly convertible to
 | ||||
| // `std::function`.  In particular, it may be used as a simpler replacement for
 | ||||
|  | @ -140,7 +138,9 @@ ABSL_NAMESPACE_BEGIN | |||
| //
 | ||||
| // Example: Storing bound arguments by reference.
 | ||||
| //
 | ||||
| //   void Print(const string& a, const string& b) { LOG(INFO) << a << b; }
 | ||||
| //   void Print(const std::string& a, const std::string& b) {
 | ||||
| //     std::cerr << a << b;
 | ||||
| //   }
 | ||||
| //
 | ||||
| //   std::string hi = "Hello, ";
 | ||||
| //   std::vector<std::string> names = {"Chuk", "Gek"};
 | ||||
|  | @ -152,6 +152,24 @@ ABSL_NAMESPACE_BEGIN | |||
| //   // dangling references.
 | ||||
| //   foo->DoInFuture(absl::bind_front(Print, std::ref(hi), "Guest"));  // BAD!
 | ||||
| //   auto f = absl::bind_front(Print, std::ref(hi), "Guest"); // BAD!
 | ||||
| //
 | ||||
| // Example: Storing reference-like types.
 | ||||
| //
 | ||||
| //   void Print(absl::string_view a, const std::string& b) {
 | ||||
| //     std::cerr << a << b;
 | ||||
| //   }
 | ||||
| //
 | ||||
| //   std::string hi = "Hello, ";
 | ||||
| //   // Copies "hi".
 | ||||
| //   absl::bind_front(Print, hi)("Chuk");
 | ||||
| //
 | ||||
| //   // Compile error: std::reference_wrapper<const string> is not implicitly
 | ||||
| //   // convertible to string_view.
 | ||||
| //   // absl::bind_front(Print, std::cref(hi))("Chuk");
 | ||||
| //
 | ||||
| //   // Doesn't copy "hi".
 | ||||
| //   absl::bind_front(Print, absl::string_view(hi))("Chuk");
 | ||||
| //
 | ||||
| template <class F, class... BoundArgs> | ||||
| constexpr functional_internal::bind_front_t<F, BoundArgs...> bind_front( | ||||
|     F&& func, BoundArgs&&... args) { | ||||
|  |  | |||
|  | @ -27,9 +27,6 @@ namespace { | |||
| 
 | ||||
| constexpr int kLength = 50; | ||||
| using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>; | ||||
| using ThrowerStorage = | ||||
|     absl::aligned_storage_t<sizeof(Thrower), alignof(Thrower)>; | ||||
| using ThrowerList = std::array<ThrowerStorage, kLength>; | ||||
| 
 | ||||
| TEST(MakeUnique, CheckForLeaks) { | ||||
|   constexpr int kValue = 321; | ||||
|  |  | |||
|  | @ -63,16 +63,16 @@ namespace { | |||
| // Type used with std::allocator for allocating and deallocating
 | ||||
| // `CordRepExternal`. std::allocator is used because it opaquely handles the
 | ||||
| // different new / delete overloads available on a given platform.
 | ||||
| using ExternalAllocType = | ||||
|     absl::aligned_storage_t<absl::cord_internal::ExternalRepAlignment(), | ||||
|                             absl::cord_internal::ExternalRepAlignment()>; | ||||
| struct alignas(absl::cord_internal::ExternalRepAlignment()) ExternalAllocType { | ||||
|   unsigned char value[absl::cord_internal::ExternalRepAlignment()]; | ||||
| }; | ||||
| 
 | ||||
| // Returns the number of objects to pass in to std::allocator<ExternalAllocType>
 | ||||
| // allocate() and deallocate() to create enough room for `CordRepExternal` with
 | ||||
| // `releaser_size` bytes on the end.
 | ||||
| constexpr size_t GetExternalAllocNumObjects(size_t releaser_size) { | ||||
|   // Be sure to round up since `releaser_size` could be smaller than
 | ||||
|   // sizeof(ExternalAllocType)`.
 | ||||
|   // `sizeof(ExternalAllocType)`.
 | ||||
|   return (sizeof(CordRepExternal) + releaser_size + sizeof(ExternalAllocType) - | ||||
|           1) / | ||||
|          sizeof(ExternalAllocType); | ||||
|  |  | |||
|  | @ -252,8 +252,8 @@ class SynchronizationStorage { | |||
| 
 | ||||
|   absl::once_flag once_; | ||||
| 
 | ||||
|   // An aligned space for T.
 | ||||
|   typename std::aligned_storage<sizeof(T), alignof(T)>::type space_; | ||||
|   // An aligned space for the T.
 | ||||
|   alignas(T) unsigned char space_[sizeof(T)]; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace synchronization_internal
 | ||||
|  |  | |||
|  | @ -368,31 +368,29 @@ class Waiter::WinHelper { | |||
|     return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_); | ||||
|   } | ||||
| 
 | ||||
|   static_assert(sizeof(SRWLOCK) == sizeof(Waiter::SRWLockStorage), | ||||
|                 "SRWLockStorage does not have the same size as SRWLOCK"); | ||||
|   static_assert( | ||||
|       alignof(SRWLOCK) == alignof(Waiter::SRWLockStorage), | ||||
|       "SRWLockStorage does not have the same alignment as SRWLOCK"); | ||||
|   static_assert(sizeof(SRWLOCK) == sizeof(void *), | ||||
|                 "`mu_storage_` does not have the same size as SRWLOCK"); | ||||
|   static_assert(alignof(SRWLOCK) == alignof(void *), | ||||
|                 "`mu_storage_` does not have the same alignment as SRWLOCK"); | ||||
| 
 | ||||
|   static_assert(sizeof(CONDITION_VARIABLE) == | ||||
|                     sizeof(Waiter::ConditionVariableStorage), | ||||
|                 "ABSL_CONDITION_VARIABLE_STORAGE does not have the same size " | ||||
|                 "as CONDITION_VARIABLE"); | ||||
|   static_assert(alignof(CONDITION_VARIABLE) == | ||||
|                     alignof(Waiter::ConditionVariableStorage), | ||||
|                 "ConditionVariableStorage does not have the same " | ||||
|                 "alignment as CONDITION_VARIABLE"); | ||||
|   static_assert(sizeof(CONDITION_VARIABLE) == sizeof(void *), | ||||
|                 "`ABSL_CONDITION_VARIABLE_STORAGE` does not have the same size " | ||||
|                 "as `CONDITION_VARIABLE`"); | ||||
|   static_assert( | ||||
|       alignof(CONDITION_VARIABLE) == alignof(void *), | ||||
|       "`cv_storage_` does not have the same alignment as `CONDITION_VARIABLE`"); | ||||
| 
 | ||||
|   // The SRWLOCK and CONDITION_VARIABLE types must be trivially constructible
 | ||||
|   // and destructible because we never call their constructors or destructors.
 | ||||
|   static_assert(std::is_trivially_constructible<SRWLOCK>::value, | ||||
|                 "The SRWLOCK type must be trivially constructible"); | ||||
|   static_assert(std::is_trivially_constructible<CONDITION_VARIABLE>::value, | ||||
|                 "The CONDITION_VARIABLE type must be trivially constructible"); | ||||
|                 "The `SRWLOCK` type must be trivially constructible"); | ||||
|   static_assert( | ||||
|       std::is_trivially_constructible<CONDITION_VARIABLE>::value, | ||||
|       "The `CONDITION_VARIABLE` type must be trivially constructible"); | ||||
|   static_assert(std::is_trivially_destructible<SRWLOCK>::value, | ||||
|                 "The SRWLOCK type must be trivially destructible"); | ||||
|                 "The `SRWLOCK` type must be trivially destructible"); | ||||
|   static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value, | ||||
|                 "The CONDITION_VARIABLE type must be trivially destructible"); | ||||
|                 "The `CONDITION_VARIABLE` type must be trivially destructible"); | ||||
| }; | ||||
| 
 | ||||
| class LockHolder { | ||||
|  |  | |||
|  | @ -133,13 +133,6 @@ class Waiter { | |||
|   std::atomic<int> wakeups_; | ||||
| 
 | ||||
| #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 | ||||
|   // We can't include Windows.h in our headers, so we use aligned storage
 | ||||
|   // buffers to define the storage of SRWLOCK and CONDITION_VARIABLE.
 | ||||
|   using SRWLockStorage = | ||||
|       typename std::aligned_storage<sizeof(void*), alignof(void*)>::type; | ||||
|   using ConditionVariableStorage = | ||||
|       typename std::aligned_storage<sizeof(void*), alignof(void*)>::type; | ||||
| 
 | ||||
|   // WinHelper - Used to define utilities for accessing the lock and
 | ||||
|   // condition variable storage once the types are complete.
 | ||||
|   class WinHelper; | ||||
|  | @ -147,8 +140,10 @@ class Waiter { | |||
|   // REQUIRES: WinHelper::GetLock(this) must be held.
 | ||||
|   void InternalCondVarPoke(); | ||||
| 
 | ||||
|   SRWLockStorage mu_storage_; | ||||
|   ConditionVariableStorage cv_storage_; | ||||
|   // We can't include Windows.h in our headers, so we use aligned charachter
 | ||||
|   // buffers to define the storage of SRWLOCK and CONDITION_VARIABLE.
 | ||||
|   alignas(void*) unsigned char mu_storage_[sizeof(void*)]; | ||||
|   alignas(void*) unsigned char cv_storage_[sizeof(void*)]; | ||||
|   int waiter_count_; | ||||
|   int wakeup_count_; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue