зеркало из https://github.com/microsoft/STL.git
4824 строки
203 KiB
C++
4824 строки
203 KiB
C++
// algorithm standard header
|
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#pragma once
|
|
#ifndef _ALGORITHM_
|
|
#define _ALGORITHM_
|
|
#include <yvals_core.h>
|
|
#if _STL_COMPILER_PREPROCESSOR
|
|
#include <xmemory>
|
|
|
|
#pragma pack(push, _CRT_PACKING)
|
|
#pragma warning(push, _STL_WARNING_LEVEL)
|
|
#pragma warning(disable : _STL_DISABLED_WARNINGS)
|
|
_STL_DISABLE_CLANG_WARNINGS
|
|
#pragma push_macro("new")
|
|
#undef new
|
|
|
|
#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID)
|
|
_EXTERN_C
|
|
// See note about "noalias" in <xutility>
|
|
__declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias(
|
|
void* _First1, void* _Last1, void* _First2) noexcept;
|
|
_END_EXTERN_C
|
|
#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID)
|
|
|
|
_STD_BEGIN
|
|
// COMMON SORT PARAMETERS
|
|
_INLINE_VAR constexpr int _ISORT_MAX = 32; // maximum size for insertion sort
|
|
|
|
// STRUCT TEMPLATE _Optimistic_temporary_buffer
|
|
template <class _Diff>
|
|
constexpr ptrdiff_t _Temporary_buffer_size(const _Diff _Value) noexcept {
|
|
// convert an iterator difference_type to a ptrdiff_t for use in temporary buffers
|
|
using _CT = common_type_t<ptrdiff_t, _Diff>;
|
|
return static_cast<ptrdiff_t>(_Min_value(static_cast<_CT>(PTRDIFF_MAX), static_cast<_CT>(_Value)));
|
|
}
|
|
|
|
template <class _Ty>
|
|
struct _Optimistic_temporary_buffer { // temporary storage with _alloca-like attempt
|
|
static constexpr size_t _Optimistic_size = 4096; // default to ~1 page
|
|
static constexpr size_t _Optimistic_count = _Max_value(static_cast<size_t>(1), _Optimistic_size / sizeof(_Ty));
|
|
|
|
template <class _Diff>
|
|
explicit _Optimistic_temporary_buffer(const _Diff _Requested_size) noexcept { // get temporary storage
|
|
const auto _Attempt = _Temporary_buffer_size(_Requested_size);
|
|
// Since _Diff is a count of elements in a forward range, and forward iterators must denote objects in memory,
|
|
// it must fit in a size_t.
|
|
if (static_cast<size_t>(_Requested_size) <= _Optimistic_count) { // unconditionally engage stack space
|
|
_Data = reinterpret_cast<_Ty*>(&_Stack_space[0]);
|
|
_Capacity = static_cast<ptrdiff_t>(_Requested_size); // in bounds due to if condition
|
|
return;
|
|
}
|
|
|
|
const pair<_Ty*, ptrdiff_t> _Raw = _Get_temporary_buffer<_Ty>(_Attempt);
|
|
if (_Raw.second > _Optimistic_count) { // engage heap space
|
|
_Data = _Raw.first;
|
|
_Capacity = _Raw.second;
|
|
return;
|
|
}
|
|
|
|
// less heap space than stack space, give up and use stack instead
|
|
_Return_temporary_buffer(_Raw.first);
|
|
_Data = reinterpret_cast<_Ty*>(&_Stack_space[0]);
|
|
_Capacity = _Optimistic_count;
|
|
}
|
|
|
|
_Optimistic_temporary_buffer(const _Optimistic_temporary_buffer&) = delete;
|
|
_Optimistic_temporary_buffer& operator=(const _Optimistic_temporary_buffer&) = delete;
|
|
|
|
~_Optimistic_temporary_buffer() noexcept {
|
|
if (_Capacity > _Optimistic_count) {
|
|
_Return_temporary_buffer(_Data);
|
|
}
|
|
}
|
|
|
|
_Ty* _Data; // points to heap memory iff _Capacity > _Optimistic_count
|
|
ptrdiff_t _Capacity;
|
|
aligned_union_t<0, _Ty> _Stack_space[_Optimistic_count];
|
|
};
|
|
|
|
// FUNCTION TEMPLATE for_each
|
|
template <class _InIt, class _Fn>
|
|
_CONSTEXPR20 _Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last)
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
_Func(*_UFirst);
|
|
}
|
|
|
|
return _Func;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Fn, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void for_each(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Fn _Func) noexcept; // terminates
|
|
|
|
// FUNCTION TEMPLATE for_each_n
|
|
template <class _InIt, class _Diff, class _Fn>
|
|
_CONSTEXPR20 _InIt for_each_n(_InIt _First, const _Diff _Count_raw, _Fn _Func) {
|
|
// perform function for each element [_First, _First + _Count)
|
|
_Algorithm_int_t<_Diff> _Count = _Count_raw;
|
|
if (0 < _Count) {
|
|
auto _UFirst = _Get_unwrapped_n(_First, _Count);
|
|
do {
|
|
_Func(*_UFirst);
|
|
--_Count;
|
|
++_UFirst;
|
|
} while (0 < _Count);
|
|
|
|
_Seek_wrapped(_First, _UFirst);
|
|
}
|
|
|
|
return _First;
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, class _Diff, class _Fn, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt for_each_n(_ExPo&& _Exec, _FwdIt _First, _Diff _Count_raw, _Fn _Func) noexcept; // terminates
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InTy, size_t _InSize, class _Diff, class _Fn>
|
|
_CONSTEXPR20 _InTy* for_each_n(_InTy (&_First)[_InSize], const _Diff _Count_raw, _Fn _Func) {
|
|
// perform function for each element [_First, _First + _Count)
|
|
_Algorithm_int_t<_Diff> _Count = _Count_raw;
|
|
_STL_VERIFY_ARRAY_SIZE(_First, _Count);
|
|
_InTy* _UFirst = _First;
|
|
for (; 0 < _Count; --_Count, (void) ++_UFirst) {
|
|
_Func(*_UFirst);
|
|
}
|
|
|
|
return _UFirst;
|
|
}
|
|
|
|
template <class _ExPo, class _SourceTy, size_t _SourceSize, class _Diff, class _Fn,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_SourceTy* for_each_n(
|
|
_ExPo&& _Exec, _SourceTy (&_First)[_SourceSize], _Diff _Count_raw, _Fn _Func) noexcept; // terminates
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
#if _HAS_CXX17
|
|
// PARALLEL FUNCTION TEMPLATE find_if
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE find_if_not
|
|
template <class _InIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _InIt find_if_not(_InIt _First, const _InIt _Last, _Pr _Pred) {
|
|
// find first element that satisfies !_Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (!_Pred(*_UFirst)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First, _UFirst);
|
|
return _First;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt find_if_not(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE adjacent_find
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
|
// find first satisfying _Pred with successor
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
auto _ULast = _Get_unwrapped(_Last);
|
|
if (_UFirst != _ULast) {
|
|
for (auto _UNext = _UFirst; ++_UNext != _ULast; _UFirst = _UNext) {
|
|
if (_Pred(*_UFirst, *_UNext)) {
|
|
_ULast = _UFirst;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Last, _ULast);
|
|
return _Last;
|
|
}
|
|
|
|
template <class _FwdIt>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, const _FwdIt _Last) { // find first matching successor
|
|
return _STD adjacent_find(_First, _Last, equal_to<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt adjacent_find(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt adjacent_find(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last) noexcept /* terminates */ {
|
|
// find first matching successor
|
|
return _STD adjacent_find(_STD forward<_ExPo>(_Exec), _First, _Last, equal_to<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE count_if
|
|
template <class _InIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> count_if(_InIt _First, _InIt _Last, _Pr _Pred) {
|
|
// count elements satisfying _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
_Iter_diff_t<_InIt> _Count = 0;
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (_Pred(*_UFirst)) {
|
|
++_Count;
|
|
}
|
|
}
|
|
|
|
return _Count;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _Iter_diff_t<_FwdIt> count_if(
|
|
_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE mismatch
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _Pr _Pred) {
|
|
// return [_First1, _Last1)/[_First2, ...) mismatch using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_InIt1>(_UFirst1, _ULast1));
|
|
while (_UFirst1 != _ULast1 && _Pred(*_UFirst1, *_UFirst2)) {
|
|
++_UFirst1;
|
|
++_UFirst2;
|
|
}
|
|
|
|
_Seek_wrapped(_First2, _UFirst2);
|
|
_Seek_wrapped(_First1, _UFirst1);
|
|
return {_First1, _First2};
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _RightTy, size_t _RightSize, class _Pr, enable_if_t<!is_same_v<_RightTy*, _Pr>, int> = 0>
|
|
_NODISCARD _CONSTEXPR20 pair<_InIt1, _RightTy*> mismatch(
|
|
const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], _Pr _Pred) {
|
|
// return [_First1, _Last1)/[_First2, ...) mismatch using _Pred
|
|
const auto _Result =
|
|
_STD mismatch(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Pass_fn(_Pred));
|
|
return {_Result.first, _Result.second._Unwrapped()};
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD pair<_FwdIt1, _FwdIt2> mismatch(
|
|
_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) noexcept; // terminates
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _RightTy, size_t _RightSize, class _Pr,
|
|
enable_if_t<is_execution_policy_v<decay_t<_ExPo>> && !is_same_v<_RightTy*, _Pr>, int> = 0>
|
|
_NODISCARD pair<_FwdIt1, _RightTy*> mismatch(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1,
|
|
_RightTy (&_First2)[_RightSize], _Pr _Pred) { // return [_First1, _Last1)/[_First2, ...) mismatch using _Pred
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
const auto _Result = _STD mismatch(
|
|
_STD forward<_ExPo>(_Exec), _First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Pass_fn(_Pred));
|
|
return {_Result.first, _Result.second._Unwrapped()};
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
template <class _InIt1, class _InIt2>
|
|
_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2) {
|
|
// return [_First1, _Last1)/[_First2, ...) mismatch
|
|
return _STD mismatch(_First1, _Last1, _First2, equal_to<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _RightTy, size_t _RightSize>
|
|
_NODISCARD _CONSTEXPR20 pair<_InIt1, _RightTy*> mismatch(
|
|
const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize]) {
|
|
// return [_First1, _Last1)/[_First2, ...) mismatch, array source
|
|
return _STD mismatch(_First1, _Last1, _First2, equal_to<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD pair<_FwdIt1, _FwdIt2> mismatch(
|
|
_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2) noexcept /* terminates */ {
|
|
// return [_First1, _Last1)/[_First2, ...) mismatch
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, equal_to<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _RightTy, size_t _RightSize, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD pair<_FwdIt1, _RightTy*> mismatch(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1,
|
|
_RightTy (&_First2)[_RightSize]) noexcept /* terminates */ {
|
|
// return [_First1, _Last1)/[_First2, ...) mismatch, array source
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, equal_to<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
#if _HAS_IF_CONSTEXPR
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) {
|
|
// return [_First1, _Last1)/[_First2, _Last2) mismatch using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
if constexpr (_Is_random_iter_v<_InIt1> && _Is_random_iter_v<_InIt2>) {
|
|
using _CT = _Common_diff_t<_InIt1, _InIt2>;
|
|
const _CT _Count1 = _ULast1 - _UFirst1;
|
|
const _CT _Count2 = _ULast2 - _UFirst2;
|
|
const auto _Count = static_cast<_Iter_diff_t<_InIt1>>(_Min_value(_Count1, _Count2));
|
|
_ULast1 = _UFirst1 + _Count;
|
|
while (_UFirst1 != _ULast1 && _Pred(*_UFirst1, *_UFirst2)) {
|
|
++_UFirst1;
|
|
++_UFirst2;
|
|
}
|
|
} else {
|
|
while (_UFirst1 != _ULast1 && _UFirst2 != _ULast2 && _Pred(*_UFirst1, *_UFirst2)) {
|
|
++_UFirst1;
|
|
++_UFirst2;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First2, _UFirst2);
|
|
_Seek_wrapped(_First1, _UFirst1);
|
|
return {_First1, _First2};
|
|
}
|
|
#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
pair<_InIt1, _InIt2> _Mismatch_unchecked(_InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, const _InIt2 _Last2,
|
|
_Pr _Pred, input_iterator_tag, input_iterator_tag) {
|
|
// return [_First1, _Last1)/[_First2, _Last2) mismatch using _Pred, no special optimization
|
|
while (_First1 != _Last1 && _First2 != _Last2 && _Pred(*_First1, *_First2)) {
|
|
++_First1;
|
|
++_First2;
|
|
}
|
|
|
|
return {_First1, _First2};
|
|
}
|
|
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
pair<_InIt1, _InIt2> _Mismatch_unchecked(const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2,
|
|
const _InIt2 _Last2, _Pr _Pred, random_access_iterator_tag, random_access_iterator_tag) {
|
|
// return [_First1, _Last1)/[_First2, _Last2) mismatch using _Pred, random-access iterators
|
|
using _CT = _Common_diff_t<_InIt1, _InIt2>;
|
|
const _CT _Count1 = _Last1 - _First1;
|
|
const _CT _Count2 = _Last2 - _First2;
|
|
const auto _Count = static_cast<_Iter_diff_t<_InIt1>>(_Min_value(_Count1, _Count2));
|
|
return _STD mismatch(_First1, _First1 + _Count, _First2, _Pred);
|
|
}
|
|
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
_NODISCARD pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) {
|
|
// return [_First1, _Last1)/[_First2, _Last2) mismatch using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
const auto _Result = _Mismatch_unchecked(_Get_unwrapped(_First1), _Get_unwrapped(_Last1), _Get_unwrapped(_First2),
|
|
_Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_InIt1>(), _Iter_cat_t<_InIt2>());
|
|
_Seek_wrapped(_First2, _Result.second);
|
|
_Seek_wrapped(_First1, _Result.first);
|
|
return {_First1, _First2};
|
|
}
|
|
#endif // _HAS_IF_CONSTEXPR
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD pair<_FwdIt1, _FwdIt2> mismatch(
|
|
_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
template <class _InIt1, class _InIt2>
|
|
_NODISCARD _CONSTEXPR20 pair<_InIt1, _InIt2> mismatch(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) {
|
|
// return [_First1, _Last1)/[_First2, _Last2) mismatch
|
|
return _STD mismatch(_First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD pair<_FwdIt1, _FwdIt2> mismatch(
|
|
_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) noexcept /* terminates */ {
|
|
// return [_First1, _Last1)/[_First2, _Last2) mismatch
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD mismatch(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE all_of
|
|
template <class _InIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool all_of(_InIt _First, _InIt _Last, _Pr _Pred) { // test if all elements satisfy _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (!_Pred(*_UFirst)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool all_of(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE any_of
|
|
template <class _InIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool any_of(const _InIt _First, const _InIt _Last, _Pr _Pred) {
|
|
// test if any element satisfies _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (_Pred(*_UFirst)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool any_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE none_of
|
|
template <class _InIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool none_of(const _InIt _First, const _InIt _Last, _Pr _Pred) {
|
|
// test if no elements satisfy _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (_Pred(*_UFirst)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool none_of(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE copy_if
|
|
template <class _InIt, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _OutIt copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy each satisfying _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (_Pred(*_UFirst)) {
|
|
*_UDest = *_UFirst;
|
|
++_UDest;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* copy_if(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// copy each satisfying _Pred, array dest
|
|
return _STD copy_if(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _Pr _Pred) noexcept /* terminates */ {
|
|
// copy each satisfying _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD copy_if(_First, _Last, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* copy_if(
|
|
_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// copy each satisfying _Pred, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD copy_if(_First, _Last, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE partition_copy
|
|
template <class _InIt, class _OutIt1, class _OutIt2, class _Pr>
|
|
_CONSTEXPR20 pair<_OutIt1, _OutIt2> partition_copy(
|
|
_InIt _First, _InIt _Last, _OutIt1 _Dest_true, _OutIt2 _Dest_false, _Pr _Pred) {
|
|
// copy true partition to _Dest_true, false to _Dest_false
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest_true = _Get_unwrapped_unverified(_Dest_true);
|
|
auto _UDest_false = _Get_unwrapped_unverified(_Dest_false);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (_Pred(*_UFirst)) {
|
|
*_UDest_true = *_UFirst;
|
|
++_UDest_true;
|
|
} else {
|
|
*_UDest_false = *_UFirst;
|
|
++_UDest_false;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest_false, _UDest_false);
|
|
_Seek_wrapped(_Dest_true, _UDest_true);
|
|
return {_Dest_true, _Dest_false};
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTrueTy, size_t _DestTrueSize, class _OutIt2, class _Pr>
|
|
_CONSTEXPR20 pair<_DestTrueTy*, _OutIt2> partition_copy(
|
|
_InIt _First, _InIt _Last, _DestTrueTy (&_Dest_true)[_DestTrueSize], _OutIt2 _Dest_false, _Pr _Pred) {
|
|
// copy true partition to _Dest_true, false to _Dest_false, array dest
|
|
const auto _Result = _STD partition_copy(
|
|
_First, _Last, _Array_iterator<_DestTrueTy, _DestTrueSize>(_Dest_true), _Dest_false, _Pass_fn(_Pred));
|
|
return {_Result.first._Unwrapped(), _Result.second};
|
|
}
|
|
|
|
template <class _InIt, class _OutIt1, class _DestFalseTy, size_t _DestFalseSize, class _Pr>
|
|
_CONSTEXPR20 pair<_OutIt1, _DestFalseTy*> partition_copy(
|
|
_InIt _First, _InIt _Last, _OutIt1 _Dest_true, _DestFalseTy (&_Dest_false)[_DestFalseSize], _Pr _Pred) {
|
|
// copy true partition to _Dest_true, false to _Dest_false, array dest
|
|
const auto _Result = _STD partition_copy(
|
|
_First, _Last, _Dest_true, _Array_iterator<_DestFalseTy, _DestFalseSize>(_Dest_false), _Pass_fn(_Pred));
|
|
return {_Result.first, _Result.second._Unwrapped()};
|
|
}
|
|
|
|
template <class _InIt, class _DestTrueTy, size_t _DestTrueSize, class _DestFalseTy, size_t _DestFalseSize, class _Pr>
|
|
_CONSTEXPR20 pair<_DestTrueTy*, _DestFalseTy*> partition_copy(_InIt _First, _InIt _Last,
|
|
_DestTrueTy (&_Dest_true)[_DestTrueSize], _DestFalseTy (&_Dest_false)[_DestFalseSize], _Pr _Pred) {
|
|
// copy true partition to _Dest_true, false to _Dest_false, array dest
|
|
const auto _Result = _STD partition_copy(_First, _Last, _Array_iterator<_DestTrueTy, _DestTrueSize>(_Dest_true),
|
|
_Array_iterator<_DestFalseTy, _DestFalseSize>(_Dest_false), _Pass_fn(_Pred));
|
|
return {_Result.first._Unwrapped(), _Result.second._Unwrapped()};
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
pair<_FwdIt2, _FwdIt3> partition_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest_true, _FwdIt3 _Dest_false,
|
|
_Pr _Pred) noexcept /* terminates */ {
|
|
// copy true partition to _Dest_true, false to _Dest_false
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD partition_copy(_First, _Last, _Dest_true, _Dest_false, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTrueTy, size_t _DestTrueSize, class _FwdIt3, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
pair<_DestTrueTy*, _FwdIt3> partition_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last,
|
|
_DestTrueTy (&_Dest_true)[_DestTrueSize], _FwdIt3 _Dest_false, _Pr _Pred) noexcept /* terminates */ {
|
|
// copy true partition to _Dest_true, false to _Dest_false, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD partition_copy(_First, _Last, _Dest_true, _Dest_false, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestFalseTy, size_t _DestFalseSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
pair<_FwdIt2, _DestFalseTy*> partition_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest_true,
|
|
_DestFalseTy (&_Dest_false)[_DestFalseSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// copy true partition to _Dest_true, false to _Dest_false, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD partition_copy(_First, _Last, _Dest_true, _Dest_false, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt1, class _DestTrueTy, size_t _DestTrueSize, class _DestFalseTy,
|
|
size_t _DestFalseSize, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
pair<_DestTrueTy*, _DestFalseTy*> partition_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last,
|
|
_DestTrueTy (&_Dest_true)[_DestTrueSize], _DestFalseTy (&_Dest_false)[_DestFalseSize],
|
|
_Pr _Pred) noexcept /* terminates */ {
|
|
// copy true partition to _Dest_true, false to _Dest_false, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD partition_copy(_First, _Last, _Dest_true, _Dest_false, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE is_partitioned
|
|
template <class _InIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool is_partitioned(const _InIt _First, const _InIt _Last, _Pr _Pred) {
|
|
// test if [_First, _Last) partitioned by _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
for (;; ++_UFirst) { // skip true partition
|
|
if (_UFirst == _ULast) {
|
|
return true;
|
|
}
|
|
|
|
if (!_Pred(*_UFirst)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (++_UFirst != _ULast) { // verify false partition
|
|
if (_Pred(*_UFirst)) {
|
|
return false; // found out of place element
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool is_partitioned(_ExPo&&, const _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE partition_point
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt partition_point(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
|
// find beginning of false partition in [_First, _Last)
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _Count = _STD distance(_UFirst, _ULast);
|
|
while (0 < _Count) { // divide and conquer, find half that contains answer
|
|
const auto _Count2 = static_cast<_Iter_diff_t<_FwdIt>>(_Count / 2);
|
|
const auto _UMid = _STD next(_UFirst, _Count2);
|
|
|
|
if (_Pred(*_UMid)) { // try top half
|
|
_UFirst = _Next_iter(_UMid);
|
|
_Count -= _Count2;
|
|
--_Count;
|
|
} else {
|
|
_Count = _Count2;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First, _UFirst);
|
|
return _First;
|
|
}
|
|
|
|
// FUNCTION TEMPLATE _Equal_rev_pred_unchecked
|
|
#if _HAS_IF_CONSTEXPR
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool _Equal_rev_pred_unchecked(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) {
|
|
// compare [_First1, ...) to [_First2, _Last2) using _Pred
|
|
if constexpr (decltype(_Equal_memcmp_is_safe(_First1, _First2, _Pred))::value) {
|
|
#ifdef __cpp_lib_is_constant_evaluated
|
|
if (!_STD is_constant_evaluated())
|
|
#endif // __cpp_lib_is_constant_evaluated
|
|
{
|
|
const auto _First1_ch = reinterpret_cast<const char*>(_First1);
|
|
const auto _First2_ch = reinterpret_cast<const char*>(_First2);
|
|
const auto _Count = static_cast<size_t>(reinterpret_cast<const char*>(_Last2) - _First2_ch);
|
|
return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0;
|
|
}
|
|
}
|
|
|
|
for (; _First2 != _Last2; ++_First1, (void) ++_First2) {
|
|
if (!_Pred(*_First1, *_First2)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
bool _Equal_rev_pred_unchecked1(_InIt1 _First1, _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred, false_type) {
|
|
// compare [_First1, ...) to [_First2, _Last2) using _Pred, no special optimization
|
|
for (; _First2 != _Last2; ++_First1, (void) ++_First2) {
|
|
if (!_Pred(*_First1, *_First2)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
bool _Equal_rev_pred_unchecked1(const _InIt1 _First1, const _InIt2 _First2, const _InIt2 _Last2, _Pr, true_type) {
|
|
// compare [_First1, ...) to [_First2, _Last2), memcmp optimization
|
|
const auto _First1_ch = reinterpret_cast<const char*>(_First1);
|
|
const auto _First2_ch = reinterpret_cast<const char*>(_First2);
|
|
const auto _Count = static_cast<size_t>(reinterpret_cast<const char*>(_Last2) - _First2_ch);
|
|
return _CSTD memcmp(_First1_ch, _First2_ch, _Count) == 0;
|
|
}
|
|
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
bool _Equal_rev_pred_unchecked(const _InIt1 _First1, const _InIt2 _First2, const _InIt2 _Last2, _Pr _Pred) {
|
|
// compare [_First1, ...) to [_First2, _Last2) using _Pred, choose optimization
|
|
return _Equal_rev_pred_unchecked1(_First1, _First2, _Last2, _Pred, _Equal_memcmp_is_safe(_First1, _First2, _Pred));
|
|
}
|
|
#endif // _HAS_IF_CONSTEXPR
|
|
|
|
// FUNCTION TEMPLATE search
|
|
#if _HAS_IF_CONSTEXPR
|
|
template <class _FwdItHaystack, class _FwdItPat, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdItHaystack search(_FwdItHaystack _First1, _FwdItHaystack _Last1, const _FwdItPat _First2,
|
|
const _FwdItPat _Last2, _Pr _Pred) { // find first [_First2, _Last2) satisfying _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
const auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
if constexpr (_Is_random_iter_v<_FwdItHaystack> && _Is_random_iter_v<_FwdItPat>) {
|
|
const _Iter_diff_t<_FwdItPat> _Count2 = _ULast2 - _UFirst2;
|
|
if (_ULast1 - _UFirst1 >= _Count2) {
|
|
const auto _Last_possible = _ULast1 - static_cast<_Iter_diff_t<_FwdItHaystack>>(_Count2);
|
|
for (;; ++_UFirst1) {
|
|
if (_Equal_rev_pred_unchecked(_UFirst1, _UFirst2, _ULast2, _Pass_fn(_Pred))) {
|
|
_Seek_wrapped(_Last1, _UFirst1);
|
|
break;
|
|
}
|
|
|
|
if (_UFirst1 == _Last_possible) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (;; ++_UFirst1) { // loop until match or end of a sequence
|
|
auto _UMid1 = _UFirst1;
|
|
for (auto _UMid2 = _UFirst2;; ++_UMid1, (void) ++_UMid2) {
|
|
if (_UMid2 == _ULast2) {
|
|
_Seek_wrapped(_Last1, _UFirst1);
|
|
return _Last1;
|
|
} else if (_UMid1 == _ULast1) {
|
|
return _Last1;
|
|
} else if (!_Pred(*_UMid1, *_UMid2)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Last1;
|
|
}
|
|
#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv
|
|
template <class _FwdItHaystack, class _FwdItPat, class _Pr>
|
|
_FwdItHaystack _Search_unchecked(_FwdItHaystack _First1, _FwdItHaystack _Last1, _FwdItPat _First2, _FwdItPat _Last2,
|
|
_Pr _Pred, forward_iterator_tag, forward_iterator_tag) {
|
|
// find first [_First2, _Last2) satisfying _Pred, arbitrary iterators
|
|
for (;; ++_First1) { // loop until match or end of a sequence
|
|
_FwdItHaystack _Mid1 = _First1;
|
|
for (_FwdItPat _Mid2 = _First2;; ++_Mid1, (void) ++_Mid2) {
|
|
if (_Mid2 == _Last2) {
|
|
return _First1;
|
|
} else if (_Mid1 == _Last1) {
|
|
return _Last1;
|
|
} else if (!_Pred(*_Mid1, *_Mid2)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _FwdItHaystack, class _FwdItPat, class _Pr>
|
|
_FwdItHaystack _Search_unchecked(_FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2,
|
|
const _FwdItPat _Last2, _Pr _Pred, random_access_iterator_tag, random_access_iterator_tag) {
|
|
// find first [_First2, _Last2) satisfying _Pred, random-access iterators
|
|
_Iter_diff_t<_FwdItPat> _Count2 = _Last2 - _First2;
|
|
if (_Last1 - _First1 >= _Count2) {
|
|
const auto _Last_possible = _Last1 - static_cast<_Iter_diff_t<_FwdItHaystack>>(_Count2);
|
|
for (;; ++_First1) {
|
|
if (_Equal_rev_pred_unchecked(_First1, _First2, _Last2, _Pred)) {
|
|
return _First1;
|
|
}
|
|
|
|
if (_First1 == _Last_possible) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Last1;
|
|
}
|
|
|
|
template <class _FwdItHaystack, class _FwdItPat, class _Pr>
|
|
_NODISCARD _FwdItHaystack search(_FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2,
|
|
const _FwdItPat _Last2, _Pr _Pred) { // find first [_First2, _Last2) satisfying _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
_Seek_wrapped(
|
|
_First1, _Search_unchecked(_Get_unwrapped(_First1), _Get_unwrapped(_Last1), _Get_unwrapped(_First2),
|
|
_Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_FwdItHaystack>(), _Iter_cat_t<_FwdItPat>()));
|
|
return _First1;
|
|
}
|
|
#endif // _HAS_IF_CONSTEXPR
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdItHaystack, class _FwdItPat, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdItHaystack search(_ExPo&& _Exec, const _FwdItHaystack _First1, _FwdItHaystack _Last1,
|
|
const _FwdItPat _First2, const _FwdItPat _Last2, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
template <class _FwdItHaystack, class _FwdItPat>
|
|
_NODISCARD _CONSTEXPR20 _FwdItHaystack search(
|
|
const _FwdItHaystack _First1, const _FwdItHaystack _Last1, const _FwdItPat _First2, const _FwdItPat _Last2) {
|
|
// find first [_First2, _Last2) match
|
|
return _STD search(_First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdItHaystack, class _FwdItPat, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdItHaystack search(_ExPo&& _Exec, const _FwdItHaystack _First1, const _FwdItHaystack _Last1,
|
|
const _FwdItPat _First2, const _FwdItPat _Last2) noexcept /* terminates */ {
|
|
// find first [_First2, _Last2) match
|
|
return _STD search(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
template <class _FwdItHaystack, class _Searcher>
|
|
_NODISCARD _CONSTEXPR20 _FwdItHaystack search(
|
|
const _FwdItHaystack _First, const _FwdItHaystack _Last, const _Searcher& _Search) {
|
|
// find _Search's pattern in [_First, _Last)
|
|
return _Search(_First, _Last).first;
|
|
}
|
|
|
|
// FUNCTION TEMPLATE search_n
|
|
#if _HAS_IF_CONSTEXPR
|
|
template <class _FwdIt, class _Diff, class _Ty, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt search_n(
|
|
const _FwdIt _First, _FwdIt _Last, const _Diff _Count_raw, const _Ty& _Val, _Pr _Pred) {
|
|
// find first _Count * _Val satisfying _Pred
|
|
const _Algorithm_int_t<_Diff> _Count = _Count_raw;
|
|
if (_Count <= 0) {
|
|
return _First;
|
|
}
|
|
|
|
if (static_cast<uintmax_t>(_Count) > static_cast<uintmax_t>((numeric_limits<_Iter_diff_t<_FwdIt>>::max)())) {
|
|
// if the number of _Vals searched for is larger than the longest possible sequence, we can't find it
|
|
return _Last;
|
|
}
|
|
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
if constexpr (_Is_random_iter_v<_FwdIt>) {
|
|
const auto _Count_diff = static_cast<_Iter_diff_t<_FwdIt>>(_Count);
|
|
auto _UOld_first = _UFirst;
|
|
for (_Iter_diff_t<_FwdIt> _Inc = 0; _Count_diff <= _ULast - _UOld_first;) { // enough room, look for a match
|
|
_UFirst = _UOld_first + _Inc;
|
|
if (_Pred(*_UFirst, _Val)) { // found part of possible match, check it out
|
|
_Iter_diff_t<_FwdIt> _Count1 = _Count_diff;
|
|
auto _UMid = _UFirst;
|
|
|
|
while (_UOld_first != _UFirst && _Pred(*(_UFirst - 1), _Val)) { // back up over any skipped prefix
|
|
--_Count1;
|
|
--_UFirst;
|
|
}
|
|
|
|
if (_Count1 <= _ULast - _UMid) {
|
|
for (;;) { // enough left, test suffix
|
|
if (--_Count1 == 0) {
|
|
_Seek_wrapped(_Last, _UFirst); // found rest of match, report it
|
|
return _Last;
|
|
} else if (!_Pred(*++_UMid, _Val)) { // short match not at end
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
_UOld_first = ++_UMid; // failed match, take small jump
|
|
_Inc = 0;
|
|
} else { // no match, take big jump and back up as needed
|
|
_UOld_first = _UFirst + 1;
|
|
_Inc = _Count_diff - 1;
|
|
}
|
|
}
|
|
} else {
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (_Pred(*_UFirst, _Val)) { // found start of possible match, check it out
|
|
auto _UMid = _UFirst;
|
|
|
|
for (_Algorithm_int_t<_Diff> _Count1 = _Count;;) {
|
|
if (--_Count1 == 0) {
|
|
_Seek_wrapped(_Last, _UFirst); // found rest of match, report it
|
|
return _Last;
|
|
} else if (++_UMid == _ULast) {
|
|
return _Last; // short match at end
|
|
} else if (!_Pred(*_UMid, _Val)) { // short match not at end
|
|
break;
|
|
}
|
|
}
|
|
|
|
_UFirst = _UMid; // pick up just beyond failed match
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Last;
|
|
}
|
|
#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv
|
|
template <class _FwdIt, class _Diff, class _Ty, class _Pr>
|
|
_FwdIt _Search_n_unchecked1(_FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val, _Pr _Pred,
|
|
forward_iterator_tag) { // find first _Count * _Val satisfying _Pred, forward iterators
|
|
for (; _First != _Last; ++_First) {
|
|
if (_Pred(*_First, _Val)) { // found start of possible match, check it out
|
|
_FwdIt _Mid = _First;
|
|
|
|
for (_Diff _Count1 = _Count;;) {
|
|
if (--_Count1 == 0) {
|
|
return _First; // found rest of match, report it
|
|
} else if (++_Mid == _Last) {
|
|
return _Last; // short match at end
|
|
} else if (!_Pred(*_Mid, _Val)) { // short match not at end
|
|
break;
|
|
}
|
|
}
|
|
|
|
_First = _Mid; // pick up just beyond failed match
|
|
}
|
|
}
|
|
|
|
return _Last;
|
|
}
|
|
|
|
template <class _FwdIt, class _Diff, class _Ty, class _Pr>
|
|
_FwdIt _Search_n_unchecked1(_FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val, _Pr _Pred,
|
|
random_access_iterator_tag) { // find first _Count * _Val satisfying _Pred, random-access iterators
|
|
const auto _Count_diff = static_cast<_Iter_diff_t<_FwdIt>>(_Count);
|
|
_FwdIt _Old_first = _First;
|
|
for (_Iter_diff_t<_FwdIt> _Inc = 0; _Count_diff <= _Last - _Old_first;) { // enough room, look for a match
|
|
_First = _Old_first + _Inc;
|
|
if (_Pred(*_First, _Val)) { // found part of possible match, check it out
|
|
_Iter_diff_t<_FwdIt> _Count1 = _Count_diff;
|
|
_FwdIt _Mid = _First;
|
|
|
|
while (_Old_first != _First && _Pred(*(_First - 1), _Val)) {
|
|
--_Count1; // back up over any skipped prefix
|
|
--_First;
|
|
}
|
|
|
|
if (_Count1 <= _Last - _Mid) {
|
|
for (;;) { // enough left, test suffix
|
|
if (--_Count1 == 0) {
|
|
return _First; // found rest of match, report it
|
|
} else if (!_Pred(*++_Mid, _Val)) { // short match not at end
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
_Old_first = ++_Mid; // failed match, take small jump
|
|
_Inc = 0;
|
|
} else { // no match, take big jump and back up as needed
|
|
_Old_first = _First + 1;
|
|
_Inc = _Count_diff - 1;
|
|
}
|
|
}
|
|
|
|
return _Last;
|
|
}
|
|
|
|
template <class _FwdIt, class _Diff, class _Ty, class _Pr>
|
|
_NODISCARD _FwdIt search_n(_FwdIt _First, const _FwdIt _Last, const _Diff _Count_raw, const _Ty& _Val, _Pr _Pred) {
|
|
// find first _Count * _Val satisfying _Pred
|
|
const _Algorithm_int_t<_Diff> _Count = _Count_raw;
|
|
if (_Count <= 0) {
|
|
return _First;
|
|
}
|
|
|
|
if (static_cast<uintmax_t>(_Count) > static_cast<uintmax_t>((numeric_limits<_Iter_diff_t<_FwdIt>>::max)())) {
|
|
// if the number of _Vals searched for is larger than the longest possible sequence, we can't find it
|
|
_First = _Last;
|
|
return _First;
|
|
}
|
|
|
|
_Adl_verify_range(_First, _Last);
|
|
_Seek_wrapped(_First, _Search_n_unchecked1(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Count, _Val,
|
|
_Pass_fn(_Pred), _Iter_cat_t<_FwdIt>()));
|
|
|
|
return _First;
|
|
}
|
|
#endif // _HAS_IF_CONSTEXPR
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Diff, class _Ty, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt search_n(_ExPo&& _Exec, const _FwdIt _First, _FwdIt _Last, const _Diff _Count_raw, const _Ty& _Val,
|
|
_Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
template <class _FwdIt, class _Diff, class _Ty>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt search_n(const _FwdIt _First, const _FwdIt _Last, const _Diff _Count, const _Ty& _Val) {
|
|
// find first _Count * _Val match
|
|
return _STD search_n(_First, _Last, _Count, _Val, equal_to<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Diff, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt search_n(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Diff _Count,
|
|
const _Ty& _Val) noexcept /* terminates */ { // find first _Count * _Val match
|
|
return _STD search_n(_STD forward<_ExPo>(_Exec), _First, _Last, _Count, _Val, equal_to<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE find_end
|
|
#if _HAS_IF_CONSTEXPR
|
|
template <class _FwdIt1, class _FwdIt2, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt1 find_end(
|
|
_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, _Pr _Pred) {
|
|
// find last [_First2, _Last2) satisfying _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
const auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
if constexpr (_Is_random_iter_v<_FwdIt1> && _Is_random_iter_v<_FwdIt2>) {
|
|
const _Iter_diff_t<_FwdIt2> _Count2 = _ULast2 - _UFirst2;
|
|
if (0 < _Count2 && _Count2 <= _ULast1 - _UFirst1) {
|
|
for (auto _UCandidate = _ULast1 - static_cast<_Iter_diff_t<_FwdIt1>>(_Count2);; --_UCandidate) {
|
|
if (_Equal_rev_pred_unchecked(_UCandidate, _UFirst2, _ULast2, _Pass_fn(_Pred))) {
|
|
_Seek_wrapped(_First1, _UCandidate);
|
|
return _First1;
|
|
}
|
|
|
|
if (_UFirst1 == _UCandidate) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Last1;
|
|
} else if constexpr (_Is_bidi_iter_v<_FwdIt1> && _Is_bidi_iter_v<_FwdIt2>) {
|
|
for (auto _UCandidate = _ULast1;; --_UCandidate) { // try a match at _Candidate
|
|
auto _UNext1 = _UCandidate;
|
|
auto _UNext2 = _ULast2;
|
|
for (;;) { // test if [_UFirst2, _ULast2) is a suffix of [_UFirst1, _Candidate)
|
|
if (_UFirst2 == _UNext2) { // match found
|
|
_Seek_wrapped(_First1, _UNext1);
|
|
return _First1;
|
|
}
|
|
|
|
if (_UFirst1 == _UNext1) {
|
|
// [_UFirst1, _Candidate) is shorter than [_UFirst2, _ULast2), remaining candidates nonviable
|
|
return _Last1;
|
|
}
|
|
|
|
--_UNext1;
|
|
--_UNext2;
|
|
if (!_Pred(*_UNext1, *_UNext2)) { // counterexample found
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
auto _UResult = _ULast1;
|
|
for (;;) { // try a match at _UFirst1
|
|
auto _UNext1 = _UFirst1;
|
|
auto _UNext2 = _UFirst2;
|
|
for (;;) { // test if [_UFirst2, _ULast2) is a prefix of [_UFirst1, _ULast1)
|
|
const bool _End_of_needle = static_cast<bool>(_UNext2 == _ULast2);
|
|
if (_End_of_needle) { // match candidate found
|
|
_UResult = _UFirst1;
|
|
}
|
|
|
|
if (_UNext1 == _ULast1) {
|
|
// trying the next candidate would make [_UFirst1, _ULast1) shorter than [_UFirst2, _ULast2), done
|
|
_Seek_wrapped(_First1, _UResult);
|
|
return _First1;
|
|
}
|
|
|
|
if (_End_of_needle || !_Pred(*_UNext1, *_UNext2)) {
|
|
break; // end of match or counterexample found, go to the next candidate
|
|
}
|
|
|
|
++_UNext1;
|
|
++_UNext2;
|
|
}
|
|
|
|
++_UFirst1;
|
|
}
|
|
|
|
_Seek_wrapped(_First1, _UResult);
|
|
return _First1;
|
|
}
|
|
}
|
|
#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv
|
|
template <class _FwdIt1, class _FwdIt2, class _Pr>
|
|
_FwdIt1 _Find_end_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2,
|
|
_Pr _Pred, forward_iterator_tag, forward_iterator_tag) {
|
|
// find last [_First2, _Last2) satisfying _Pred in forward ranges
|
|
_FwdIt1 _Result = _Last1;
|
|
for (;;) { // try a match at _First1
|
|
_FwdIt1 _Next1 = _First1;
|
|
_FwdIt2 _Next2 = _First2;
|
|
for (;;) { // test if [_First2, _Last2) is a prefix of [_First1, _Last1)
|
|
const bool _End_of_needle = static_cast<bool>(_Next2 == _Last2);
|
|
if (_End_of_needle) { // match candidate found
|
|
_Result = _First1;
|
|
}
|
|
|
|
if (_Next1 == _Last1) {
|
|
// trying the next candidate would make [_First1, _Last1) shorter than [_First2, _Last2), done
|
|
return _Result;
|
|
}
|
|
|
|
if (_End_of_needle || !_Pred(*_Next1, *_Next2)) {
|
|
break; // end of match or counterexample found, go to the next candidate
|
|
}
|
|
|
|
++_Next1;
|
|
++_Next2;
|
|
}
|
|
|
|
++_First1;
|
|
}
|
|
}
|
|
|
|
template <class _BidIt1, class _BidIt2, class _Pr>
|
|
_BidIt1 _Find_end_unchecked(const _BidIt1 _First1, const _BidIt1 _Last1, const _BidIt2 _First2, const _BidIt2 _Last2,
|
|
_Pr _Pred, bidirectional_iterator_tag, bidirectional_iterator_tag) {
|
|
// find last [_First2, _Last2) satisfying _Pred in bidirectional ranges
|
|
for (_BidIt1 _Candidate = _Last1;; --_Candidate) { // try a match at _Candidate
|
|
_BidIt1 _Next1 = _Candidate;
|
|
_BidIt2 _Next2 = _Last2;
|
|
for (;;) { // test if [_First2, _Last2) is a suffix of [_First1, _Candidate)
|
|
if (_First2 == _Next2) { // match found
|
|
return _Next1;
|
|
}
|
|
|
|
if (_First1 == _Next1) {
|
|
// [_First1, _Candidate) is shorter than [_First2, _Last2), remaining candidates nonviable
|
|
return _Last1;
|
|
}
|
|
|
|
--_Next1;
|
|
--_Next2;
|
|
if (!_Pred(*_Next1, *_Next2)) { // counterexample found
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _RanIt1, class _RanIt2, class _Pr>
|
|
_RanIt1 _Find_end_unchecked(const _RanIt1 _First1, const _RanIt1 _Last1, const _RanIt2 _First2, const _RanIt2 _Last2,
|
|
_Pr _Pred, random_access_iterator_tag, random_access_iterator_tag) {
|
|
// find last [_First2, _Last2) satisfying _Pred in random-access ranges
|
|
const _Iter_diff_t<_RanIt2> _Count2 = _Last2 - _First2;
|
|
if (0 < _Count2 && _Count2 <= _Last1 - _First1) {
|
|
for (_RanIt1 _Candidate = _Last1 - static_cast<_Iter_diff_t<_RanIt1>>(_Count2);; --_Candidate) {
|
|
if (_Equal_rev_pred_unchecked(_Candidate, _First2, _Last2, _Pred)) {
|
|
return _Candidate;
|
|
}
|
|
|
|
if (_First1 == _Candidate) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Last1;
|
|
}
|
|
|
|
template <class _FwdIt1, class _FwdIt2, class _Pr>
|
|
_NODISCARD _FwdIt1 find_end(_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2,
|
|
_Pr _Pred) { // find last [_First2, _Last2) satisfying _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
_Seek_wrapped(
|
|
_First1, _Find_end_unchecked(_Get_unwrapped(_First1), _Get_unwrapped(_Last1), _Get_unwrapped(_First2),
|
|
_Get_unwrapped(_Last2), _Pass_fn(_Pred), _Iter_cat_t<_FwdIt1>(), _Iter_cat_t<_FwdIt2>()));
|
|
|
|
return _First1;
|
|
}
|
|
#endif // _HAS_IF_CONSTEXPR
|
|
|
|
template <class _FwdIt1, class _FwdIt2>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt1 find_end(
|
|
_FwdIt1 const _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2) {
|
|
// find last [_First2, _Last2) match
|
|
return _STD find_end(_First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt1 find_end(
|
|
_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) noexcept; // terminates
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt1 find_end(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2,
|
|
_FwdIt2 _Last2) noexcept /* terminates */ { // find last [_First2, _Last2) match
|
|
return _STD find_end(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE find_first_of
|
|
template <class _FwdIt1, class _FwdIt2, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of(
|
|
_FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, const _FwdIt2 _Last2, _Pr _Pred) {
|
|
// look for one of [_First2, _Last2) satisfying _Pred with element
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
const auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
for (; _UFirst1 != _ULast1; ++_UFirst1) {
|
|
for (auto _UMid2 = _UFirst2; _UMid2 != _ULast2; ++_UMid2) {
|
|
if (_Pred(*_UFirst1, *_UMid2)) {
|
|
_Seek_wrapped(_First1, _UFirst1);
|
|
return _First1;
|
|
}
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First1, _UFirst1);
|
|
return _First1;
|
|
}
|
|
|
|
template <class _FwdIt1, class _FwdIt2>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt1 find_first_of(const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2,
|
|
const _FwdIt2 _Last2) { // look for one of [_First2, _Last2) that matches element
|
|
return _STD find_first_of(_First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt1 find_first_of(_ExPo&& _Exec, const _FwdIt1 _First1, _FwdIt1 _Last1, const _FwdIt2 _First2,
|
|
const _FwdIt2 _Last2, _Pr _Pred) noexcept; // terminates
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt1 find_first_of(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2,
|
|
const _FwdIt2 _Last2) noexcept /* terminates */ { // look for one of [_First2, _Last2) that matches element
|
|
return _STD find_first_of(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, equal_to<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
|
|
// FUNCTION TEMPLATE swap_ranges
|
|
template <class _FwdIt1, class _FwdIt2>
|
|
_CONSTEXPR20 _FwdIt2 _Swap_ranges_unchecked(_FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) {
|
|
// swap [_First1, _Last1) with [_First2, ...), no special optimization
|
|
for (; _First1 != _Last1; ++_First1, (void) ++_First2) {
|
|
_STD iter_swap(_First1, _First2);
|
|
}
|
|
|
|
return _First2;
|
|
}
|
|
|
|
#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID)
|
|
template <class _Ty, enable_if_t<_Is_trivially_swappable_v<_Ty>, int> = 0>
|
|
_CONSTEXPR20 _Ty* _Swap_ranges_unchecked(_Ty* _First1, _Ty* const _Last1, _Ty* _First2) {
|
|
// swap [_First1, _Last1) with [_First2, ...), trivially swappable optimization
|
|
#ifdef __cpp_lib_is_constant_evaluated
|
|
if (!_STD is_constant_evaluated())
|
|
#endif // __cpp_lib_is_constant_evaluated
|
|
{
|
|
__std_swap_ranges_trivially_swappable_noalias(_First1, _Last1, _First2);
|
|
return _First2 + (_Last1 - _First1);
|
|
}
|
|
|
|
for (; _First1 != _Last1; ++_First1, (void) ++_First2) {
|
|
_STD iter_swap(_First1, _First2);
|
|
}
|
|
|
|
return _First2;
|
|
}
|
|
#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_CEE_PURE) && !defined(_M_HYBRID)
|
|
|
|
template <class _FwdIt1, class _FwdIt2>
|
|
_CONSTEXPR20 _FwdIt2 swap_ranges(const _FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2) {
|
|
// swap [_First1, _Last1) with [_First2, ...)
|
|
_Adl_verify_range(_First1, _Last1);
|
|
const auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
const auto _UFirst2 = _Get_unwrapped_n(_First2, _Idl_distance<_FwdIt1>(_UFirst1, _ULast1));
|
|
_Seek_wrapped(_First2, _Swap_ranges_unchecked(_UFirst1, _ULast1, _UFirst2));
|
|
return _First2;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _FwdIt1, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* swap_ranges(_FwdIt1 _First1, _FwdIt1 _Last1, _DestTy (&_Dest)[_DestSize]) {
|
|
// swap [_First1, _Last1) with [_Dest, ...), array dest
|
|
return _STD swap_ranges(_First1, _Last1, _Array_iterator<_DestTy, _DestSize>(_Dest))._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 swap_ranges(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _Dest) noexcept /* terminates */ {
|
|
// swap [_First1, _Last1) with [_Dest, ...)
|
|
// not parallelized as benchmarks show it isn't worth it
|
|
return _STD swap_ranges(_First1, _Last1, _Dest);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* swap_ranges(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// swap [_First1, _Last1) with [_Dest, ...), array dest
|
|
// not parallelized as benchmarks show it isn't worth it
|
|
return _STD swap_ranges(_First1, _Last1, _Dest);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE transform
|
|
template <class _InIt, class _OutIt, class _Fn>
|
|
_CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Dest, _Fn _Func) {
|
|
// transform [_First, _Last) with _Func
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));
|
|
for (; _UFirst != _ULast; ++_UFirst, (void) ++_UDest) {
|
|
*_UDest = _Func(*_UFirst);
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize, class _Fn>
|
|
_CONSTEXPR20 _DestTy* transform(const _InIt _First, const _InIt _Last, _DestTy (&_Dest)[_DestSize], _Fn _Func) {
|
|
// transform [_First, _Last) with _Func, array dest
|
|
return _STD transform(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func))._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Fn, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 transform(
|
|
_ExPo&& _Exec, const _FwdIt1 _First, const _FwdIt1 _Last, _FwdIt2 _Dest, _Fn _Func) noexcept; // terminates
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, class _Fn,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* transform(
|
|
_ExPo&& _Exec, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize], _Fn _Func) noexcept /* terminates */ {
|
|
// transform [_First, _Last) with _Func, array dest
|
|
return _STD transform(
|
|
_STD forward<_ExPo>(_Exec), _First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
template <class _InIt1, class _InIt2, class _OutIt, class _Fn>
|
|
_CONSTEXPR20 _OutIt transform(
|
|
const _InIt1 _First1, const _InIt1 _Last1, const _InIt2 _First2, _OutIt _Dest, _Fn _Func) {
|
|
// transform [_First1, _Last1) and [_First2, ...) with _Func
|
|
_Adl_verify_range(_First1, _Last1);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
const auto _Count = _Idl_distance<_InIt1>(_UFirst1, _ULast1);
|
|
auto _UFirst2 = _Get_unwrapped_n(_First2, _Count);
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Count);
|
|
for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2, ++_UDest) {
|
|
*_UDest = _Func(*_UFirst1, *_UFirst2);
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _RightTy, size_t _RightSize, class _OutIt, class _Fn>
|
|
_CONSTEXPR20 _OutIt transform(
|
|
const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize], const _OutIt _Dest, _Fn _Func) {
|
|
// transform [_First1, _Last1) and [_First2, ...), array source
|
|
return _STD transform(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2), _Dest, _Pass_fn(_Func));
|
|
}
|
|
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize, class _Fn>
|
|
_CONSTEXPR20 _DestTy* transform(
|
|
const _InIt1 _First1, const _InIt1 _Last1, _InIt2 _First2, _DestTy (&_Dest)[_DestSize], _Fn _Func) {
|
|
// transform [_First1, _Last1) and [_First2, ...), array dest
|
|
return _STD transform(_First1, _Last1, _First2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func))
|
|
._Unwrapped();
|
|
}
|
|
|
|
template <class _InIt1, class _RightTy, size_t _RightSize, class _DestTy, size_t _DestSize, class _Fn>
|
|
_CONSTEXPR20 _DestTy* transform(const _InIt1 _First1, const _InIt1 _Last1, _RightTy (&_First2)[_RightSize],
|
|
_DestTy (&_Dest)[_DestSize], _Fn _Func) {
|
|
// transform [_First1, _Last1) and [_First2, ...), array source/dest
|
|
return _STD transform(_First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2),
|
|
_Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, class _Fn, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 transform(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, const _FwdIt2 _First2, _FwdIt3 _Dest,
|
|
_Fn _Func) noexcept; // terminates
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _RightTy, size_t _RightSize, class _FwdIt3, class _Fn,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 transform(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, _RightTy (&_First2)[_RightSize],
|
|
const _FwdIt3 _Dest, _Fn _Func) noexcept /* terminates */ {
|
|
// transform [_First1, _Last1) and [_First2, ...), array source
|
|
return _STD transform(_STD forward<_ExPo>(_Exec), _First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2),
|
|
_Dest, _Pass_fn(_Func));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize, class _Fn,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* transform(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, _FwdIt2 _First2,
|
|
_DestTy (&_Dest)[_DestSize], _Fn _Func) noexcept /* terminates */ {
|
|
// transform [_First1, _Last1) and [_First2, ...), array dest
|
|
return _STD transform(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2,
|
|
_Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func))
|
|
._Unwrapped();
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt1, class _RightTy, size_t _RightSize, class _DestTy, size_t _DestSize, class _Fn,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* transform(_ExPo&& _Exec, const _FwdIt1 _First1, const _FwdIt1 _Last1, _RightTy (&_First2)[_RightSize],
|
|
_DestTy (&_Dest)[_DestSize], _Fn _Func) noexcept /* terminates */ {
|
|
// transform [_First1, _Last1) and [_First2, ...), array source/dest
|
|
return _STD transform(_STD forward<_ExPo>(_Exec), _First1, _Last1, _Array_iterator<_RightTy, _RightSize>(_First2),
|
|
_Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Func))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE replace
|
|
template <class _FwdIt, class _Ty>
|
|
_CONSTEXPR20 void replace(const _FwdIt _First, const _FwdIt _Last, const _Ty& _Oldval, const _Ty& _Newval) {
|
|
// replace each matching _Oldval with _Newval
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (*_UFirst == _Oldval) {
|
|
*_UFirst = _Newval;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void replace(_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& _Oldval,
|
|
const _Ty& _Newval) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE replace_if
|
|
template <class _FwdIt, class _Pr, class _Ty>
|
|
_CONSTEXPR20 void replace_if(const _FwdIt _First, const _FwdIt _Last, _Pr _Pred, const _Ty& _Val) {
|
|
// replace each satisfying _Pred with _Val
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (_Pred(*_UFirst)) {
|
|
*_UFirst = _Val;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void replace_if(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred, const _Ty& _Val) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE replace_copy
|
|
template <class _InIt, class _OutIt, class _Ty>
|
|
_CONSTEXPR20 _OutIt replace_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Oldval, const _Ty& _Newval) {
|
|
// copy replacing each matching _Oldval with _Newval
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));
|
|
for (; _UFirst != _ULast; ++_UFirst, (void) ++_UDest) {
|
|
if (*_UFirst == _Oldval) {
|
|
*_UDest = _Newval;
|
|
} else {
|
|
*_UDest = *_UFirst;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize, class _Ty>
|
|
_CONSTEXPR20 _DestTy* replace_copy(
|
|
_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Oldval, const _Ty& _Newval) {
|
|
// copy replacing each matching _Oldval with _Newval, array dest
|
|
return _STD replace_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Oldval, _Newval)._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 replace_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, const _Ty& _Oldval,
|
|
const _Ty& _Newval) noexcept /* terminates */ {
|
|
// copy replacing each matching _Oldval with _Newval
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD replace_copy(_First, _Last, _Dest, _Oldval, _Newval);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, class _Ty,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* replace_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Oldval,
|
|
const _Ty& _Newval) noexcept /* terminates */ {
|
|
// copy replacing each matching _Oldval with _Newval
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD replace_copy(_First, _Last, _Dest, _Oldval, _Newval);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE replace_copy_if
|
|
template <class _InIt, class _OutIt, class _Pr, class _Ty>
|
|
_CONSTEXPR20 _OutIt replace_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, const _Ty& _Val) {
|
|
// copy replacing each satisfying _Pred with _Val
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));
|
|
for (; _UFirst != _ULast; ++_UFirst, (void) ++_UDest) {
|
|
if (_Pred(*_UFirst)) {
|
|
*_UDest = _Val;
|
|
} else {
|
|
*_UDest = *_UFirst;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize, class _Pr, class _Ty>
|
|
_CONSTEXPR20 _DestTy* replace_copy_if(
|
|
_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred, const _Ty& _Val) {
|
|
// copy replacing each satisfying _Pred with _Val, array dest
|
|
return _STD replace_copy_if(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred), _Val)
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 replace_copy_if(
|
|
_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _Pr _Pred, const _Ty& _Val) noexcept /* terminates */ {
|
|
// copy replacing each satisfying _Pred with _Val
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD replace_copy_if(_First, _Last, _Dest, _Pass_fn(_Pred), _Val);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, class _Pr, class _Ty,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred,
|
|
const _Ty& _Val) noexcept /* terminates */ {
|
|
// copy replacing each satisfying _Pred with _Val, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD replace_copy_if(_First, _Last, _Dest, _Pass_fn(_Pred), _Val);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE generate
|
|
template <class _FwdIt, class _Fn>
|
|
_CONSTEXPR20 void generate(_FwdIt _First, _FwdIt _Last, _Fn _Func) { // replace [_First, _Last) with _Func()
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
*_UFirst = _Func();
|
|
}
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Fn, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void generate(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Fn _Func) noexcept /* terminates */ {
|
|
// replace [_First, _Last) with _Func()
|
|
// not parallelized at present due to unclear parallelism requirements on _Func
|
|
return _STD generate(_First, _Last, _Pass_fn(_Func));
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE generate_n
|
|
template <class _OutIt, class _Diff, class _Fn>
|
|
_CONSTEXPR20 _OutIt generate_n(_OutIt _Dest, const _Diff _Count_raw, _Fn _Func) {
|
|
// replace [_Dest, _Dest + _Count) with _Func()
|
|
_Algorithm_int_t<_Diff> _Count = _Count_raw;
|
|
if (0 < _Count) {
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Count);
|
|
do {
|
|
*_UDest = _Func();
|
|
--_Count;
|
|
++_UDest;
|
|
} while (0 < _Count);
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
}
|
|
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _DestTy, size_t _DestSize, class _Diff, class _Fn>
|
|
_CONSTEXPR20 _DestTy* generate_n(_DestTy (&_Dest)[_DestSize], const _Diff _Count_raw, _Fn _Func) {
|
|
// replace [_Dest, _Dest + _Count) with _Func(), array dest
|
|
_Algorithm_int_t<_Diff> _Count = _Count_raw;
|
|
_STL_VERIFY_ARRAY_SIZE(_Dest, _Count);
|
|
_DestTy* _UDest = _Dest;
|
|
for (; 0 < _Count; --_Count, (void) ++_UDest) {
|
|
*_UDest = _Func();
|
|
}
|
|
|
|
return _UDest;
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Diff, class _Fn, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt generate_n(_ExPo&&, const _FwdIt _Dest, const _Diff _Count_raw, _Fn _Func) noexcept /* terminates */ {
|
|
// replace [_Dest, _Dest + _Count) with _Func()
|
|
// not parallelized at present due to unclear parallelism requirements on _Func
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt);
|
|
return _STD generate_n(_Dest, _Count_raw, _Pass_fn(_Func));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _DestTy, size_t _DestSize, class _Diff, class _Fn,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* generate_n(_ExPo&&, _DestTy (&_Dest)[_DestSize], const _Diff _Count_raw, _Fn _Func) noexcept /* terminates */ {
|
|
// replace [_Dest, _Dest + _Count) with _Func()
|
|
// not parallelized at present due to unclear parallelism requirements on _Func
|
|
return _STD generate_n(_Dest, _Count_raw, _Pass_fn(_Func));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE remove_copy
|
|
template <class _InIt, class _OutIt, class _Ty>
|
|
_CONSTEXPR20 _OutIt remove_copy(_InIt _First, _InIt _Last, _OutIt _Dest, const _Ty& _Val) {
|
|
// copy omitting each matching _Val
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (!(*_UFirst == _Val)) {
|
|
*_UDest = *_UFirst;
|
|
++_UDest;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize, class _Ty>
|
|
_CONSTEXPR20 _DestTy* remove_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Val) {
|
|
// copy omitting each matching _Val, array dest
|
|
return _STD remove_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Val)._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 remove_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, const _Ty& _Val) noexcept /* terminates */ {
|
|
// copy omitting each matching _Val
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD remove_copy(_First, _Last, _Dest, _Val);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, class _Ty,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* remove_copy(
|
|
_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize], const _Ty& _Val) noexcept /* terminates */ {
|
|
// copy omitting each matching _Val, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD remove_copy(_First, _Last, _Dest, _Val);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE remove_copy_if
|
|
template <class _InIt, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _OutIt remove_copy_if(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) {
|
|
// copy omitting each element satisfying _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
for (; _UFirst != _ULast; ++_UFirst) {
|
|
if (!_Pred(*_UFirst)) {
|
|
*_UDest = *_UFirst;
|
|
++_UDest;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* remove_copy_if(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// copy omitting each element satisfying _Pred, array dest
|
|
return _STD remove_copy_if(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 remove_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _Pr _Pred) noexcept /* terminates */ {
|
|
// copy omitting each element satisfying _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD remove_copy_if(_First, _Last, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* remove_copy_if(
|
|
_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// copy omitting each element satisfying _Pred, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD remove_copy_if(_First, _Last, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt remove(
|
|
_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt remove_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE unique
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
|
// remove each satisfying _Pred with previous
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
if (_UFirst != _ULast) {
|
|
for (auto _UFirstb = _UFirst; ++_UFirst != _ULast; _UFirstb = _UFirst) {
|
|
if (_Pred(*_UFirstb, *_UFirst)) { // copy down
|
|
while (++_UFirst != _ULast) {
|
|
if (!_Pred(*_UFirstb, *_UFirst)) {
|
|
*++_UFirstb = _STD move(*_UFirst);
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Last, ++_UFirstb);
|
|
return _Last;
|
|
}
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Last, _ULast);
|
|
return _Last;
|
|
}
|
|
|
|
template <class _FwdIt>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last) { // remove each matching previous
|
|
return _STD unique(_First, _Last, equal_to<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt unique(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// remove each satisfying _Pred with previous
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD unique(_First, _Last, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt unique(_ExPo&&, _FwdIt _First, _FwdIt _Last) noexcept /* terminates */ {
|
|
// remove each matching previous
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD unique(_First, _Last);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE unique_copy
|
|
#if _HAS_IF_CONSTEXPR
|
|
// clang-format off
|
|
#ifdef __cpp_lib_concepts
|
|
template <class _InIt, class _OutIt>
|
|
concept _Can_reread_dest = forward_iterator<_OutIt> && same_as<iter_value_t<_InIt>, iter_value_t<_OutIt>>;
|
|
#else // ^^^ defined(__cpp_lib_concepts) / !defined(__cpp_lib_concepts) vvv
|
|
template <class _InIt, class _OutIt>
|
|
_INLINE_VAR constexpr bool _Can_reread_dest =
|
|
_Is_fwd_iter_v<_OutIt> && is_same_v<_Iter_value_t<_InIt>, _Iter_value_t<_OutIt>>;
|
|
#endif // __cpp_lib_concepts
|
|
// clang-format on
|
|
|
|
template <class _InIt, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) {
|
|
// copy compressing pairs that match
|
|
_Adl_verify_range(_First, _Last);
|
|
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
if (_UFirst == _ULast) {
|
|
return _Dest;
|
|
}
|
|
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
|
|
if constexpr (_Is_fwd_iter_v<_InIt>) { // can reread the source for comparison
|
|
auto _Firstb = _UFirst;
|
|
|
|
*_UDest = *_Firstb;
|
|
++_UDest;
|
|
|
|
while (++_UFirst != _ULast) {
|
|
if (!static_cast<bool>(_Pred(*_Firstb, *_UFirst))) { // copy unmatched
|
|
_Firstb = _UFirst;
|
|
*_UDest = *_Firstb;
|
|
++_UDest;
|
|
}
|
|
}
|
|
} else if constexpr (_Can_reread_dest<_InIt, _OutIt>) { // assignment copies T; can reread dest for comparison
|
|
*_UDest = *_UFirst;
|
|
|
|
while (++_UFirst != _ULast) {
|
|
if (!static_cast<bool>(_Pred(*_UDest, *_UFirst))) {
|
|
*++_UDest = *_UFirst;
|
|
}
|
|
}
|
|
|
|
++_UDest;
|
|
} else { // can't reread source or dest, construct a temporary
|
|
_Iter_value_t<_InIt> _Val = *_UFirst;
|
|
|
|
*_UDest = _Val;
|
|
++_UDest;
|
|
|
|
while (++_UFirst != _ULast) {
|
|
if (!static_cast<bool>(_Pred(_Val, *_UFirst))) { // copy unmatched
|
|
_Val = *_UFirst;
|
|
*_UDest = _Val;
|
|
++_UDest;
|
|
}
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv
|
|
template <class _FwdIt, class _OutIt, class _Pr>
|
|
_OutIt _Unique_copy_unchecked(_FwdIt _First, _FwdIt _Last, _OutIt _Dest, _Pr _Pred, true_type, _Any_tag) {
|
|
// copy compressing pairs satisfying _Pred, forward source iterator
|
|
// (can reread the source for comparison)
|
|
if (_First != _Last) {
|
|
_FwdIt _Firstb = _First;
|
|
|
|
*_Dest = *_Firstb;
|
|
++_Dest;
|
|
|
|
while (++_First != _Last) {
|
|
if (!_Pred(*_Firstb, *_First)) { // copy unmatched
|
|
_Firstb = _First;
|
|
*_Dest = *_Firstb;
|
|
++_Dest;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Dest;
|
|
}
|
|
|
|
template <class _InIt, class _FwdIt, class _Pr>
|
|
_FwdIt _Unique_copy_unchecked(_InIt _First, _InIt _Last, _FwdIt _Dest, _Pr _Pred, false_type, true_type) {
|
|
// copy compressing pairs satisfying _Pred, forward dest iterator with matching T
|
|
// (assignment copies T; can reread dest for comparison)
|
|
if (_First != _Last) {
|
|
*_Dest = *_First;
|
|
|
|
while (++_First != _Last) {
|
|
if (!_Pred(*_Dest, *_First)) {
|
|
*++_Dest = *_First;
|
|
}
|
|
}
|
|
|
|
++_Dest;
|
|
}
|
|
|
|
return _Dest;
|
|
}
|
|
|
|
template <class _InIt, class _OutIt, class _Pr>
|
|
_OutIt _Unique_copy_unchecked(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred, false_type, false_type) {
|
|
// copy compressing pairs satisfying _Pred, otherwise
|
|
// (can't reread source or dest, construct a temporary)
|
|
if (_First != _Last) {
|
|
_Iter_value_t<_InIt> _Val = *_First;
|
|
|
|
*_Dest = _Val;
|
|
++_Dest;
|
|
|
|
while (++_First != _Last) {
|
|
if (!_Pred(_Val, *_First)) { // copy unmatched
|
|
_Val = *_First;
|
|
*_Dest = _Val;
|
|
++_Dest;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Dest;
|
|
}
|
|
|
|
template <class _InIt, class _OutIt, class _Pr>
|
|
_OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest, _Pr _Pred) { // copy compressing pairs that match
|
|
_Adl_verify_range(_First, _Last);
|
|
_Seek_wrapped(
|
|
_Dest, _Unique_copy_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Get_unwrapped_unverified(_Dest),
|
|
_Pass_fn(_Pred), bool_constant<_Is_fwd_iter_v<_InIt>>{}, // to avoid ambiguity
|
|
bool_constant<conjunction_v<bool_constant<_Is_fwd_iter_v<_OutIt>>,
|
|
is_same<_Iter_value_t<_InIt>, _Iter_value_t<_OutIt>>>>{}));
|
|
|
|
return _Dest;
|
|
}
|
|
#endif // _HAS_IF_CONSTEXPR
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* unique_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// copy compressing pairs that match, array dest
|
|
return _STD unique_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _InIt, class _OutIt>
|
|
_CONSTEXPR20 _OutIt unique_copy(_InIt _First, _InIt _Last, _OutIt _Dest) { // copy compressing pairs that match
|
|
return _STD unique_copy(_First, _Last, _Dest, equal_to<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* unique_copy(_InIt _First, _InIt _Last, _DestTy (&_Dest)[_DestSize]) {
|
|
// copy compressing pairs that match, array dest
|
|
return _STD unique_copy(_First, _Last, _Dest, equal_to<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 unique_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _Pr _Pred) noexcept /* terminates */ {
|
|
// copy compressing pairs that match
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD unique_copy(_First, _Last, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* unique_copy(
|
|
_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// copy compressing pairs that match, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD unique_copy(_First, _Last, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 unique_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest) noexcept /* terminates */ {
|
|
// copy compressing pairs that match
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD unique_copy(_First, _Last, _Dest);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _DestTy, size_t _DestSize, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* unique_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// copy compressing pairs that match, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
return _STD unique_copy(_First, _Last, _Dest);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE reverse_copy
|
|
template <class _BidIt, class _OutIt>
|
|
_CONSTEXPR20 _OutIt reverse_copy(_BidIt _First, _BidIt _Last, _OutIt _Dest) {
|
|
// copy reversing elements in [_First, _Last)
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_BidIt>(_UFirst, _ULast));
|
|
for (; _UFirst != _ULast; ++_UDest) {
|
|
*_UDest = *--_ULast;
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _BidIt, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* reverse_copy(_BidIt _First, _BidIt _Last, _DestTy (&_Dest)[_DestSize]) {
|
|
// copy reversing elements in [_First, _Last), array dest
|
|
return _STD reverse_copy(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest))._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _BidIt, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt reverse_copy(_ExPo&&, _BidIt _First, _BidIt _Last, _FwdIt _Dest) noexcept /* terminates */ {
|
|
// copy reversing elements in [_First, _Last)
|
|
// not parallelized as benchmarks show it isn't worth it
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt);
|
|
return _STD reverse_copy(_First, _Last, _Dest);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _BidIt, class _DestTy, size_t _DestSize, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* reverse_copy(_ExPo&&, _BidIt _First, _BidIt _Last, _DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// copy reversing elements in [_First, _Last), array dest
|
|
// not parallelized as benchmarks show it isn't worth it
|
|
return _STD reverse_copy(_First, _Last, _Dest);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE rotate_copy
|
|
template <class _FwdIt, class _OutIt>
|
|
_CONSTEXPR20 _OutIt rotate_copy(_FwdIt _First, _FwdIt _Mid, _FwdIt _Last, _OutIt _Dest) {
|
|
// copy rotating [_First, _Last)
|
|
_Adl_verify_range(_First, _Mid);
|
|
_Adl_verify_range(_Mid, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _UMid = _Get_unwrapped(_Mid);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_FwdIt>(_UFirst, _ULast));
|
|
_UDest = _Copy_unchecked(_UMid, _ULast, _UDest);
|
|
_Seek_wrapped(_Dest, _Copy_unchecked(_UFirst, _UMid, _UDest));
|
|
return _Dest;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt2 rotate_copy(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Mid, _FwdIt1 _Last, _FwdIt2 _Dest) noexcept /* terminates */ {
|
|
// copy rotating [_First, _Last)
|
|
// not parallelized as benchmarks show it isn't worth it
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD rotate_copy(_First, _Mid, _Last, _Dest);
|
|
}
|
|
|
|
// FUNCTION TEMPLATE sample
|
|
template <class _PopIt, class _SampleIt, class _Diff, class _RngFn>
|
|
_SampleIt _Sample_reservoir_unchecked(
|
|
_PopIt _First, const _PopIt _Last, const _SampleIt _Dest, const _Diff _Count, _RngFn& _RngFunc) {
|
|
// source is input: use reservoir sampling (unstable)
|
|
// pre: _SampleIt is random-access && 0 < _Count && the range [_Dest, _Dest + _Count) is valid
|
|
using _Diff_sample = _Iter_diff_t<_SampleIt>;
|
|
const auto _SCount = static_cast<_Diff_sample>(_Count);
|
|
_Iter_diff_t<_PopIt> _PopSize{};
|
|
for (; _PopSize < _SCount; ++_PopSize, (void) ++_First) {
|
|
// _PopSize is less than _SCount, and [_Dest, _Dest + _SCount) is valid,
|
|
// so [_Dest, _Dest + _PopSize) must be valid, so narrowing to _Diff_sample
|
|
// can't overflow
|
|
const auto _Sample_pop = static_cast<_Diff_sample>(_PopSize);
|
|
if (_First == _Last) {
|
|
return _Dest + _Sample_pop;
|
|
}
|
|
|
|
*(_Dest + _Sample_pop) = *_First;
|
|
}
|
|
for (; _First != _Last; ++_First) {
|
|
const auto _Idx = _RngFunc(++_PopSize);
|
|
if (_Idx < _SCount) {
|
|
*(_Dest + static_cast<_Diff_sample>(_Idx)) = *_First; // again, valid narrowing because _Idx < _SCount
|
|
}
|
|
}
|
|
return _Dest + _SCount;
|
|
}
|
|
|
|
template <class _PopIt, class _SampleIt, class _Diff, class _RngFn>
|
|
_SampleIt _Sample_selection_unchecked(
|
|
_PopIt _First, const _PopIt _Last, _Iter_diff_t<_PopIt> _PopSize, _SampleIt _Dest, _Diff _Count, _RngFn& _RngFunc) {
|
|
// source is forward *and* we know the source range size: use selection sampling (stable)
|
|
// pre: _PopIt is forward && _Count <= _PopSize
|
|
using _CT = common_type_t<_Iter_diff_t<_PopIt>, _Diff>;
|
|
for (; _Count > 0 && _First != _Last; ++_First, (void) --_PopSize) {
|
|
if (static_cast<_CT>(_RngFunc(_PopSize)) < static_cast<_CT>(_Count)) {
|
|
--_Count;
|
|
*_Dest = *_First;
|
|
++_Dest;
|
|
}
|
|
}
|
|
return _Dest;
|
|
}
|
|
|
|
template <class _PopIt, class _SampleIt, class _Diff, class _RngFn>
|
|
_SampleIt _Sample1(_PopIt _First, _PopIt _Last, _SampleIt _Dest, _Diff _Count, _RngFn& _RngFunc, input_iterator_tag) {
|
|
// source is input: use reservoir sampling (unstable)
|
|
// pre: _Count > 0
|
|
_Seek_wrapped(
|
|
_Dest, _Sample_reservoir_unchecked(_First, _Last, _Get_unwrapped_unverified(_Dest), _Count, _RngFunc));
|
|
return _Dest;
|
|
}
|
|
|
|
template <class _PopIt, class _SampleIt, class _Diff, class _RngFn>
|
|
_SampleIt _Sample1(_PopIt _First, _PopIt _Last, _SampleIt _Dest, _Diff _Count, _RngFn& _RngFunc, forward_iterator_tag) {
|
|
// source is forward: use selection sampling (stable)
|
|
// pre: _Count > 0
|
|
using _PopDiff = _Iter_diff_t<_PopIt>;
|
|
using _CT = common_type_t<_Diff, _PopDiff>;
|
|
const auto _PopSize = _STD distance(_First, _Last);
|
|
if (static_cast<_CT>(_Count) > static_cast<_CT>(_PopSize)) {
|
|
_Count = static_cast<_Diff>(_PopSize); // narrowing OK because _Count is getting smaller
|
|
}
|
|
|
|
_Seek_wrapped(
|
|
_Dest, _Sample_selection_unchecked(_First, _Last, _PopSize, _Get_unwrapped_n(_Dest, _Count), _Count, _RngFunc));
|
|
return _Dest;
|
|
}
|
|
|
|
template <class _PopIt, class _SampleIt, class _Diff, class _Urng>
|
|
_SampleIt sample(_PopIt _First, _PopIt _Last, _SampleIt _Dest, _Diff _Count,
|
|
_Urng&& _Func) { // randomly select _Count elements from [_First, _Last) into _Dest
|
|
static_assert(_Is_fwd_iter_v<_PopIt> || _Is_random_iter_v<_SampleIt>,
|
|
"If the source range is not forward, the destination range must be random-access.");
|
|
static_assert(is_integral_v<_Diff>, "The sample size must have an integer type.");
|
|
_Adl_verify_range(_First, _Last);
|
|
if (0 < _Count) {
|
|
_Rng_from_urng<_Iter_diff_t<_PopIt>, remove_reference_t<_Urng>> _RngFunc(_Func);
|
|
_Dest = _Sample1(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Dest, _Count, _RngFunc, _Iter_cat_t<_PopIt>());
|
|
}
|
|
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _PopIt, class _DestTy, size_t _DestSize, class _Diff, class _Urng>
|
|
_DestTy* sample(_PopIt _First, _PopIt _Last, _DestTy (&_Dest)[_DestSize], _Diff _Count, _Urng&& _Func) {
|
|
// randomly select _Count elements from [_First, _Last) into _Dest
|
|
return _STD sample(_First, _Last, _Array_iterator<_DestTy, _DestSize>(_Dest), _Count, _Func)._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE shuffle WITH URNG
|
|
template <class _RanIt, class _RngFn>
|
|
void _Random_shuffle1(_RanIt _First, _RanIt _Last, _RngFn& _RngFunc) {
|
|
// shuffle [_First, _Last) using random function _RngFunc
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
if (_UFirst == _ULast) {
|
|
return;
|
|
}
|
|
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
auto _UTarget = _UFirst;
|
|
_Diff _Target_index = 1;
|
|
for (; ++_UTarget != _ULast; ++_Target_index) { // randomly place an element from [_First, _Target] at _Target
|
|
_Diff _Off = _RngFunc(static_cast<_Diff>(_Target_index + 1));
|
|
_STL_ASSERT(0 <= _Off && _Off <= _Target_index, "random value out of range");
|
|
if (_Off != _Target_index) { // avoid self-move-assignment
|
|
_STD iter_swap(_UTarget, _UFirst + _Off);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Urng>
|
|
void shuffle(_RanIt _First, _RanIt _Last, _Urng&& _Func) { // shuffle [_First, _Last) using URNG _Func
|
|
using _Urng0 = remove_reference_t<_Urng>;
|
|
_Rng_from_urng<_Iter_diff_t<_RanIt>, _Urng0> _RngFunc(_Func);
|
|
_Random_shuffle1(_First, _Last, _RngFunc);
|
|
}
|
|
|
|
#if _HAS_AUTO_PTR_ETC
|
|
// FUNCTION TEMPLATE random_shuffle WITH RANDOM FN
|
|
template <class _RanIt, class _RngFn>
|
|
void random_shuffle(_RanIt _First, _RanIt _Last, _RngFn&& _RngFunc) {
|
|
// shuffle [_First, _Last) using random function _RngFunc
|
|
_Random_shuffle1(_First, _Last, _RngFunc);
|
|
}
|
|
|
|
// STRUCT _Rand_urng_from_func
|
|
struct _Rand_urng_from_func { // wrap rand() as a URNG
|
|
using result_type = unsigned int;
|
|
|
|
static result_type(min)() { // return minimum possible generated value
|
|
return 0;
|
|
}
|
|
|
|
static result_type(max)() { // return maximum possible generated value
|
|
return RAND_MAX;
|
|
}
|
|
|
|
result_type operator()() { // invoke rand()
|
|
return static_cast<result_type>(_CSTD rand());
|
|
}
|
|
};
|
|
|
|
// FUNCTION TEMPLATE random_shuffle
|
|
template <class _RanIt>
|
|
void random_shuffle(_RanIt _First, _RanIt _Last) { // shuffle [_First, _Last) using rand()
|
|
_Rand_urng_from_func _Func;
|
|
_STD shuffle(_First, _Last, _Func);
|
|
}
|
|
#endif // _HAS_AUTO_PTR_ETC
|
|
|
|
#if _HAS_CXX20
|
|
// FUNCTION TEMPLATE shift_left
|
|
template <class _FwdIt>
|
|
constexpr _FwdIt shift_left(_FwdIt _First, const _FwdIt _Last, _Iter_diff_t<_FwdIt> _Pos_to_shift) {
|
|
// shift [_First, _Last) left by _Pos_to_shift
|
|
// positions; returns the end of the resulting range
|
|
_Adl_verify_range(_First, _Last);
|
|
|
|
if (_Pos_to_shift <= 0) {
|
|
return _Last;
|
|
}
|
|
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _Start_at = _UFirst;
|
|
|
|
if constexpr (_Is_random_iter_v<_FwdIt>) {
|
|
if (_Pos_to_shift >= _ULast - _UFirst) {
|
|
return _First;
|
|
}
|
|
_Start_at += _Pos_to_shift;
|
|
} else {
|
|
for (; 0 < _Pos_to_shift; --_Pos_to_shift) {
|
|
if (_Start_at == _ULast) {
|
|
return _First;
|
|
}
|
|
++_Start_at;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First, _Move_unchecked(_Start_at, _ULast, _UFirst));
|
|
return _First;
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt shift_left(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Iter_diff_t<_FwdIt> _Pos_to_shift) noexcept /* terminates */ {
|
|
// shift [_First, _Last) left by _Pos_to_shift positions
|
|
// not parallelized as benchmarks show it isn't worth it
|
|
return _STD shift_left(_First, _Last, _Pos_to_shift);
|
|
}
|
|
|
|
// FUNCTION TEMPLATE shift_right
|
|
template <class _FwdIt>
|
|
constexpr _FwdIt shift_right(_FwdIt _First, const _FwdIt _Last, _Iter_diff_t<_FwdIt> _Pos_to_shift) {
|
|
// shift [_First, _Last) right by _Pos_to_shift
|
|
// positions; returns the beginning of the resulting range
|
|
_Adl_verify_range(_First, _Last);
|
|
|
|
if (_Pos_to_shift <= 0) {
|
|
return _First;
|
|
}
|
|
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
if constexpr (_Is_bidi_iter_v<_FwdIt>) {
|
|
auto _UEnd_at = _ULast;
|
|
if constexpr (_Is_random_iter_v<_FwdIt>) {
|
|
if (_Pos_to_shift >= _ULast - _UFirst) {
|
|
return _Last;
|
|
}
|
|
_UEnd_at -= _Pos_to_shift;
|
|
} else {
|
|
for (; 0 < _Pos_to_shift; --_Pos_to_shift) {
|
|
if (_UEnd_at == _UFirst) {
|
|
return _Last;
|
|
}
|
|
--_UEnd_at;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First, _Move_backward_unchecked(_UFirst, _UEnd_at, _ULast));
|
|
return _First;
|
|
} else {
|
|
auto _UResult = _UFirst;
|
|
|
|
for (; 0 < _Pos_to_shift; --_Pos_to_shift) {
|
|
if (_UResult == _ULast) {
|
|
return _Last;
|
|
}
|
|
++_UResult;
|
|
}
|
|
_Seek_wrapped(_First, _UResult);
|
|
|
|
auto _Trail = _UFirst;
|
|
auto _Lead = _UResult;
|
|
|
|
for (; _Trail != _UResult; ++_Trail, (void) ++_Lead) {
|
|
if (_Lead == _ULast) {
|
|
_Move_unchecked(_UFirst, _Trail, _UResult);
|
|
|
|
return _First;
|
|
}
|
|
}
|
|
|
|
// Here, _Trail = _UFirst + original _Pos_to_shift
|
|
// Here, _Lead = _UFirst + 2 * original _Pos_to_shift
|
|
|
|
for (;;) {
|
|
// This loop swaps the range [_UFirst, _UResult) with [_Trail, _Lead),
|
|
// advancing _Trail and _Lead by _Pos_to_shift
|
|
for (auto _Mid = _UFirst; _Mid != _UResult; ++_Mid, (void) ++_Trail, ++_Lead) {
|
|
if (_Lead == _ULast) {
|
|
_Trail = _Move_unchecked(_Mid, _UResult, _Trail);
|
|
_Move_unchecked(_UFirst, _Mid, _Trail);
|
|
|
|
return _First;
|
|
}
|
|
_Swap_adl(*_Mid, *_Trail);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt shift_right(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Iter_diff_t<_FwdIt> _Pos_to_shift) noexcept /* terminates */ {
|
|
// shift [_First, _Last) right by _Pos_to_shift positions
|
|
// not parallelized as benchmarks show it isn't worth it
|
|
return _STD shift_right(_First, _Last, _Pos_to_shift);
|
|
}
|
|
#endif // _HAS_CXX20
|
|
|
|
// FUNCTION TEMPLATE partition
|
|
#if _HAS_IF_CONSTEXPR
|
|
template <class _FwdIt, class _Pr>
|
|
_CONSTEXPR20 _FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) {
|
|
// move elements satisfying _Pred to beginning of sequence
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
auto _ULast = _Get_unwrapped(_Last);
|
|
if constexpr (_Is_bidi_iter_v<_FwdIt>) {
|
|
for (;;) { // find any out-of-order pair
|
|
for (;;) { // skip in-place elements at beginning
|
|
if (_UFirst == _ULast) {
|
|
_Seek_wrapped(_First, _UFirst);
|
|
return _First;
|
|
}
|
|
|
|
if (!_Pred(*_UFirst)) {
|
|
break;
|
|
}
|
|
|
|
++_UFirst;
|
|
}
|
|
|
|
do { // skip in-place elements at end
|
|
--_ULast;
|
|
if (_UFirst == _ULast) {
|
|
_Seek_wrapped(_First, _UFirst);
|
|
return _First;
|
|
}
|
|
} while (!_Pred(*_ULast));
|
|
|
|
_STD iter_swap(_UFirst, _ULast); // out of place, swap and loop
|
|
++_UFirst;
|
|
}
|
|
} else {
|
|
for (;;) { // skip in-place elements at beginning
|
|
if (_UFirst == _ULast) {
|
|
_Seek_wrapped(_First, _UFirst);
|
|
return _First;
|
|
}
|
|
|
|
if (!_Pred(*_UFirst)) {
|
|
break;
|
|
}
|
|
|
|
++_UFirst;
|
|
}
|
|
|
|
for (auto _UNext = _UFirst; ++_UNext != _ULast;) {
|
|
if (_Pred(*_UNext)) {
|
|
_STD iter_swap(_UFirst, _UNext); // out of place, swap and loop
|
|
++_UFirst;
|
|
}
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First, _UFirst);
|
|
return _First;
|
|
}
|
|
#else // ^^^ _HAS_IF_CONSTEXPR ^^^ // vvv !_HAS_IF_CONSTEXPR vvv
|
|
template <class _FwdIt, class _Pr>
|
|
_FwdIt _Partition_unchecked(_FwdIt _First, const _FwdIt _Last, _Pr _Pred, forward_iterator_tag) {
|
|
// move elements satisfying _Pred to front, forward iterators
|
|
for (;;) { // skip in-place elements at beginning
|
|
if (_First == _Last) {
|
|
return _First;
|
|
}
|
|
|
|
if (!_Pred(*_First)) {
|
|
break;
|
|
}
|
|
|
|
++_First;
|
|
}
|
|
|
|
for (_FwdIt _Next = _First; ++_Next != _Last;) {
|
|
if (_Pred(*_Next)) {
|
|
_STD iter_swap(_First, _Next); // out of place, swap and loop
|
|
++_First;
|
|
}
|
|
}
|
|
|
|
return _First;
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
_BidIt _Partition_unchecked(_BidIt _First, _BidIt _Last, _Pr _Pred, bidirectional_iterator_tag) {
|
|
// move elements satisfying _Pred to front, bidirectional iterators
|
|
for (;;) { // find any out-of-order pair
|
|
for (;;) { // skip in-place elements at beginning
|
|
if (_First == _Last) {
|
|
return _First;
|
|
}
|
|
|
|
if (!_Pred(*_First)) {
|
|
break;
|
|
}
|
|
|
|
++_First;
|
|
}
|
|
|
|
do { // skip in-place elements at end
|
|
--_Last;
|
|
if (_First == _Last) {
|
|
return _First;
|
|
}
|
|
} while (!_Pred(*_Last));
|
|
|
|
_STD iter_swap(_First, _Last); // out of place, swap and loop
|
|
++_First;
|
|
}
|
|
}
|
|
|
|
template <class _FwdIt, class _Pr>
|
|
_FwdIt partition(_FwdIt _First, const _FwdIt _Last, _Pr _Pred) {
|
|
// move elements satisfying _Pred to beginning of sequence
|
|
_Adl_verify_range(_First, _Last);
|
|
_Seek_wrapped(_First,
|
|
_Partition_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred), _Iter_cat_t<_FwdIt>()));
|
|
|
|
return _First;
|
|
}
|
|
#endif // _HAS_IF_CONSTEXPR
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt partition(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE stable_partition
|
|
template <class _BidIt>
|
|
_BidIt _Buffered_rotate_unchecked(const _BidIt _First, const _BidIt _Mid, const _BidIt _Last,
|
|
const _Iter_diff_t<_BidIt> _Count1, const _Iter_diff_t<_BidIt> _Count2, _Iter_value_t<_BidIt>* const _Temp_ptr,
|
|
const ptrdiff_t _Capacity) { // rotate [_First, _Last) using temp buffer
|
|
// precondition: _Count1 == distance(_First, _Mid)
|
|
// precondition: _Count2 == distance(_Mid, _Last)
|
|
if (_Count1 == 0) {
|
|
return _Last;
|
|
}
|
|
|
|
if (_Count2 == 0) {
|
|
return _First;
|
|
}
|
|
|
|
if (_Count1 <= _Count2 && _Count1 <= _Capacity) { // buffer left range, then copy parts
|
|
_Uninitialized_backout<_Iter_value_t<_BidIt>*> _Backout{
|
|
_Temp_ptr, _Uninitialized_move_unchecked(_First, _Mid, _Temp_ptr)};
|
|
const _BidIt _New_mid = _Move_unchecked(_Mid, _Last, _First);
|
|
_Move_unchecked(_Backout._First, _Backout._Last, _New_mid);
|
|
return _New_mid; // _Backout destroys elements in temporary buffer
|
|
}
|
|
|
|
if (_Count2 <= _Capacity) { // buffer right range, then copy parts
|
|
_Uninitialized_backout<_Iter_value_t<_BidIt>*> _Backout{
|
|
_Temp_ptr, _Uninitialized_move_unchecked(_Mid, _Last, _Temp_ptr)};
|
|
_Move_backward_unchecked(_First, _Mid, _Last);
|
|
return _Move_unchecked(_Backout._First, _Backout._Last, _First); // ditto _Backout destroys elements
|
|
}
|
|
|
|
// buffer too small, rotate in place
|
|
return _STD rotate(_First, _Mid, _Last);
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
pair<_BidIt, _Iter_diff_t<_BidIt>> _Stable_partition_unchecked1(_BidIt _First, _BidIt _Last, _Pr _Pred,
|
|
const _Iter_diff_t<_BidIt> _Count, _Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity) {
|
|
// implement stable_partition of [_First, _Last] (note: closed range)
|
|
// precondition: !_Pred(*_First)
|
|
// precondition: _Pred(*_Last)
|
|
// precondition: distance(_First, _Last) + 1 == _Count
|
|
// note: _Count >= 2 and _First != _Last
|
|
// returns: a pair such that first is the partition point, and second is distance(_First, partition point)
|
|
using _Diff = _Iter_diff_t<_BidIt>;
|
|
if (_Count - static_cast<_Diff>(1) <= _Capacity) { // - 1 since we never need to store *_Last
|
|
_Uninitialized_backout<_Iter_value_t<_BidIt>*> _Backout{_Temp_ptr};
|
|
_BidIt _Next = _First;
|
|
_Backout._Emplace_back(_STD move(*_First));
|
|
while (++_First != _Last) { // test each element, copying to _Temp_ptr if it's in the false range, or assigning
|
|
// backwards if it's in the true range
|
|
if (_Pred(*_First)) {
|
|
*_Next = _STD move(*_First);
|
|
++_Next;
|
|
} else {
|
|
_Backout._Emplace_back(_STD move(*_First));
|
|
}
|
|
}
|
|
|
|
// move the last true element, *_Last, to the end of the true range
|
|
*_Next = _STD move(*_Last);
|
|
++_Next;
|
|
_Move_unchecked(_Backout._First, _Backout._Last, _Next); // copy back the false range
|
|
_Diff _True_distance = static_cast<_Diff>(_Count - static_cast<_Diff>(_Backout._Last - _Backout._First));
|
|
return pair<_BidIt, _Diff>(_Next, _True_distance); // _Backout destroys elements
|
|
}
|
|
|
|
const _Diff _Mid_offset = _Count / static_cast<_Diff>(2); // note: >= 1 because _Count >= 2
|
|
const _BidIt _Mid = _STD next(_First, _Mid_offset);
|
|
|
|
// form [_First, _Left) true range, [_Left, _Mid) false range
|
|
_BidIt _Left = _Mid;
|
|
_Diff _Left_true_count = _Mid_offset;
|
|
for (;;) { // skip over the trailing false range before _Mid
|
|
--_Left;
|
|
if (_First == _Left) { // the entire left range is false
|
|
--_Left_true_count; // to exclude *_First
|
|
break;
|
|
}
|
|
|
|
if (_Pred(*_Left)) { // excluded the false range before _Mid, invariants reestablished, recurse
|
|
const pair<_BidIt, _Diff> _Low =
|
|
_Stable_partition_unchecked1(_First, _Left, _Pred, _Left_true_count, _Temp_ptr, _Capacity);
|
|
_Left = _Low.first;
|
|
_Left_true_count = _Low.second;
|
|
break;
|
|
}
|
|
|
|
--_Left_true_count;
|
|
}
|
|
|
|
// form [_Mid, _Right) true range, [_Right, next(_Last)) false range
|
|
_BidIt _Right = _Mid;
|
|
_Diff _Right_true_count = 0;
|
|
for (;;) { // skip over the leading true range after and including _Mid
|
|
if (_Right == _Last) { // the entire right range is true
|
|
++_Right; // to include _Last
|
|
++_Right_true_count;
|
|
break;
|
|
}
|
|
|
|
if (!_Pred(*_Right)) { // excluded the true range after and including _Mid, invariants reestablished, recurse
|
|
const _Diff _Right_count = _Count - _Mid_offset;
|
|
const _Diff _Remaining = _Right_count - _Right_true_count;
|
|
const pair<_BidIt, _Diff> _High =
|
|
_Stable_partition_unchecked1(_Right, _Last, _Pred, _Remaining, _Temp_ptr, _Capacity);
|
|
_Right = _High.first;
|
|
_Right_true_count += _High.second;
|
|
break;
|
|
}
|
|
|
|
++_Right;
|
|
++_Right_true_count;
|
|
}
|
|
|
|
// swap the [_Left, _Mid) false range with the [_Mid, _Right) true range
|
|
const _BidIt _Partition_point = _Buffered_rotate_unchecked(_Left, _Mid, _Right,
|
|
static_cast<_Diff>(_Mid_offset - _Left_true_count), _Right_true_count, _Temp_ptr, _Capacity);
|
|
return pair<_BidIt, _Diff>(_Partition_point, static_cast<_Diff>(_Left_true_count + _Right_true_count));
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
_BidIt _Stable_partition_unchecked(_BidIt _First, _BidIt _Last, _Pr _Pred) {
|
|
// partition preserving order of equivalents, using _Pred
|
|
for (;;) {
|
|
if (_First == _Last) { // the input range range is true (already partitioned)
|
|
return _First;
|
|
}
|
|
|
|
if (!_Pred(*_First)) { // excluded the leading true range
|
|
break;
|
|
}
|
|
|
|
++_First;
|
|
}
|
|
|
|
for (;;) {
|
|
--_Last;
|
|
if (_First == _Last) { // the input range is already partitioned
|
|
return _First;
|
|
}
|
|
|
|
if (_Pred(*_Last)) { // excluded the trailing false range
|
|
break;
|
|
}
|
|
}
|
|
|
|
using _Diff = _Iter_diff_t<_BidIt>;
|
|
const _Diff _Temp_count = _STD distance(_First, _Last); // _Total_count - 1 since we never need to store *_Last
|
|
const _Diff _Total_count = _Temp_count + static_cast<_Diff>(1);
|
|
_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{_Temp_count};
|
|
return _Stable_partition_unchecked1(_First, _Last, _Pred, _Total_count, _Temp_buf._Data, _Temp_buf._Capacity).first;
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
_BidIt stable_partition(_BidIt _First, _BidIt _Last, _Pr _Pred) {
|
|
// partition preserving order of equivalents, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
_Seek_wrapped(_First, _Stable_partition_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred)));
|
|
return _First;
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _BidIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_BidIt stable_partition(_ExPo&&, _BidIt _First, _BidIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// partition preserving order of equivalents, using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD stable_partition(_First, _Last, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE push_heap
|
|
template <class _RanIt, class _Ty, class _Pr>
|
|
_CONSTEXPR20 void _Push_heap_by_index(
|
|
_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) {
|
|
// percolate _Hole to _Top or where _Val belongs, using _Pred
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen
|
|
_Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val); //
|
|
_Idx = (_Hole - 1) >> 1) { // shift for codegen
|
|
// move _Hole up to parent
|
|
*(_First + _Hole) = _STD move(*(_First + _Idx));
|
|
_Hole = _Idx;
|
|
}
|
|
|
|
*(_First + _Hole) = _STD move(_Val); // drop _Val into final hole
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// push *(_Last - 1) onto heap at [_First, _Last - 1), using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
auto _ULast = _Get_unwrapped(_Last);
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
_Diff _Count = _ULast - _UFirst;
|
|
if (2 <= _Count) {
|
|
_Iter_value_t<_RanIt> _Val = _STD move(*--_ULast);
|
|
_Push_heap_by_index(_UFirst, --_Count, _Diff(0), _STD move(_Val), _Pass_fn(_Pred));
|
|
}
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) {
|
|
// push *(_Last - 1) onto heap at [_First, _Last - 1), using operator<
|
|
_STD push_heap(_First, _Last, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE pop_heap
|
|
template <class _RanIt, class _Ty, class _Pr>
|
|
_CONSTEXPR20 void _Pop_heap_hole_by_index(
|
|
_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Bottom, _Ty&& _Val, _Pr _Pred) {
|
|
// percolate _Hole to _Bottom, then push _Val, using _Pred
|
|
_STL_INTERNAL_CHECK(_Bottom != 0);
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
const _Diff _Top = _Hole;
|
|
_Diff _Idx = _Hole;
|
|
|
|
// Check whether _Idx can have a child before calculating that child's index, since
|
|
// calculating the child's index can trigger integer overflows
|
|
const _Diff _Max_sequence_non_leaf = (_Bottom - 1) >> 1; // shift for codegen
|
|
while (_Idx < _Max_sequence_non_leaf) { // move _Hole down to larger child
|
|
_Idx = 2 * _Idx + 2;
|
|
if (_DEBUG_LT_PRED(_Pred, *(_First + _Idx), *(_First + (_Idx - 1)))) {
|
|
--_Idx;
|
|
}
|
|
*(_First + _Hole) = _STD move(*(_First + _Idx));
|
|
_Hole = _Idx;
|
|
}
|
|
|
|
if (_Idx == _Max_sequence_non_leaf && _Bottom % 2 == 0) { // only child at bottom, move _Hole down to it
|
|
*(_First + _Hole) = _STD move(*(_First + (_Bottom - 1)));
|
|
_Hole = _Bottom - 1;
|
|
}
|
|
|
|
_Push_heap_by_index(_First, _Hole, _Top, _STD move(_Val), _Pred);
|
|
}
|
|
|
|
template <class _RanIt, class _Ty, class _Pr>
|
|
_CONSTEXPR20 void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _Dest, _Ty&& _Val, _Pr _Pred) {
|
|
// pop *_First to *_Dest and reheap, using _Pred
|
|
// precondition: _First != _Last
|
|
// precondition: _First != _Dest
|
|
*_Dest = _STD move(*_First);
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
_Pop_heap_hole_by_index(_First, static_cast<_Diff>(0), static_cast<_Diff>(_Last - _First), _STD move(_Val), _Pred);
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// pop *_First to *(_Last - 1) and reheap, using _Pred
|
|
if (2 <= _Last - _First) {
|
|
--_Last;
|
|
_Iter_value_t<_RanIt> _Val = _STD move(*_Last);
|
|
_Pop_heap_hole_unchecked(_First, _Last, _Last, _STD move(_Val), _Pred);
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// pop *_First to *(_Last - 1) and reheap, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
_Pop_heap_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) {
|
|
// pop *_First to *(_Last - 1) and reheap, using operator<
|
|
_STD pop_heap(_First, _Last, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE make_heap
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// make nontrivial [_First, _Last) into a heap, using _Pred
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
_Diff _Bottom = _Last - _First;
|
|
for (_Diff _Hole = _Bottom >> 1; 0 < _Hole;) { // shift for codegen
|
|
// reheap top half, bottom to top
|
|
--_Hole;
|
|
_Iter_value_t<_RanIt> _Val = _STD move(*(_First + _Hole));
|
|
_Pop_heap_hole_by_index(_First, _Hole, _Bottom, _STD move(_Val), _Pred);
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // make [_First, _Last) into a heap, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
_Make_heap_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Last) into a heap, using operator<
|
|
_STD make_heap(_First, _Last, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATES is_heap AND is_heap_until
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 _RanIt _Is_heap_until_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// find extent of range that is a heap ordered by _Pred
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
const _Diff _Size = _Last - _First;
|
|
for (_Diff _Off = 1; _Off < _Size; ++_Off) {
|
|
if (_DEBUG_LT_PRED(_Pred, *(_First + ((_Off - 1) >> 1)), *(_First + _Off))) { // shift for codegen
|
|
return _First + _Off;
|
|
}
|
|
}
|
|
|
|
return _Last;
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _RanIt is_heap_until(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// find extent of range that is a heap ordered by _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
_Seek_wrapped(_First, _Is_heap_until_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred)));
|
|
return _First;
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool is_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// test if range is a heap ordered by _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
return _Is_heap_until_unchecked(_UFirst, _ULast, _Pass_fn(_Pred)) == _ULast;
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_NODISCARD _CONSTEXPR20 _RanIt is_heap_until(_RanIt _First, _RanIt _Last) {
|
|
// find extent of range that is a heap ordered by operator<
|
|
return _STD is_heap_until(_First, _Last, less<>());
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_NODISCARD _CONSTEXPR20 bool is_heap(_RanIt _First, _RanIt _Last) { // test if range is a heap ordered by operator<
|
|
return _STD is_heap(_First, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _RanIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _RanIt is_heap_until(_ExPo&& _Exec, _RanIt _First, _RanIt _Last, _Pr _Pred) noexcept; // terminates
|
|
|
|
template <class _ExPo, class _RanIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool is_heap(_ExPo&& _Exec, _RanIt _First, _RanIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// test if range is a heap ordered by _Pred
|
|
return _STD is_heap_until(_STD forward<_ExPo>(_Exec), _First, _Last, _Pass_fn(_Pred)) == _Last;
|
|
}
|
|
|
|
template <class _ExPo, class _RanIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _RanIt is_heap_until(_ExPo&& _Exec, _RanIt _First, _RanIt _Last) noexcept /* terminates */ {
|
|
// find extent of range that is a heap ordered by operator<
|
|
return _STD is_heap_until(_STD forward<_ExPo>(_Exec), _First, _Last, less{});
|
|
}
|
|
|
|
template <class _ExPo, class _RanIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool is_heap(_ExPo&& _Exec, _RanIt _First, _RanIt _Last) noexcept /* terminates */ {
|
|
// test if range is a heap ordered by operator<
|
|
return _STD is_heap(_STD forward<_ExPo>(_Exec), _First, _Last, less{});
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE sort_heap
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void _Sort_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// order heap by repeatedly popping, using _Pred
|
|
for (; 2 <= _Last - _First; --_Last) {
|
|
_Pop_heap_unchecked(_First, _Last, _Pred);
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order heap by repeatedly popping, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
#if _ITERATOR_DEBUG_LEVEL == 2
|
|
const auto _Counterexample = _Is_heap_until_unchecked(_UFirst, _ULast, _Pass_fn(_Pred));
|
|
if (_Counterexample != _ULast) {
|
|
_STL_REPORT_ERROR("invalid heap in sort_heap()");
|
|
}
|
|
#endif // _ITERATOR_DEBUG_LEVEL == 2
|
|
_Sort_heap_unchecked(_UFirst, _ULast, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repeatedly popping, using operator<
|
|
_STD sort_heap(_First, _Last, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE upper_bound
|
|
template <class _FwdIt, class _Ty, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) {
|
|
// find first element that _Val is before, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
_Iter_diff_t<_FwdIt> _Count = _STD distance(_UFirst, _Get_unwrapped(_Last));
|
|
|
|
while (0 < _Count) { // divide and conquer, find half that contains answer
|
|
_Iter_diff_t<_FwdIt> _Count2 = _Count / 2;
|
|
const auto _UMid = _STD next(_UFirst, _Count2);
|
|
if (_Pred(_Val, *_UMid)) {
|
|
_Count = _Count2;
|
|
} else { // try top half
|
|
_UFirst = _Next_iter(_UMid);
|
|
_Count -= _Count2 + 1;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_First, _UFirst);
|
|
return _First;
|
|
}
|
|
|
|
template <class _FwdIt, class _Ty>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt upper_bound(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) {
|
|
// find first element that _Val is before, using operator<
|
|
return _STD upper_bound(_First, _Last, _Val, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE equal_range
|
|
template <class _FwdIt, class _Ty, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) {
|
|
// find range equivalent to _Val, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
using _Diff = _Iter_diff_t<_FwdIt>;
|
|
_Diff _Count = _STD distance(_UFirst, _ULast);
|
|
|
|
for (;;) { // divide and conquer, check midpoint
|
|
if (_Count <= 0) {
|
|
_Seek_wrapped(_Last, _UFirst); // empty range
|
|
_Seek_wrapped(_First, _UFirst);
|
|
break;
|
|
}
|
|
|
|
_Diff _Count2 = _Count / 2;
|
|
const auto _UMid = _STD next(_UFirst, _Count2);
|
|
if (_DEBUG_LT_PRED(_Pred, *_UMid, _Val)) { // range begins above _UMid, loop
|
|
_UFirst = _Next_iter(_UMid);
|
|
_Count -= _Count2 + 1;
|
|
} else if (_Pred(_Val, *_UMid)) {
|
|
_Count = _Count2; // range in first half, loop
|
|
} else { // range straddles _UMid, find each end and return
|
|
auto _UFirst2 = _STD lower_bound(_UFirst, _UMid, _Val, _Pass_fn(_Pred));
|
|
_STD advance(_UFirst, _Count);
|
|
auto _ULast2 = _STD upper_bound(_Next_iter(_UMid), _UFirst, _Val, _Pass_fn(_Pred));
|
|
_Seek_wrapped(_Last, _ULast2);
|
|
_Seek_wrapped(_First, _UFirst2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return {_First, _Last};
|
|
}
|
|
|
|
template <class _FwdIt, class _Ty>
|
|
_NODISCARD _CONSTEXPR20 pair<_FwdIt, _FwdIt> equal_range(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) {
|
|
// find range equivalent to _Val, using operator<
|
|
return _STD equal_range(_First, _Last, _Val, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE binary_search
|
|
template <class _FwdIt, class _Ty, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val, _Pr _Pred) {
|
|
// test if _Val equivalent to some element, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
_UFirst = _STD lower_bound(_UFirst, _ULast, _Val, _Pass_fn(_Pred));
|
|
return _UFirst != _ULast && !_Pred(_Val, *_UFirst);
|
|
}
|
|
|
|
template <class _FwdIt, class _Ty>
|
|
_NODISCARD _CONSTEXPR20 bool binary_search(_FwdIt _First, _FwdIt _Last, const _Ty& _Val) {
|
|
// test if _Val equivalent to some element, using operator<
|
|
return _STD binary_search(_First, _Last, _Val, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE merge
|
|
_NODISCARD constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Distance_unknown) {
|
|
return {};
|
|
}
|
|
|
|
template <class _Diff1>
|
|
_NODISCARD constexpr _Distance_unknown _Idl_dist_add(_Diff1, _Distance_unknown) {
|
|
return {};
|
|
}
|
|
|
|
template <class _Diff2>
|
|
_NODISCARD constexpr _Distance_unknown _Idl_dist_add(_Distance_unknown, _Diff2) {
|
|
return {};
|
|
}
|
|
|
|
template <class _Diff1, class _Diff2>
|
|
_NODISCARD constexpr auto _Idl_dist_add(_Diff1 _Lhs, _Diff2 _Rhs) {
|
|
return _Lhs + _Rhs;
|
|
}
|
|
|
|
template <class _InIt1, class _InIt2, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) {
|
|
// copy merging ranges, both using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt2, _UFirst1, _ULast1, _Pred);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt1, _UFirst2, _ULast2, _Pred);
|
|
const auto _Count1 = _Idl_distance<_InIt1>(_UFirst1, _ULast1);
|
|
const auto _Count2 = _Idl_distance<_InIt2>(_UFirst2, _ULast2);
|
|
auto _UDest = _Get_unwrapped_n(_Dest, _Idl_dist_add(_Count1, _Count2));
|
|
if (_UFirst1 != _ULast1 && _UFirst2 != _ULast2) {
|
|
for (;;) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UFirst2, *_UFirst1)) {
|
|
*_UDest = *_UFirst2;
|
|
++_UDest;
|
|
++_UFirst2;
|
|
|
|
if (_UFirst2 == _ULast2) {
|
|
break;
|
|
}
|
|
} else {
|
|
*_UDest = *_UFirst1;
|
|
++_UDest;
|
|
++_UFirst1;
|
|
|
|
if (_UFirst1 == _ULast1) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_UDest = _Copy_unchecked(_UFirst1, _ULast1, _UDest); // copy any tail
|
|
_Seek_wrapped(_Dest, _Copy_unchecked(_UFirst2, _ULast2, _UDest));
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* merge(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// copy merging ranges, both using _Pred, array dest
|
|
return _STD merge(_First1, _Last1, _First2, _Last2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _InIt1, class _InIt2, class _OutIt>
|
|
_CONSTEXPR20 _OutIt merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) {
|
|
// copy merging ranges, both using operator<
|
|
return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* merge(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) {
|
|
// copy merging ranges, both using operator<, array dest
|
|
return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 merge(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _FwdIt3 _Dest,
|
|
_Pr _Pred) noexcept /* terminates */ {
|
|
// copy merging ranges, both using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* merge(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _DestTy (&_Dest)[_DestSize],
|
|
_Pr _Pred) noexcept /* terminates */ {
|
|
// copy merging ranges, both using _Pred, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD merge(_First1, _Last1, _First2, _Last2, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 merge(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_FwdIt3 _Dest) noexcept /* terminates */ {
|
|
// copy merging ranges, both using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD merge(_First1, _Last1, _First2, _Last2, _Dest);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* merge(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// copy merging ranges, both using operator<, array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD merge(_First1, _Last1, _First2, _Last2, _Dest);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE inplace_merge
|
|
// The "usual invariants" for the inplace_merge helpers below are:
|
|
// [_First, _Mid) and [_Mid, _Last) are sorted
|
|
// _Pred(*_Mid, *_First) note: this means *_Mid is the "lowest" element
|
|
// _Pred(*prev(_Last), *prev(_Mid)) note: this means *prev(_Mid) is the "highest" element
|
|
// _Count1 == distance(_First, _Mid)
|
|
// _Count2 == distance(_Mid, _Last)
|
|
// _Count1 > 1
|
|
// _Count2 > 1
|
|
template <class _BidIt>
|
|
void _Rotate_one_right(_BidIt _First, _BidIt _Mid, _BidIt _Last) {
|
|
// exchanges the range [_First, _Mid) with [_Mid, _Last)
|
|
// pre: distance(_Mid, _Last) is 1
|
|
_Iter_value_t<_BidIt> _Temp(_STD move(*_Mid));
|
|
_Move_backward_unchecked(_First, _Mid, _Last);
|
|
*_First = _STD move(_Temp);
|
|
}
|
|
|
|
template <class _BidIt>
|
|
void _Rotate_one_left(_BidIt _First, _BidIt _Mid, _BidIt _Last) {
|
|
// exchanges the range [_First, _Mid) with [_Mid, _Last)
|
|
// pre: distance(_First, _Mid) is 1
|
|
_Iter_value_t<_BidIt> _Temp(_STD move(*_First));
|
|
*_Move_unchecked(_Mid, _Last, _First) = _STD move(_Temp);
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Inplace_merge_buffer_left(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Iter_value_t<_BidIt>* const _Temp_ptr,
|
|
_Pr _Pred) { // move the range [_First, _Mid) to _Temp_ptr, and merge it with [_Mid, _Last) to _First, using _Pred
|
|
// usual invariants apply
|
|
using _Ptr_ty = _Iter_value_t<_BidIt>*;
|
|
_Uninitialized_backout<_Ptr_ty> _Backout{_Temp_ptr, _Uninitialized_move_unchecked(_First, _Mid, _Temp_ptr)};
|
|
_Ptr_ty _Left_first = _Temp_ptr;
|
|
const _Ptr_ty _Left_last = _Backout._Last - 1; // avoid a compare with the highest element
|
|
*_First = _STD move(*_Mid); // the lowest element is now in position
|
|
++_First;
|
|
++_Mid;
|
|
for (;;) {
|
|
if (_Pred(*_Mid, *_Left_first)) { // take element from the right partition
|
|
*_First = _STD move(*_Mid);
|
|
++_First;
|
|
++_Mid;
|
|
if (_Mid == _Last) {
|
|
_Move_unchecked(_Left_first, _Backout._Last, _First); // move any tail (and the highest element)
|
|
return;
|
|
}
|
|
} else { // take element from the left partition
|
|
*_First = _STD move(*_Left_first);
|
|
++_First;
|
|
++_Left_first;
|
|
if (_Left_first == _Left_last) {
|
|
// move the remaining right partition and highest element, since *_Left_first is highest
|
|
*_Move_unchecked(_Mid, _Last, _First) = _STD move(*_Left_last);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Inplace_merge_buffer_right(
|
|
_BidIt _First, _BidIt _Mid, _BidIt _Last, _Iter_value_t<_BidIt>* const _Temp_ptr, _Pr _Pred) {
|
|
// move the range [_Mid, _Last) to _Temp_ptr, and merge it with [_First, _Mid) to _Last, using _Pred
|
|
// usual invariants apply
|
|
using _Ptr_ty = _Iter_value_t<_BidIt>*;
|
|
_Uninitialized_backout<_Ptr_ty> _Backout{_Temp_ptr, _Uninitialized_move_unchecked(_Mid, _Last, _Temp_ptr)};
|
|
*--_Last = _STD move(*--_Mid); // move the highest element into position
|
|
const _Ptr_ty _Right_first = _Temp_ptr;
|
|
_Ptr_ty _Right_last = _Backout._Last - 1;
|
|
--_Mid;
|
|
for (;;) {
|
|
if (_Pred(*_Right_last, *_Mid)) { // merge from the left partition
|
|
*--_Last = _STD move(*_Mid);
|
|
if (_First == _Mid) {
|
|
*--_Last = _STD move(*_Right_last); // to make [_Right_first, _Right_last) a half-open range
|
|
_Move_backward_unchecked(_Right_first, _Right_last, _Last); // move any head (and lowest element)
|
|
return;
|
|
}
|
|
|
|
--_Mid;
|
|
} else { // merge from the right partition
|
|
*--_Last = _STD move(*_Right_last);
|
|
--_Right_last;
|
|
if (_Right_first == _Right_last) { // we can't compare with *_Right_first, but we know it is lowest
|
|
*--_Last = _STD move(*_Mid); // restore half-open range [_First, _Mid)
|
|
_Move_backward_unchecked(_First, _Mid, _Last);
|
|
*_First = _STD move(*_Right_first);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Buffered_inplace_merge_unchecked(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Iter_diff_t<_BidIt> _Count1,
|
|
_Iter_diff_t<_BidIt> _Count2, _Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred);
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Buffered_inplace_merge_divide_and_conquer2(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Iter_diff_t<_BidIt> _Count1,
|
|
_Iter_diff_t<_BidIt> _Count2, _Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred,
|
|
_BidIt _Firstn, _BidIt _Lastn, _Iter_diff_t<_BidIt> _Count1n, _Iter_diff_t<_BidIt> _Count2n) {
|
|
// common block of _Buffered_inplace_merge_divide_and_conquer, below
|
|
using _Diff = _Iter_diff_t<_BidIt>;
|
|
_BidIt _Midn = _Buffered_rotate_unchecked(_Firstn, _Mid, _Lastn, static_cast<_Diff>(_Count1 - _Count1n), _Count2n,
|
|
_Temp_ptr, _Capacity); // rearrange middle
|
|
_Buffered_inplace_merge_unchecked(
|
|
_First, _Firstn, _Midn, _Count1n, _Count2n, _Temp_ptr, _Capacity, _Pred); // merge each new part
|
|
_Buffered_inplace_merge_unchecked(_Midn, _Lastn, _Last, static_cast<_Diff>(_Count1 - _Count1n),
|
|
static_cast<_Diff>(_Count2 - _Count2n), _Temp_ptr, _Capacity, _Pred);
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Buffered_inplace_merge_divide_and_conquer(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Iter_diff_t<_BidIt> _Count1,
|
|
_Iter_diff_t<_BidIt> _Count2, _Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred) {
|
|
// merge sorted [_First, _Mid) with sorted [_Mid, _Last), using _Pred
|
|
// usual invariants apply
|
|
using _Diff = _Iter_diff_t<_BidIt>;
|
|
if (_Count1 <= _Count2) {
|
|
const _Diff _Count1n = _Count1 >> 1; // shift for codegen
|
|
const _BidIt _Firstn = _STD next(_First, _Count1n);
|
|
const _BidIt _Lastn = _STD lower_bound(_Mid, _Last, *_Firstn, _Pred);
|
|
_Buffered_inplace_merge_divide_and_conquer2(_First, _Mid, _Last, _Count1, _Count2, _Temp_ptr, _Capacity, _Pred,
|
|
_Firstn, _Lastn, _Count1n, _STD distance(_Mid, _Lastn));
|
|
} else {
|
|
const _Diff _Count2n = _Count2 >> 1; // shift for codegen
|
|
const _BidIt _Lastn = _STD next(_Mid, _Count2n);
|
|
const _BidIt _Firstn = _STD upper_bound(_First, _Mid, *_Lastn, _Pred);
|
|
_Buffered_inplace_merge_divide_and_conquer2(_First, _Mid, _Last, _Count1, _Count2, _Temp_ptr, _Capacity, _Pred,
|
|
_Firstn, _Lastn, _STD distance(_First, _Firstn), _Count2n);
|
|
}
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Buffered_inplace_merge_unchecked_impl(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Iter_diff_t<_BidIt> _Count1,
|
|
_Iter_diff_t<_BidIt> _Count2, _Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred) {
|
|
// merge sorted [_First, _Mid) with sorted [_Mid, _Last), using _Pred
|
|
// usual invariants apply
|
|
if (_Count1 <= _Count2 && _Count1 <= _Capacity) {
|
|
_Inplace_merge_buffer_left(_First, _Mid, _Last, _Temp_ptr, _Pred);
|
|
} else if (_Count2 <= _Capacity) {
|
|
_Inplace_merge_buffer_right(_First, _Mid, _Last, _Temp_ptr, _Pred);
|
|
} else {
|
|
_Buffered_inplace_merge_divide_and_conquer(_First, _Mid, _Last, _Count1, _Count2, _Temp_ptr, _Capacity, _Pred);
|
|
}
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Buffered_inplace_merge_unchecked(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Iter_diff_t<_BidIt> _Count1,
|
|
_Iter_diff_t<_BidIt> _Count2, _Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred) {
|
|
// merge sorted [_First, _Mid) with sorted [_Mid, _Last), using _Pred
|
|
// usual invariants *do not* apply; only sortedness applies
|
|
// establish the usual invariants (explained in inplace_merge)
|
|
if (_Mid == _Last) {
|
|
return;
|
|
}
|
|
|
|
for (;;) {
|
|
if (_First == _Mid) {
|
|
return;
|
|
}
|
|
|
|
if (_Pred(*_Mid, *_First)) {
|
|
break;
|
|
}
|
|
|
|
++_First;
|
|
--_Count1;
|
|
}
|
|
|
|
const auto _Highest = _Prev_iter(_Mid);
|
|
do {
|
|
--_Last;
|
|
--_Count2;
|
|
if (_Mid == _Last) {
|
|
_Rotate_one_right(_First, _Mid, ++_Last);
|
|
return;
|
|
}
|
|
} while (!_Pred(*_Last, *_Highest));
|
|
|
|
++_Last;
|
|
++_Count2;
|
|
|
|
if (_Count1 == 1) {
|
|
_Rotate_one_left(_First, _Mid, _Last);
|
|
return;
|
|
}
|
|
|
|
_Buffered_inplace_merge_unchecked_impl(_First, _Mid, _Last, _Count1, _Count2, _Temp_ptr, _Capacity, _Pred);
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last, _Pr _Pred) {
|
|
// merge [_First, _Mid) with [_Mid, _Last), using _Pred
|
|
_Adl_verify_range(_First, _Mid);
|
|
_Adl_verify_range(_Mid, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
auto _UMid = _Get_unwrapped(_Mid);
|
|
auto _ULast = _Get_unwrapped(_Last);
|
|
_DEBUG_ORDER_UNWRAPPED(_UFirst, _UMid, _Pred);
|
|
|
|
// establish the usual invariants:
|
|
if (_UMid == _ULast) {
|
|
return;
|
|
}
|
|
|
|
for (;;) {
|
|
if (_UFirst == _UMid) {
|
|
return;
|
|
}
|
|
|
|
if (_Pred(*_UMid, *_UFirst)) { // found that *_UMid goes in *_UFirst's position
|
|
break;
|
|
}
|
|
|
|
++_UFirst;
|
|
}
|
|
|
|
const auto _Highest = _Prev_iter(_UMid);
|
|
do {
|
|
--_ULast;
|
|
if (_UMid == _ULast) { // rotate only element remaining in right partition to the beginning, without allocating
|
|
_Rotate_one_right(_UFirst, _UMid, ++_ULast);
|
|
return;
|
|
}
|
|
} while (!_Pred(*_ULast, *_Highest)); // found that *_Highest goes in *_ULast's position
|
|
|
|
++_ULast;
|
|
|
|
using _Diff = _Iter_diff_t<_BidIt>;
|
|
const _Diff _Count1 = _STD distance(_UFirst, _UMid);
|
|
if (_Count1 == 1) { // rotate only element remaining in left partition to the end, without allocating
|
|
_Rotate_one_left(_UFirst, _UMid, _ULast);
|
|
return;
|
|
}
|
|
|
|
const _Diff _Count2 = _STD distance(_UMid, _ULast);
|
|
_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{_Min_value(_Count1, _Count2)};
|
|
_Buffered_inplace_merge_unchecked_impl(
|
|
_UFirst, _UMid, _ULast, _Count1, _Count2, _Temp_buf._Data, _Temp_buf._Capacity, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _BidIt>
|
|
void inplace_merge(_BidIt _First, _BidIt _Mid, _BidIt _Last) {
|
|
// merge [_First, _Mid) with [_Mid, _Last), using operator<
|
|
_STD inplace_merge(_First, _Mid, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _BidIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void inplace_merge(_ExPo&&, _BidIt _First, _BidIt _Mid, _BidIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// merge [_First, _Mid) with [_Mid, _Last), using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_STD inplace_merge(_First, _Mid, _Last, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _BidIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void inplace_merge(_ExPo&&, _BidIt _First, _BidIt _Mid, _BidIt _Last) noexcept /* terminates */ {
|
|
// merge [_First, _Mid) with [_Mid, _Last), using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_STD inplace_merge(_First, _Mid, _Last);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE sort
|
|
template <class _BidIt, class _Pr>
|
|
_CONSTEXPR20 _BidIt _Insertion_sort_unchecked(_BidIt _First, const _BidIt _Last, _Pr _Pred) {
|
|
// insertion sort [_First, _Last), using _Pred
|
|
if (_First != _Last) {
|
|
for (_BidIt _Next = _First; ++_Next != _Last;) { // order next element
|
|
_BidIt _Next1 = _Next;
|
|
_Iter_value_t<_BidIt> _Val = _STD move(*_Next);
|
|
|
|
if (_DEBUG_LT_PRED(_Pred, _Val, *_First)) { // found new earliest element, move to front
|
|
_Move_backward_unchecked(_First, _Next, ++_Next1);
|
|
*_First = _STD move(_Val);
|
|
} else { // look for insertion point after first
|
|
for (_BidIt _First1 = _Next1; _DEBUG_LT_PRED(_Pred, _Val, *--_First1); _Next1 = _First1) {
|
|
*_Next1 = _STD move(*_First1); // move hole down
|
|
}
|
|
|
|
*_Next1 = _STD move(_Val); // insert element in hole
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Last;
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void _Med3_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) {
|
|
// sort median of three elements to middle
|
|
if (_DEBUG_LT_PRED(_Pred, *_Mid, *_First)) {
|
|
_STD iter_swap(_Mid, _First);
|
|
}
|
|
|
|
if (_DEBUG_LT_PRED(_Pred, *_Last, *_Mid)) { // swap middle and last, then test first again
|
|
_STD iter_swap(_Last, _Mid);
|
|
|
|
if (_DEBUG_LT_PRED(_Pred, *_Mid, *_First)) {
|
|
_STD iter_swap(_Mid, _First);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void _Guess_median_unchecked(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) {
|
|
// sort median element to middle
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
const _Diff _Count = _Last - _First;
|
|
if (40 < _Count) { // Tukey's ninther
|
|
const _Diff _Step = (_Count + 1) >> 3; // +1 can't overflow because range was made inclusive in caller
|
|
const _Diff _Two_step = _Step << 1; // note: intentionally discards low-order bit
|
|
_Med3_unchecked(_First, _First + _Step, _First + _Two_step, _Pred);
|
|
_Med3_unchecked(_Mid - _Step, _Mid, _Mid + _Step, _Pred);
|
|
_Med3_unchecked(_Last - _Two_step, _Last - _Step, _Last, _Pred);
|
|
_Med3_unchecked(_First + _Step, _Mid, _Last - _Step, _Pred);
|
|
} else {
|
|
_Med3_unchecked(_First, _Mid, _Last, _Pred);
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 pair<_RanIt, _RanIt> _Partition_by_median_guess_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
|
// partition [_First, _Last), using _Pred
|
|
_RanIt _Mid = _First + ((_Last - _First) >> 1); // shift for codegen
|
|
_Guess_median_unchecked(_First, _Mid, _Last - 1, _Pred);
|
|
_RanIt _Pfirst = _Mid;
|
|
_RanIt _Plast = _Pfirst + 1;
|
|
|
|
while (_First < _Pfirst && !_DEBUG_LT_PRED(_Pred, *(_Pfirst - 1), *_Pfirst) && !_Pred(*_Pfirst, *(_Pfirst - 1))) {
|
|
--_Pfirst;
|
|
}
|
|
|
|
while (_Plast < _Last && !_DEBUG_LT_PRED(_Pred, *_Plast, *_Pfirst) && !_Pred(*_Pfirst, *_Plast)) {
|
|
++_Plast;
|
|
}
|
|
|
|
_RanIt _Gfirst = _Plast;
|
|
_RanIt _Glast = _Pfirst;
|
|
|
|
for (;;) { // partition
|
|
for (; _Gfirst < _Last; ++_Gfirst) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_Pfirst, *_Gfirst)) {
|
|
} else if (_Pred(*_Gfirst, *_Pfirst)) {
|
|
break;
|
|
} else if (_Plast != _Gfirst) {
|
|
_STD iter_swap(_Plast, _Gfirst);
|
|
++_Plast;
|
|
} else {
|
|
++_Plast;
|
|
}
|
|
}
|
|
|
|
for (; _First < _Glast; --_Glast) {
|
|
if (_DEBUG_LT_PRED(_Pred, *(_Glast - 1), *_Pfirst)) {
|
|
} else if (_Pred(*_Pfirst, *(_Glast - 1))) {
|
|
break;
|
|
} else if (--_Pfirst != _Glast - 1) {
|
|
_STD 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) {
|
|
_STD iter_swap(_Pfirst, _Plast);
|
|
}
|
|
|
|
++_Plast;
|
|
_STD iter_swap(_Pfirst, _Gfirst);
|
|
++_Pfirst;
|
|
++_Gfirst;
|
|
} else if (_Gfirst == _Last) { // no room at top, rotate pivot downward
|
|
if (--_Glast != --_Pfirst) {
|
|
_STD iter_swap(_Glast, _Pfirst);
|
|
}
|
|
|
|
_STD iter_swap(_Pfirst, --_Plast);
|
|
} else {
|
|
_STD iter_swap(_Gfirst, --_Glast);
|
|
++_Gfirst;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) {
|
|
// order [_First, _Last), using _Pred
|
|
for (;;) {
|
|
if (_Last - _First <= _ISORT_MAX) { // small
|
|
_Insertion_sort_unchecked(_First, _Last, _Pred);
|
|
return;
|
|
}
|
|
|
|
if (_Ideal <= 0) { // heap sort if too many divisions
|
|
_Make_heap_unchecked(_First, _Last, _Pred);
|
|
_Sort_heap_unchecked(_First, _Last, _Pred);
|
|
return;
|
|
}
|
|
|
|
// divide and conquer by quicksort
|
|
auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred);
|
|
|
|
_Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions
|
|
|
|
if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half
|
|
_Sort_unchecked(_First, _Mid.first, _Ideal, _Pred);
|
|
_First = _Mid.second;
|
|
} else { // loop on first half
|
|
_Sort_unchecked(_Mid.second, _Last, _Ideal, _Pred);
|
|
_Last = _Mid.first;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last, _Pr _Pred) { // order [_First, _Last), using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
_Sort_unchecked(_UFirst, _ULast, _ULast - _UFirst, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_CONSTEXPR20 void sort(const _RanIt _First, const _RanIt _Last) { // order [_First, _Last), using operator<
|
|
_STD sort(_First, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _RanIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void sort(_ExPo&& _Exec, _RanIt _First, _RanIt _Last, _Pr _Pred) noexcept; // terminates
|
|
|
|
template <class _ExPo, class _RanIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void sort(_ExPo&& _Exec, const _RanIt _First, const _RanIt _Last) noexcept /* terminates */ {
|
|
// order [_First, _Last), using operator<
|
|
_STD sort(_STD forward<_ExPo>(_Exec), _First, _Last, less<>{});
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE stable_sort
|
|
template <class _FwdIt, class _Ty, class _Pr>
|
|
_Ty* _Uninitialized_merge_move(_FwdIt _First, const _FwdIt _Mid, const _FwdIt _Last, _Ty* const _Dest, _Pr _Pred) {
|
|
// move merging ranges to uninitialized storage, both using _Pred
|
|
// pre: _First != _Mid && _Mid != _Last
|
|
_Uninitialized_backout<_Ty*> _Backout{_Dest};
|
|
_FwdIt _Next = _Mid;
|
|
for (;;) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_Next, *_First)) {
|
|
_Backout._Emplace_back(_STD move(*_Next));
|
|
++_Next;
|
|
|
|
if (_Next == _Last) {
|
|
_Backout._Last = _Uninitialized_move_unchecked(_First, _Mid, _Backout._Last);
|
|
return _Backout._Release();
|
|
}
|
|
} else {
|
|
_Backout._Emplace_back(_STD move(*_First));
|
|
++_First;
|
|
|
|
if (_First == _Mid) {
|
|
_Backout._Last = _Uninitialized_move_unchecked(_Next, _Last, _Backout._Last);
|
|
return _Backout._Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _InIt, class _OutIt, class _Pr>
|
|
_OutIt _Merge_move(_InIt _First, const _InIt _Mid, const _InIt _Last, _OutIt _Dest, _Pr _Pred) {
|
|
// move merging adjacent ranges [_First, _Mid) and [_Mid, _Last) to _Dest, both using _Pred
|
|
// pre: _First != _Mid && _Mid != _Last
|
|
_InIt _Next = _Mid;
|
|
for (;;) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_Next, *_First)) {
|
|
*_Dest = _STD move(*_Next);
|
|
++_Dest;
|
|
++_Next;
|
|
|
|
if (_Next == _Last) {
|
|
return _Move_unchecked(_First, _Mid, _Dest);
|
|
}
|
|
} else {
|
|
*_Dest = _STD move(*_First);
|
|
++_Dest;
|
|
++_First;
|
|
|
|
if (_First == _Mid) {
|
|
return _Move_unchecked(_Next, _Last, _Dest);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _BidIt, class _Ty, class _Pr>
|
|
void _Uninitialized_chunked_merge_unchecked(_BidIt _First, const _BidIt _Last, _Ty* _Dest,
|
|
const _Iter_diff_t<_BidIt> _Chunk, _Iter_diff_t<_BidIt> _Count, _Pr _Pred) {
|
|
// move to uninitialized merging adjacent chunks of distance _Chunk, using _Pred
|
|
// pre: _Count == distance(_First, _Last)
|
|
// pre: _Chunk > 0
|
|
_Uninitialized_backout<_Ty*> _Backout{_Dest};
|
|
while (_Chunk < _Count) {
|
|
_Count -= _Chunk;
|
|
const _BidIt _Mid1 = _STD next(_First, _Chunk);
|
|
const auto _Chunk2 = _Min_value(_Chunk, _Count);
|
|
_Count -= _Chunk2;
|
|
const _BidIt _Mid2 = _STD next(_Mid1, _Chunk2);
|
|
_Backout._Last = _Uninitialized_merge_move(_First, _Mid1, _Mid2, _Backout._Last, _Pred);
|
|
_First = _Mid2;
|
|
}
|
|
|
|
_Uninitialized_move_unchecked(_First, _Last, _Backout._Last); // copy partial last chunk
|
|
_Backout._Release();
|
|
}
|
|
|
|
template <class _BidIt, class _OutIt, class _Pr>
|
|
void _Chunked_merge_unchecked(_BidIt _First, const _BidIt _Last, _OutIt _Dest, const _Iter_diff_t<_BidIt> _Chunk,
|
|
_Iter_diff_t<_BidIt> _Count, _Pr _Pred) {
|
|
// move merging adjacent chunks of distance _Chunk, using _Pred
|
|
// pre: _Count == distance(_First, _Last)
|
|
// pre: _Chunk > 0
|
|
while (_Chunk < _Count) {
|
|
_Count -= _Chunk;
|
|
const _BidIt _Mid1 = _STD next(_First, _Chunk);
|
|
const auto _Chunk2 = _Min_value(_Chunk, _Count);
|
|
_Count -= _Chunk2;
|
|
const _BidIt _Mid2 = _STD next(_Mid1, _Chunk2);
|
|
_Dest = _Merge_move(_First, _Mid1, _Mid2, _Dest, _Pred);
|
|
_First = _Mid2;
|
|
}
|
|
|
|
_Move_unchecked(_First, _Last, _Dest); // copy partial last chunk
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Insertion_sort_isort_max_chunks(_BidIt _First, const _BidIt _Last, _Iter_diff_t<_BidIt> _Count, _Pr _Pred) {
|
|
// insertion sort every chunk of distance _ISORT_MAX in [_First, _Last)
|
|
// pre: _Count == distance(_First, _Last)
|
|
for (; _ISORT_MAX < _Count; _Count -= _ISORT_MAX) { // sort chunks
|
|
_First = _Insertion_sort_unchecked(_First, _STD next(_First, _ISORT_MAX), _Pred);
|
|
}
|
|
|
|
_Insertion_sort_unchecked(_First, _Last, _Pred); // sort partial last chunk
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Buffered_merge_sort_unchecked(const _BidIt _First, const _BidIt _Last, const _Iter_diff_t<_BidIt> _Count,
|
|
_Iter_value_t<_BidIt>* const _Temp_ptr, _Pr _Pred) {
|
|
// sort using temp buffer for merges, using _Pred
|
|
// pre: _Last - _First == _Count
|
|
// pre: _Count <= capacity of buffer at _Temp_ptr; also allows safe narrowing to ptrdiff_t
|
|
_Insertion_sort_isort_max_chunks(_First, _Last, _Count, _Pred);
|
|
// merge adjacent pairs of chunks to and from temp buffer
|
|
auto _Chunk = static_cast<_Iter_diff_t<_BidIt>>(_ISORT_MAX);
|
|
if (_Count <= _Chunk) {
|
|
return;
|
|
}
|
|
|
|
// do the first merge, constructing elements in the temporary buffer
|
|
_Uninitialized_chunked_merge_unchecked(_First, _Last, _Temp_ptr, _Chunk, _Count, _Pred);
|
|
_Uninitialized_backout<_Iter_value_t<_BidIt>*> _Backout{_Temp_ptr, _Temp_ptr + _Count};
|
|
for (;;) {
|
|
// unconditionally merge elements back into the source buffer
|
|
_Chunk <<= 1;
|
|
_Chunked_merge_unchecked(_Temp_ptr, _Temp_ptr + _Count, _First, static_cast<ptrdiff_t>(_Chunk),
|
|
static_cast<ptrdiff_t>(_Count), _Pred);
|
|
_Chunk <<= 1;
|
|
if (_Count <= _Chunk) { // if the input would be a single chunk, it's already sorted and we're done
|
|
return;
|
|
}
|
|
|
|
// more merges necessary; merge to temporary buffer
|
|
_Chunked_merge_unchecked(_First, _Last, _Temp_ptr, _Chunk, _Count, _Pred);
|
|
}
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void _Stable_sort_unchecked(const _BidIt _First, const _BidIt _Last, const _Iter_diff_t<_BidIt> _Count,
|
|
_Iter_value_t<_BidIt>* const _Temp_ptr, const ptrdiff_t _Capacity, _Pr _Pred) {
|
|
// sort preserving order of equivalents, using _Pred
|
|
using _Diff = _Iter_diff_t<_BidIt>;
|
|
if (_Count <= _ISORT_MAX) {
|
|
_Insertion_sort_unchecked(_First, _Last, _Pred); // small
|
|
} else { // sort halves and merge
|
|
const auto _Half_count = static_cast<_Diff>(_Count / 2);
|
|
const auto _Half_count_ceil = static_cast<_Diff>(_Count - _Half_count);
|
|
const _BidIt _Mid = _STD next(_First, _Half_count_ceil);
|
|
if (_Half_count_ceil <= _Capacity) { // temp buffer big enough, sort each half using buffer
|
|
_Buffered_merge_sort_unchecked(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Pred);
|
|
_Buffered_merge_sort_unchecked(_Mid, _Last, _Half_count, _Temp_ptr, _Pred);
|
|
} else { // temp buffer not big enough, divide and conquer
|
|
_Stable_sort_unchecked(_First, _Mid, _Half_count_ceil, _Temp_ptr, _Capacity, _Pred);
|
|
_Stable_sort_unchecked(_Mid, _Last, _Half_count, _Temp_ptr, _Capacity, _Pred);
|
|
}
|
|
|
|
_Buffered_inplace_merge_unchecked(
|
|
_First, _Mid, _Last, _Half_count_ceil, _Half_count, _Temp_ptr, _Capacity, _Pred); // merge halves
|
|
}
|
|
}
|
|
|
|
template <class _BidIt, class _Pr>
|
|
void stable_sort(const _BidIt _First, const _BidIt _Last, _Pr _Pred) {
|
|
// sort preserving order of equivalents, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
const auto _Count = _STD distance(_UFirst, _ULast);
|
|
if (_Count <= _ISORT_MAX) {
|
|
_Insertion_sort_unchecked(_UFirst, _ULast, _Pass_fn(_Pred));
|
|
return;
|
|
}
|
|
|
|
_Optimistic_temporary_buffer<_Iter_value_t<_BidIt>> _Temp_buf{_Count - _Count / 2};
|
|
_Stable_sort_unchecked(_UFirst, _ULast, _Count, _Temp_buf._Data, _Temp_buf._Capacity, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _BidIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void stable_sort(_ExPo&& _Exec, const _BidIt _First, const _BidIt _Last, _Pr _Pred) noexcept; // terminates
|
|
#endif // _HAS_CXX17
|
|
|
|
template <class _BidIt>
|
|
void stable_sort(const _BidIt _First, const _BidIt _Last) { // sort preserving order of equivalents, using operator<
|
|
_STD stable_sort(_First, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _BidIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void stable_sort(_ExPo&& _Exec, _BidIt _First, _BidIt _Last) noexcept /* terminates */ {
|
|
// sort preserving order of equivalents, using operator<
|
|
_STD stable_sort(_STD forward<_ExPo>(_Exec), _First, _Last, less<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE partial_sort
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) {
|
|
// order [_First, _Last) up to _Mid, using _Pred
|
|
_Adl_verify_range(_First, _Mid);
|
|
_Adl_verify_range(_Mid, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _UMid = _Get_unwrapped(_Mid);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
|
|
if (_UFirst == _UMid) {
|
|
return; // nothing to do, avoid violating _Pop_heap_hole_unchecked preconditions
|
|
}
|
|
|
|
_Make_heap_unchecked(_UFirst, _UMid, _Pass_fn(_Pred));
|
|
for (auto _UNext = _UMid; _UNext < _ULast; ++_UNext) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UNext, *_UFirst)) { // replace top with new largest
|
|
_Iter_value_t<_RanIt> _Val = _STD move(*_UNext);
|
|
_Pop_heap_hole_unchecked(_UFirst, _UMid, _UNext, _STD move(_Val), _Pass_fn(_Pred));
|
|
}
|
|
}
|
|
|
|
_Sort_heap_unchecked(_UFirst, _UMid, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_CONSTEXPR20 void partial_sort(_RanIt _First, _RanIt _Mid, _RanIt _Last) {
|
|
// order [_First, _Last) up to _Mid, using operator<
|
|
_STD partial_sort(_First, _Mid, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _RanIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void partial_sort(_ExPo&&, _RanIt _First, _RanIt _Mid, _RanIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// order [_First, _Last) up to _Mid, using _Pred
|
|
// parallelism suspected to be infeasible
|
|
return _STD partial_sort(_First, _Mid, _Last, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _RanIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void partial_sort(_ExPo&&, _RanIt _First, _RanIt _Mid, _RanIt _Last) noexcept /* terminates */ {
|
|
// order [_First, _Last) up to _Mid, using operator<
|
|
// parallelism suspected to be infeasible
|
|
return _STD partial_sort(_First, _Mid, _Last);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE partial_sort_copy
|
|
template <class _InIt, class _RanIt, class _Pr>
|
|
_CONSTEXPR20 _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _Last2, _Pr _Pred) {
|
|
// copy [_First1, _Last1) into [_First2, _Last2) using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
auto _UMid2 = _UFirst2;
|
|
if (_UFirst1 != _ULast1 && _UFirst2 != _ULast2) {
|
|
for (; _UFirst1 != _ULast1 && _UMid2 != _ULast2; ++_UFirst1, (void) ++_UMid2) {
|
|
*_UMid2 = *_UFirst1; // copy min(_ULast1 - _UFirst1, _ULast2 - _UFirst2)
|
|
}
|
|
|
|
_Make_heap_unchecked(_UFirst2, _UMid2, _Pass_fn(_Pred));
|
|
for (; _UFirst1 != _ULast1; ++_UFirst1) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UFirst1, *_UFirst2)) {
|
|
// replace top with new largest:
|
|
using _Diff = _Iter_diff_t<_RanIt>;
|
|
_Pop_heap_hole_by_index(_UFirst2, static_cast<_Diff>(0), static_cast<_Diff>(_UMid2 - _UFirst2),
|
|
static_cast<_Iter_value_t<_InIt>>(*_UFirst1), _Pass_fn(_Pred));
|
|
}
|
|
}
|
|
|
|
_Sort_heap_unchecked(_UFirst2, _UMid2, _Pass_fn(_Pred));
|
|
}
|
|
|
|
_Seek_wrapped(_First2, _UMid2);
|
|
return _First2;
|
|
}
|
|
|
|
template <class _InIt, class _RanIt>
|
|
_CONSTEXPR20 _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First2, _RanIt _Last2) {
|
|
// copy [_First1, _Last1) into [_First2, _Last2), using operator<
|
|
return _STD partial_sort_copy(_First1, _Last1, _First2, _Last2, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _RanIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_RanIt partial_sort_copy(
|
|
_ExPo&&, _FwdIt _First1, _FwdIt _Last1, _RanIt _First2, _RanIt _Last2, _Pr _Pred) noexcept /* terminates */ {
|
|
// copy [_First1, _Last1) into [_First2, _Last2) using _Pred
|
|
// parallelism suspected to be infeasible
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt);
|
|
return _STD partial_sort_copy(_First1, _Last1, _First2, _Last2, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, class _RanIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_RanIt partial_sort_copy(
|
|
_ExPo&&, _FwdIt _First1, _FwdIt _Last1, _RanIt _First2, _RanIt _Last2) noexcept /* terminates */ {
|
|
// copy [_First1, _Last1) into [_First2, _Last2), using operator<
|
|
// parallelism suspected to be infeasible
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt);
|
|
return _STD partial_sort_copy(_First1, _Last1, _First2, _Last2);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE nth_element
|
|
template <class _RanIt, class _Pr>
|
|
_CONSTEXPR20 void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _Pred) {
|
|
// order Nth element, using _Pred
|
|
_Adl_verify_range(_First, _Nth);
|
|
_Adl_verify_range(_Nth, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _UNth = _Get_unwrapped(_Nth);
|
|
auto _ULast = _Get_unwrapped(_Last);
|
|
if (_UNth == _ULast) {
|
|
return; // nothing to do
|
|
}
|
|
|
|
while (_ISORT_MAX < _ULast - _UFirst) { // divide and conquer, ordering partition containing Nth
|
|
auto _UMid = _Partition_by_median_guess_unchecked(_UFirst, _ULast, _Pass_fn(_Pred));
|
|
|
|
if (_UMid.second <= _UNth) {
|
|
_UFirst = _UMid.second;
|
|
} else if (_UMid.first <= _UNth) {
|
|
return; // Nth inside fat pivot, done
|
|
} else {
|
|
_ULast = _UMid.first;
|
|
}
|
|
}
|
|
|
|
_Insertion_sort_unchecked(_UFirst, _ULast, _Pass_fn(_Pred)); // sort any remainder
|
|
}
|
|
|
|
template <class _RanIt>
|
|
_CONSTEXPR20 void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last) { // order Nth element, using operator<
|
|
_STD nth_element(_First, _Nth, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _RanIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void nth_element(_ExPo&&, _RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// order Nth element, using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_STD nth_element(_First, _Nth, _Last, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _RanIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
void nth_element(_ExPo&&, _RanIt _First, _RanIt _Nth, _RanIt _Last) noexcept /* terminates */ {
|
|
// order Nth element, using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_STD nth_element(_First, _Nth, _Last);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE includes
|
|
template <class _InIt1, class _InIt2, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _Pr _Pred) {
|
|
// test if every element in sorted [_First2, _Last2) is in sorted [_First1, _Last1), using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt2, _UFirst1, _ULast1, _Pred);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt1, _UFirst2, _ULast2, _Pred);
|
|
for (; _UFirst1 != _ULast1 && _UFirst2 != _ULast2; ++_UFirst1) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UFirst2, *_UFirst1)) {
|
|
return false;
|
|
}
|
|
|
|
if (!_Pred(*_UFirst1, *_UFirst2)) {
|
|
++_UFirst2;
|
|
}
|
|
}
|
|
|
|
return _UFirst2 == _ULast2;
|
|
}
|
|
|
|
template <class _InIt1, class _InIt2>
|
|
_NODISCARD _CONSTEXPR20 bool includes(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2) {
|
|
// test if every element in sorted [_First2, _Last2) is in sorted [_First1, _Last1), using operator<
|
|
return _STD includes(_First1, _Last1, _First2, _Last2, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
// FUNCTION TEMPLATE includes
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool includes(
|
|
_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _Pr _Pred) noexcept /* terminates */ {
|
|
// test if every element in sorted [_First2, _Last2) is in sorted [_First1, _Last1), using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD includes(_First1, _Last1, _First2, _Last2, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool includes(
|
|
_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) noexcept /* terminates */ {
|
|
// test if every element in sorted [_First2, _Last2) is in sorted [_First1, _Last1), using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD includes(_First1, _Last1, _First2, _Last2);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE set_union
|
|
template <class _InIt1, class _InIt2, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt2, _UFirst1, _ULast1, _Pred);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt1, _UFirst2, _ULast2, _Pred);
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
for (; _UFirst1 != _ULast1 && _UFirst2 != _ULast2; ++_UDest) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UFirst1, *_UFirst2)) { // copy first
|
|
*_UDest = *_UFirst1;
|
|
++_UFirst1;
|
|
} else if (_Pred(*_UFirst2, *_UFirst1)) { // copy second
|
|
*_UDest = *_UFirst2;
|
|
++_UFirst2;
|
|
} else { // advance both
|
|
*_UDest = *_UFirst1;
|
|
++_UFirst1;
|
|
++_UFirst2;
|
|
}
|
|
}
|
|
|
|
_UDest = _Copy_unchecked(_UFirst1, _ULast1, _UDest);
|
|
_Seek_wrapped(_Dest, _Copy_unchecked(_UFirst2, _ULast2, _UDest));
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* set_union(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_union(_First1, _Last1, _First2, _Last2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _InIt1, class _InIt2, class _OutIt>
|
|
_CONSTEXPR20 _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), using operator<
|
|
return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* set_union(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_union(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _FwdIt3 _Dest,
|
|
_Pr _Pred) noexcept /* terminates */ {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_union(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_union(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_FwdIt3 _Dest) noexcept /* terminates */ {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_union(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// OR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD set_union(_First1, _Last1, _First2, _Last2, _Dest);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE set_intersection
|
|
template <class _InIt1, class _InIt2, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _OutIt set_intersection(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) {
|
|
// AND sets [_First1, _Last1) and [_First2, _Last2), using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt2, _UFirst1, _ULast1, _Pred);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt1, _UFirst2, _ULast2, _Pred);
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
while (_UFirst1 != _ULast1 && _UFirst2 != _ULast2) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UFirst1, *_UFirst2)) {
|
|
++_UFirst1;
|
|
} else if (_Pred(*_UFirst2, *_UFirst1)) {
|
|
++_UFirst2;
|
|
} else {
|
|
*_UDest = *_UFirst1;
|
|
++_UDest;
|
|
++_UFirst1;
|
|
++_UFirst2;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _UDest);
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* set_intersection(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// AND sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_intersection(
|
|
_First1, _Last1, _First2, _Last2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _InIt1, class _InIt2, class _OutIt>
|
|
_CONSTEXPR20 _OutIt set_intersection(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) {
|
|
// AND sets [_First1, _Last1) and [_First2, _Last2), using operator<
|
|
return _STD set_intersection(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* set_intersection(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) {
|
|
// AND sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_intersection(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_intersection(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _FwdIt3 _Dest,
|
|
_Pr _Pred) noexcept; // terminates
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_intersection(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// AND sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_intersection(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2,
|
|
_Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_intersection(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_FwdIt3 _Dest) noexcept /* terminates */ {
|
|
// AND sets [_First1, _Last1) and [_First2, _Last2), using operator<
|
|
return _STD set_intersection(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, _Dest, less{});
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_intersection(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// AND sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_intersection(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, _Dest, less{});
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE set_difference
|
|
template <class _InIt1, class _InIt2, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _OutIt set_difference(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest, _Pr _Pred) {
|
|
// take set [_First2, _Last2) from [_First1, _Last1), using _Pred
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt2, _UFirst1, _ULast1, _Pred);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt1, _UFirst2, _ULast2, _Pred);
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
while (_UFirst1 != _ULast1 && _UFirst2 != _ULast2) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UFirst1, *_UFirst2)) { // copy first
|
|
*_UDest = *_UFirst1;
|
|
++_UDest;
|
|
++_UFirst1;
|
|
} else {
|
|
if (!_Pred(*_UFirst2, *_UFirst1)) {
|
|
++_UFirst1;
|
|
}
|
|
|
|
++_UFirst2;
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Dest, _Copy_unchecked(_UFirst1, _ULast1, _UDest));
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* set_difference(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// take set [_First2, _Last2) from [_First1, _Last1), array dest
|
|
return _STD set_difference(
|
|
_First1, _Last1, _First2, _Last2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _InIt1, class _InIt2, class _OutIt>
|
|
_CONSTEXPR20 _OutIt set_difference(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) {
|
|
// take set [_First2, _Last2) from [_First1, _Last1), using operator<
|
|
return _STD set_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* set_difference(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) {
|
|
// take set [_First2, _Last2) from [_First1, _Last1), array dest
|
|
return _STD set_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_difference(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2, _FwdIt3 _Dest,
|
|
_Pr _Pred) noexcept; // terminates
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_difference(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// take set [_First2, _Last2) from [_First1, _Last1), array dest
|
|
return _STD set_difference(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2,
|
|
_Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_difference(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_FwdIt3 _Dest) noexcept /* terminates */ {
|
|
// take set [_First2, _Last2) from [_First1, _Last1), using operator<
|
|
return _STD set_difference(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, _Dest, less{});
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_difference(_ExPo&& _Exec, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// take set [_First2, _Last2) from [_First1, _Last1), array dest
|
|
return _STD set_difference(_STD forward<_ExPo>(_Exec), _First1, _Last1, _First2, _Last2, _Dest, less{});
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE set_symmetric_difference
|
|
template <class _InIt1, class _InIt2, class _OutIt, class _Pr>
|
|
_CONSTEXPR20 _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
|
|
_Adl_verify_range(_First1, _Last1);
|
|
_Adl_verify_range(_First2, _Last2);
|
|
auto _UFirst1 = _Get_unwrapped(_First1);
|
|
const auto _ULast1 = _Get_unwrapped(_Last1);
|
|
auto _UFirst2 = _Get_unwrapped(_First2);
|
|
const auto _ULast2 = _Get_unwrapped(_Last2);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt2, _UFirst1, _ULast1, _Pred);
|
|
_DEBUG_ORDER_SET_UNWRAPPED(_InIt1, _UFirst2, _ULast2, _Pred);
|
|
auto _UDest = _Get_unwrapped_unverified(_Dest);
|
|
while (_UFirst1 != _ULast1 && _UFirst2 != _ULast2) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UFirst1, *_UFirst2)) { // copy first
|
|
*_UDest = *_UFirst1;
|
|
++_UDest;
|
|
++_UFirst1;
|
|
} else if (_Pred(*_UFirst2, *_UFirst1)) { // copy second
|
|
*_UDest = *_UFirst2;
|
|
++_UDest;
|
|
++_UFirst2;
|
|
} else { // advance both
|
|
++_UFirst1;
|
|
++_UFirst2;
|
|
}
|
|
}
|
|
|
|
_UDest = _Copy_unchecked(_UFirst1, _ULast1, _UDest);
|
|
_Seek_wrapped(_Dest, _Copy_unchecked(_UFirst2, _ULast2, _UDest));
|
|
return _Dest;
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize, class _Pr>
|
|
_CONSTEXPR20 _DestTy* set_symmetric_difference(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize], _Pr _Pred) {
|
|
// XOR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_symmetric_difference(
|
|
_First1, _Last1, _First2, _Last2, _Array_iterator<_DestTy, _DestSize>(_Dest), _Pass_fn(_Pred))
|
|
._Unwrapped();
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _InIt1, class _InIt2, class _OutIt>
|
|
_CONSTEXPR20 _OutIt set_symmetric_difference(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest) {
|
|
// XOR sets [_First1, _Last1) and [_First2, _Last2), using operator<
|
|
return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _InIt1, class _InIt2, class _DestTy, size_t _DestSize>
|
|
_CONSTEXPR20 _DestTy* set_symmetric_difference(
|
|
_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _DestTy (&_Dest)[_DestSize]) {
|
|
// XOR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, less<>());
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_symmetric_difference(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_FwdIt3 _Dest, _Pr _Pred) noexcept /* terminates */ {
|
|
// XOR sets [_First1, _Last1) and [_First2, _Last2), using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize, class _Pr,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_symmetric_difference(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize], _Pr _Pred) noexcept /* terminates */ {
|
|
// XOR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest, _Pass_fn(_Pred));
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _FwdIt3, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_FwdIt3 set_symmetric_difference(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_FwdIt3 _Dest) noexcept /* terminates */ {
|
|
// XOR sets [_First1, _Last1) and [_First2, _Last2), using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt3);
|
|
return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest);
|
|
}
|
|
|
|
#if _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
template <class _ExPo, class _FwdIt1, class _FwdIt2, class _DestTy, size_t _DestSize,
|
|
_Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_DestTy* set_symmetric_difference(_ExPo&&, _FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2,
|
|
_DestTy (&_Dest)[_DestSize]) noexcept /* terminates */ {
|
|
// XOR sets [_First1, _Last1) and [_First2, _Last2), array dest
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt1);
|
|
_REQUIRE_PARALLEL_ITERATOR(_FwdIt2);
|
|
return _STD set_symmetric_difference(_First1, _Last1, _First2, _Last2, _Dest);
|
|
}
|
|
#endif // _ITERATOR_DEBUG_ARRAY_OVERLOADS
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE max_element
|
|
template <class _FwdIt, class _Pr>
|
|
constexpr _FwdIt _Max_element_unchecked(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find largest element, using _Pred
|
|
_FwdIt _Found = _First;
|
|
if (_First != _Last) {
|
|
while (++_First != _Last) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_Found, *_First)) {
|
|
_Found = _First;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Found;
|
|
}
|
|
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD constexpr _FwdIt max_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find largest element, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
_Seek_wrapped(_First, _Max_element_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred)));
|
|
return _First;
|
|
}
|
|
|
|
template <class _FwdIt>
|
|
_NODISCARD constexpr _FwdIt max_element(_FwdIt _First, _FwdIt _Last) { // find largest element, using operator<
|
|
return _STD max_element(_First, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt max_element(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// find largest element, using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD max_element(_First, _Last, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt max_element(_ExPo&&, _FwdIt _First, _FwdIt _Last) noexcept /* terminates */ {
|
|
// find largest element, using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD max_element(_First, _Last);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE min_element
|
|
template <class _FwdIt, class _Pr>
|
|
constexpr _FwdIt _Min_element_unchecked(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find smallest element, using _Pred
|
|
_FwdIt _Found = _First;
|
|
if (_First != _Last) {
|
|
while (++_First != _Last) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_First, *_Found)) {
|
|
_Found = _First;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Found;
|
|
}
|
|
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD constexpr _FwdIt min_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred) { // find smallest element, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
_Seek_wrapped(_First, _Min_element_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred)));
|
|
return _First;
|
|
}
|
|
|
|
template <class _FwdIt>
|
|
_NODISCARD constexpr _FwdIt min_element(_FwdIt _First, _FwdIt _Last) { // find smallest element, using operator<
|
|
return _STD min_element(_First, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt min_element(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// find smallest element, using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD min_element(_First, _Last, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt min_element(_ExPo&&, _FwdIt _First, _FwdIt _Last) noexcept /* terminates */ {
|
|
// find smallest element, using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD min_element(_First, _Last);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE minmax_element
|
|
template <class _FwdIt, class _Pr>
|
|
constexpr pair<_FwdIt, _FwdIt> _Minmax_element_unchecked(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
|
// find smallest and largest elements, using _Pred
|
|
pair<_FwdIt, _FwdIt> _Found(_First, _First);
|
|
|
|
if (_First != _Last) {
|
|
while (++_First != _Last) { // process one or two elements
|
|
_FwdIt _Next = _First;
|
|
if (++_Next == _Last) { // process last element
|
|
if (_DEBUG_LT_PRED(_Pred, *_First, *_Found.first)) {
|
|
_Found.first = _First;
|
|
} else if (!_DEBUG_LT_PRED(_Pred, *_First, *_Found.second)) {
|
|
_Found.second = _First;
|
|
}
|
|
} else { // process next two elements
|
|
if (_DEBUG_LT_PRED(_Pred, *_Next, *_First)) { // test _Next for new smallest
|
|
if (_DEBUG_LT_PRED(_Pred, *_Next, *_Found.first)) {
|
|
_Found.first = _Next;
|
|
}
|
|
if (!_DEBUG_LT_PRED(_Pred, *_First, *_Found.second)) {
|
|
_Found.second = _First;
|
|
}
|
|
} else { // test _First for new smallest
|
|
if (_DEBUG_LT_PRED(_Pred, *_First, *_Found.first)) {
|
|
_Found.first = _First;
|
|
}
|
|
if (!_DEBUG_LT_PRED(_Pred, *_Next, *_Found.second)) {
|
|
_Found.second = _Next;
|
|
}
|
|
}
|
|
_First = _Next;
|
|
}
|
|
}
|
|
}
|
|
|
|
return _Found;
|
|
}
|
|
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD constexpr pair<_FwdIt, _FwdIt> minmax_element(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
|
// find smallest and largest elements, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _Result = _Minmax_element_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Pass_fn(_Pred));
|
|
_Seek_wrapped(_Last, _Result.second);
|
|
_Seek_wrapped(_First, _Result.first);
|
|
return {_First, _Last};
|
|
}
|
|
|
|
template <class _FwdIt>
|
|
_NODISCARD constexpr pair<_FwdIt, _FwdIt> minmax_element(_FwdIt _First, _FwdIt _Last) {
|
|
// find smallest and largest elements, using operator<
|
|
return _STD minmax_element(_First, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD pair<_FwdIt, _FwdIt> minmax_element(
|
|
_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// find smallest and largest elements, using _Pred
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD minmax_element(_First, _Last, _Pass_fn(_Pred));
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD pair<_FwdIt, _FwdIt> minmax_element(_ExPo&&, _FwdIt _First, _FwdIt _Last) noexcept /* terminates */ {
|
|
// find smallest and largest elements, using operator<
|
|
// not parallelized at present, parallelism expected to be feasible in a future release
|
|
return _STD minmax_element(_First, _Last);
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
// FUNCTION TEMPLATE max
|
|
template <class _Ty, class _Pr>
|
|
_NODISCARD constexpr const _Ty&(max)(const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept(
|
|
noexcept(_DEBUG_LT_PRED(_Pred, _Left, _Right))) /* strengthened */ {
|
|
// return larger of _Left and _Right using _Pred
|
|
return _DEBUG_LT_PRED(_Pred, _Left, _Right) ? _Right : _Left;
|
|
}
|
|
|
|
template <class _Ty, class _Pr>
|
|
_NODISCARD constexpr _Ty(max)(initializer_list<_Ty> _Ilist, _Pr _Pred) {
|
|
// return leftmost/largest
|
|
const _Ty* _Res = _Max_element_unchecked(_Ilist.begin(), _Ilist.end(), _Pass_fn(_Pred));
|
|
return *_Res;
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 28285) // (syntax error in SAL annotation, occurs when _Ty is not an integral type)
|
|
template <class _Ty>
|
|
_NODISCARD _Post_equal_to_(_Left < _Right ? _Right : _Left) constexpr const _Ty&(max)(
|
|
const _Ty& _Left, const _Ty& _Right) noexcept(noexcept(_Left < _Right)) /* strengthened */ {
|
|
// return larger of _Left and _Right
|
|
if (_Left < _Right) {
|
|
_STL_ASSERT(!(_Right < _Left), "invalid comparator");
|
|
return _Right;
|
|
}
|
|
|
|
return _Left;
|
|
}
|
|
#pragma warning(pop)
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr _Ty(max)(initializer_list<_Ty> _Ilist) {
|
|
// return leftmost/largest
|
|
return (_STD max)(_Ilist, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE min
|
|
template <class _Ty, class _Pr>
|
|
_NODISCARD constexpr const _Ty&(min)(const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept(
|
|
noexcept(_DEBUG_LT_PRED(_Pred, _Right, _Left))) /* strengthened */ {
|
|
// return smaller of _Left and _Right using _Pred
|
|
return _DEBUG_LT_PRED(_Pred, _Right, _Left) ? _Right : _Left;
|
|
}
|
|
|
|
template <class _Ty, class _Pr>
|
|
_NODISCARD constexpr _Ty(min)(initializer_list<_Ty> _Ilist, _Pr _Pred) {
|
|
// return leftmost/smallest
|
|
const _Ty* _Res = _Min_element_unchecked(_Ilist.begin(), _Ilist.end(), _Pass_fn(_Pred));
|
|
return *_Res;
|
|
}
|
|
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 28285) // (syntax error in SAL annotation, occurs when _Ty is not an integral type)
|
|
template <class _Ty>
|
|
_NODISCARD _Post_equal_to_(_Right < _Left ? _Right : _Left) constexpr const _Ty&(min)(
|
|
const _Ty& _Left, const _Ty& _Right) noexcept(noexcept(_Right < _Left)) /* strengthened */ {
|
|
// return smaller of _Left and _Right
|
|
if (_Right < _Left) {
|
|
_STL_ASSERT(!(_Left < _Right), "invalid comparator");
|
|
return _Right;
|
|
}
|
|
|
|
return _Left;
|
|
}
|
|
#pragma warning(pop)
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr _Ty(min)(initializer_list<_Ty> _Ilist) {
|
|
// return leftmost/smallest
|
|
return (_STD min)(_Ilist, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE minmax
|
|
template <class _Ty, class _Pr>
|
|
_NODISCARD constexpr pair<const _Ty&, const _Ty&> minmax(const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept(
|
|
noexcept(_DEBUG_LT_PRED(_Pred, _Right, _Left))) /* strengthened */ {
|
|
// return pair(leftmost/smaller, rightmost/larger) of _Left and _Right
|
|
if (_DEBUG_LT_PRED(_Pred, _Right, _Left)) {
|
|
return {_Right, _Left};
|
|
}
|
|
|
|
return {_Left, _Right};
|
|
}
|
|
|
|
template <class _Ty, class _Pr>
|
|
_NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist, _Pr _Pred) {
|
|
// return {leftmost/smallest, rightmost/largest}
|
|
pair<const _Ty*, const _Ty*> _Res = _Minmax_element_unchecked(_Ilist.begin(), _Ilist.end(), _Pass_fn(_Pred));
|
|
return pair<_Ty, _Ty>(*_Res.first, *_Res.second);
|
|
}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr pair<const _Ty&, const _Ty&> minmax(const _Ty& _Left, const _Ty& _Right) noexcept(
|
|
noexcept(_Right < _Left)) /* strengthened */ {
|
|
// return pair(leftmost/smaller, rightmost/larger) of _Left and _Right
|
|
if (_Right < _Left) {
|
|
_STL_ASSERT(!(_Left < _Right), "invalid comparator");
|
|
return {_Right, _Left};
|
|
}
|
|
|
|
return {_Left, _Right};
|
|
}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr pair<_Ty, _Ty> minmax(initializer_list<_Ty> _Ilist) {
|
|
// return {leftmost/smallest, rightmost/largest}
|
|
return _STD minmax(_Ilist, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE next_permutation
|
|
template <class _BidIt, class _Pr>
|
|
_CONSTEXPR20 bool next_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) {
|
|
// permute and test for pure ascending, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UNext = _ULast;
|
|
if (_UFirst == _ULast || _UFirst == --_UNext) {
|
|
return false;
|
|
}
|
|
|
|
for (;;) { // find rightmost element smaller than successor
|
|
auto _UNext1 = _UNext;
|
|
if (_DEBUG_LT_PRED(_Pred, *--_UNext, *_UNext1)) { // swap with rightmost element that's smaller, flip suffix
|
|
auto _UMid = _ULast;
|
|
do {
|
|
--_UMid;
|
|
} while (!_DEBUG_LT_PRED(_Pred, *_UNext, *_UMid));
|
|
|
|
_STD iter_swap(_UNext, _UMid);
|
|
_STD reverse(_UNext1, _ULast);
|
|
return true;
|
|
}
|
|
|
|
if (_UNext == _UFirst) { // pure descending, flip all
|
|
_STD reverse(_UFirst, _ULast);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _BidIt>
|
|
_CONSTEXPR20 bool next_permutation(_BidIt _First, _BidIt _Last) {
|
|
// permute and test for pure ascending, using operator<
|
|
return _STD next_permutation(_First, _Last, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATE prev_permutation
|
|
template <class _BidIt, class _Pr>
|
|
_CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last, _Pr _Pred) {
|
|
// reverse permute and test for pure descending, using _Pred
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
auto _UNext = _ULast;
|
|
if (_UFirst == _ULast || _UFirst == --_UNext) {
|
|
return false;
|
|
}
|
|
|
|
for (;;) { // find rightmost element not smaller than successor
|
|
auto _UNext1 = _UNext;
|
|
if (_DEBUG_LT_PRED(_Pred, *_UNext1, *--_UNext)) { // swap with rightmost element that's not smaller, flip suffix
|
|
auto _UMid = _ULast;
|
|
do {
|
|
--_UMid;
|
|
} while (!_DEBUG_LT_PRED(_Pred, *_UMid, *_UNext));
|
|
|
|
_STD iter_swap(_UNext, _UMid);
|
|
_STD reverse(_UNext1, _ULast);
|
|
return true;
|
|
}
|
|
|
|
if (_UNext == _UFirst) { // pure ascending, flip all
|
|
_STD reverse(_UFirst, _ULast);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class _BidIt>
|
|
_CONSTEXPR20 bool prev_permutation(_BidIt _First, _BidIt _Last) {
|
|
// reverse permute and test for pure descending, using operator<
|
|
return _STD prev_permutation(_First, _Last, less<>());
|
|
}
|
|
|
|
// FUNCTION TEMPLATES is_sorted AND is_sorted_until
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
|
// find extent of range that is ordered by predicate
|
|
_Adl_verify_range(_First, _Last);
|
|
auto _UFirst = _Get_unwrapped(_First);
|
|
auto _ULast = _Get_unwrapped(_Last);
|
|
if (_UFirst != _ULast) {
|
|
for (auto _UNext = _UFirst; ++_UNext != _ULast; ++_UFirst) {
|
|
if (_DEBUG_LT_PRED(_Pred, *_UNext, *_UFirst)) {
|
|
_ULast = _UNext;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_Seek_wrapped(_Last, _ULast);
|
|
return _Last;
|
|
}
|
|
|
|
template <class _FwdIt, class _Pr>
|
|
_NODISCARD _CONSTEXPR20 bool is_sorted(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
|
// test if range is ordered by predicate
|
|
_Adl_verify_range(_First, _Last);
|
|
const auto _UFirst = _Get_unwrapped(_First);
|
|
const auto _ULast = _Get_unwrapped(_Last);
|
|
return _STD is_sorted_until(_UFirst, _ULast, _Pass_fn(_Pred)) == _ULast;
|
|
}
|
|
|
|
template <class _FwdIt>
|
|
_NODISCARD _CONSTEXPR20 _FwdIt is_sorted_until(_FwdIt _First, _FwdIt _Last) {
|
|
// find extent of range that is ordered by operator<
|
|
return _STD is_sorted_until(_First, _Last, less<>());
|
|
}
|
|
|
|
template <class _FwdIt>
|
|
_NODISCARD _CONSTEXPR20 bool is_sorted(_FwdIt _First, _FwdIt _Last) { // test if range is ordered by operator<
|
|
return _STD is_sorted(_First, _Last, less<>());
|
|
}
|
|
|
|
#if _HAS_CXX17
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt is_sorted_until(_ExPo&&, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
|
|
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool is_sorted(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept /* terminates */ {
|
|
// test if range is ordered by predicate
|
|
return _STD is_sorted_until(_STD forward<_ExPo>(_Exec), _First, _Last, _Pass_fn(_Pred)) == _Last;
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD _FwdIt is_sorted_until(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last) noexcept /* terminates */ {
|
|
// find extent of range that is ordered by operator<
|
|
return _STD is_sorted_until(_STD forward<_ExPo>(_Exec), _First, _Last, less{});
|
|
}
|
|
|
|
template <class _ExPo, class _FwdIt, _Enable_if_execution_policy_t<_ExPo> = 0>
|
|
_NODISCARD bool is_sorted(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last) noexcept /* terminates */ {
|
|
// test if range is ordered by operator<
|
|
return _STD is_sorted(_STD forward<_ExPo>(_Exec), _First, _Last, less{});
|
|
}
|
|
|
|
#endif // _HAS_CXX17
|
|
|
|
#if _HAS_CXX17
|
|
// FUNCTION TEMPLATE clamp
|
|
template <class _Ty, class _Pr>
|
|
_NODISCARD constexpr const _Ty& clamp(const _Ty& _Val, const _Ty& _Min_val, const _Ty& _Max_val, _Pr _Pred) {
|
|
// returns _Val constrained to [_Min_val, _Max_val] ordered by _Pred
|
|
#if _ITERATOR_DEBUG_LEVEL == 2
|
|
if (_DEBUG_LT_PRED(_Pred, _Max_val, _Min_val)) {
|
|
_STL_REPORT_ERROR("invalid bounds arguments passed to std::clamp");
|
|
return _Val;
|
|
}
|
|
#endif // _ITERATOR_DEBUG_LEVEL == 2
|
|
|
|
if (_DEBUG_LT_PRED(_Pred, _Max_val, _Val)) {
|
|
return _Max_val;
|
|
}
|
|
|
|
if (_DEBUG_LT_PRED(_Pred, _Val, _Min_val)) {
|
|
return _Min_val;
|
|
}
|
|
|
|
return _Val;
|
|
}
|
|
|
|
template <class _Ty>
|
|
_NODISCARD constexpr const _Ty& clamp(const _Ty& _Val, const _Ty& _Min_val, const _Ty& _Max_val) {
|
|
// returns _Val constrained to [_Min_val, _Max_val]
|
|
return _STD clamp(_Val, _Min_val, _Max_val, less<>());
|
|
}
|
|
#endif // _HAS_CXX17
|
|
|
|
_STD_END
|
|
#pragma pop_macro("new")
|
|
_STL_RESTORE_CLANG_WARNINGS
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
#endif // _STL_COMPILER_PREPROCESSOR
|
|
#endif // _ALGORITHM_
|