32#ifndef WPIUTIL_WPI_FUNCTIONEXTRAS_H
33#define WPIUTIL_WPI_FUNCTIONEXTRAS_H
59#if defined(__GNUC__) && !defined(__clang__)
60#pragma GCC diagnostic push
61#pragma GCC diagnostic ignored "-Warray-bounds"
62#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
69 std::enable_if_t<wpi::is_trivially_move_constructible<T>::value &&
70 std::is_trivially_destructible<T>::value>;
71template <
typename CallableT,
typename ThisT>
73 std::enable_if_t<!std::is_same<remove_cvref_t<CallableT>, ThisT>
::value>;
74template <
typename CallableT,
typename Ret,
typename... Params>
77 std::is_same<decltype(std::declval<CallableT>()(std::declval<Params>()...)),
79 std::is_same<
const decltype(std::declval<CallableT>()(
80 std::declval<Params>()...)),
82 std::is_convertible<
decltype(std::declval<CallableT>()(
83 std::declval<Params>()...)),
90 template <
typename T,
class =
void>
95 T,
std::
enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
106 template <
typename T>
struct AdjustedParamTBase {
107 static_assert(!std::is_reference<T>::value,
108 "references should be handled by template specialization");
109 using type =
typename std::conditional<
112 IsSizeLessThanThresholdT<T>::value,
119 template <
typename T>
struct AdjustedParamTBase<T &> {
using type = T &; };
120 template <
typename T>
struct AdjustedParamTBase<T &&> {
using type = T &; };
122 template <
typename T>
127 using CallPtrT = ReturnT (*)(
void *CallableAddr,
128 AdjustedParamT<ParamTs>... Params);
129 using MovePtrT = void (*)(
void *LHSCallableAddr,
void *RHSCallableAddr);
130 using DestroyPtrT = void (*)(
void *CallableAddr);
134 struct alignas(8) TrivialCallback {
140 struct alignas(8) NonTrivialCallbacks {
143 DestroyPtrT DestroyPtr;
149 using CallbackPointerUnionT =
150 PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
154 union StorageUnionT {
157 struct OutOfLineStorageT {
164 "Should always use all of the out-of-line storage for inline storage!");
178 PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
180 bool isInlineStorage()
const {
return CallbackAndInlineFlag.getInt(); }
182 bool isTrivialCallback()
const {
183 return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
186 CallPtrT getTrivialCallback()
const {
187 return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
191 return CallbackAndInlineFlag.getPointer()
192 .template get<NonTrivialCallbacks *>();
196 return isTrivialCallback() ? getTrivialCallback()
211 return StorageUnion.OutOfLineStorage.StoragePtr;
215 return StorageUnion.OutOfLineStorage.Size;
218 return StorageUnion.OutOfLineStorage.Alignment;
222 StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
225 template <
typename CalledAsT>
227 AdjustedParamT<ParamTs>... Params) {
228 auto &Func = *
reinterpret_cast<CalledAsT *
>(CallableAddr);
229 return Func(std::forward<ParamTs>(Params)...);
232 template <
typename CallableT>
233 static void MoveImpl(
void *LHSCallableAddr,
void *RHSCallableAddr)
noexcept {
234 new (LHSCallableAddr)
235 CallableT(std::move(*
reinterpret_cast<CallableT *
>(RHSCallableAddr)));
238 template <
typename CallableT>
240 reinterpret_cast<CallableT *
>(CallableAddr)->~CallableT();
251 template <
typename CallableT,
typename CalledAs,
typename Enable =
void>
258 template <
typename CallableT,
typename CalledAs>
269 template <
typename CallableT,
typename CalledAsT>
271 bool IsInlineStorage =
true;
274 alignof(CallableT) >
alignof(
decltype(StorageUnion.InlineStorage))) {
275 IsInlineStorage =
false;
278 auto Size =
sizeof(CallableT);
279 auto Alignment =
alignof(CallableT);
285 new (CallableAddr) CallableT(std::move(Callable));
286 CallbackAndInlineFlag.setPointerAndInt(
291 if (!CallbackAndInlineFlag.getPointer())
295 bool IsInlineStorage = isInlineStorage();
297 if (!isTrivialCallback())
301 if (!IsInlineStorage)
308 CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
314 if (!isInlineStorage()) {
316 StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
317 }
else if (isTrivialCallback()) {
323 RHS.getInlineStorage());
327 RHS.CallbackAndInlineFlag = {};
350 explicit operator bool()
const {
351 return (
bool)CallbackAndInlineFlag.getPointer();
355template <
typename R,
typename... P>
356template <
typename CallableT,
typename CalledAsT,
typename Enable>
357typename UniqueFunctionBase<
R, P...>::NonTrivialCallbacks UniqueFunctionBase<
358 R, P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
359 &CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
361template <
typename R,
typename... P>
362template <
typename CallableT,
typename CalledAsT>
363typename UniqueFunctionBase<
R, P...>::TrivialCallback
364 UniqueFunctionBase<
R, P...>::CallbacksHolder<
365 CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
366 &CallImpl<CalledAsT>};
370template <
typename R,
typename... P>
382 template <
typename CallableT>
387 :
Base(
std::forward<CallableT>(Callable),
388 typename
Base::template CalledAs<CallableT>{}) {}
391 return this->getCallPtr()(this->getCalleePtr(), Params...);
395template <
typename R,
typename... P>
408 template <
typename CallableT>
413 :
Base(
std::forward<CallableT>(Callable),
414 typename
Base::template CalledAs<const CallableT>{}) {}
417 return this->getCallPtr()(this->getCalleePtr(), Params...);
421#if defined(__GNUC__) && !defined(__clang__)
422#pragma GCC diagnostic pop
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.
Definition: FunctionExtras.h:86
void * getInlineStorage() const
Definition: FunctionExtras.h:209
struct IsSizeLessThanThresholdT< T, std::enable_if_t< sizeof(T)<=2 *sizeof(void *)> > :std::true_type {};template< typename T > struct AdjustedParamTBase { static_assert(!std::is_reference< T >::value, "references should be handled by template specialization");using type=typename std::conditional< wpi::is_trivially_copy_constructible< T >::value &&wpi::is_trivially_move_constructible< T >::value &&IsSizeLessThanThresholdT< T >::value, T, T & >::type;};template< typename T > struct AdjustedParamTBase< T & > { using type=T &;};template< typename T > struct AdjustedParamTBase< T && > { using type=T &;};template< typename T > using AdjustedParamT=typename AdjustedParamTBase< T >::type;using CallPtrT=ReturnT(*)(void *CallableAddr, AdjustedParamT< ParamTs >... Params);using MovePtrT=void(*)(void *LHSCallableAddr, void *RHSCallableAddr);using DestroyPtrT=void(*)(void *CallableAddr);struct alignas(8) TrivialCallback { CallPtrT CallPtr;};struct alignas(8) NonTrivialCallbacks { CallPtrT CallPtr;MovePtrT MovePtr;DestroyPtrT DestroyPtr;};using CallbackPointerUnionT=PointerUnion< TrivialCallback *, NonTrivialCallbacks * >;union StorageUnionT { struct OutOfLineStorageT { void *StoragePtr;size_t Size;size_t Alignment;} OutOfLineStorage;static_assert(sizeof(OutOfLineStorageT)<=InlineStorageSize, "Should always use all of the out-of-line storage for inline storage!");mutable typename std::aligned_storage< InlineStorageSize, alignof(void *)>::type InlineStorage;} StorageUnion;PointerIntPair< CallbackPointerUnionT, 1, bool > CallbackAndInlineFlag;bool isInlineStorage() const { return CallbackAndInlineFlag.getInt();} bool isTrivialCallback() const { return CallbackAndInlineFlag.getPointer().template is< TrivialCallback * >();} CallPtrT getTrivialCallback() const { return CallbackAndInlineFlag.getPointer().template get< TrivialCallback * >() -> CallPtr
Definition: FunctionExtras.h:94
static constexpr size_t InlineStorageSize
Definition: FunctionExtras.h:88
UniqueFunctionBase & operator=(UniqueFunctionBase &&RHS) noexcept
Definition: FunctionExtras.h:335
size_t getOutOfLineStorageSize() const
Definition: FunctionExtras.h:214
void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment)
Definition: FunctionExtras.h:221
NonTrivialCallbacks * getNonTrivialCallbacks() const
Definition: FunctionExtras.h:190
static ReturnT CallImpl(void *CallableAddr, AdjustedParamT< ParamTs >... Params)
Definition: FunctionExtras.h:226
UniqueFunctionBase()=default
UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept
Definition: FunctionExtras.h:306
size_t getOutOfLineStorageAlignment() const
Definition: FunctionExtras.h:217
UniqueFunctionBase(CallableT Callable, CalledAs< CalledAsT >)
Definition: FunctionExtras.h:270
static void DestroyImpl(void *CallableAddr) noexcept
Definition: FunctionExtras.h:239
void * getCalleePtr() const
Definition: FunctionExtras.h:206
static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept
Definition: FunctionExtras.h:233
CallPtrT getCallPtr() const
Definition: FunctionExtras.h:195
void * getOutOfLineStorage() const
Definition: FunctionExtras.h:210
~UniqueFunctionBase()
Definition: FunctionExtras.h:290
unique_function()=default
unique_function(const unique_function &)=delete
unique_function & operator=(unique_function &&)=default
R operator()(P... Params) const
Definition: FunctionExtras.h:416
unique_function & operator=(const unique_function &)=delete
unique_function(unique_function &&)=default
unique_function(std::nullptr_t)
Definition: FunctionExtras.h:402
unique_function(CallableT Callable, detail::EnableUnlessSameType< CallableT, unique_function > *=nullptr, detail::EnableIfCallable< const CallableT, R, P... > *=nullptr)
Definition: FunctionExtras.h:409
unique_function()=default
R operator()(P... Params)
Definition: FunctionExtras.h:390
unique_function(const unique_function &)=delete
unique_function(CallableT Callable, detail::EnableUnlessSameType< CallableT, unique_function > *=nullptr, detail::EnableIfCallable< CallableT, R, P... > *=nullptr)
Definition: FunctionExtras.h:383
unique_function(std::nullptr_t)
Definition: FunctionExtras.h:376
unique_function(unique_function &&)=default
unique_function & operator=(unique_function &&)=default
unique_function & operator=(const unique_function &)=delete
unique_function is a type-erasing functor similar to std::function.
Definition: FunctionExtras.h:56
typename std::enable_if< B, T >::type enable_if_t
Definition: core.h:298
type
Definition: core.h:575
Definition: format-inl.h:32
Definition: BFloat16.h:88
static constexpr const unit_t< compound_unit< energy::joules, inverse< temperature::kelvin >, inverse< substance::moles > > > R(8.3144598)
Gas constant.
std::enable_if_t< wpi::is_trivially_move_constructible< T >::value &&std::is_trivially_destructible< T >::value > EnableIfTrivial
Definition: FunctionExtras.h:70
std::enable_if_t< wpi::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
Definition: FunctionExtras.h:84
std::enable_if_t<!std::is_same< remove_cvref_t< CallableT >, ThisT >::value > EnableUnlessSameType
Definition: FunctionExtras.h:73
typename std::enable_if< B, T >::type enable_if_t
Definition: json.h:207
Definition: AprilTagFieldLayout.h:18
std::is_trivially_copy_constructible< T > is_trivially_copy_constructible
Definition: type_traits.h:99
std::is_trivially_move_constructible< T > is_trivially_move_constructible
Definition: type_traits.h:96
void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment)
Deallocate a buffer of memory with the given size and alignment.
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.
static TrivialCallback Callbacks
Definition: FunctionExtras.h:260
Definition: FunctionExtras.h:252
static NonTrivialCallbacks Callbacks
Definition: FunctionExtras.h:253
Definition: FunctionExtras.h:264
Definition: FunctionExtras.h:91
Definition: STLForwardCompat.h:42