carb/IObject.h
File members: carb/IObject.h
// Copyright (c) 2020-2022, 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 "Interface.h"
#include <cstdint>
namespace carb
{
class IObject
{
public:
    CARB_PLUGIN_INTERFACE("carb::IObject", 1, 0)
    virtual ~IObject() = default;
    virtual size_t addRef() = 0;
    virtual size_t release() = 0;
};
template <class T>
class ObjectPtr
{
public:
    enum class InitPolicy
    {
        eBorrow,
        eSteal
    };
    ObjectPtr() : m_object(nullptr)
    {
    }
    ObjectPtr(std::nullptr_t) : m_object(nullptr)
    {
    }
    explicit ObjectPtr(T* object) : m_object(object)
    {
        if (m_object)
        {
            m_object->addRef();
        }
    }
    ObjectPtr(T* object, InitPolicy policy) : m_object(object)
    {
        if (policy == InitPolicy::eBorrow && m_object != nullptr)
        {
            m_object->addRef();
        }
    }
    ObjectPtr(const ObjectPtr<T>& other) : ObjectPtr(other.m_object, InitPolicy::eBorrow)
    {
    }
    template <class U>
    ObjectPtr(const ObjectPtr<U>& other) : ObjectPtr(other.m_object, InitPolicy::eBorrow)
    {
    }
    ObjectPtr(ObjectPtr<T>&& other) : m_object(other.m_object)
    {
        other.m_object = nullptr;
    }
    template <class U>
    ObjectPtr(ObjectPtr<U>&& other) : m_object(other.m_object)
    {
        other.m_object = nullptr;
    }
    ~ObjectPtr()
    {
        _release();
    }
    T* get() const
    {
        return m_object;
    }
    T* operator->() const
    {
        CARB_ASSERT(m_object);
        return m_object;
    }
    T& operator*() const
    {
        CARB_ASSERT(m_object);
        return *m_object;
    }
    explicit operator bool() const
    {
        return get() != nullptr;
    }
    T* const* getAddressOf() const
    {
        return &m_object;
    }
    T** getAddressOf()
    {
        return &m_object;
    }
    T** releaseAndGetAddressOf()
    {
        _release();
        return &m_object;
    }
    T* detach()
    {
        T* temp = m_object;
        m_object = nullptr;
        return temp;
    }
    void attach(T* other)
    {
        _release();
        m_object = other;
    }
    ObjectPtr& operator=(decltype(nullptr))
    {
        _release();
        return *this;
    }
    ObjectPtr& operator=(T* other)
    {
        ObjectPtr(other).swap(*this);
        return *this;
    }
    template <typename U>
    ObjectPtr& operator=(U* other)
    {
        ObjectPtr(other).swap(*this);
        return *this;
    }
    ObjectPtr& operator=(const ObjectPtr& other)
    {
        ObjectPtr(other).swap(*this);
        return *this;
    }
    template <class U>
    ObjectPtr& operator=(const ObjectPtr<U>& other)
    {
        ObjectPtr(other).swap(*this);
        return *this;
    }
    ObjectPtr& operator=(ObjectPtr&& other)
    {
        other.swap(*this);
        return *this;
    }
    template <class U>
    ObjectPtr& operator=(ObjectPtr<U>&& other)
    {
        ObjectPtr(std::move(other)).swap(*this);
        return *this;
    }
    template <class U>
    bool operator==(const ObjectPtr<U>& other) const
    {
        return get() == other.get();
    }
    template <class U>
    bool operator!=(const ObjectPtr<U>& other) const
    {
        return get() != other.get();
    }
    void swap(ObjectPtr& other)
    {
        std::swap(m_object, other.m_object);
    }
private:
    void _release()
    {
        if (T* old = std::exchange(m_object, nullptr))
        {
            old->release();
        }
    }
    T* m_object;
};
template <class T>
inline ObjectPtr<T> stealObject(T* other)
{
    return ObjectPtr<T>(other, ObjectPtr<T>::InitPolicy::eSteal);
}
template <class T>
inline ObjectPtr<T> borrowObject(T* other)
{
    return ObjectPtr<T>(other, ObjectPtr<T>::InitPolicy::eBorrow);
}
} // namespace carb