// bdlb_algorithmworkaroundutil.h                                     -*-C++-*-
#ifndef INCLUDED_BDLB_ALGORITHMWORKAROUNDUTIL
#define INCLUDED_BDLB_ALGORITHMWORKAROUNDUTIL

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

//@PURPOSE: Provide a namespace for workarounds for faulty standard algorithms
//
//@CLASSES:
//  AlgorithmWorkaroundUtil: namespace for fixed faulty standard algorithms
//
//@SEE_ALSO: std::lower_bound, std::upper_bound
//
//@DESCRIPTION: This component provides a `struct` namespace for replacement
// workarounds for some platform supplied faulty algorithms (particularly for
// the Sun Studio compiler).
//
///Usage
///-----
// Suppose that we

#include <bdlscm_version.h>

#include <bsls_libraryfeatures.h>
#include <bsls_platform.h>

#include <bsl_algorithm.h>
#include <bsl_iterator.h>

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

namespace BloombergLP {
namespace bdlb {

                    // ==============================
                    // struct AlgorithmWorkaroundUtil
                    // ==============================

/// A namespace for replacement workarounds for some platform supplied
/// faulty algorithms (particularly for the Sun Studio compiler).
struct AlgorithmWorkaroundUtil {

    // CLASS METHODS

    /// Returns an iterator pointing to the first element in the range
    /// starting at the specified `first` iterator and ending immediately
    /// before the specified `last` iterator, that is greater than or equal
    /// to the specified `value`, or `last` if no such element is found.
    /// This method works around a deficiency in the STLPort standard
    /// library that prevents using `lower_bound` to search for a value of a
    /// different type than that held in the range being searched (even if
    /// an appropriate `operator<` is defined).  See DRQS 139734639.
    template<class FORWARD_IT, class TYPE>
    static
    FORWARD_IT lowerBound(FORWARD_IT  first,
                          FORWARD_IT  last,
                          const TYPE& value);

    /// Returns an iterator pointing to the first element in the range
    /// starting at the specified `first` iterator and ending immediately
    /// before the specified `last` iterator, that is greater than or equal
    /// to the specified `value` as determined by the specified `comp`, or
    /// `last` if no such element is found.  This method works around a
    /// deficiency in the STLPort standard library that prevents using
    /// `lower_bound` to search for a value of a different type than that
    /// held in the range being searched (even if an appropriate `operator<`
    /// is defined).  See DRQS 139734639.
    template <class FORWARD_IT, class TYPE, class COMPARE>
    static
    FORWARD_IT lowerBound(FORWARD_IT  first,
                          FORWARD_IT  last,
                          const TYPE& value,
                          COMPARE     comp);

    /// Returns an iterator pointing to the first element in the range
    /// starting at the specified `first` iterator and ending immediately
    /// before the specified `last` iterator, that is greater than the
    /// specified `value`, or `last` if no such element is found.  This
    /// method works around a deficiency in the STLPort standard library
    /// that prevents using `upper_bound` to search for a value of a
    /// different type than that held in the range being searched (even if
    /// an appropriate `operator<` is defined).  See DRQS 139734639.
    template<class FORWARD_IT, class TYPE>
    static
    FORWARD_IT upperBound(FORWARD_IT  first,
                          FORWARD_IT  last,
                          const TYPE& value);

    /// Returns an iterator pointing to the first element in the range
    /// starting at the specified `first` iterator and ending immediately
    /// before the specified `last` iterator, that is greater than the
    /// specified `value` as determined by the specified `comp`, or `last`
    /// if no such element is found.  This method works around a deficiency
    /// in the STLPort standard library that prevents using `upper_bound` to
    /// search for a value of a different type than that held in the range
    /// being searched (even if an appropriate `operator<` is defined).  See
    /// DRQS 139734639.
    template <class FORWARD_IT, class TYPE, class COMPARE>
    static
    FORWARD_IT upperBound(FORWARD_IT  first,
                           FORWARD_IT  last,
                           const TYPE& value,
                           COMPARE     comp);
};

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

