// bslstl_bidirectionaliterator.h                                     -*-C++-*-
#ifndef INCLUDED_BSLSTL_BIDIRECTIONALITERATOR
#define INCLUDED_BSLSTL_BIDIRECTIONALITERATOR

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a template to create STL-compliant bidirectional iterators.
//
//@CLASSES:
//  bslstl::BidirectionalIterator: bidirectional iterator template
//
//@CANONICAL_HEADER: bsl_iterator.h
//
//@SEE_ALSO: bslstl_iterator, bslstl_forwarditerator,
//           bslstl_randomaccessiterator
//
//@DESCRIPTION: This component provides an iterator adaptor that, given an
// implementation class defining a core set of iterator functionality specified
// in the class level documentation, adapts it to provide an STL-compliant
// bidirectional iterator interface.  'bslstl::BidirectionalIterator' meets the
// requirements of a bidirectional iterator described in the C++11 standard
// [24.2.7] under the tag "[bidirectional.iterators]".  Include bsl_iterator.h
// to use this component.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Defining a Standard Compliant Bidirectional Iterator
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to create a standard compliant bidirectional access iterator
// for a container.
//
// First, we define an iterator, 'MyArrayIterator', that meets the requirements
// of the 'IMP_ITER' template parameter of 'BidirectionalIterator' class (see
// class level documentation), but does not meet the full set of requirements
// for a bidirectional iterator as defined by the C++ standard.  Note that the
// following shows only the public interface required.  Private members and
// additional methods that may be needed to implement this class are elided in
// this example:
//..
//  template <class VALUE>
//  class MyArrayIterator {
//      // This class implements the minimal requirements to implement a
//      // bidirectional iterator using 'bslstl::BidirectionalIterator'.
//
//    public:
//      // CREATORS
//      MyArrayIterator();
//          // Create a 'MyArrayIterator' object that does not refer to any
//          // value.
//
//      MyArrayIterator(const MyArrayIterator& original);
//          // Create a 'MyArrayIterator' object having the same value
//          // as the specified 'original' object.
//
//      ~MyArrayIterator();
//          // Destroy this object;
//
//      // MANIPULATORS
//      MyArrayIterator& operator=(const MyArrayIterator& rhs);
//          // Assign to this object the value of the specified 'rhs' object,
//          // and return a reference providing modifiable access to this
//          // object.
//
//      void operator++();
//          // Increment this object to refer to the next element in an array.
//
//      void operator--();
//          // Decrement this object to refer to the previous element in an
//          // array.
//
//      // ACCESSORS
//      VALUE& operator*() const;
//          // Return a reference providing modifiable access to the value (of
//          // the parameterized 'VALUE' type) of the element referred to by
//          // this object.
//  };
//
//  template <class VALUE>
//  bool operator==(const MyArrayIterator<VALUE>&,
//                  const MyArrayIterator<VALUE>&);
//..
// Notice that 'MyArrayIterator' does not implement a complete standard
// compliant bidirectional iterator.  It is missing methods such as 'operator+'
// and 'operator[]'.
//
// Then, we define the interface for our container class template,
// 'MyFixedSizeArray'.  The implementation of the interface is elided for
// brevity:
//..
//  template <class VALUE, int SIZE>
//  class MyFixedSizeArray {
//      // This class implements a container that contains the parameterized
//      // 'SIZE' number of elements of the parameterized 'VALUE' type.
//
//      // DATA
//      VALUE d_array[SIZE];   // storage of the container
//
//    public:
//      // PUBLIC TYPES
//      typedef VALUE value_type;
//..
// Now, we use 'BidirectionalIterator' to create a standard compliant iterator
// for this container:
//..
//      typedef bslstl::BidirectionalIterator<VALUE,
//                                           MyArrayIterator<VALUE> > iterator;
//      typedef bslstl::BidirectionalIterator<const VALUE,
//                                           MyArrayIterator<VALUE> >
//                                                              const_iterator;
//..
// Notice that the implementation for 'const_iterator' is
// 'MyArrayIterator<VALUE>' and *not* 'MyArrayIterator<const VALUE>'.
//
// Next, we continue defining the rest of the class.
//..
//      // CREATORS
//      //! MyFixedSizeArray() = default;
//          // Create a 'MyFixedSizeArray' object having the parameterized
//          // 'SIZE' number of elements of the parameterized type 'VALUE'.
//
//      //! MyFixedSizeArray(const MyFixedSizeArray& original) = default;
//          // Create a 'MyFixedSizeArray' object having same number of
//          // elements as that of the specified 'original', the same value of
//          // each element as that of corresponding element in 'original'.
//
//      //! ~MyFixedSizeArray() = default;
//          // Destroy this object.
//
//      // MANIPULATORS
//      iterator begin();
//          // Return a bidirectional iterator providing modifiable access to
//          // the first valid element of this object.
//
//      iterator end();
//          // Return a bidirectional iterator providing modifiable access to
//          // the last valid element of this object.
//
//      VALUE& operator[](int position);
//          // Return a reference providing modifiable access to the element at
//          // the specified 'position'.
//
//      // ACCESSORS
//      const_iterator begin() const;
//          // Return a bidirectional iterator providing non-modifiable access
//          // to the first valid element of this object.
//
//      const_iterator end() const;
//          // Return a bidirectional iterator providing non-modifiable access
//          // to the last valid element of this object.
//
//      const VALUE& operator[](int position) const;
//          // Return a reference providing non-modifiable access to the
//          // specified 'i'th element in this object.
//  };
//..
// Then, we create a 'MyFixedSizeArray' and initialize its elements:
//..
//  MyFixedSizeArray<int, 5> fixedArray;
//  fixedArray[0] = 1;
//  fixedArray[1] = 2;
//  fixedArray[2] = 3;
//  fixedArray[3] = 4;
//  fixedArray[4] = 5;
//..
// Finally, to show that 'MyFixedSizeArray::iterator' can be used as a
// bidirectional iterator, we invoke a function that takes bidirectional
// iterators as parameters, such as 'std::reverse', on the 'begin' and 'end'
// iterators and verify the results:
//..
//  std::reverse(fixedArray.begin(), fixedArray.end());
//
//  assert(fixedArray[0] == 5);
//  assert(fixedArray[1] == 4);
//  assert(fixedArray[2] == 3);
//  assert(fixedArray[3] == 2);
//  assert(fixedArray[4] == 1);
//..

