33 #ifndef LLVM_ADT_FUNCTION_EXTRAS_H 34 #define LLVM_ADT_FUNCTION_EXTRAS_H 45 template <
typename ReturnT,
typename... ParamTs>
47 static constexpr
size_t InlineStorageSize =
sizeof(
void *) * 3;
52 template <
typename T>
struct IsSizeLessThanThresholdT {
53 static constexpr
bool value =
sizeof(
T) <= (2 *
sizeof(
void *));
66 using AdjustedParamT =
typename std::conditional<
67 !std::is_reference<T>::value &&
70 IsSizeLessThanThresholdT<T>::value,
75 using CallPtrT = ReturnT (*)(
void *CallableAddr,
76 AdjustedParamT<ParamTs>... Params);
77 using MovePtrT = void (*)(
void *LHSCallableAddr,
void *RHSCallableAddr);
78 using DestroyPtrT = void (*)(
void *CallableAddr);
82 struct alignas(8) TrivialCallback {
88 struct alignas(8) NonTrivialCallbacks {
91 DestroyPtrT DestroyPtr;
102 union StorageUnionT {
105 struct OutOfLineStorageT {
111 sizeof(OutOfLineStorageT) <= InlineStorageSize,
112 "Should always use all of the out-of-line storage for inline storage!");
116 typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
125 bool isInlineStorage()
const {
return CallbackAndInlineFlag.
getInt(); }
127 bool isTrivialCallback()
const {
128 return CallbackAndInlineFlag.
getPointer().template is<TrivialCallback *>();
131 CallPtrT getTrivialCallback()
const {
132 return CallbackAndInlineFlag.
getPointer().template get<TrivialCallback *>()->CallPtr;
135 NonTrivialCallbacks *getNonTrivialCallbacks()
const {
137 .template get<NonTrivialCallbacks *>();
140 void *getInlineStorage() {
return &StorageUnion.InlineStorage; }
142 void *getOutOfLineStorage() {
143 return StorageUnion.OutOfLineStorage.StoragePtr;
145 size_t getOutOfLineStorageSize()
const {
146 return StorageUnion.OutOfLineStorage.Size;
148 size_t getOutOfLineStorageAlignment()
const {
149 return StorageUnion.OutOfLineStorage.Alignment;
152 void setOutOfLineStorage(
void *Ptr,
size_t Size,
size_t Alignment) {
153 StorageUnion.OutOfLineStorage = {Ptr,
Size, Alignment};
156 template <
typename CallableT>
157 static ReturnT CallImpl(
void *CallableAddr, AdjustedParamT<ParamTs>... Params) {
158 return (*reinterpret_cast<CallableT *>(CallableAddr))(
159 std::forward<ParamTs>(Params)...);
162 template <
typename CallableT>
163 static void MoveImpl(
void *LHSCallableAddr,
void *RHSCallableAddr) noexcept {
164 new (LHSCallableAddr)
165 CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
168 template <
typename CallableT>
169 static void DestroyImpl(
void *CallableAddr) noexcept {
170 reinterpret_cast<CallableT *
>(CallableAddr)->~CallableT();
182 bool IsInlineStorage = isInlineStorage();
184 if (!isTrivialCallback())
185 getNonTrivialCallbacks()->DestroyPtr(
186 IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
188 if (!IsInlineStorage)
190 getOutOfLineStorageAlignment());
195 CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
201 if (!isInlineStorage()) {
203 StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
204 }
else if (isTrivialCallback()) {
206 memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
209 getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
210 RHS.getInlineStorage());
214 RHS.CallbackAndInlineFlag = {};
218 memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
235 bool IsInlineStorage =
true;
236 void *CallableAddr = getInlineStorage();
237 if (
sizeof(CallableT) > InlineStorageSize ||
238 alignof(CallableT) >
alignof(decltype(StorageUnion.InlineStorage))) {
239 IsInlineStorage =
false;
242 auto Size =
sizeof(CallableT);
243 auto Alignment =
alignof(CallableT);
245 setOutOfLineStorage(CallableAddr,
Size, Alignment);
249 new (CallableAddr) CallableT(std::move(Callable));
259 std::is_trivially_destructible<CallableT>::value) {
262 static TrivialCallback Callback = { &CallImpl<CallableT> };
264 CallbackAndInlineFlag = {&Callback, IsInlineStorage};
271 static NonTrivialCallbacks Callbacks = {
272 &CallImpl<CallableT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
274 CallbackAndInlineFlag = {&Callbacks, IsInlineStorage};
279 isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
281 return (isTrivialCallback()
282 ? getTrivialCallback()
283 : getNonTrivialCallbacks()->CallPtr)(CallableAddr, Params...);
286 explicit operator bool()
const {
287 return (
bool)CallbackAndInlineFlag.
getPointer();
293 #endif // LLVM_ADT_FUNCTION_H
This class represents lattice values for constants.
PointerTy getPointer() const
unique_function & operator=(unique_function &&RHS) noexcept
unique_function(unique_function &&RHS) noexcept
An implementation of std::is_trivially_move_constructible since we have users with STLs that don't ye...
void * allocate_buffer(size_t Size, size_t Alignment)
Allocate a buffer of memory with the given size and alignment.
PointerIntPair - This class implements a pair of a pointer and small integer.
An implementation of std::is_trivially_copy_constructible since we have users with STLs that don't ye...
unique_function(CallableT Callable)
void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment)
Deallocate a buffer of memory with the given size and alignment.
unique_function(std::nullptr_t)
ReturnT operator()(ParamTs... Params)
A discriminated union of two pointer types, with the discriminator in the low bit of the pointer...