omni/core/IWeakObject.h
File members: omni/core/IWeakObject.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 <carb/cpp/Atomic.h> // atomic_ref
#include <carb/detail/DeferredLoad.h>
#include <omni/core/Api.h> // OMNI_API
#include <omni/core/Assert.h>
#include <omni/core/IObject.h>
#include <limits>
namespace omni
{
namespace core
{
class IWeakObject;
class IWeakObject_abi;
class IWeakObjectControlBlock;
class IWeakObjectControlBlock_abi;
class IWeakObjectControlBlock_abi
: public omni::core::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.core.IWeakObjectControlBlock")>
{
protected:
virtual IObject* getObject_abi() noexcept = 0;
};
class IWeakObject_abi : public omni::core::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.core.IWeakObject")>
{
protected:
virtual OMNI_ATTR("not_null") IWeakObjectControlBlock* getWeakObjectControlBlock_abi() noexcept = 0;
};
} // namespace core
} // namespace omni
#define OMNI_BIND_INCLUDE_INTERFACE_DECL
#include <omni/core/IWeakObject.gen.h>
namespace omni
{
namespace core
{
class IWeakObjectControlBlock : public omni::core::Generated<omni::core::IWeakObjectControlBlock_abi>
{
};
class IWeakObject : public omni::core::Generated<omni::core::IWeakObject_abi>
{
};
#ifdef CARB_DOC_BUILD
#endif
template <typename T>
class WeakPtr
{
public:
WeakPtr(std::nullptr_t = nullptr) noexcept
{
}
WeakPtr(const omni::core::ObjectPtr<T>& strong) noexcept
{
if (strong)
{
m_ref = strong->getWeakObjectControlBlock();
}
}
WeakPtr(T* strong) noexcept
{
if (strong)
{
m_ref = strong->getWeakObjectControlBlock();
}
}
WeakPtr(const WeakPtr& other) noexcept = default;
WeakPtr(WeakPtr&& other) noexcept = default;
~WeakPtr() noexcept = default;
WeakPtr& operator=(const WeakPtr& other) noexcept = default;
WeakPtr& operator=(WeakPtr&& other) noexcept = default;
omni::core::ObjectPtr<T> getObjectPtr() const noexcept
{
if (m_ref)
{
return m_ref->getObject().template as<T>();
}
return nullptr;
}
omni::core::ObjectPtr<T> lock() const noexcept
{
if (m_ref)
{
return m_ref->getObject().template as<T>();
}
return nullptr;
}
private:
ObjectPtr<IWeakObjectControlBlock> m_ref;
};
#ifndef DOXYGEN_BUILD
namespace detail
{
enum class WeakObjectControlBlockOp
{
eIncrementStrong = 0,
eDecrementStrong = 1,
eDecrementWeak = 2,
eGetStrongCount = 3, // for testing
eGetWeakCount = 4, // for testing
eHasControlBlock = 5, // for testing
};
} // namespace detail
#endif // DOXYGEN_BUILD
} // namespace core
} // namespace omni
// carb.dll C-ABI to hide the implementation details of a weak object's control block. see IWeakObject's class docs for
// motivation.
#ifndef DOXYGEN_BUILD
# if CARB_REQUIRE_LINKED
OMNI_API omni::core::IWeakObjectControlBlock* omniWeakObjectGetOrCreateControlBlock(omni::core::IObject* obj,
uintptr_t* refCountOrEncodedPtr);
OMNI_API uint32_t omniWeakObjectControlBlockOp(uintptr_t* refCountOrEncodedPtr, omni::core::WeakObjectControlBlockOp op);
# else
OMNI_API omni::core::IWeakObjectControlBlock* omniWeakObjectGetOrCreateControlBlock(omni::core::IObject* obj,
uintptr_t* refCountOrEncodedPtr)
CARB_ATTRIBUTE(weak);
OMNI_API uint32_t omniWeakObjectControlBlockOp(uintptr_t* refCountOrEncodedPtr,
omni::core::detail::WeakObjectControlBlockOp op) CARB_ATTRIBUTE(weak);
# endif
#endif // DOXYGEN_BUILD
namespace omni
{
namespace core
{
#ifndef DOXYGEN_BUILD
namespace detail
{
CARB_DETAIL_DEFINE_DEFERRED_LOAD(loadWeakObjectGetOrCreateControlBlock,
omniWeakObjectGetOrCreateControlBlock,
(omni::core::IWeakObjectControlBlock * (*)(omni::core::IObject*, uintptr_t*)));
inline omni::core::IWeakObjectControlBlock* getOrCreateWeakObjectControlBlock(omni::core::IObject* obj,
uintptr_t* refCountOrEncodedPtr)
{
auto impl = detail::loadWeakObjectGetOrCreateControlBlock();
OMNI_ASSERT(impl);
return impl(obj, refCountOrEncodedPtr);
}
CARB_DETAIL_DEFINE_DEFERRED_LOAD(loadWeakObjectControlBlockOp,
omniWeakObjectControlBlockOp,
(uint32_t(*)(uintptr_t*, WeakObjectControlBlockOp)));
inline uint32_t incrementWeakObjectStrongCount(uintptr_t* refCountOrEncodedPtr)
{
auto impl = detail::loadWeakObjectControlBlockOp();
OMNI_ASSERT(impl);
return impl(refCountOrEncodedPtr, WeakObjectControlBlockOp::eIncrementStrong);
}
inline uint32_t decrementWeakObjectStrongCount(uintptr_t* refCountOrEncodedPtr)
{
auto impl = detail::loadWeakObjectControlBlockOp();
OMNI_ASSERT(impl);
return impl(refCountOrEncodedPtr, WeakObjectControlBlockOp::eDecrementStrong);
}
inline void decrementWeakObjectWeakCount(uintptr_t* refCountOrEncodedPtr)
{
auto impl = detail::loadWeakObjectControlBlockOp();
OMNI_ASSERT(impl);
(void)impl(refCountOrEncodedPtr, WeakObjectControlBlockOp::eDecrementWeak);
}
inline uint32_t getWeakObjectStrongCount(uintptr_t* refCountOrEncodedPtr)
{
auto impl = detail::loadWeakObjectControlBlockOp();
OMNI_ASSERT(impl);
return impl(refCountOrEncodedPtr, WeakObjectControlBlockOp::eGetStrongCount);
}
inline uint32_t getWeakObjectWeakCount(uintptr_t* refCountOrEncodedPtr)
{
auto impl = detail::loadWeakObjectControlBlockOp();
OMNI_ASSERT(impl);
return impl(refCountOrEncodedPtr, WeakObjectControlBlockOp::eGetWeakCount);
}
inline bool hasWeakObjectControlBlock(uintptr_t* refCountOrEncodedPtr)
{
auto impl = detail::loadWeakObjectControlBlockOp();
OMNI_ASSERT(impl);
return (0 != impl(refCountOrEncodedPtr, WeakObjectControlBlockOp::eHasControlBlock));
}
} // namespace detail
#endif // DOXYGEN_BUILD
#ifdef CARB_DOC_BUILD
#endif
#ifdef CARB_DOC_BUILD
#endif
template <typename T, typename... Rest>
struct ImplementsWeak : public ImplementsCast<T, Rest...>
{
public:
inline void acquire() noexcept
{
// note: this implementation is needed to disambiguate which `cast` to call when using multiple inheritance. it
// has zero-overhead.
static_cast<T*>(this)->acquire();
}
inline void release() noexcept
{
// note: this implementation is needed to disambiguate which `cast` to call when using multiple inheritance. it
// has zero-overhead.
static_cast<T*>(this)->release();
}
inline ObjectPtr<IWeakObjectControlBlock> getWeakObjectControlBlock() noexcept
{
// note: this implementation is needed to disambiguate which `getWeakObjectControlBlock` to call when using
// multiple inheritance. it has zero-overhead.
return static_cast<T*>(this)->getWeakObjectControlBlock();
}
protected:
virtual ~ImplementsWeak() noexcept
{
// decrementWeakObjectWeakCount() will no-op if a control block has not been created
omni::core::detail::decrementWeakObjectWeakCount(&m_refCountOrPtr);
}
virtual void acquire_abi() noexcept override
{
omni::core::detail::incrementWeakObjectStrongCount(&m_refCountOrPtr);
}
virtual void release_abi() noexcept override
{
if (0 == omni::core::detail::decrementWeakObjectStrongCount(&m_refCountOrPtr))
{
delete this;
}
}
virtual IWeakObjectControlBlock* getWeakObjectControlBlock_abi() noexcept override
{
return omni::core::detail::getOrCreateWeakObjectControlBlock(static_cast<T*>(this), &m_refCountOrPtr);
}
#ifndef DOXYGEN_BUILD
uint32_t _getStrongCount() noexcept
{
return omni::core::detail::getWeakObjectStrongCount(&m_refCountOrPtr);
}
bool _hasWeakObjectControlBlock() noexcept
{
return omni::core::detail::hasWeakObjectControlBlock(&m_refCountOrPtr);
}
#endif
private:
// by default, this value stores the reference count of the object.
//
// however, when getWeakObjectControlBlock_abi() is called, this memory is repurposed to store a pointer to an
// IWeakObjectControlBlock. it's the IWeakObjectControlBlock that will store both a strong and weak reference count
// for this object.
//
// the pointer to the IWeakObjectControlBlock count is "encoded" so that we can easily determine if this memory is a
// reference count or a pointer to an IWeakObjectControlBlock.
//
// the encoding of this pointer is an implementation detail and not exposed to the user.
//
// this value should be treated as opaque.
uintptr_t m_refCountOrPtr{ 1 };
};
} // namespace core
} // namespace omni
#define OMNI_BIND_INCLUDE_INTERFACE_IMPL
#include <omni/core/IWeakObject.gen.h>