omni/Function.h

File members: omni/Function.h

// Copyright (c) 2022-2023, 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 <functional>

#include "detail/FunctionImpl.h"
#include "../carb/detail/NoexceptType.h"

namespace omni
{

using std::bad_function_call;

template <typename Signature>
class function;

template <typename TReturn, typename... TArgs>
class function<TReturn(TArgs...)> : private ::omni::detail::FunctionData
{
    using base_type = ::omni::detail::FunctionData;
    using traits = ::omni::detail::FunctionTraits<TReturn(TArgs...)>;

public:
    using result_type = typename traits::result_type;

public:
    function(std::nullptr_t) noexcept : base_type(nullptr)
    {
    }

    function() noexcept : function(nullptr)
    {
    }

    function(function const& other) = default;

    function(function&& other) noexcept = default;

    function& operator=(std::nullptr_t) noexcept
    {
        reset();
        return *this;
    }

    function& operator=(function const& other) = default;

    function& operator=(function&& other) noexcept = default;

    CARB_DETAIL_PUSH_IGNORE_NOEXCEPT_TYPE()
    template <typename F, typename Assigner = ::omni::detail::FunctionAssigner<traits, F>>
    function(F&& f) : base_type(Assigner{}, std::forward<F>(f))
    {
    }

    template <typename F, typename Assigner = ::omni::detail::FunctionAssigner<traits, F>>
    function& operator=(F&& f)
    {
        return operator=(function{ std::forward<F>(f) });
    }
    CARB_DETAIL_POP_IGNORE_NOEXCEPT_TYPE()

    ~function() noexcept = default;

    TReturn operator()(TArgs... args) const
    {
        if (m_trampoline == nullptr)
            ::omni::detail::null_function_call();

        auto f = reinterpret_cast<TReturn (*)(::omni::detail::FunctionBuffer const*, TArgs...)>(m_trampoline);
        return f(&m_buffer, std::forward<TArgs>(args)...);
    }

    explicit operator bool() const noexcept
    {
        return bool(m_trampoline);
    }

    void swap(function& other) noexcept
    {
        base_type::swap(other);
    }
};

template <typename TReturn, typename... TArgs>
bool operator==(function<TReturn(TArgs...)> const& func, std::nullptr_t) noexcept
{
    return !func;
}

template <typename TReturn, typename... TArgs>
bool operator==(std::nullptr_t, function<TReturn(TArgs...)> const& func) noexcept
{
    return !func;
}

template <typename TReturn, typename... TArgs>
bool operator!=(function<TReturn(TArgs...)> const& func, std::nullptr_t) noexcept
{
    return static_cast<bool>(func);
}

template <typename TReturn, typename... TArgs>
bool operator!=(std::nullptr_t, function<TReturn(TArgs...)> const& func) noexcept
{
    return static_cast<bool>(func);
}

template <typename TReturn, typename... TArgs>
void swap(function<TReturn(TArgs...)>& a, function<TReturn(TArgs...)>& b) noexcept
{
    a.swap(b);
}

} // namespace omni