Coverage Report

Created: 2025-07-11 06:37

/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/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) unsigned 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
0
                         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
0
                                TypeErasedState* const to) noexcept {
211
0
  // This single statement without branching handles both possible operations.
212
0
  //
213
0
  // For FunctionToCall::dispose, "from" and "to" point to the same state, and
214
0
  // so this assignment logically would do nothing.
215
0
  //
216
0
  // Note: Correctness here relies on http://wg21.link/p0593, which has only
217
0
  // become standard in C++20, though implementations do not break it in
218
0
  // practice for earlier versions of C++.
219
0
  //
220
0
  // The correct way to do this without that paper is to first placement-new a
221
0
  // default-constructed T in "to->storage" prior to the memmove, but doing so
222
0
  // requires a different function to be created for each T that is stored
223
0
  // locally, which can cause unnecessary bloat and be less cache friendly.
224
0
  *to = *from;
225
0
226
0
  // Note: Because the type is trivially copyable, the destructor does not need
227
0
  // to be called ("trivially copyable" requires a trivial destructor).
228
0
}
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
0
                                 TypeErasedState* const to) noexcept {
277
0
  switch (operation) {
278
0
    case FunctionToCall::relocate_from_to:
279
0
      // NOTE: Requires that the left-hand operand is already empty.
280
0
      to->remote = from->remote;
281
0
      return;
282
0
    case FunctionToCall::dispose:
283
0
#if defined(__cpp_sized_deallocation)
284
0
      ::operator delete(from->remote.target, from->remote.size);
285
0
#else   // __cpp_sized_deallocation
286
0
      ::operator delete(from->remote.target);
287
0
#endif  // __cpp_sized_deallocation
288
0
      return;
289
0
  }
290
0
  ABSL_UNREACHABLE();
291
0
}
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
0
  explicit TrivialDeleter(std::size_t) {}
377
378
0
  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
0
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_