forked from OSchip/llvm-project
[libc++][ranges] implement `std::ranges::inplace_merge`
Differential Revision: https://reviews.llvm.org/D130627
This commit is contained in:
parent
1dc26b80b8
commit
8a61749f76
|
@ -77,7 +77,7 @@ Permutation,sort,Konstantin Varlamov,`D127557 <https://llvm.org/D127557>`_,✅
|
|||
Permutation,stable_sort,Konstantin Varlamov,`D127834 <https://llvm.org/D127834>`_,✅
|
||||
Permutation,nth_element,Konstantin Varlamov,`D128149 <https://llvm.org/D128149>`_,✅
|
||||
Permutation,partial_sort,Konstantin Varlamov,`D128744 <https://llvm.org/D128744>`_,✅
|
||||
Permutation,inplace_merge,Not assigned,n/a,Not started
|
||||
Permutation,inplace_merge,Hui Xie,`D130627 <https://llvm.org/D130627>`_,✅
|
||||
Permutation,make_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
|
||||
Permutation,push_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
|
||||
Permutation,pop_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
|
||||
|
|
|
|
@ -1,5 +1,6 @@
|
|||
set(files
|
||||
__algorithm/adjacent_find.h
|
||||
__algorithm/algorithm_family.h
|
||||
__algorithm/all_of.h
|
||||
__algorithm/any_of.h
|
||||
__algorithm/binary_search.h
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___ALGORITHM_ALGORITHM_FAMILY_H
|
||||
#define _LIBCPP___ALGORITHM_ALGORITHM_FAMILY_H
|
||||
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/move.h>
|
||||
#include <__algorithm/ranges_move.h>
|
||||
#include <__config>
|
||||
#include <__utility/move.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _AlgPolicy>
|
||||
struct _AlgFamily;
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
template <>
|
||||
struct _AlgFamily<_RangeAlgPolicy> {
|
||||
static constexpr auto __move = ranges::move;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct _AlgFamily<_ClassicAlgPolicy> {
|
||||
|
||||
// move
|
||||
template <class _InputIterator, class _OutputIterator>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 static _OutputIterator
|
||||
__move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
|
||||
return std::move(
|
||||
std::move(__first),
|
||||
std::move(__last),
|
||||
std::move(__result));
|
||||
}
|
||||
};
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___ALGORITHM_ALGORITHM_FAMILY_H
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef _LIBCPP___ALGORITHM_INPLACE_MERGE_H
|
||||
#define _LIBCPP___ALGORITHM_INPLACE_MERGE_H
|
||||
|
||||
#include <__algorithm/algorithm_family.h>
|
||||
#include <__algorithm/comp.h>
|
||||
#include <__algorithm/comp_ref_type.h>
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
|
@ -54,18 +55,17 @@ public:
|
|||
bool operator()(const _T1& __x, const _T2& __y) {return __p_(__y, __x);}
|
||||
};
|
||||
|
||||
template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2,
|
||||
class _OutputIterator>
|
||||
void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
|
||||
_InputIterator2 __first2, _InputIterator2 __last2,
|
||||
_OutputIterator __result, _Compare __comp)
|
||||
template <class _AlgPolicy, class _Compare, class _InputIterator1, class _Sent1,
|
||||
class _InputIterator2, class _Sent2, class _OutputIterator>
|
||||
void __half_inplace_merge(_InputIterator1 __first1, _Sent1 __last1,
|
||||
_InputIterator2 __first2, _Sent2 __last2,
|
||||
_OutputIterator __result, _Compare&& __comp)
|
||||
{
|
||||
for (; __first1 != __last1; ++__result)
|
||||
{
|
||||
if (__first2 == __last2)
|
||||
{
|
||||
// TODO(alg-policy): pass `_AlgPolicy` once it's supported by `move`.
|
||||
_VSTD::move(__first1, __last1, __result);
|
||||
_AlgFamily<_AlgPolicy>::__move(__first1, __last1, __result);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -84,13 +84,15 @@ void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
|
|||
}
|
||||
|
||||
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
|
||||
void
|
||||
__buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
|
||||
_Compare __comp, typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
|
||||
typename iterator_traits<_BidirectionalIterator>::difference_type __len2,
|
||||
typename iterator_traits<_BidirectionalIterator>::value_type* __buff)
|
||||
{
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
|
||||
void __buffered_inplace_merge(
|
||||
_BidirectionalIterator __first,
|
||||
_BidirectionalIterator __middle,
|
||||
_BidirectionalIterator __last,
|
||||
_Compare&& __comp,
|
||||
typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
|
||||
typename iterator_traits<_BidirectionalIterator>::difference_type __len2,
|
||||
typename iterator_traits<_BidirectionalIterator>::value_type* __buff) {
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
|
||||
__destruct_n __d(0);
|
||||
unique_ptr<value_type, __destruct_n&> __h2(__buff, __d);
|
||||
if (__len1 <= __len2)
|
||||
|
@ -98,7 +100,7 @@ __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator
|
|||
value_type* __p = __buff;
|
||||
for (_BidirectionalIterator __i = __first; __i != __middle; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
|
||||
::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
|
||||
std::__half_inplace_merge<_AlgPolicy, _Compare>(__buff, __p, __middle, __last, __first, __comp);
|
||||
std::__half_inplace_merge<_AlgPolicy>(__buff, __p, __middle, __last, __first, __comp);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -108,19 +110,22 @@ __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator
|
|||
typedef __unconstrained_reverse_iterator<_BidirectionalIterator> _RBi;
|
||||
typedef __unconstrained_reverse_iterator<value_type*> _Rv;
|
||||
typedef __invert<_Compare> _Inverted;
|
||||
std::__half_inplace_merge<_AlgPolicy, _Inverted>(_Rv(__p), _Rv(__buff),
|
||||
std::__half_inplace_merge<_AlgPolicy>(_Rv(__p), _Rv(__buff),
|
||||
_RBi(__middle), _RBi(__first),
|
||||
_RBi(__last), _Inverted(__comp));
|
||||
}
|
||||
}
|
||||
|
||||
template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
|
||||
void
|
||||
__inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
|
||||
_Compare __comp, typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
|
||||
typename iterator_traits<_BidirectionalIterator>::difference_type __len2,
|
||||
typename iterator_traits<_BidirectionalIterator>::value_type* __buff, ptrdiff_t __buff_size)
|
||||
{
|
||||
void __inplace_merge(
|
||||
_BidirectionalIterator __first,
|
||||
_BidirectionalIterator __middle,
|
||||
_BidirectionalIterator __last,
|
||||
_Compare&& __comp,
|
||||
typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
|
||||
typename iterator_traits<_BidirectionalIterator>::difference_type __len2,
|
||||
typename iterator_traits<_BidirectionalIterator>::value_type* __buff,
|
||||
ptrdiff_t __buff_size) {
|
||||
using _Ops = _IterOps<_AlgPolicy>;
|
||||
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
|
||||
|
@ -130,7 +135,7 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
|
|||
if (__len2 == 0)
|
||||
return;
|
||||
if (__len1 <= __buff_size || __len2 <= __buff_size)
|
||||
return std::__buffered_inplace_merge<_AlgPolicy, _Compare>
|
||||
return std::__buffered_inplace_merge<_AlgPolicy>
|
||||
(__first, __middle, __last, __comp, __len1, __len2, __buff);
|
||||
// shrink [__first, __middle) as much as possible (with no moves), returning if it shrinks to 0
|
||||
for (; true; ++__first, (void) --__len1)
|
||||
|
@ -158,8 +163,7 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
|
|||
__len21 = __len2 / 2;
|
||||
__m2 = __middle;
|
||||
_Ops::advance(__m2, __len21);
|
||||
// TODO: replace _ClassicAlgPolicy and __identity with _AlgPolicy and projection
|
||||
__m1 = std::__upper_bound<_ClassicAlgPolicy>(__first, __middle, *__m2, __comp, std::__identity());
|
||||
__m1 = std::__upper_bound<_AlgPolicy>(__first, __middle, *__m2, __comp, std::__identity());
|
||||
__len11 = _Ops::distance(__first, __m1);
|
||||
}
|
||||
else
|
||||
|
@ -187,9 +191,8 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
|
|||
// merge smaller range with recursive call and larger with tail recursion elimination
|
||||
if (__len11 + __len21 < __len12 + __len22)
|
||||
{
|
||||
std::__inplace_merge<_AlgPolicy, _Compare>(
|
||||
std::__inplace_merge<_AlgPolicy>(
|
||||
__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
|
||||
// _VSTD::__inplace_merge<_Compare>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
|
||||
__first = __middle;
|
||||
__middle = __m2;
|
||||
__len1 = __len12;
|
||||
|
@ -197,9 +200,8 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
|
|||
}
|
||||
else
|
||||
{
|
||||
std::__inplace_merge<_AlgPolicy, _Compare>(
|
||||
std::__inplace_merge<_AlgPolicy>(
|
||||
__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
|
||||
// _VSTD::__inplace_merge<_Compare>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
|
||||
__last = __middle;
|
||||
__middle = __m1;
|
||||
__len1 = __len11;
|
||||
|
@ -208,33 +210,40 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
|
|||
}
|
||||
}
|
||||
|
||||
template <class _BidirectionalIterator, class _Compare>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
template <class _AlgPolicy, class _BidirectionalIterator, class _Compare>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
void
|
||||
inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
|
||||
_Compare __comp)
|
||||
__inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
|
||||
_Compare&& __comp)
|
||||
{
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
|
||||
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
|
||||
difference_type __len1 = _VSTD::distance(__first, __middle);
|
||||
difference_type __len2 = _VSTD::distance(__middle, __last);
|
||||
difference_type __len1 = _IterOps<_AlgPolicy>::distance(__first, __middle);
|
||||
difference_type __len2 = _IterOps<_AlgPolicy>::distance(__middle, __last);
|
||||
difference_type __buf_size = _VSTD::min(__len1, __len2);
|
||||
// TODO: Remove the use of std::get_temporary_buffer
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
pair<value_type*, ptrdiff_t> __buf = _VSTD::get_temporary_buffer<value_type>(__buf_size);
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
unique_ptr<value_type, __return_temporary_buffer> __h(__buf.first);
|
||||
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
|
||||
return _VSTD::__inplace_merge<_ClassicAlgPolicy, _Comp_ref>(__first, __middle, __last, __comp, __len1, __len2,
|
||||
__buf.first, __buf.second);
|
||||
return std::__inplace_merge<_AlgPolicy>(
|
||||
std::move(__first), std::move(__middle), std::move(__last), __comp, __len1, __len2, __buf.first, __buf.second);
|
||||
}
|
||||
|
||||
template <class _BidirectionalIterator, class _Compare>
|
||||
inline _LIBCPP_HIDE_FROM_ABI void inplace_merge(
|
||||
_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last, _Compare __comp) {
|
||||
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
|
||||
std::__inplace_merge<_ClassicAlgPolicy>(
|
||||
std::move(__first), std::move(__middle), std::move(__last), static_cast<_Comp_ref>(__comp));
|
||||
}
|
||||
|
||||
template <class _BidirectionalIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
void
|
||||
inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last)
|
||||
{
|
||||
_VSTD::inplace_merge(__first, __middle, __last,
|
||||
std::inplace_merge(std::move(__first), std::move(__middle), std::move(__last),
|
||||
__less<typename iterator_traits<_BidirectionalIterator>::value_type>());
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#define _LIBCPP___ALGORITHM_RANGES_INPLACE_MERGE_H
|
||||
|
||||
#include <__algorithm/inplace_merge.h>
|
||||
#include <__algorithm/iterator_operations.h>
|
||||
#include <__algorithm/make_projected.h>
|
||||
#include <__config>
|
||||
#include <__functional/identity.h>
|
||||
|
@ -17,6 +18,7 @@
|
|||
#include <__functional/ranges_operations.h>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/projected.h>
|
||||
#include <__iterator/sortable.h>
|
||||
#include <__ranges/access.h>
|
||||
|
@ -36,28 +38,38 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||
namespace ranges {
|
||||
namespace __inplace_merge {
|
||||
|
||||
struct __fn {
|
||||
struct __fn {
|
||||
template <class _Iter, class _Sent, class _Comp, class _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI static constexpr auto
|
||||
__inplace_merge_impl(_Iter __first, _Iter __middle, _Sent __last, _Comp&& __comp, _Proj&& __proj) {
|
||||
auto __last_iter = ranges::next(__middle, __last);
|
||||
std::__inplace_merge<_RangeAlgPolicy>(
|
||||
std::move(__first), std::move(__middle), __last_iter, ranges::__make_projected_comp(__comp, __proj));
|
||||
return __last_iter;
|
||||
}
|
||||
|
||||
template <bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, class _Comp = ranges::less, class _Proj = identity>
|
||||
requires sortable<_Iter, _Comp, _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
_Iter operator()(_Iter __first, _Iter __middle, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__first; (void)__middle; (void)__last; (void)__comp; (void)__proj;
|
||||
return {};
|
||||
}
|
||||
template <
|
||||
bidirectional_iterator _Iter,
|
||||
sentinel_for<_Iter> _Sent,
|
||||
class _Comp = ranges::less,
|
||||
class _Proj = identity>
|
||||
requires sortable<_Iter, _Comp, _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI _Iter
|
||||
operator()(_Iter __first, _Iter __middle, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
return __inplace_merge_impl(
|
||||
std::move(__first), std::move(__middle), std::move(__last), std::move(__comp), std::move(__proj));
|
||||
}
|
||||
|
||||
template <bidirectional_range _Range, class _Comp = ranges::less, class _Proj = identity>
|
||||
requires sortable<iterator_t<_Range>, _Comp, _Proj>
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
borrowed_iterator_t<_Range> operator()(_Range&& __range, iterator_t<_Range> __middle,
|
||||
_Comp __comp = {}, _Proj __proj = {}) const {
|
||||
// TODO: implement
|
||||
(void)__range; (void)__middle; (void)__comp; (void)__proj;
|
||||
return {};
|
||||
}
|
||||
|
||||
};
|
||||
template <bidirectional_range _Range, class _Comp = ranges::less, class _Proj = identity>
|
||||
requires sortable<
|
||||
iterator_t<_Range>,
|
||||
_Comp,
|
||||
_Proj> _LIBCPP_HIDE_FROM_ABI borrowed_iterator_t<_Range>
|
||||
operator()(_Range&& __range, iterator_t<_Range> __middle, _Comp __comp = {}, _Proj __proj = {}) const {
|
||||
return __inplace_merge_impl(
|
||||
ranges::begin(__range), std::move(__middle), ranges::end(__range), std::move(__comp), std::move(__proj));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __inplace_merge
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
|
|||
}
|
||||
std::__stable_sort<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff, __buff_size);
|
||||
std::__stable_sort<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size);
|
||||
std::__inplace_merge<_AlgPolicy, _Compare>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
|
||||
std::__inplace_merge<_AlgPolicy>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
|
||||
}
|
||||
|
||||
template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
|
||||
|
|
|
@ -803,7 +803,7 @@ namespace ranges {
|
|||
set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
|
||||
Comp comp = {}, Proj1 proj1 = {},
|
||||
Proj2 proj2 = {}); // since C++20
|
||||
|
||||
|
||||
template<input_range R1, input_range R2, weakly_incrementable O,
|
||||
class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
|
||||
requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
|
||||
|
@ -816,13 +816,13 @@ namespace ranges {
|
|||
indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
|
||||
constexpr subrange<I>
|
||||
equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); // since C++20
|
||||
|
||||
|
||||
template<forward_range R, class T, class Proj = identity,
|
||||
indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
|
||||
ranges::less>
|
||||
constexpr borrowed_subrange_t<R>
|
||||
equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {}); // since C++20
|
||||
|
||||
|
||||
template<class I1, class I2, class O>
|
||||
using set_union_result = in_in_out_result<I1, I2, O>; // since C++20
|
||||
|
||||
|
@ -847,13 +847,24 @@ namespace ranges {
|
|||
ranges::less>
|
||||
constexpr bool includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {},
|
||||
Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
|
||||
|
||||
|
||||
template<input_range R1, input_range R2, class Proj1 = identity,
|
||||
class Proj2 = identity,
|
||||
indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>,
|
||||
projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
|
||||
constexpr bool includes(R1&& r1, R2&& r2, Comp comp = {},
|
||||
Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
|
||||
|
||||
template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
|
||||
class Proj = identity>
|
||||
requires sortable<I, Comp, Proj>
|
||||
I inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {}); // Since C++20
|
||||
|
||||
template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
|
||||
requires sortable<iterator_t<R>, Comp, Proj>
|
||||
borrowed_iterator_t<R>
|
||||
inplace_merge(R&& r, iterator_t<R> middle, Comp comp = {},
|
||||
Proj proj = {}); // Since C++20
|
||||
}
|
||||
|
||||
constexpr bool // constexpr in C++20
|
||||
|
@ -1607,6 +1618,7 @@ template <class BidirectionalIterator, class Compare>
|
|||
#include <__algorithm/ranges_generate.h>
|
||||
#include <__algorithm/ranges_generate_n.h>
|
||||
#include <__algorithm/ranges_includes.h>
|
||||
#include <__algorithm/ranges_inplace_merge.h>
|
||||
#include <__algorithm/ranges_is_heap.h>
|
||||
#include <__algorithm/ranges_is_heap_until.h>
|
||||
#include <__algorithm/ranges_is_partitioned.h>
|
||||
|
|
|
@ -239,6 +239,7 @@ module std [system] {
|
|||
|
||||
module __algorithm {
|
||||
module adjacent_find { private header "__algorithm/adjacent_find.h" }
|
||||
module algorithm_family { private header "__algorithm/algorithm_family.h" }
|
||||
module all_of { private header "__algorithm/all_of.h" }
|
||||
module any_of { private header "__algorithm/any_of.h" }
|
||||
module binary_search { private header "__algorithm/binary_search.h" }
|
||||
|
|
|
@ -138,8 +138,8 @@ constexpr bool all_the_algorithms()
|
|||
(void)std::ranges::is_sorted(a, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::is_sorted_until(first, last, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::is_sorted_until(a, Less(&copies)); assert(copies == 0);
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(&copies)); assert(copies == 0); }
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(&copies)); assert(copies == 0); }
|
||||
(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::lexicographical_compare(a, b, Less(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::lower_bound(first, last, value, Less(&copies)); assert(copies == 0);
|
||||
|
|
|
@ -121,8 +121,8 @@ constexpr bool all_the_algorithms()
|
|||
(void)std::ranges::is_sorted(a, Less(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::is_sorted_until(first, last, Less(), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::is_sorted_until(a, Less(), Proj(&copies)); assert(copies == 0);
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(), Proj(&copies)); assert(copies == 0); }
|
||||
//if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(), Proj(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(), Proj(&copies)); assert(copies == 0); }
|
||||
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(), Proj(&copies)); assert(copies == 0); }
|
||||
(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::lexicographical_compare(a, b, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0);
|
||||
(void)std::ranges::lower_bound(first, last, value, Less(), Proj(&copies)); assert(copies == 0);
|
||||
|
|
|
@ -37,6 +37,7 @@ END-SCRIPT
|
|||
// DO NOT MANUALLY EDIT ANYTHING BETWEEN THE MARKERS BELOW
|
||||
// GENERATED-MARKER
|
||||
#include <__algorithm/adjacent_find.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/adjacent_find.h'}}
|
||||
#include <__algorithm/algorithm_family.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/algorithm_family.h'}}
|
||||
#include <__algorithm/all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/all_of.h'}}
|
||||
#include <__algorithm/any_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/any_of.h'}}
|
||||
#include <__algorithm/binary_search.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/binary_search.h'}}
|
||||
|
|
|
@ -27,23 +27,315 @@
|
|||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#include "almost_satisfies_types.h"
|
||||
#include "counting_predicates.h"
|
||||
#include "counting_projection.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// TODO: SFINAE tests.
|
||||
template < class Iter,
|
||||
class Middle = Iter,
|
||||
class Sent = sentinel_wrapper<std::remove_cvref_t<Iter>>,
|
||||
class Comp = std::ranges::less,
|
||||
class Proj = std::identity>
|
||||
concept HasInplaceMergeIter =
|
||||
requires(Iter&& iter, Middle&& mid, Sent&& sent, Comp&& comp, Proj&& proj) {
|
||||
std::ranges::inplace_merge(
|
||||
std::forward<Iter>(iter),
|
||||
std::forward<Middle>(mid),
|
||||
std::forward<Sent>(sent),
|
||||
std::forward<Comp>(comp),
|
||||
std::forward<Proj>(proj));
|
||||
};
|
||||
|
||||
constexpr bool test() {
|
||||
// TODO: main tests.
|
||||
// TODO: A custom comparator works.
|
||||
// TODO: A custom projection works.
|
||||
static_assert(HasInplaceMergeIter<int*, int*, int*>);
|
||||
|
||||
// !bidirectional_iterator<I>
|
||||
static_assert(!HasInplaceMergeIter<BidirectionalIteratorNotDerivedFrom>);
|
||||
static_assert(!HasInplaceMergeIter<cpp20_input_iterator<int*>>);
|
||||
|
||||
// !sentinel_for<S, I>
|
||||
static_assert(!HasInplaceMergeIter<int*, int*, SentinelForNotSemiregular>);
|
||||
static_assert(!HasInplaceMergeIter<int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
|
||||
|
||||
// !sortable<I, Comp, Proj>
|
||||
static_assert(!HasInplaceMergeIter<int*, int*, int*, ComparatorNotCopyable<int*>>);
|
||||
static_assert(!HasInplaceMergeIter<const int*, const int*, const int*>);
|
||||
|
||||
template < class Range,
|
||||
class Middle = std::ranges::iterator_t<Range>,
|
||||
class Comp = std::ranges::less,
|
||||
class Proj = std::identity>
|
||||
concept HasInplaceMergeRange =
|
||||
requires(Range&& r, Middle&& mid, Comp&& comp, Proj&& proj) {
|
||||
std::ranges::inplace_merge(
|
||||
std::forward<Range>(r), std::forward<Middle>(mid), std::forward<Comp>(comp), std::forward<Proj>(proj));
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using R = UncheckedRange<T>;
|
||||
|
||||
static_assert(HasInplaceMergeRange<R<int*>, int*>);
|
||||
|
||||
// !bidirectional_range<R>
|
||||
static_assert(!HasInplaceMergeRange<R<cpp20_input_iterator<int*>>>);
|
||||
static_assert(!HasInplaceMergeRange<R<BidirectionalIteratorNotDecrementable>>);
|
||||
|
||||
// !sortable<iterator_t<R>, Comp, Proj>
|
||||
static_assert(!HasInplaceMergeRange<R<int*>, int*, ComparatorNotCopyable<int*>>);
|
||||
static_assert(!HasInplaceMergeIter<R<const int*>, const int*>);
|
||||
|
||||
template <class In, template <class> class SentWrapper, std::size_t N1, std::size_t N2>
|
||||
void testInplaceMergeImpl(std::array<int, N1> input, int midIdx, std::array<int, N2> expected) {
|
||||
std::is_sorted(input.begin(), input.begin() + midIdx);
|
||||
std::is_sorted(input.begin() + midIdx, input.end());
|
||||
std::is_sorted(expected.begin(), expected.end());
|
||||
|
||||
using Sent = SentWrapper<In>;
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
std::same_as<In> decltype(auto) result =
|
||||
std::ranges::inplace_merge(In{in.data()}, In{in.data() + midIdx}, Sent{In{in.data() + in.size()}});
|
||||
assert(std::ranges::equal(in, expected));
|
||||
assert(base(result) == in.data() + in.size());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
std::ranges::subrange r{In{in.data()}, Sent{In{in.data() + in.size()}}};
|
||||
std::same_as<In> decltype(auto) result = std::ranges::inplace_merge(r, In{in.data() + midIdx});
|
||||
assert(std::ranges::equal(in, expected));
|
||||
assert(base(result) == in.data() + in.size());
|
||||
}
|
||||
}
|
||||
|
||||
template <class In, template <class> class SentWrapper>
|
||||
void testImpl() {
|
||||
// sorted range
|
||||
{
|
||||
std::array in{0, 1, 5, 6, 9, 10};
|
||||
std::array expected = in;
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 3, expected);
|
||||
}
|
||||
|
||||
// [first, mid) is longer
|
||||
{
|
||||
std::array in{0, 5, 9, 15, 18, 22, 2, 4, 6, 10};
|
||||
std::array expected = {0, 2, 4, 5, 6, 9, 10, 15, 18, 22};
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 6, expected);
|
||||
}
|
||||
|
||||
// [first, mid) is shorter
|
||||
{
|
||||
std::array in{0, 5, 9, 2, 4, 6, 10};
|
||||
std::array expected = {0, 2, 4, 5, 6, 9, 10};
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 3, expected);
|
||||
}
|
||||
|
||||
// [first, mid) == [mid, last)
|
||||
{
|
||||
std::array in{0, 5, 9, 0, 5, 9};
|
||||
std::array expected = {0, 0, 5, 5, 9, 9};
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 3, expected);
|
||||
}
|
||||
|
||||
// duplicates within each range
|
||||
{
|
||||
std::array in{1, 5, 5, 2, 9, 9, 9};
|
||||
std::array expected = {1, 2, 5, 5, 9, 9, 9};
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 3, expected);
|
||||
}
|
||||
|
||||
// all the same
|
||||
{
|
||||
std::array in{5, 5, 5, 5, 5, 5, 5, 5};
|
||||
std::array expected = in;
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 5, expected);
|
||||
}
|
||||
|
||||
// [first, mid) is empty (mid == begin)
|
||||
{
|
||||
std::array in{0, 1, 5, 6, 9, 10};
|
||||
std::array expected = in;
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 0, expected);
|
||||
}
|
||||
|
||||
// [mid, last] is empty (mid == end)
|
||||
{
|
||||
std::array in{0, 1, 5, 6, 9, 10};
|
||||
std::array expected = in;
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 6, expected);
|
||||
}
|
||||
|
||||
// both empty
|
||||
{
|
||||
std::array<int, 0> in{};
|
||||
std::array expected = in;
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 0, expected);
|
||||
}
|
||||
|
||||
// mid == first + 1
|
||||
{
|
||||
std::array in{9, 2, 5, 7, 10};
|
||||
std::array expected{2, 5, 7, 9, 10};
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 1, expected);
|
||||
}
|
||||
|
||||
// mid == last - 1
|
||||
{
|
||||
std::array in{2, 5, 7, 10, 9};
|
||||
std::array expected{2, 5, 7, 9, 10};
|
||||
testInplaceMergeImpl<In, SentWrapper>(in, 4, expected);
|
||||
}
|
||||
}
|
||||
|
||||
template < template <class> class SentWrapper>
|
||||
void withAllPermutationsOfIter() {
|
||||
testImpl<bidirectional_iterator<int*>, SentWrapper>();
|
||||
testImpl<random_access_iterator<int*>, SentWrapper>();
|
||||
testImpl<contiguous_iterator<int*>, SentWrapper>();
|
||||
testImpl<int*, SentWrapper>();
|
||||
}
|
||||
|
||||
bool test() {
|
||||
withAllPermutationsOfIter<std::type_identity_t>();
|
||||
withAllPermutationsOfIter<sentinel_wrapper>();
|
||||
|
||||
struct Data {
|
||||
int data;
|
||||
};
|
||||
|
||||
const auto equal = [](const Data& x, const Data& y) { return x.data == y.data; };
|
||||
// Test custom comparator
|
||||
{
|
||||
std::array<Data, 4> input{{{4}, {8}, {2}, {5}}};
|
||||
std::array<Data, 4> expected{{{2}, {4}, {5}, {8}}};
|
||||
const auto comp = [](const Data& x, const Data& y) { return x.data < y.data; };
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::inplace_merge(in.begin(), in.begin() + 2, in.end(), comp);
|
||||
assert(std::ranges::equal(in, expected, equal));
|
||||
assert(result == in.end());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::inplace_merge(in, in.begin() + 2, comp);
|
||||
assert(std::ranges::equal(in, expected, equal));
|
||||
assert(result == in.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Test custom projection
|
||||
{
|
||||
std::array<Data, 4> input{{{4}, {8}, {2}, {5}}};
|
||||
std::array<Data, 4> expected{{{2}, {4}, {5}, {8}}};
|
||||
|
||||
const auto proj = &Data::data;
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::inplace_merge(in.begin(), in.begin() + 2, in.end(), {}, proj);
|
||||
assert(std::ranges::equal(in, expected, equal));
|
||||
assert(result == in.end());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::inplace_merge(in, in.begin() + 2, {}, proj);
|
||||
assert(std::ranges::equal(in, expected, equal));
|
||||
assert(result == in.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Remarks: Stable.
|
||||
{
|
||||
struct IntAndID {
|
||||
int data;
|
||||
int id;
|
||||
constexpr auto operator<=>(const IntAndID& rhs) const { return data <=> rhs.data; }
|
||||
constexpr auto operator==(const IntAndID& rhs) const { return data == rhs.data; }
|
||||
};
|
||||
std::array<IntAndID, 6> input{{{0, 0}, {1, 0}, {2, 0}, {0, 1}, {1, 1}, {2, 1}}};
|
||||
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::inplace_merge(in.begin(), in.begin() + 3, in.end());
|
||||
assert(std::ranges::equal(in, std::array{0, 0, 1, 1, 2, 2}, {}, &IntAndID::data));
|
||||
assert(std::ranges::equal(in, std::array{0, 1, 0, 1, 0, 1}, {}, &IntAndID::id));
|
||||
assert(result == in.end());
|
||||
}
|
||||
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
auto result = std::ranges::inplace_merge(in, in.begin() + 3);
|
||||
assert(std::ranges::equal(in, std::array{0, 0, 1, 1, 2, 2}, {}, &IntAndID::data));
|
||||
assert(std::ranges::equal(in, std::array{0, 1, 0, 1, 0, 1}, {}, &IntAndID::id));
|
||||
assert(result == in.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Complexity: Let N = last - first :
|
||||
// - For the overloads with no ExecutionPolicy, and if enough
|
||||
// additional memory is available, exactly N − 1 comparisons.
|
||||
// - Otherwise, O(NlogN) comparisons.
|
||||
// In either case, twice as many projections as comparisons.
|
||||
{
|
||||
std::array input{1, 2, 3, 3, 3, 7, 7, 2, 2, 5, 5, 6, 6};
|
||||
std::array expected{1, 2, 2, 2, 3, 3, 3, 5, 5, 6, 6, 7, 7};
|
||||
auto mid = 7;
|
||||
// iterator overload
|
||||
{
|
||||
auto in = input;
|
||||
int numberOfComp = 0;
|
||||
int numberOfProj = 0;
|
||||
auto result = std::ranges::inplace_merge(
|
||||
in.begin(),
|
||||
in.begin() + mid,
|
||||
in.end(),
|
||||
counting_predicate{std::ranges::less{}, numberOfComp},
|
||||
counting_projection{numberOfProj});
|
||||
assert(std::ranges::equal(in, expected));
|
||||
assert(result == in.end());
|
||||
|
||||
// the spec specifies exactly N-1 comparison but we actually
|
||||
// do not invoke as many times as specified
|
||||
assert(numberOfComp <= static_cast<int>(in.size() - 1));
|
||||
assert(numberOfProj <= 2 * numberOfComp);
|
||||
}
|
||||
// range overload
|
||||
{
|
||||
auto in = input;
|
||||
int numberOfComp = 0;
|
||||
int numberOfProj = 0;
|
||||
auto result = std::ranges::inplace_merge(
|
||||
in,
|
||||
in.begin() + mid,
|
||||
counting_predicate{std::ranges::less{}, numberOfComp},
|
||||
counting_projection{numberOfProj});
|
||||
assert(std::ranges::equal(in, expected));
|
||||
assert(result == in.end());
|
||||
assert(numberOfComp <= static_cast<int>(in.size() - 1));
|
||||
assert(numberOfProj <= 2 * numberOfComp);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
// inplace_merge is not constexpr in the latest finished Standard (C++20)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -193,8 +193,8 @@ constexpr bool test_all() {
|
|||
dangling_1st(std::ranges::stable_sort, in);
|
||||
dangling_1st(std::ranges::partial_sort, in, mid);
|
||||
dangling_1st(std::ranges::nth_element, in, mid);
|
||||
//if (!std::is_constant_evaluated())
|
||||
// dangling_1st(std::ranges::inplace_merge, in, mid);
|
||||
if (!std::is_constant_evaluated())
|
||||
dangling_1st(std::ranges::inplace_merge, in, mid);
|
||||
dangling_1st(std::ranges::make_heap, in);
|
||||
dangling_1st(std::ranges::push_heap, in);
|
||||
dangling_1st(std::ranges::pop_heap, in);
|
||||
|
|
|
@ -35,36 +35,36 @@ static_assert(std::convertible_to<decltype(binary_pred(1, 2)), bool>);
|
|||
// Invokes both the (iterator, sentinel, ...) and the (range, ...) overloads of the given niebloid.
|
||||
|
||||
// (in, ...)
|
||||
template <class Func, std::ranges::range Input, class ...Args>
|
||||
constexpr void test(Func&& func, Input& in, Args&& ...args) {
|
||||
template <class Func, std::ranges::range Input, class... Args>
|
||||
constexpr void test(Func&& func, Input& in, Args&&... args) {
|
||||
func(in.begin(), in.end(), std::forward<Args>(args)...);
|
||||
func(in, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// (in1, in2, ...)
|
||||
template <class Func, std::ranges::range Input, class ...Args>
|
||||
constexpr void test(Func&& func, Input& in1, Input& in2, Args&& ...args) {
|
||||
template <class Func, std::ranges::range Input, class... Args>
|
||||
constexpr void test(Func&& func, Input& in1, Input& in2, Args&&... args) {
|
||||
func(in1.begin(), in1.end(), in2.begin(), in2.end(), std::forward<Args>(args)...);
|
||||
func(in1, in2, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// (in, mid, ...)
|
||||
template <class Func, std::ranges::range Input, class ...Args>
|
||||
constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t<Input> mid, Args&& ...args) {
|
||||
template <class Func, std::ranges::range Input, class... Args>
|
||||
constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t<Input> mid, Args&&... args) {
|
||||
func(in.begin(), mid, in.end(), std::forward<Args>(args)...);
|
||||
func(in, mid, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
constexpr bool test_all() {
|
||||
std::array in = {1, 2, 3};
|
||||
std::array in = {1, 2, 3};
|
||||
std::array in2 = {4, 5, 6};
|
||||
auto mid = in.begin() + 1;
|
||||
auto mid = in.begin() + 1;
|
||||
|
||||
std::array output = {7, 8, 9, 10, 11, 12};
|
||||
auto out = output.begin();
|
||||
auto out2 = output.begin() + 1;
|
||||
auto out = output.begin();
|
||||
auto out2 = output.begin() + 1;
|
||||
|
||||
int x = 2;
|
||||
int x = 2;
|
||||
int count = 1;
|
||||
|
||||
test(std::ranges::any_of, in, unary_pred);
|
||||
|
@ -133,7 +133,8 @@ constexpr bool test_all() {
|
|||
test(std::ranges::stable_sort, in, binary_pred);
|
||||
test_mid(std::ranges::partial_sort, in, mid, binary_pred);
|
||||
test_mid(std::ranges::nth_element, in, mid, binary_pred);
|
||||
//test_mid(std::ranges::inplace_merge, in, mid, binary_pred);
|
||||
if (!std::is_constant_evaluated())
|
||||
test_mid(std::ranges::inplace_merge, in, mid, binary_pred);
|
||||
test(std::ranges::make_heap, in, binary_pred);
|
||||
test(std::ranges::push_heap, in, binary_pred);
|
||||
test(std::ranges::pop_heap, in, binary_pred);
|
||||
|
|
|
@ -36,34 +36,34 @@ struct Bar {
|
|||
// Invokes both the (iterator, sentinel, ...) and the (range, ...) overloads of the given niebloid.
|
||||
|
||||
// (in, ...)
|
||||
template <class Func, std::ranges::range Input, class ...Args>
|
||||
constexpr void test(Func&& func, Input& in, Args&& ...args) {
|
||||
template <class Func, std::ranges::range Input, class... Args>
|
||||
constexpr void test(Func&& func, Input& in, Args&&... args) {
|
||||
func(in.begin(), in.end(), std::forward<Args>(args)...);
|
||||
func(in, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// (in1, in2, ...)
|
||||
template <class Func, std::ranges::range Input, class ...Args>
|
||||
constexpr void test(Func&& func, Input& in1, Input& in2, Args&& ...args) {
|
||||
template <class Func, std::ranges::range Input, class... Args>
|
||||
constexpr void test(Func&& func, Input& in1, Input& in2, Args&&... args) {
|
||||
func(in1.begin(), in1.end(), in2.begin(), in2.end(), std::forward<Args>(args)...);
|
||||
func(in1, in2, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// (in, mid, ...)
|
||||
template <class Func, std::ranges::range Input, class ...Args>
|
||||
constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t<Input> mid, Args&& ...args) {
|
||||
template <class Func, std::ranges::range Input, class... Args>
|
||||
constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t<Input> mid, Args&&... args) {
|
||||
func(in.begin(), mid, in.end(), std::forward<Args>(args)...);
|
||||
func(in, mid, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
constexpr bool test_all() {
|
||||
std::array in = {Bar{Foo{1}}, Bar{Foo{2}}, Bar{Foo{3}}};
|
||||
std::array in = {Bar{Foo{1}}, Bar{Foo{2}}, Bar{Foo{3}}};
|
||||
std::array in2 = {Bar{Foo{4}}, Bar{Foo{5}}, Bar{Foo{6}}};
|
||||
auto mid = in.begin() + 1;
|
||||
auto mid = in.begin() + 1;
|
||||
|
||||
std::array output = {Bar{Foo{7}}, Bar{Foo{8}}, Bar{Foo{9}}, Bar{Foo{10}}, Bar{Foo{11}}, Bar{Foo{12}}};
|
||||
auto out = output.begin();
|
||||
auto out2 = output.begin() + 1;
|
||||
auto out = output.begin();
|
||||
auto out2 = output.begin() + 1;
|
||||
|
||||
Bar a{Foo{1}};
|
||||
Bar b{Foo{2}};
|
||||
|
@ -162,7 +162,8 @@ constexpr bool test_all() {
|
|||
test(std::ranges::stable_sort, in, &Foo::binary_pred, &Bar::val);
|
||||
test_mid(std::ranges::partial_sort, in, mid, &Foo::binary_pred, &Bar::val);
|
||||
test_mid(std::ranges::nth_element, in, mid, &Foo::binary_pred, &Bar::val);
|
||||
//test_mid(std::ranges::inplace_merge, in, mid, binary_pred);
|
||||
if (!std::is_constant_evaluated())
|
||||
test_mid(std::ranges::inplace_merge, in, mid, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::make_heap, in, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::push_heap, in, &Foo::binary_pred, &Bar::val);
|
||||
test(std::ranges::pop_heap, in, &Foo::binary_pred, &Bar::val);
|
||||
|
|
|
@ -164,6 +164,7 @@ constexpr void run_tests() {
|
|||
// test(std::ranges::stable_sort, in);
|
||||
test_mid(std::ranges::partial_sort, in, mid);
|
||||
test_mid(std::ranges::nth_element, in, mid);
|
||||
// TODO(ranges): `inplace_merge` requires `ranges::rotate` to be implemented.
|
||||
//if (!std::is_constant_evaluated())
|
||||
// test_mid(std::ranges::inplace_merge, in, mid);
|
||||
test(std::ranges::make_heap, in);
|
||||
|
|
|
@ -87,7 +87,7 @@ static_assert(test(std::ranges::for_each_n, a, 10, odd));
|
|||
static_assert(test(std::ranges::generate, a, gen));
|
||||
static_assert(test(std::ranges::generate_n, a, 10, gen));
|
||||
static_assert(test(std::ranges::includes, a, a));
|
||||
//static_assert(test(std::ranges::inplace_merge, a, a+5));
|
||||
static_assert(test(std::ranges::inplace_merge, a, a+5));
|
||||
static_assert(test(std::ranges::is_heap, a));
|
||||
static_assert(test(std::ranges::is_heap_until, a));
|
||||
static_assert(test(std::ranges::is_partitioned, a, odd));
|
||||
|
|
Loading…
Reference in New Issue