// bslalg_rangecompare.h                                              -*-C++-*-
#ifndef INCLUDED_BSLALG_RANGECOMPARE
#define INCLUDED_BSLALG_RANGECOMPARE

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

//@PURPOSE: Provide algorithms to compare iterator-ranges of elements.
//
//@CLASSES:
//  bslalg::RangeCompare: comparison algorithms for iterator ranges
//
//@SEE_ALSO: bslmf_isbitwiseequalitycomparable
//
//@DESCRIPTION: This component provides a utility 'struct',
// 'bslalg::RangeCompare', that defines two overloaded class methods, 'equal'
// and 'lexicographical', for comparing two ranges, each specified by a pair of
// input iterators that are compliant with the C++11 standard [24.2.3].  The
// 'equal' method determines whether two specified ranges compare equal.  The
// 'lexicographical' method determines whether the first range compares
// lexicographically less than, equal to, or greater than the second range.
// Under certain circumstances, 'bslalg::RangeCompare::equal' and
// 'bslalg::RangeCompare::lexicographical' may perform optimized comparisons,
// as described below.
//
// 'bslalg::RangeCompare::equal' may perform a bit-wise comparison of the two
// ranges when the following two criteria are met:
//: o The input iterators are convertible to a pointer type.
//: o The trait 'bslmf::IsBitwiseEqualityComparable' is declared for
//:   the type of the objects in the ranges being compared.
//
// 'bslalg::RangeCompare::lexicographical' may perform a bit-wise comparison of
// the two ranges when the following criterion is met:
//: o The input iterators are convertible to pointers to a wide or unsigned
//    character type.
//
// Note that a class having the 'bslmf::IsBitwiseEqualityComparable'
// trait can be described as bit-wise comparable and should meet the following
// criteria:
//: o The values represented by two objects belonging to the class are the same
//:   if and only if each of the data members in the class has the same value
//:   in both objects.
//: o The class layout includes no padding.
//: o The class has no virtual members.
//
// Note that this component is for use primarily by the 'bslstl' package.
// Other clients should use the STL algorithms (in headers '<bsl_algorithm.h>'
// and '<bsl_memory.h>').
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Defining Equality-Comparison Operators on a Container
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example we will use the 'bslalg::RangeCompare::equal' class method
// to implement the equality-comparison operators for an iterable container
// type residing in the 'bslstl' package, and highlight the circumstances under
// which the optimization provided by the class method may be applied.
//
// Suppose that we have a new iterable container type that will be included in
// the 'bslstl' package, and we wish to define comparison operators for the
// container.  If the container has an iterator that provides access to the
// container's elements in a consistent order, and the elements themselves are
// equality-comparable, we can implement the container's equality-comparison
// operators by pair-wise comparing each of the elements over the entire range
// of elements in both containers.  In such cases the container can use the
// 'bslalg::RangeCompare::equal' class method to equal-compare the container's
// elements, taking advantage of the optimizations the class method provides
// for bit-wise equality-comparable objects.
//
// First, we create an elided definition of a container class, 'MyContainer',
// which provides read-only iterators of the type 'MyContainer::ConstIterator':
//..
//  template <class VALUE_TYPE>
//  class MyContainer {
//      // This class implements a container, semantically similar to
//      // 'std::vector', holding objects of the (template parameter) type
//      // 'VALUE_TYPE'.
//
//    private:
//      // DATA
//      // ...
//
//    public:
//      // PUBLIC TYPES
//      typedef const VALUE_TYPE *ConstIterator;
//          // This 'typedef' provides an alias for the type of iterator
//          // providing non-modifiable access to the elements in the
//          // container.
//
//      // CREATORS
//      explicit MyContainer(bslma::Allocator *basicAllocator = 0);
//          // Create an empty 'MyContainer' object having no capacity.
//          // Optionally specify a 'basicAllocator' used to supply memory.  If
//          // 'basicAllocator' is 0, the currently installed default allocator
//          // is used.
//
//      // ...
//
//      // MANIPULATORS
//      // ...
//
//      void push_back(const VALUE_TYPE& value);
//          // Append the specified 'value' at the past-the-end position in
//          // this container, increasing the container's capacity if needed.
//
//      // ...
//
//      // ACCESSORS
//      ConstIterator begin() const;
//          // Return an iterator providing non-modifiable access to the first
//          // element in this container.
//
//      ConstIterator end() const;
//          // Return an iterator providing non-modifiable access to the
//          // past-the-end element in this container.
//
//      std::size_t size() const;
//          // Return the number of elements in this container.
//
//      // ...
//  };
//..
// Notice that 'ConstIterator' is defined as a pointer type, which is one of
// the criteria required to enable the optimizations provided by the
// 'bslalg::RangeCompare::equal' class method.
//
// Then, we declare the equality-comparison operators for 'MyContainer':
//..
//  template <class VALUE_TYPE>
//  bool operator==(const MyContainer<VALUE_TYPE>& lhs,
//                  const MyContainer<VALUE_TYPE>& rhs);
//      // Return 'true' if the specified 'lhs' and 'rhs' objects have the same
//      // value, and 'false' otherwise.  Two 'MyContainer' objects have the
//      // same value if they have the same length, and each element in 'lhs'
//      // has the same value as the corresponding element in 'rhs'.
//
//  template <class VALUE_TYPE>
//  bool operator!=(const MyContainer<VALUE_TYPE>& lhs,
//                  const MyContainer<VALUE_TYPE>& rhs);
//      // Return 'true' if the specified 'lhs' and 'rhs' objects do not have
//      // the same value, and 'false' otherwise.  Two 'MyContainer' objects do
//      // not have the same value if they do not have the same length, or if
//      // any element in 'lhs' does not have the same value as the
//      // corresponding element in 'rhs'.
//..
// Next, we implement the equality-comparison operators using
// 'bslalg::RangeCompare::equal':
//..
//  template <class VALUE_TYPE>
//  inline
//  bool operator==(const MyContainer<VALUE_TYPE>& lhs,
//                  const MyContainer<VALUE_TYPE>& rhs)
//  {
//      return BloombergLP::bslalg::RangeCompare::equal(lhs.begin(),
//                                                      lhs.end(),
//                                                      lhs.size(),
//                                                      rhs.begin(),
//                                                      rhs.end(),
//                                                      rhs.size());
//  }
//
//  template <class VALUE_TYPE>
//  inline
//  bool operator!=(const MyContainer<VALUE_TYPE>& lhs,
//                  const MyContainer<VALUE_TYPE>& rhs)
//  {
//      return !BloombergLP::bslalg::RangeCompare::equal(lhs.begin(),
//                                                       lhs.end(),
//                                                       lhs.size(),
//                                                       rhs.begin(),
//                                                       rhs.end(),
//                                                       rhs.size());
//  }
//..
// Then, we create the elided definition of a value-semantic class, 'MyString',
// together with its definition of 'operator==':
//..
//  class MyString {
//      // This class provides a simple, elided string class that conforms to
//      // the 'bslma::Allocator' model.
//
//    private:
//      // DATA
//      char             *d_start_p;      // storage for the string
//      std::size_t       d_length;       // length of the string
//      bslma::Allocator *d_allocator_p;  // memory allocator (held, not owned)
//
//      // ...
//
//      // FRIENDS
//      friend bool operator==(const MyString&, const MyString&);
//      // ...
//
//    public:
//      // CREATORS
//      explicit MyString(const char       *string,
//                        bslma::Allocator *basicAllocator = 0);
//          // Create a 'MyString' object initialized to the value of the
//          // specified 'string'.  Optionally specify a 'basicAllocator' used
//          // to supply memory.  If 'basicAllocator' is 0, the currently
//          // installed default allocator is used.
//
//      // ...
//  };
//
//  bool operator==(const MyString& lhs, const MyString& rhs)
//  {
//      return lhs.d_length == rhs.d_length
//          && 0 == std::strncmp(lhs.d_start_p, rhs.d_start_p, lhs.d_length);
//  }
//..
// Notice that 'MyString' is not bit-wise comparable because the address values
// of the 'd_start_p' pointer data members in two 'MyString' objects will be
// different, even if the string values of the two objects are the same.
//
// Next, we create two 'MyContainer<MyString>' objects, and compare them using
// 'operator==':
//..
//  MyContainer<MyString> c1;
//  MyContainer<MyString> c2;
//
//  c1.push_back(MyString("hello"));
//  c1.push_back(MyString("goodbye"));
//
//  c2.push_back(MyString("hello"));
//  c2.push_back(MyString("goodbye"));
//
//  assert(c1 == c2);
//..
// Here, the call to the 'bslalg::RangeCompare::equal' class method in
// 'operator==' will perform an unoptimized pair-wise comparison of the
// elements in 'c1' and 'c2'.
//
// Then, we create the elided definition of another value-semantic class,
// 'MyPoint', together with its definition of 'operator==':
//..
//  class MyPoint {
//      // This class provides a simple, elided point type that is bit-wise
//      // comparable with other objects of the same type.
//
//    private:
//      // DATA
//      int d_x;  // the x-coordinate of the point
//      int d_y;  // the y-coordinate of the point
//
//      // FRIENDS
//      friend bool operator==(const MyPoint&, const MyPoint&);
//      // ...
//
//    public:
//      // TRAITS
//      BSLMF_NESTED_TRAIT_DECLARATION(MyPoint,
//                            BloombergLP::bslmf::IsBitwiseEqualityComparable);
//
//      // CREATORS
//      MyPoint(int x, int y);
//          // Create a 'MyPoint' object whose x- and y-coordinates have the
//          // specified 'x' and 'y' values, respectively.
//
//      // ...
//  };
//
//  bool operator==(const MyPoint& lhs, const MyPoint& rhs)
//  {
//      return lhs.d_x == rhs.d_x && lhs.d_y == rhs.d_y;
//  }
//..
// Notice that the value of a 'MyPoint' object derives from the values of all
// of its data members, and that no padding is required for alignment.
// Furthermore, 'MyPoint' has no virtual methods.  Therefore, 'MyPoint' objects
// are bit-wise comparable, and we can correctly declare the
// 'bslmf::IsBitwiseEqualityComparable' trait for the class, as shown
// above under the public 'TRAITS' section.
//
// Now, we create two 'MyContainer<MyPoint>' objects and compare them using
// 'operator==':
//..
//  MyContainer<MyPoint> c3;
//  MyContainer<MyPoint> c4;
//
//  c3.push_back(MyPoint(1, 2));
//  c3.push_back(MyPoint(3, 4));
//
//  c4.push_back(MyPoint(1, 2));
//  c4.push_back(MyPoint(3, 4));
//
//  assert(c3 == c4);  // potentially optimized
//..
// Here, the call to 'bslalg::RangeCompare::equal' in 'operator==' may take
// advantage of the fact that 'MyPoint' is bit-wise comparable and perform the
// comparison by directly bit-wise comparing the entire range of elements
// contained in the 'MyContainer<MyPoint>' objects.  This comparison can
// provide a significant performance boost over the comparison between two
// 'MyContainer<MyPoint>' objects in which the nested
// 'bslmf::IsBitwiseEqualityComparable' trait is not associated with the
// 'MyPoint' class.
//
// Finally, note that we can instantiate 'MyContainer' with 'int' or any other
// primitive type as the 'VALUE_TYPE' and still benefit from the optimized
// comparison operators, because primitive (i.e.: fundamental, enumerated, and
// pointer) types are inherently bit-wise comparable:
//..
//  MyContainer<int> c5;
//  MyContainer<int> c6;
//
//  c5.push_back(1);
//  c5.push_back(2);
//  c5.push_back(3);
//
//  c6.push_back(1);
//  c6.push_back(2);
//  c6.push_back(3);
//
//  assert(c5 == c6);  // potentially optimized
//..

