Skip to content

Commit 7620421

Browse files
committed
Update DelegateMQ library
1 parent b7b7c84 commit 7620421

File tree

16 files changed

+976
-173
lines changed

16 files changed

+976
-173
lines changed

DelegateMQ/delegate/Delegate.h

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,149 @@ class DelegateMember<TClass, RetType(Args...)> : public Delegate<RetType(Args...
475475
MemberFunc m_func = nullptr;
476476
};
477477

478+
template <class C, class R>
479+
struct DelegateMemberShared; // Not defined
480+
481+
/// @brief `DelegateMemberShared<>` class synchronously invokes a class member target
482+
/// function using a weak pointer.
483+
/// @details This class is a "safe" version of DelegateMember. It holds a std::weak_ptr
484+
/// to the target. If the target is destroyed, the callback is silently dropped.
485+
/// @tparam TClass The class type that contains the member function.
486+
/// @tparam RetType The return type of the bound delegate function.
487+
/// @tparam Args The argument types of the bound delegate function.
488+
template <class TClass, class RetType, class... Args>
489+
class DelegateMemberShared<TClass, RetType(Args...)> : public Delegate<RetType(Args...)> {
490+
public:
491+
typedef TClass* ObjectPtr;
492+
typedef std::shared_ptr<TClass> SharedPtr;
493+
typedef std::weak_ptr<TClass> WeakPtr;
494+
typedef RetType(TClass::* MemberFunc)(Args...);
495+
typedef RetType(TClass::* ConstMemberFunc)(Args...) const;
496+
using ClassType = DelegateMemberShared<TClass, RetType(Args...)>;
497+
498+
/// @brief Constructor to create a class instance.
499+
/// @param[in] object The target object pointer to store.
500+
/// @param[in] func The target member function to store.
501+
DelegateMemberShared(SharedPtr object, MemberFunc func) { Bind(object, func); }
502+
503+
/// @brief Constructor to create a class instance.
504+
/// @param[in] object The target object pointer to store.
505+
/// @param[in] func The target const member function to store.
506+
DelegateMemberShared(SharedPtr object, ConstMemberFunc func) { Bind(object, func); }
507+
508+
/// @brief Copy constructor.
509+
DelegateMemberShared(const ClassType& rhs) { Assign(rhs); }
510+
511+
/// @brief Move constructor.
512+
DelegateMemberShared(ClassType&& rhs) noexcept : m_object(std::move(rhs.m_object)), m_func(rhs.m_func) { rhs.Clear(); }
513+
514+
/// @brief Default constructor.
515+
DelegateMemberShared() = default;
516+
517+
/// @brief Destructor.
518+
~DelegateMemberShared() { Clear(); }
519+
520+
/// @brief Bind a member function to the delegate.
521+
void Bind(SharedPtr object, MemberFunc func) {
522+
static_assert(!std::is_const<TClass>::value, "Cannot bind non-const function to const object.");
523+
m_object = object; // Implicit conversion from shared_ptr to weak_ptr
524+
m_func = func;
525+
}
526+
527+
/// @brief Bind a const member function to the delegate.
528+
void Bind(SharedPtr object, ConstMemberFunc func) {
529+
m_object = object; // Implicit conversion from shared_ptr to weak_ptr
530+
m_func = reinterpret_cast<MemberFunc>(func);
531+
}
532+
533+
/// @brief Creates a copy of the current object.
534+
virtual ClassType* Clone() const override {
535+
return new(std::nothrow) ClassType(*this);
536+
}
537+
538+
/// @brief Assigns the state of one object to another.
539+
void Assign(const ClassType& rhs) {
540+
m_object = rhs.m_object;
541+
m_func = rhs.m_func;
542+
}
543+
544+
/// @brief Invoke the bound delegate function synchronously.
545+
/// @details SAFELY locks the weak pointer. If object is dead, returns default.
546+
virtual RetType operator()(Args... args) override {
547+
// 1. Try to promote weak_ptr to strong shared_ptr
548+
if (auto strongPtr = m_object.lock())
549+
{
550+
// 2. SUCCESS: Object is alive. Invoke.
551+
if constexpr (std::is_const<TClass>::value)
552+
return std::invoke(reinterpret_cast<ConstMemberFunc>(m_func), strongPtr, std::forward<Args>(args)...);
553+
else
554+
return std::invoke(m_func, strongPtr, std::forward<Args>(args)...);
555+
}
556+
557+
// 3. FAILURE: Object is dead. Silently ignore.
558+
return RetType();
559+
}
560+
561+
/// @brief Assignment operator.
562+
ClassType& operator=(const ClassType& rhs) {
563+
if (&rhs != this) {
564+
Assign(rhs);
565+
}
566+
return *this;
567+
}
568+
569+
/// @brief Move assignment operator.
570+
ClassType& operator=(ClassType&& rhs) noexcept {
571+
if (&rhs != this) {
572+
m_object = std::move(rhs.m_object);
573+
m_func = rhs.m_func;
574+
rhs.Clear();
575+
}
576+
return *this;
577+
}
578+
579+
/// @brief Clear the target function.
580+
virtual void operator=(std::nullptr_t) noexcept {
581+
return Clear();
582+
}
583+
584+
/// @brief Compares two delegate objects for equality.
585+
virtual bool Equal(const DelegateBase& rhs) const override {
586+
auto derivedRhs = dynamic_cast<const ClassType*>(&rhs);
587+
if (!derivedRhs) return false;
588+
589+
// Compare Weak Pointers by locking them first
590+
auto ptr1 = m_object.lock();
591+
auto ptr2 = derivedRhs->m_object.lock();
592+
593+
return (ptr1 == ptr2) && (m_func == derivedRhs->m_func);
594+
}
595+
596+
// Standard operator== overloads
597+
bool operator==(const ClassType& rhs) const noexcept { return Equal(rhs); }
598+
virtual bool operator==(std::nullptr_t) const noexcept override { return Empty(); }
599+
virtual bool operator!=(std::nullptr_t) const noexcept override { return !Empty(); }
600+
friend bool operator==(std::nullptr_t, const ClassType& rhs) noexcept { return rhs.Empty(); }
601+
friend bool operator!=(std::nullptr_t, const ClassType& rhs) noexcept { return !rhs.Empty(); }
602+
603+
/// @brief Check if the delegate is bound (Note: Doesn't check if object is alive).
604+
bool Empty() const noexcept { return m_object.expired() || !m_func; }
605+
606+
/// @brief Clear the target function.
607+
void Clear() noexcept { m_object.reset(); m_func = nullptr; }
608+
609+
explicit operator bool() const noexcept { return !Empty(); }
610+
611+
private:
612+
bool operator<(const ClassType& rhs) const = delete;
613+
614+
/// Weak pointer to the target object.
615+
WeakPtr m_object;
616+
617+
/// Pointer to a member function.
618+
MemberFunc m_func = nullptr;
619+
};
620+
478621
template <class R>
479622
class DelegateFunction; // Not defined
480623

