Coverage Report

Created: 2026-09-14 06:45

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