#include <bslscm_version.h>

#include <bslmf_integralconstant.h>
#include <bslmf_isbitwiseequalitycomparable.h>
#include <bslmf_isconvertible.h>
#include <bslmf_matchanytype.h>

#include <climits>

#include <cstddef>

#include <cstring>

#include <cwchar>

namespace BloombergLP {

namespace bslalg {

                          // ==================
                          // class RangeCompare
                          // ==================

struct RangeCompare {
    // This utility 'struct' provides two static class methods, 'equal' and
    // 'lexicographical', for comparing two ranges of values.  'equal' returns
    // 'true' if each element in one range has the same value as the
    // corresponding element in the other range, and 'false' otherwise.
    // 'lexicographical' returns 0 if the two ranges are equal, a positive
    // value if the first range is greater than the second, and a negative
    // value if the second range is greater than the first.  A range is
    // specified by a pair of beginning and ending iterators, with an optional
    // length parameter.  Additionally, an overload is provided for the 'equal'
    // class method that allows the end iterator for one range to be omitted.
    //
    // 'equal' requires that the elements in the ranges can be compared with
    // 'operator=='.
    //
    // 'lexicographical' requires that the elements in the ranges can be
    // compared with 'operator<'.

    // TYPES
    typedef std::size_t size_type;
        // 'size_type' is an alias for an unsigned value representing the size
        // of an object or the number of elements in a range.

