carb/tasking/Delegate.h
File members: carb/tasking/Delegate.h
// Copyright (c) 2021-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 "../delegate/detail/DelegateBase.h"
#include "TaskingUtils.h"
namespace carb
{
namespace tasking
{
namespace detail
{
struct TaskingExec
{
    using Id = TaskContext;
    Id operator()() const noexcept
    {
        auto tasking = carb::getCachedInterface<ITasking>();
        TaskContext taskContext = tasking ? tasking->getTaskContext() : kInvalidTaskContext;
        if (taskContext == kInvalidTaskContext)
        {
            // There won't be overlap here because TaskContext has a bit set in the upper word, and thread IDs are only
            // 32-bit
            static_assert(sizeof(carb::this_thread::getId()) == sizeof(uint32_t), "Invalid assumption");
            taskContext = TaskContext(carb::this_thread::getId());
        }
        return taskContext;
    }
};
} // namespace detail
template <class T>
class Delegate;
template <class T>
class DelegateRef;
template <class... Args>
class Delegate<void(Args...)>
    : public delegate::detail::DelegateBase<::carb::tasking::MutexWrapper, detail::TaskingExec, void(Args...)>
{
    using Base = delegate::detail::DelegateBase<::carb::tasking::MutexWrapper, detail::TaskingExec, void(Args...)>;
public:
    Delegate() = default;
    Delegate(Delegate&& other) : Base(std::move(other))
    {
    }
    Delegate& operator=(Delegate&& other)
    {
        Base::swap(other);
        return *this;
    }
private:
    template <class U>
    friend class DelegateRef;
    // Null constructor, only for DelegateRef use.
    constexpr Delegate(std::nullptr_t) : Base(nullptr)
    {
    }
    // Copy constructor, only for DelegateRef use.
    Delegate(const Delegate& other) : Base(other)
    {
    }
    // Copy-assign operator, only for DelegateRef use.
    Delegate& operator=(const Delegate& other)
    {
        Base::copy(other);
        return *this;
    }
};
template <class... Args>
class DelegateRef<void(Args...)>
{
public:
    using DelegateType = Delegate<void(Args...)>;
    constexpr DelegateRef() noexcept : m_delegate{ nullptr }
    {
    }
    explicit DelegateRef(DelegateType& delegate) : m_delegate(delegate)
    {
    }
    DelegateRef(const DelegateRef& other) : m_delegate(other.m_delegate)
    {
    }
    DelegateRef(DelegateRef&& other) = default;
    ~DelegateRef()
    {
        // The Delegate destructor calls UnbindAll(), which we definitely don't want. So just reset our reference.
        m_delegate.reset();
    }
    DelegateRef& operator=(const DelegateRef& other)
    {
        m_delegate = other.m_delegate;
        return *this;
    }
    DelegateRef& operator=(DelegateRef&& other) = default;
    explicit operator bool() const noexcept
    {
        return m_delegate.isValid();
    }
    void reset()
    {
        m_delegate.reset();
    }
    void reset(DelegateType& delegate)
    {
        m_delegate = delegate;
    }
    void swap(DelegateRef& other)
    {
        m_delegate.swap(other);
    }
    DelegateType* get() const noexcept
    {
        return m_delegate.isValid() ? const_cast<DelegateType*>(&m_delegate) : nullptr;
    }
    DelegateType& operator*() const noexcept
    {
        CARB_ASSERT(*this);
        return const_cast<DelegateType&>(m_delegate);
    }
    DelegateType* operator->() const noexcept
    {
        CARB_ASSERT(*this);
        return const_cast<DelegateType*>(&m_delegate);
    }
private:
    DelegateType m_delegate;
};
template <class Del>
struct RefFromDelegate
{
    using type = DelegateRef<typename Del::FunctionType>;
};
template <class Del>
using RefFromDelegate_t = typename RefFromDelegate<Del>::type;
} // namespace tasking
} // namespace carb