Skip to content

Commit 493f140

Browse files
committed
[libc++] [P0879] constexpr std::sort
This completes libc++'s implementation of P0879 "Constexpr for swap and swap related functions." http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0879r0.html For the feature-macro adjustment, see https://cplusplus.github.io/LWG/issue3256 Differential Revision: https://reviews.llvm.org/D93661
1 parent 26e9c99 commit 493f140

File tree

10 files changed

+256
-90
lines changed

10 files changed

+256
-90
lines changed

Diff for: libcxx/docs/Cxx2aStatusIssuesStatus.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@
176176
"`3244 <https://wg21.link/LWG3244>`__","Constraints for ``Source``\ in |sect|\ [fs.path.req] insufficiently constrainty","Belfast","",""
177177
"`3241 <https://wg21.link/LWG3241>`__","``chrono-spec``\ grammar ambiguity in |sect|\ [time.format]","Belfast","",""
178178
"`3257 <https://wg21.link/LWG3257>`__","Missing feature testing macro update from P0858","Belfast","",""
179-
"`3256 <https://wg21.link/LWG3256>`__","Feature testing macro for ``constexpr``\ algorithms","Belfast","",""
179+
"`3256 <https://wg21.link/LWG3256>`__","Feature testing macro for ``constexpr``\ algorithms","Belfast","|Complete|","13.0"
180180
"`3273 <https://wg21.link/LWG3273>`__","Specify ``weekday_indexed``\ to range of ``[0, 7]``\ ","Belfast","",""
181181
"`3070 <https://wg21.link/LWG3070>`__","``path::lexically_relative``\ causes surprising results if a filename can also be a *root-name*","Belfast","",""
182182
"`3266 <https://wg21.link/LWG3266>`__","``to_chars(bool)``\ should be deleted","Belfast","",""

Diff for: libcxx/docs/Cxx2aStatusPaperStatus.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"`P0759R1 <https://wg21.link/P0759R1>`__","LWG","fpos Requirements","Rapperswil","|Complete|","11.0"
4141
"`P0769R2 <https://wg21.link/P0769R2>`__","LWG","Add shift to <algorithm>","Rapperswil","|Complete|","12.0"
4242
"`P0788R3 <https://wg21.link/P0788R3>`__","LWG","Standard Library Specification in a Concepts and Contracts World","Rapperswil","*Removed in Cologne*","n/a"
43-
"`P0879R0 <https://wg21.link/P0879R0>`__","LWG","Constexpr for swap and swap related functions Also resolves LWG issue 2800.","Rapperswil","",""
43+
"`P0879R0 <https://wg21.link/P0879R0>`__","LWG","Constexpr for swap and swap related functions Also resolves LWG issue 2800.","Rapperswil","|Complete|","13.0"
4444
"`P0887R1 <https://wg21.link/P0887R1>`__","LWG","The identity metafunction","Rapperswil","|Complete|","8.0"
4545
"`P0892R2 <https://wg21.link/P0892R2>`__","CWG","explicit(bool)","Rapperswil","",""
4646
"`P0898R3 <https://wg21.link/P0898R3>`__","LWG","Standard Library Concepts","Rapperswil","|In Progress|",""

Diff for: libcxx/docs/FeatureTestMacroTable.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ Status
200200
------------------------------------------------- -----------------
201201
``__cpp_lib_concepts`` *unimplemented*
202202
------------------------------------------------- -----------------
203-
``__cpp_lib_constexpr_algorithms`` *unimplemented*
203+
``__cpp_lib_constexpr_algorithms`` ``201806L``
204204
------------------------------------------------- -----------------
205205
``__cpp_lib_constexpr_complex`` *unimplemented*
206206
------------------------------------------------- -----------------

Diff for: libcxx/include/algorithm

+29-41
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,11 @@ template <class ForwardIterator, class Compare>
351351
is_sorted_until(ForwardIterator first, ForwardIterator last, Compare comp);
352352
353353
template <class RandomAccessIterator>
354-
void
354+
constexpr void // constexpr in C++20
355355
sort(RandomAccessIterator first, RandomAccessIterator last);
356356
357357
template <class RandomAccessIterator, class Compare>
358-
void
358+
constexpr void // constexpr in C++20
359359
sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
360360
361361
template <class RandomAccessIterator>
@@ -4047,7 +4047,6 @@ template <class _Compare, class _RandomAccessIterator>
40474047
void
40484048
__sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
40494049
{
4050-
// _Compare is known to be a reference type
40514050
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
40524051
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
40534052
const difference_type __limit = is_trivially_copy_constructible<value_type>::value &&
@@ -4236,47 +4235,13 @@ __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __c
42364235
}
42374236
}
42384237

