1 // Copyright 2022 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Implementation details for `absl::AnyInvocable` 16 17 #ifndef ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_ 18 #define ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_ 19 20 //////////////////////////////////////////////////////////////////////////////// 21 // // 22 // This implementation chooses between local storage and remote storage for // 23 // the contained target object based on the target object's size, alignment // 24 // requirements, and whether or not it has a nothrow move constructor. // 25 // Additional optimizations are performed when the object is a trivially // 26 // copyable type [basic.types]. // 27 // // 28 // There are three datamembers per `AnyInvocable` instance // 29 // // 30 // 1) A union containing either // 31 // - A pointer to the target object referred to via a void*, or // 32 // - the target object, emplaced into a raw char buffer // 33 // // 34 // 2) A function pointer to a "manager" function operation that takes a // 35 // discriminator and logically branches to either perform a move operation // 36 // or destroy operation based on that discriminator. // 37 // // 38 // 3) A function pointer to an "invoker" function operation that invokes the // 39 // target object, directly returning the result. // 40 // // 41 // When in the logically empty state, the manager function is an empty // 42 // function and the invoker function is one that would be undefined behavior // 43 // to call. // 44 // // 45 // An additional optimization is performed when converting from one // 46 // AnyInvocable to another where only the noexcept specification and/or the // 47 // cv/ref qualifiers of the function type differ. In these cases, the // 48 // conversion works by "moving the guts", similar to if they were the same // 49 // exact type, as opposed to having to perform an additional layer of // 50 // wrapping through remote storage. // 51 // // 52 //////////////////////////////////////////////////////////////////////////////// 53 54 // IWYU pragma: private, include "absl/functional/any_invocable.h" 55 56 #include <cassert> 57 #include <cstddef> 58 #include <cstring> 59 #include <exception> 60 #include <functional> 61 #include <memory> 62 #include <new> 63 #include <type_traits> 64 #include <utility> 65 66 #include "absl/base/attributes.h" 67 #include "absl/base/config.h" 68 #include "absl/base/macros.h" 69 #include "absl/base/optimization.h" 70 #include "absl/meta/type_traits.h" 71 #include "absl/utility/utility.h" 72 73 namespace absl { 74 ABSL_NAMESPACE_BEGIN 75 76 // Defined in functional/any_invocable.h 77 template <class Sig> 78 class AnyInvocable; 79 80 namespace internal_any_invocable { 81 82 // Constants relating to the small-object-storage for AnyInvocable 83 enum StorageProperty : std::size_t { 84 kAlignment = alignof(std::max_align_t), // The alignment of the storage 85 kStorageSize = sizeof(void*) * 2 // The size of the storage 86 }; 87 88 //////////////////////////////////////////////////////////////////////////////// 89 // 90 // A metafunction for checking if a type is an AnyInvocable instantiation. 91 // This is used during conversion operations. 92 template <class T> 93 struct IsAnyInvocable : std::false_type {}; 94 95 template <class Sig> 96 struct IsAnyInvocable<AnyInvocable<Sig>> : std::true_type {}; 97 // 98 //////////////////////////////////////////////////////////////////////////////// 99 100 // A metafunction that tells us whether or not a target function type should be 101 // stored locally in the small object optimization storage 102 template <class T> 103 constexpr bool IsStoredLocally() { 104 if constexpr (sizeof(T) <= kStorageSize && alignof(T) <= kAlignment && 105 kAlignment % alignof(T) == 0) { 106 return std::is_nothrow_move_constructible<T>::value; 107 } 108 return false; 109 } 110 111 // An implementation of std::remove_cvref_t of C++20. 112 template <class T> 113 using RemoveCVRef = 114 typename std::remove_cv<typename std::remove_reference<T>::type>::type; 115 116 // An implementation of std::invoke_r of C++23. 117 template <class ReturnType, class F, class... P> 118 ReturnType InvokeR(F&& f, P&&... args) { 119 if constexpr (std::is_void_v<ReturnType>) { 120 std::invoke(std::forward<F>(f), std::forward<P>(args)...); 121 } else { 122 return std::invoke(std::forward<F>(f), std::forward<P>(args)...); 123 } 124 } 125 126 // 127 //////////////////////////////////////////////////////////////////////////////// 128 129 //////////////////////////////////////////////////////////////////////////////// 130 /// 131 // A metafunction that takes a "T" corresponding to a parameter type of the 132 // user's specified function type, and yields the parameter type to use for the 133 // type-erased invoker. In order to prevent observable moves, this must be 134 // either a reference or, if the type is trivial, the original parameter type 135 // itself. Since the parameter type may be incomplete at the point that this 136 // metafunction is used, we can only do this optimization for scalar types 137 // rather than for any trivial type. 138 template <typename T> 139 T ForwardImpl(std::true_type); 140 141 template <typename T> 142 T&& ForwardImpl(std::false_type); 143 144 // NOTE: We deliberately use an intermediate struct instead of a direct alias, 145 // as a workaround for b/206991861 on MSVC versions < 1924. 146 template <class T> 147 struct ForwardedParameter { 148 using type = decltype(( 149 ForwardImpl<T>)(std::integral_constant<bool, 150 std::is_scalar<T>::value>())); 151 }; 152 153 template <class T> 154 using ForwardedParameterType = typename ForwardedParameter<T>::type; 155 // 156 //////////////////////////////////////////////////////////////////////////////// 157 158 // A discriminator when calling the "manager" function that describes operation 159 // type-erased operation should be invoked. 160 // 161 // "relocate_from_to" specifies that the manager should perform a move. 162 // 163 // "dispose" specifies that the manager should perform a destroy. 164 enum class FunctionToCall : bool { relocate_from_to, dispose }; 165 166 // The portion of `AnyInvocable` state that contains either a pointer to the 167 // target object or the object itself in local storage 168 union TypeErasedState { 169 struct { 170 // A pointer to the type-erased object when remotely stored 171 void* target; 172 // The size of the object for `RemoteManagerTrivial` 173 std::size_t size; 174 } remote; 175 176 // Local-storage for the type-erased object when small and trivial enough 177 alignas(kAlignment) char storage[kStorageSize]; 178 }; 179 180 // A typed accessor for the object in `TypeErasedState` storage 181 template <class T> 182 T& ObjectInLocalStorage(TypeErasedState* const state) { 183 // We launder here because the storage may be reused with the same type. 184 return *std::launder(reinterpret_cast<T*>(&state->storage)); 185 } 186 187 // The type for functions issuing lifetime-related operations: move and dispose 188 // A pointer to such a function is contained in each `AnyInvocable` instance. 189 // NOTE: When specifying `FunctionToCall::`dispose, the same state must be 190 // passed as both "from" and "to". 191 using ManagerType = void(FunctionToCall /*operation*/, 192 TypeErasedState* /*from*/, 193 TypeErasedState* /*to*/) noexcept(true); 194 195 // The type for functions issuing the actual invocation of the object 196 // A pointer to such a function is contained in each AnyInvocable instance. 197 template <bool SigIsNoexcept, class ReturnType, class... P> 198 using InvokerType = ReturnType( 199 TypeErasedState*, ForwardedParameterType<P>...) noexcept(SigIsNoexcept); 200 201 // The manager that is used when AnyInvocable is empty 202 inline void EmptyManager(FunctionToCall /*operation*/, 203 TypeErasedState* /*from*/, 204 TypeErasedState* /*to*/) noexcept {} 205 206 // The manager that is used when a target function is in local storage and is 207 // a trivially copyable type. 208 inline void LocalManagerTrivial(FunctionToCall /*operation*/, 209 TypeErasedState* const from, 210 TypeErasedState* const to) noexcept { 211 // This single statement without branching handles both possible operations. 212 // 213 // For FunctionToCall::dispose, "from" and "to" point to the same state, and 214 // so this assignment logically would do nothing. 215 // 216 // Note: Correctness here relies on http://wg21.link/p0593, which has only 217 // become standard in C++20, though implementations do not break it in 218 // practice for earlier versions of C++. 219 // 220 // The correct way to do this without that paper is to first placement-new a 221 // default-constructed T in "to->storage" prior to the memmove, but doing so 222 // requires a different function to be created for each T that is stored 223 // locally, which can cause unnecessary bloat and be less cache friendly. 224 *to = *from; 225 226 // Note: Because the type is trivially copyable, the destructor does not need 227 // to be called ("trivially copyable" requires a trivial destructor). 228 } 229 230 // The manager that is used when a target function is in local storage and is 231 // not a trivially copyable type. 232 template <class T> 233 void LocalManagerNontrivial(FunctionToCall operation, 234 TypeErasedState* const from, 235 TypeErasedState* const to) noexcept { 236 static_assert(IsStoredLocally<T>(), 237 "Local storage must only be used for supported types."); 238 static_assert(!std::is_trivially_copyable<T>::value, 239 "Locally stored types must be trivially copyable."); 240 241 T& from_object = (ObjectInLocalStorage<T>)(from); 242 243 switch (operation) { 244 case FunctionToCall::relocate_from_to: 245 // NOTE: Requires that the left-hand operand is already empty. 246 ::new (static_cast<void*>(&to->storage)) T(std::move(from_object)); 247 ABSL_FALLTHROUGH_INTENDED; 248 case FunctionToCall::dispose: 249 from_object.~T(); // Must not throw. // NOLINT 250 return; 251 } 252 ABSL_UNREACHABLE(); 253 } 254 255 // The invoker that is used when a target function is in local storage 256 // Note: QualTRef here is the target function type along with cv and reference 257 // qualifiers that must be used when calling the function. 258 template <bool SigIsNoexcept, class ReturnType, class QualTRef, class... P> 259 ReturnType LocalInvoker( 260 TypeErasedState* const state, 261 ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) { 262 using RawT = RemoveCVRef<QualTRef>; 263 static_assert( 264 IsStoredLocally<RawT>(), 265 "Target object must be in local storage in order to be invoked from it."); 266 267 auto& f = (ObjectInLocalStorage<RawT>)(state); 268 return (InvokeR<ReturnType>)(static_cast<QualTRef>(f), 269 static_cast<ForwardedParameterType<P>>(args)...); 270 } 271 272 // The manager that is used when a target function is in remote storage and it 273 // has a trivial destructor 274 inline void RemoteManagerTrivial(FunctionToCall operation, 275 TypeErasedState* const from, 276 TypeErasedState* const to) noexcept { 277 switch (operation) { 278 case FunctionToCall::relocate_from_to: 279 // NOTE: Requires that the left-hand operand is already empty. 280 to->remote = from->remote; 281 return; 282 case FunctionToCall::dispose: 283 #if defined(__cpp_sized_deallocation) 284 ::operator delete(from->remote.target, from->remote.size); 285 #else // __cpp_sized_deallocation 286 ::operator delete(from->remote.target); 287 #endif // __cpp_sized_deallocation 288 return; 289 } 290 ABSL_UNREACHABLE(); 291 } 292 293 // The manager that is used when a target function is in remote storage and the 294 // destructor of the type is not trivial 295 template <class T> 296 void RemoteManagerNontrivial(FunctionToCall operation, 297 TypeErasedState* const from, 298 TypeErasedState* const to) noexcept { 299 static_assert(!IsStoredLocally<T>(), 300 "Remote storage must only be used for types that do not " 301 "qualify for local storage."); 302 303 switch (operation) { 304 case FunctionToCall::relocate_from_to: 305 // NOTE: Requires that the left-hand operand is already empty. 306 to->remote.target = from->remote.target; 307 return; 308 case FunctionToCall::dispose: 309 ::delete static_cast<T*>(from->remote.target); // Must not throw. 310 return; 311 } 312 ABSL_UNREACHABLE(); 313 } 314 315 // The invoker that is used when a target function is in remote storage 316 template <bool SigIsNoexcept, class ReturnType, class QualTRef, class... P> 317 ReturnType RemoteInvoker( 318 TypeErasedState* const state, 319 ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) { 320 using RawT = RemoveCVRef<QualTRef>; 321 static_assert(!IsStoredLocally<RawT>(), 322 "Target object must be in remote storage in order to be " 323 "invoked from it."); 324 325 auto& f = *static_cast<RawT*>(state->remote.target); 326 return (InvokeR<ReturnType>)(static_cast<QualTRef>(f), 327 static_cast<ForwardedParameterType<P>>(args)...); 328 } 329 330 //////////////////////////////////////////////////////////////////////////////// 331 // 332 // A metafunction that checks if a type T is an instantiation of 333 // absl::in_place_type_t (needed for constructor constraints of AnyInvocable). 334 template <class T> 335 struct IsInPlaceType : std::false_type {}; 336 337 template <class T> 338 struct IsInPlaceType<absl::in_place_type_t<T>> : std::true_type {}; 339 // 340 //////////////////////////////////////////////////////////////////////////////// 341 342 // A constructor name-tag used with CoreImpl (below) to request the 343 // conversion-constructor. QualDecayedTRef is the decayed-type of the object to 344 // wrap, along with the cv and reference qualifiers that must be applied when 345 // performing an invocation of the wrapped object. 346 template <class QualDecayedTRef> 347 struct TypedConversionConstruct {}; 348 349 // A helper base class for all core operations of AnyInvocable. Most notably, 350 // this class creates the function call operator and constraint-checkers so that 351 // the top-level class does not have to be a series of partial specializations. 352 // 353 // Note: This definition exists (as opposed to being a declaration) so that if 354 // the user of the top-level template accidentally passes a template argument 355 // that is not a function type, they will get a static_assert in AnyInvocable's 356 // class body rather than an error stating that Impl is not defined. 357 template <class Sig> 358 class Impl {}; // Note: This is partially-specialized later. 359 360 // A std::unique_ptr deleter that deletes memory allocated via ::operator new. 361 #if defined(__cpp_sized_deallocation) 362 class TrivialDeleter { 363 public: 364 explicit TrivialDeleter(std::size_t size) : size_(size) {} 365 366 void operator()(void* target) const { 367 ::operator delete(target, size_); 368 } 369 370 private: 371 std::size_t size_; 372 }; 373 #else // __cpp_sized_deallocation 374 class TrivialDeleter { 375 public: 376 explicit TrivialDeleter(std::size_t) {} 377 378 void operator()(void* target) const { ::operator delete(target); } 379 }; 380 #endif // __cpp_sized_deallocation 381 382 template <bool SigIsNoexcept, class ReturnType, class... P> 383 class CoreImpl; 384 385 constexpr bool IsCompatibleConversion(void*, void*) { return false; } 386 template <bool NoExceptSrc, bool NoExceptDest, class... T> 387 constexpr bool IsCompatibleConversion(CoreImpl<NoExceptSrc, T...>*, 388 CoreImpl<NoExceptDest, T...>*) { 389 return !NoExceptDest || NoExceptSrc; 390 } 391 392 // A helper base class for all core operations of AnyInvocable that do not 393 // depend on the cv/ref qualifiers of the function type. 394 template <bool SigIsNoexcept, class ReturnType, class... P> 395 class CoreImpl { 396 public: 397 using result_type = ReturnType; 398 399 CoreImpl() noexcept : manager_(EmptyManager), invoker_(nullptr) {} 400 401 // Note: QualDecayedTRef here includes the cv-ref qualifiers associated with 402 // the invocation of the Invocable. The unqualified type is the target object 403 // type to be stored. 404 template <class QualDecayedTRef, class F> 405 explicit CoreImpl(TypedConversionConstruct<QualDecayedTRef>, F&& f) { 406 using DecayedT = RemoveCVRef<QualDecayedTRef>; 407 408 if constexpr (std::is_pointer<DecayedT>::value || 409 std::is_member_pointer<DecayedT>::value) { 410 // This condition handles types that decay into pointers. This includes 411 // function references, which cannot be null. GCC warns against comparing 412 // their decayed form with nullptr (https://godbolt.org/z/9r9TMTcPK). 413 // We could work around this warning with constexpr programming, using 414 // std::is_function_v<std::remove_reference_t<F>>, but we choose to ignore 415 // it instead of writing more code. 416 #if !defined(__clang__) && defined(__GNUC__) 417 #pragma GCC diagnostic push 418 #pragma GCC diagnostic ignored "-Wpragmas" 419 #pragma GCC diagnostic ignored "-Waddress" 420 #pragma GCC diagnostic ignored "-Wnonnull-compare" 421 #endif 422 if (static_cast<DecayedT>(f) == nullptr) { 423 #if !defined(__clang__) && defined(__GNUC__) 424 #pragma GCC diagnostic pop 425 #endif 426 manager_ = EmptyManager; 427 invoker_ = nullptr; 428 } else { 429 InitializeStorage<QualDecayedTRef>(std::forward<F>(f)); 430 } 431 } else if constexpr (IsCompatibleAnyInvocable<DecayedT>::value) { 432 // In this case we can "steal the guts" of the other AnyInvocable. 433 f.manager_(FunctionToCall::relocate_from_to, &f.state_, &state_); 434 manager_ = f.manager_; 435 invoker_ = f.invoker_; 436 437 f.manager_ = EmptyManager; 438 f.invoker_ = nullptr; 439 } else if constexpr (IsAnyInvocable<DecayedT>::value) { 440 if (f.HasValue()) { 441 InitializeStorage<QualDecayedTRef>(std::forward<F>(f)); 442 } else { 443 manager_ = EmptyManager; 444 invoker_ = nullptr; 445 } 446 } else { 447 InitializeStorage<QualDecayedTRef>(std::forward<F>(f)); 448 } 449 } 450 451 // Note: QualTRef here includes the cv-ref qualifiers associated with the 452 // invocation of the Invocable. The unqualified type is the target object 453 // type to be stored. 454 template <class QualTRef, class... Args> 455 explicit CoreImpl(absl::in_place_type_t<QualTRef>, Args&&... args) { 456 InitializeStorage<QualTRef>(std::forward<Args>(args)...); 457 } 458 459 CoreImpl(CoreImpl&& other) noexcept { 460 other.manager_(FunctionToCall::relocate_from_to, &other.state_, &state_); 461 manager_ = other.manager_; 462 invoker_ = other.invoker_; 463 other.manager_ = EmptyManager; 464 other.invoker_ = nullptr; 465 } 466 467 CoreImpl& operator=(CoreImpl&& other) noexcept { 468 // Put the left-hand operand in an empty state. 469 // 470 // Note: A full reset that leaves us with an object that has its invariants 471 // intact is necessary in order to handle self-move. This is required by 472 // types that are used with certain operations of the standard library, such 473 // as the default definition of std::swap when both operands target the same 474 // object. 475 Clear(); 476 477 // Perform the actual move/destroy operation on the target function. 478 other.manager_(FunctionToCall::relocate_from_to, &other.state_, &state_); 479 manager_ = other.manager_; 480 invoker_ = other.invoker_; 481 other.manager_ = EmptyManager; 482 other.invoker_ = nullptr; 483 484 return *this; 485 } 486 487 ~CoreImpl() { manager_(FunctionToCall::dispose, &state_, &state_); } 488 489 // Check whether or not the AnyInvocable is in the empty state. 490 bool HasValue() const { return invoker_ != nullptr; } 491 492 // Effects: Puts the object into its empty state. 493 void Clear() { 494 manager_(FunctionToCall::dispose, &state_, &state_); 495 manager_ = EmptyManager; 496 invoker_ = nullptr; 497 } 498 499 // Use local (inline) storage for applicable target object types. 500 template <class QualTRef, class... Args> 501 void InitializeStorage(Args&&... args) { 502 using RawT = RemoveCVRef<QualTRef>; 503 if constexpr (IsStoredLocally<RawT>()) { 504 ::new (static_cast<void*>(&state_.storage)) 505 RawT(std::forward<Args>(args)...); 506 invoker_ = LocalInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>; 507 // We can simplify our manager if we know the type is trivially copyable. 508 if constexpr (std::is_trivially_copyable_v<RawT>) { 509 manager_ = LocalManagerTrivial; 510 } else { 511 manager_ = LocalManagerNontrivial<RawT>; 512 } 513 } else { 514 InitializeRemoteManager<RawT>(std::forward<Args>(args)...); 515 // This is set after everything else in case an exception is thrown in an 516 // earlier step of the initialization. 517 invoker_ = RemoteInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>; 518 } 519 } 520 521 template <class T, class... Args> 522 void InitializeRemoteManager(Args&&... args) { 523 if constexpr (std::is_trivially_destructible_v<T> && 524 alignof(T) <= ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT) { 525 // unique_ptr is used for exception-safety in case construction throws. 526 std::unique_ptr<void, TrivialDeleter> uninitialized_target( 527 ::operator new(sizeof(T)), TrivialDeleter(sizeof(T))); 528 ::new (uninitialized_target.get()) T(std::forward<Args>(args)...); 529 state_.remote.target = uninitialized_target.release(); 530 state_.remote.size = sizeof(T); 531 manager_ = RemoteManagerTrivial; 532 } else { 533 state_.remote.target = ::new T(std::forward<Args>(args)...); 534 manager_ = RemoteManagerNontrivial<T>; 535 } 536 } 537 538 ////////////////////////////////////////////////////////////////////////////// 539 // 540 // Type trait to determine if the template argument is an AnyInvocable whose 541 // function type is compatible enough with ours such that we can 542 // "move the guts" out of it when moving, rather than having to place a new 543 // object into remote storage. 544 545 template <typename Other> 546 struct IsCompatibleAnyInvocable { 547 static constexpr bool value = false; 548 }; 549 550 template <typename Sig> 551 struct IsCompatibleAnyInvocable<AnyInvocable<Sig>> { 552 static constexpr bool value = 553 (IsCompatibleConversion)(static_cast< 554 typename AnyInvocable<Sig>::CoreImpl*>( 555 nullptr), 556 static_cast<CoreImpl*>(nullptr)); 557 }; 558 559 // 560 ////////////////////////////////////////////////////////////////////////////// 561 562 TypeErasedState state_; 563 ManagerType* manager_; 564 InvokerType<SigIsNoexcept, ReturnType, P...>* invoker_; 565 }; 566 567 // A constructor name-tag used with Impl to request the 568 // conversion-constructor 569 struct ConversionConstruct {}; 570 571 //////////////////////////////////////////////////////////////////////////////// 572 // 573 // A metafunction that is normally an identity metafunction except that when 574 // given a std::reference_wrapper<T>, it yields T&. This is necessary because 575 // currently std::reference_wrapper's operator() is not conditionally noexcept, 576 // so when checking if such an Invocable is nothrow-invocable, we must pull out 577 // the underlying type. 578 template <class T> 579 struct UnwrapStdReferenceWrapperImpl { 580 using type = T; 581 }; 582 583 template <class T> 584 struct UnwrapStdReferenceWrapperImpl<std::reference_wrapper<T>> { 585 using type = T&; 586 }; 587 588 template <class T> 589 using UnwrapStdReferenceWrapper = 590 typename UnwrapStdReferenceWrapperImpl<T>::type; 591 // 592 //////////////////////////////////////////////////////////////////////////////// 593 594 // An alias that always yields std::true_type (used with constraints) where 595 // substitution failures happen when forming the template arguments. 596 template <class... T> 597 using TrueAlias = 598 std::integral_constant<bool, sizeof(absl::void_t<T...>*) != 0>; 599 600 /*SFINAE constraints for the conversion-constructor.*/ 601 template <class Sig, class F, 602 class = absl::enable_if_t< 603 !std::is_same<RemoveCVRef<F>, AnyInvocable<Sig>>::value>> 604 using CanConvert = TrueAlias< 605 absl::enable_if_t<!IsInPlaceType<RemoveCVRef<F>>::value>, 606 absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>, 607 absl::enable_if_t< 608 Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>, 609 absl::enable_if_t<std::is_constructible<absl::decay_t<F>, F>::value>>; 610 611 /*SFINAE constraints for the std::in_place constructors.*/ 612 template <class Sig, class F, class... Args> 613 using CanEmplace = TrueAlias< 614 absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>, 615 absl::enable_if_t< 616 Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>, 617 absl::enable_if_t<std::is_constructible<absl::decay_t<F>, Args...>::value>>; 618 619 /*SFINAE constraints for the conversion-assign operator.*/ 620 template <class Sig, class F, 621 class = absl::enable_if_t< 622 !std::is_same<RemoveCVRef<F>, AnyInvocable<Sig>>::value>> 623 using CanAssign = TrueAlias< 624 absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>, 625 absl::enable_if_t< 626 Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>, 627 absl::enable_if_t<std::is_constructible<absl::decay_t<F>, F>::value>>; 628 629 /*SFINAE constraints for the reference-wrapper conversion-assign operator.*/ 630 template <class Sig, class F> 631 using CanAssignReferenceWrapper = TrueAlias< 632 absl::enable_if_t< 633 Impl<Sig>::template CallIsValid<std::reference_wrapper<F>>::value>, 634 absl::enable_if_t<Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept< 635 std::reference_wrapper<F>>::value>>; 636 637 // The constraint for checking whether or not a call meets the noexcept 638 // callability requirements. We use a preprocessor macro because specifying it 639 // this way as opposed to a disjunction/branch can improve the user-side error 640 // messages and avoids an instantiation of std::is_nothrow_invocable_r in the 641 // cases where the user did not specify a noexcept function type. 642 // 643 // The disjunction below is because we can't rely on std::is_nothrow_invocable_r 644 // to give the right result when ReturnType is non-moveable in toolchains that 645 // don't treat non-moveable result types correctly. For example this was the 646 // case in libc++ before commit c3a24882 (2022-05). 647 #define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_true(inv_quals) \ 648 absl::enable_if_t<absl::disjunction< \ 649 std::is_nothrow_invocable_r< \ 650 ReturnType, UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, \ 651 P...>, \ 652 std::conjunction< \ 653 std::is_nothrow_invocable< \ 654 UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, P...>, \ 655 std::is_same< \ 656 ReturnType, \ 657 std::invoke_result_t< \ 658 UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, \ 659 P...>>>>::value> 660 661 #define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_false(inv_quals) 662 // 663 //////////////////////////////////////////////////////////////////////////////// 664 665 // A macro to generate partial specializations of Impl with the different 666 // combinations of supported cv/reference qualifiers and noexcept specifier. 667 // 668 // Here, `cv` are the cv-qualifiers if any, `ref` is the ref-qualifier if any, 669 // inv_quals is the reference type to be used when invoking the target, and 670 // noex is "true" if the function type is noexcept, or false if it is not. 671 // 672 // The CallIsValid condition is more complicated than simply using 673 // std::is_invocable_r because we can't rely on it to give the right result 674 // when ReturnType is non-moveable in toolchains that don't treat non-moveable 675 // result types correctly. For example this was the case in libc++ before commit 676 // c3a24882 (2022-05). 677 #define ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, noex) \ 678 template <class ReturnType, class... P> \ 679 class Impl<ReturnType(P...) cv ref noexcept(noex)> \ 680 : public CoreImpl<noex, ReturnType, P...> { \ 681 public: \ 682 /*The base class, which contains the datamembers and core operations*/ \ 683 using Core = CoreImpl<noex, ReturnType, P...>; \ 684 \ 685 /*SFINAE constraint to check if F is invocable with the proper signature*/ \ 686 template <class F> \ 687 using CallIsValid = TrueAlias<absl::enable_if_t<absl::disjunction< \ 688 std::is_invocable_r<ReturnType, absl::decay_t<F> inv_quals, P...>, \ 689 std::is_same< \ 690 ReturnType, \ 691 std::invoke_result_t<absl::decay_t<F> inv_quals, P...>>>::value>>; \ 692 \ 693 /*SFINAE constraint to check if F is nothrow-invocable when necessary*/ \ 694 template <class F> \ 695 using CallIsNoexceptIfSigIsNoexcept = \ 696 TrueAlias<ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_##noex( \ 697 inv_quals)>; \ 698 \ 699 /*Put the AnyInvocable into an empty state.*/ \ 700 Impl() = default; \ 701 \ 702 /*The implementation of a conversion-constructor from "f*/ \ 703 /*This forwards to Core, attaching inv_quals so that the base class*/ \ 704 /*knows how to properly type-erase the invocation.*/ \ 705 template <class F> \ 706 explicit Impl(ConversionConstruct, F&& f) \ 707 : Core(TypedConversionConstruct< \ 708 typename std::decay<F>::type inv_quals>(), \ 709 std::forward<F>(f)) {} \ 710 \ 711 /*Forward along the in-place construction parameters.*/ \ 712 template <class T, class... Args> \ 713 explicit Impl(absl::in_place_type_t<T>, Args&&... args) \ 714 : Core(absl::in_place_type<absl::decay_t<T> inv_quals>, \ 715 std::forward<Args>(args)...) {} \ 716 \ 717 /*Raises a fatal error when the AnyInvocable is invoked after a move*/ \ 718 static ReturnType InvokedAfterMove( \ 719 TypeErasedState*, ForwardedParameterType<P>...) noexcept(noex) { \ 720 ABSL_HARDENING_ASSERT(false && "AnyInvocable use-after-move"); \ 721 std::terminate(); \ 722 } \ 723 \ 724 InvokerType<noex, ReturnType, P...>* ExtractInvoker() cv { \ 725 using QualifiedTestType = int cv ref; \ 726 auto* invoker = this->invoker_; \ 727 if (!std::is_const<QualifiedTestType>::value && \ 728 std::is_rvalue_reference<QualifiedTestType>::value) { \ 729 ABSL_ASSERT([this]() { \ 730 /* We checked that this isn't const above, so const_cast is safe */ \ 731 const_cast<Impl*>(this)->invoker_ = InvokedAfterMove; \ 732 return this->HasValue(); \ 733 }()); \ 734 } \ 735 return invoker; \ 736 } \ 737 \ 738 /*The actual invocation operation with the proper signature*/ \ 739 ReturnType operator()(P... args) cv ref noexcept(noex) { \ 740 assert(this->invoker_ != nullptr); \ 741 return this->ExtractInvoker()( \ 742 const_cast<TypeErasedState*>(&this->state_), \ 743 static_cast<ForwardedParameterType<P>>(args)...); \ 744 } \ 745 } 746 747 // A convenience macro that defines specializations for the noexcept(true) and 748 // noexcept(false) forms, given the other properties. 749 #define ABSL_INTERNAL_ANY_INVOCABLE_IMPL(cv, ref, inv_quals) \ 750 ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, false); \ 751 ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, true) 752 753 // Non-ref-qualified partial specializations 754 ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, , &); 755 ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, , const&); 756 757 // Lvalue-ref-qualified partial specializations 758 ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, &, &); 759 ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, &, const&); 760 761 // Rvalue-ref-qualified partial specializations 762 ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, &&, &&); 763 ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, &&, const&&); 764 765 // Undef the detail-only macros. 766 #undef ABSL_INTERNAL_ANY_INVOCABLE_IMPL 767 #undef ABSL_INTERNAL_ANY_INVOCABLE_IMPL_ 768 #undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_false 769 #undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_true 770 771 } // namespace internal_any_invocable 772 ABSL_NAMESPACE_END 773 } // namespace absl 774 775 #endif // ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_ 776