carb/assets/AssetsUtils.h

File members: carb/assets/AssetsUtils.h

// Copyright (c) 2019-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 "IAssets.h"

namespace carb
{

namespace assets
{

template <class Type>
class ScopedSnapshot
{
public:
    ScopedSnapshot() = default;

    ScopedSnapshot(std::nullptr_t)
    {
    }

    ScopedSnapshot(IAssets* assets, Id assetId) : m_assets(assets)
    {
        m_snapshot = assets->acquireSnapshot(assetId, getAssetType<Type>(), m_reason);
        m_value = reinterpret_cast<Type*>(assets->getDataFromSnapshot(m_snapshot));
    }

    ~ScopedSnapshot()
    {
        release();
    }

    ScopedSnapshot(ScopedSnapshot&& other)
    {
        m_value = other.m_value;
        m_assets = other.m_assets;
        m_snapshot = other.m_snapshot;
        m_reason = other.m_reason;
        other.m_assets = nullptr;
        other.m_value = nullptr;
        other.m_snapshot = kInvalidSnapshot;
        other.m_reason = Reason::eFailed;
    }

    ScopedSnapshot& operator=(ScopedSnapshot&& other)
    {
        // This assert should never happen, but it is possible to accidentally write this
        // code, though one has to contort themselves to do it. It is considered
        // invalid nonetheless.
        CARB_ASSERT(this != &other);
        release();
        m_value = other.m_value;
        m_assets = other.m_assets;
        m_snapshot = other.m_snapshot;
        m_reason = other.m_reason;
        other.m_assets = nullptr;
        other.m_value = nullptr;
        other.m_snapshot = kInvalidSnapshot;
        other.m_reason = Reason::eFailed;
        return *this;
    }

    CARB_PREVENT_COPY(ScopedSnapshot);

    Type* get()
    {
        return m_value;
    }

    const Type* get() const
    {
        return m_value;
    }

    Type* operator->()
    {
        return get();
    }

    const Type* operator->() const
    {
        return get();
    }

    Type& operator*()
    {
        return *get();
    }

    const Type& operator*() const
    {
        return *get();
    }

    constexpr explicit operator bool() const noexcept
    {
        return m_value != nullptr;
    }

    Reason getReason() const
    {
        return m_reason;
    }

private:
    void release()
    {
        if (m_assets && m_snapshot)
        {
            m_assets->releaseSnapshot(m_snapshot);
        }
        m_value = nullptr;
        m_assets = nullptr;
        m_snapshot = kInvalidSnapshot;
        m_reason = Reason::eFailed;
    }

    // Note this member is first to help in debugging.
    Type* m_value = nullptr;
    carb::assets::IAssets* m_assets = nullptr;
    Snapshot m_snapshot = kInvalidSnapshot;
    Reason m_reason = Reason::eFailed;
};

template <class Type>
bool operator==(const carb::assets::ScopedSnapshot<Type>& a, const carb::assets::ScopedSnapshot<Type>& b)
{
    return a.get() == b.get();
}

template <class Type>
bool operator!=(const carb::assets::ScopedSnapshot<Type>& a, const carb::assets::ScopedSnapshot<Type>& b)
{
    return a.get() != b.get();
}

#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <class Type>
bool operator==(const carb::assets::ScopedSnapshot<Type>& a, std::nullptr_t)
{
    return a.get() == nullptr;
}

template <class Type>
bool operator==(std::nullptr_t, const carb::assets::ScopedSnapshot<Type>& a)
{
    return a.get() == nullptr;
}

template <class Type>
bool operator!=(const carb::assets::ScopedSnapshot<Type>& a, std::nullptr_t)
{
    return a.get() != nullptr;
}

template <class Type>
bool operator!=(std::nullptr_t, const carb::assets::ScopedSnapshot<Type>& a)
{
    return a.get() != nullptr;
}
#endif

} // namespace assets
} // namespace carb