// bsltf_inputiterator.h                                              -*-C++-*-
#ifndef INCLUDED_BSLTF_INPUTITERATOR
#define INCLUDED_BSLTF_INPUTITERATOR

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

//@PURPOSE: Provide a pure input iterator capable of traversing a range.
//
//@CLASSES:
//  bsltf::InputIterator: empty input iterator template
//
//@DESCRIPTION: This components provides a value-semantic 'class',
// 'bsltf::InputIterator', that defines an input iterator that supports the
// following operations:
//
//: o Obj& operator++()
//:
//: o Obj operator++(int)
//:
//: o pointer operator->() const
//:
//: o reference& operator*() const
//
// The iterator is initializable with either a pointer into a range, or a
// non-pointer iterator over a contiguous range.
//
// This iterator type is typically used to check algorithms for compatibility
// with input iterators.  The goal is to make sure that their code is able to
// compile and work even with the most restrictive input iterator.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Use of 'bsltf::InputIterator':
/// - - - - - - - - - - - - - - - - - - - - - - -
// In the following example we use a 'bsltf::InputIterator' to test that an
// aggregation function compiles and works when instantiated with a pure input
// iterator.
//
// First, we define a function 'sum' that accepts two input iterators and
// returns the sum of all elements in range specified by them:
//..
//  template <class IN_ITER>
//  double sum(IN_ITER first, IN_ITER last)
//      // Return the sum of the 'double's in the specified range
//      // '[ first, last )'.
//  {
//      double total = 0;
//      while (first != last) {
//          total += *first++;
//      }
//      return total;
//  }
//..
// Then, in 'main', we define an array of 'double's and define 'InputIterators'
// pointing to the beginning and ending of it, initializing the iterators with
// pointers:
//..
//  static double myArray[] = { 2.5, 3, 5, 7, 11.5, 5 };
//  enum { k_MY_ARRAY_LEN = sizeof myArray / sizeof *myArray };
//
//  typedef bsltf::InputIterator<const double> Iter;
//
//  Iter begin(myArray + 0), end(myArray + k_MY_ARRAY_LEN);
//..
// Next, we call 'sum' with the two iterators, and observe that its yields the
// expected result, and because it compiles, we know that 'sum' did not attempt
// any operations on the iterators other than those defined for the most basic
// input iterator:
//..
//  const double x = sum(begin, end);
//  assert(34.0 == x);
//..
// Then, we illustrate that we can just make 'begin' and 'end' iterators from
// the array directly with the 'begin' and 'end' class methods of the
// 'InputIteratorUtil' class.
//..
//  typedef bsltf::InputIteratorUtil Util;
//
//  const double y = sum(Util::begin(myArray), Util::end(myArray));
//  assert(34.0 == y);
//..
// Now, we make an 'std::vector' containing the elements of 'myArray':
//..
//  const std::vector<double> v(myArray + 0, myArray + k_MY_ARRAY_LEN);
//..
// Finally, we call 'sum' using, again, the 'begin' and 'end' class methods to
// create iterators for it directly from our 'vector':
//..
//  const double z = sum(Util::begin(v), Util::end(v));
//  assert(34.0 == z);
//..

#include <bslscm_version.h>

#include <bsls_assert.h>
#include <bsls_libraryfeatures.h>

#include <cstddef>
#include <iterator>

namespace BloombergLP {
namespace bsltf {

