Program Listing for File HandleWrapper.hpp

Return to documentation for file (nvcv_types/include/nvcv/HandleWrapper.hpp)

/*
 * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef NVCV_HANDLE_WRAPPER_HPP
#define NVCV_HANDLE_WRAPPER_HPP

#include "detail/CheckError.hpp"
#include "detail/CompilerUtils.h"

#include <cassert>
#include <utility>

namespace nvcv {

template<typename HandleType>
int HandleDecRef(HandleType handle);

template<typename HandleType>
int HandleIncRef(HandleType handle);

template<typename HandleType>
int HandleRefCount(HandleType handle);

template<typename HandleType>
void HandleDestroy(HandleType handle);

template<typename HandleType>
constexpr HandleType NullHandle()
{
    return {};
}

template<typename HandleType>
constexpr bool HandleIsNull(HandleType h)
{
    return h == NullHandle<HandleType>();
}

namespace detail {

template<typename HandleType>
struct SharedHandleOps
{
    static int DecRef(HandleType handle)
    {
        return HandleDecRef(handle);
    }

    static int IncRef(HandleType handle)
    {
        return HandleIncRef(handle);
    }

    static int RefCount(HandleType handle)
    {
        return HandleRefCount(handle);
    }

    static constexpr bool IsNull(HandleType handle)
    {
        return HandleIsNull(handle);
    }

    static constexpr HandleType Null()
    {
        return NullHandle<HandleType>();
    };
};

template<typename HandleType>
struct UniqueHandleOps
{
    static void Destroy(HandleType handle)
    {
        HandleDestroy(handle);
    }

    static constexpr bool IsNull(HandleType handle)
    {
        return HandleIsNull(handle);
    }

    static constexpr HandleType Null()
    {
        return NullHandle<HandleType>();
    };
};

} // namespace detail

template<typename HandleType, typename HandleOps = detail::UniqueHandleOps<HandleType>>
class UniqueHandle
{
public:
    ~UniqueHandle()
    {
        reset();
    }

    explicit UniqueHandle(HandleType &&handle)
        : m_handle(handle)
    {
        handle = HandleOps::Null();
    }

    UniqueHandle()                          = default;
    UniqueHandle(const UniqueHandle &other) = delete;

    UniqueHandle(UniqueHandle &&other)
        : m_handle(std::move(other.m_handle))
    {
        other.m_handle = HandleOps::Null();
    }

    UniqueHandle &operator=(UniqueHandle &&other)
    {
        if (&other == this)
            return *this; // avoid self-reset in self-move
        swap(other);
        other.reset();
        return *this;
    }

    void swap(UniqueHandle &other) noexcept
    {
        std::swap(m_handle, other.m_handle);
    }

    void reset(HandleType &&handle = HandleOps::Null())
    {
        assert(HandleOps::IsNull(handle) || handle != m_handle);
        if (*this)
        {
            HandleOps::Destroy(m_handle);
        }
        m_handle = std::move(handle);
        handle   = HandleOps::Null();
    }

    NVCV_NODISCARD HandleType release() noexcept
    {
        HandleType h = std::move(m_handle);
        m_handle     = HandleOps::Null();
        return h;
    }

    constexpr const HandleType get() const noexcept
    {
        return m_handle;
    }

    constexpr bool empty() const noexcept
    {
        return HandleOps::IsNull(m_handle);
    }

    constexpr explicit operator bool() const noexcept
    {
        return !empty();
    }

    bool operator==(const UniqueHandle &other) const
    {
        return m_handle == other.m_handle;
    }

    bool operator!=(const UniqueHandle &other) const
    {
        return m_handle != other.m_handle;
    }

private:
    HandleType m_handle = HandleOps::Null();
};

template<typename HandleType, typename HandleOps = detail::SharedHandleOps<HandleType>>
class SharedHandle
{
public:
    ~SharedHandle()
    {
        reset();
    }

    SharedHandle() = default;

    explicit SharedHandle(HandleType &&handle) noexcept
        : m_handle(handle)
    {
        handle = HandleOps::Null();
    }

    SharedHandle(SharedHandle &&other) noexcept
        : m_handle(std::move(other.m_handle))
    {
        other.m_handle = HandleOps::Null();
    }

    SharedHandle(const SharedHandle &other)
    {
        *this = other;
    }

    SharedHandle &operator=(SharedHandle &&other)
    {
        if (&other == this)
            return *this; // we must not reset the "other" in case of self-move
        swap(other);
        other.reset();
        return *this;
    }

    SharedHandle &operator=(const SharedHandle &other)
    {
        HandleType new_handle = other.get();
        if (m_handle == new_handle)
            return *this;
        if (!HandleOps::IsNull(new_handle))
            HandleOps::IncRef(new_handle);
        reset(std::move(new_handle));
        return *this;
    }

    void swap(SharedHandle &other) noexcept
    {
        std::swap(m_handle, other.m_handle);
    }

    int reset(HandleType &&handle = HandleOps::Null())
    {
        auto old = m_handle;
        m_handle = std::move(handle);
        handle   = HandleOps::Null();
        if (!HandleOps::IsNull(old))
            return HandleOps::DecRef(old);
        return 0;
    }

    NVCV_NODISCARD HandleType release() noexcept
    {
        HandleType h = std::move(m_handle);
        m_handle     = HandleOps::Null();
        return h;
    }

    constexpr const HandleType get() const noexcept
    {
        return m_handle;
    }

    int refCount() const noexcept
    {
        HandleType h = m_handle;
        return HandleOps::IsNull(h) ? 0 : HandleOps::RefCount(h);
    }

    constexpr bool empty() const noexcept
    {
        return HandleOps::IsNull(m_handle);
    }

    constexpr explicit operator bool() const noexcept
    {
        return !empty();
    }

    bool operator==(const SharedHandle &other) const
    {
        return m_handle == other.m_handle;
    }

    bool operator!=(const SharedHandle &other) const
    {
        return m_handle != other.m_handle;
    }

private:
    HandleType m_handle = HandleOps::Null();
};

#define NVCV_IMPL_DEC_REF(ObjectKind)                                             \
    template<>                                                                    \
    inline int HandleDecRef<NVCV##ObjectKind##Handle>(NVCV##ObjectKind##Handle h) \
    {                                                                             \
        int ref = -1;                                                             \
        nvcv::detail::CheckThrow(nvcv##ObjectKind##DecRef(h, &ref));              \
        return ref;                                                               \
    }

#define NVCV_IMPL_INC_REF(ObjectKind)                                             \
    template<>                                                                    \
    inline int HandleIncRef<NVCV##ObjectKind##Handle>(NVCV##ObjectKind##Handle h) \
    {                                                                             \
        int ref = -1;                                                             \
        nvcv::detail::CheckThrow(nvcv##ObjectKind##IncRef(h, &ref));              \
        return ref;                                                               \
    }

#define NVCV_IMPL_REF_COUNT(ObjectKind)                                             \
    template<>                                                                      \
    inline int HandleRefCount<NVCV##ObjectKind##Handle>(NVCV##ObjectKind##Handle h) \
    {                                                                               \
        int ref = -1;                                                               \
        nvcv::detail::CheckThrow(nvcv##ObjectKind##RefCount(h, &ref));              \
        return ref;                                                                 \
    }

#define NVCV_IMPL_SHARED_HANDLE(ObjectKind) \
    NVCV_IMPL_DEC_REF(ObjectKind)           \
    NVCV_IMPL_INC_REF(ObjectKind)           \
    NVCV_IMPL_REF_COUNT(ObjectKind)

#define NVCV_IMPL_DESTROY(ObjectKind)                                               \
    template<>                                                                      \
    inline void HandleDestroy<NVCV##ObjectKind##Handle>(NVCV##ObjectKind##Handle h) \
    {                                                                               \
        nvcv::detail::CheckThrow(nvcv##ObjectKind##Destroy(h));                     \
    }

#define NVCV_IMPL_DESTROY_VOID(ObjectKind)                                          \
    template<>                                                                      \
    inline void HandleDestroy<NVCV##ObjectKind##Handle>(NVCV##ObjectKind##Handle h) \
    {                                                                               \
        nvcv##ObjectKind##Destroy(h);                                               \
    }

} // namespace nvcv

#endif