// Iterator_base.h
// ----------------------------------------------------------------
// COMP 290-001: Algorithm Library Design, Lutz Kettner, 01/11/2000
// The identity iterator adaptor based on the Barton Nackman trick.
// We factor common implementation into a base class.
//
// There is only one catch we have to address: function name lookup
// stops in derived classes as soon as the function name has been 
// found. It does not look for overloaded functions of the same name 
// further up in the class hierarchy. The functions addressed by this
// problem are here operator++, operator--, and operator-. We give
// them new names in the derived class and let the base class implement
// all functions of these names. The new names are increment(), 
// decrement(), and diff() respectively.

#ifndef CBP_ITERATOR_BASE_H
#define CBP_ITERATOR_BASE_H 1

#include <iterator>

template < class Derived, class Diff, class Ref, class Ptr >
class Iterator_base {
    // private function helps in downcasting this
    Derived&       derived() { return static_cast<Derived&>(*this); }
    const Derived& derived() const { 
	return static_cast<const Derived&>(*this);
    }
public:
    typedef Iterator_base<Derived,Diff,Ref,Ptr>   Self;

    typedef Diff   difference_type;
    typedef Ref    reference;
    typedef Ptr    pointer;

    // Default Constructible !
    Iterator_base() {}

    // Assignable by default.

    // Equality Comparable:
    bool operator!=( const Derived& i) const { return !( derived() == i); }

    // Trivial Iterator:
    pointer   operator->() const { return & * derived(); }

    // Input Iterator, Forward Iterator
    Derived& operator++() {
        derived().increment();
        return derived();
    }
    const Derived  operator++(int) {
        Derived tmp = derived();
        derived().increment();
        return tmp;
    }

    // Bidirectional Iterator
    Derived& operator--() {
        derived().decrement();
        return derived();
    }
    const Derived  operator--(int) {
        Derived tmp = derived();
        derived().decrement();
        return tmp;
    }

    // Random Access Iterator
    const Derived operator+( difference_type n) const {
        Derived tmp = derived();
        return tmp += n;
    }
    Derived& operator-=( difference_type n) { return derived() += (-n); }
    const Derived operator-( difference_type n) const {
        Derived tmp = derived();
        return tmp += -n;
    }
    reference operator[]( difference_type n) const {
        Derived tmp = derived();
        tmp += n;
        return * tmp;
    }
    difference_type  operator-( const Derived& i) const {
        return derived().diff(i);
    }
    bool operator> ( const Derived& i) const { return i < derived(); }
    bool operator<=( const Derived& i) const { return !(i < derived()); }
    bool operator>=( const Derived& i) const { return !(derived() < i); }
};

template < class D, class Derived, class Diff, class Ref, class Ptr>
inline               // Note: we cannot match with Derived only (too general)
Derived operator+( D n, const Iterator_base<Derived,Diff,Ref,Ptr>& i) {
    typedef typename Iterator_base<Derived,Diff,Ref,Ptr>::difference_type
	difference_type;
    Derived derived = static_cast<const Derived&>(i);
    return derived += difference_type(n);
}

// example using the above base class
 
template < class I >
class Iterator_identity
    : public Iterator_base< Iterator_identity<I>,
          typename std::iterator_traits<I>::difference_type,
          typename std::iterator_traits<I>::reference,
          typename std::iterator_traits<I>::pointer > {
private:
    I        nt;    // The internal iterator.
public:
    typedef I                                  Iterator;
    typedef Iterator_identity<I>               Self;

    typedef std::iterator_traits<I>            traits;
    typedef typename traits::reference         reference;
    typedef typename traits::pointer           pointer;
    typedef typename traits::value_type        value_type;
    typedef typename traits::difference_type   difference_type;
    typedef typename traits::iterator_category iterator_category;

    // Default Constructible !
    Iterator_identity() {}
    Iterator_identity( Iterator j) : nt(j) {}

    // Assignable by default, but templated constructor implements
    // automatic conversion between Iterator_identity's whose underlying
    // iterator types are assignable.
    template <class II>
    Iterator_identity( const Iterator_identity<II>& ii) 
	: nt( ii.current_iterator()) {}

    // Additional member functions (typically accessors):
    Iterator  current_iterator() const { return nt;}

    // Equality Comparable:
    bool operator==( const Self& i) const { return ( nt == i.nt); }

    // Trivial Iterator:
    reference operator*()  const { return *nt; }

    // Input Iterator, Forward Iterator
    Self& increment() {
        ++nt;
        return *this;
    }

    // Bidirectional Iterator
    Self& decrement() {
        --nt;
        return *this;
    }

    // Random Access Iterator
    Self& operator+=( difference_type n) {
        nt += n;
        return *this;
    }
    difference_type  diff( const Self& i) const { return nt - i.nt; }
    bool operator< ( const Self& i) const { return ( nt < i.nt); }
};

 
#endif // ITERATOR_IDENTITY_H //
// EOF //

