LkEngine 0.1.2
 
Loading...
Searching...
No Matches
Delegate.h
1/******************************************************************
2 * LDelegate and LMulticastDelegate
3 *
4 * Implementations for single and multicast delegates.
5 *
6 * The creation of a delegate should use the following macros:
7 * - LK_DECLARE_DELEGATE
8 * - LK_DECLARE_MULTICAST_DELEGATE
9 * - LK_DECLARE_DELEGATE_RET
10 * - LK_DECLARE_EVENT
11 *
12 * TODO:
13 * - Set static names for LMulticastDelegate on declaration.
14 *
15 *******************************************************************/
16#pragma once
17
18#include "DelegateFwd.h"
19
21#include "LkEngine/Core/Template/TypeTrait.h"
22
23#include "LkEngine/Core/LObject/ObjectPtr.h"
24
25namespace LkEngine::Core {
26
27 namespace DelegateCore
28 {
29 static constexpr std::size_t BUFSIZE_NAME = 100;
30
35 static constexpr int INLINE_ALLOCATION_SIZE = 48;
36
37 static void* (*Alloc)(std::size_t Size) = [](std::size_t Size)
38 {
39 return std::malloc(Size);
40 };
41
42 static void(*Free)(void* InHeapPointer) = [](void* InHeapPointer)
43 {
44 std::free(InHeapPointer);
45 };
46 }
47
48 namespace DelegateMemory
49 {
50 using FAllocateCallback = void*(*)(std::size_t Size);
51 using FFreeCallback = void(*)(void* HeapPointer);
52
53 inline void SetAllocationCallbacks(const FAllocateCallback AllocateCallback,
54 const FFreeCallback FreeCallback)
55 {
56 DelegateCore::Alloc = AllocateCallback;
57 DelegateCore::Free = FreeCallback;
58 }
59 }
60
67 {
68 public:
69 IDelegateBase() = default;
70 virtual ~IDelegateBase() noexcept = default;
71
72 virtual const void* GetOwner() const { return nullptr; }
73 virtual void Clone(void* Destination) = 0;
74 };
75
81 template<typename TReturnValue, typename... TArgs>
82 class IDelegate : public IDelegateBase
83 {
84 public:
85 virtual TReturnValue Execute(TArgs&&... Args) = 0;
86 };
87
88
92 template<typename TReturnValue, typename... Args2>
94
100 template<typename TReturnValue, typename... TArgs, typename... Args2>
101 class LStaticDelegate<TReturnValue(TArgs...), Args2...> : public IDelegate<TReturnValue, TArgs...>
102 {
103 public:
104 using DelegateFunction = TReturnValue(*)(TArgs..., Args2...);
105
106 LStaticDelegate(DelegateFunction InFunction, Args2&&... InPayload)
107 : Function(InFunction)
108 , Payload(std::forward<Args2>(InPayload)...)
109 {
110 }
111
112 LStaticDelegate(DelegateFunction InFunction, const std::tuple<Args2...>& InPayload)
113 : Function(InFunction)
114 , Payload(InPayload)
115 {
116 }
117
118 FORCEINLINE virtual TReturnValue Execute(TArgs&&... Args) override
119 {
120 return Execute_Internal(std::forward<TArgs>(Args)..., std::index_sequence_for<Args2...>());
121 }
122
123 virtual void Clone(void* Destination) override
124 {
125 new (Destination) LStaticDelegate(Function, Payload);
126 }
127
128 private:
129 template<std::size_t... Is>
130 FORCEINLINE TReturnValue Execute_Internal(TArgs&&... Args, std::index_sequence<Is...>)
131 {
132 return Function(std::forward<TArgs>(Args)..., std::get<Is>(Payload)...);
133 }
134
135 DelegateFunction Function;
136 std::tuple<Args2...> Payload;
137 };
138
139
143 template<bool bIsConst, typename T, typename TReturnValue, typename... Args2>
145
151 template<bool bIsConst, typename T, typename TReturnValue, typename... TArgs, typename... Args2>
152 class LRawDelegate<bIsConst, T, TReturnValue(TArgs...), Args2...> : public IDelegate<TReturnValue, TArgs...>
153 {
154 public:
155 using DelegateFunction = typename Core::MemberFunction<bIsConst, T, TReturnValue, TArgs..., Args2...>::type;
156
157 LRawDelegate(T* InObjectRef, DelegateFunction InFunction, Args2&&... InPayload)
158 : ObjectRef(InObjectRef)
159 , Function(InFunction)
160 , Payload(std::forward<Args2>(InPayload)...)
161 {
162 LK_CORE_ASSERT(InObjectRef, "Passed object is nullptr");
163 LK_CORE_ASSERT(InFunction, "Passed function is invalid");
164 }
165
166 LRawDelegate(T* InObjectRef, DelegateFunction InFunction, const std::tuple<Args2...>& InPayload)
167 : ObjectRef(InObjectRef)
168 , Function(InFunction)
169 , Payload(InPayload)
170 {
171 LK_CORE_ASSERT(InObjectRef, "Passed object is nullptr");
172 LK_CORE_ASSERT(InFunction, "Passed function is invalid");
173 }
174
175 FORCEINLINE virtual TReturnValue Execute(TArgs&&... Args) override
176 {
177 return Execute_Internal(std::forward<TArgs>(Args)..., std::index_sequence_for<Args2...>());
178 }
179
180 FORCEINLINE virtual const void* GetOwner() const override
181 {
182 return ObjectRef;
183 }
184
185 virtual void Clone(void* Destination) override
186 {
187 new (Destination) LRawDelegate(ObjectRef, Function, Payload);
188 }
189
190 private:
191 template<std::size_t... Is>
192 FORCEINLINE TReturnValue Execute_Internal(TArgs&&... Args, std::index_sequence<Is...>)
193 {
194 return (ObjectRef->*Function)(std::forward<TArgs>(Args)..., std::get<Is>(Payload)...);
195 }
196
197 T* ObjectRef = nullptr;
198 DelegateFunction Function;
199 std::tuple<Args2...> Payload;
200 };
201
202
206 template<typename TLambda, typename TReturnValue, typename... TArgs>
208
214 template<typename TLambda, typename TReturnValue, typename... TArgs, typename... Args2>
215 class LLambdaDelegate<TLambda, TReturnValue(TArgs...), Args2...> : public IDelegate<TReturnValue, TArgs...>
216 {
217 public:
218 explicit LLambdaDelegate(TLambda&& InLambda, Args2&&... InPayload)
219 : Lambda(std::forward<TLambda>(InLambda))
220 , Payload(std::forward<Args2>(InPayload)...)
221 {
222 }
223
224 explicit LLambdaDelegate(const TLambda& InLambda, const std::tuple<Args2...>& InPayload)
225 : Lambda(InLambda)
226 , Payload(InPayload)
227 {
228 }
229
230 FORCEINLINE TReturnValue Execute(TArgs&&... Args) override
231 {
232 return Execute_Internal(std::forward<TArgs>(Args)..., std::index_sequence_for<Args2...>());
233 }
234
235 FORCEINLINE virtual void Clone(void* Destination) override
236 {
237 new (Destination) LLambdaDelegate(Lambda, Payload);
238 }
239
240 private:
241 template<std::size_t... Is>
242 FORCEINLINE TReturnValue Execute_Internal(TArgs&&... Args, std::index_sequence<Is...>)
243 {
244 return (TReturnValue)((Lambda)(std::forward<TArgs>(Args)..., std::get<Is>(Payload)...));
245 }
246
247 TLambda Lambda;
248 std::tuple<Args2...> Payload;
249 };
250
251
257 template<bool bIsConst, typename T, typename TReturnValue, typename... TArgs>
259
260 template<bool bIsConst, typename TReturnValue, typename T, typename... TArgs, typename... Args2>
261 class LSharedPtrDelegate<bIsConst, T, TReturnValue(TArgs...), Args2...> : public IDelegate<TReturnValue, TArgs...>
262 {
263 public:
264 using DelegateFunction = typename Core::MemberFunction<bIsConst, T, TReturnValue, TArgs..., Args2...>::type;
265
266 LSharedPtrDelegate(std::shared_ptr<T> InObjectRef,
267 const DelegateFunction InFunction,
268 Args2&&... InPayload)
269 : ObjectRef(InObjectRef)
270 , Function(InFunction)
271 , Payload(std::forward<Args2>(InPayload)...)
272 {
273 }
274
275 LSharedPtrDelegate(std::weak_ptr<T> InObjectRef,
276 const DelegateFunction InFunction,
277 const std::tuple<Args2...>& InPayload)
278 : ObjectRef(InObjectRef)
279 , Function(InFunction)
280 , Payload(InPayload)
281 {
282 }
283
284 FORCEINLINE virtual TReturnValue Execute(TArgs&&... Args) override
285 {
286 return Execute_Internal(std::forward<TArgs>(Args)..., std::index_sequence_for<Args2...>());
287 }
288
289 FORCEINLINE virtual const void* GetOwner() const override
290 {
291 return (ObjectRef.expired() ? nullptr : ObjectRef.lock().get());
292 }
293
294 FORCEINLINE virtual void Clone(void* Destination) override
295 {
296 new (Destination) LSharedPtrDelegate(ObjectRef, Function, Payload);
297 }
298
299 private:
300 template<std::size_t... Is>
301 TReturnValue Execute_Internal(TArgs&&... Args, std::index_sequence<Is...>)
302 {
303 if (ObjectRef.expired())
304 {
305 return TReturnValue();
306 }
307 else
308 {
309 std::shared_ptr<T> Object = ObjectRef.lock();
310 return (Object.get()->*Function)(std::forward<TArgs>(Args)..., std::get<Is>(Payload)...);
311 }
312 }
313
314 std::weak_ptr<T> ObjectRef;
315 DelegateFunction Function;
316 std::tuple<Args2...> Payload;
317 };
318
319
327 {
328 public:
329 constexpr FDelegateHandle() noexcept
330 : ID(NullID)
331 {
332 }
333
334 explicit FDelegateHandle(bool) noexcept
335 : ID(GetNewID())
336 {
337 }
338
339 ~FDelegateHandle() noexcept = default;
340
341 FDelegateHandle(const FDelegateHandle& Other) = default;
342 FDelegateHandle& operator=(const FDelegateHandle& Other) = default;
343
344 FDelegateHandle(FDelegateHandle&& Other) noexcept
345 : ID(Other.ID)
346 {
347 Other.Reset();
348 }
349
350 FDelegateHandle& operator=(FDelegateHandle&& Other) noexcept
351 {
352 ID = Other.ID;
353 Other.Reset();
354
355 return *this;
356 }
357
358 FORCEINLINE operator bool() const noexcept
359 {
360 return IsValid();
361 }
362
363 FORCEINLINE bool operator==(const FDelegateHandle& Other) const noexcept
364 {
365 return (ID == Other.ID);
366 }
367
368 FORCEINLINE bool operator<(const FDelegateHandle& Other) const noexcept
369 {
370 return (ID < Other.ID);
371 }
372
373 FORCEINLINE bool IsValid() const noexcept
374 {
375 return (ID != NullID);
376 }
377
378 FORCEINLINE void Reset() noexcept
379 {
380 ID = NullID;
381 }
382
383 inline static constexpr unsigned int NullID = std::numeric_limits<unsigned int>::max();
384
385 private:
386 unsigned int ID = 0;
387
389 inline static unsigned int IDCounter = 0;
390
391 FORCEINLINE static int GetNewID()
392 {
393 const unsigned int Output = FDelegateHandle::IDCounter++;
394 if (FDelegateHandle::IDCounter == NullID)
395 {
396 FDelegateHandle::IDCounter = 0;
397 }
398
399 return Output;
400 }
401 };
402
410 template<size_t MaxStackSize>
412 {
413 public:
414 constexpr LInlineAllocator() noexcept
415 : Size(0)
416 {
417 static_assert(MaxStackSize > sizeof(void*), "The stack size is too small");
418 }
419
420 ~LInlineAllocator() noexcept
421 {
422 Free();
423 }
424
426 : Size(0)
427 {
428 if (Other.HasAllocation())
429 {
430 /* Deep copy. */
431 memcpy(Allocate(Other.Size), Other.GetAllocation(), Other.Size);
432 }
433
434 Size = Other.Size;
435 }
436
437 LInlineAllocator(LInlineAllocator&& Other) noexcept
438 : Size(Other.Size)
439 {
440 Other.Size = 0;
441
442 if (Size > MaxStackSize)
443 {
444 std::swap(HeapPointer, Other.HeapPointer);
445 }
446 else
447 {
448 memcpy(Buffer, Other.Buffer, Size);
449 }
450 }
451
452 LInlineAllocator& operator=(const LInlineAllocator& Other)
453 {
454 if (Other.HasAllocation())
455 {
456 /* Deep copy. */
457 memcpy(Allocate(Other.Size), Other.GetAllocation(), Other.Size);
458 }
459
460 Size = Other.Size;
461
462 return *this;
463 }
464
465 LInlineAllocator& operator=(LInlineAllocator&& Other) noexcept
466 {
467 Free();
468
469 Size = Other.Size;
470 Other.Size = 0;
471
472 if (Size > MaxStackSize)
473 {
474 std::swap(HeapPointer, Other.HeapPointer);
475 }
476 else
477 {
478 memcpy(Buffer, Other.Buffer, Size);
479 }
480
481 return *this;
482 }
483
490 FORCEINLINE void* Allocate(const size_t InSize)
491 {
492 if (Size != InSize)
493 {
494 Free();
495 Size = InSize;
496
497 if (InSize > MaxStackSize)
498 {
499 HeapPointer = DelegateCore::Alloc(InSize);
500 return HeapPointer;
501 }
502 }
503
504 return (void*)Buffer;
505 }
506
512 FORCEINLINE void Free()
513 {
514 if (Size > MaxStackSize)
515 {
516 DelegateCore::Free(HeapPointer);
517 }
518
519 Size = 0;
520 }
521
527 FORCEINLINE void* GetAllocation() const
528 {
529 if (HasAllocation())
530 {
531 return (HasHeapAllocation() ? HeapPointer : (void*)Buffer);
532 }
533 else
534 {
535 return nullptr;
536 }
537 }
538
539 FORCEINLINE size_t GetSize() const { return Size; }
540
541 FORCEINLINE bool HasAllocation() const
542 {
543 return (Size > 0);
544 }
545
546 FORCEINLINE bool HasHeapAllocation() const
547 {
548 return (Size > MaxStackSize);
549 }
550
551 private:
552 union
553 {
554 char Buffer[MaxStackSize] = {};
555 void* HeapPointer;
556 };
557
558 size_t Size = 0;
559 };
560
561
568 {
569 public:
570 constexpr LDelegateBase() noexcept
571 : Allocator()
572 {
573 }
574
575 virtual ~LDelegateBase() noexcept
576 {
577 Release();
578 }
579
580 LDelegateBase(const LDelegateBase& Other)
581 {
582 if (Other.Allocator.HasAllocation())
583 {
584 Allocator.Allocate(Other.Allocator.GetSize());
585 Other.GetDelegate()->Clone(Allocator.GetAllocation());
586 }
587 }
588
589 LDelegateBase(LDelegateBase&& Other) noexcept
590 : Allocator(std::move(Other.Allocator))
591 {
592 }
593
597 FORCEINLINE bool IsBound() const
598 {
599 return Allocator.HasAllocation();
600 }
601
602 protected:
603 LDelegateBase& operator=(const LDelegateBase& Other)
604 {
605 Release();
606 if (Other.Allocator.HasAllocation())
607 {
608 Allocator.Allocate(Other.Allocator.GetSize());
609 Other.GetDelegate()->Clone(Allocator.GetAllocation());
610 }
611
612 return *this;
613 }
614
615 LDelegateBase& operator=(LDelegateBase&& Other) noexcept
616 {
617 Release();
618 Allocator = std::move(Other.Allocator);
619
620 return *this;
621 }
622
623 FORCEINLINE const void* GetOwner() const
624 {
625 return (Allocator.HasAllocation() ? GetDelegate()->GetOwner() : nullptr);
626 }
627
628 FORCEINLINE size_t GetSize() const
629 {
630 return Allocator.GetSize();
631 }
632
633 FORCEINLINE void ClearIfBoundTo(void* InObject)
634 {
635 if (InObject && IsBoundTo(InObject))
636 {
637 Release();
638 }
639 }
640
641 FORCEINLINE void Clear()
642 {
643 Release();
644 }
645
646 FORCEINLINE bool IsBoundTo(void* InObject) const
647 {
648 if (!InObject || !Allocator.HasAllocation())
649 {
650 return false;
651 }
652
653 return (GetDelegate()->GetOwner() == InObject);
654 }
655
656 protected:
657 FORCEINLINE void Release()
658 {
659 if (Allocator.HasAllocation())
660 {
661 GetDelegate()->~IDelegateBase();
662 Allocator.Free();
663 }
664 }
665
666 IDelegateBase* GetDelegate() const
667 {
668 return static_cast<IDelegateBase*>(Allocator.GetAllocation());
669 }
670
671 LInlineAllocator<DelegateCore::INLINE_ALLOCATION_SIZE> Allocator;
672 };
673
674
680 template<TStringLiteral DelegateName, typename TReturnValue, typename... TArgs>
682 {
683 public:
684 LDelegate() = default;
685 ~LDelegate() = default;
686
687 private:
688 template<typename T, typename... Args2>
689 using ConstMemberFunction = typename Core::MemberFunction<true, T, TReturnValue, TArgs..., Args2...>::type;
690
691 template<typename T, typename... Args2>
692 using NonConstMemberFunction = typename Core::MemberFunction<false, T, TReturnValue, TArgs..., Args2...>::type;
693
694 using TDelegateInterface = IDelegate<TReturnValue, TArgs...>;
695
696 public:
702 [[nodiscard]] FORCEINLINE TReturnValue Execute(TArgs... Args) const
703 {
704 LK_CORE_VERIFY(Allocator.HasAllocation(), "Delegate '{}' is not bound", typeid(this).name());
705 return ((TDelegateInterface*)GetDelegate())->Execute(std::forward<TArgs>(Args)...);
706 }
707
714 [[nodiscard]] FORCEINLINE TReturnValue ExecuteIfBound(TArgs... Args) const
715 {
716 if (IsBound())
717 {
718 return ((TDelegateInterface*)GetDelegate())->Execute(std::forward<TArgs>(Args)...);
719 }
720
721 return TReturnValue();
722 }
723
724 private:
725 template<typename T, typename... TArgs2>
726 [[nodiscard]] static LDelegate CreateRaw(T* InObject, NonConstMemberFunction<T, TArgs2...> InFunction, TArgs2... Args)
727 {
728 LDelegate Handler;
729 Handler.Bind_Internal<LRawDelegate<false, T, TReturnValue(TArgs...), TArgs2...>>(
730 InObject,
731 InFunction,
732 std::forward<TArgs2>(Args)...
733 );
734
735 return Handler;
736 }
737
738 template<typename T, typename... TArgs2>
739 [[nodiscard]] static LDelegate CreateRaw(T* InObject, ConstMemberFunction<T, TArgs2...> InFunction, TArgs2... Args)
740 {
741 LDelegate Handler;
742 Handler.Bind_Internal<LRawDelegate<true, T, TReturnValue(TArgs...), TArgs2...>>(InObject, InFunction, std::forward<TArgs2>(Args)...);
743 return Handler;
744 }
745
746 template<typename... TArgs2>
747 [[nodiscard]] static LDelegate CreateStatic(TReturnValue(*InFunction)(TArgs..., TArgs2...), TArgs2... Args)
748 {
749 LDelegate Handler;
750 Handler.Bind_Internal<LStaticDelegate<TReturnValue(TArgs...), TArgs2...>>(InFunction, std::forward<TArgs2>(Args)...);
751 return Handler;
752 }
753
754 template<typename T, typename... TArgs2>
755 [[nodiscard]] static LDelegate CreateShared(const std::shared_ptr<T>& ObjectRef,
756 NonConstMemberFunction<T, TArgs2...> InFunction,
757 TArgs2... Args)
758 {
759 LDelegate Handler;
760 Handler.Bind_Internal<LSharedPtrDelegate<false, T, TReturnValue(TArgs...), TArgs2...>>(
761 ObjectRef,
762 InFunction,
763 std::forward<TArgs2>(Args)...
764 );
765
766 return Handler;
767 }
768
769 template<typename T, typename... TArgs2>
770 [[nodiscard]] static LDelegate CreateShared(const std::shared_ptr<T>& ObjectRef,
771 ConstMemberFunction<T, TArgs2...> InFunction,
772 TArgs2... Args)
773 {
774 LDelegate Handler;
775 Handler.Bind_Internal<LSharedPtrDelegate<true, T, TReturnValue(TArgs...), TArgs2...>>(
776 ObjectRef,
777 InFunction,
778 std::forward<TArgs2>(Args)...
779 );
780
781 return Handler;
782 }
783
784 template<typename TLambda, typename... TArgs2>
785 [[nodiscard]] static LDelegate CreateLambda(TLambda&& InLambda, TArgs2... Args)
786 {
787 using LambdaType = std::decay_t<TLambda>;
788 LDelegate Handler;
789 Handler.Bind_Internal<LLambdaDelegate<LambdaType, TReturnValue(TArgs...), TArgs2...>>(
790 std::forward<LambdaType>(InLambda),
791 std::forward<TArgs2>(Args)...
792 );
793
794 return Handler;
795 }
796
797 public:
798 /* Bind: Raw, non-const member function. */
799 template<typename T, typename... TArgs2>
800 void Bind(T* ObjectRef, NonConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
801 {
802 static_assert(!std::is_const_v<T>, "Non-const function cannot be bound on a const object");
803 *this = CreateRaw<T, TArgs2...>(ObjectRef, InFunction, std::forward<TArgs2>(Args)...);
804 }
805
806 /* Bind: Raw, const member function. */
807 template<typename T, typename... TArgs2>
808 void Bind(T* ObjectRef, ConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
809 {
810 *this = CreateRaw<T, TArgs2...>(ObjectRef, InFunction, std::forward<TArgs2>(Args)...);
811 }
812
813 /* Bind: Static. */
814 template<typename... TArgs2>
815 void Bind(TReturnValue(*InFunction)(TArgs..., TArgs2...), TArgs2&&... Args)
816 {
817 *this = CreateStatic<TArgs2...>(InFunction, std::forward<TArgs2>(Args)...);
818 }
819
820 /* Bind: Lambda. */
821 template<typename LambdaType, typename... Args2>
822 void Bind(LambdaType&& InLambda, Args2&&... args)
823 {
824 *this = CreateLambda<LambdaType, Args2...>(std::forward<LambdaType>(InLambda), std::forward<Args2>(args)...);
825 }
826
827 /* Bind: Shared Pointer, non-const member function. */
828 template<typename T, typename... Args2>
829 void Bind(std::shared_ptr<T> ObjectRef, NonConstMemberFunction<T, Args2...> InFunction, Args2&&... args)
830 {
831 static_assert(!std::is_const_v<T>, "Attempted to bind a non-const member function on a const object reference");
832 *this = CreateShared<T, Args2...>(ObjectRef, InFunction, std::forward<Args2>(args)...);
833 }
834
835 /* Bind: Shared Pointer, const member function. */
836 template<typename T, typename... Args2>
837 void Bind(std::shared_ptr<T> ObjectRef, ConstMemberFunction<T, Args2...> InFunction, Args2&&... args)
838 {
839 *this = CreateShared<T, Args2...>(ObjectRef, InFunction, std::forward<Args2>(args)...);
840 }
841
842 private:
843 template<typename T, typename... TBindArgs>
844 FORCEINLINE void Bind_Internal(TBindArgs&&... Args)
845 {
846 Release();
847 void* AllocPointer = Allocator.Allocate(sizeof(T));
848 new (AllocPointer) T(std::forward<TBindArgs>(Args)...);
849 }
850
851 static std::string_view GetStaticName() { return StaticName; }
852
853 private:
855 #if defined(LK_ENGINE_MSVC)
856 template<typename... TArgs>
857 #elif defined(LK_ENGINE_GCC) || defined(LK_ENGINE_CLANG)
858 template<typename... TArgs2>
859 #endif
860 friend class LMulticastDelegate;
861
862 inline static constexpr TStringLiteral StaticName = DelegateName;
863 };
864
865
871 template<typename... TArgs>
873 {
874 private:
875 template<typename T, typename... TArgs2>
876 using ConstMemberFunction = typename Core::MemberFunction<true, T, void, TArgs..., TArgs2...>::type;
877
878 template<typename T, typename... TArgs2>
879 using NonConstMemberFunction = typename Core::MemberFunction<false, T, void, TArgs..., TArgs2...>::type;
880
881 public:
882 using TDelegate = LDelegate<"MulticastComponent", void, TArgs...>;
883
884 constexpr LMulticastDelegate() : Locks(0) {}
885 ~LMulticastDelegate() noexcept = default;
886
887 LMulticastDelegate(const LMulticastDelegate& Other) = default;
888 LMulticastDelegate(LMulticastDelegate&& Other) noexcept
889 : Dispatchers(std::move(Other.Dispatchers))
890 , Locks(std::move(Other.Locks))
891 {
892 }
893
894 LMulticastDelegate& operator=(const LMulticastDelegate& Other) = default;
895
896 LMulticastDelegate& operator=(LMulticastDelegate&& Other) noexcept
897 {
898 Dispatchers = std::move(Other.Dispatchers);
899 Locks = std::move(Other.Locks);
900 return *this;
901 }
902
908 FORCEINLINE void Broadcast(TArgs... Args)
909 {
910 Lock();
911 {
912 for (size_t i = 0; i < Dispatchers.size(); ++i)
913 {
914 if (Dispatchers[i].Handle.IsValid())
915 {
916 Dispatchers[i].Callback.Execute(Args...);
917 }
918 }
919 }
920 Unlock();
921 }
922
928 FORCEINLINE bool Remove(FDelegateHandle& Handle)
929 {
930 if (Handle.IsValid())
931 {
932 for (size_t i = 0; i < Dispatchers.size(); ++i)
933 {
934 if (Dispatchers[i].Handle == Handle)
935 {
936 if (IsLocked())
937 {
938 Dispatchers[i].Callback.Clear();
939 }
940 else
941 {
942 std::swap(Dispatchers[i], Dispatchers[Dispatchers.size() - 1]);
943 Dispatchers.pop_back();
944 }
945
946 Handle.Reset();
947 return true;
948 }
949 }
950 }
951
952 return false;
953 }
954
960 FORCEINLINE void RemoveAll()
961 {
962 if (IsLocked())
963 {
964 for (FDelegateHandlerPair& Handler : Dispatchers)
965 {
966 Handler.Callback.Clear();
967 }
968 }
969 else
970 {
971 Dispatchers.clear();
972 }
973 }
974
980 FORCEINLINE size_t GetSize() const { return Dispatchers.size(); }
981
982 FORCEINLINE std::string_view GetName() const { return typeid(decltype(this)).name(); }
983
984 FORCEINLINE std::string ToString() const
985 {
986 #if 0
987 return LK_FMT_LIB::format("\n[Multicast Delegate]\n"
988 " - Name: {}\n"
989 " - Raw Name: {}\n",
990 TypeName, typeid(*this).raw_name());
991 #endif
992 return "MulticastDelegate::FIXME";
993 }
994
996 template<typename T, typename... TArgs2>
997 FDelegateHandle Add(T* ObjectRef, NonConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
998 {
999 return AddHandler(TDelegate::CreateRaw(ObjectRef, InFunction, std::forward<TArgs2>(Args)...));
1000 }
1001
1003 template<typename T, typename... TArgs2>
1004 FDelegateHandle Add(T* ObjectRef, ConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
1005 {
1006 return AddHandler(TDelegate::CreateRaw(ObjectRef, InFunction, std::forward<TArgs2>(Args)...));
1007 }
1008
1010 template<typename LambdaType, typename... TArgs2>
1011 FDelegateHandle Add(LambdaType&& InLambda, TArgs2&&... LambdaArgs)
1012 {
1013 return AddHandler(TDelegate::CreateLambda(std::forward<LambdaType>(InLambda), std::forward<TArgs2>(LambdaArgs)...));
1014 }
1015
1017 template<typename T, typename... TArgs2>
1018 FDelegateHandle Add(std::shared_ptr<T> ObjectRef, NonConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
1019 {
1020 return AddHandler(TDelegate::CreateShared(ObjectRef, InFunction, std::forward<TArgs2>(Args)...));
1021 }
1022
1024 template<typename T, typename... TArgs2>
1025 FDelegateHandle Add(std::shared_ptr<T> ObjectRef, ConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
1026 {
1027 return AddHandler(TDelegate::CreateShared(ObjectRef, InFunction, std::forward<TArgs2>(Args)...));
1028 }
1029
1031 template<typename T, typename... TArgs2>
1032 FDelegateHandle Add(TObjectPtr<T> ObjectRef, NonConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
1033 {
1034 return AddHandler(TDelegate::CreateRaw(ObjectRef.Get(), InFunction, std::forward<TArgs2>(Args)...));
1035 }
1036
1038 template<typename T, typename... TArgs2>
1039 FDelegateHandle Add(TObjectPtr<T> ObjectRef, ConstMemberFunction<T, TArgs2...> InFunction, TArgs2&&... Args)
1040 {
1041 return AddHandler(TDelegate::CreateRaw(ObjectRef.Get(), InFunction, std::forward<TArgs2>(Args)...));
1042 }
1043
1045 template<typename... TArgs2>
1046 FDelegateHandle Add(void(*InFunction)(TArgs..., TArgs2...), TArgs2&&... Args)
1047 {
1048 return AddHandler(TDelegate::CreateStatic(InFunction, std::forward<TArgs2>(Args)...));
1049 }
1050
1051 private:
1052 template<typename T>
1053 FDelegateHandle operator+=(T&& LHS)
1054 {
1055 return AddHandler(TDelegate::CreateLambda(std::move(LHS)));
1056 }
1057
1058 FDelegateHandle operator+=(TDelegate&& InHandler) noexcept
1059 {
1060 return AddHandler(std::forward<TDelegate>(InHandler));
1061 }
1062
1063 bool operator-=(FDelegateHandle& InHandle)
1064 {
1065 return Remove(InHandle);
1066 }
1067
1068 FORCEINLINE FDelegateHandle AddHandler(TDelegate&& Handler) noexcept
1069 {
1070 for (size_t i = 0; i < Dispatchers.size(); ++i)
1071 {
1072 if (Dispatchers[i].Handle.IsValid() == false)
1073 {
1074 Dispatchers[i] = FDelegateHandlerPair(FDelegateHandle(true), std::move(Handler));
1075
1076 return Dispatchers[i].Handle;
1077 }
1078 }
1079
1080 Dispatchers.emplace_back(FDelegateHandle(true), std::move(Handler));
1081
1082 return Dispatchers.back().Handle;
1083 }
1084
1090 FORCEINLINE void RemoveObject(void* InObjectRef)
1091 {
1092 if (InObjectRef)
1093 {
1094 for (size_t i = 0; i < Dispatchers.size(); ++i)
1095 {
1096 if (Dispatchers[i].Callback.GetOwner() == InObjectRef)
1097 {
1098 if (IsLocked())
1099 {
1100 Dispatchers[i].Callback.Clear();
1101 }
1102 else
1103 {
1104 std::swap(Dispatchers[i], Dispatchers[Dispatchers.size() - 1]);
1105 Dispatchers.pop_back();
1106 }
1107 }
1108 }
1109 }
1110 }
1111
1112 FORCEINLINE bool IsBoundTo(const FDelegateHandle& Handle) const
1113 {
1114 if (Handle.IsValid())
1115 {
1116 for (size_t i = 0; i < Dispatchers.size(); ++i)
1117 {
1118 if (Dispatchers[i].Handle == Handle)
1119 {
1120 return true;
1121 }
1122 }
1123 }
1124
1125 return false;
1126 }
1127
1128 FORCEINLINE void Compress(const size_t MaxSpace = 0)
1129 {
1130 if (IsLocked() == false)
1131 {
1132 size_t ToDelete = 0;
1133 for (size_t i = 0; i < Dispatchers.size() - ToDelete; i++)
1134 {
1135 if (!Dispatchers[i].Handle.IsValid())
1136 {
1137 std::swap(Dispatchers[i], Dispatchers[ToDelete]);
1138 ToDelete++;
1139 }
1140 }
1141
1142 if (ToDelete > MaxSpace)
1143 {
1144 Dispatchers.resize(Dispatchers.size() - ToDelete);
1145 }
1146 }
1147 }
1148
1149 private:
1150 FORCEINLINE void Lock()
1151 {
1152 Locks++;
1153 }
1154
1155 FORCEINLINE void Unlock()
1156 {
1157 LK_CORE_ASSERT(Locks > 0, "Cannot unlock, locks is {}", Locks);
1158 Locks--;
1159 }
1160
1166 FORCEINLINE bool IsLocked() const { return (Locks > 0); }
1167
1173 struct FDelegateHandlerPair
1174 {
1175 FDelegateHandle Handle;
1176 TDelegate Callback;
1177
1178 FDelegateHandlerPair()
1179 : Handle(false)
1180 {
1181 }
1182
1183 FDelegateHandlerPair(const FDelegateHandle& InHandle, const TDelegate& InCallback)
1184 : Handle(InHandle)
1185 , Callback(InCallback)
1186 {
1187 }
1188
1189 FDelegateHandlerPair(const FDelegateHandle& InHandle, TDelegate&& InCallback)
1190 : Handle(InHandle)
1191 , Callback(std::move(InCallback))
1192 {
1193 }
1194 };
1195
1196 private:
1197 std::vector<FDelegateHandlerPair> Dispatchers{};
1198 uint32_t Locks = 0;
1199 };
1200}
Core macros used by the entire engine.
Definition Delegate.h:67
Definition Delegate.h:83
Definition Delegate.h:568
FORCEINLINE bool IsBound() const
Check if the delegate is bound.
Definition Delegate.h:597
Definition Delegate.h:682
FORCEINLINE TReturnValue ExecuteIfBound(TArgs... Args) const
Definition Delegate.h:714
FORCEINLINE TReturnValue Execute(TArgs... Args) const
Definition Delegate.h:702
Definition Delegate.h:412
FORCEINLINE void * Allocate(const size_t InSize)
Definition Delegate.h:490
FORCEINLINE void Free()
Definition Delegate.h:512
FORCEINLINE void * GetAllocation() const
Definition Delegate.h:527
Definition Delegate.h:207
Definition Delegate.h:873
FDelegateHandle Add(LambdaType &&InLambda, TArgs2 &&... LambdaArgs)
Definition Delegate.h:1011
FORCEINLINE bool Remove(FDelegateHandle &Handle)
Definition Delegate.h:928
FDelegateHandle Add(T *ObjectRef, NonConstMemberFunction< T, TArgs2... > InFunction, TArgs2 &&... Args)
Definition Delegate.h:997
FORCEINLINE void RemoveAll()
Definition Delegate.h:960
FDelegateHandle Add(TObjectPtr< T > ObjectRef, ConstMemberFunction< T, TArgs2... > InFunction, TArgs2 &&... Args)
Definition Delegate.h:1039
FDelegateHandle Add(void(*InFunction)(TArgs..., TArgs2...), TArgs2 &&... Args)
Definition Delegate.h:1046
FDelegateHandle Add(std::shared_ptr< T > ObjectRef, ConstMemberFunction< T, TArgs2... > InFunction, TArgs2 &&... Args)
Definition Delegate.h:1025
FDelegateHandle Add(TObjectPtr< T > ObjectRef, NonConstMemberFunction< T, TArgs2... > InFunction, TArgs2 &&... Args)
Definition Delegate.h:1032
FDelegateHandle Add(T *ObjectRef, ConstMemberFunction< T, TArgs2... > InFunction, TArgs2 &&... Args)
Definition Delegate.h:1004
FORCEINLINE void Broadcast(TArgs... Args)
Definition Delegate.h:908
FORCEINLINE size_t GetSize() const
Definition Delegate.h:980
FDelegateHandle Add(std::shared_ptr< T > ObjectRef, NonConstMemberFunction< T, TArgs2... > InFunction, TArgs2 &&... Args)
Definition Delegate.h:1018
Definition Delegate.h:144
Definition Delegate.h:258
Definition Delegate.h:93
Definition ObjectPtr.h:102
Definition UUID.h:33
Definition Delegate.h:327
Definition TypeTrait.h:113
Definition TypeTrait.h:48