                            // ===================
                            // class InputIterator
                            // ===================

#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.

template <class TYPE>
class InputIterator : public std::iterator<std::input_iterator_tag,
                                           TYPE,
                                           std::ptrdiff_t,
                                           TYPE *,
                                           TYPE> {
#else
template <class TYPE>
class InputIterator {
#endif
    // Provide an input iterator that iterates that can iterate over a
    // contiguous range of object while supporting no operations other than
    // those defined for 'LegacyInputIterator'.

  public:
    // PUBLIC TYPES
    typedef std::input_iterator_tag  iterator_category;
    typedef TYPE                     value_type;
    typedef std::ptrdiff_t           difference_type;
    typedef TYPE                    *pointer;
    typedef TYPE&                    reference;

  private:
    // DATA
    TYPE *d_value_p;

    // FRIENDS
    template <class TYPE2>
    friend bool operator==(const InputIterator<TYPE2>&,
                           const InputIterator<TYPE2>&);
    template <class TYPE2>
    friend bool operator!=(const InputIterator<TYPE2>&,
                           const InputIterator<TYPE2>&);

  public:
    // CREATORS
    InputIterator();
        // Construct an empty input iterator.

    explicit InputIterator(TYPE *ptr);
        // Construct an input iterator based on the specified 'ptr'.

    // InputIterator(const InputIterator& original) = default;
        // Construct a copy of the specified 'original' object.

    // ~InputIterator() = default;
        // Destroy this object.

    // MANIPULATORS
    // InputIterator& operator=(const InputIterator& rhs) = default;
        // Assign to this object the value of the specified 'rhs' and return a
        // reference to this modifiable object.

    InputIterator& operator++();
        // Increment this iterator to refer to the next contiguous 'TYPE'
        // object, and return a reference to after the increment.  The behavior
        // is undefined if this iterator is empty.

    InputIterator operator++(int);
        // Copy this iterator, increment, and return by value the copy that was
        // made prior to the increment.  The behavior is undefined if this
        // iterator is empty.

    // ACCESSORS
    pointer operator->() const;
        // Return a pointer to the 'TYPE' object referred to by this iterator.
        // The behavior is undefined if this iterator is empty.

    reference operator*() const;
        // Return a const reference to the 'TYPE' object referred to by this
        // iterator.  The behavior is undefined if this iterator is empty.
};

// FREE OPERATORS
template <class TYPE>
inline
bool operator==(const InputIterator<TYPE>& lhs,
                const InputIterator<TYPE>& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' refer to the same 'TYPE'
    // object and 'false' othersise.

template <class TYPE>
inline
bool operator!=(const InputIterator<TYPE>& lhs,
                const InputIterator<TYPE>& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' do not refer to the same
    // 'TYPE' object and 'false' othersise.

                          // =======================
                          // class InputIteratorUtil
                          // =======================

struct InputIteratorUtil {
    // This namespace 'struct' allows the easy creation of 'begin' and 'end'
    // iterators from a variety of contiguous range types.  Either the argument
    // must be an array, or a container that supports the following operations:
    //: o 'size()'
    //:
    //: o 'operator[](size_t)' (if 0 != size())
    //
    // and the type 'CONTIGUOUS_CONTAINER::value_type'.

    // CLASS METHODS
    template <class CONTIGUOUS_CONTAINER>
    static InputIterator<typename CONTIGUOUS_CONTAINER::value_type> begin(
                                              CONTIGUOUS_CONTAINER& container);
    template <class CONTIGUOUS_CONTAINER>
    static InputIterator<const typename CONTIGUOUS_CONTAINER::value_type>
                                  begin(const CONTIGUOUS_CONTAINER& container);
        // Return an 'InputIterator' referring to the first element of the
        // specified 'container' or a null iterator if 'container' is empty.

    template <class TYPE, std::size_t LEN>
    static InputIterator<TYPE> begin(TYPE (&array)[LEN]);
    template <class TYPE, std::size_t LEN>
    static InputIterator<const TYPE> begin(const TYPE (&array)[LEN]);
        // Return an 'InputIterator' referring to the first element of the
        // specified 'array'.

    template <class CONTIGUOUS_CONTAINER>
    static InputIterator<typename CONTIGUOUS_CONTAINER::value_type> end(
                                              CONTIGUOUS_CONTAINER& container);
    template <class CONTIGUOUS_CONTAINER>
    static InputIterator<const typename CONTIGUOUS_CONTAINER::value_type> end(
                                        const CONTIGUOUS_CONTAINER& container);
        // Return an 'InputIterator' referring to after the last element of the
        // specified 'container' or a null iterator if 'container' is empty.

    template <class TYPE, std::size_t LEN>
    static InputIterator<TYPE> end(TYPE (&array)[LEN]);
    template <class TYPE, std::size_t LEN>
    static InputIterator<const TYPE> end(const TYPE (&array)[LEN]);
        // Return an 'InputIterator' referring to after the last element of the
        // specified 'array'.
};

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

                              // -------------------
                              // class InputIterator
                              // -------------------

// CREATORS
template<class TYPE>
inline
InputIterator<TYPE>::InputIterator()
: d_value_p(0)
{
}

template<class TYPE>
inline
InputIterator<TYPE>::InputIterator(TYPE *ptr)
: d_value_p(ptr)
{
}

// MANIPULATORS
template<class TYPE>
inline
InputIterator<TYPE>& InputIterator<TYPE>::operator++()
{
    BSLS_ASSERT_SAFE(d_value_p);

    ++d_value_p;

    return *this;
}

template<class TYPE>
inline
InputIterator<TYPE> InputIterator<TYPE>::operator++(int)
{
    BSLS_ASSERT_SAFE(d_value_p);

    TYPE *prev = d_value_p++;
    return InputIterator(prev);
}

// ACCESSORS
template<class TYPE>
inline
typename InputIterator<TYPE>::pointer InputIterator<TYPE>::operator->() const
{
    BSLS_ASSERT_SAFE(d_value_p);

    return d_value_p;
}

template<class TYPE>
inline
typename InputIterator<TYPE>::reference InputIterator<TYPE>::operator*() const
{
    BSLS_ASSERT_SAFE(d_value_p);

    return *d_value_p;
}

}  // close package namespace

// FREE OPERATORS
template <class TYPE>
inline
bool bsltf::operator==(const bsltf::InputIterator<TYPE>& lhs,
                       const bsltf::InputIterator<TYPE>& rhs)
{
    return lhs.d_value_p == rhs.d_value_p;
}

template <class TYPE>
inline
bool bsltf::operator!=(const bsltf::InputIterator<TYPE>& lhs,
                       const bsltf::InputIterator<TYPE>& rhs)
{
    return lhs.d_value_p != rhs.d_value_p;
}

namespace bsltf {

                          // -----------------------
                          // class InputIteratorUtil
                          // -----------------------

// CLASS METHODS
template <class CONTIGUOUS_CONTAINER>
inline
InputIterator<typename CONTIGUOUS_CONTAINER::value_type>
                      InputIteratorUtil::begin(CONTIGUOUS_CONTAINER& container)
{
    return InputIterator<typename CONTIGUOUS_CONTAINER::value_type>(
                                    0 == container.size() ? 0 : &container[0]);
}

template <class CONTIGUOUS_CONTAINER>
InputIterator<const typename CONTIGUOUS_CONTAINER::value_type>
                InputIteratorUtil::begin(const CONTIGUOUS_CONTAINER& container)
{
    return InputIterator<const typename CONTIGUOUS_CONTAINER::value_type>(
                                    0 == container.size() ? 0 : &container[0]);
}

template <class TYPE, std::size_t LEN>
InputIterator<TYPE> InputIteratorUtil::begin(TYPE (&array)[LEN])
{
    return InputIterator<TYPE>(array + 0);
}

template <class TYPE, std::size_t LEN>
InputIterator<const TYPE> InputIteratorUtil::begin(const TYPE (&array)[LEN])
{
    return InputIterator<const TYPE>(array + 0);
}

template <class CONTIGUOUS_CONTAINER>
InputIterator<typename CONTIGUOUS_CONTAINER::value_type>
                        InputIteratorUtil::end(CONTIGUOUS_CONTAINER& container)
{
    return InputIterator<typename CONTIGUOUS_CONTAINER::value_type>(
                 0 == container.size() ? 0 : &container[0] + container.size());
}

template <class CONTIGUOUS_CONTAINER>
InputIterator<const typename CONTIGUOUS_CONTAINER::value_type>
                  InputIteratorUtil::end(const CONTIGUOUS_CONTAINER& container)
{
    return InputIterator<const typename CONTIGUOUS_CONTAINER::value_type>(
                 0 == container.size() ? 0 : &container[0] + container.size());
}

template <class TYPE, std::size_t LEN>
InputIterator<TYPE> InputIteratorUtil::end(TYPE (&array)[LEN])
{
    return InputIterator<TYPE>(array + LEN);
}

template <class TYPE, std::size_t LEN>
InputIterator<const TYPE> InputIteratorUtil::end(const TYPE (&array)[LEN])
{
    return InputIterator<const TYPE>(array + LEN);
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2021 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 ----------------------------------