                    // ------------------------------
                    // struct AlgorithmWorkaroundUtil
                    // ------------------------------

template<class FORWARD_IT, class TYPE>
inline
FORWARD_IT AlgorithmWorkaroundUtil::lowerBound(FORWARD_IT first,
                                               FORWARD_IT last,
                                               const TYPE& value)
{
#if   defined(BSLS_LIBRARYFEATURES_STDCPP_STLPORT)                            \
    && defined(_STLPORT_VERSION)                                              \
    && (_STLPORT_VERSION <= 0x452)

    typedef typename bsl::iterator_traits<FORWARD_IT>::difference_type
        difference_type;

    difference_type length = bsl::distance(first, last);

    while (length > 0) {
        difference_type half = length >> 1;
        FORWARD_IT      it   = first;

        bsl::advance(it, half);
        if (*it < value) {
            first = ++it;
            length -= half + 1;
        }
        else {
            length = half;
        }
    }
    return first;
#else
    return std::lower_bound(first, last, value);
#endif
}

template <class FORWARD_IT, class TYPE, class COMPARE>
inline
FORWARD_IT AlgorithmWorkaroundUtil::lowerBound(FORWARD_IT  first,
                                               FORWARD_IT  last,
                                               const TYPE& value,
                                               COMPARE     comp)
{
#if   defined(BSLS_LIBRARYFEATURES_STDCPP_STLPORT)                            \
    && defined(_STLPORT_VERSION)                                              \
    && (_STLPORT_VERSION <= 0x452)

    typedef typename bsl::iterator_traits<FORWARD_IT>::difference_type
        difference_type;

    difference_type length = bsl::distance(first, last);

    while (length > 0) {
        difference_type half = length >> 1;
        FORWARD_IT       it   = first;

        bsl::advance(it, half);
        if (comp(*it, value)) {
            first = ++it;
            length -= half + 1;
        }
        else {
            length = half;
        }
    }
    return first;
#else
    return std::lower_bound(first, last, value, comp);
#endif
}

template<class FORWARD_IT, class TYPE>
inline
FORWARD_IT AlgorithmWorkaroundUtil::upperBound(FORWARD_IT  first,
                                               FORWARD_IT  last,
                                               const TYPE& value)
{
#if   defined(BSLS_LIBRARYFEATURES_STDCPP_STLPORT)                            \
    && defined(_STLPORT_VERSION)                                              \
    && (_STLPORT_VERSION <= 0x452)

    typedef typename bsl::iterator_traits<FORWARD_IT>::difference_type
        difference_type;

    difference_type length = bsl::distance(first, last);

    while (length > 0) {
        difference_type half = length >> 1;
        FORWARD_IT      it   = first;

        bsl::advance(it, half);
        if (!(value < *it)) {
            first = ++it;
            length -= half + 1;
        }
        else {
            length = half;
        }
    }
    return first;
#else
    return std::upper_bound(first, last, value);
#endif
}

template <class FORWARD_IT, class TYPE, class COMPARE>
inline
FORWARD_IT AlgorithmWorkaroundUtil::upperBound(FORWARD_IT  first,
                                               FORWARD_IT  last,
                                               const TYPE& value,
                                               COMPARE     comp)
{
#if   defined(BSLS_LIBRARYFEATURES_STDCPP_STLPORT)                            \
    && defined(_STLPORT_VERSION)                                              \
    && (_STLPORT_VERSION <= 0x452)

    typedef typename bsl::iterator_traits<FORWARD_IT>::difference_type
        difference_type;

    difference_type length = bsl::distance(first, last);

    while (length > 0) {
        difference_type half = length >> 1;
        FORWARD_IT      it   = first;

        bsl::advance(it, half);
        if (!comp(value, *it)) {
            first = ++it;
            length -= half + 1;
        }
        else {
            length = half;
        }
    }
    return first;
#else
    return std::upper_bound(first, last, value, comp);
#endif
}

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

#endif

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