Coverage Report

Created: 2026-07-16 06:43

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