@@ -721,7 +864,7 @@ auto MakeDelegate(const TClass* object, RetType(TClass::* func)(Args... args) co
721864
/// @return A `DelegateMember` shared pointer bound to the specified non-const member function.
722865
template <class TClass, class RetType, class... Args>
723866
auto MakeDelegate(std::shared_ptr<TClass> object, RetType(TClass::* func)(Args... args)) {
724-
return DelegateMember<TClass, RetType(Args...)>(object, func);
867+
return DelegateMemberShared<TClass, RetType(Args...)>(object, func);
725868
}
726869

727870
/// @brief Creates a delegate that binds to a const member function with a shared pointer to the object.
@@ -733,7 +876,7 @@ auto MakeDelegate(std::shared_ptr<TClass> object, RetType(TClass::* func)(Args..
733876
/// @return A `DelegateMember` shared pointer bound to the specified const member function.
734877
template <class TClass, class RetType, class... Args>
735878
auto MakeDelegate(std::shared_ptr<TClass> object, RetType(TClass::* func)(Args... args) const) {
736-
return DelegateMember<TClass, RetType(Args...)>(object, func);
879+
return DelegateMemberShared<TClass, RetType(Args...)>(object, func);
737880
}
738881

739882
/// @brief Creates a delegate that binds to a `std::function`.

0 commit comments

Comments
 (0)