// algorithm standard header -*-c++-*-
// Copyright 2003-2020 IAR Systems AB. 
#ifndef _DLIB5_ALGORITHM_
#define _DLIB5_ALGORITHM_

#ifndef _SYSTEM_BUILD
#pragma system_include
#endif

#include <dlib5/memory>
_DLIB5_BEGIN

// COMMON SORT PARAMETERS
const int _ISORT_MAX = 32;      // maximum size for insertion sort

// TEMPLATE FUNCTION for_each
#pragma basic_template_matching
template<class _InIt,
         class _Fn1> inline
_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{       // perform function for each element
  for (; _First != _Last; ++_First)
    _Func(*_First);
  return (_Func);
}

// TEMPLATE FUNCTION find
#pragma basic_template_matching
template<class _InIt,
         class _Ty> inline
_InIt find(_InIt _First, _InIt _Last, const _Ty& _Val)
{       // find first matching _Val
  for (; _First != _Last; ++_First)
    if (*_First == _Val)
      break;
  return (_First);
}

inline const char *find(const char *_First, const char *_Last, int _Val)
{       // find first char that matches _Val
  _First = (const char *)_CSTD memchr(_First, _Val, _Last - _First);
  return (_First == 0 ? _Last : _First);
}

inline const signed char *find(const signed char *_First,
                               const signed char *_Last, int _Val)
{       // find first signed char that matches _Val
  _First = (const signed char *)_CSTD memchr(_First, _Val,
                                             _Last - _First);
  return (_First == 0 ? _Last : _First);
}

inline const unsigned char *find(const unsigned char *_First,
                                 const unsigned char *_Last, int _Val)
{       // find first unsigned char that matches _Val
  _First = (const unsigned char *)_CSTD memchr(_First, _Val,
                                               _Last - _First);
  return (_First == 0 ? _Last : _First);
}

// TEMPLATE FUNCTION find_if
#pragma basic_template_matching
template<class _InIt,
         class _Pr> inline
_InIt find_if(_InIt _First, _InIt _Last, _Pr _Pred)
{       // find first satisfying _Pred
  for (; _First != _Last; ++_First)
    if (_Pred(*_First))
      break;
  return (_First);
}

// TEMPLATE FUNCTION adjacent_find
#pragma basic_template_matching
template<class _FwdIt> inline
_FwdIt adjacent_find(_FwdIt _First, _FwdIt _Last)
{       // find first matching successor
  for (_FwdIt _Firstb; (_Firstb = _First) != _Last && ++_First != _Last; )
    if (*_Firstb == *_First)
      return (_Firstb);
  return (_Last);
}

// TEMPLATE FUNCTION adjacent_find WITH PRED
#pragma basic_template_matching
template<class _FwdIt,
         class _Pr> inline
