Coverage Report

Created: 2025-12-31 06:30

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