4239-
// This forwarder keeps the top call and the recursive calls using the same instantiation, forcing a reference _Compare
4240-
template <class _RandomAccessIterator, class _Compare>
4241-
inline _LIBCPP_INLINE_VISIBILITY
4242-
void
4243-
sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
4244-
{
4245-
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
4246-
_VSTD::__sort<_Comp_ref>(__first, __last, _Comp_ref(__comp));
4247-
}
4248-
4249-
template <class _RandomAccessIterator>
4250-
inline _LIBCPP_INLINE_VISIBILITY
4251-
void
4252-
sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
4253-
{
4254-
_VSTD::sort(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
4255-
}
4256-
4257-
template <class _Tp>
4258-
inline _LIBCPP_INLINE_VISIBILITY
4259-
void
4260-
sort(_Tp** __first, _Tp** __last)
4261-
{
4262-
_VSTD::sort((uintptr_t*)__first, (uintptr_t*)__last, __less<uintptr_t>());
4263-
}
4264-
4265-
template <class _Tp>
4266-
inline _LIBCPP_INLINE_VISIBILITY
4267-
void
4268-
sort(__wrap_iter<_Tp*> __first, __wrap_iter<_Tp*> __last)
4269-
{
4270-
_VSTD::sort(__first.base(), __last.base());
4271-
}
4272-
4273-
template <class _Tp, class _Compare>
4238+
template <class _Compare, class _Tp>
42744239
inline _LIBCPP_INLINE_VISIBILITY
42754240
void
4276-
sort(__wrap_iter<_Tp*> __first, __wrap_iter<_Tp*> __last, _Compare __comp)
4241+
__sort(_Tp** __first, _Tp** __last, __less<_Tp*>&)
42774242
{
4278-
typedef typename add_lvalue_reference<_Compare>::type _Comp_ref;
4279-
_VSTD::sort<_Tp*, _Comp_ref>(__first.base(), __last.base(), __comp);
4243+
__less<uintptr_t> __comp;
4244+
_VSTD::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
42804245
}
42814246

42824247
_LIBCPP_EXTERN_TEMPLATE(_LIBCPP_FUNC_VIS void __sort<__less<char>&, char*>(char*, char*, __less<char>&))
@@ -5478,6 +5443,29 @@ nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomA
54785443
_VSTD::nth_element(__first, __nth, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
54795444
}
54805445

5446+
// sort
5447+
5448+
template <class _RandomAccessIterator, class _Compare>
5449+
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
5450+
void
5451+
sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
5452+
{
5453+
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
5454+
if (__libcpp_is_constant_evaluated()) {
5455+
_VSTD::__partial_sort<_Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
5456+
} else {
5457+
_VSTD::__sort<_Comp_ref>(_VSTD::__unwrap_iter(__first), _VSTD::__unwrap_iter(__last), _Comp_ref(__comp));
5458+
}
5459+
}
5460+
5461+
template <class _RandomAccessIterator>
5462+
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
5463+
void
5464+
sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
5465+
{
5466+
_VSTD::sort(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
5467+
}
5468+
54815469
// includes
54825470

54835471
template <class _Compare, class _InputIterator1, class _InputIterator2>

Diff for: libcxx/include/version

+1-1
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ __cpp_lib_void_t 201411L <type_traits>
294294
# define __cpp_lib_char8_t 201811L
295295
# endif
296296
// # define __cpp_lib_concepts 202002L
297-
// # define __cpp_lib_constexpr_algorithms 201806L
297+
# define __cpp_lib_constexpr_algorithms 201806L
298298
// # define __cpp_lib_constexpr_complex 201711L
299299
# define __cpp_lib_constexpr_dynamic_alloc 201907L
300300
# define __cpp_lib_constexpr_functional 201907L
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <algorithm>
10+
11+
// template<RandomAccessIterator Iter>
12+
// requires ShuffleIterator<Iter>
13+
// && LessThanComparable<Iter::value_type>
14+
// void
15+
// sort(Iter first, Iter last);
16+
17+
#include <algorithm>
18+
#include <cassert>
19+
20+
#include "test_macros.h"
21+
#include "test_iterators.h"
22+
#include "MoveOnly.h"
23+
24+
template<int N, class T, class Iter>
25+
TEST_CONSTEXPR_CXX20 bool test()
26+
{
27+
int orig[N] = {};
28+
unsigned x = 1;
29+
for (int i=0; i < N; ++i) {
30+
x = (x * 1664525) + 1013904223;
31+
orig[i] = x % 1000;
32+
}
33+
T work[N] = {};
34+
std::copy(orig, orig+N, work);
35+
std::sort(Iter(work), Iter(work+N));
36+
assert(std::is_sorted(work, work+N));
37+
assert(std::is_permutation(work, work+N, orig));
38+
39+
return true;
40+
}
41+
42+
template<int N, class T, class Iter>
43+
TEST_CONSTEXPR_CXX20 bool test_pointers()
44+
{
45+
T data[N] = {};
46+
T *orig[N] = {};
47+
unsigned x = 1;
48+
for (int i=0; i < N; ++i) {
49+
orig[i] = &data[x % 258];
50+
}
51+
T *work[N] = {};
52+
std::copy(orig, orig+N, work);
53+
std::sort(Iter(work), Iter(work+N));
54+
assert(std::is_sorted(work, work+N));
55+
assert(std::is_permutation(work, work+N, orig));
56+
57+
return true;
58+
}
59+
60+
int main(int, char**)
61+
{
62+
test<7, int, int*>();
63+
test<7, int, random_access_iterator<int*> >();
64+
test<257, int, int*>();
65+
test<257, int, random_access_iterator<int*> >();
66+
67+
#if TEST_STD_VER >= 11
68+
test<7, MoveOnly, MoveOnly*>();
69+
test<7, MoveOnly, random_access_iterator<MoveOnly*> >();
70+
test<257, MoveOnly, MoveOnly*>();
71+
test<257, MoveOnly, random_access_iterator<MoveOnly*> >();
72+
#endif
73+
74+
test_pointers<17, char, char**>();
75+
test_pointers<17, char, random_access_iterator<char**> >();
76+
test_pointers<17, const char, const char**>();
77+
test_pointers<17, const char, random_access_iterator<const char**> >();
78+
test_pointers<17, int, int**>();
79+
test_pointers<17, int, random_access_iterator<int**> >();
80+
81+
#if TEST_STD_VER >= 20
82+
static_assert(test<7, int, int*>());
83+
static_assert(test<7, int, random_access_iterator<int*>>());
84+
static_assert(test<257, int, int*>());
85+
static_assert(test<257, int, random_access_iterator<int*>>());
86+
87+
static_assert(test<7, MoveOnly, MoveOnly*>());
88+
static_assert(test<7, MoveOnly, random_access_iterator<MoveOnly*>>());
89+
static_assert(test<257, MoveOnly, MoveOnly*>());
90+
static_assert(test<257, MoveOnly, random_access_iterator<MoveOnly*>>());
91+
92+
static_assert(test_pointers<17, char, char**>());
93+
static_assert(test_pointers<17, char, random_access_iterator<char**>>());
94+
static_assert(test_pointers<17, const char, const char**>());
95+
static_assert(test_pointers<17, const char, random_access_iterator<const char**>>());
96+
static_assert(test_pointers<17, int, int**>());
97+
static_assert(test_pointers<17, int, random_access_iterator<int**>>());
98+
#endif
99+
100+
return 0;
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <algorithm>
10+
11+
// template<RandomAccessIterator Iter, StrictWeakOrder<auto, Iter::value_type> Compare>
12+
// requires ShuffleIterator<Iter>
13+
// && CopyConstructible<Compare>
14+
// void
15+
// sort(Iter first, Iter last, Compare comp);
16+
17+
#include <algorithm>
18+
#include <cassert>
19+
#include <functional>
20+
21+
#include "test_macros.h"
22+
#include "test_iterators.h"
23+
#include "MoveOnly.h"
24+
25+
template<int N, class T, class Iter>
26+
TEST_CONSTEXPR_CXX20 bool test()
27+
{
28+
int orig[N] = {};
29+
unsigned x = 1;
30+
for (int i=0; i < N; ++i) {
31+
x = (x * 1664525) + 1013904223;
32+
orig[i] = x % 1000;
33+
}
34+
T work[N] = {};
35+
std::copy(orig, orig+N, work);
36+
std::sort(Iter(work), Iter(work+N), std::greater<T>());
37+
assert(std::is_sorted(work, work+N, std::greater<T>()));
38+
assert(std::is_permutation(work, work+N, orig));
39+
40+
return true;
41+
}
42+
43+
template<int N, class T, class Iter>
44+
TEST_CONSTEXPR_CXX20 bool test_pointers()
45+
{
46+
T data[N] = {};
47+
T *orig[N] = {};
48+
unsigned x = 1;
49+
for (int i=0; i < N; ++i) {
50+
orig[i] = &data[x % 258];
51+
}
52+
T *work[N] = {};
53+
std::copy(orig, orig+N, work);
54+
std::sort(Iter(work), Iter(work+N), std::greater<T*>());
55+
assert(std::is_sorted(work, work+N, std::greater<T*>()));
56+
assert(std::is_permutation(work, work+N, orig));
57+
58+
return true;
59+
}
60+
61+
int main(int, char**)
62+
{
63+
test<7, int, int*>();
64+
test<7, int, random_access_iterator<int*> >();
65+
test<257, int, int*>();
66+
test<257, int, random_access_iterator<int*> >();
67+
68+
#if TEST_STD_VER >= 11
69+
test<7, MoveOnly, MoveOnly*>();
70+
test<7, MoveOnly, random_access_iterator<MoveOnly*> >();
71+
test<257, MoveOnly, MoveOnly*>();
72+
test<257, MoveOnly, random_access_iterator<MoveOnly*> >();
73+
#endif
74+
75+
test_pointers<17, char, char**>();
76+
test_pointers<17, char, random_access_iterator<char**> >();
77+
test_pointers<17, const char, const char**>();
78+
test_pointers<17, const char, random_access_iterator<const char**> >();
79+
test_pointers<17, int, int**>();
80+
test_pointers<17, int, random_access_iterator<int**> >();
81+
82+
#if TEST_STD_VER >= 20
83+
static_assert(test<7, int, int*>());
84+
static_assert(test<7, int, random_access_iterator<int*>>());
85+
static_assert(test<257, int, int*>());
86+
static_assert(test<257, int, random_access_iterator<int*>>());
87+
88+
static_assert(test<7, MoveOnly, MoveOnly*>());
89+
static_assert(test<7, MoveOnly, random_access_iterator<MoveOnly*>>());
90+
static_assert(test<257, MoveOnly, MoveOnly*>());
91+
static_assert(test<257, MoveOnly, random_access_iterator<MoveOnly*>>());
92+
93+
static_assert(test_pointers<17, char, char**>());
94+
static_assert(test_pointers<17, char, random_access_iterator<char**>>());
95+
static_assert(test_pointers<17, const char, const char**>());
96+
static_assert(test_pointers<17, const char, random_access_iterator<const char**>>());
97+
static_assert(test_pointers<17, int, int**>());
98+
static_assert(test_pointers<17, int, random_access_iterator<int**>>());
99+
#endif
100+
101+
return 0;
102+
}

Diff for: libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp

+10-22
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,11 @@
148148
# error "__cpp_lib_clamp should have the value 201603L in c++20"
149149
# endif
150150

151-
# if !defined(_LIBCPP_VERSION)
152-
# ifndef __cpp_lib_constexpr_algorithms
153-
# error "__cpp_lib_constexpr_algorithms should be defined in c++20"
154-
# endif
155-
# if __cpp_lib_constexpr_algorithms != 201806L
156-
# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++20"
157-
# endif
158-
# else // _LIBCPP_VERSION
159-
# ifdef __cpp_lib_constexpr_algorithms
160-
# error "__cpp_lib_constexpr_algorithms should not be defined because it is unimplemented in libc++!"
161-
# endif
151+
# ifndef __cpp_lib_constexpr_algorithms
152+
# error "__cpp_lib_constexpr_algorithms should be defined in c++20"
153+
# endif
154+
# if __cpp_lib_constexpr_algorithms != 201806L
155+
# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++20"
162156
# endif
163157

164158
# if !defined(_LIBCPP_VERSION)
@@ -217,17 +211,11 @@
217211
# error "__cpp_lib_clamp should have the value 201603L in c++2b"
218212
# endif
219213

220-
# if !defined(_LIBCPP_VERSION)
221-
# ifndef __cpp_lib_constexpr_algorithms
222-
# error "__cpp_lib_constexpr_algorithms should be defined in c++2b"
223-
# endif
224-
# if __cpp_lib_constexpr_algorithms != 201806L
225-
# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++2b"
226-
# endif
227-
# else // _LIBCPP_VERSION
228-
# ifdef __cpp_lib_constexpr_algorithms
229-
# error "__cpp_lib_constexpr_algorithms should not be defined because it is unimplemented in libc++!"
230-
# endif
214+
# ifndef __cpp_lib_constexpr_algorithms
215+
# error "__cpp_lib_constexpr_algorithms should be defined in c++2b"
216+
# endif
217+
# if __cpp_lib_constexpr_algorithms != 201806L
218+
# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++2b"
231219
# endif
232220

233221
# if !defined(_LIBCPP_VERSION)

0 commit comments

Comments
 (0)