Coverage Report

Created: 2025-08-25 06:55

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