_FwdIt adjacent_find(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{       // find first satisfying _Pred with successor
  for (_FwdIt _Firstb; (_Firstb = _First) != _Last && ++_First != _Last; )
    if (_Pred(*_Firstb, *_First))
      return (_Firstb);
  return (_Last);
}

// TEMPLATE FUNCTION count
#pragma basic_template_matching
template<class _InIt,
         class _Ty> inline
typename iterator_traits<_InIt>::difference_type
count(_InIt _First, _InIt _Last, const _Ty& _Val)
{       // count elements that match _Val
  typename iterator_traits<_InIt>::difference_type _Count = 0;

  for (; _First != _Last; ++_First)
    if (*_First == _Val)
      ++_Count;
  return (_Count);
}

// TEMPLATE FUNCTION count_if
#pragma basic_template_matching
template<class _InIt,
         class _Pr> inline
typename iterator_traits<_InIt>::difference_type
count_if(_InIt _First, _InIt _Last, _Pr _Pred)
{       // count elements satisfying _Pred
  typename iterator_traits<_InIt>::difference_type _Count = 0;

  for (; _First != _Last; ++_First)
    if (_Pred(*_First))
      ++_Count;
  return (_Count);
}

// TEMPLATE FUNCTION search
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2,
         class _Diff1,
         class _Diff2> inline
_FwdIt1 _Search(_FwdIt1 _First1, _FwdIt1 _Last1,
                _FwdIt2 _First2, _FwdIt2 _Last2, _Diff1 *, _Diff2 *)
{       // find first [_First2, _Last2) match
  _Diff1 _Count1 = distance(_First1, _Last1);
  _Diff2 _Count2 = distance(_First2, _Last2);

  for (; _Count2 <= _Count1; ++_First1, --_Count1)
  {       // room for match, try it
    _FwdIt1 _Mid1 = _First1;
    for (_FwdIt2 _Mid2 = _First2; ; ++_Mid1, ++_Mid2)
      if (_Mid2 == _Last2)
        return (_First1);
      else if (!(*_Mid1 == *_Mid2))
        break;
  }
  return (_Last1);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2> inline
_FwdIt1 search(_FwdIt1 _First1, _FwdIt1 _Last1,
               _FwdIt2 _First2, _FwdIt2 _Last2)
{       // find first [_First2, _Last2) match
  return (_Search(_First1, _Last1, _First2, _Last2,
                  _Dist_type(_First1), _Dist_type(_First2)));
}

// TEMPLATE FUNCTION search WITH PRED
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2,
         class _Diff1,
         class _Diff2,
         class _Pr> inline
_FwdIt1 _Search(_FwdIt1 _First1, _FwdIt1 _Last1,
                _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred, _Diff1 *, _Diff2 *)
{       // find first [_First2, _Last2) satisfying _Pred
  _Diff1 _Count1 = distance(_First1, _Last1);
  _Diff2 _Count2 = distance(_First2, _Last2);

  for (; _Count2 <= _Count1; ++_First1, --_Count1)
  {       // room for match, try it
    _FwdIt1 _Mid1 = _First1;
    for (_FwdIt2 _Mid2 = _First2; ; ++_Mid1, ++_Mid2)
      if (_Mid2 == _Last2)
        return (_First1);
      else if (!_Pred(*_Mid1, *_Mid2))
        break;
  }
  return (_Last1);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2,
         class _Pr> inline
_FwdIt1 search(_FwdIt1 _First1, _FwdIt1 _Last1,
               _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred)
{       // find first [_First2, _Last2) satisfying _Pred
  return (_Search(_First1, _Last1, _First2, _Last2, _Pred,
                  _Dist_type(_First1), _Dist_type(_First2)));
}

// TEMPLATE FUNCTION search_n
#pragma basic_template_matching
template<class _FwdIt1,
         class _Diff2,
         class _Ty> inline
_FwdIt1 _Search_n(_FwdIt1 _First1, _FwdIt1 _Last1,
                  _Diff2 _Count, const _Ty& _Val, forward_iterator_tag)
{       // find first _Count * _Val match, forward iterators
  if (_Count <= 0)
    return (_First1);

  for (; _First1 != _Last1; ++_First1)
    if (*_First1 == _Val)
    {       // found start of possible match, check it out
      _FwdIt1 _Mid1  = _First1;

      for (_Diff2 _Count1 = _Count; ; )
        if (--_Count1 == 0)
          return (_First1);       // found rest of match, report it
        else if (++_Mid1 == _Last1)
          return (_Last1);        // short match at end
        else if (!(*_Mid1 == _Val))
          break;  // short match not at end

      _First1 = _Mid1;        // pick up just beyond failed match
    }
  return (_Last1);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _Diff2,
         class _Ty> inline
_FwdIt1 _Search_n(_FwdIt1 _First1, _FwdIt1 _Last1,
                  _Diff2 _Count, const _Ty& _Val, random_access_iterator_tag)
{       // find first _Count * _Val match, random-access iterators
  if (_Count <= 0)
    return (_First1);

  _FwdIt1 _Oldfirst1 = _First1;
  for (; _Count <= _Last1 - _Oldfirst1; )
  {       // enough room, look for a match 
    if (*_First1 == _Val)
    {       // found part of possible match, check it out
      _Diff2 _Count1 = _Count;
      _FwdIt1 _Mid1  = _First1;

      for (; _Oldfirst1 != _First1 && _First1[-1] == _Val; --_First1)
        --_Count1;      // back up over any skipped prefix

      if (_Count1 <= _Last1 - _Mid1)
        for (; ; )      // enough left, test suffix
          if (--_Count1 == 0)
            return (_First1);       // found rest of match, report it
          else if (!(*++_Mid1 == _Val))
            break;  // short match not at end

      _Oldfirst1 = ++_Mid1;   // failed match, take small jump
      _First1 = _Oldfirst1;
    }
    else
    {       // no match, take big jump and back up as needed
      _Oldfirst1 = _First1 + 1;
      _First1 += _Count;
    }
  }
  return (_Last1);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _Diff2,
         class _Ty> inline
_FwdIt1 search_n(_FwdIt1 _First1, _FwdIt1 _Last1,
                 _Diff2 _Count, const _Ty& _Val)
{       // find first _Count * _Val match
  return _Search_n(_First1, _Last1, _Count, _Val,
                   _Iter_cat(_First1));
}

// TEMPLATE FUNCTION search_n WITH PRED
#pragma basic_template_matching
template<class _FwdIt1,
         class _Diff2,
         class _Ty,
         class _Pr> inline
_FwdIt1 _Search_n(_FwdIt1 _First1, _FwdIt1 _Last1,
                  _Diff2 _Count, const _Ty& _Val, _Pr _Pred, forward_iterator_tag)
{       // find first _Count * _Val satisfying _Pred, forward iterators
  if (_Count <= 0)
    return (_First1);

  for (; _First1 != _Last1; ++_First1)
    if (_Pred(*_First1, _Val))
    {       // found start of possible match, check it out
      _FwdIt1 _Mid1  = _First1;

      for (_Diff2 _Count1 = _Count; ; )
        if (--_Count1 == 0)
          return (_First1);       // found rest of match, report it
        else if (++_Mid1 == _Last1)
          return (_Last1);        // short match at end
        else if (!_Pred(*_Mid1, _Val))
          break;  // short match not at end

      _First1 = _Mid1;        // pick up just beyond failed match
    }
  return (_Last1);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _Diff2,
         class _Ty,
         class _Pr> inline
_FwdIt1 _Search_n(_FwdIt1 _First1, _FwdIt1 _Last1,
                  _Diff2 _Count, const _Ty& _Val, _Pr _Pred, random_access_iterator_tag)
{       // find first _Count * _Val satisfying _Pred, random-access iterators
  if (_Count <= 0)
    return (_First1);

  _FwdIt1 _Oldfirst1 = _First1;
  for (; _Count <= _Last1 - _Oldfirst1; )
  {       // enough room, look for a match 
    if (_Pred(*_First1, _Val))
    {       // found part of possible match, check it out
      _Diff2 _Count1 = _Count;
      _FwdIt1 _Mid1  = _First1;

      for (; _Oldfirst1 != _First1 && _First1[-1] == _Val; --_First1)
        --_Count1;      // back up over any skipped prefix

      if (_Count1 <= _Last1 - _Mid1)
        for (; ; )      // enough left, test suffix
          if (--_Count1 == 0)
            return (_First1);       // found rest of match, report it
          else if (!_Pred(*++_Mid1, _Val))
            break;  // short match not at end

      _Oldfirst1 = ++_Mid1;   // failed match, take small jump
      _First1 = _Oldfirst1;
    }
    else
    {       // no match, take big jump and back up as needed
      _Oldfirst1 = _First1 + 1;
      _First1 += _Count;
    }
  }
  return (_Last1);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _Diff2,
         class _Ty,
         class _Pr> inline
_FwdIt1 search_n(_FwdIt1 _First1, _FwdIt1 _Last1,
                 _Diff2 _Count, const _Ty& _Val, _Pr _Pred)
{       // find first _Count * _Val satisfying _Pred
  return _Search_n(_First1, _Last1, _Count, _Val, _Pred,
                   _Iter_cat(_First1));
}

// TEMPLATE FUNCTION find_end
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2,
         class _Diff1,
         class _Diff2> inline
_FwdIt1 _Find_end(_FwdIt1 _First1, _FwdIt1 _Last1,
                  _FwdIt2 _First2, _FwdIt2 _Last2, _Diff1 *, _Diff2 *)
{       // find last [_First2, _Last2) match
  _Diff1 _Count1 = distance(_First1, _Last1);
  _Diff2 _Count2 = distance(_First2, _Last2);
  _FwdIt1 _Ans = _Last1;

  if (0 < _Count2)
    for (; _Count2 <= _Count1; ++_First1, --_Count1)
    {       // room for match, try it
      _FwdIt1 _Mid1 = _First1;
      for (_FwdIt2 _Mid2 = _First2; ; ++_Mid1)
        if (!(*_Mid1 == *_Mid2))
          break;
        else if (++_Mid2 == _Last2)
        {       // potential answer, save it
          _Ans = _First1;
          break;
        }
    }
  return (_Ans);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2> inline
_FwdIt1 find_end(_FwdIt1 _First1, _FwdIt1 _Last1,
                 _FwdIt2 _First2, _FwdIt2 _Last2)
{       // find last [_First2, _Last2) match
  return (_Find_end(_First1, _Last1, _First2, _Last2,
                    _Dist_type(_First1), _Dist_type(_First2)));
}

// TEMPLATE FUNCTION find_end WITH PRED
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2,
         class _Diff1,
         class _Diff2,
         class _Pr> inline
_FwdIt1 _Find_end(_FwdIt1 _First1, _FwdIt1 _Last1,
                  _FwdIt2 _First2, _FwdIt2 _Last2, 
                  _Pr _Pred, _Diff1 *, _Diff2 *)
{       // find last [_First2, _Last2) satisfying _Pred
  _Diff1 _Count1 = distance(_First1, _Last1);
  _Diff2 _Count2 = distance(_First2, _Last2);
  _FwdIt1 _Ans = _Last1;

  if (0 < _Count2)
    for (; _Count2 <= _Count1; ++_First1, --_Count1)
    {       // room for match, try it
      _FwdIt1 _Mid1 = _First1;
      for (_FwdIt2 _Mid2 = _First2; ; ++_Mid1)
        if (!_Pred(*_Mid1, *_Mid2))
          break;
        else if (++_Mid2 == _Last2)
        {       // potential answer, save it
          _Ans = _First1;
          break;
        }
    }
  return (_Ans);
}

#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2,
         class _Pr> inline
_FwdIt1 find_end(_FwdIt1 _First1, _FwdIt1 _Last1,
                 _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred)
{       // find last [_First2, _Last2) satisfying _Pred
  return (_Find_end(_First1, _Last1, _First2, _Last2, _Pred,
                    _Dist_type(_First1), _Dist_type(_First2)));
}

// TEMPLATE FUNCTION find_first_of
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2> inline
_FwdIt1 find_first_of(_FwdIt1 _First1, _FwdIt1 _Last1,
                      _FwdIt2 _First2, _FwdIt2 _Last2)
{       // look for one of [_First2, _Last2) that matches element
  for (; _First1 != _Last1; ++_First1)
    for (_FwdIt2 _Mid2 = _First2; _Mid2 != _Last2; ++_Mid2)
      if (*_First1 == *_Mid2)
        return (_First1);
  return (_First1);
}

// TEMPLATE FUNCTION find_first_of WITH PRED
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2,
         class _Pr> inline
_FwdIt1 find_first_of(_FwdIt1 _First1, _FwdIt1 _Last1,
                      _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred)
{       // look for one of [_First2, _Last2) satisfying _Pred with element
  for (; _First1 != _Last1; ++_First1)
    for (_FwdIt2 _Mid2 = _First2; _Mid2 != _Last2; ++_Mid2)
      if (_Pred(*_First1, *_Mid2))
        return (_First1);
  return (_First1);
}

// TEMPLATE FUNCTION iter_swap
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2> inline
void iter_swap(_FwdIt1 _Left, _FwdIt2 _Right)
{       // swap *_Left and *_Right
  /* _STD */ swap(*_Left, *_Right); 
}

// TEMPLATE FUNCTION swap_ranges
#pragma basic_template_matching
template<class _FwdIt1,
         class _FwdIt2> inline
_FwdIt2 swap_ranges(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2)
{       // swap [_First1, _Last1) with [_First2, ...)
  for (; _First1 != _Last1; ++_First1, ++_First2)
    _DLIB5 iter_swap(_First1, _First2);
  return (_First2);
}

// TEMPLATE FUNCTION transform WITH UNARY OP
#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Fn1> inline
_OutIt transform(_InIt _First, _InIt _Last, _OutIt _Dest, _Fn1 _Func)
{       // transform [_First, _Last) with _Func
  for (; _First != _Last; ++_First, ++_Dest)
    *_Dest = _Func(*_First);
  return (_Dest);
}

// TEMPLATE FUNCTION transform WITH BINARY OP
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt,
         class _Fn2> inline
_OutIt transform(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2,
                 _OutIt _Dest, _Fn2 _Func)
{       // transform [_First1, _Last1) and [_First2, _Last2) with _Func
  for (; _First1 != _Last1; ++_First1, ++_First2, ++_Dest)
    *_Dest = _Func(*_First1, *_First2);
  return (_Dest);
}

// TEMPLATE FUNCTION replace
template<class _FwdIt,
         class _Ty> inline
void replace(_FwdIt _First, _FwdIt _Last,
             const _Ty& _Oldval, const _Ty& _Newval)
{       // replace each matching _Oldval with _Newval
  for (; _First != _Last; ++_First)
    if (*_First == _Oldval)
      *_First = _Newval;
}

// TEMPLATE FUNCTION replace_if
template<class _FwdIt,
         class _Pr,
         class _Ty> inline
void replace_if(_FwdIt _First, _FwdIt _Last, _Pr _Pred, const _Ty& _Val)
{       // replace each satisfying _Pred with _Val
  for (; _First != _Last; ++_First)
    if (_Pred(*_First))
      *_First = _Val;
}

// TEMPLATE FUNCTION replace_copy
#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Ty> inline
_OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest,
                    const _Ty& _Oldval, const _Ty& _Newval)
{       // copy replacing each matching _Oldval with _Newval
  for (; _First != _Last; ++_First, ++_Dest)
    *_Dest = *_First == _Oldval ? _Newval : *_First;
  return (_Dest);
}

// TEMPLATE FUNCTION replace_copy_if
#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Pr,
         class _Ty> inline
_OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest,
                       _Pr _Pred, const _Ty& _Val)
{       // copy replacing each satisfying _Pred with _Val
  for (; _First != _Last; ++_First, ++_Dest)
    *_Dest = _Pred(*_First) ? _Val : *_First;
  return (_Dest);
}

// TEMPLATE FUNCTION generate
template<class _FwdIt,
         class _Fn0> inline
void generate(_FwdIt _First, _FwdIt _Last, _Fn0 _Func)
{       // replace [_First, _Last) with _Func()
  for (; _First != _Last; ++_First)
    *_First = _Func();
}

// TEMPLATE FUNCTION generate_n
template<class _OutIt,
         class _Diff,
         class _Fn0> inline
void generate_n(_OutIt _Dest, _Diff _Count, _Fn0 _Func)
{       // replace [_Dest, _Dest + _Count) with _Func()
  for (; 0 < _Count; --_Count, ++_Dest)
    *_Dest = _Func();
}

// TEMPLATE FUNCTION remove_copy
#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Ty> inline
_OutIt remove_copy(_InIt _First, _InIt _Last,
                   _OutIt _Dest, const _Ty& _Val)
{       // copy omitting each matching _Val
  for (; _First != _Last; ++_First)
    if (!(*_First == _Val))
      *_Dest++ = *_First;
  return (_Dest);
}

// TEMPLATE FUNCTION remove_copy_if
#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Pr> inline
_OutIt remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred)
{       // copy omitting each element satisfying _Pred
  for (; _First != _Last; ++_First)
    if (!_Pred(*_First))
      *_Dest++ = *_First;
  return (_Dest);
}

// TEMPLATE FUNCTION remove
#pragma basic_template_matching
template<class _FwdIt,
         class _Ty> inline
_FwdIt remove(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
{       // remove each matching _Val
  _First = find(_First, _Last, _Val);
  if (_First == _Last)
    return (_First);        // empty sequence, all done
  else
  {       // nonempty sequence, worth doing
    _FwdIt _First1 = _First;
    return (_DLIB5 remove_copy(++_First1, _Last, _First, _Val));
  }
}

// TEMPLATE FUNCTION remove_if
#pragma basic_template_matching
template<class _FwdIt,
         class _Pr> inline
_FwdIt remove_if(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{       // remove each satisfying _Pred
  _First = _DLIB5 find_if(_First, _Last, _Pred);
  if (_First == _Last)
    return (_First);        // empty sequence, all done
  else
  {       // nonempty sequence, worth doing
    _FwdIt _First1 = _First;
    return (_DLIB5 remove_copy_if(++_First1, _Last, _First, _Pred));
  }
}

// TEMPLATE FUNCTION unique
#pragma basic_template_matching
template<class _FwdIt> inline
_FwdIt unique(_FwdIt _First, _FwdIt _Last)
{       // remove each matching previous
  for (_FwdIt _Firstb; (_Firstb = _First) != _Last && ++_First != _Last; )
    if (*_Firstb == *_First)
    {       // copy down
      for (; ++_First != _Last; )
        if (!(*_Firstb == *_First))
          *++_Firstb = *_First;
      return (++_Firstb);
    }
  return (_Last);
}

// TEMPLATE FUNCTION unique WITH PRED
#pragma basic_template_matching
template<class _FwdIt,
         class _Pr> inline
_FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{       // remove each satisfying _Pred with previous
  for (_FwdIt _Firstb; (_Firstb = _First) != _Last && ++_First != _Last; )
    if (_Pred(*_Firstb, *_First))
    {       // copy down
      for (; ++_First != _Last; )
        if (!_Pred(*_Firstb, *_First))
          *++_Firstb = *_First;
      return (++_Firstb);
    }
  return (_Last);
}

// TEMPLATE FUNCTION unique_copy
#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Ty> inline
_OutIt _Unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Ty *)
{       // copy compressing pairs that match, input iterators
  // IAR memory support
  typename _ClassUtil::_TmpHolder<_Ty>::_Type _Val(*_First);

  for (*_Dest++ = _Val; ++_First != _Last; )
    if (!(_Val == *_First))
      _Val = *_First, *_Dest++ = _Val;
  return (_Dest);
}

#pragma basic_template_matching
template<class _InIt,
         class _OutIt> inline
_OutIt _Unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest,
                    input_iterator_tag)
{       // copy compressing pairs that match, input iterators
  return (_Unique_copy(_First, _Last, _Dest, _Val_type(_First)));
}

#pragma basic_template_matching
template<class _FwdIt,
         class _OutIt> inline
_OutIt _Unique_copy(_FwdIt _First, _FwdIt _Last, _OutIt _Dest,
                    forward_iterator_tag)
{       // copy compressing pairs that match, forward iterators
  _FwdIt _Firstb = _First;
  for (*_Dest++ = *_Firstb; ++_First != _Last; )
    if (!(*_Firstb == *_First))
      _Firstb = _First, *_Dest++ = *_Firstb;
  return (_Dest);
}

#pragma basic_template_matching
template<class _BidIt,
         class _OutIt> inline
_OutIt _Unique_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest,
                    bidirectional_iterator_tag)
{       // copy compressing pairs that match, bidirectional iterators
  return (_Unique_copy(_First, _Last, _Dest, forward_iterator_tag()));
}

#pragma basic_template_matching
template<class _RanIt,
         class _OutIt> inline
_OutIt _Unique_copy(_RanIt _First, _RanIt _Last, _OutIt _Dest,
                    random_access_iterator_tag)
{       // copy compressing pairs that match, random-access iterators
  return (_Unique_copy(_First, _Last, _Dest, forward_iterator_tag()));
}

#pragma basic_template_matching
template<class _InIt,
         class _OutIt> inline
_OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest)
{       // copy compressing pairs that match
  return (_First == _Last ? _Dest :
          _Unique_copy(_First, _Last, _Dest, _Iter_cat(_First)));
}

// TEMPLATE FUNCTION unique_copy WITH PRED
#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Ty,
         class _Pr> inline
_OutIt _Unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred,
                    _Ty *)
{       // copy compressing pairs satisfying _Pred, input iterators
  // IAR memory support
  typename _ClassUtil::_TmpHolder<_Ty>::_Type _Val(*_First);

  for (*_Dest++ = _Val; ++_First != _Last; )
    if (!_Pred(_Val, *_First))
      _Val = *_First, *_Dest++ = _Val;
  return (_Dest);
}

#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Pr> inline
_OutIt _Unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred,
                    input_iterator_tag)
{       // copy compressing pairs satisfying _Pred, input iterators
  return (_Unique_copy(_First, _Last, _Dest, _Pred, _Val_type(_First)));
}

#pragma basic_template_matching
template<class _FwdIt,
         class _OutIt,
         class _Pr> inline
_OutIt _Unique_copy(_FwdIt _First, _FwdIt _Last, _OutIt _Dest, _Pr _Pred,
                    forward_iterator_tag)
{       // copy compressing pairs satisfying _Pred, forward iterators
  _FwdIt _Firstb = _First;

  for (*_Dest++ = *_Firstb; ++_First != _Last; )
    if (!_Pred(*_Firstb, *_First))
      _Firstb = _First, *_Dest++ = *_Firstb;
  return (_Dest);
}

#pragma basic_template_matching
template<class _BidIt,
         class _OutIt,
         class _Pr> inline
_OutIt _Unique_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest, _Pr _Pred,
                    bidirectional_iterator_tag)
{       // copy compressing pairs satisfying _Pred, bidirectional iterators
  return (_Unique_copy(_First, _Last, _Dest, _Pred,
                       forward_iterator_tag()));
}

#pragma basic_template_matching
template<class _RanIt,
         class _OutIt,
         class _Pr> inline
