This completes the implementation of P2562R1 for C++26.
Unlike the other constexpr algorithms of the same family,
stable_partition does not have a constexpr-friendly version "ready to
use" during constant evaluation. In fact, it is not even available on
freestanding, because it always allocates a temporary memory buffer.
This commit implements the simplest possible strategy: during constant
evaluation allocate a buffer of length 1 on the stack, and use that as
a working area.
libstdc++-v3/ChangeLog:
* include/bits/algorithmfwd.h (stable_partition): Mark it
as constexpr for C++26.
* include/bits/ranges_algo.h (__stable_partition_fn): Likewise.
* include/bits/stl_algo.h (stable_partition): Mark it as
constexpr for C++26; during constant evaluation use a new
codepath where a temporary buffer of 1 element is used.
* testsuite/25_algorithms/headers/algorithm/synopsis.cc
(stable_partition): Add constexpr.
* testsuite/25_algorithms/stable_partition/constexpr.cc: New test.
#if _GLIBCXX_HOSTED
template<typename _BIter, typename _Predicate>
+ _GLIBCXX26_CONSTEXPR
_BIter
stable_partition(_BIter, _BIter, _Predicate);
#endif
typename _Proj = identity,
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
requires permutable<_Iter>
+ _GLIBCXX26_CONSTEXPR
subrange<_Iter>
operator()(_Iter __first, _Sent __last,
_Pred __pred, _Proj __proj = {}) const
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>>
_Pred>
requires permutable<iterator_t<_Range>>
+ _GLIBCXX26_CONSTEXPR
borrowed_subrange_t<_Range>
operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const
{
/// move-assign an element onto itself.
template<typename _ForwardIterator, typename _Pointer, typename _Predicate,
typename _Distance>
+ _GLIBCXX26_CONSTEXPR
_ForwardIterator
__stable_partition_adaptive(_ForwardIterator __first,
_ForwardIterator __last,
}
template<typename _ForwardIterator, typename _Predicate>
+ _GLIBCXX26_CONSTEXPR
_ForwardIterator
__stable_partition(_ForwardIterator __first, _ForwardIterator __last,
_Predicate __pred)
typedef typename iterator_traits<_ForwardIterator>::difference_type
_DistanceType;
+ const _DistanceType __len = std::distance(__first, __last);
+
+#if __glibcxx_constexpr_algorithms >= 202306L // >= C++26
+ if consteval {
+ // Simulate a _Temporary_buffer of length 1:
+ _ValueType __buf = std::move(*__first);
+ *__first = std::move(__buf);
+ return std::__stable_partition_adaptive(__first, __last, __pred,
+ __len,
+ &__buf,
+ _DistanceType(1));
+ }
+#endif
+
_Temporary_buffer<_ForwardIterator, _ValueType>
- __buf(__first, std::distance(__first, __last));
+ __buf(__first, __len);
return
std::__stable_partition_adaptive(__first, __last, __pred,
- _DistanceType(__buf.requested_size()),
+ __len,
__buf.begin(),
_DistanceType(__buf.size()));
}
* relative ordering after calling @p stable_partition().
*/
template<typename _ForwardIterator, typename _Predicate>
+ _GLIBCXX26_CONSTEXPR
inline _ForwardIterator
stable_partition(_ForwardIterator __first, _ForwardIterator __last,
_Predicate __pred)
partition(_BIter, _BIter, _Predicate);
template<typename _BIter, typename _Predicate>
+ _GLIBCXX26_CONSTEXPR
_BIter
stable_partition(_BIter, _BIter, _Predicate);
--- /dev/null
+// { dg-do compile { target c++26 } }
+
+#include <algorithm>
+#include <array>
+
+constexpr auto
+create_array()
+{
+ return std::to_array({0, 10, 1, 2, 3, 3, 4, -1, -2, -4, 5, 6});
+}
+
+constexpr bool
+test01()
+{
+ auto ar = create_array();
+ auto pred = [](int i) { return i % 2 == 0; };
+ std::stable_partition(ar.begin(), ar.end(), pred);
+ return std::is_partitioned(ar.begin(), ar.end(), pred);
+}
+
+static_assert(test01());
+
+constexpr bool
+test02()
+{
+ auto ar = create_array();
+ auto pred = [](int i) { return i % 2 == 0; };
+ std::ranges::stable_partition(ar, pred);
+ return std::ranges::is_partitioned(ar, pred);
+}
+
+static_assert(test02());
+
+constexpr bool
+test03()
+{
+ auto ar = create_array();
+ auto pred = [](int i) { return i % 2 == 0; };
+ auto proj = [](int i) { return i + 1; };
+ std::ranges::stable_partition(ar, pred, proj);
+ return std::ranges::is_partitioned(ar, pred, proj);
+}
+
+static_assert(test03());