    // CLASS METHODS
    template <class INPUT_ITER>
    static bool equal(INPUT_ITER start1,
                      INPUT_ITER end1,
                      INPUT_ITER start2);
        // Compare each element in the range beginning at the specified
        // 'start1' position and ending immediately before the specified 'end1'
        // position to the corresponding element in the range of the same
        // length beginning at the specified 'start2' position, as if using
        // 'operator==' element-by-element.  Return 'true' if every pair of
        // corresponding elements compares equal, and 'false' otherwise.  Note
        // that this implementation uses 'operator==' to perform the
        // comparisons, or bit-wise comparison if the value type has the
        // bit-wise equality-comparable trait.

    template <class INPUT_ITER>
    static bool equal(INPUT_ITER start1,
                      INPUT_ITER end1,
                      INPUT_ITER start2,
                      INPUT_ITER end2);
    template <class INPUT_ITER>
    static bool equal(INPUT_ITER start1, INPUT_ITER end1, size_type length1,
                      INPUT_ITER start2, INPUT_ITER end2, size_type length2);
        // Compare each element in the range beginning at the specified
        // 'start1' position and ending immediately before the specified 'end1'
        // position, to the corresponding element in the range beginning at the
        // specified 'start2' position and ending immediately before the
        // specified 'end2' position, as if by using 'operator=='
        // element-by-element.  Optionally specify the length of each range,
        // 'length1' and 'length2'.  Return 'true' if the ranges have the same
        // length and every element in the first range compares equal with the
        // corresponding element in the second, and 'false' otherwise.  The
        // behavior is undefined unless 'length1' is either unspecified or
        // equals the length of the range '[start1, end1)', and 'length2' is
        // either unspecified or equals the length of the range
        // '[start2, end2)'.  Note that this implementation uses 'operator=='
        // to perform the comparisons, or bit-wise comparison if the value type
        // has the bit-wise equality-comparable trait.  Also note that
        // providing lengths may reduce the runtime cost of this operation.