#include <bslscm_version.h>

#include <bslstl_forwarditerator.h>
#include <bslstl_iterator.h>

#include <bslmf_removecv.h>

#include <iterator>

#include <cstddef>  // 'ptrdiff_t'

namespace BloombergLP {

namespace bslstl {

                        //============================
                        // class BidirectionalIterator
                        //============================

template <class T, class ITER_IMP, class TAG_TYPE =
                                               std::bidirectional_iterator_tag>
class BidirectionalIterator
    : public ForwardIterator<T, ITER_IMP, TAG_TYPE> {
    // Given an 'ITER_IMP' type that implements a minimal subset of an iterator
    // interface, this template generates a complete iterator that meets all of
    // the requirements of a "bidirectional iterator" in the C++ standard.  If
    // 'T' is 'const'-qualified, then the resulting type is a constant
    // iterator.  'T' shall not be a function, reference type or void.
    // 'ITER_IMP' must provide public operations so that, for objects 'i' and
    // 'j' of type 'ITER_IMP', the following operations are supported:
    //..
    //     ITER_IMP i;                            default construction
    //     ITER_IMP j(i);                         copy construction
    //     i = j                                  assignment
    //     ++i                                    increment to next element
    //     --i                                    decrement to previous element
    //     i == j // convertible to bool          equality comparison
    //     *i     // reference convertible to T&  element access (dereference)
    //..

    // PRIVATE TYPES
    typedef typename bsl::remove_cv<T>::type UnCvqT;  // value type without
                                                      // 'const' and
                                                      // 'volatile'
                                                      // qualifications

    typedef BidirectionalIterator<UnCvqT, ITER_IMP, TAG_TYPE>
                                                 BidirectionalNonConstIterator;

  public:
    // TYPES
    typedef UnCvqT                           value_type;
    typedef std::ptrdiff_t                   difference_type;
    typedef T                               *pointer;
    typedef T&                               reference;
    typedef std::bidirectional_iterator_tag  iterator_category;

    // CREATORS
    BidirectionalIterator();
        // Construct the default value for this iterator type.  All default-
        // constructed 'BidirectionalIterator' objects represent
        // non-dereferenceable iterators into the same empty range.  They do
        // not have a singular value unless an object of the type specified by
        // the template parameter 'ITER_IMP' has a singular value after
        // value-initialization.

    BidirectionalIterator(const ITER_IMP& implementation);          // IMPLICIT
        // Construct a bidirectional iterator having the specified
        // 'implementation' of the parameterized 'ITER_IMP' type.

    //! BidirectionalIterator(const BidirectionalIterator& original);
        // Construct a bidirectional iterator having the same value as the
        // 'original' iterator.  Note that this method's definition is compiler
        // generated.

    BidirectionalIterator(const BidirectionalNonConstIterator& other);
        // Construct a bidirectional iterator from the specified 'other'
        // iterator of another (compatible) 'BidirectionalIterator' type, e.g.,
        // a mutable iterator of the same type.  Note that this constructor may
        // be the copy constructor (inhibiting the implicit declaration of a
        // copy constructor above), or may be an additional overload.


    //! ~BidirectionalIterator();
        // Destroy this iterator.  Note that this method's definition is
        // compiler generated.

    // MANIPULATORS
    //! BidirectionalIterator& operator=(const BidirectionalIterator& rhs);
        // Copy the value of the specified 'rhs' to this iterator.  Return a
        // reference to this modifiable object.  Note that this method's
        // definition is compiler generated.

    BidirectionalIterator& operator=(const BidirectionalNonConstIterator& rhs);
        // Copy the value of the specified 'rhs' of another (compatible)
        // 'BidirectionalIterator' type, (e.g., a mutable iterator of the same
        // type) to this iterator.  Return a reference to this modifiable
        // object.  Note that this method may be the copy-assignment operator
        // (inhibiting the implicit declaration of a copy-assignment operator
        // above), or may be an additional overload.

    BidirectionalIterator& operator++();
        // Increment to the next element.  Return a reference to this
        // modifiable iterator.  The behavior is undefined if, on entry, this
        // iterator has the past-the-end value for an iterator over the
        // underlying sequence.

    BidirectionalIterator& operator--();
        // Decrement to the previous element.  Return a reference to this
        // modifiable iterator.  The behavior is undefined if, on entry, this
        // iterator has the same value as an iterator the refers to the start
        // of the underlying sequence.
};

// FREE OPERATORS
template <class T1, class T2, class ITER_IMP, class TAG_TYPE>
bool operator==(const BidirectionalIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                const BidirectionalIterator<T2,ITER_IMP,TAG_TYPE>& rhs);
    // Return 'true' if the specified 'lhs' iterator has the same value as the
    // specified 'rhs' iterator, and 'false' otherwise.  Two iterators have the
    // same value if they refer to the same element, or both have the past-the-
    // end value for the underlying sequence.  The behavior is undefined unless
    // both iterators refer to the same underlying sequence.

template <class T1, class T2, class ITER_IMP, class TAG_TYPE>
bool operator!=(const BidirectionalIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                const BidirectionalIterator<T2,ITER_IMP,TAG_TYPE>& rhs);
    // Return 'true' if the specified 'lhs' iterator does not have the same
    // value as the specified 'rhs' iterator, and 'false' otherwise.  Two
    // iterators do not have the same value if (1) they do not refer to the
    // same element and (2) both do not have the past-the-end iterator value
    // for the underlying sequence.  The behavior is undefined unless both
    // iterators refer to the same underlying sequence.

template <class T, class ITER_IMP, class TAG_TYPE>
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>
operator++(BidirectionalIterator<T,ITER_IMP,TAG_TYPE>& iter, int);
    // Increment the specified 'iter' to the next element.  Return the previous
    // value of 'iter'.  The behavior is undefined if, on entry, 'iter' has the
    // past-the-end value for an iterator of the underlying sequence.

template <class T, class ITER_IMP, class TAG_TYPE>
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>
operator--(BidirectionalIterator<T,ITER_IMP,TAG_TYPE>& iter, int);
    // Decrement the specified 'iter' to the previous element.  Return the
    // previous value of 'iter'.  The behavior is undefined if, on entry,
    // 'iter' has the same value as an iterator to the start of the underlying
    // sequence.

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================

