Coverage Report

Created: 2024-09-23 06:29

/src/abseil-cpp/absl/functional/internal/any_invocable.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2022 The Abseil Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
//
15
// Implementation details for `absl::AnyInvocable`
16
17
#ifndef ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_
18
#define ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_
19
20
////////////////////////////////////////////////////////////////////////////////
21
//                                                                            //
22
// This implementation chooses between local storage and remote storage for   //
23
// the contained target object based on the target object's size, alignment   //
24
// requirements, and whether or not it has a nothrow move constructor.        //
25
// Additional optimizations are performed when the object is a trivially      //
26
// copyable type [basic.types].                                               //
27
//                                                                            //
28
// There are three datamembers per `AnyInvocable` instance                    //
29
//                                                                            //
30
// 1) A union containing either                                               //
31
//        - A pointer to the target object referred to via a void*, or        //
32
//        - the target object, emplaced into a raw char buffer                //
33
//                                                                            //
34
// 2) A function pointer to a "manager" function operation that takes a       //
35
//    discriminator and logically branches to either perform a move operation //
36
//    or destroy operation based on that discriminator.                       //
37
//                                                                            //
38
// 3) A function pointer to an "invoker" function operation that invokes the  //
39
//    target object, directly returning the result.                           //
40
//                                                                            //
41
// When in the logically empty state, the manager function is an empty        //
42
// function and the invoker function is one that would be undefined behavior  //
43
// to call.                                                                   //
44
//                                                                            //
45
// An additional optimization is performed when converting from one           //
46
// AnyInvocable to another where only the noexcept specification and/or the   //
47
// cv/ref qualifiers of the function type differ. In these cases, the         //
48
// conversion works by "moving the guts", similar to if they were the same    //
49
// exact type, as opposed to having to perform an additional layer of         //
50
// wrapping through remote storage.                                           //
51
//                                                                            //
52
////////////////////////////////////////////////////////////////////////////////
53
54
// IWYU pragma: private, include "absl/functional/any_invocable.h"
55
56
#include <cassert>
57
#include <cstddef>
58
#include <cstring>
59
#include <exception>
60
#include <functional>
61
#include <memory>
62
#include <new>
63
#include <type_traits>
64
#include <utility>
65
66
#include "absl/base/attributes.h"
67
#include "absl/base/config.h"
68
#include "absl/base/internal/invoke.h"
69
#include "absl/base/macros.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
// Helper macro used to prevent spelling `noexcept` in language versions older
78
// than C++17, where it is not part of the type system, in order to avoid
79
// compilation failures and internal compiler errors.
80
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
81
#define ABSL_INTERNAL_NOEXCEPT_SPEC(noex) noexcept(noex)
82
#else
83
#define ABSL_INTERNAL_NOEXCEPT_SPEC(noex)
84
#endif
85
86
// Defined in functional/any_invocable.h
87
template <class Sig>
88
class AnyInvocable;
89
90
namespace internal_any_invocable {
91
92
// Constants relating to the small-object-storage for AnyInvocable
93
enum StorageProperty : std::size_t {
94
  kAlignment = alignof(std::max_align_t),  // The alignment of the storage
95
  kStorageSize = sizeof(void*) * 2         // The size of the storage
96
};
97
98
////////////////////////////////////////////////////////////////////////////////
99
//
100
// A metafunction for checking if a type is an AnyInvocable instantiation.
101
// This is used during conversion operations.
102
template <class T>
103
struct IsAnyInvocable : std::false_type {};
104
105
template <class Sig>
106
struct IsAnyInvocable<AnyInvocable<Sig>> : std::true_type {};
107
//
108
////////////////////////////////////////////////////////////////////////////////
109
110
// A type trait that tells us whether or not a target function type should be
111
// stored locally in the small object optimization storage
112
template <class T>
113
using IsStoredLocally = std::integral_constant<
114
    bool, sizeof(T) <= kStorageSize && alignof(T) <= kAlignment &&
115
              kAlignment % alignof(T) == 0 &&
116
              std::is_nothrow_move_constructible<T>::value>;
117
118
// An implementation of std::remove_cvref_t of C++20.
119
template <class T>
120
using RemoveCVRef =
121
    typename std::remove_cv<typename std::remove_reference<T>::type>::type;
122
123
////////////////////////////////////////////////////////////////////////////////
124
//
125
// An implementation of the C++ standard INVOKE<R> pseudo-macro, operation is
126
// equivalent to std::invoke except that it forces an implicit conversion to the
127
// specified return type. If "R" is void, the function is executed and the
128
// return value is simply ignored.
129
template <class ReturnType, class F, class... P,
130
          typename = absl::enable_if_t<std::is_void<ReturnType>::value>>
131
void InvokeR(F&& f, P&&... args) {
132
  absl::base_internal::invoke(std::forward<F>(f), std::forward<P>(args)...);
133
}
134
135
template <class ReturnType, class F, class... P,
136
          absl::enable_if_t<!std::is_void<ReturnType>::value, int> = 0>
137
ReturnType InvokeR(F&& f, P&&... args) {
138
  // GCC 12 has a false-positive -Wmaybe-uninitialized warning here.
139
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
140
#pragma GCC diagnostic push
141
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
142
#endif
143
  return absl::base_internal::invoke(std::forward<F>(f),
144
                                     std::forward<P>(args)...);
145
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
146
#pragma GCC diagnostic pop
147
#endif
148
}
149
150
//
151
////////////////////////////////////////////////////////////////////////////////
152
153
////////////////////////////////////////////////////////////////////////////////
154
///
155
// A metafunction that takes a "T" corresponding to a parameter type of the
156
// user's specified function type, and yields the parameter type to use for the
157
// type-erased invoker. In order to prevent observable moves, this must be
158
// either a reference or, if the type is trivial, the original parameter type
159
// itself. Since the parameter type may be incomplete at the point that this
160
// metafunction is used, we can only do this optimization for scalar types
161
// rather than for any trivial type.
162
template <typename T>
163
T ForwardImpl(std::true_type);
164
165
template <typename T>
166
T&& ForwardImpl(std::false_type);
167
168
// NOTE: We deliberately use an intermediate struct instead of a direct alias,
169
// as a workaround for b/206991861 on MSVC versions < 1924.
170
template <class T>
171
struct ForwardedParameter {
172
  using type = decltype((
173
      ForwardImpl<T>)(std::integral_constant<bool,
174
                                             std::is_scalar<T>::value>()));
175
};
176
177
template <class T>
178
using ForwardedParameterType = typename ForwardedParameter<T>::type;
179
//
180
////////////////////////////////////////////////////////////////////////////////
181
182
// A discriminator when calling the "manager" function that describes operation
183
// type-erased operation should be invoked.
184
//
185
// "relocate_from_to" specifies that the manager should perform a move.
186
//
187
// "dispose" specifies that the manager should perform a destroy.
188
enum class FunctionToCall : bool { relocate_from_to, dispose };
189
190
// The portion of `AnyInvocable` state that contains either a pointer to the
191
// target object or the object itself in local storage
192
union TypeErasedState {
193
  struct {
194
    // A pointer to the type-erased object when remotely stored
195
    void* target;
196
    // The size of the object for `RemoteManagerTrivial`
197
    std::size_t size;
198
  } remote;
199
200
  // Local-storage for the type-erased object when small and trivial enough
201
  alignas(kAlignment) char storage[kStorageSize];
202
};
203
204
// A typed accessor for the object in `TypeErasedState` storage
205
template <class T>
206
T& ObjectInLocalStorage(TypeErasedState* const state) {
207
  // We launder here because the storage may be reused with the same type.
208
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
209
  return *std::launder(reinterpret_cast<T*>(&state->storage));
210
#elif ABSL_HAVE_BUILTIN(__builtin_launder)
211
  return *__builtin_launder(reinterpret_cast<T*>(&state->storage));
212
#else
213
214
  // When `std::launder` or equivalent are not available, we rely on undefined
215
  // behavior, which works as intended on Abseil's officially supported
216
  // platforms as of Q2 2022.
217
#if !defined(__clang__) && defined(__GNUC__)
218
#pragma GCC diagnostic push
219
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
220
#endif
221
  return *reinterpret_cast<T*>(&state->storage);
222
#if !defined(__clang__) && defined(__GNUC__)
223
#pragma GCC diagnostic pop
224
#endif
225
226
#endif
227
}
228
229
// The type for functions issuing lifetime-related operations: move and dispose
230
// A pointer to such a function is contained in each `AnyInvocable` instance.
231
// NOTE: When specifying `FunctionToCall::`dispose, the same state must be
232
// passed as both "from" and "to".
233
using ManagerType = void(FunctionToCall /*operation*/,
234
                         TypeErasedState* /*from*/, TypeErasedState* /*to*/)
235
    ABSL_INTERNAL_NOEXCEPT_SPEC(true);
236
237
// The type for functions issuing the actual invocation of the object
238
// A pointer to such a function is contained in each AnyInvocable instance.
239
template <bool SigIsNoexcept, class ReturnType, class... P>
240
using InvokerType = ReturnType(TypeErasedState*, ForwardedParameterType<P>...)
241
    ABSL_INTERNAL_NOEXCEPT_SPEC(SigIsNoexcept);
242
243
// The manager that is used when AnyInvocable is empty
244
inline void EmptyManager(FunctionToCall /*operation*/,
245
                         TypeErasedState* /*from*/,
246
0
                         TypeErasedState* /*to*/) noexcept {}
247
248
// The manager that is used when a target function is in local storage and is
249
// a trivially copyable type.
250
inline void LocalManagerTrivial(FunctionToCall /*operation*/,
251
                                TypeErasedState* const from,
252
0
                                TypeErasedState* const to) noexcept {
253
0
  // This single statement without branching handles both possible operations.
254
0
  //
255
0
  // For FunctionToCall::dispose, "from" and "to" point to the same state, and
256
0
  // so this assignment logically would do nothing.
257
0
  //
258
0
  // Note: Correctness here relies on http://wg21.link/p0593, which has only
259
0
  // become standard in C++20, though implementations do not break it in
260
0
  // practice for earlier versions of C++.
261
0
  //
262
0
  // The correct way to do this without that paper is to first placement-new a
263
0
  // default-constructed T in "to->storage" prior to the memmove, but doing so
264
0
  // requires a different function to be created for each T that is stored
265
0
  // locally, which can cause unnecessary bloat and be less cache friendly.
266
0
  *to = *from;
267
0
268
0
  // Note: Because the type is trivially copyable, the destructor does not need
269
0
  // to be called ("trivially copyable" requires a trivial destructor).
270
0
}
271
272
// The manager that is used when a target function is in local storage and is
273
// not a trivially copyable type.
274
template <class T>
275
void LocalManagerNontrivial(FunctionToCall operation,
276
                            TypeErasedState* const from,
277
                            TypeErasedState* const to) noexcept {
278
  static_assert(IsStoredLocally<T>::value,
279
                "Local storage must only be used for supported types.");
280
  static_assert(!std::is_trivially_copyable<T>::value,
281
                "Locally stored types must be trivially copyable.");
282
283
  T& from_object = (ObjectInLocalStorage<T>)(from);
284
285
  switch (operation) {
286
    case FunctionToCall::relocate_from_to:
287
      // NOTE: Requires that the left-hand operand is already empty.
288
      ::new (static_cast<void*>(&to->storage)) T(std::move(from_object));
289
      ABSL_FALLTHROUGH_INTENDED;
290
    case FunctionToCall::dispose:
291
      from_object.~T();  // Must not throw. // NOLINT
292
      return;
293
  }
294
  ABSL_UNREACHABLE();
295
}
296
297
// The invoker that is used when a target function is in local storage
298
// Note: QualTRef here is the target function type along with cv and reference
299
// qualifiers that must be used when calling the function.
300
template <bool SigIsNoexcept, class ReturnType, class QualTRef, class... P>
301
ReturnType LocalInvoker(
302
    TypeErasedState* const state,
303
    ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) {
304
  using RawT = RemoveCVRef<QualTRef>;
305
  static_assert(
306
      IsStoredLocally<RawT>::value,
307
      "Target object must be in local storage in order to be invoked from it.");
308
309
  auto& f = (ObjectInLocalStorage<RawT>)(state);
310
  return (InvokeR<ReturnType>)(static_cast<QualTRef>(f),
311
                               static_cast<ForwardedParameterType<P>>(args)...);
312
}
313
314
// The manager that is used when a target function is in remote storage and it
315
// has a trivial destructor
316
inline void RemoteManagerTrivial(FunctionToCall operation,
317
                                 TypeErasedState* const from,
318
0
                                 TypeErasedState* const to) noexcept {
319
0
  switch (operation) {
320
0
    case FunctionToCall::relocate_from_to:
321
0
      // NOTE: Requires that the left-hand operand is already empty.
322
0
      to->remote = from->remote;
323
0
      return;
324
0
    case FunctionToCall::dispose:
325
0
#if defined(__cpp_sized_deallocation)
326
0
      ::operator delete(from->remote.target, from->remote.size);
327
0
#else   // __cpp_sized_deallocation
328
0
      ::operator delete(from->remote.target);
329
0
#endif  // __cpp_sized_deallocation
330
0
      return;
331
0
  }
332
0
  ABSL_UNREACHABLE();
333
0
}
334
335
// The manager that is used when a target function is in remote storage and the
336
// destructor of the type is not trivial
337
template <class T>
338
void RemoteManagerNontrivial(FunctionToCall operation,
339
                             TypeErasedState* const from,
340
                             TypeErasedState* const to) noexcept {
341
  static_assert(!IsStoredLocally<T>::value,
342
                "Remote storage must only be used for types that do not "
343
                "qualify for local storage.");
344
345
  switch (operation) {
346
    case FunctionToCall::relocate_from_to:
347
      // NOTE: Requires that the left-hand operand is already empty.
348
      to->remote.target = from->remote.target;
349
      return;
350
    case FunctionToCall::dispose:
351
      ::delete static_cast<T*>(from->remote.target);  // Must not throw.
352
      return;
353
  }
354
  ABSL_UNREACHABLE();
355
}
356
357
// The invoker that is used when a target function is in remote storage
358
template <bool SigIsNoexcept, class ReturnType, class QualTRef, class... P>
359
ReturnType RemoteInvoker(
360
    TypeErasedState* const state,
361
    ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) {
362
  using RawT = RemoveCVRef<QualTRef>;
363
  static_assert(!IsStoredLocally<RawT>::value,
364
                "Target object must be in remote storage in order to be "
365
                "invoked from it.");
366
367
  auto& f = *static_cast<RawT*>(state->remote.target);
368
  return (InvokeR<ReturnType>)(static_cast<QualTRef>(f),
369
                               static_cast<ForwardedParameterType<P>>(args)...);
370
}
371
372
////////////////////////////////////////////////////////////////////////////////
373
//
374
// A metafunction that checks if a type T is an instantiation of
375
// absl::in_place_type_t (needed for constructor constraints of AnyInvocable).
376
template <class T>
377
struct IsInPlaceType : std::false_type {};
378
379
template <class T>
380
struct IsInPlaceType<absl::in_place_type_t<T>> : std::true_type {};
381
//
382
////////////////////////////////////////////////////////////////////////////////
383
384
// A constructor name-tag used with CoreImpl (below) to request the
385
// conversion-constructor. QualDecayedTRef is the decayed-type of the object to
386
// wrap, along with the cv and reference qualifiers that must be applied when
387
// performing an invocation of the wrapped object.
388
template <class QualDecayedTRef>
389
struct TypedConversionConstruct {};
390
391
// A helper base class for all core operations of AnyInvocable. Most notably,
392
// this class creates the function call operator and constraint-checkers so that
393
// the top-level class does not have to be a series of partial specializations.
394
//
395
// Note: This definition exists (as opposed to being a declaration) so that if
396
// the user of the top-level template accidentally passes a template argument
397
// that is not a function type, they will get a static_assert in AnyInvocable's
398
// class body rather than an error stating that Impl is not defined.
399
template <class Sig>
400
class Impl {};  // Note: This is partially-specialized later.
401
402
// A std::unique_ptr deleter that deletes memory allocated via ::operator new.
403
#if defined(__cpp_sized_deallocation)
404
class TrivialDeleter {
405
 public:
406
  explicit TrivialDeleter(std::size_t size) : size_(size) {}
407
408
  void operator()(void* target) const {
409
    ::operator delete(target, size_);
410
  }
411
412
 private:
413
  std::size_t size_;
414
};
415
#else   // __cpp_sized_deallocation
416
class TrivialDeleter {
417
 public:
418
0
  explicit TrivialDeleter(std::size_t) {}
419
420
0
  void operator()(void* target) const { ::operator delete(target); }
421
};
422
#endif  // __cpp_sized_deallocation
423
424
template <bool SigIsNoexcept, class ReturnType, class... P>
425
class CoreImpl;
426
427
0
constexpr bool IsCompatibleConversion(void*, void*) { return false; }
428
template <bool NoExceptSrc, bool NoExceptDest, class... T>
429
constexpr bool IsCompatibleConversion(CoreImpl<NoExceptSrc, T...>*,
430
                                      CoreImpl<NoExceptDest, T...>*) {
431
  return !NoExceptDest || NoExceptSrc;
432
}
433
434
// A helper base class for all core operations of AnyInvocable that do not
435
// depend on the cv/ref qualifiers of the function type.
436
template <bool SigIsNoexcept, class ReturnType, class... P>
437
class CoreImpl {
438
 public:
439
  using result_type = ReturnType;
440
441
  CoreImpl() noexcept : manager_(EmptyManager), invoker_(nullptr) {}
442
443
  enum class TargetType {
444
    kPointer,
445
    kCompatibleAnyInvocable,
446
    kIncompatibleAnyInvocable,
447
    kOther,
448
  };
449
450
  // Note: QualDecayedTRef here includes the cv-ref qualifiers associated with
451
  // the invocation of the Invocable. The unqualified type is the target object
452
  // type to be stored.
453
  template <class QualDecayedTRef, class F>
454
  explicit CoreImpl(TypedConversionConstruct<QualDecayedTRef>, F&& f) {
455
    using DecayedT = RemoveCVRef<QualDecayedTRef>;
456
457
    constexpr TargetType kTargetType =
458
        (std::is_pointer<DecayedT>::value ||
459
         std::is_member_pointer<DecayedT>::value)
460
            ? TargetType::kPointer
461
        : IsCompatibleAnyInvocable<DecayedT>::value
462
            ? TargetType::kCompatibleAnyInvocable
463
        : IsAnyInvocable<DecayedT>::value
464
            ? TargetType::kIncompatibleAnyInvocable
465
            : TargetType::kOther;
466
    // NOTE: We only use integers instead of enums as template parameters in
467
    // order to work around a bug on C++14 under MSVC 2017.
468
    // See b/236131881.
469
    Initialize<kTargetType, QualDecayedTRef>(std::forward<F>(f));
470
  }
471
472
  // Note: QualTRef here includes the cv-ref qualifiers associated with the
473
  // invocation of the Invocable. The unqualified type is the target object
474
  // type to be stored.
475
  template <class QualTRef, class... Args>
476
  explicit CoreImpl(absl::in_place_type_t<QualTRef>, Args&&... args) {
477
    InitializeStorage<QualTRef>(std::forward<Args>(args)...);
478
  }
479
480
  CoreImpl(CoreImpl&& other) noexcept {
481
    other.manager_(FunctionToCall::relocate_from_to, &other.state_, &state_);
482
    manager_ = other.manager_;
483
    invoker_ = other.invoker_;
484
    other.manager_ = EmptyManager;
485
    other.invoker_ = nullptr;
486
  }
487
488
  CoreImpl& operator=(CoreImpl&& other) noexcept {
489
    // Put the left-hand operand in an empty state.
490
    //
491
    // Note: A full reset that leaves us with an object that has its invariants
492
    // intact is necessary in order to handle self-move. This is required by
493
    // types that are used with certain operations of the standard library, such
494
    // as the default definition of std::swap when both operands target the same
495
    // object.
496
    Clear();
497
498
    // Perform the actual move/destroy operation on the target function.
499
    other.manager_(FunctionToCall::relocate_from_to, &other.state_, &state_);
500
    manager_ = other.manager_;
501
    invoker_ = other.invoker_;
502
    other.manager_ = EmptyManager;
503
    other.invoker_ = nullptr;
504
505
    return *this;
506
  }
507
508
  ~CoreImpl() { manager_(FunctionToCall::dispose, &state_, &state_); }
509
510
  // Check whether or not the AnyInvocable is in the empty state.
511
  bool HasValue() const { return invoker_ != nullptr; }
512
513
  // Effects: Puts the object into its empty state.
514
  void Clear() {
515
    manager_(FunctionToCall::dispose, &state_, &state_);
516
    manager_ = EmptyManager;
517
    invoker_ = nullptr;
518
  }
519
520
  template <TargetType target_type, class QualDecayedTRef, class F,
521
            absl::enable_if_t<target_type == TargetType::kPointer, int> = 0>
522
  void Initialize(F&& f) {
523
// This condition handles types that decay into pointers, which includes
524
// function references. Since function references cannot be null, GCC warns
525
// against comparing their decayed form with nullptr.
526
// Since this is template-heavy code, we prefer to disable these warnings
527
// locally instead of adding yet another overload of this function.
528
#if !defined(__clang__) && defined(__GNUC__)
529
#pragma GCC diagnostic push
530
#pragma GCC diagnostic ignored "-Wpragmas"
531
#pragma GCC diagnostic ignored "-Waddress"
532
#pragma GCC diagnostic ignored "-Wnonnull-compare"
533
#endif
534
    if (static_cast<RemoveCVRef<QualDecayedTRef>>(f) == nullptr) {
535
#if !defined(__clang__) && defined(__GNUC__)
536
#pragma GCC diagnostic pop
537
#endif
538
      manager_ = EmptyManager;
539
      invoker_ = nullptr;
540
      return;
541
    }
542
    InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
543
  }
544
545
  template <TargetType target_type, class QualDecayedTRef, class F,
546
            absl::enable_if_t<
547
                target_type == TargetType::kCompatibleAnyInvocable, int> = 0>
548
  void Initialize(F&& f) {
549
    // In this case we can "steal the guts" of the other AnyInvocable.
550
    f.manager_(FunctionToCall::relocate_from_to, &f.state_, &state_);
551
    manager_ = f.manager_;
552
    invoker_ = f.invoker_;
553
554
    f.manager_ = EmptyManager;
555
    f.invoker_ = nullptr;
556
  }
557
558
  template <TargetType target_type, class QualDecayedTRef, class F,
559
            absl::enable_if_t<
560
                target_type == TargetType::kIncompatibleAnyInvocable, int> = 0>
561
  void Initialize(F&& f) {
562
    if (f.HasValue()) {
563
      InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
564
    } else {
565
      manager_ = EmptyManager;
566
      invoker_ = nullptr;
567
    }
568
  }
569
570
  template <TargetType target_type, class QualDecayedTRef, class F,
571
            typename = absl::enable_if_t<target_type == TargetType::kOther>>
572
  void Initialize(F&& f) {
573
    InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
574
  }
575
576
  // Use local (inline) storage for applicable target object types.
577
  template <class QualTRef, class... Args,
578
            typename = absl::enable_if_t<
579
                IsStoredLocally<RemoveCVRef<QualTRef>>::value>>
580
  void InitializeStorage(Args&&... args) {
581
    using RawT = RemoveCVRef<QualTRef>;
582
    ::new (static_cast<void*>(&state_.storage))
583
        RawT(std::forward<Args>(args)...);
584
585
    invoker_ = LocalInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>;
586
    // We can simplify our manager if we know the type is trivially copyable.
587
    InitializeLocalManager<RawT>();
588
  }
589
590
  // Use remote storage for target objects that cannot be stored locally.
591
  template <class QualTRef, class... Args,
592
            absl::enable_if_t<!IsStoredLocally<RemoveCVRef<QualTRef>>::value,
593
                              int> = 0>
594
  void InitializeStorage(Args&&... args) {
595
    InitializeRemoteManager<RemoveCVRef<QualTRef>>(std::forward<Args>(args)...);
596
    // This is set after everything else in case an exception is thrown in an
597
    // earlier step of the initialization.
598
    invoker_ = RemoteInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>;
599
  }
600
601
  template <class T,
602
            typename = absl::enable_if_t<std::is_trivially_copyable<T>::value>>
603
  void InitializeLocalManager() {
604
    manager_ = LocalManagerTrivial;
605
  }
606
607
  template <class T,
608
            absl::enable_if_t<!std::is_trivially_copyable<T>::value, int> = 0>
609
  void InitializeLocalManager() {
610
    manager_ = LocalManagerNontrivial<T>;
611
  }
612
613
  template <class T>
614
  using HasTrivialRemoteStorage =
615
      std::integral_constant<bool, std::is_trivially_destructible<T>::value &&
616
                                       alignof(T) <=
617
                                           ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT>;
618
619
  template <class T, class... Args,
620
            typename = absl::enable_if_t<HasTrivialRemoteStorage<T>::value>>
621
  void InitializeRemoteManager(Args&&... args) {
622
    // unique_ptr is used for exception-safety in case construction throws.
623
    std::unique_ptr<void, TrivialDeleter> uninitialized_target(
624
        ::operator new(sizeof(T)), TrivialDeleter(sizeof(T)));
625
    ::new (uninitialized_target.get()) T(std::forward<Args>(args)...);
626
    state_.remote.target = uninitialized_target.release();
627
    state_.remote.size = sizeof(T);
628
    manager_ = RemoteManagerTrivial;
629
  }
630
631
  template <class T, class... Args,
632
            absl::enable_if_t<!HasTrivialRemoteStorage<T>::value, int> = 0>
633
  void InitializeRemoteManager(Args&&... args) {
634
    state_.remote.target = ::new T(std::forward<Args>(args)...);
635
    manager_ = RemoteManagerNontrivial<T>;
636
  }
637
638
  //////////////////////////////////////////////////////////////////////////////
639
  //
640
  // Type trait to determine if the template argument is an AnyInvocable whose
641
  // function type is compatible enough with ours such that we can
642
  // "move the guts" out of it when moving, rather than having to place a new
643
  // object into remote storage.
644
645
  template <typename Other>
646
  struct IsCompatibleAnyInvocable {
647
    static constexpr bool value = false;
648
  };
649
650
  template <typename Sig>
651
  struct IsCompatibleAnyInvocable<AnyInvocable<Sig>> {
652
    static constexpr bool value =
653
        (IsCompatibleConversion)(static_cast<
654
                                     typename AnyInvocable<Sig>::CoreImpl*>(
655
                                     nullptr),
656
                                 static_cast<CoreImpl*>(nullptr));
657
  };
658
659
  //
660
  //////////////////////////////////////////////////////////////////////////////
661
662
  TypeErasedState state_;
663
  ManagerType* manager_;
664
  InvokerType<SigIsNoexcept, ReturnType, P...>* invoker_;
665
};
666
667
// A constructor name-tag used with Impl to request the
668
// conversion-constructor
669
struct ConversionConstruct {};
670
671
////////////////////////////////////////////////////////////////////////////////
672
//
673
// A metafunction that is normally an identity metafunction except that when
674
// given a std::reference_wrapper<T>, it yields T&. This is necessary because
675
// currently std::reference_wrapper's operator() is not conditionally noexcept,
676
// so when checking if such an Invocable is nothrow-invocable, we must pull out
677
// the underlying type.
678
template <class T>
679
struct UnwrapStdReferenceWrapperImpl {
680
  using type = T;
681
};
682
683
template <class T>
684
struct UnwrapStdReferenceWrapperImpl<std::reference_wrapper<T>> {
685
  using type = T&;
686
};
687
688
template <class T>
689
using UnwrapStdReferenceWrapper =
690
    typename UnwrapStdReferenceWrapperImpl<T>::type;
691
//
692
////////////////////////////////////////////////////////////////////////////////
693
694
// An alias that always yields std::true_type (used with constraints) where
695
// substitution failures happen when forming the template arguments.
696
template <class... T>
697
using TrueAlias =
698
    std::integral_constant<bool, sizeof(absl::void_t<T...>*) != 0>;
699
700
/*SFINAE constraints for the conversion-constructor.*/
701
template <class Sig, class F,
702
          class = absl::enable_if_t<
703
              !std::is_same<RemoveCVRef<F>, AnyInvocable<Sig>>::value>>
704
using CanConvert = TrueAlias<
705
    absl::enable_if_t<!IsInPlaceType<RemoveCVRef<F>>::value>,
706
    absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>,
707
    absl::enable_if_t<
708
        Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>,
709
    absl::enable_if_t<std::is_constructible<absl::decay_t<F>, F>::value>>;
710
711
/*SFINAE constraints for the std::in_place constructors.*/
712
template <class Sig, class F, class... Args>
713
using CanEmplace = TrueAlias<
714
    absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>,
715
    absl::enable_if_t<
716
        Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>,
717
    absl::enable_if_t<std::is_constructible<absl::decay_t<F>, Args...>::value>>;
718
719
/*SFINAE constraints for the conversion-assign operator.*/
720
template <class Sig, class F,
721
          class = absl::enable_if_t<
722
              !std::is_same<RemoveCVRef<F>, AnyInvocable<Sig>>::value>>
723
using CanAssign = TrueAlias<
724
    absl::enable_if_t<Impl<Sig>::template CallIsValid<F>::value>,
725
    absl::enable_if_t<
726
        Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<F>::value>,
727
    absl::enable_if_t<std::is_constructible<absl::decay_t<F>, F>::value>>;
728
729
/*SFINAE constraints for the reference-wrapper conversion-assign operator.*/
730
template <class Sig, class F>
731
using CanAssignReferenceWrapper = TrueAlias<
732
    absl::enable_if_t<
733
        Impl<Sig>::template CallIsValid<std::reference_wrapper<F>>::value>,
734
    absl::enable_if_t<Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<
735
        std::reference_wrapper<F>>::value>>;
736
737
////////////////////////////////////////////////////////////////////////////////
738
//
739
// The constraint for checking whether or not a call meets the noexcept
740
// callability requirements. This is a preprocessor macro because specifying it
741
// this way as opposed to a disjunction/branch can improve the user-side error
742
// messages and avoids an instantiation of std::is_nothrow_invocable_r in the
743
// cases where the user did not specify a noexcept function type.
744
//
745
#define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT(inv_quals, noex) \
746
  ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_##noex(inv_quals)
747
748
// The disjunction below is because we can't rely on std::is_nothrow_invocable_r
749
// to give the right result when ReturnType is non-moveable in toolchains that
750
// don't treat non-moveable result types correctly. For example this was the
751
// case in libc++ before commit c3a24882 (2022-05).
752
#define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_true(inv_quals)      \
753
  absl::enable_if_t<absl::disjunction<                                       \
754
      std::is_nothrow_invocable_r<                                           \
755
          ReturnType, UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, \
756
          P...>,                                                             \
757
      std::conjunction<                                                      \
758
          std::is_nothrow_invocable<                                         \
759
              UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, P...>,  \
760
          std::is_same<                                                      \
761
              ReturnType,                                                    \
762
              absl::base_internal::invoke_result_t<                          \
763
                  UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals,     \
764
                  P...>>>>::value>
765
766
#define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_false(inv_quals)
767
//
768
////////////////////////////////////////////////////////////////////////////////
769
770
// A macro to generate partial specializations of Impl with the different
771
// combinations of supported cv/reference qualifiers and noexcept specifier.
772
//
773
// Here, `cv` are the cv-qualifiers if any, `ref` is the ref-qualifier if any,
774
// inv_quals is the reference type to be used when invoking the target, and
775
// noex is "true" if the function type is noexcept, or false if it is not.
776
//
777
// The CallIsValid condition is more complicated than simply using
778
// absl::base_internal::is_invocable_r because we can't rely on it to give the
779
// right result when ReturnType is non-moveable in toolchains that don't treat
780
// non-moveable result types correctly. For example this was the case in libc++
781
// before commit c3a24882 (2022-05).
782
#define ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, noex)            \
783
  template <class ReturnType, class... P>                                      \
784
  class Impl<ReturnType(P...) cv ref ABSL_INTERNAL_NOEXCEPT_SPEC(noex)>        \
785
      : public CoreImpl<noex, ReturnType, P...> {                              \
786
   public:                                                                     \
787
    /*The base class, which contains the datamembers and core operations*/     \
788
    using Core = CoreImpl<noex, ReturnType, P...>;                             \
789
                                                                               \
790
    /*SFINAE constraint to check if F is invocable with the proper signature*/ \
791
    template <class F>                                                         \
792
    using CallIsValid = TrueAlias<absl::enable_if_t<absl::disjunction<         \
793
        absl::base_internal::is_invocable_r<ReturnType,                        \
794
                                            absl::decay_t<F> inv_quals, P...>, \
795
        std::is_same<ReturnType,                                               \
796
                     absl::base_internal::invoke_result_t<                     \
797
                         absl::decay_t<F> inv_quals, P...>>>::value>>;         \
798
                                                                               \
799
    /*SFINAE constraint to check if F is nothrow-invocable when necessary*/    \
800
    template <class F>                                                         \
801
    using CallIsNoexceptIfSigIsNoexcept =                                      \
802
        TrueAlias<ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT(inv_quals,   \
803
                                                                  noex)>;      \
804
                                                                               \
805
    /*Put the AnyInvocable into an empty state.*/                              \
806
    Impl() = default;                                                          \
807
                                                                               \
808
    /*The implementation of a conversion-constructor from "f*/                 \
809
    /*This forwards to Core, attaching inv_quals so that the base class*/      \
810
    /*knows how to properly type-erase the invocation.*/                       \
811
    template <class F>                                                         \
812
    explicit Impl(ConversionConstruct, F&& f)                                  \
813
        : Core(TypedConversionConstruct<                                       \
814
                   typename std::decay<F>::type inv_quals>(),                  \
815
               std::forward<F>(f)) {}                                          \
816
                                                                               \
817
    /*Forward along the in-place construction parameters.*/                    \
818
    template <class T, class... Args>                                          \
819
    explicit Impl(absl::in_place_type_t<T>, Args&&... args)                    \
820
        : Core(absl::in_place_type<absl::decay_t<T> inv_quals>,                \
821
               std::forward<Args>(args)...) {}                                 \
822
                                                                               \
823
    /*Raises a fatal error when the AnyInvocable is invoked after a move*/     \
824
    static ReturnType InvokedAfterMove(                                        \
825
      TypeErasedState*,                                                        \
826
      ForwardedParameterType<P>...) noexcept(noex) {                           \
827
      ABSL_HARDENING_ASSERT(false && "AnyInvocable use-after-move");           \
828
      std::terminate();                                                        \
829
    }                                                                          \
830
                                                                               \
831
    InvokerType<noex, ReturnType, P...>* ExtractInvoker() cv {                 \
832
      using QualifiedTestType = int cv ref;                                    \
833
      auto* invoker = this->invoker_;                                          \
834
      if (!std::is_const<QualifiedTestType>::value &&                          \
835
          std::is_rvalue_reference<QualifiedTestType>::value) {                \
836
        ABSL_ASSERT([this]() {                                                 \
837
          /* We checked that this isn't const above, so const_cast is safe */  \
838
          const_cast<Impl*>(this)->invoker_ = InvokedAfterMove;                \
839
          return this->HasValue();                                             \
840
        }());                                                                  \
841
      }                                                                        \
842
      return invoker;                                                          \
843
    }                                                                          \
844
                                                                               \
845
    /*The actual invocation operation with the proper signature*/              \
846
    ReturnType operator()(P... args) cv ref noexcept(noex) {                   \
847
      assert(this->invoker_ != nullptr);                                       \
848
      return this->ExtractInvoker()(                                           \
849
          const_cast<TypeErasedState*>(&this->state_),                         \
850
          static_cast<ForwardedParameterType<P>>(args)...);                    \
851
    }                                                                          \
852
  }
853
854
// Define the `noexcept(true)` specialization only for C++17 and beyond, when
855
// `noexcept` is part of the type system.
856
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
857
// A convenience macro that defines specializations for the noexcept(true) and
858
// noexcept(false) forms, given the other properties.
859
#define ABSL_INTERNAL_ANY_INVOCABLE_IMPL(cv, ref, inv_quals)    \
860
  ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, false); \
861
  ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, true)
862
#else
863
#define ABSL_INTERNAL_ANY_INVOCABLE_IMPL(cv, ref, inv_quals) \
864
  ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, false)
865
#endif
866
867
// Non-ref-qualified partial specializations
868
ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, , &);
869
ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, , const&);
870
871
// Lvalue-ref-qualified partial specializations
872
ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, &, &);
873
ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, &, const&);
874
875
// Rvalue-ref-qualified partial specializations
876
ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, &&, &&);
877
ABSL_INTERNAL_ANY_INVOCABLE_IMPL(const, &&, const&&);
878
879
// Undef the detail-only macros.
880
#undef ABSL_INTERNAL_ANY_INVOCABLE_IMPL
881
#undef ABSL_INTERNAL_ANY_INVOCABLE_IMPL_
882
#undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_false
883
#undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_true
884
#undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT
885
#undef ABSL_INTERNAL_NOEXCEPT_SPEC
886
887
}  // namespace internal_any_invocable
888
ABSL_NAMESPACE_END
889
}  // namespace absl
890
891
#endif  // ABSL_FUNCTIONAL_INTERNAL_ANY_INVOCABLE_H_