32#ifndef LLVM_ADT_FUNCTIONEXTRAS_H
33#define LLVM_ADT_FUNCTIONEXTRAS_H
62 std::enable_if_t<llvm::is_trivially_move_constructible<T>::value &&
63 std::is_trivially_destructible<T>::value>;
64template <
typename CallableT,
typename ThisT>
66 std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>
::value>;
67template <
typename CallableT,
typename Ret,
typename... Params>
70 std::is_same<decltype(std::declval<CallableT>()(std::declval<Params>()...)),
72 std::is_same<
const decltype(std::declval<CallableT>()(
73 std::declval<Params>()...)),
75 std::is_convertible<
decltype(std::declval<CallableT>()(
76 std::declval<Params>()...)),
83 template <
typename T,
class =
void>
88 T,
std::enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
99 template <
typename T>
struct AdjustedParamTBase {
100 static_assert(!std::is_reference<T>::value,
101 "references should be handled by template specialization");
102 using type = std::conditional_t<
105 IsSizeLessThanThresholdT<T>::value,
112 template <
typename T>
struct AdjustedParamTBase<
T &> {
using type =
T &; };
113 template <
typename T>
struct AdjustedParamTBase<
T &&> {
using type =
T &; };
115 template <
typename T>
116 using AdjustedParamT =
typename AdjustedParamTBase<T>::type;
120 using CallPtrT = ReturnT (*)(
void *CallableAddr,
121 AdjustedParamT<ParamTs>... Params);
122 using MovePtrT = void (*)(
void *LHSCallableAddr,
void *RHSCallableAddr);
123 using DestroyPtrT = void (*)(
void *CallableAddr);
127 struct alignas(8) TrivialCallback {
133 struct alignas(8) NonTrivialCallbacks {
136 DestroyPtrT DestroyPtr;
142 using CallbackPointerUnionT =
143 PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
147 union StorageUnionT {
150 struct OutOfLineStorageT {
156 sizeof(OutOfLineStorageT) <= InlineStorageSize,
157 "Should always use all of the out-of-line storage for inline storage!");
163 mutable std::aligned_storage_t<InlineStorageSize,
alignof(
void *)>
170 PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
172 bool isInlineStorage()
const {
return CallbackAndInlineFlag.getInt(); }
174 bool isTrivialCallback()
const {
175 return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
178 CallPtrT getTrivialCallback()
const {
179 return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
183 return CallbackAndInlineFlag.getPointer()
184 .template get<NonTrivialCallbacks *>();
188 return isTrivialCallback() ? getTrivialCallback()
203 return StorageUnion.OutOfLineStorage.StoragePtr;
207 return StorageUnion.OutOfLineStorage.Size;
210 return StorageUnion.OutOfLineStorage.Alignment;
214 StorageUnion.OutOfLineStorage = {
Ptr,
Size, Alignment};
217 template <
typename CalledAsT>
219 AdjustedParamT<ParamTs>... Params) {
220 auto &Func = *
reinterpret_cast<CalledAsT *
>(CallableAddr);
221 return Func(std::forward<ParamTs>(Params)...);
224 template <
typename CallableT>
225 static void MoveImpl(
void *LHSCallableAddr,
void *RHSCallableAddr)
noexcept {
226 new (LHSCallableAddr)
227 CallableT(std::move(*
reinterpret_cast<CallableT *
>(RHSCallableAddr)));
230 template <
typename CallableT>
232 reinterpret_cast<CallableT *
>(CallableAddr)->~CallableT();
243 template <
typename CallableT,
typename CalledAs,
typename Enable =
void>
250 template <
typename CallableT,
typename CalledAs>
261 template <
typename CallableT,
typename CalledAsT>
263 bool IsInlineStorage =
true;
266 alignof(CallableT) >
alignof(
decltype(StorageUnion.InlineStorage))) {
267 IsInlineStorage =
false;
270 auto Size =
sizeof(CallableT);
271 auto Alignment =
alignof(CallableT);
277 new (CallableAddr) CallableT(std::move(Callable));
278 CallbackAndInlineFlag.setPointerAndInt(
283 if (!CallbackAndInlineFlag.getPointer())
287 bool IsInlineStorage = isInlineStorage();
289 if (!isTrivialCallback())
293 if (!IsInlineStorage)
300 CallbackAndInlineFlag =
RHS.CallbackAndInlineFlag;
306 if (!isInlineStorage()) {
308 StorageUnion.OutOfLineStorage =
RHS.StorageUnion.OutOfLineStorage;
309 }
else if (isTrivialCallback()) {
315 RHS.getInlineStorage());
319 RHS.CallbackAndInlineFlag = {};
342 explicit operator bool()
const {
343 return (
bool)CallbackAndInlineFlag.getPointer();
347template <
typename R,
typename...
P>
348template <
typename CallableT,
typename CalledAsT,
typename Enable>
349typename UniqueFunctionBase<R,
P...>::NonTrivialCallbacks UniqueFunctionBase<
350 R,
P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
351 &CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
353template <
typename R,
typename...
P>
354template <
typename CallableT,
typename CalledAsT>
355typename UniqueFunctionBase<R,
P...>::TrivialCallback
356 UniqueFunctionBase<R,
P...>::CallbacksHolder<
357 CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
358 &CallImpl<CalledAsT>};
362template <
typename R,
typename...
P>
374 template <
typename CallableT>
379 :
Base(
std::forward<CallableT>(Callable),
380 typename
Base::template CalledAs<CallableT>{}) {}
383 return this->getCallPtr()(this->getCalleePtr(), Params...);
387template <
typename R,
typename...
P>
400 template <
typename CallableT>
405 :
Base(
std::forward<CallableT>(Callable),
406 typename
Base::template CalledAs<
const CallableT>{}) {}
409 return this->getCallPtr()(this->getCalleePtr(), Params...);
Given that RA is a live value
This file defines counterparts of C library allocation functions defined in the namespace 'std'.
This file defines the PointerIntPair class.
This file defines the PointerUnion class, which is a discriminated union of pointer types.
This file contains library features backported from future STL versions.
CallPtrT getCallPtr() const
void * getInlineStorage() const
UniqueFunctionBase()=default
void * getOutOfLineStorage() const
void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment)
UniqueFunctionBase & operator=(UniqueFunctionBase &&RHS) noexcept
NonTrivialCallbacks * getNonTrivialCallbacks() const
UniqueFunctionBase(CallableT Callable, CalledAs< CalledAsT >)
static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept
static void DestroyImpl(void *CallableAddr) noexcept
size_t getOutOfLineStorageSize() const
static ReturnT CallImpl(void *CallableAddr, AdjustedParamT< ParamTs >... Params)
void * getCalleePtr() const
size_t getOutOfLineStorageAlignment() const
UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept
static constexpr size_t InlineStorageSize
unique_function(std::nullptr_t)
unique_function()=default
unique_function(const unique_function &)=delete
unique_function(unique_function &&)=default
unique_function & operator=(const unique_function &)=delete
unique_function & operator=(unique_function &&)=default
R operator()(P... Params) const
unique_function(CallableT Callable, detail::EnableUnlessSameType< CallableT, unique_function > *=nullptr, detail::EnableIfCallable< const CallableT, R, P... > *=nullptr)
unique_function(unique_function &&)=default
unique_function & operator=(const unique_function &)=delete
unique_function(CallableT Callable, detail::EnableUnlessSameType< CallableT, unique_function > *=nullptr, detail::EnableIfCallable< CallableT, R, P... > *=nullptr)
unique_function & operator=(unique_function &&)=default
R operator()(P... Params)
unique_function()=default
unique_function(std::nullptr_t)
unique_function(const unique_function &)=delete
unique_function is a type-erasing functor similar to std::function.
std::enable_if_t< std::disjunction< std::is_void< Ret >, std::is_same< decltype(std::declval< CallableT >()(std::declval< Params >()...)), Ret >, std::is_same< const decltype(std::declval< CallableT >()(std::declval< Params >()...)), Ret >, std::is_convertible< decltype(std::declval< CallableT >()(std::declval< Params >()...)), Ret > >::value > EnableIfCallable
std::enable_if_t< llvm::is_trivially_move_constructible< T >::value &&std::is_trivially_destructible< T >::value > EnableIfTrivial
std::enable_if_t<!std::is_same< remove_cvref_t< CallableT >, ThisT >::value > EnableUnlessSameType
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * allocate_buffer(size_t Size, size_t Alignment)
Allocate a buffer of memory with the given size and alignment.
void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment)
Deallocate a buffer of memory with the given size and alignment.
static TrivialCallback Callbacks
static NonTrivialCallbacks Callbacks
An implementation of std::is_trivially_copy_constructible since we have users with STLs that don't ye...
An implementation of std::is_trivially_move_constructible since we have users with STLs that don't ye...