    template <class INPUT_ITER>
    static int lexicographical(INPUT_ITER start1,
                               INPUT_ITER end1,
                               INPUT_ITER start2,
                               INPUT_ITER end2);
    template <class INPUT_ITER>
    static int lexicographical(INPUT_ITER start1,
                               INPUT_ITER end1,
                               size_type  length1,
                               INPUT_ITER start2,
                               INPUT_ITER end2,
                               size_type  length2);
        // Compare each element in the range beginning at the specified
        // 'start1' position and ending immediately before the specified 'end1'
        // position, to the corresponding element in the range beginning at the
        // specified 'start2' position and ending immediately before the
        // specified 'end2' position.  Optionally specify the length of each
        // range, 'length1' and 'length2'.  Return a negative value if the
        // first range compares lexicographically less than the second range, 0
        // if they are the same length and compare lexicographically equal, and
        // a positive value if the first range compares lexicographically
        // greater than the second range.  The behavior is undefined unless
        // 'length1' is either unspecified or equals the length of the range
        // '[start1, end1)', and 'length2' is either unspecified or equals the
        // length of the range '[start2, end2)'.  Note that this implementation
        // uses 'std::memcmp' for unsigned character comparisons,
        // 'std::wmemcmp' for wide character comparisons, and 'operator<' for
        // all other types.
};

                       // =======================
                       // struct RangeCompare_Imp
                       // =======================

struct RangeCompare_Imp {
    // This utility 'struct' provides the implementations for
    // 'bslalg::RangeCompare'.  Multiple implementations are provided for each
    // method in 'bslalg::RangeCompare', and the most efficient version is
    // found by disambiguating based on the iterator type, the value type, or
    // the presence of nested traits.

    // CLASS METHODS
    template <class VALUE_TYPE>
    static bool equal(const VALUE_TYPE  *start1,
                      const VALUE_TYPE  *end1,
                      const VALUE_TYPE  *start2,
                      const VALUE_TYPE  *end2,
                      const VALUE_TYPE&,
                      bsl::true_type);
    template <class INPUT_ITER, class VALUE_TYPE>
    static bool equal(INPUT_ITER         start1,
                      INPUT_ITER         end1,
                      INPUT_ITER         start2,
                      INPUT_ITER         end2,
                      const VALUE_TYPE&,
                      bsl::false_type);
    template <class INPUT_ITER, class VALUE_TYPE>
    static bool equal(INPUT_ITER         start1,
                      INPUT_ITER         end1,
                      INPUT_ITER         start2,
                      INPUT_ITER         end2,
                      const VALUE_TYPE&);
        // Compare the range beginning at the specified 'start1' position and
        // ending immediately before the specified 'end1' position with the
        // range beginning at the specified 'start2' position and ending
        // immediately before the specified 'end2' position, as if using
        // 'operator==' element-by-element.  The unnamed 'VALUE_TYPE' argument
        // is for automatic type deduction, and is ignored.  The fifth argument
        // is for overloading resolution, and is also ignored.

