// bslstl_forwarditerator.h                                           -*-C++-*-
#ifndef INCLUDED_BSLSTL_FORWARDITERATOR
#define INCLUDED_BSLSTL_FORWARDITERATOR

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

//@PURPOSE: Provide a template to create STL-compliant forward iterators.
//
//@CLASSES:
//  bslstl::ForwardIterator: forward iterator template
//
//@CANONICAL_HEADER: bsl_iterator.h
//
//@SEE_ALSO: bslstl_iterator, bslstl_bidirectionaliterator,
//           bslstl_randomaccessiterator
//
//@DESCRIPTION: This component provides an iterator adaptor that, given an
// implementation class defining a core set of iterator functionality, adapts
// it to provide an STL-compliant forward iterator interface.  The set of
// requirements for a forward iterator is found in "Table 106: Forward iterator
// requirements", under the tag "[forward.iterators]".  (Note that this
// reference is sourced in N3092, a C++0x working paper; the actual table
// number may vary in the actual standard.)  Include bsl_iterator.h to use this
// component.
//
///Usage
///-----
// Given the following "iterator-like" implementation class:
//..
//  template <class T>
//  class my_IteratorImp {
//    public:
//      // CREATORS
//      my_IteratorImp();
//      my_IteratorImp(const my_IteratorImp&);
//      ~my_IteratorImp();
//
//      // An additional value-constructor should be supplied that can be
//      // called by the unspecified container type, providing access to the
//      // container's internal data structure that is to be iterated over.
//      // This would typically be called by 'begin' and 'end'.
//
//      // MANIPULATORS
//      my_IteratorImp& operator=(const my_IteratorImp&);
//
//      void operator++();
//
//      // ACCESSORS
//      T& operator*() const;
//  };
//
//  template <class T>
//  bool operator==(const my_IteratorImp<T>& lhs,
//                  const my_IteratorImp<T>& rhs);
//..
// simply add the following two 'typedef's to any container class that provides
// 'my_IteratorImp<T>' access, and the container will have STL-compliant
// forward iterators:
//..
//  typedef bslstl::ForwardIterator<T, my_IteratorImp<T> > iterator;
//  typedef bslstl::ForwardIterator<const T, my_IteratorImp<T> >
//                                                              const_iterator;
//..
// Note that the implementation for 'const_iterator' is 'my_IteratorImp<T>' and
// *not* 'my_IteratorImp<const T>', rather the 'const' is added to the return
// value of 'operator*' by way of conversion to the first template argument.

// DOCUMENTATION IS INCOMPLETE: Note that we need to say something about 'T'
// and iterator stability.  Incrementing two copies of 'T' must produce two
// iterators that compare equal, and refer to exactly the same object.  Without
// this guarantee, we cannot build the multi-pass property of Forward Iterator,
// and merely have an Input Iterator.  This is not something we can detect at
// compile time, and is prohibitively expensive to validate at runtime.  It is
// the sort of thing that should be validated by a Forward Iterator test suite,
// it could be what we really need, in addition to the adapters, is a
// generalized test case to validate that a type conforms to the iterator
// requirements.

#include <bslscm_version.h>

#include <bslstl_iterator.h>

#include <bslmf_islvaluereference.h>
#include <bslmf_removecv.h>
#include <bslmf_util.h>

#include <bsls_compilerfeatures.h>
#include <bsls_libraryfeatures.h>
#include <bsls_util.h>

#include <cstddef>
#include <iterator>

namespace BloombergLP {

namespace bslstl {

