32 #ifndef LLVM_ADT_FUNCTIONEXTRAS_H
33 #define LLVM_ADT_FUNCTIONEXTRAS_H
42 #include <type_traits>
62 std::enable_if_t<llvm::is_trivially_move_constructible<T>::value &&
63 std::is_trivially_destructible<T>::value>;
64 template <
typename CallableT,
typename ThisT>
66 std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>::value>;
67 template <
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>
87 struct IsSizeLessThanThresholdT<
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 =
typename std::conditional<
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>
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 {
157 "Should always use all of the out-of-line storage for inline storage!");
171 PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
173 bool isInlineStorage()
const {
return CallbackAndInlineFlag.getInt(); }
175 bool isTrivialCallback()
const {
176 return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
179 CallPtrT getTrivialCallback()
const {
180 return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
184 return CallbackAndInlineFlag.getPointer()
185 .template get<NonTrivialCallbacks *>();
189 return isTrivialCallback() ? getTrivialCallback()
204 return StorageUnion.OutOfLineStorage.StoragePtr;
208 return StorageUnion.OutOfLineStorage.Size;
211 return StorageUnion.OutOfLineStorage.Alignment;
215 StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
218 template <
typename CalledAsT>
220 AdjustedParamT<ParamTs>... Params) {
221 auto &Func = *
reinterpret_cast<CalledAsT *
>(CallableAddr);
222 return Func(std::forward<ParamTs>(Params)...);
225 template <
typename CallableT>
226 static void MoveImpl(
void *LHSCallableAddr,
void *RHSCallableAddr) noexcept {
227 new (LHSCallableAddr)
228 CallableT(
std::move(*
reinterpret_cast<CallableT *
>(RHSCallableAddr)));
231 template <
typename CallableT>
233 reinterpret_cast<CallableT *
>(CallableAddr)->~CallableT();
244 template <
typename CallableT,
typename CalledAs,
typename Enable =
void>
251 template <
typename CallableT,
typename CalledAs>
262 template <
typename CallableT,
typename CalledAsT>
264 bool IsInlineStorage =
true;
267 alignof(CallableT) >
alignof(decltype(StorageUnion.InlineStorage))) {
268 IsInlineStorage =
false;
271 auto Size =
sizeof(CallableT);
272 auto Alignment =
alignof(CallableT);
278 new (CallableAddr) CallableT(
std::move(Callable));
279 CallbackAndInlineFlag.setPointerAndInt(
284 if (!CallbackAndInlineFlag.getPointer())
288 bool IsInlineStorage = isInlineStorage();
290 if (!isTrivialCallback())
294 if (!IsInlineStorage)
301 CallbackAndInlineFlag =
RHS.CallbackAndInlineFlag;
307 if (!isInlineStorage()) {
309 StorageUnion.OutOfLineStorage =
RHS.StorageUnion.OutOfLineStorage;
310 }
else if (isTrivialCallback()) {
316 RHS.getInlineStorage());
320 RHS.CallbackAndInlineFlag = {};
343 explicit operator bool()
const {
344 return (
bool)CallbackAndInlineFlag.getPointer();
348 template <
typename R,
typename...
P>
349 template <
typename CallableT,
typename CalledAsT,
typename Enable>
350 typename UniqueFunctionBase<R,
P...>::NonTrivialCallbacks UniqueFunctionBase<
351 R,
P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
352 &CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
354 template <
typename R,
typename...
P>
355 template <
typename CallableT,
typename CalledAsT>
356 typename UniqueFunctionBase<R,
P...>::TrivialCallback
357 UniqueFunctionBase<R,
P...>::CallbacksHolder<
358 CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
359 &CallImpl<CalledAsT>};
363 template <
typename R,
typename...
P>
375 template <
typename CallableT>
380 :
Base(
std::forward<CallableT>(Callable),
381 typename
Base::template CalledAs<CallableT>{}) {}
384 return this->getCallPtr()(this->getCalleePtr(), Params...);
388 template <
typename R,
typename...
P>
401 template <
typename CallableT>
406 :
Base(
std::forward<CallableT>(Callable),
407 typename
Base::template CalledAs<
const CallableT>{}) {}
410 return this->getCallPtr()(this->getCalleePtr(), Params...);
416 #endif // LLVM_ADT_FUNCTIONEXTRAS_H