    template <class INPUT_ITER, class VALUE_TYPE>
    static bool equal(INPUT_ITER        start1,
                      INPUT_ITER        end1,
                      INPUT_ITER        start2,
                      const VALUE_TYPE&,
                      bsl::true_type);
    template <class INPUT_ITER, class VALUE_TYPE>
    static bool equal(INPUT_ITER        start1,
                      INPUT_ITER        end1,
                      INPUT_ITER        start2,
                      const VALUE_TYPE&,
                      bsl::false_type);
    template <class INPUT_ITER, class VALUE_TYPE>
    static bool equal(INPUT_ITER        start1,
                      INPUT_ITER        end1,
                      INPUT_ITER        start2,
                      const VALUE_TYPE&);
        // Compare the range beginning at the specified 'start1' position and
        // ending immediately before the specified 'end1' position with the
        // range beginning at the specified 'start2' position of the same
        // length (namely, 'end1 - start1'), as if using 'operator=='
        // element-by-element.  The unnamed 'VALUE_TYPE' argument is for
        // automatic type deduction, and is ignored.  The fifth argument is for
        // overloading resolution, and is also ignored.

    template <class VALUE_TYPE>
    static bool equalBitwiseEqualityComparable(const VALUE_TYPE  *start1,
                                               const VALUE_TYPE  *end1,
                                               const VALUE_TYPE  *start2,
                                               bsl::true_type);
        // Compare the range beginning at the specified 'start1' position and
        // ending immediately before the specified 'end1' position with the
        // range beginning at the specified 'start2' position of the same
        // length (namely, 'end1 - start1'), using bit-wise comparison across
        // the entire ranges.  The last argument is for removing overload
        // ambiguities, and is not used.  Return 'true' if the ranges are
        // bit-wise equal, and 'false' otherwise.

    template <class INPUT_ITER>
    static bool equalBitwiseEqualityComparable(INPUT_ITER        start1,
                                               INPUT_ITER        end1,
                                               INPUT_ITER        start2,
                                               bsl::false_type);
        // Compare the range beginning at the specified 'start1' position and
        // ending immediately before the specified 'end1' position with the
        // range beginning at the specified 'start2' position of the same
        // length (namely, 'end1 - start1'), using 'operator=='
        // element-by-element.  The last argument is for removing overload
        // ambiguities, and is not used.  Return 'true' if each element in the
        // first range is equal to the corresponding element in the second
        // range, and 'false' otherwise.

    template <class VALUE_TYPE>
    static int lexicographical(const VALUE_TYPE  *start1,
                               const VALUE_TYPE  *end1,
                               const VALUE_TYPE  *start2,
                               const VALUE_TYPE  *end2,
                               const VALUE_TYPE&,
                               bsl::true_type);
        // Compare the range beginning at the specified 'start1' position and
        // ending immediately before the specified 'end1' position with the
        // range beginning at the specified 'start2' position and ending
        // immediately before the specified 'end2' position.  The last two
        // arguments are for removing overload ambiguities and are not used.
        // Return a negative value if the
        // first range compares lexicographically less than the second range, 0
        // if they are the same length and compare lexicographically equal, and
        // a positive value if the first range compares lexicographically
        // greater than the second range.

    template <class INPUT_ITER, class VALUE_TYPE>
    static int lexicographical(INPUT_ITER        start1,
                               INPUT_ITER        end1,
                               INPUT_ITER        start2,
                               INPUT_ITER        end2,
                               const VALUE_TYPE&,
                               bsl::false_type);
        // Compare each element in the range beginning at the specified
        // 'start1' position and ending immediately before the specified 'end1'
        // position with the corresponding element in the range beginning at
        // the specified 'start2' position and ending immediately before the
        // specified 'end2' position using 'operator<'.  The last two arguments
        // are for removing overload ambiguities and are not used.  Return a
        // negative value if the first range compares lexicographically less
        // than the second range, 0 if they are the same length and compare
        // lexicographically equal, and a positive value if the first range
        // compares lexicographically greater than the second range.