_OutIt _Unique_copy(_RanIt _First, _RanIt _Last, _OutIt _Dest, _Pr _Pred,
                    random_access_iterator_tag)
{       // copy compressing pairs satisfying _Pred, random-access iterators
  return (_Unique_copy(_First, _Last, _Dest, _Pred,
                       forward_iterator_tag()));
}

#pragma basic_template_matching
template<class _InIt,
         class _OutIt,
         class _Pr> inline
_OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred)
{       // copy compressing pairs satisfying _Pred
  return (_First == _Last ? _Dest
          : _Unique_copy(_First, _Last, _Dest, _Pred, _Iter_cat(_First)));
}

// TEMPLATE FUNCTION reverse
#pragma basic_template_matching
template<class _BidIt> inline
void _Reverse(_BidIt _First, _BidIt _Last, bidirectional_iterator_tag)
{       // reverse elements in [_First, _Last), bidirectional iterators
  for (; _First != _Last && _First != --_Last; ++_First)
    _DLIB5 iter_swap(_First, _Last);
}

#pragma basic_template_matching
template<class _RanIt> inline
void _Reverse(_RanIt _First, _RanIt _Last, random_access_iterator_tag)
{       // reverse elements in [_First, _Last), random-access iterators
  for (; _First < _Last; ++_First)
    _DLIB5 iter_swap(_First, --_Last);
}

#pragma basic_template_matching
template<class _BidIt> inline
void reverse(_BidIt _First, _BidIt _Last)
{       // reverse elements in [_First, _Last)
  _Reverse(_First, _Last, _Iter_cat(_First));
}

// TEMPLATE FUNCTION reverse_copy
#pragma basic_template_matching
template<class _BidIt,
         class _OutIt> inline
_OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest)
{       // copy reversing elements in [_First, _Last)
  for (; _First != _Last; ++_Dest)
    *_Dest = *--_Last;
  return (_Dest);
}

// TEMPLATE FUNCTION rotate
template<class _FwdIt> inline
void _Rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last,
             forward_iterator_tag)
{       // rotate [_First, _Last), forward iterators
  for (_FwdIt _Next = _Mid; ; )
  {       // swap [_First, ...) into place
    _DLIB5 iter_swap(_First, _Next);
    if (++_First == _Mid)
      if (++_Next == _Last)
        break;  // done, quit
      else
        _Mid = _Next;   // mark end of next interval
    else if (++_Next == _Last)
      _Next = _Mid;   // wrap to last end
  }
}

template<class _BidIt> inline
void _Rotate(_BidIt _First, _BidIt _Mid, _BidIt _Last,
             bidirectional_iterator_tag)
{       // rotate [_First, _Last), bidirectional iterators
  _DLIB5 reverse(_First, _Mid);
  _DLIB5 reverse(_Mid, _Last);
  _DLIB5 reverse(_First, _Last);
}

template<class _RanIt,
         class _Diff,
         class _Ty> inline
void _Rotate(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Diff *, _Ty *)
{       // rotate [_First, _Last), random-access iterators
  _Diff _Shift = _Mid - _First;
  _Diff _Count = _Last - _First;

  for (_Diff _Factor = _Shift; _Factor != 0; )
  {       // find subcycle count as GCD of shift count and length
    _Diff _Tmp = _Count % _Factor;
    _Count = _Factor, _Factor = _Tmp;
  }

  if (_Count < _Last - _First)
    for (; 0 < _Count; --_Count)
    {       // rotate each subcycle
      _RanIt _Hole = _First + _Count;
      _RanIt _Next = _Hole;
      // IAR memory support
      typename _ClassUtil::_TmpHolder<_Ty>::_Type _Holeval(*_Hole);
      _RanIt _Next1 = _Next + _Shift == _Last ? _First : _Next + _Shift;
      while (_Next1 != _Hole)
      {       // percolate elements back around subcycle
        *_Next = *_Next1;
        _Next = _Next1;
        _Next1 = _Shift < _Last - _Next1 ? _Next1 + _Shift
          : _First + (_Shift - (_Last - _Next1));
      }
      *_Next = _Holeval;
    }
}

template<class _RanIt> inline
void _Rotate(_RanIt _First, _RanIt _Mid, _RanIt _Last,
             random_access_iterator_tag)
{       // rotate [_First, _Last), random-access iterators
  _Rotate(_First, _Mid, _Last, _Dist_type(_First), _Val_type(_First));
}

template<class _FwdIt> inline
void rotate(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last)
{       // rotate [_First, _Last)
  if (_First != _Mid && _Mid != _Last)
    _Rotate(_First, _Mid, _Last, _Iter_cat(_First));
}

// TEMPLATE FUNCTION rotate_copy
#pragma basic_template_matching
template<class _FwdIt,
         class _OutIt> inline
_OutIt rotate_copy(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last, _OutIt _Dest)
{       // copy rotating [_First, _Last)
  _Dest = _DLIB5 copy(_Mid, _Last, _Dest);
  return (_DLIB5 copy(_First, _Mid, _Dest));
}

// TEMPLATE FUNCTION random_shuffle
template<class _RanIt,
         class _Diff> inline
void _Random_shuffle(_RanIt _First, _RanIt _Last, _Diff *)
{       // shuffle [_First, _Last)
  const int _RANDOM_BITS = 15;    // minimum random bits from rand()
  const int _RANDOM_MAX = (1U << _RANDOM_BITS) - 1;

  _RanIt _Next = _First;
  for (unsigned long _Index = 2; ++_Next != _Last; ++_Index)
  {       // assume unsigned long big enough for _Diff count
    unsigned long _Rm = _RANDOM_MAX;
    unsigned long _Rn = _CSTD rand() & _RANDOM_MAX;
    for (; _Rm < _Index && _Rm != ~0UL;
         _Rm = _Rm << _RANDOM_BITS | _RANDOM_MAX)
      _Rn = _Rn << _RANDOM_BITS
        | (_CSTD rand() & _RANDOM_MAX); // build random value

    _DLIB5 iter_swap(_Next, _First + _Diff(_Rn % _Index));    // swap a pair
  }
}

template<class _RanIt> inline
void random_shuffle(_RanIt _First, _RanIt _Last)
{       // shuffle [_First, _Last)
  if (_First != _Last)
    _Random_shuffle(_First, _Last, _Dist_type(_First));
}

// TEMPLATE FUNCTION random_shuffle WITH RANDOM FN
template<class _RanIt,
         class _Fn1,
         class _Diff> inline
void _Random_shuffle(_RanIt _First, _RanIt _Last, _Fn1& _Func, _Diff *)
{       // shuffle nonempty [_First, _Last) using random function _Func
  _RanIt _Next = _First;

  for (_Diff _Index = 2; ++_Next != _Last; ++_Index)
    _DLIB5 iter_swap(_Next, _First + _Diff(_Func(_Index) % _Index));
}

template<class _RanIt,
         class _Fn1> inline
void random_shuffle(_RanIt _First, _RanIt _Last, _Fn1& _Func)
{       // shuffle [_First, _Last) using random function _Func
  if (_First != _Last)
    _Random_shuffle(_First, _Last, _Func, _Dist_type(_First));
}

// TEMPLATE FUNCTION partition
#pragma basic_template_matching
template<class _BidIt,
         class _Pr> inline
_BidIt partition(_BidIt _First, _BidIt _Last, _Pr _Pred)
{       // move elements satisfying _Pred to beginning of sequence
  for (; ; ++_First)
  {       // find any out-of-order pair
    for (; _First != _Last && _Pred(*_First); ++_First)
      ;       // skip in-place elements at beginning
    if (_First == _Last)
      break;  // done

    for (; _First != --_Last && !_Pred(*_Last); )
      ;       // skip in-place elements at end
    if (_First == _Last)
      break;  // done

    _DLIB5 iter_swap(_First, _Last);  // swap out-of-place pair and loop
  }
  return (_First);
}

// TEMPLATE FUNCTION stable_partition
#pragma basic_template_matching
template<class _BidIt,
         class _Pr,
         class _Diff,
         class _Ty> inline
_BidIt _Stable_partition(_BidIt _First, _BidIt _Last, _Pr _Pred,
                         _Diff _Count, _Temp_iterator<_Ty>& _Tempbuf)
{       // partition preserving order of equivalents, using _Pred
  if (_Count == 0)
    return (_First);
  else if (_Count == 1)
    return (_Pred(*_First) ? _Last : _First);
  else if (_Count <= _Tempbuf._Maxlen())
  {       // temp buffer big enough, copy right partition out and back
    _BidIt _Next = _First;
    for (_Tempbuf._Init(); _First != _Last; ++_First)
      if (_Pred(*_First))
        *_Next++ = *_First;
      else
        *_Tempbuf++ = *_First;

    _DLIB5 copy(_Tempbuf._First(), _Tempbuf._Last(), _Next);  // copy back
    return (_Next);
  }
  else
  {       // temp buffer not big enough, divide and conquer
    _BidIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count / 2);

    _BidIt _Left = 
      _Stable_partition(_First, _Mid, _Pred,
                        _Count / 2, _Tempbuf);  // form L1R1 in left half
    _BidIt _Right = 
      _Stable_partition(_Mid, _Last, _Pred,  // form L2R2 in right half
                        _Count - _Count / 2, _Tempbuf); 

    _Diff _Count1 = distance(_Left, _Mid);
    _Diff _Count2 = distance(_Mid, _Right);

    return (_Buffered_rotate(_Left, _Mid, _Right,// rotate L1R1L2R2 to L1L2R1R2
                             _Count1, _Count2, _Tempbuf));  
  }
} 

template<class _BidIt,
         class _Pr,
         class _Diff,
         class _Ty> inline
_BidIt _Stable_partition(_BidIt _First, _BidIt _Last, _Pr _Pred,
                         _Diff *, _Ty *)
{       // partition preserving order of equivalents, using _Pred
  _Diff _Count = distance(_First, _Last);
  _Temp_iterator<_Ty> _Tempbuf(_Count);
  return (_Stable_partition(_First, _Last, _Pred, _Count, _Tempbuf));
}

template<class _BidIt,
         class _Pr> inline
_BidIt stable_partition(_BidIt _First, _BidIt _Last, _Pr _Pred)
{       // partition preserving order of equivalents, using _Pred
  return (_First == _Last ? _First : _Stable_partition(_First, _Last, _Pred,
                                                       _Dist_type(_First),
                                                       _Val_type(_First)));
}

// TEMPLATE FUNCTION push_heap
#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty> inline
void _Push_heap(_RanIt _First, _Diff _Hole,
                _Diff _Top, _Ty const & _Val) // IAR memory support
{       // percolate _Hole to _Top or where _Val belongs, using operator<
  for (_Diff _Idx = (_Hole - 1) / 2;
       _Top < _Hole && *(_First + _Idx) < _Val;
       _Idx = (_Hole - 1) / 2)
  {       // move _Hole up to parent
    *(_First + _Hole) = *(_First + _Idx);
    _Hole = _Idx;
  }

  *(_First + _Hole) = _Val;     // drop _Val into final hole
}

#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty> inline
void _Push_heap_0(_RanIt _First, _RanIt _Last, _Diff *, _Ty *)
{       // push *_Last onto heap at [_First, _Last), using operator<
  _Diff _Count = _Last - _First;
  if (0 < _Count)
    _DLIB5 _Push_heap(_First, _Count, _Diff(0),
                    // IAR memory support
                    typename _ClassUtil::_TmpHolder<_Ty>::_Type(*_Last));
}

#pragma basic_template_matching
template<class _RanIt> inline
void push_heap(_RanIt _First, _RanIt _Last)
{       // push *(_Last - 1) onto heap at [_First, _Last - 1), using operator<
  if (_First != _Last)
  {       // check and push to nontrivial heap
    _DLIB5 _Push_heap_0(_First, --_Last,
                      _Dist_type(_First), _Val_type(_First));
  }
}

// TEMPLATE FUNCTION push_heap WITH PRED
#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Push_heap(_RanIt _First, _Diff _Hole,
                _Diff _Top, _Ty const & _Val, _Pr _Pred) // IAR memory support
{       // percolate _Hole to _Top or where _Val belongs, using operator<
  for (_Diff _Idx = (_Hole - 1) / 2;
       _Top < _Hole && _Pred(*(_First + _Idx), _Val);
       _Idx = (_Hole - 1) / 2)
  {       // move _Hole up to parent
    *(_First + _Hole) = *(_First + _Idx);
    _Hole = _Idx;
  }

  *(_First + _Hole) = _Val;      // drop _Val into final hole
}

#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Push_heap_0(_RanIt _First, _RanIt _Last, _Pr _Pred, _Diff *, _Ty *)
{       // push *_Last onto heap at [_First, _Last), using _Pred
  _Diff _Count = _Last - _First;
  if (0 < _Count)
    _DLIB5 _Push_heap(_First, _Count, _Diff(0),
                    // IAR memory support
                    typename _ClassUtil::_TmpHolder<_Ty>::_Type(*_Last),
                    _Pred);
}

