aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHui Xie <hui.xie1990@gmail.com>2022-07-27 13:20:16 +0100
committerTom Stellard <tstellar@redhat.com>2022-08-02 21:48:48 -0700
commite38b9de601b36b26754854fda60b11817fd54b17 (patch)
tree4b18578556e815ed05f8259b49bd0b418497b09f
parent96a26d96c7d468af4dde717827365e5eeb5e289d (diff)
[libc++][ranges] implement `std::ranges::inplace_merge`
Differential Revision: https://reviews.llvm.org/D130627 (cherry picked from commit 8a61749f767e9af773051fc4f6dc99276fe189e3)
-rw-r--r--libcxx/docs/Status/RangesAlgorithms.csv2
-rw-r--r--libcxx/include/CMakeLists.txt1
-rw-r--r--libcxx/include/__algorithm/algorithm_family.h52
-rw-r--r--libcxx/include/__algorithm/inplace_merge.h89
-rw-r--r--libcxx/include/__algorithm/ranges_inplace_merge.h52
-rw-r--r--libcxx/include/__algorithm/stable_sort.h2
-rw-r--r--libcxx/include/algorithm20
-rw-r--r--libcxx/include/module.modulemap.in1
-rw-r--r--libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp4
-rw-r--r--libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp4
-rw-r--r--libcxx/test/libcxx/private_headers.verify.cpp1
-rw-r--r--libcxx/test/std/algorithms/alg.sorting/alg.merge/ranges_inplace_merge.pass.cpp304
-rw-r--r--libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp4
-rw-r--r--libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp25
-rw-r--r--libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp23
-rw-r--r--libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp1
-rw-r--r--libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp2
17 files changed, 485 insertions, 102 deletions
diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv
index ecbfb3329c53..3ae87225c3eb 100644
--- a/libcxx/docs/Status/RangesAlgorithms.csv
+++ b/libcxx/docs/Status/RangesAlgorithms.csv
@@ -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>`_,✅
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 970b4683d37b..371f0c0cf223 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -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
diff --git a/libcxx/include/__algorithm/algorithm_family.h b/libcxx/include/__algorithm/algorithm_family.h
new file mode 100644
index 000000000000..30ffff832ebc
--- /dev/null
+++ b/libcxx/include/__algorithm/algorithm_family.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
diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index cb662e791872..e33894eada3f 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.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>());
}
diff --git a/libcxx/include/__algorithm/ranges_inplace_merge.h b/libcxx/include/__algorithm/ranges_inplace_merge.h
index a0867e486c3a..2152e6648c35 100644
--- a/libcxx/include/__algorithm/ranges_inplace_merge.h
+++ b/libcxx/include/__algorithm/ranges_inplace_merge.h
@@ -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
diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index 6122758bdefe..fb149eeb65dc 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -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>
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 197b3b1043bb..4fc353a8ce5d 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -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>
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 98485bcd93ab..1cfd4ae3bfef 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -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" }
diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
index 48eeb01b5758..669fa9c1842e 100644
--- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
@@ -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);
diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
index 80b8a5ec4d83..22fdf09888af 100644
--- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
@@ -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);
diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
index f9cb581c16b8..5b3e65be251d 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -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'}}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/ranges_inplace_merge.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/ranges_inplace_merge.pass.cpp
index fff2a6700455..12863b8b9e01 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/ranges_inplace_merge.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/ranges_inplace_merge.pass.cpp
@@ -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;
}
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
index 40d1043d4b1b..e147c875902c 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
@@ -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);
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp
index f5f716086936..eeeec9c1f57f 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp
@@ -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);
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp
index 2da3db405c32..aa0b15db6dee 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp
@@ -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);
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
index aba570160899..4013065eb42a 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
@@ -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);
diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
index ebe78c174221..1fc6dfb89c4b 100644
--- a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
+++ b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
@@ -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));