    template <class INPUT_ITER, class VALUE_TYPE>
    static int lexicographical(INPUT_ITER        start1,
                               INPUT_ITER        end1,
                               INPUT_ITER        start2,
                               INPUT_ITER        end2,
                               const VALUE_TYPE&);
        // Compare the range beginning at the specified 'start1' position and
        // ending immediately before the specified 'end1' position with the
        // range beginning at the specified 'start2' position and ending
        // immediately before the specified 'end2' position.  The type of the
        // last argument is considered in determining what optimizations, if
        // any, can be applied to the comparison.  The last argument is not
        // used in any other way.  Return a negative value if the
        // first range compares lexicographically less than the second range, 0
        // if they are the same length and compare lexicographically equal, and
        // a positive value if the first range compares lexicographically
        // greater than the second range.

    static int lexicographical(const char *start1,
                               const char *end1,
                               const char *start2);
        // Compare the range beginning at the specified 'start1' position and
        // ending immediately before the specified 'end1' position with the
        // range beginning at the specified 'start2' position of the same
        // length (namely, 'end1 - start1'), using a bit-wise comparison
        // across the entire range, if 'const char' is unsigned, and using
        // 'operator<' otherwise.  Return a negative value if the
        // first range compares lexicographically less than the second range, 0
        // if they are the same length and compare lexicographically equal, and
        // a positive value if the first range compares lexicographically
        // greater than the second range.

    static int lexicographical(const unsigned char *start1,
                               const unsigned char *end1,
                               const unsigned char *start2);
    static int lexicographical(const wchar_t *start1,
                               const wchar_t *end1,
                               const wchar_t *start2);
    template <class INPUT_ITER>
    static int lexicographical(INPUT_ITER           start1,
                               INPUT_ITER           end1,
                               INPUT_ITER           start2,
                               bslmf::MatchAnyType);
    template <class INPUT_ITER>
    static int lexicographical(INPUT_ITER     start1,
                               INPUT_ITER     end1,
                               INPUT_ITER     start2);
        // Compare each element in the range beginning at the specified
        // 'start1' position and ending immediately before the specified 'end1'
        // position with the corresponding element in the range of the same
        // length beginning at the specified 'start2' position.  Return a
        // negative value if the first range compares lexicographically less
        // than the second range, 0 if they are the same length and compare
        // lexicographically equal, and a positive value if the first range
        // compares lexicographically greater than the second range.
};

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

                         // -------------------
                         // struct RangeCompare
                         // -------------------

// CLASS METHODS
template <class INPUT_ITER>
inline
bool RangeCompare::equal(INPUT_ITER start1,
                         INPUT_ITER end1,
                         INPUT_ITER start2)
{
    if (start1 == end1) {
        return true;                                                  // RETURN
    }
    return RangeCompare_Imp::equal(start1, end1, start2, *start1);
}

template <class INPUT_ITER>
inline
bool RangeCompare::equal(INPUT_ITER start1,
                         INPUT_ITER end1,
                         INPUT_ITER start2,
                         INPUT_ITER end2)
{
    if (start1 == end1) {
        return start2 == end2;                                        // RETURN
    }
    return RangeCompare_Imp::equal(start1, end1, start2, end2, *start1);
}

template <class INPUT_ITER>
inline
bool RangeCompare::equal(INPUT_ITER start1,
                         INPUT_ITER end1,
                         size_type  length1,
                         INPUT_ITER start2,
                         INPUT_ITER,
                         size_type  length2)
{
    if (length1 != length2) {
        return false;                                                 // RETURN
    }
    if (start1 == end1) {
        return true;                                                  // RETURN
    }
    return RangeCompare_Imp::equal(start1, end1, start2, *start1);
}

template <class INPUT_ITER>
int RangeCompare::lexicographical(INPUT_ITER start1,
                                  INPUT_ITER end1,
                                  INPUT_ITER start2,
                                  INPUT_ITER end2)
{
    if (start1 == end1) {
        return start2 != end2 ? -1 : 0;                               // RETURN
    }
    return RangeCompare_Imp::lexicographical(start1,
                                             end1,
                                             start2,
                                             end2,
                                             *start1);
}

template <class INPUT_ITER>
int RangeCompare::lexicographical(INPUT_ITER start1,
                                  INPUT_ITER end1,
                                  size_type  length1,
                                  INPUT_ITER start2,
                                  INPUT_ITER end2,
                                  size_type  length2)
{
    const int result = length2 < length1
                       ? - RangeCompare_Imp::lexicographical(start2,
                                                             end2,
                                                             start1)
                       :   RangeCompare_Imp::lexicographical(start1,
                                                             end1,
                                                             start2);

    if (result < 0) {
        return -1;                                                    // RETURN
    }
    if (0 < result) {
        return 1;                                                     // RETURN
    }
    if (length1 < length2) {
        return -1;                                                    // RETURN
    }
    if (length2 < length1) {
        return 1;                                                     // RETURN
    }
    return 0;
}

