diff --git a/Source/Engine/Core/Delegate.h b/Source/Engine/Core/Delegate.h index 00614a9ff..f71fcb94b 100644 --- a/Source/Engine/Core/Delegate.h +++ b/Source/Engine/Core/Delegate.h @@ -62,7 +62,7 @@ private: struct Lambda { int64 Refs; - void (*Dtor)(void*); + void (*Dtor)(void* callee, Lambda* lambda); }; void* _callee; @@ -78,8 +78,7 @@ private: { if (Platform::InterlockedDecrement(&_lambda->Refs) == 0) { - ((Lambda*)_lambda)->Dtor(_callee); - Allocator::Free(_lambda); + _lambda->Dtor(_callee, _lambda); } } @@ -189,9 +188,10 @@ public: LambdaDtor(); _lambda = (Lambda*)Allocator::Allocate(sizeof(Lambda) + sizeof(T)); _lambda->Refs = 1; - _lambda->Dtor = [](void* callee) -> void + _lambda->Dtor = [](void* callee, Lambda* lambda) -> void { static_cast(callee)->~T(); + Allocator::Free(lambda); }; _function = [](void* callee, Params... params) -> ReturnType { @@ -201,6 +201,45 @@ public: new(_callee) T(lambda); } + /// + /// Binds a lambda with a custom memory allocator. + /// + /// The custom allocation tag. + /// The lambda. + template + void Bind(typename AllocationType::Tag tag, const T& lambda) + { + if (_lambda) + LambdaDtor(); + using AllocationData = typename AllocationType::template Data; + static_assert(AllocationType::HasSwap, "Function lambda binding supports only custom allocators with swap operation."); + + // Allocate lambda (using temp data) + AllocationData tempAlloc(tag); + tempAlloc.Allocate(sizeof(Lambda) + sizeof(AllocationData) + sizeof(T)); + + // Move temp data into the one allocated + AllocationData* dataAlloc = (AllocationData*)(tempAlloc.Get() + sizeof(Lambda)); + new(dataAlloc) AllocationData(); + dataAlloc->Swap(tempAlloc); + + // Initialize lambda + _lambda = (Lambda*)dataAlloc->Get(); + _lambda->Refs = 1; + _lambda->Dtor = [](void* callee, Lambda* lambda) -> void + { + static_cast(callee)->~T(); + AllocationData* dataAlloc = (AllocationData*)((byte*)lambda + sizeof(Lambda)); + dataAlloc->Free(); + }; + _function = [](void* callee, Params... params) -> ReturnType + { + return (*static_cast(callee))(Forward(params)...); + }; + _callee = (byte*)_lambda + sizeof(AllocationData) + sizeof(Lambda); + new(_callee) T(lambda); + } + /// /// Unbinds the function. ///