                    //======================
                    // class ForwardIterator
                    //======================

template <class T, class ITER_IMP, class TAG_TYPE = std::forward_iterator_tag>
class ForwardIterator
#if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD)
// Sun CC workaround: iterators must be derived from 'std::iterator' to work
// with the native std library algorithms.  However, 'std::iterator' is
// deprecated in C++17, so do not rely on derivation unless required, to avoid
// deprecation warnings on modern compilers.
    : public std::iterator<TAG_TYPE,
                           typename bsl::remove_cv<T>::type,
                           std::ptrdiff_t,
                           T *,
                           T&>
#endif
{
    // 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 "forward iterator" in the C++ standard.  If 'T' is
    // const-qualified, then the resulting type is a const 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 == j // convertible to bool           Equality comparison
    //     *i     // reference convertible to T&   Element access (dereference)
    //..

#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE) && \
    defined(BSLS_COMPILERFEATURES_SUPPORT_STATIC_ASSERT)
    static_assert(
        bsl::is_lvalue_reference<
                    decltype(*bslmf::Util::declval<const ITER_IMP&>())>::value,
        "Forward iterators must return a true reference to their element when "
                                                              "dereferenced.");
#endif

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

    typedef ForwardIterator<UnCvqT, ITER_IMP, TAG_TYPE>
                                             ForwardNonConstIterator;

  private:
    // DATA
    ITER_IMP d_imp;  // externally-supplied implementation of iterator
                     // functionality

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

    // CREATORS
    ForwardIterator();
        // Construct the default value for this iterator type.  All default-
        // constructed 'ForwardIterator' 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.

    ForwardIterator(const ITER_IMP& implementation);
        // Construct a forward iterator having the specified 'implementation'
        // of the parameterized 'ITER_IMP' type.

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

    ForwardIterator(const ForwardNonConstIterator& other);
        // Construct a forward iterator from the specified 'other' iterator of
        // another (compatible) 'ForwardIterator' 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.

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

    // MANIPULATORS
    //! ForwardIterator& operator=(const ForwardIterator& 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.

    ForwardIterator& operator=(const ForwardNonConstIterator& rhs);
        // Copy the value of the specified 'rhs' of another (compatible)
        // 'ForwardIterator' 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.

    ForwardIterator& 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.

    ITER_IMP& imp();
        // Return a modifiable reference to the implementation object.

    // ACCESSORS
    T& operator*() const;
        // Return a reference to the current, modifiable element.  The behavior
        // is undefined if this iterator has the past-the-end value for an
        // iterator over the underlying sequence.

    T *operator->() const;
        // Return a pointer to the current, modifiable element.  The behavior
        // is undefined if this iterator has the past-the-end value for an
        // iterator over the underlying sequence.

    const ITER_IMP& imp() const;
        // Return a non-modifiable reference to the implementation object.
};

// FREE OPERATORS
template <class T1, class T2, class ITER_IMP, class TAG_TYPE>
bool operator==(const ForwardIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                const ForwardIterator<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 ForwardIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                const ForwardIterator<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>
ForwardIterator<T,ITER_IMP,TAG_TYPE>
operator++(ForwardIterator<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.

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

                        //----------------------
                        // class ForwardIterator
                        //----------------------

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

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

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

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

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

template <class T, class ITER_IMP, class TAG_TYPE>
inline
ITER_IMP& ForwardIterator<T,ITER_IMP,TAG_TYPE>::imp()
{
    return d_imp;
}

// ACCESSORS
template <class T, class ITER_IMP, class TAG_TYPE>
inline
T& ForwardIterator<T,ITER_IMP,TAG_TYPE>::operator*() const
{
    return *d_imp;
}

template <class T, class ITER_IMP, class TAG_TYPE>
inline
T *ForwardIterator<T,ITER_IMP,TAG_TYPE>::operator->() const
{
    return BSLS_UTIL_ADDRESSOF(*d_imp);
}

template <class T, class ITER_IMP, class TAG_TYPE>
inline
const ITER_IMP&
ForwardIterator<T,ITER_IMP,TAG_TYPE>::imp() const
{
    return d_imp;
}

}  // close package namespace

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

template <class T1, class T2, class ITER_IMP, class TAG_TYPE>
inline
bool bslstl::operator==(const ForwardIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                        const ForwardIterator<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 ForwardIterator<T1,ITER_IMP,TAG_TYPE>& lhs,
                        const ForwardIterator<T2,ITER_IMP,TAG_TYPE>& rhs)
{
    return !(lhs == rhs);
}

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#ifdef bslstl_ForwardIterator
#undef bslstl_ForwardIterator
#endif
#define bslstl_ForwardIterator bslstl::ForwardIterator
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // 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 ----------------------------------