#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred)
{       // push *(_Last - 1) onto heap at [_First, _Last - 1), using _Pred
  if (_First != _Last)
  {       // check and push to nontrivial heap
    _DLIB5 _Push_heap_0(_First, --_Last, _Pred,
                      _Dist_type(_First), _Val_type(_First));
  }
}

// TEMPLATE FUNCTION pop_heap
#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty> inline
void _Adjust_heap(_RanIt _First, _Diff _Hole, _Diff _Bottom, _Ty const & _Val)
                                                         // IAR memory support
{       // percolate _Hole to _Bottom, then push _Val, using operator<
  _Diff _Top = _Hole;
  _Diff _Idx = 2 * _Hole + 2;

  for (; _Idx < _Bottom; _Idx = 2 * _Idx + 2)
  {       // move _Hole down to larger child
    if (*(_First + _Idx) < *(_First + (_Idx - 1)))
      --_Idx;
    *(_First + _Hole) = *(_First + _Idx), _Hole = _Idx;
  }

  if (_Idx == _Bottom)
  {       // only child at bottom, move _Hole down to it
    *(_First + _Hole) = *(_First + (_Bottom - 1));
    _Hole = _Bottom - 1;
  }
  _DLIB5 _Push_heap(_First, _Hole, _Top, _Val);
}

#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty> inline
void _Pop_heap(_RanIt _First, _RanIt _Last, _RanIt _Dest,
               _Ty const & _Val, _Diff *) // IAR memory support
{       // pop *_First to *_Dest and reheap, using operator<
  *_Dest = *_First;
  _DLIB5 _Adjust_heap(_First, _Diff(0), _Diff(_Last - _First), _Val);
}

#pragma basic_template_matching
template<class _RanIt,
         class _Ty> inline
void _Pop_heap_0(_RanIt _First, _RanIt _Last, _Ty *)
{       // pop *_First to *(_Last - 1) and reheap, using operator<
  _Pop_heap(_First, _Last - 1, _Last - 1,
            // IAR memory support
            typename _ClassUtil::_TmpHolder<_Ty>::_Type(*(_Last - 1)),
            _Dist_type(_First));
}

#pragma basic_template_matching
template<class _RanIt> inline
void pop_heap(_RanIt _First, _RanIt _Last)
{       // pop *_First to *(_Last - 1) and reheap, using operator<
  if (1 < _Last - _First)
    _Pop_heap_0(_First, _Last, _Val_type(_First));
}

// TEMPLATE FUNCTION pop_heap WITH PRED
#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Adjust_heap(_RanIt _First, _Diff _Hole, _Diff _Bottom,
                  _Ty const & _Val, _Pr _Pred) // IAR memory support
{       // percolate _Hole to _Bottom, then push _Val, using _Pred
  _Diff _Top = _Hole;
  _Diff _Idx = 2 * _Hole + 2;

  for (; _Idx < _Bottom; _Idx = 2 * _Idx + 2)
  {       // move _Hole down to larger child
    if (_Pred(*(_First + _Idx), *(_First + (_Idx - 1))))
      --_Idx;
    *(_First + _Hole) = *(_First + _Idx), _Hole = _Idx;
  }

  if (_Idx == _Bottom)
  {       // only child at bottom, move _Hole down to it
    *(_First + _Hole) = *(_First + (_Bottom - 1));
    _Hole = _Bottom - 1;
  }
  _DLIB5 _Push_heap(_First, _Hole, _Top, _Val, _Pred);
}

#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Pop_heap(_RanIt _First, _RanIt _Last, _RanIt _Dest,
               _Ty const & _Val, _Pr _Pred, _Diff *) // IAR memory support
{       // pop *_First to *_Dest and reheap, using _Pred
  *_Dest = *_First;
  _DLIB5 _Adjust_heap(_First, _Diff(0), _Diff(_Last - _First), _Val, _Pred);
}

#pragma basic_template_matching
template<class _RanIt,
         class _Ty,
         class _Pr> inline
void _Pop_heap_0(_RanIt _First, _RanIt _Last, _Pr _Pred, _Ty *)
{       // pop *_First to *(_Last - 1) and reheap, using _Pred
  _Pop_heap(_First, _Last - 1, _Last - 1,
            // IAR memory support
            typename _ClassUtil::_TmpHolder<_Ty>::_Type(*(_Last - 1)), _Pred,
            _Dist_type(_First));
}

#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred)
{       // pop *_First to *(_Last - 1) and reheap, using _Pred
  if (1 < _Last - _First)
    _Pop_heap_0(_First, _Last, _Pred, _Val_type(_First));
}

// TEMPLATE FUNCTION make_heap
#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty> inline
void _Make_heap(_RanIt _First, _RanIt _Last, _Diff *, _Ty *)
{       // make nontrivial [_First, _Last) into a heap, using operator<
  _Diff _Bottom = _Last - _First;

  for (_Diff _Hole = _Bottom / 2; 0 < _Hole; )
  {       // reheap top half, bottom to top
    --_Hole;
    _DLIB5 _Adjust_heap(_First, _Hole, _Bottom,
                      // IAR memory support
                      typename _ClassUtil::_TmpHolder<_Ty>::_Type(
                        *(_First + _Hole)));
  }
}

#pragma basic_template_matching
template<class _RanIt> inline
void make_heap(_RanIt _First, _RanIt _Last)
{       // make [_First, _Last) into a heap, using operator<
  if (1 < _Last - _First)
    _Make_heap(_First, _Last,
               _Dist_type(_First), _Val_type(_First));
}

// TEMPLATE FUNCTION make_heap WITH PRED
#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred, _Diff *, _Ty *)
{       // make nontrivial [_First, _Last) into a heap, using _Pred
  _Diff _Bottom = _Last - _First;
  for (_Diff _Hole = _Bottom / 2; 0 < _Hole; )
  {       // reheap top half, bottom to top
    --_Hole;
    _DLIB5 _Adjust_heap(_First, _Hole, _Bottom,
                      // IAR memory support
                      typename _ClassUtil::_TmpHolder<_Ty>::_Type(
                        *(_First + _Hole)),
                      _Pred);
  }
}

#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred)
{       // make [_First, _Last) into a heap, using _Pred
  if (1 < _Last - _First)
    _Make_heap(_First, _Last, _Pred,
               _Dist_type(_First), _Val_type(_First));
}

// TEMPLATE FUNCTION sort_heap
#pragma basic_template_matching
template<class _RanIt> inline
void sort_heap(_RanIt _First, _RanIt _Last)
{       // order heap by repeatedly popping, using operator<
  for (; 1 < _Last - _First; --_Last)
    _DLIB5 pop_heap(_First, _Last);
}

// TEMPLATE FUNCTION sort_heap WITH PRED
#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred)
{       // order heap by repeatedly popping, using _Pred
  for (; 1 < _Last - _First; --_Last)
    _DLIB5 pop_heap(_First, _Last, _Pred);
}

// TEMPLATE FUNCTION lower_bound
#pragma basic_template_matching
template<class _FwdIt,
         class _Ty,
         class _Diff> inline
_FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Diff *)
{       // find first element not before _Val, using operator<
  _Diff _Count = distance(_First, _Last);

  for (; 0 < _Count; )
  {       // divide and conquer, find half that contains answer
    _Diff _Count2 = _Count / 2;
    _FwdIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    if (*_Mid < _Val)
      _First = ++_Mid, _Count -= _Count2 + 1;
    else
      _Count = _Count2;
  }
  return (_First);
}

#pragma basic_template_matching
template<class _FwdIt,
         class _Ty> inline
_FwdIt lower_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
{       // find first element not before _Val, using operator<
  return (_Lower_bound(_First, _Last, _Val, _Dist_type(_First)));
}

// TEMPLATE FUNCTION lower_bound WITH PRED
#pragma basic_template_matching
template<class _FwdIt,
         class _Ty,
         class _Diff,
         class _Pr> inline
_FwdIt _Lower_bound(_FwdIt _First, _FwdIt _Last,
                    const _Ty& _Val, _Pr _Pred, _Diff *)
{       // find first element not before _Val, using _Pred
  _Diff _Count = distance(_First, _Last);
  for (; 0 < _Count; )
  {       // divide and conquer, find half that contains answer
    _Diff _Count2 = _Count / 2;
    _FwdIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    if (_Pred(*_Mid, _Val))
      _First = ++_Mid, _Count -= _Count2 + 1;
    else
      _Count = _Count2;
  }
  return (_First);
}

#pragma basic_template_matching
template<class _FwdIt,
         class _Ty,
         class _Pr> inline
_FwdIt lower_bound(_FwdIt _First, _FwdIt _Last,
                   const _Ty& _Val, _Pr _Pred)
{       // find first element not before _Val, using _Pred
  return (_Lower_bound(_First, _Last, _Val, _Pred, _Dist_type(_First)));
}

// TEMPLATE FUNCTION upper_bound
#pragma basic_template_matching
template<class _FwdIt,
         class _Ty,
         class _Diff> inline
_FwdIt _Upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Diff *)
{       // find first element that _Val is before, using operator<
  _Diff _Count = distance(_First, _Last);
  for (; 0 < _Count; )
  {       // divide and conquer, find half that contains answer
    _Diff _Count2 = _Count / 2;
    _FwdIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    if (!(_Val < *_Mid))
      _First = ++_Mid, _Count -= _Count2 + 1;
    else
      _Count = _Count2;
  }
  return (_First);
}

#pragma basic_template_matching
template<class _FwdIt,
         class _Ty> inline
_FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
{       // find first element that _Val is before, using operator<
  return (_Upper_bound(_First, _Last, _Val, _Dist_type(_First)));
}

// TEMPLATE FUNCTION upper_bound WITH PRED
#pragma basic_template_matching
template<class _FwdIt,
         class _Ty,
         class _Diff,
         class _Pr> inline
_FwdIt _Upper_bound(_FwdIt _First, _FwdIt _Last,
                    const _Ty& _Val, _Pr _Pred, _Diff *)
{       // find first element that _Val is before, using _Pred
  _Diff _Count = distance(_First, _Last);
  for (; 0 < _Count; )
  {       // divide and conquer, find half that contains answer
    _Diff _Count2 = _Count / 2;
    _FwdIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    if (!_Pred(_Val, *_Mid))
      _First = ++_Mid, _Count -= _Count2 + 1;
    else
      _Count = _Count2;
  }
  return (_First);
}

#pragma basic_template_matching
template<class _FwdIt,
         class _Ty,
         class _Pr> inline
_FwdIt upper_bound(_FwdIt _First, _FwdIt _Last,
                   const _Ty& _Val, _Pr _Pred)
{       // find first element that _Val is before, using _Pred
  return (_Upper_bound(_First, _Last, _Val, _Pred, _Dist_type(_First)));
}

// TEMPLATE FUNCTION equal_range
template<class _FwdIt,
         class _Ty,
         class _Diff> inline
pair<_FwdIt, _FwdIt> _Equal_range(_FwdIt _First, _FwdIt _Last,
                                  const _Ty& _Val, _Diff *)
{       // find range equivalent to _Val, using operator<
  _Diff _Count = distance(_First, _Last);

  for (; 0 < _Count; )
  {       // divide and conquer, check midpoint
    _Diff _Count2 = _Count / 2;
    _FwdIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    if (*_Mid < _Val)
    {       // range begins above _Mid, loop
      _First = ++_Mid;
      _Count -= _Count2 + 1;
    }
    else if (_Val < *_Mid)
      _Count = _Count2;       // range in first half, loop
    else
    {       // range straddles mid, find each end and return
      _FwdIt _First2 = lower_bound(_First, _Mid, _Val);
      _DLIB5 advance(_First, _Count);
      _FwdIt _Last2 = upper_bound(++_Mid, _First, _Val);
      return (pair<_FwdIt, _FwdIt>(_First2, _Last2));
    }
  }

  return (pair<_FwdIt, _FwdIt>(_First, _First));  // empty range
}

template<class _FwdIt,
         class _Ty> inline
pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last,
                                 const _Ty& _Val)
{       // find range equivalent to _Val, using operator<
  return (_Equal_range(_First, _Last, _Val, _Dist_type(_First)));
}

// TEMPLATE FUNCTION equal_range WITH PRED
template<class _FwdIt,
         class _Ty,
         class _Diff,
         class _Pr> inline
pair<_FwdIt, _FwdIt> _Equal_range(_FwdIt _First, _FwdIt _Last,
                                  const _Ty& _Val, _Pr _Pred, _Diff *)
{       // find range equivalent to _Val, using _Pred
  _Diff _Count = distance(_First, _Last);

  for (; 0 < _Count; )
  {       // divide and conquer, check midpoint
    _Diff _Count2 = _Count / 2;
    _FwdIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    if (_Pred(*_Mid, _Val))
    {       // range begins above _Mid, loop
      _First = ++_Mid;
      _Count -= _Count2 + 1;
    }
    else if (_Pred(_Val, *_Mid))
      _Count = _Count2;       // range in first half, loop
    else
    {       // range straddles _Mid, find each end and return
      _FwdIt _First2 = lower_bound(_First, _Mid, _Val, _Pred);
      _DLIB5 advance(_First, _Count);
      _FwdIt _Last2 = upper_bound(++_Mid, _First, _Val, _Pred);
      return (pair<_FwdIt, _FwdIt>(_First2, _Last2));
    }
  }

  return (pair<_FwdIt, _FwdIt>(_First, _First));  // empty range
}

