carb/delegate/detail/DelegateBase.h
File members: carb/delegate/detail/DelegateBase.h
// Copyright (c) 2024, 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 "../../thread/Util.h"
#include <memory>
#include <vector>
namespace carb
{
namespace delegate
{
template <class T>
class DelegateRef;
namespace detail
{
// The default executor class, which works in terms of thread IDs.
struct DefaultExec
{
    using Id = carb::thread::ThreadId;
    Id operator()() const
    {
        return carb::this_thread::getId();
    }
};
template <class M, class E, class T>
class DelegateBase;
template <class Mutex, class Exec, class... Args>
class DelegateBase<Mutex, Exec, void(Args...)>
{
public:
    using FunctionType = void(Args...);
    CARB_STRONGTYPE(Handle, size_t);
    CARB_DOC_CONSTEXPR static Handle kInvalidHandle{ 0 };
    DelegateBase() = default;
    DelegateBase(DelegateBase&& other);
    DelegateBase& operator=(DelegateBase&& other);
    ~DelegateBase();
    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(DelegateBase& other);
protected:
    constexpr DelegateBase(std::nullptr_t);
    DelegateBase(const DelegateBase& copy) : m_impl(copy.m_impl)
    {
    }
    void copy(const DelegateBase& other)
    {
        m_impl = other.m_impl;
    }
    void reset()
    {
        m_impl.reset();
    }
    bool isValid() const noexcept
    {
        return m_impl != nullptr;
    }
private:
    using MutexType = Mutex;
    using ExecType = Exec;
    using ExecutorId = typename Exec::Id;
    // Forward declaration of the base class for bindings.
    struct BaseBinding;
    // Forward declaration of the keyed bindings class.
    template <class Key>
    struct KeyedBinding;
    // The container for storing bindings.
    using Container = carb::container::IntrusiveList<BaseBinding, &BaseBinding::link>;
    // Forward declaration of a call in progress.
    struct ActiveCall;
    // The container for storing active calls.
    using ActiveCallList = carb::container::IntrusiveList<ActiveCall, &ActiveCall::link>;
    // Forward declaration of our internal implementation.
    struct Impl;
    ActiveCall* lastCurrentThreadCall();
    const ActiveCall* lastCurrentThreadCall() const;
    void UnbindInternal(std::unique_lock<Mutex>& g, typename Container::iterator iter);
    static size_t nextHandle();
    std::shared_ptr<Impl> m_impl{ std::make_shared<Impl>() };
};
} // namespace detail
} // namespace delegate
} // namespace carb
#include "DelegateImpl.inl"