// bslstl_iteratorutil.h                                              -*-C++-*-
#ifndef INCLUDED_BSLSTL_ITERATORUTIL
#define INCLUDED_BSLSTL_ITERATORUTIL

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

//@PURPOSE: Provide utilities operating on iterators and iterator ranges.
//
//@CLASSES:
//  bslstl::IteratorUtil:
//
//@SEE_ALSO: bslstl_hashtable
//
//@DESCRIPTION: This component provides a namespace, 'bslstl::IteratorUtil',
// containing utility functions for iterator types.  In particular, this
// component includes a function 'insertDistance' that returns the number of
// elements that should be accounted for when range-inserting in a container,
// given a pair of iterator 'a' and 'b' describing a half-open range
// '[a .. b)'.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Finding the Distance Between Two Random Access Iterators
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to find the number of elements between two random access
// iterators.
//
// First, we create an array of integer values and two pointers (which are
// considered random access iterators) referring to the beginning and end of a
// range within that array:
//..
//  int values[] = { 1, 2, 3, 4, 5 };
//  int *begin = &values[0];
//  int *end   = &values[3];
//..
// Now, we use the 'IteratorUtil::insertDistance' class method to calculate the
// distance of the open range '[begin .. end)':
//..
//  std::size_t distance = IteratorUtil::insertDistance(begin, end);
//  assert(3 == distance);
//..

#include <bslscm_version.h>

#include <bslstl_iterator.h>  // iterator tags, distance
#include <bslstl_pair.h>      // pair

#include <bslmf_addconst.h>
#include <bslmf_removeconst.h>

#include <bsls_platform.h>

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_nativestd.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

namespace BloombergLP {
namespace bslstl {

                        // ===================
                        // struct IteratorUtil
                        // ===================

struct IteratorUtil {
    // This utility struct provides a namespace for functions on iterators and
    // iterator ranges.

    template <class InputIterator>
    static typename bsl::iterator_traits<InputIterator>::difference_type
    insertDistance(InputIterator first, InputIterator last);
        // Return 0 if the (template parameter) type 'InputIterator' is limited
        // to the standard input-iterator category, otherwise return the number
        // of elements that is reachable from the specified 'first' to (but not
        // including) the specified 'last'.  This function has a constant-time
        // complexity if the iterator category of 'InputIterator' is a strictly
        // a standard input iterator, or is a random access iterator, otherwise
        // it is linear in the length of the range '[first .. last)'.  The
        // behavior is undefined unless 'last' is reachable from 'first'.  Note
        // that this function always returns 0 when compiled with the Sun
        // compiler, while we work around issues in the Sun standard library.

#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
    // These template aliases are 'convenience alises' defined in the standard
    // as 'exposition-only' to simplify the specification of the deduction
    // guides for the associative containers.

    template <class INPUT_ITER>  // aka iter-val-type
    using IterVal_t = typename bsl::iterator_traits<INPUT_ITER>::value_type;
        // returns the 'value_type' of the specified iterator type.

    template <class INPUT_ITER> // aka iter-key-type
    using IterKey_t = bsl::remove_const_t<
        typename bsl::iterator_traits<INPUT_ITER>::value_type::first_type>;
        // returns the 'key-type' of the specified iterator type, which is
        // expected to refer to a 'pair<KEY_TYPE, MAPPED_TYPE>'

    template <class INPUT_ITER> // aka iter-mapped-type
    using IterMapped_t =
        typename bsl::iterator_traits<INPUT_ITER>::value_type::second_type;
        // returns the 'mapped-type' of the specified iterator type, which is
        // expected to refer to a 'pair<KEY_TYPE, MAPPED_TYPE>'

    template <class INPUT_ITER>  // aka iter-to-alloc-type
    using IterToAlloc_t = bsl::pair<
        bsl::add_const_t<
            typename bsl::iterator_traits<INPUT_ITER>::value_type::first_type>,
            typename bsl::iterator_traits<INPUT_ITER>::value_type::second_type
        >;
        // returns the type that is actually stored in a map.  The supplied
        // iterator type is expected to refer to a
        // 'pair<KEY_TYPE, MAPPED_TYPE>'.
#endif

};

// ============================================================================
//                      TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

                    // ------------------
                    // class IteratorUtil
                    // ------------------

template <class InputIterator>
typename bsl::iterator_traits<InputIterator>::difference_type
IteratorUtil::insertDistance(InputIterator first, InputIterator last)
{
    struct impl {
        // This local class provides a utility to estimate the maximum
        // number of elements that may be inserted by a range-insert
        // operation on a standard container, by performing tag dispatch
        // on the iterator's category type.

        static
        typename bsl::iterator_traits<InputIterator>::difference_type
        calc(InputIterator, InputIterator, std::input_iterator_tag)
        {
            return 0;
        }

        static
        typename bsl::iterator_traits<InputIterator>::difference_type
        calc(InputIterator first,
             InputIterator last,
             std::forward_iterator_tag)
        {
            return bsl::distance(first, last);
        }
    };

    typedef typename bsl::iterator_traits<InputIterator>::iterator_category
                                                                  IterCategory;
    return impl::calc(first, last, IterCategory());
}

}  // close package namespace
}  // 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 ----------------------------------