template<class _FwdIt,
         class _Ty,
         class _Pr> inline
pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last,
                                 const _Ty& _Val, _Pr _Pred)
{       // find range equivalent to _Val, using _Pred
  return (_Equal_range(_First, _Last, _Val, _Pred, _Dist_type(_First)));
}

// TEMPLATE FUNCTION binary_search
template<class _FwdIt,
         class _Ty> inline
bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val)
{       // test if _Val equivalent to some element, using operator<
  _First = _DLIB5 lower_bound(_First, _Last, _Val);
  return (_First != _Last && !(_Val < *_First));
}

// TEMPLATE FUNCTION binary_search WITH PRED
template<class _FwdIt,
         class _Ty,
         class _Pr> inline
bool binary_search(_FwdIt _First, _FwdIt _Last,
                   const _Ty& _Val, _Pr _Pred)
{       // test if _Val equivalent to some element, using _Pred
  _First = _DLIB5 lower_bound(_First, _Last, _Val, _Pred);
  return (_First != _Last && !_Pred(_Val, *_First));
}

// TEMPLATE FUNCTION merge
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt> inline
_OutIt merge(_InIt1 _First1, _InIt1 _Last1,
             _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
{       // copy merging ranges, both using operator<
  for (; _First1 != _Last1 && _First2 != _Last2; ++_Dest)
    if (*_First2 < *_First1)
      *_Dest = *_First2, ++_First2;
    else
      *_Dest = *_First1, ++_First1;

  _Dest = _DLIB5 copy(_First1, _Last1, _Dest);      // copy any tail
  return (_DLIB5 copy(_First2, _Last2, _Dest));
}

// TEMPLATE FUNCTION merge WITH PRED
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt,
         class _Pr> inline
_OutIt merge(_InIt1 _First1, _InIt1 _Last1,
             _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred)
{       //  copy merging ranges, both using _Pred
  for (; _First1 != _Last1 && _First2 != _Last2; ++_Dest)
    if (_Pred(*_First2, *_First1))
      *_Dest = *_First2, ++_First2;
    else
      *_Dest = *_First1, ++_First1;

  _Dest = _DLIB5 copy(_First1, _Last1, _Dest);      // copy any tail
  return (_DLIB5 copy(_First2, _Last2, _Dest));
}

// TEMPLATE FUNCTION inplace_merge
#pragma basic_template_matching
template<class _BidIt,
         class _Diff,
         class _Ty> inline
_BidIt _Buffered_rotate(_BidIt _First, _BidIt _Mid, _BidIt _Last,
                        _Diff _Count1, _Diff _Count2, 
                        _Temp_iterator<_Ty>& _Tempbuf)
{       // rotate [_First, _Last) using temp buffer
  if (_Count1 <= _Count2 && _Count1 <= _Tempbuf._Maxlen())
  {       // buffer left partition, then copy parts
    _DLIB5 copy(_First, _Mid, _Tempbuf._Init());
    _DLIB5 copy(_Mid, _Last, _First);
    return (_DLIB5 copy_backward(_Tempbuf._First(), _Tempbuf._Last(),
                               _Last));
  }
  else if (_Count2 <= _Tempbuf._Maxlen())
  {       // buffer right partition, then copy parts
    _DLIB5 copy(_Mid, _Last, _Tempbuf._Init());
    _DLIB5 copy_backward(_First, _Mid, _Last);
    return (_DLIB5 copy(_Tempbuf._First(), _Tempbuf._Last(), _First));
  }
  else
  {       // buffer too small, rotate in place
    _DLIB5 rotate(_First, _Mid, _Last);
    _DLIB5 advance(_First, _Count2);
    return (_First);
  }
}

#pragma basic_template_matching
template<class _BidIt1,
         class _BidIt2,
         class _BidIt3> inline
_BidIt3 _Merge_backward(_BidIt1 _First1, _BidIt1 _Last1,
                        _BidIt2 _First2, _BidIt2 _Last2, _BidIt3 _Dest)
{       // merge backwards to _Dest, using operator<
  for (; ; )
    if (_First1 == _Last1)
      return (_DLIB5 copy_backward(_First2, _Last2, _Dest));
    else if (_First2 == _Last2)
      return (_DLIB5 copy_backward(_First1, _Last1, _Dest));
    else if (*--_Last2 < *--_Last1)
      *--_Dest = *_Last1, ++_Last2;
    else
      *--_Dest = *_Last2, ++_Last1;
}

#pragma basic_template_matching
template<class _BidIt,
         class _Diff,
         class _Ty> inline
void _Buffered_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last,
                     _Diff _Count1, _Diff _Count2,
                     _Temp_iterator<_Ty>& _Tempbuf)
{       // merge [_First, _Mid) with [_Mid, _Last), using operator<
  if (_Count1 + _Count2 == 2)
  {       // order two one-element partitions
    if (*_Mid < *_First)
      _DLIB5 iter_swap(_First, _Mid);
  }
  else if (_Count1 <= _Count2 && _Count1 <= _Tempbuf._Maxlen())
  {       // buffer left partition, then merge
    _DLIB5 copy(_First, _Mid, _Tempbuf._Init());
    _DLIB5 merge(_Tempbuf._First(), _Tempbuf._Last(), _Mid, _Last, _First);
  }
  else if (_Count2 <= _Tempbuf._Maxlen())
  {       // buffer right partition, then merge
    _DLIB5 copy(_Mid, _Last, _Tempbuf._Init());
    _DLIB5 _Merge_backward(_First, _Mid,
                         _Tempbuf._First(), _Tempbuf._Last(), _Last);
  }
  else
  {       // buffer too small, divide and conquer
    _BidIt _Firstn, _Lastn;
    _Diff _Count1n, _Count2n;

    if (_Count2 < _Count1)
    {       // left larger, cut it in half and partition right to match
      _Count1n = _Count1 / 2, _Count2n = 0;
      _Firstn = _First;
      _DLIB5 advance(_Firstn, _Count1n);
      _Lastn = _DLIB5 lower_bound(_Mid, _Last, *_Firstn);
      _Count2n = distance(_Mid, _Lastn);
    }
    else
    {       // right larger, cut it in half and partition left to match
      _Count1n = 0, _Count2n = _Count2 / 2;
      _Lastn = _Mid;
      _DLIB5 advance(_Lastn, _Count2n);
      _Firstn = _DLIB5 upper_bound(_First, _Mid, *_Lastn);
      _Count1n = distance(_First, _Firstn);
    }

    _Diff _Count1Diff = _Count1 - _Count1n;
    _BidIt _Midn = _Buffered_rotate(_Firstn, _Mid, _Lastn, // rearrange middle
                                    _Count1Diff, _Count2n, _Tempbuf);
    _Buffered_merge(_First, _Firstn, _Midn,
                    _Count1n, _Count2n, _Tempbuf);  // merge each new part
    _Diff _Count2Diff = _Count2 - _Count2n;
    _Buffered_merge(_Midn, _Lastn, _Last,
                    _Count1Diff, _Count2Diff, _Tempbuf);
  }
}

#pragma basic_template_matching
template<class _BidIt,
         class _Diff,
         class _Ty> inline
void _Inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last,
                    _Diff *, _Ty *)
{       // merge [_First, _Mid) with [_Mid, _Last), using operator<
  _Diff _Count1 = distance(_First, _Mid);
  _Diff _Count2 = distance(_Mid, _Last);
  _Temp_iterator<_Ty> _Tempbuf(_Count1 < _Count2 ? _Count1 : _Count2);
  _Buffered_merge(_First, _Mid, _Last,
                  _Count1, _Count2, _Tempbuf);
}

#pragma basic_template_matching
template<class _BidIt> inline
void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last)
{       // merge [_First, _Mid) with [_Mid, _Last), using operator<
  if (_First != _Mid && _Mid != _Last)
    _Inplace_merge(_First, _Mid, _Last,
                   _Dist_type(_First), _Val_type(_First));
}

// TEMPLATE FUNCTION inplace_merge WITH PRED
#pragma basic_template_matching
template<class _BidIt1,
         class _BidIt2,
         class _BidIt3,
         class _Pr> inline
_BidIt3 _Merge_backward(_BidIt1 _First1, _BidIt1 _Last1,
                        _BidIt2 _First2, _BidIt2 _Last2, _BidIt3 _Dest, 
                        _Pr _Pred)
{       // merge backwards to _Dest, using _Pred
  for (; ; )
    if (_First1 == _Last1)
      return (_DLIB5 copy_backward(_First2, _Last2, _Dest));
    else if (_First2 == _Last2)
      return (_DLIB5 copy_backward(_First1, _Last1, _Dest));
    else if (_Pred(*--_Last2, *--_Last1))
      *--_Dest = *_Last1, ++_Last2;
    else
      *--_Dest = *_Last2, ++_Last1;
}

#pragma basic_template_matching
template<class _BidIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Buffered_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last,
                     _Diff _Count1, _Diff _Count2,
                     _Temp_iterator<_Ty>& _Tempbuf, _Pr _Pred)
{       // merge [_First, _Mid) with [_Mid, _Last), using _Pred
  if (_Count1 + _Count2 == 2)
  {       // order two one-element partitions
    if (_Pred(*_Mid, *_First))
      _DLIB5 iter_swap(_First, _Mid);
  }
  else if (_Count1 <= _Count2 && _Count1 <= _Tempbuf._Maxlen())
  {       // buffer left partition, then merge
    _DLIB5 copy(_First, _Mid, _Tempbuf._Init());
    _DLIB5 merge(_Tempbuf._First(), _Tempbuf._Last(),
               _Mid, _Last, _First, _Pred);
  }
  else if (_Count2 <= _Tempbuf._Maxlen())
  {       // buffer right partition, then merge
    _DLIB5 copy(_Mid, _Last, _Tempbuf._Init());
    _DLIB5 _Merge_backward(_First, _Mid,
                         _Tempbuf._First(), _Tempbuf._Last(), _Last, _Pred);
  }
  else
  {       // buffer too small, divide and conquer
    _BidIt _Firstn, _Lastn;
    _Diff _Count1n, _Count2n;
    if (_Count2 < _Count1)
    {       // left larger, cut it in half and partition right to match
      _Count1n = _Count1 / 2, _Count2n = 0;
      _Firstn = _First;
      _DLIB5 advance(_Firstn, _Count1n);
      _Lastn = lower_bound(_Mid, _Last, *_Firstn, _Pred);
      _Count2n = distance(_Mid, _Lastn);
    }
    else
    {       // right larger, cut it in half and partition left to match
      _Count1n = 0, _Count2n = _Count2 / 2;
      _Lastn = _Mid;
      _DLIB5 advance(_Lastn, _Count2n);
      _Firstn = upper_bound(_First, _Mid, *_Lastn, _Pred);
      _Count1n = distance(_First, _Firstn);
    }

    _Diff _Count1Diff = _Count1 - _Count1n;
    _BidIt _Midn = _Buffered_rotate(_Firstn, _Mid, _Lastn, // rearrange middle
                                    _Count1Diff, _Count2n, _Tempbuf);
    _Buffered_merge(_First, _Firstn, _Midn,  // merge each new part
                    _Count1n, _Count2n, _Tempbuf, _Pred);
    _Diff _Count2Diff = _Count2 - _Count2n;
    _Buffered_merge(_Midn, _Lastn, _Last,
                    _Count1Diff, _Count2Diff, _Tempbuf, _Pred);
  }
}

template<class _BidIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Pr _Pred,
                    _Diff *, _Ty *)
{       // merge [_First, _Mid) with [_Mid, _Last), using _Pred
  _Diff _Count1 = distance(_First, _Mid);
  _Diff _Count2 = distance(_Mid, _Last);
  _Temp_iterator<_Ty> _Tempbuf(_Count1 < _Count2 ? _Count1 : _Count2);
  _Buffered_merge(_First, _Mid, _Last,
                  _Count1, _Count2, _Tempbuf, _Pred);
}

template<class _BidIt,
         class _Pr> inline
void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Pr _Pred)
{       // merge [_First, _Mid) with [_Mid, _Last), using _Pred
  if (_First != _Mid && _Mid != _Last)
    _Inplace_merge(_First, _Mid, _Last, _Pred,
                   _Dist_type(_First), _Val_type(_First));
}

// TEMPLATE FUNCTION sort
#pragma basic_template_matching
template<class _BidIt,
         class _Ty> inline
