/* -*- c++ -*- */
/*
 * Copyright (C) 2010 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef ANDROID_ASTL_ITERATOR__
#define ANDROID_ASTL_ITERATOR__

#include <cstddef>
#include <type_traits.h>

// Iterators are a generalization of pointers to allow programs to
// work with different data structures (containers) in a uniform
// manner.
namespace std {

// Tags for the various iterator categories. Only input and forward
// iterators are supported.
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

template<typename _Category, typename _T, typename _Distance = ptrdiff_t,
         typename _Pointer = _T*, typename _Reference = _T&>
struct iterator
{
    typedef _Category  iterator_category;  // See tags above.
    typedef _T         value_type;
    typedef _Distance  difference_type;  // Distance between iterators.
    typedef _Pointer   pointer;
    typedef _Reference reference;
};

// Generic version, simply forward the typedef to the iterator
// template argument.
template<typename _Iterator>
struct iterator_traits
{
    typedef typename _Iterator::iterator_category iterator_category;
    typedef typename _Iterator::value_type        value_type;
    typedef typename _Iterator::difference_type   difference_type;
    typedef typename _Iterator::pointer           pointer;
    typedef typename _Iterator::reference         reference;
};

// Specialization for pointers and const pointers. These are random
// access iterators.
template<typename _T>
struct iterator_traits<_T*>
{
    typedef random_access_iterator_tag iterator_category;
    typedef _T                         value_type;
    typedef ptrdiff_t                  difference_type;
    typedef _T*                        pointer;
    typedef _T&                        reference;
};

template<typename _T>
struct iterator_traits<const _T*>
{
    typedef random_access_iterator_tag iterator_category;
    typedef _T                         value_type;
    typedef ptrdiff_t                  difference_type;
    typedef const _T*                  pointer;
    typedef const _T&                  reference;
};

// Wrap an interator that is not a class (e.g pointer) into an
// iterator that is a class.
// TODO: move this definition in the android ns.
template<typename _Iterator, typename _Container>
class __wrapper_iterator
{
  public:
    typedef _Iterator iterator_type;
    typedef typename iterator_traits<_Iterator>::iterator_category
    iterator_category;
    typedef typename iterator_traits<_Iterator>::value_type value_type;
    typedef typename iterator_traits<_Iterator>::difference_type
    difference_type;
    typedef typename iterator_traits<_Iterator>::reference reference;
    typedef typename iterator_traits<_Iterator>::pointer pointer;

    __wrapper_iterator() : mCurrent(_Iterator()) { }
    explicit __wrapper_iterator(const _Iterator& i) : mCurrent(i) { }

    // Allow iterator to const_iterator conversion
    template<typename _Iter>
    __wrapper_iterator(const __wrapper_iterator<_Iter, _Container>& i)
        : mCurrent(i.base()) { }

    // Forward iterator requirements
    reference operator*() const { return *mCurrent; }
    pointer operator->() const { return mCurrent; }
    __wrapper_iterator& operator++() {
        ++mCurrent;
        return *this;
    }
    __wrapper_iterator operator++(int) {
        return __wrapper_iterator(mCurrent++);
    }

    // Bidirectional iterator requirements
    __wrapper_iterator& operator--() {
        --mCurrent;
        return *this;
    }
    __wrapper_iterator operator--(int) {
        return __wrapper_iterator(mCurrent--);
    }

    // Random access iterator requirements
    reference operator[](const difference_type& n) const {
        return mCurrent[n];
    }

    __wrapper_iterator& operator+=(const difference_type& n) {
        mCurrent += n;
        return *this;
    }

    __wrapper_iterator operator+(const difference_type& n) const {
        return __wrapper_iterator(mCurrent + n);
    }

    __wrapper_iterator& operator-=(const difference_type& n) {
        mCurrent -= n; return *this;
    }

    __wrapper_iterator operator-(const difference_type& n) const {
        return __wrapper_iterator(mCurrent - n);
    }

    const _Iterator& base() const {
        return mCurrent;
    }

  private:
    _Iterator mCurrent;
};

// Forward iterator requirements
template<typename _IteratorL, typename _IteratorR, typename _Container>
inline bool
operator==(const __wrapper_iterator<_IteratorL, _Container>& lhs,
           const __wrapper_iterator<_IteratorR, _Container>& rhs)
{ return lhs.base() == rhs.base(); }

template<typename _Iterator, typename _Container>
inline bool
operator==(const __wrapper_iterator<_Iterator, _Container>& lhs,
           const __wrapper_iterator<_Iterator, _Container>& rhs)
{ return lhs.base() == rhs.base(); }

template<typename _IteratorL, typename _IteratorR, typename _Container>
inline bool
operator!=(const __wrapper_iterator<_IteratorL, _Container>& lhs,
           const __wrapper_iterator<_IteratorR, _Container>& rhs)
{ return lhs.base() != rhs.base(); }

template<typename _Iterator, typename _Container>
inline bool
operator!=(const __wrapper_iterator<_Iterator, _Container>& lhs,
           const __wrapper_iterator<_Iterator, _Container>& rhs)
{ return lhs.base() != rhs.base(); }

// operator+ so we support 100 + iterator<>.
template<typename _Iterator, typename _Container>
inline __wrapper_iterator<_Iterator, _Container>
operator+(typename __wrapper_iterator<_Iterator, _Container>::difference_type n,
          const __wrapper_iterator<_Iterator, _Container>& i)
{ return __wrapper_iterator<_Iterator, _Container>(i.base() + n); }

// operator- : diff is supported on iterators.

template<typename _Iterator, typename _Container>
inline typename __wrapper_iterator<_Iterator, _Container>::difference_type
operator-(const __wrapper_iterator<_Iterator, _Container>& lhs,
          const __wrapper_iterator<_Iterator, _Container>& rhs)
{ return lhs.base() - rhs.base(); }

}  // namespace std

namespace android {

// Shorthand to return the catogory of an iterator. Not part of the
// STL -> android namespace.
template<typename _Iterator>
inline typename std::iterator_traits<_Iterator>::iterator_category
iterator_category(const _Iterator&)
{ return typename std::iterator_traits<_Iterator>::iterator_category(); }

// Detect wrapper iterators.
template<typename _T>
struct is_wrapper_iterator: public std::false_type { };

template<typename _Iterator, typename _Container>
struct is_wrapper_iterator<std::__wrapper_iterator<_Iterator, _Container> >:
            public std::true_type { };

// iter::base
//
// For wrapper iterators, android::iter::base(it) returns a pointer
// (it.base()) which is going to match implementation(s) that use
// pointers (e.g memmove).
template<typename _Iterator,
         bool _IsWrapper = is_wrapper_iterator<_Iterator>::value>
struct iter {
    static _Iterator base(_Iterator it) { return it; }
};

template<typename _Iterator>
struct iter<_Iterator, true> {
    static typename _Iterator::iterator_type base(_Iterator it) {
        return it.base();
    }
};

}  // namespace android

namespace std {

// Utilities: distance().

template<typename _InputIterator>
inline typename iterator_traits<_InputIterator>::difference_type
distance(_InputIterator first, _InputIterator last,
         input_iterator_tag)  // Match input iterators.
{
    typename iterator_traits<_InputIterator>::difference_type dist = 0;
    while (first != last) {
        ++first;
        ++dist;
    }
    return dist;
}

// Random access iterator: equivalent to mem pointer arithmetic.
template<typename _RandomAccessIterator>
inline typename iterator_traits<_RandomAccessIterator>::difference_type
distance(_RandomAccessIterator first, _RandomAccessIterator last,
         random_access_iterator_tag)  // Match random access iterators.
{
    return last - first;
}

/**
 * Iterator arithmetic.
 * @param first An input iterator.
 * @param last  An input iterator.
 * @return The distance between them.
 */
template<typename _InputIterator>
inline typename iterator_traits<_InputIterator>::difference_type
distance(_InputIterator first, _InputIterator last)
{
    // The correct implementation (above) will be called based on the
    // iterator's category.
    return distance(first, last, android::iterator_category(first));
}

}  // namespace std

#endif  // ANDROID_ASTL_ITERATOR__