    #ifndef INCLUDED_ITERATOR_H_
    #define INCLUDED_ITERATOR_H_

//HEAD
    #include <iterator>
    #include <compare>

    template <typename Class, typename BaseIterator, typename Type>
    struct RandomPtrIterator;

    #define PtrIterator RandomPtrIterator<Class, BaseIterator, Type>
    #define PtrIteratorValue RandomPtrIterator<Class, BaseIterator, value_type>

    template <typename Class, typename BaseIterator, typename Type>
    bool operator==(PtrIterator const &lhs, PtrIterator const &rhs);

    template <typename Class, typename BaseIterator, typename Type>
    auto operator<=>(PtrIterator const &lhs, PtrIterator const &rhs);

    template <typename Class, typename BaseIterator, typename Type>
    int operator-(PtrIterator const &lhs, PtrIterator const &rhs);

    template <typename Class, typename BaseIterator, typename Type>
    struct RandomPtrIterator
    {
        using iterator_category = std::random_access_iterator_tag;
        using difference_type   = std::ptrdiff_t;
        using value_type        = Type;
        using pointer           = value_type *;
        using reference         = value_type &;


        friend PtrIterator Class::begin();
        friend PtrIterator Class::end();

        friend bool operator==<>(RandomPtrIterator const &lhs,
                                 RandomPtrIterator const &rhs);
        friend auto operator<=><>(RandomPtrIterator const &lhs,
                                  RandomPtrIterator const &rhs);
        friend int operator-<>(RandomPtrIterator const &lhs,
                               RandomPtrIterator const &rhs);
        private:
            BaseIterator d_current;

        public:
            int operator-(RandomPtrIterator const &rhs) const;
            RandomPtrIterator operator+(int step) const;
            value_type &operator*() const;
            RandomPtrIterator &operator--();
            RandomPtrIterator operator--(int);
            RandomPtrIterator &operator++();
            RandomPtrIterator operator++(int);
            RandomPtrIterator operator-(int step) const;
            RandomPtrIterator &operator-=(int step);
            RandomPtrIterator &operator+=(int step);
            value_type *operator->() const;

        private:
            RandomPtrIterator(BaseIterator const &current);
    };

    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue::RandomPtrIterator(BaseIterator const &current)
    :
        d_current(current)
    {}
//=

    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue PtrIteratorValue::operator+(int step) const
    {
        return RandomPtrIterator(d_current + step);
    }
//OP*
    template <typename Class, typename BaseIterator, typename value_type>
    value_type &PtrIteratorValue::operator*() const
    {
        return **d_current;
    }
//=
//CMP
    template <typename Class, typename BaseIterator, typename Type>
    inline auto operator<=>(PtrIterator const &lhs, PtrIterator const &rhs)
    {
        return **lhs.d_current <=> **rhs.d_current;
    }

//=
    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue &PtrIteratorValue::operator--()
    {
        --d_current;
        return *this;
    }
    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue PtrIteratorValue::operator--(int)
    {
        return RandomPtrIterator(d_current--);
    }
//INC
    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue &PtrIteratorValue::operator++()
    {
        ++d_current;
        return *this;
    }
    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue PtrIteratorValue::operator++(int)
    {
        return RandomPtrIterator(d_current++);
    }
//=

    template <typename Class, typename BaseIterator, typename Type>
    inline bool operator==(PtrIterator const &lhs, PtrIterator const &rhs)
    {
        return lhs.d_current == rhs.d_current;
    }
    template <typename Class, typename BaseIterator, typename Type>
    int operator-(PtrIterator const &lhs, PtrIterator const &rhs)
    {
        return lhs.d_current - rhs.d_current;
    }
    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue &PtrIteratorValue::operator-=(int step)
    {
        d_current -= step;
        return *this;
    }
    template <typename Class, typename BaseIterator, typename value_type>
    PtrIteratorValue &PtrIteratorValue::operator+=(int step)
    {
        d_current += step;
        return *this;
    }
    template <typename Class, typename BaseIterator, typename value_type>
    value_type *PtrIteratorValue::operator->() const
    {
        return *d_current;
    }

    #undef PtrIteratorValue
    #undef PtrIterator

    #endif