void _Insertion_sort1(_BidIt _First, _BidIt _Last, _Ty *)
{       // insertion sort [_First, _Last), using operator<
  if (_First != _Last)
    for (_BidIt _Next = _First; ++_Next != _Last; )
    {       // order next element
      _BidIt _Next1 = _Next;
      // IAR memory support
      typename _ClassUtil::_TmpHolder<_Ty>::_Type _Val0(*_Next);
      typename _ClassUtil::_TmpHolder<_Ty>::_RefType const & _Val = _Val0;

      if (_DEBUG_LT(_Val, *_First))
      {       // found new earliest element, move to front
        _DLIB5 copy_backward(_First, _Next, ++_Next1);
        *_First = _Val;
      }
      else
      {       // look for insertion point after first
        for (_BidIt _First1 = _Next1;
             _DEBUG_LT(_Val, *--_First1);
             _Next1 = _First1)
          *_Next1 = *_First1;     // move hole down
        *_Next1 = _Val; // insert element in hole
      }
    }
}

#pragma basic_template_matching
template<class _BidIt> inline
void _Insertion_sort(_BidIt _First, _BidIt _Last)
{       // insertion sort [_First, _Last), using operator<
  _DLIB5 _Insertion_sort1(_First, _Last, _Val_type(_First));
}

#pragma basic_template_matching
template<class _RanIt> inline
void _Med3(_RanIt _First, _RanIt _Mid, _RanIt _Last)
{       // sort median of three elements to middle
  if (*_Mid < *_First)
    _DLIB5 iter_swap(_Mid, _First);
  if (*_Last < *_Mid)
    _DLIB5 iter_swap(_Last, _Mid);
  if (*_Mid < *_First)
    _DLIB5 iter_swap(_Mid, _First);
}

#pragma basic_template_matching
template<class _RanIt> inline
void _Median(_RanIt _First, _RanIt _Mid, _RanIt _Last)
{       // sort median element to middle
  if (40 < _Last - _First)
  {       // median of nine
    size_t _Step = (_Last - _First + 1) / 8;
    _DLIB5 _Med3(_First, _First + _Step, _First + 2 * _Step);
    _DLIB5 _Med3(_Mid - _Step, _Mid, _Mid + _Step);
    _DLIB5 _Med3(_Last - 2 * _Step, _Last - _Step, _Last);
    _DLIB5 _Med3(_First + _Step, _Mid, _Last - _Step);
  }
  else
    _DLIB5 _Med3(_First, _Mid, _Last);
}

#pragma basic_template_matching
template<class _RanIt> inline
pair<_RanIt, _RanIt> _Unguarded_partition(_RanIt _First, _RanIt _Last)
{       // partition [_First, _Last), using operator<
  _RanIt _Mid = _First + (_Last - _First) / 2;    // sort median to _Mid
  _DLIB5 _Median(_First, _Mid, _Last - 1);
  _RanIt _Pfirst = _Mid;
  _RanIt _Plast = _Pfirst + 1;

  while (_First < _Pfirst
         && !(*(_Pfirst - 1) < *_Pfirst)
         && !(*_Pfirst < *(_Pfirst - 1)))
    --_Pfirst;
  while (_Plast < _Last
         && !(*_Plast < *_Pfirst)
         && !(*_Pfirst < *_Plast))
    ++_Plast;

  _RanIt _Gfirst = _Plast;
  _RanIt _Glast = _Pfirst;

  for (; ; )
  {       // partition
    for (; _Gfirst < _Last; ++_Gfirst)
      if (*_Pfirst < *_Gfirst)
        ;
      else if (*_Gfirst < *_Pfirst)
        break;
      else
        _DLIB5 iter_swap(_Plast++, _Gfirst);
    for (; _First < _Glast; --_Glast)
      if (*(_Glast - 1) < *_Pfirst)
        ;
      else if (*_Pfirst < *(_Glast - 1))
        break;
      else
        _DLIB5 iter_swap(--_Pfirst, _Glast - 1);
    if (_Glast == _First && _Gfirst == _Last)
      return (pair<_RanIt, _RanIt>(_Pfirst, _Plast));

    if (_Glast == _First)
    {       // no room at bottom, rotate pivot upward
      if (_Plast != _Gfirst)
        _DLIB5 iter_swap(_Pfirst, _Plast);
      ++_Plast;
      _DLIB5 iter_swap(_Pfirst++, _Gfirst++);
    }
    else if (_Gfirst == _Last)
    {       // no room at top, rotate pivot downward
      if (--_Glast != --_Pfirst)
        _DLIB5 iter_swap(_Glast, _Pfirst);
      _DLIB5 iter_swap(_Pfirst, --_Plast);
    }
    else
      _DLIB5 iter_swap(_Gfirst++, --_Glast);
  }
}

#pragma basic_template_matching
template<class _RanIt,
         class _Diff> inline
void _Sort(_RanIt _First, _RanIt _Last, _Diff _Ideal)
{       // order [_First, _Last), using operator<
  _Diff _Count;
  for (; _ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal; )
  {       // divide and conquer by quicksort
    pair<_RanIt, _RanIt> _Mid =
      _DLIB5 _Unguarded_partition(_First, _Last);
    _Ideal /= 2, _Ideal += _Ideal / 2;      // allow 1.5 log2(N) divisions

    if (_Mid.first - _First < _Last - _Mid.second)
    {       // loop on second half
      _DLIB5 _Sort(_First, _Mid.first, _Ideal);
      _First = _Mid.second;
    }
    else
    {       // loop on first half
      _DLIB5 _Sort(_Mid.second, _Last, _Ideal);
      _Last = _Mid.first;
    }
  }

  if (_ISORT_MAX < _Count)
  {       // heap sort if too many divisions
    _DLIB5 make_heap(_First, _Last);
    _DLIB5 sort_heap(_First, _Last);
  }
  else if (1 < _Count)
    _DLIB5 _Insertion_sort(_First, _Last);    // small, insertion sort
}

#pragma basic_template_matching
template<class _RanIt> inline
void sort(_RanIt _First, _RanIt _Last)
{       // order [_First, _Last), using operator<
  _DLIB5 _Sort(_First, _Last, _Last - _First);
}

// TEMPLATE FUNCTION sort WITH PRED
#pragma basic_template_matching
template<class _BidIt,
         class _Pr,
         class _Ty> inline
void _Insertion_sort1(_BidIt _First, _BidIt _Last, _Pr _Pred, _Ty *)
{       // insertion sort [_First, _Last), using _Pred
  if (_First != _Last)
    for (_BidIt _Next = _First; ++_Next != _Last; )
    {       // order next element
      _BidIt _Next1 = _Next;
      _Ty _Val = *_Next;

      if (_DEBUG_LT_PRED(_Pred, _Val, *_First))
      {       // found new earliest element, move to front
        _DLIB5 copy_backward(_First, _Next, ++_Next1);
        *_First = _Val;
      }
      else
      {       // look for insertion point after first
        for (_BidIt _First1 = _Next1;
             _DEBUG_LT_PRED(_Pred, _Val, *--_First1);
             _Next1 = _First1)
          *_Next1 = *_First1;     // move hole down
        *_Next1 = _Val; // insert element in hole
      }
    }
}

#pragma basic_template_matching
template<class _BidIt,
         class _Pr> inline
void _Insertion_sort(_BidIt _First, _BidIt _Last, _Pr _Pred)
{       // insertion sort [_First, _Last), using _Pred
  _DLIB5 _Insertion_sort1(_First, _Last, _Pred, _Val_type(_First));
}

#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
void _Med3(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred)
{       // sort median of three elements to middle
  if (_Pred(*_Mid, *_First))
    _DLIB5 iter_swap(_Mid, _First);
  if (_Pred(*_Last, *_Mid))
    _DLIB5 iter_swap(_Last, _Mid);
  if (_Pred(*_Mid, *_First))
    _DLIB5 iter_swap(_Mid, _First);
}

#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
void _Median(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred)
{       // sort median element to middle
  if (40 < _Last - _First)
  {       // median of nine
    size_t _Step = (_Last - _First + 1) / 8;
    _DLIB5 _Med3(_First, _First + _Step, _First + 2 * _Step, _Pred);
    _DLIB5 _Med3(_Mid - _Step, _Mid, _Mid + _Step, _Pred);
    _DLIB5 _Med3(_Last - 2 * _Step, _Last - _Step, _Last, _Pred);
    _DLIB5 _Med3(_First + _Step, _Mid, _Last - _Step, _Pred);
  }
  else
    _DLIB5 _Med3(_First, _Mid, _Last, _Pred);
}

#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
pair<_RanIt, _RanIt> _Unguarded_partition(_RanIt _First, _RanIt _Last,
                                          _Pr _Pred)
{       // partition [_First, _Last), using _Pred
  _RanIt _Mid = _First + (_Last - _First) / 2;
  _DLIB5 _Median(_First, _Mid, _Last - 1, _Pred);
  _RanIt _Pfirst = _Mid;
  _RanIt _Plast = _Pfirst + 1;

  while (_First < _Pfirst
         && !_Pred(*(_Pfirst - 1), *_Pfirst)
         && !_Pred(*_Pfirst, *(_Pfirst - 1)))
    --_Pfirst;
  while (_Plast < _Last
         && !_Pred(*_Plast, *_Pfirst)
         && !_Pred(*_Pfirst, *_Plast))
    ++_Plast;

  _RanIt _Gfirst = _Plast;
  _RanIt _Glast = _Pfirst;

  for (; ; )
  {       // partition
    for (; _Gfirst < _Last; ++_Gfirst)
      if (_Pred(*_Pfirst, *_Gfirst))
        ;
      else if (_Pred(*_Gfirst, *_Pfirst))
        break;
      else
        _DLIB5 iter_swap(_Plast++, _Gfirst);
    for (; _First < _Glast; --_Glast)
      if (_Pred(*(_Glast - 1), *_Pfirst))
        ;
      else if (_Pred(*_Pfirst, *(_Glast - 1)))
        break;
      else
        _DLIB5 iter_swap(--_Pfirst, _Glast - 1);
    if (_Glast == _First && _Gfirst == _Last)
      return (pair<_RanIt, _RanIt>(_Pfirst, _Plast));

    if (_Glast == _First)
    {       // no room at bottom, rotate pivot upward
      if (_Plast != _Gfirst)
        _DLIB5 iter_swap(_Pfirst, _Plast);
      ++_Plast;
      _DLIB5 iter_swap(_Pfirst++, _Gfirst++);
    }
    else if (_Gfirst == _Last)
    {       // no room at top, rotate pivot downward
      if (--_Glast != --_Pfirst)
        _DLIB5 iter_swap(_Glast, _Pfirst);
      _DLIB5 iter_swap(_Pfirst, --_Plast);
    }
    else
      _DLIB5 iter_swap(_Gfirst++, --_Glast);
  }
}

#pragma basic_template_matching
template<class _RanIt,
         class _Diff,
         class _Pr> inline
void _Sort(_RanIt _First, _RanIt _Last, _Diff _Ideal, _Pr _Pred)
{       // order [_First, _Last), using _Pred
  _Diff _Count;
  for (; _ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal; )
  {       // divide and conquer by quicksort
    pair<_RanIt, _RanIt> _Mid =
      _DLIB5 _Unguarded_partition(_First, _Last, _Pred);
    _Ideal /= 2, _Ideal += _Ideal / 2;      // allow 1.5 log2(N) divisions

    if (_Mid.first - _First < _Last - _Mid.second)
    {       // loop on second half
      _DLIB5 _Sort(_First, _Mid.first, _Ideal, _Pred);
      _First = _Mid.second;
    }
    else
    {       // loop on first half
      _DLIB5 _Sort(_Mid.second, _Last, _Ideal, _Pred);
      _Last = _Mid.first;
    }
  }

  if (_ISORT_MAX < _Count)
  {       // heap sort if too many divisions
    _DLIB5 make_heap(_First, _Last, _Pred);
    _DLIB5 sort_heap(_First, _Last, _Pred);
  }
  else if (1 < _Count)
    _DLIB5 _Insertion_sort(_First, _Last, _Pred);     // small, insertion sort
}

#pragma basic_template_matching
template<class _RanIt,
         class _Pr> inline
void sort(_RanIt _First, _RanIt _Last, _Pr _Pred)
{       // order [_First, _Last), using _Pred
  _DLIB5 _Sort(_First, _Last, _Last - _First, _Pred);
}

// TEMPLATE FUNCTION stable_sort
template<class _BidIt,
         class _OutIt,
         class _Diff> inline
void _Chunked_merge(_BidIt _First, _BidIt _Last, _OutIt _Dest,
                    _Diff _Chunk, _Diff _Count)
{       // copy merging chunks, using operator<
  for (_Diff _Chunk2 = _Chunk * 2; _Chunk2 <= _Count; _Count -= _Chunk2)
  {       // copy merging pairs of adjacent chunks
    _BidIt _Mid1 = _First;
    _DLIB5 advance(_Mid1, _Chunk);
    _BidIt _Mid2 = _Mid1;
    _DLIB5 advance(_Mid2, _Chunk);

    _Dest = _DLIB5 merge(_First, _Mid1, _Mid1, _Mid2, _Dest);
    _First = _Mid2;
  }

  if (_Count <= _Chunk)
    _DLIB5 copy(_First, _Last, _Dest);        // copy partial last chunk
  else
  {       // copy merging whole and partial last chunk
    _BidIt _Mid = _First;
    _DLIB5 advance(_Mid, _Chunk);

    _DLIB5 merge(_First, _Mid, _Mid, _Last, _Dest);
  }
}