                       // -----------------------
                       // struct RangeCompare_Imp
                       // -----------------------

// CLASS METHODS

                          // *** equal overloads: ***

template <class VALUE_TYPE>
inline
bool RangeCompare_Imp::equal(const VALUE_TYPE  *start1,
                             const VALUE_TYPE  *end1,
                             const VALUE_TYPE  *start2,
                             const VALUE_TYPE  *end2,
                             const VALUE_TYPE&,
                             bsl::true_type)
{
    return RangeCompare::equal(start1,
                               end1,
                               end1 - start1,
                               start2,
                               end2,
                               end2 - start2);
}

template <class INPUT_ITER, class VALUE_TYPE>
bool RangeCompare_Imp::equal(INPUT_ITER        start1,
                             INPUT_ITER        end1,
                             INPUT_ITER        start2,
                             INPUT_ITER        end2,
                             const VALUE_TYPE&,
                             bsl::false_type)
{
    for ( ; start1 != end1 && start2 != end2; ++start1, ++start2) {
        if (!(*start1 == *start2)) {
            return false;                                             // RETURN
        }
    }
    return start1 == end1 && start2 == end2;
}

template <class INPUT_ITER, class VALUE_TYPE>
bool RangeCompare_Imp::equal(INPUT_ITER        start1,
                             INPUT_ITER        end1,
                             INPUT_ITER        start2,
                             INPUT_ITER        end2,
                             const VALUE_TYPE& value)
{
    typedef typename bsl::is_convertible<INPUT_ITER, const VALUE_TYPE *>::type
                                                      CanUseLengthOptimization;

    return equal(start1,
                 end1,
                 start2,
                 end2,
                 value,
                 CanUseLengthOptimization());
}

template <class INPUT_ITER, class VALUE_TYPE>
inline
bool RangeCompare_Imp::equal(INPUT_ITER        start1,
                             INPUT_ITER        end1,
                             INPUT_ITER        start2,
                             const VALUE_TYPE&,
                             bsl::true_type)
{
    // Note: We are forced to call a different function to resolve whether
    // 'INPUT_ITER' is convertible to 'const TARGET_TYPE *' or not, otherwise
    // we would be introducing ambiguities (the additional parameter
    // 'CanUseBitwiseCopyOptimization' is necessary to remove further
    // ambiguities on SunPro).

    typedef typename bsl::is_convertible<INPUT_ITER, const VALUE_TYPE *>::type
                                              CanUseBitwiseCompareOptimization;

    return equalBitwiseEqualityComparable(start1,
                                          end1,
                                          start2,
                                          CanUseBitwiseCompareOptimization());
}

template <class INPUT_ITER, class VALUE_TYPE>
bool RangeCompare_Imp::equal(INPUT_ITER        start1,
                             INPUT_ITER        end1,
                             INPUT_ITER        start2,
                             const VALUE_TYPE&,
                             bsl::false_type)
{
    for ( ; start1 != end1; ++start1, ++start2) {
        if (!(*start1 == *start2)) {
            return false;                                             // RETURN
        }
    }
    return true;
}

template <class INPUT_ITER, class VALUE_TYPE>
inline
bool RangeCompare_Imp::equal(INPUT_ITER        start1,
                             INPUT_ITER        end1,
                             INPUT_ITER        start2,
                             const VALUE_TYPE& value)
{
    typedef typename
        bslmf::IsBitwiseEqualityComparable<VALUE_TYPE>::type Trait;
    return equal(start1, end1, start2, value, Trait());
}

