MakeIterator.h

// MakeIterator.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2010

#pragma once
#ifndef Ceda_cxUtils_MakeIterator_H
#define Ceda_cxUtils_MakeIterator_H

#include "cxUtils.h"
#include <iterator>

namespace ceda
{

template <class _Iter>
using iterator_category_type = typename std::iterator_traits<_Iter>::iterator_category;

template <class _Ty, class = void>
inline constexpr bool is_iterator_v = false;

template <class _Ty>
inline constexpr bool is_iterator_v<_Ty, std::void_t<iterator_category_type<_Ty>>> = true;

/*
// Define both iterators using a given policy
struct Policy
{
    typename iterator_category
    typename value_type
    typename difference_type
    typename pointer
    typename reference
    
    bool operator==(const Policy& rhs) const;
    void next();
    void prev();
    value_type& deref() const;
    const value_type& const_deref() const;
};
*/

///////////////////////////////////////////////////////////////////////////////////////////////////

template <typename Policy>
struct make_iterator : public Policy
{
    using pointer = typename Policy::pointer;
    using reference = typename Policy::reference;
    using difference_type = typename Policy::difference_type;

	make_iterator() {}
	explicit make_iterator(const Policy& p) : Policy(p) {}

    // Prefix
    make_iterator& operator++() { Policy::next(); return *this; }
    make_iterator& operator--() { Policy::prev(); return *this; }

    // Postfix
    const make_iterator operator++(int) { make_iterator it = *this; Policy::next(); return it; }
    const make_iterator operator--(int) { make_iterator it = *this; Policy::prev(); return it; }
    
    reference operator*() const { return Policy::deref(); }
    auto operator->() const { return &Policy::deref(); }

    bool operator<(const make_iterator& rhs) const { return Policy::operator<(rhs); }
    bool operator<=(const make_iterator& rhs) const { return !(rhs < *this); }
    bool operator>(const make_iterator& rhs) const { return rhs < *this; }
    bool operator>=(const make_iterator& rhs) const { return !(*this < rhs); }
    
    bool operator==(const make_iterator& rhs) const { return Policy::operator==(rhs); }
    bool operator!=(const make_iterator& rhs) const { return !operator==(rhs); }

    // The methods below are only supported on random access iterators

    make_iterator operator+(difference_type x) const { return make_iterator(Policy::operator+(x)); }
    make_iterator operator-(difference_type x) const { return make_iterator(Policy::operator+(-x)); }
    difference_type operator-(const make_iterator& rhs) const { return Policy::operator-(rhs); }

    make_iterator& operator+=(difference_type x)
    {
        *this = *this + x;
        return *this;
    }
    make_iterator& operator-=(difference_type x)
    {
        *this = *this - x;
        return *this;
    }
};

template <typename Policy>
struct make_const_iterator : public Policy
{
    using value_type = typename Policy::value_type;
    using pointer = typename Policy::const_pointer;
    using reference = typename Policy::const_reference;
    using difference_type = typename Policy::difference_type;
    
	make_const_iterator() {}
	explicit make_const_iterator(const Policy& p) : Policy(p) {}
	make_const_iterator(const make_iterator<Policy>& i) : Policy(i) {}

    // Prefix
    make_const_iterator& operator++() { Policy::next(); return *this; }
    make_const_iterator& operator--() { Policy::prev(); return *this; }

    // Postfix
    const make_const_iterator operator++(int) { make_const_iterator it = *this; Policy::next(); return it; }
    const make_const_iterator operator--(int) { make_const_iterator it = *this; Policy::prev(); return it; }
    
    reference operator*() const { return Policy::const_deref(); }
    auto operator->() const { return &Policy::const_deref(); }

    bool operator<(const make_const_iterator& rhs) const { return Policy::operator<(rhs); }
    bool operator<=(const make_const_iterator& rhs) const { return !(rhs < *this); }
    bool operator>(const make_const_iterator& rhs) const { return rhs < *this; }
    bool operator>=(const make_const_iterator& rhs) const { return !(*this < rhs); }
    
    bool operator==(const make_const_iterator& rhs) const { return Policy::operator==(rhs); }
    bool operator!=(const make_const_iterator& rhs) const { return !operator==(rhs); }

    // The methods below are only supported on random access iterators

    make_const_iterator operator+(difference_type x) const { return make_const_iterator(Policy::operator+(x)); }
    make_const_iterator operator-(difference_type x) const { return make_const_iterator(Policy::operator-(x)); }
    difference_type operator-(const make_const_iterator& rhs) const { return Policy::operator-(rhs); }

    make_const_iterator& operator+=(difference_type x)
    {
        *this = *this + x;
        return *this;
    }
    make_const_iterator& operator-=(difference_type x)
    {
        *this = *this - x;
        return *this;
    }
};

} // namespace ceda

#endif // include guard