Program Listing for File iterator.h#

Return to documentation for file (support\iterator.h)

#ifndef SDV_ITERATOR_H
#define SDV_ITERATOR_H

#include <iterator>
#ifndef DONT_LOAD_CORE_TYPES
#include "../interfaces/core_types.h"
#endif

namespace sdv
{
    namespace internal
    {
        template <class TContainer, bool bConstIterator, bool bReverseIterator>
        class index_iterator
        {
            friend index_iterator<TContainer, !bConstIterator, bReverseIterator>;

        public:
            using container_reference = std::conditional_t<bConstIterator, const TContainer&, TContainer&>;

            using container_pointer = std::conditional_t<bConstIterator, const TContainer*, TContainer*>;

            using iterator_category = std::random_access_iterator_tag;

            using value_type = typename TContainer::value_type;

            using difference_type = size_t;

            using pointer = std::conditional_t<bConstIterator, const value_type*, value_type*>;

            using reference = std::conditional_t<bConstIterator, const value_type&, value_type&>;

            index_iterator() {}

            index_iterator(container_pointer pContainer) : m_pContainer(pContainer)
            {}

            index_iterator(const index_iterator& rit) : m_pContainer(rit.m_pContainer), m_nIndex(rit.m_nIndex)
            {}

            index_iterator(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit) :
                m_pContainer(const_cast<container_pointer>(rit.m_pContainer)), m_nIndex(rit.m_nIndex)
            {}

            index_iterator(index_iterator&& rit) noexcept : m_pContainer(rit.m_pContainer), m_nIndex(rit.m_nIndex)
            {
                rit.m_pContainer = nullptr;
                rit.m_nIndex = 0;
            }

            index_iterator& operator=(const index_iterator& rit)
            {
                m_pContainer = rit.m_pContainer;
                m_nIndex = rit.m_nIndex;
                return *this;
            }

            index_iterator& operator=(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit)
            {
                m_pContainer = rit.m_pContainer;
                m_nIndex = rit.m_nIndex;
                return *this;
            }

            index_iterator& operator=(index_iterator&& rit) noexcept
            {
                m_pContainer = rit.m_pContainer;
                m_nIndex = rit.m_nIndex;
                rit.m_pContainer = nullptr;
                rit.m_nIndex = 0;
                return *this;
            }

            bool is_valid(container_reference rContainer) const
            {
                return m_pContainer == &rContainer;
            }

            bool operator==(const index_iterator& rit) const
            {
                return m_pContainer == rit.m_pContainer && m_nIndex == rit.m_nIndex;
            }

            bool operator==(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit) const
            {
                return m_pContainer == rit.m_pContainer && m_nIndex == rit.m_nIndex;
            }

            bool operator!=(const index_iterator& rit) const
            {
                return !(*this == rit);
            }

            bool operator!=(const index_iterator<TContainer, !bConstIterator, bReverseIterator>& rit) const
            {
                return !(*this == rit);
            }

            reference operator*() const
            {
                size_t nIndex = m_nIndex;
                if (!m_pContainer || m_nIndex >= m_pContainer->size())
                {
                    XIndexOutOfRange exception;
                    exception.uiIndex = static_cast<uint32_t>(nIndex);
                    exception.uiSize = static_cast<uint32_t>(m_pContainer ? m_pContainer->size() : 0);
                    throw exception;
                }
                if constexpr (bReverseIterator)
                    nIndex = m_pContainer->size() - m_nIndex - 1;
                return (*m_pContainer)[nIndex];
            }

            pointer operator->() const
            {
                return std::pointer_traits<pointer>::pointer_to(**this);
            }

            index_iterator& operator++()
            {
                if (m_pContainer && m_nIndex < m_pContainer->size())
                    m_nIndex++;
                return *this;
            }

            index_iterator operator++(int)
            {
                index_iterator itCopy = *this;
                operator++();
                return itCopy;
            }

            index_iterator& operator--() noexcept
            {
                if (m_pContainer && m_nIndex > 0)
                    m_nIndex--;
                return *this;
            }

            index_iterator operator--(int) noexcept
            {
                index_iterator itCopy = *this;
                operator--();
                return itCopy;
            }

            index_iterator& operator+=(size_t nOffset) noexcept
            {
                if (!m_pContainer) return *this;
                if (nOffset > m_pContainer->size() - m_nIndex)
                    m_nIndex = m_pContainer->size();
                else
                    m_nIndex += nOffset;
                return *this;
            }

            index_iterator operator+(size_t nOffset) const noexcept
            {
                index_iterator itCopy = *this;
                itCopy += nOffset;
                return itCopy;
            }

            index_iterator& operator-=(size_t nOffset) noexcept
            {
                if (!m_pContainer) return *this;
                if (m_nIndex > nOffset)
                    m_nIndex -= nOffset;
                else if (m_nIndex)
                    m_nIndex = 0;

                return *this;
            }

            index_iterator operator-(size_t nOffset) const noexcept
            {
                index_iterator itCopy = *this;
                itCopy -= nOffset;
                return itCopy;
            }

            difference_type operator-(index_iterator it) const
            {
                if (m_pContainer != it.m_pContainer) return 0;
                if (m_nIndex > it.m_nIndex)
                    return m_nIndex - it.m_nIndex;
                else
                    return it.m_nIndex - m_nIndex;
            }

            reference operator[](size_t nOffset) const
            {
                if (!m_pContainer || m_pContainer->empty())
                {
                    XIndexOutOfRange exception;
                    exception.uiIndex = static_cast<uint32_t>(nOffset + m_nIndex);
                    exception.uiSize = static_cast<uint32_t>(0);
                    throw exception;
                }
                return *(operator+(nOffset));
            }

        private:
            container_pointer m_pContainer = nullptr;
            size_t            m_nIndex     = 0;
        };
    } // namespace internal
} // namespace sdv

#endif // !defined SDV_ITERATOR_H