MoveOnlyFunctionImpl.h#
Fully qualified name: omni/detail/MoveOnlyFunctionImpl.h
File members: omni/detail/MoveOnlyFunctionImpl.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.
//
// Purposely missing #pragma once so it can be included multiple times
#if defined DOXYGEN_BUILD
# include "../../carb/Defines.h"
#endif
#if !OMNI_MOF && !defined __INTELLISENSE__
# error Should only be included from MoveOnlyFunction.h
#endif
#include "MoveOnlyFunctionStorage.h"
#ifndef OMNI_MOF_CV
# define OMNI_MOF_CV
#endif
#ifndef OMNI_MOF_REF
# define OMNI_MOF_REF
#endif
#ifndef OMNI_MOF_MOVE
# define OMNI_MOF_MOVE
#endif
#ifndef OMNI_MOF_NOEX
# define OMNI_MOF_NOEX
#endif
namespace omni
{
template <typename T>
class move_only_function;
template <typename Ret, typename... Args>
class move_only_function<Ret(Args...) OMNI_MOF_CV OMNI_MOF_REF OMNI_MOF_NOEX>
{
public:
move_only_function() = default;
move_only_function(std::nullptr_t) noexcept {};
CARB_PREVENT_COPY(move_only_function);
template <typename F CARB_NO_DOC(, typename = std::enable_if_t<!std::is_same_v<std::decay_t<F>, move_only_function>>)>
move_only_function(F&& f)
{
using Ft = std::decay_t<F>;
if constexpr (std::is_function_v<std::remove_pointer_t<Ft>> || std::is_member_pointer_v<Ft>)
{
if (f == nullptr)
{
return;
}
}
m_buf.store<Ft>(std::forward<F>(f));
m_invoker = &_invoke<OMNI_MOF_CV Ft>;
}
move_only_function(move_only_function&& other) noexcept
{
*this = std::move(other);
}
template <typename F CARB_NO_DOC(, typename = std::enable_if_t<!std::is_same_v<std::decay_t<F>, move_only_function>>)>
move_only_function& operator=(F&& f)
{
using Ft = std::decay_t<F>;
if constexpr (std::is_function_v<std::remove_pointer_t<Ft>> || std::is_member_pointer_v<Ft>)
{
if (f == nullptr)
{
*this = nullptr;
return *this;
}
}
m_buf.store<Ft>(std::forward<F>(f));
m_invoker = &_invoke<OMNI_MOF_CV Ft>;
return *this;
}
template <typename F, typename... Args_>
explicit move_only_function(std::in_place_type_t<F>, Args_... args)
{
static_assert(std::is_same_v<std::decay_t<F>, F>);
m_buf.store<F>(std::forward<Args_>(args)...);
m_invoker = &_invoke<OMNI_MOF_CV F>;
}
move_only_function& operator=(move_only_function&& other) noexcept
{
if (this != &other)
{
m_buf = std::move(other.m_buf);
m_invoker = std::exchange(other.m_invoker, nullptr);
}
return *this;
}
move_only_function& operator=(std::nullptr_t) noexcept
{
m_buf = nullptr;
m_invoker = nullptr;
return *this;
}
~move_only_function() = default;
Ret operator()(Args... args) OMNI_MOF_CV OMNI_MOF_REF OMNI_MOF_NOEX
{
return m_invoker(this, std::forward<Args>(args)...);
}
friend bool operator==(const move_only_function& other, std::nullptr_t) noexcept
{
return other.m_invoker == nullptr;
}
friend bool operator!=(const move_only_function& other, std::nullptr_t) noexcept
{
return other.m_invoker != nullptr;
}
explicit operator bool() const noexcept
{
return m_invoker != nullptr;
}
private:
template <typename Ft>
static Ret _invoke(move_only_function OMNI_MOF_CV* self, Args... args) OMNI_MOF_NOEX
{
return std::invoke(OMNI_MOF_MOVE(*self->m_buf.template get<Ft>()), std::forward<Args>(args)...);
}
detail::storage<16> m_buf;
Ret (*m_invoker)(move_only_function OMNI_MOF_CV*, Args...) OMNI_MOF_NOEX = nullptr;
};
#undef OMNI_MOF_CV
#undef OMNI_MOF_REF
#undef OMNI_MOF_MOVE
#undef OMNI_MOF_NOEX
} // namespace omni