Program Listing for carb/delegate/Delegate.h

↰ Return to documentation for carb/delegate/Delegate.h

// Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//

#pragma once

#include "../Defines.h"

#include "../Strong.h"
#include "../container/IntrusiveList.h"
#include "../cpp17/Tuple.h"
#include "../thread/Mutex.h"
#include "../thread/Util.h"

#include <type_traits>
#include <vector>

namespace carb
{

namespace delegate
{


template <class T>
class Delegate;

template <class T>
class DelegateRef;

template <class... Args>
class Delegate<void(Args...)>
{
public:
    CARB_STRONGTYPE(Handle, size_t);
    CARB_DOC_CONSTEXPR static Handle kInvalidHandle{ 0 };

    Delegate() = default;

    Delegate(Delegate&& other);

    Delegate& operator=(Delegate&& other);

    ~Delegate();

    template <class Callable, class... BindArgs>
    Handle Bind(Handle* hOut, Callable&& func, BindArgs&&... args);

    template <class KeyType, class Callable, class... BindArgs>
    void BindWithKey(KeyType&& key, Callable&& func, BindArgs&&... args);

    template <class KeyType>
    bool Unbind(KeyType&& key);

    template <class KeyType>
    bool HasKey(KeyType&& key) const noexcept;

    bool UnbindCurrent();

    void UnbindAll();

    size_t Count() const noexcept;

    bool HasPending() const noexcept;

    bool IsEmpty() const noexcept;

    template <class KeyType>
    std::vector<std::decay_t<KeyType>> GetKeysByType() const;

    void Call(Args... args);

    void operator()(Args... args);

    void swap(Delegate& other);

    CARB_PREVENT_COPY(Delegate);

private:
    template <class U>
    friend class DelegateRef;

    struct BaseBinding;
    template <class Key>
    struct KeyedBinding;
    using Container = carb::container::IntrusiveList<BaseBinding, &BaseBinding::link>;

    struct ActiveCall;
    using ActiveCallList = carb::container::IntrusiveList<ActiveCall, &ActiveCall::link>;

    struct Impl : public std::enable_shared_from_this<Impl>
    {
        mutable carb::thread::mutex m_mutex;
        Container m_entries;
        ActiveCallList m_activeCalls;

        ~Impl();
    };

    constexpr Delegate(std::nullptr_t);
    Delegate(std::shared_ptr<Impl> pImpl);

    ActiveCall* lastCurrentThreadCall();
    const ActiveCall* lastCurrentThreadCall() const;
    void UnbindInternal(std::unique_lock<carb::thread::mutex>& g, typename Container::iterator iter);

    static size_t nextHandle();

    std::shared_ptr<Impl> m_impl{ std::make_shared<Impl>() };
};

template <class... Args>
class DelegateRef<void(Args...)>
{
public:
    using DelegateType = Delegate<void(Args...)>;

    constexpr DelegateRef() noexcept;

    explicit DelegateRef(DelegateType& delegate);

    DelegateRef(const DelegateRef& other);

    DelegateRef(DelegateRef&& other) = default;

    DelegateRef& operator=(const DelegateRef& other);

    DelegateRef& operator=(DelegateRef&& other) = default;

    explicit operator bool() const noexcept;

    void reset();

    void reset(DelegateType& delegate);

    void swap(DelegateRef& other);

    DelegateType* get() const noexcept;

    DelegateType& operator*() const noexcept;

    DelegateType* operator->() const noexcept;

private:
    DelegateType m_delegate;
};

} // namespace delegate

} // namespace carb

#include "DelegateImpl.inl"