                //----------------------------
                // class BidirectionalIterator
                //----------------------------

// CREATORS
template <class T, class ITER_IMP, class TAG_TYPE>
inline
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>::BidirectionalIterator()
: ForwardIterator<T,ITER_IMP,TAG_TYPE>()
{
}

template <class T, class ITER_IMP, class TAG_TYPE>
inline
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>::
BidirectionalIterator(const ITER_IMP& implementation)
: ForwardIterator<T,ITER_IMP,TAG_TYPE>(implementation)
{
}

template <class T, class ITER_IMP, class TAG_TYPE>
inline
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>::BidirectionalIterator(
                                    const BidirectionalNonConstIterator& other)
: ForwardIterator<T,ITER_IMP,TAG_TYPE>(other.imp())
{
}

// MANIPULATORS
template <class T, class ITER_IMP, class TAG_TYPE>
inline
BidirectionalIterator<T,ITER_IMP,TAG_TYPE> &
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>::operator=(
                                      const BidirectionalNonConstIterator& rhs)
{
    ForwardIterator<T,ITER_IMP,TAG_TYPE>::operator=(rhs);
    return *this;
}


template <class T, class ITER_IMP, class TAG_TYPE>
inline
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>&
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>::operator++()
{
    ++this->imp();
    return *this;
}

template <class T, class ITER_IMP, class TAG_TYPE>
inline
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>&
BidirectionalIterator<T,ITER_IMP,TAG_TYPE>::operator--()
{
    --this->imp();
    return *this;
}

}  // close package namespace

// FREE OPERATORS
template <class T1, class T2, class ITER_IMP, class TAG_TYPE>
inline
bool bslstl::operator==(const BidirectionalIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                        const BidirectionalIterator<T2,ITER_IMP,TAG_TYPE>& rhs)
{
    return lhs.imp() == rhs.imp();
}

template <class T1, class T2, class ITER_IMP, class TAG_TYPE>
inline
bool bslstl::operator!=(const BidirectionalIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                        const BidirectionalIterator<T2,ITER_IMP,TAG_TYPE>& rhs)
{
    return !(lhs == rhs);
}

template <class T, class ITER_IMP, class TAG_TYPE>
inline
bslstl::BidirectionalIterator<T,ITER_IMP,TAG_TYPE>
bslstl::operator++(BidirectionalIterator<T,ITER_IMP,TAG_TYPE>& iter, int)
{
    BidirectionalIterator<T,ITER_IMP,TAG_TYPE> tmp(iter);
    ++iter;
    return tmp;
}

template <class T, class ITER_IMP, class TAG_TYPE>
inline
bslstl::BidirectionalIterator<T,ITER_IMP,TAG_TYPE>
bslstl::operator--(BidirectionalIterator<T,ITER_IMP,TAG_TYPE>& iter, int)
{
    BidirectionalIterator<T,ITER_IMP,TAG_TYPE> tmp(iter);
    --iter;
    return tmp;
}

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------