template<class _BidIt,
         class _Diff,
         class _Ty> inline
void _Buffered_merge_sort(_BidIt _First, _BidIt _Last, _Diff _Count,
                          _Temp_iterator<_Ty>& _Tempbuf)
{       // sort using temp buffer for merges, using operator<
  _BidIt _Mid = _First;
  for (_Diff _Nleft = _Count; _ISORT_MAX <= _Nleft; _Nleft -= _ISORT_MAX)
  {       // sort chunks
    _BidIt _Midend = _Mid;
    _DLIB5 advance(_Midend, (int)_ISORT_MAX);

    _DLIB5 _Insertion_sort(_Mid, _Midend);
    _Mid = _Midend;
  }
  _DLIB5 _Insertion_sort(_Mid, _Last);   // sort partial last chunk

  for (_Diff _Chunk = _ISORT_MAX; _Chunk < _Count; _Chunk *= 2)
  {       // merge adjacent pairs of chunks to and from temp buffer
    _DLIB5 _Chunked_merge(_First, _Last, _Tempbuf._Init(),
                        _Chunk, _Count);
    _DLIB5 _Chunked_merge(_Tempbuf._First(), _Tempbuf._Last(), _First,
                        _Chunk *= 2, _Count); 
  }
}

template<class _BidIt,
         class _Diff,
         class _Ty> inline
void _Stable_sort(_BidIt _First, _BidIt _Last, _Diff _Count,
                  _Temp_iterator<_Ty>& _Tempbuf)
{       //  sort preserving order of equivalents, using operator<
  if (_Count <= _ISORT_MAX)
    _DLIB5 _Insertion_sort(_First, _Last); // small, insertion sort
  else
  {       // sort halves and merge
    _Diff _Count2 = (_Count + 1) / 2;
    _BidIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    _Diff _CountDiff = _Count - _Count2;
    if (_Count2 <= _Tempbuf._Maxlen())
    {       // temp buffer big enough, sort each half using buffer
      _Buffered_merge_sort(_First, _Mid, _Count2, _Tempbuf);
      _Buffered_merge_sort(_Mid, _Last, _CountDiff, _Tempbuf);
    }
    else
    {       // temp buffer not big enough, divide and conquer
      _Stable_sort(_First, _Mid, _Count2, _Tempbuf);
      _Stable_sort(_Mid, _Last, _CountDiff, _Tempbuf);
    }

    _Buffered_merge(_First, _Mid, _Last,
                    _Count2, _CountDiff, _Tempbuf);// merge sorted halves
  }
}        

template<class _BidIt,
         class _Diff,
         class _Ty> inline
void _Stable_sort(_BidIt _First, _BidIt _Last, _Diff *, _Ty *)
{       // sort preserving order of equivalents, using operator<
  _Diff _Count = distance(_First, _Last);
  _Temp_iterator<_Ty> _Tempbuf((_Count + 1) / 2);
  _Stable_sort(_First, _Last, _Count, _Tempbuf);
}

template<class _BidIt> inline
void stable_sort(_BidIt _First, _BidIt _Last)
{       // sort preserving order of equivalents, using operator<
  if (_First != _Last)
    _Stable_sort(_First, _Last, _Dist_type(_First), _Val_type(_First));
}

// TEMPLATE FUNCTION stable_sort WITH PRED
template<class _BidIt,
         class _OutIt,
         class _Diff,
         class _Pr> inline
void _Chunked_merge(_BidIt _First, _BidIt _Last, _OutIt _Dest,
                    _Diff _Chunk, _Diff _Count, _Pr _Pred)
{       // copy merging chunks, using _Pred
  for (_Diff _Chunk2 = _Chunk * 2; _Chunk2 <= _Count; _Count -= _Chunk2)
  {       // copy merging pairs of adjacent chunks
    _BidIt _Mid1 = _First;
    _DLIB5 advance(_Mid1, _Chunk);
    _BidIt _Mid2 = _Mid1;
    _DLIB5 advance(_Mid2, _Chunk);

    _Dest = _DLIB5 merge(_First, _Mid1, _Mid1, _Mid2, _Dest, _Pred);
    _First = _Mid2;
  }

  if (_Count <= _Chunk)
    _DLIB5 copy(_First, _Last, _Dest);        // copy partial last chunk
  else
  {       // copy merging whole and partial last chunk
    _BidIt _Mid1 = _First;
    _DLIB5 advance(_Mid1, _Chunk);

    _DLIB5 merge(_First, _Mid1, _Mid1, _Last, _Dest, _Pred);
  }
}

template<class _BidIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Buffered_merge_sort(_BidIt _First, _BidIt _Last, _Diff _Count,
                          _Temp_iterator<_Ty>& _Tempbuf, _Pr _Pred)
{       // sort using temp buffer for merges, using _Pred
  _BidIt _Mid = _First;
  for (_Diff _Nleft = _Count; _ISORT_MAX <= _Nleft; _Nleft -= _ISORT_MAX)
  {       // sort chunks
    _BidIt _Midn = _Mid;
    _DLIB5 advance(_Midn, (int)_ISORT_MAX);

    _DLIB5 _Insertion_sort(_Mid, _Midn, _Pred);
    _Mid = _Midn;
  }
  _DLIB5 _Insertion_sort(_Mid, _Last, _Pred);    // sort partial last chunk

  for (_Diff _Chunk = _ISORT_MAX; _Chunk < _Count; _Chunk *= 2)
  {       // merge adjacent pairs of chunks to and from temp buffer
    _DLIB5 _Chunked_merge(_First, _Last, _Tempbuf._Init(),
                        _Chunk, _Count, _Pred);
    _DLIB5 _Chunked_merge(_Tempbuf._First(), _Tempbuf._Last(), _First,
                        _Chunk *= 2, _Count, _Pred);
  }
}

template<class _BidIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Stable_sort(_BidIt _First, _BidIt _Last, _Diff _Count,
                  _Temp_iterator<_Ty>& _Tempbuf, _Pr _Pred)
{       // sort preserving order of equivalents, using _Pred
  if (_Count <= _ISORT_MAX)
    _DLIB5 _Insertion_sort(_First, _Last, _Pred);  // small, insertion sort
  else
  {       // sort halves and merge
    _Diff _Count2 = (_Count + 1) / 2;
    _BidIt _Mid = _First;
    _DLIB5 advance(_Mid, _Count2);

    _Diff _CountDiff = _Count - _Count2;
    if (_Count2 <= _Tempbuf._Maxlen())
    {       // temp buffer big enough, sort each half using buffer
      _Buffered_merge_sort(_First, _Mid, _Count2, _Tempbuf, _Pred);
      _Buffered_merge_sort(_Mid, _Last, _CountDiff,
                           _Tempbuf, _Pred);
    }
    else
    {       // temp buffer not big enough, divide and conquer
      _Stable_sort(_First, _Mid, _Count2, _Tempbuf, _Pred);
      _Stable_sort(_Mid, _Last, _CountDiff, _Tempbuf, _Pred);
    }

    _Buffered_merge(_First, _Mid, _Last,
                    _Count2, _CountDiff, _Tempbuf, _Pred);// merge halves
  }
} 

template<class _BidIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
void _Stable_sort(_BidIt _First, _BidIt _Last, _Diff *, _Ty *, _Pr _Pred)
{       // sort preserving order of equivalents, using _Pred
  _Diff _Count = distance(_First, _Last);
  _Temp_iterator<_Ty> _Tempbuf((_Count + 1) / 2);
  _Stable_sort(_First, _Last, _Count, _Tempbuf, _Pred);
}

template<class _BidIt,
         class _Pr> inline
void stable_sort(_BidIt _First, _BidIt _Last, _Pr _Pred)
{       // sort preserving order of equivalents, using _Pred
  if (_First != _Last)
    _Stable_sort(_First, _Last,
                 _Dist_type(_First), _Val_type(_First), _Pred);
}

// TEMPLATE FUNCTION partial_sort
template<class _RanIt,
         class _Ty> inline
void _Partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Ty *)
{       // order [First, _Last) up to _Mid, using operator<
  _DLIB5 make_heap(_First, _Mid);

  // IAR memory support
  typename _ClassUtil::_TmpHolder<_Ty>::_Type _Val;
  for (_RanIt _Next = _Mid; _Next < _Last; ++_Next)
    if (*_Next < *_First)
    {
      _Val = *_Next;                            // IAR memory support
      _Pop_heap(_First, _Mid, _Next, _Val,      // IAR memory support
                _Dist_type(_First));    // replace top with new largest
    }
  _DLIB5 sort_heap(_First, _Mid); 
}

template<class _RanIt> inline
void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last)
{       // order [First, _Last) up to _Mid, using operator<
  _Partial_sort(_First, _Mid, _Last, _Val_type(_First));
}

// TEMPLATE FUNCTION partial_sort WITH PRED
template<class _RanIt,
         class _Ty,
         class _Pr> inline
void _Partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last,
                   _Pr _Pred, _Ty *)
{       // order [First, _Last) up to _Mid, using _Pred
  _DLIB5 make_heap(_First, _Mid, _Pred);

  for (_RanIt _Next = _Mid; _Next < _Last; ++_Next)
    if (_Pred(*_Next, *_First))
      _Pop_heap(_First, _Mid, _Next, _Ty(*_Next), _Pred,
                _Dist_type(_First));    // replace top with new largest
  _DLIB5 sort_heap(_First, _Mid, _Pred);
}

template<class _RanIt,
         class _Pr> inline
void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred)
{       // order [First, _Last) up to _Mid, using _Pred
  _Partial_sort(_First, _Mid, _Last, _Pred, _Val_type(_First));
}

// TEMPLATE FUNCTION partial_sort_copy
template<class _InIt,
         class _RanIt,
         class _Diff,
         class _Ty> inline
_RanIt _Partial_sort_copy(_InIt _First1, _InIt _Last1,
                          _RanIt _First2, _RanIt _Last2, _Diff *, _Ty *)
{       // copy [First1, _Last1) into [_First2, _Last2), using operator<
  _RanIt _Mid2 = _First2;
  for (; _First1 != _Last1 && _Mid2 != _Last2; ++_First1, ++_Mid2)
    *_Mid2 = *_First1;      // copy min(_Last1 - _First1, _Last2 - _First2)
  _DLIB5 make_heap(_First2, _Mid2);

  for (; _First1 != _Last1; ++_First1)
    if (*_First1 < *_First2)
      _DLIB5 _Adjust_heap(_First2, _Diff(0), _Diff(_Mid2 - _First2),
                        // IAR memory support
                        typename _ClassUtil::_TmpHolder<_Ty>::_Type(*_First1));
                                       // replace top with new largest

  _DLIB5 sort_heap(_First2, _Mid2);
  return (_Mid2);
}

template<class _InIt,
         class _RanIt> inline
_RanIt partial_sort_copy(_InIt _First1, _InIt _Last1,
                         _RanIt _First2, _RanIt _Last2)
{       // copy [First1, _Last1) into [_First2, _Last2), using operator<
  return (_First1 == _Last1 || _First2 == _Last2 ? _First2
          : _Partial_sort_copy(_First1, _Last1, _First2, _Last2,
                               _Dist_type(_First2), _Val_type(_First1)));
}

// TEMPLATE FUNCTION partial_sort_copy WITH PRED
template<class _InIt,
         class _RanIt,
         class _Diff,
         class _Ty,
         class _Pr> inline
_RanIt _Partial_sort_copy(_InIt _First1, _InIt _Last1,
                          _RanIt _First2, _RanIt _Last2, _Pr _Pred, 
                          _Diff *, _Ty *)
{       // copy [First1, _Last1) into [_First2, _Last2) using _Pred
  _RanIt _Mid2 = _First2;
  for (; _First1 != _Last1 && _Mid2 != _Last2; ++_First1, ++_Mid2)
    *_Mid2 = *_First1;      // copy min(_Last1 - _First1, _Last2 - _First2)
  _DLIB5 make_heap(_First2, _Mid2, _Pred);

  for (; _First1 != _Last1; ++_First1)
    if (_Pred(*_First1, *_First2))
      _DLIB5 _Adjust_heap(_First2, _Diff(0), _Diff(_Mid2 - _First2),
                        // IAR memory support
                        typename _ClassUtil::_TmpHolder<_Ty>::_Type(*_First1),
                        _Pred);  // replace top with new largest

  _DLIB5 sort_heap(_First2, _Mid2, _Pred);
  return (_Mid2);
}

template<class _InIt,
         class _RanIt,
         class _Pr> inline
