omni/detail/PointerIterator.h

File members: omni/detail/PointerIterator.h

// Copyright (c) 2021-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.
//
#pragma once

#include "../../carb/Defines.h"

#include <iterator>
#include <type_traits>

#if CARB_HAS_CPP20 && defined(__cpp_concepts)
#    include <concepts>
#endif

namespace omni
{
namespace detail
{

template <typename TPointer, typename TContainer>
class PointerIterator
{
    static_assert(std::is_pointer<TPointer>::value, "TPointer must be a pointer type");

private:
    using underlying_traits_type = std::iterator_traits<TPointer>;

public:
    using value_type = typename underlying_traits_type::value_type;

    using reference = typename underlying_traits_type::reference;

    using pointer = typename underlying_traits_type::pointer;

    using difference_type = typename underlying_traits_type::difference_type;

    using iterator_category = typename underlying_traits_type::iterator_category;
#if CARB_HAS_CPP20 && defined(__cpp_concepts)
    using iterator_concept = typename underlying_traits_type::iterator_concept;
#endif

public:
    constexpr PointerIterator() noexcept : m_ptr{ nullptr }
    {
    }

    explicit constexpr PointerIterator(pointer src) noexcept : m_ptr{ src }
    {
    }

    PointerIterator(const PointerIterator&) = default;

    PointerIterator(PointerIterator&&) = default;

    PointerIterator& operator=(const PointerIterator&) = default;

    PointerIterator& operator=(PointerIterator&&) = default;

    ~PointerIterator() = default;

    // clang-format off
    template <typename UPointer,
              typename = std::enable_if_t
                         <  !std::is_same<TPointer, UPointer>::value
                         && std::is_convertible
                            <
                                std::remove_reference_t<typename PointerIterator<UPointer, TContainer>::reference>(*)[],
                                std::remove_reference_t<reference>(*)[]
                            >::value
                         >
             >
    constexpr PointerIterator(const PointerIterator<UPointer, TContainer>& src) noexcept
        : m_ptr{src.operator->()}
    {
    }
    // clang-format on

    constexpr reference operator*() const noexcept
    {
        return *m_ptr;
    }

    constexpr reference operator[](difference_type idx) const noexcept
    {
        return m_ptr[idx];
    }

    constexpr pointer operator->() const noexcept
    {
        return m_ptr;
    }

    constexpr PointerIterator& operator++() noexcept
    {
        ++m_ptr;
        return *this;
    }

    constexpr PointerIterator operator++(int) noexcept
    {
        PointerIterator save{ *this };
        ++m_ptr;
        return save;
    }

    constexpr PointerIterator& operator--() noexcept
    {
        --m_ptr;
        return *this;
    }

    constexpr PointerIterator operator--(int) noexcept
    {
        PointerIterator save{ *this };
        --m_ptr;
        return save;
    }

    constexpr PointerIterator& operator+=(difference_type dist) noexcept
    {
        m_ptr += dist;
        return *this;
    }

    constexpr PointerIterator operator+(difference_type dist) const noexcept
    {
        return PointerIterator{ m_ptr + dist };
    }

    constexpr PointerIterator& operator-=(difference_type dist) noexcept
    {
        m_ptr -= dist;
        return *this;
    }

    constexpr PointerIterator operator-(difference_type dist) const noexcept
    {
        return PointerIterator{ m_ptr - dist };
    }

private:
    pointer m_ptr;
};

template <typename TPointer, typename TContainer>
inline constexpr PointerIterator<TPointer, TContainer> operator+(
    typename PointerIterator<TPointer, TContainer>::difference_type dist,
    const PointerIterator<TPointer, TContainer>& iter) noexcept
{
    return iter + dist;
}

template <typename TPointer, typename UPointer, typename TContainer>
inline constexpr auto operator-(const PointerIterator<TPointer, TContainer>& lhs,
                                const PointerIterator<UPointer, TContainer>& rhs) noexcept
    -> decltype(lhs.operator->() - rhs.operator->())
{
    return lhs.operator->() - rhs.operator->();
}

template <typename TPointer, typename UPointer, typename TContainer>
inline constexpr bool operator==(const PointerIterator<TPointer, TContainer>& lhs,
                                 const PointerIterator<UPointer, TContainer>& rhs) noexcept
{
    return lhs.operator->() == rhs.operator->();
}

template <typename TPointer, typename UPointer, typename TContainer>
inline constexpr bool operator!=(const PointerIterator<TPointer, TContainer>& lhs,
                                 const PointerIterator<UPointer, TContainer>& rhs) noexcept
{
    return lhs.operator->() != rhs.operator->();
}

template <typename TPointer, typename UPointer, typename TContainer>
inline constexpr bool operator<(const PointerIterator<TPointer, TContainer>& lhs,
                                const PointerIterator<UPointer, TContainer>& rhs) noexcept
{
    return lhs.operator->() < rhs.operator->();
}

template <typename TPointer, typename UPointer, typename TContainer>
inline constexpr bool operator<=(const PointerIterator<TPointer, TContainer>& lhs,
                                 const PointerIterator<UPointer, TContainer>& rhs) noexcept
{
    return lhs.operator->() <= rhs.operator->();
}

template <typename TPointer, typename UPointer, typename TContainer>
inline constexpr bool operator>(const PointerIterator<TPointer, TContainer>& lhs,
                                const PointerIterator<UPointer, TContainer>& rhs) noexcept
{
    return lhs.operator->() > rhs.operator->();
}

template <typename TPointer, typename UPointer, typename TContainer>
inline constexpr bool operator>=(const PointerIterator<TPointer, TContainer>& lhs,
                                 const PointerIterator<UPointer, TContainer>& rhs) noexcept
{
    return lhs.operator->() >= rhs.operator->();
}

} // namespace detail
} // namespace omni