             // *** equalBitwiseEqualityComparable overloads: ***

template <class VALUE_TYPE>
inline
bool RangeCompare_Imp::equalBitwiseEqualityComparable(
                                                     const VALUE_TYPE  *start1,
                                                     const VALUE_TYPE  *end1,
                                                     const VALUE_TYPE  *start2,
                                                     bsl::true_type)
{
    std::size_t numBytes = reinterpret_cast<const char *>(end1)
                         - reinterpret_cast<const char *>(start1);

    return 0 == std::memcmp(reinterpret_cast<const void *>(start1),
                            reinterpret_cast<const void *>(start2),
                            numBytes);
}

template <class INPUT_ITER>
inline
bool RangeCompare_Imp::equalBitwiseEqualityComparable(INPUT_ITER        start1,
                                                      INPUT_ITER        end1,
                                                      INPUT_ITER        start2,
                                                      bsl::false_type)
{
    // We can't be as optimized as above.

    return equal(start1, end1, start2, *start1, bsl::false_type());
}

                     // *** lexicographical overloads: ***

template <class VALUE_TYPE>
inline
int RangeCompare_Imp::lexicographical(const VALUE_TYPE  *start1,
                                      const VALUE_TYPE  *end1,
                                      const VALUE_TYPE  *start2,
                                      const VALUE_TYPE  *end2,
                                      const VALUE_TYPE&,
                                      bsl::true_type)
{
    // In this case, we can compute the length directly, and avoid the overhead
    // of the two comparisons in the loop condition (one is enough).

    return RangeCompare::lexicographical(start1,
                                         end1,
                                         end1 - start1,
                                         start2,
                                         end2,
                                         end2 - start2);
}

template <class INPUT_ITER, class VALUE_TYPE>
int RangeCompare_Imp::lexicographical(INPUT_ITER        start1,
                                      INPUT_ITER        end1,
                                      INPUT_ITER        start2,
                                      INPUT_ITER        end2,
                                      const VALUE_TYPE&,
                                      const bsl::false_type)
{
    for ( ; start1 != end1 && start2 != end2; ++start1, ++start2) {
        if (*start1 < *start2) {
            return -1;                                                // RETURN
        }
        else if (*start2 < *start1) {
            return 1;                                                 // RETURN
        }
    }
    if (start1 != end1) {
        return 1;                                                     // RETURN
    }
    if (start2 != end2) {
        return -1;                                                    // RETURN
    }
    return 0;
}

template <class INPUT_ITER, class VALUE_TYPE>
inline
int RangeCompare_Imp::lexicographical(INPUT_ITER        start1,
                                      INPUT_ITER        end1,
                                      INPUT_ITER        start2,
                                      INPUT_ITER        end2,
                                      const VALUE_TYPE& value)
{
    typedef typename bsl::is_convertible<INPUT_ITER, const VALUE_TYPE *>::type
                                                      CanUseLengthOptimization;

    return lexicographical(start1, end1, start2, end2, value,
                           CanUseLengthOptimization());
}

inline
int RangeCompare_Imp::lexicographical(const unsigned char *start1,
                                      const unsigned char *end1,
                                      const unsigned char *start2)
{
    return std::memcmp(start1, start2, end1 - start1);
}

inline
int RangeCompare_Imp::lexicographical(const char *start1,
                                      const char *end1,
                                      const char *start2)
{
#if CHAR_MAX == SCHAR_MAX
    return std::memcmp(start1, start2, (end1 - start1));
#else
    return lexicographical<const char *>(start1, end1, start2, 0);
#endif
}

inline
int RangeCompare_Imp::lexicographical(const wchar_t *start1,
                                      const wchar_t *end1,
                                      const wchar_t *start2)
{
    return std::wmemcmp(start1, start2, end1 - start1);
}

template <class INPUT_ITER>
int RangeCompare_Imp::lexicographical(INPUT_ITER start1,
                                      INPUT_ITER end1,
                                      INPUT_ITER start2,
                                      bslmf::MatchAnyType)
{
    for ( ; start1 != end1; ++start1, ++start2) {
        if (*start1 < *start2) {
            return -1;                                                // RETURN
        }
        else if (*start2 < *start1) {
            return 1;                                                 // RETURN
        }
    }
    return 0;
}

template <class INPUT_ITER>
inline
int RangeCompare_Imp::lexicographical(INPUT_ITER start1,
                                      INPUT_ITER end1,
                                      INPUT_ITER start2)
{
    if (start1 != end1) {
        return lexicographical(start1, end1, start2, *start1);        // RETURN
    }
    return 0;
}

}  // close package namespace

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

typedef bslalg::RangeCompare bslalg_RangeCompare;
    // 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 ----------------------------------