_RanIt partial_sort_copy(_InIt _First1, _InIt _Last1,
                         _RanIt _First2, _RanIt _Last2, _Pr _Pred)
{       // copy [First1, _Last1) into [_First2, _Last2) using _Pred
  return (_First1 == _Last1 || _First2 == _Last2 ? _First2
          : _Partial_sort_copy(_First1, _Last1, _First2, _Last2, _Pred,
                               _Dist_type(_First2), _Val_type(_First1)));
}

// TEMPLATE FUNCTION nth_element
template<class _RanIt> inline
void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last)
{       // order Nth element, using operator<
  for (; _ISORT_MAX < _Last - _First; )
  {       // divide and conquer, ordering partition containing Nth
    pair<_RanIt, _RanIt> _Mid =
      _DLIB5 _Unguarded_partition(_First, _Last);

    if (_Mid.second <= _Nth)
      _First = _Mid.second;
    else if (_Mid.first <= _Nth)
      return; // Nth inside fat pivot, done
    else
      _Last = _Mid.first;
  }

  _DLIB5 _Insertion_sort(_First, _Last);    // sort any remainder
}

// TEMPLATE FUNCTION nth_element WITH PRED
template<class _RanIt,
         class _Pr> inline
void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _Pred)
{       // order Nth element, using _Pred
  for (; _ISORT_MAX < _Last - _First; )
  {       // divide and conquer, ordering partition containing Nth
    pair<_RanIt, _RanIt> _Mid =
      _DLIB5 _Unguarded_partition(_First, _Last, _Pred);

    if (_Mid.second <= _Nth)
      _First = _Mid.second;
    else if (_Mid.first <= _Nth)
      return; // Nth inside fat pivot, done
    else
      _Last = _Mid.first;
  }

  _DLIB5 _Insertion_sort(_First, _Last, _Pred);     // sort any remainder
}

// TEMPLATE FUNCTION includes
template<class _InIt1,
         class _InIt2> inline
bool includes(_InIt1 _First1, _InIt1 _Last1,
              _InIt2 _First2, _InIt2 _Last2)
{       // test if all [_First1, _Last1) in [_First2, _Last2), using operator<
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (*_First2 < *_First1)
      return (false);
    else if (*_First1 < *_First2)
      ++_First1;
    else
      ++_First1, ++_First2;
  return (_First2 == _Last2);
}

// TEMPLATE FUNCTION includes WITH PRED
template<class _InIt1,
         class _InIt2,
         class _Pr> inline
bool includes(_InIt1 _First1, _InIt1 _Last1,
              _InIt2 _First2, _InIt2 _Last2, _Pr _Pred)
{       // test if set [_First1, _Last1) in [_First2, _Last2), using _Pred
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (_Pred(*_First2, *_First1))
      return (false);
    else if (_Pred(*_First1, *_First2))
      ++_First1;
    else
      ++_First1, ++_First2;
  return (_First2 == _Last2);
}

// TEMPLATE FUNCTION set_union
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt> inline
_OutIt set_union(_InIt1 _First1, _InIt1 _Last1,
                 _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
{       // OR sets [_First1, _Last1) and [_First2, _Last2), using operator<
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (*_First1 < *_First2)
      *_Dest++ = *_First1, ++_First1;
    else if (*_First2 < *_First1)
      *_Dest++ = *_First2, ++_First2;
    else
      *_Dest++ = *_First1, ++_First1, ++_First2;
  _Dest = _DLIB5 copy(_First1, _Last1, _Dest);
  return (_DLIB5 copy(_First2, _Last2, _Dest));
}

// TEMPLATE FUNCTION set_union WITH PRED
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt,
         class _Pr> inline
_OutIt set_union(_InIt1 _First1, _InIt1 _Last1,
                 _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred)
{       // OR sets [_First1, _Last1) and [_First2, _Last2), using _Pred
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (_Pred(*_First1, *_First2))
      *_Dest++ = *_First1, ++_First1;
    else if (_Pred(*_First2, *_First1))
      *_Dest++ = *_First2, ++_First2;
    else
      *_Dest++ = *_First1, ++_First1, ++_First2;
  _Dest = _DLIB5 copy(_First1, _Last1, _Dest);
  return (_DLIB5 copy(_First2, _Last2, _Dest));
}

// TEMPLATE FUNCTION set_intersection
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt> inline
_OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1,
                        _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
{       // AND sets [_First1, _Last1) and [_First2, _Last2), using operator<
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (*_First1 < *_First2)
      ++_First1;
    else if (*_First2 < *_First1)
      ++_First2;
    else
      *_Dest++ = *_First1++, ++_First2;
  return (_Dest);
}

// TEMPLATE FUNCTION set_intersection WITH PRED
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt,
         class _Pr> inline
_OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1,
                        _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred)
{       // AND sets [_First1, _Last1) and [_First2, _Last2), using _Pred
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (_Pred(*_First1, *_First2))
      ++_First1;
    else if (_Pred(*_First2, *_First1))
      ++_First2;
    else
      *_Dest++ = *_First1++, ++_First2;
  return (_Dest);
}

// TEMPLATE FUNCTION set_difference
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt> inline
_OutIt set_difference(_InIt1 _First1, _InIt1 _Last1,
                      _InIt2 _First2, _InIt2 _Last2,  _OutIt _Dest)
{       // take set [_First2, _Last2) from [_First1, _Last1), using operator<
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (*_First1 < *_First2)
      *_Dest++ = *_First1, ++_First1;
    else if (*_First2 < *_First1)
      ++_First2;
    else
      ++_First1, ++_First2;
  return (_DLIB5 copy(_First1, _Last1, _Dest));
}

// TEMPLATE FUNCTION set_difference WITH PRED
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt,
         class _Pr> inline
_OutIt set_difference(_InIt1 _First1, _InIt1 _Last1,
                      _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred)
{       //  take set [_First2, _Last2) from [_First1, _Last1), using _Pred
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (_Pred(*_First1, *_First2))
      *_Dest++ = *_First1, ++_First1;
    else if (_Pred(*_First2, *_First1))
      ++_First2;
    else
      ++_First1, ++_First2;
  return (_DLIB5 copy(_First1, _Last1, _Dest));
}

// TEMPLATE FUNCTION set_symmetric_difference
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt> inline
_OutIt set_symmetric_difference(_InIt1 _First1, _InIt1 _Last1,
                                _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
{       // XOR sets [_First1, _Last1) and [_First2, _Last2), using operator<
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (*_First1 < *_First2)
      *_Dest++ = *_First1, ++_First1;
    else if (*_First2 < *_First1)
      *_Dest++ = *_First2, ++_First2;
    else
      ++_First1, ++_First2;
  _Dest = _DLIB5 copy(_First1, _Last1, _Dest);
  return (_DLIB5 copy(_First2, _Last2, _Dest));
}

// TEMPLATE FUNCTION set_symmetric_difference WITH PRED
#pragma basic_template_matching
template<class _InIt1,
         class _InIt2,
         class _OutIt,
         class _Pr> inline
_OutIt set_symmetric_difference(_InIt1 _First1, _InIt1 _Last1,
                                _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, 
                                _Pr _Pred)
{       // XOR sets [_First1, _Last1) and [_First2, _Last2), using _Pred
  for (; _First1 != _Last1 && _First2 != _Last2; )
    if (_Pred(*_First1, *_First2))
      *_Dest++ = *_First1, ++_First1;
    else if (_Pred(*_First2, *_First1))
      *_Dest++ = *_First2, ++_First2;
    else
      ++_First1, ++_First2;
  _Dest = _DLIB5 copy(_First1, _Last1, _Dest);
  return (_DLIB5 copy(_First2, _Last2, _Dest));
}

// TEMPLATE FUNCTION max_element
#pragma basic_template_matching
template<class _FwdIt> inline
_FwdIt max_element(_FwdIt _First, _FwdIt _Last)
{       // find largest element, using operator<
  _FwdIt _Found = _First;
  if (_First != _Last)
    for (; ++_First != _Last; )
      if (*_Found < *_First)
        _Found = _First;
  return (_Found);
}

// TEMPLATE FUNCTION max_element WITH PRED
#pragma basic_template_matching
template<class _FwdIt,
         class _Pr> inline
_FwdIt max_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{       // find largest element, using _Pred
  _FwdIt _Found = _First;
  if (_First != _Last)
    for (; ++_First != _Last; )
      if (_Pred(*_Found, *_First))
        _Found = _First;
  return (_Found);
}

// TEMPLATE FUNCTION min_element
#pragma basic_template_matching
template<class _FwdIt> inline
_FwdIt min_element(_FwdIt _First, _FwdIt _Last)
{       // find smallest element, using operator<
  _FwdIt _Found = _First;
  if (_First != _Last)
    for (; ++_First != _Last; )
      if (*_First < *_Found)
        _Found = _First;
  return (_Found);
}

// TEMPLATE FUNCTION min_element WITH PRED
#pragma basic_template_matching
template<class _FwdIt,
         class _Pr> inline
_FwdIt min_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred)
{       // find smallest element, using _Pred
  _FwdIt _Found = _First;
  if (_First != _Last)
    for (; ++_First != _Last; )
      if (_Pred(*_First, *_Found))
        _Found = _First;
  return (_Found);
}

// TEMPLATE FUNCTION next_permutation
template<class _BidIt> inline
bool next_permutation(_BidIt _First, _BidIt _Last)
{       // permute and test for pure ascending, using operator<
  _BidIt _Next = _Last;
  if (_First == _Last || _First == --_Next)
    return (false);

  for (; ; )
  {       // find rightmost element smaller than successor
    _BidIt _Next1 = _Next;
    if (*--_Next < *_Next1)
    {       // swap with rightmost element that's smaller, flip suffix
      _BidIt _Mid = _Last;
      for (; !(*_Next < *--_Mid); )
        ;
      _DLIB5 iter_swap(_Next, _Mid);
      _DLIB5 reverse(_Next1, _Last);
      return (true);
    }

    if (_Next == _First)
    {       // pure descending, flip all
      _DLIB5 reverse(_First, _Last);
      return (false);
    }
  }
}

// TEMPLATE FUNCTION next_permutation WITH PRED
template<class _BidIt,
         class _Pr> inline
bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred)
{       // permute and test for pure ascending, using _Pred
  _BidIt _Next = _Last;
  if (_First == _Last || _First == --_Next)
    return (false);

  for (; ; )
  {       // find rightmost element smaller than successor
    _BidIt _Next1 = _Next;
    if (_Pred(*--_Next, *_Next1))
    {       // swap with rightmost element that's smaller, flip suffix
      _BidIt _Mid = _Last;
      for (; !_Pred(*_Next, *--_Mid); )
        ;
      _DLIB5 iter_swap(_Next, _Mid);
      _DLIB5 reverse(_Next1, _Last);
      return (true);
    }

    if (_Next == _First)
    {       // pure descending, flip all
      _DLIB5 reverse(_First, _Last);
      return (false);
    }
  }
}

// TEMPLATE FUNCTION prev_permutation
template<class _BidIt> inline
bool prev_permutation(_BidIt _First, _BidIt _Last)
{       // reverse permute and test for pure descending, using operator<
  _BidIt _Next = _Last;
  if (_First == _Last || _First == --_Next)
    return (false);
  for (; ; )
  {       // find rightmost element not smaller than successor
    _BidIt _Next1 = _Next;
    if (!(*--_Next < *_Next1))
    {       // swap with rightmost element that's not smaller, flip suffix
      _BidIt _Mid = _Last;
      for (; !(*--_Mid < *_Next); )
        ;
      _DLIB5 iter_swap(_Next, _Mid);
      _DLIB5 reverse(_Next1, _Last);
      return (true);
    }

    if (_Next == _First)
    {       // pure ascending, flip all
      _DLIB5 reverse(_First, _Last);
      return (false);
    }
  }
}

// TEMPLATE FUNCTION prev_permutation WITH PRED
template<class _BidIt,
         class _Pr> inline
bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred)
{       // reverse permute and test for pure descending, using _Pred
  _BidIt _Next = _Last;
  if (_First == _Last || _First == --_Next)
    return (false);

  for (; ; )
  {       // find rightmost element not smaller than successor
    _BidIt _Next1 = _Next;
    if (_Pred(*_Next1, *--_Next))
    {       // swap with rightmost element that's not smaller, flip suffix
      _BidIt _Mid = _Last;
      for (; !_Pred(*--_Mid, *_Next); )
        ;
      _DLIB5 iter_swap(_Next, _Mid);
      _DLIB5 reverse(_Next1, _Last);
      return (true);
    }

    if (_Next == _First)
    {       // pure ascending, flip all
      _DLIB5 reverse(_First, _Last);
      return (false);
    }
  }
}

_DLIB5_END
#endif /* _ALGORITHM_ */

/*
 * This file is derived from software bearing the following
 * restrictions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Permission to use, copy, modify, distribute and sell this
 * software and its documentation for any purpose is hereby
 * granted without fee, provided that the above copyright notice
 * appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation.
 * Hewlett-Packard Company makes no representations about the
 * suitability of this software for any purpose. It is provided
 * "as is" without express or implied warranty.
 */

/*
 * Copyright (c) 1992-2009 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
 V5.04:0576 */

