8 virtual void InplaceCopy(plUInt8* pBuffer)
const = 0;
9 virtual void InplaceMove(plUInt8* pBuffer) = 0;
18template <
typename Function>
22 : m_func(std::move(func))
27 template <typename = typename std::enable_if<std::is_copy_constructible<Function>::value>>
36 if constexpr (std::is_copy_constructible<Function>::value)
42 PL_REPORT_FAILURE(
"The plDelegate stores a lambda that is not copyable. Copying this plDelegate is not supported.");
47 virtual void InplaceCopy(plUInt8* pBuffer)
const override
49 if constexpr (std::is_copy_constructible<Function>::value)
55 PL_REPORT_FAILURE(
"The plDelegate stores a lambda that is not copyable. Copying this plDelegate is not supported.");
59 virtual void InplaceMove(plUInt8* pBuffer)
override
61 if constexpr (std::is_move_constructible<Function>::value)
67 PL_REPORT_FAILURE(
"The plDelegate stores a lambda that is not movable. Moving this plDelegate is not supported.");
75template <
typename R,
class... Args, plUInt32 DataSize>
80 constexpr const void* HeapLambda()
const {
return reinterpret_cast<const void*
>((size_t)-1); }
81 constexpr const void* InplaceLambda()
const {
return reinterpret_cast<const void*
>((size_t)-2); }
85 : m_DispatchFunction(
nullptr)
94 template <
typename Method,
typename Class>
95 PL_FORCE_INLINE
plDelegate(Method method, Class* pInstance)
97 CopyMemberFunctionToInplaceStorage(method);
99 m_Instance.m_Ptr = pInstance;
100 m_DispatchFunction = &DispatchToMethod<Method, Class>;
104 template <
typename Method,
typename Class>
105 PL_FORCE_INLINE
plDelegate(Method method,
const Class* pInstance)
107 CopyMemberFunctionToInplaceStorage(method);
109 m_Instance.m_ConstPtr = pInstance;
110 m_DispatchFunction = &DispatchToConstMethod<Method, Class>;
114 template <
typename Function>
117 static_assert(DataSize >= 16,
"DataSize must be at least 16 bytes");
124 constexpr size_t functionSize =
sizeof(Function);
125 using signature = R(Args...);
126 if constexpr (functionSize <= DataSize && std::is_assignable<signature*&, Function>::value)
131 if constexpr (functionSize > 1)
133 CopyFunctionToInplaceStorage(function);
137 memset(m_Data, 0, DataSize);
140 m_Instance.m_ConstPtr =
nullptr;
141 m_DispatchFunction = &DispatchToFunction<Function>;
146 if constexpr (storageSize <= DataSize)
148 m_Instance.m_ConstPtr = InplaceLambda();
150 memset(m_Data + storageSize, 0, DataSize - storageSize);
151 m_DispatchFunction = &DispatchToInplaceLambda<Function>;
155 m_Instance.m_ConstPtr = HeapLambda();
157 m_pAllocator = pAllocator;
158 memset(m_Data + 2 *
sizeof(
void*), 0, DataSize - 2 *
sizeof(
void*));
159 m_DispatchFunction = &DispatchToHeapLambda<Function>;
171 if (other.IsHeapLambda())
173 m_pAllocator = other.m_pAllocator;
174 m_pLambdaStorage = other.m_pLambdaStorage->Clone(m_pAllocator);
176 else if (other.IsInplaceLambda())
179 pOtherLambdaStorage->InplaceCopy(m_Data);
183 memcpy(m_Data, other.m_Data, DataSize);
186 m_Instance = other.m_Instance;
187 m_DispatchFunction = other.m_DispatchFunction;
194 m_Instance = other.m_Instance;
195 m_DispatchFunction = other.m_DispatchFunction;
197 if (other.IsInplaceLambda())
200 pOtherLambdaStorage->InplaceMove(m_Data);
204 memcpy(m_Data, other.m_Data, DataSize);
207 other.m_Instance.m_Ptr =
nullptr;
208 other.m_DispatchFunction =
nullptr;
209 memset(other.m_Data, 0, DataSize);
213 PL_FORCE_INLINE
void operator=(std::nullptr_t) { Invalidate(); }
218 PL_ASSERT_DEBUG(m_DispatchFunction !=
nullptr,
"Delegate is not bound.");
219 return (*m_DispatchFunction)(*
this, params...);
225 PL_REPORT_FAILURE(
"operator== for plDelegate must not be used. Use IsEqualIfNotHeapAllocated() and read its documentation!");
235 return m_Instance.m_Ptr == other.m_Instance.m_Ptr && m_DispatchFunction == other.m_DispatchFunction &&
236 memcmp(m_Data, other.m_Data, DataSize) == 0;
240 PL_ALWAYS_INLINE
bool IsValid()
const {
return m_DispatchFunction !=
nullptr; }
245 m_DispatchFunction =
nullptr;
248 PL_DELETE(m_pAllocator, m_pLambdaStorage);
250 else if (IsInplaceLambda())
253 pLambdaStorage->~plLambdaDelegateStorageBase();
256 m_Instance.m_Ptr =
nullptr;
257 memset(m_Data, 0, DataSize);
261 PL_ALWAYS_INLINE
void*
GetClassInstance()
const {
return IsComparable() ? m_Instance.m_Ptr :
nullptr; }
264 PL_ALWAYS_INLINE
bool IsComparable()
const {
return m_Instance.m_ConstPtr < InplaceLambda(); }
267 template <
typename Function>
268 PL_FORCE_INLINE
void CopyFunctionToInplaceStorage(Function function)
271 plMemoryUtils::IsAligned(&m_Data, PL_ALIGNMENT_OF(Function)),
"Wrong alignment. Expected {0} bytes alignment", PL_ALIGNMENT_OF(Function));
273 memcpy(m_Data, &function,
sizeof(Function));
274 memset(m_Data +
sizeof(Function), 0, DataSize -
sizeof(Function));
277 template <
typename Method>
278 PL_FORCE_INLINE
void CopyMemberFunctionToInplaceStorage(Method method)
280 static_assert(DataSize >= 16,
"DataSize must be at least 16 bytes");
281 static_assert(
sizeof(Method) <= DataSize,
"Member function pointer must not be bigger than 16 bytes");
283 CopyFunctionToInplaceStorage(method);
290#if PL_ENABLED(PL_COMPILER_MSVC) || (PL_ENABLED(PL_PLATFORM_WINDOWS) && PL_ENABLED(PL_COMPILER_CLANG))
291 *
reinterpret_cast<plUInt32*
>(m_Data + 12) = 0;
295 PL_ALWAYS_INLINE
bool IsInplaceLambda()
const {
return m_Instance.m_ConstPtr == InplaceLambda(); }
296 PL_ALWAYS_INLINE
bool IsHeapLambda()
const {
return m_Instance.m_ConstPtr == HeapLambda(); }
298 template <
typename Method,
typename Class>
299 static PL_FORCE_INLINE R DispatchToMethod(
const SelfType& self, Args... params)
301 PL_ASSERT_DEBUG(self.m_Instance.m_Ptr !=
nullptr,
"Instance must not be null.");
302 Method method = *
reinterpret_cast<Method*
>(&self.m_Data);
303 return (
static_cast<Class*
>(self.m_Instance.m_Ptr)->*method)(params...);
306 template <
typename Method,
typename Class>
307 static PL_FORCE_INLINE R DispatchToConstMethod(
const SelfType& self, Args... params)
309 PL_ASSERT_DEBUG(self.m_Instance.m_ConstPtr !=
nullptr,
"Instance must not be null.");
310 Method method = *
reinterpret_cast<Method*
>(&self.m_Data);
311 return (
static_cast<const Class*
>(self.m_Instance.m_ConstPtr)->*method)(params...);
314 template <
typename Function>
315 static PL_ALWAYS_INLINE R DispatchToFunction(
const SelfType& self, Args... params)
317 return (*
reinterpret_cast<Function*
>(&self.m_Data))(params...);
320 template <
typename Function>
321 static PL_ALWAYS_INLINE R DispatchToHeapLambda(
const SelfType& self, Args... params)
326 template <
typename Function>
327 static PL_ALWAYS_INLINE R DispatchToInplaceLambda(
const SelfType& self, Args... params)
332 using DispatchFunction = R (*)(
const SelfType&, Args...);
333 DispatchFunction m_DispatchFunction;
337 mutable plUInt8 m_Data[DataSize];
351template <
typename Class,
typename R,
typename... Args>
357template <
typename Class,
typename R,
typename... Args>
Base class for all memory allocators.
Definition Allocator.h:23
Base class for plDelegate.
Definition Delegate.h:7
static PL_ALWAYS_INLINE plAllocator * GetDefaultAllocator()
The default allocator can be used for any kind of allocation if no alignment is required.
Definition Basics.h:82
static bool IsAligned(const T *pPtr, size_t uiAlignment)
Checks whether ptr is aligned to a memory address that is a multiple of uiAlignment.
Definition DelegateHelper_inl.h:77
PL_FORCE_INLINE plDelegate(Method method, Class *pInstance)
Constructs the delegate from a member function type and takes the class instance on which to call the...
Definition DelegateHelper_inl.h:95
PL_ALWAYS_INLINE bool IsEqualIfComparable(const SelfType &other) const
Checks whether two delegates are bound to the exact same function, including the class instance.
Definition DelegateHelper_inl.h:233
PL_ALWAYS_INLINE bool operator==(const SelfType &other) const
This function only exists to make code compile, but it will assert when used. Use IsEqualIfNotHeapAll...
Definition DelegateHelper_inl.h:223
PL_FORCE_INLINE void operator=(SelfType &&other)
Moves the data from another delegate.
Definition DelegateHelper_inl.h:191
PL_FORCE_INLINE void operator=(std::nullptr_t)
Resets a delegate to an invalid state.
Definition DelegateHelper_inl.h:213
PL_FORCE_INLINE void Invalidate()
Resets a delegate to an invalid state.
Definition DelegateHelper_inl.h:243
PL_FORCE_INLINE R operator()(Args... params) const
Function call operator. This will call the function that is bound to the delegate,...
Definition DelegateHelper_inl.h:216
PL_FORCE_INLINE void operator=(const SelfType &other)
Copies the data from another delegate.
Definition DelegateHelper_inl.h:167
PL_ALWAYS_INLINE bool IsComparable() const
Returns whether the delegate is comparable with other delegates of the same type. This is not the cas...
Definition DelegateHelper_inl.h:264
PL_FORCE_INLINE plDelegate(Method method, const Class *pInstance)
Constructs the delegate from a member function type and takes the (const) class instance on which to ...
Definition DelegateHelper_inl.h:105
PL_ALWAYS_INLINE void * GetClassInstance() const
Returns the class instance that is used to call a member function pointer on.
Definition DelegateHelper_inl.h:261
PL_ALWAYS_INLINE bool IsValid() const
Returns true when the delegate is bound to a valid non-nullptr function.
Definition DelegateHelper_inl.h:240
PL_FORCE_INLINE plDelegate(Function function, plAllocator *pAllocator=plFoundation::GetDefaultAllocator())
Constructs the delegate from a regular C function type.
Definition DelegateHelper_inl.h:115
A generic delegate class which supports static functions and member functions.
Definition Delegate.h:76
[Internal] Storage for lambdas with captures in plDelegate.
Definition DelegateHelper_inl.h:4
Definition DelegateHelper_inl.h:20
Definition DelegateHelper_inl.h:348