blob: 04c6d48e92500adcd731c13b505b7589df08851b [file] [log] [blame]
commit 493f1407927cdf6db2e08f150ed9f9b8abe4ac45
Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Sun Dec 20 15:21:42 2020 -0500
[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
diff --git a/libcxx/docs/Cxx2aStatusIssuesStatus.csv b/libcxx/docs/Cxx2aStatusIssuesStatus.csv
index 859c52ae2b21..d2adde69d9d2 100644
--- a/libcxx/docs/Cxx2aStatusIssuesStatus.csv
+++ b/libcxx/docs/Cxx2aStatusIssuesStatus.csv
@@ -176,7 +176,7 @@
"`3244 <https://wg21.link/LWG3244>`__","Constraints for ``Source``\ in |sect|\ [fs.path.req] insufficiently constrainty","Belfast","",""
"`3241 <https://wg21.link/LWG3241>`__","``chrono-spec``\ grammar ambiguity in |sect|\ [time.format]","Belfast","",""
"`3257 <https://wg21.link/LWG3257>`__","Missing feature testing macro update from P0858","Belfast","",""
-"`3256 <https://wg21.link/LWG3256>`__","Feature testing macro for ``constexpr``\ algorithms","Belfast","",""
+"`3256 <https://wg21.link/LWG3256>`__","Feature testing macro for ``constexpr``\ algorithms","Belfast","|Complete|","13.0"
"`3273 <https://wg21.link/LWG3273>`__","Specify ``weekday_indexed``\ to range of ``[0, 7]``\ ","Belfast","",""
"`3070 <https://wg21.link/LWG3070>`__","``path::lexically_relative``\ causes surprising results if a filename can also be a *root-name*","Belfast","",""
"`3266 <https://wg21.link/LWG3266>`__","``to_chars(bool)``\ should be deleted","Belfast","",""
diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv
index b3b60d2ca730..d3819a83fa43 100644
--- a/libcxx/docs/Cxx2aStatusPaperStatus.csv
+++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv
@@ -40,7 +40,7 @@
"`P0759R1 <https://wg21.link/P0759R1>`__","LWG","fpos Requirements","Rapperswil","|Complete|","11.0"
"`P0769R2 <https://wg21.link/P0769R2>`__","LWG","Add shift to <algorithm>","Rapperswil","|Complete|","12.0"
"`P0788R3 <https://wg21.link/P0788R3>`__","LWG","Standard Library Specification in a Concepts and Contracts World","Rapperswil","*Removed in Cologne*","n/a"
-"`P0879R0 <https://wg21.link/P0879R0>`__","LWG","Constexpr for swap and swap related functions Also resolves LWG issue 2800.","Rapperswil","",""
+"`P0879R0 <https://wg21.link/P0879R0>`__","LWG","Constexpr for swap and swap related functions Also resolves LWG issue 2800.","Rapperswil","|Complete|","13.0"
"`P0887R1 <https://wg21.link/P0887R1>`__","LWG","The identity metafunction","Rapperswil","|Complete|","8.0"
"`P0892R2 <https://wg21.link/P0892R2>`__","CWG","explicit(bool)","Rapperswil","",""
"`P0898R3 <https://wg21.link/P0898R3>`__","LWG","Standard Library Concepts","Rapperswil","|In Progress|",""
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 5fe7005c19c2..7028ff0d83f1 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -200,7 +200,7 @@ Status
------------------------------------------------- -----------------
``__cpp_lib_concepts`` *unimplemented*
------------------------------------------------- -----------------
- ``__cpp_lib_constexpr_algorithms`` *unimplemented*
+ ``__cpp_lib_constexpr_algorithms`` ``201806L``
------------------------------------------------- -----------------
``__cpp_lib_constexpr_complex`` *unimplemented*
------------------------------------------------- -----------------
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index d8fbac731b19..7220585d15a3 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -351,11 +351,11 @@ template <class ForwardIterator, class Compare>
is_sorted_until(ForwardIterator first, ForwardIterator last, Compare comp);
template <class RandomAccessIterator>
- void
+ constexpr void // constexpr in C++20
sort(RandomAccessIterator first, RandomAccessIterator last);
template <class RandomAccessIterator, class Compare>
- void
+ constexpr void // constexpr in C++20
sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
template <class RandomAccessIterator>
@@ -4047,7 +4047,6 @@ template <class _Compare, class _RandomAccessIterator>
void
__sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
{
- // _Compare is known to be a reference type
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
const difference_type __limit = is_trivially_copy_constructible<value_type>::value &&
@@ -4236,47 +4235,13 @@ __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __c
}
}
-// This forwarder keeps the top call and the recursive calls using the same instantiation, forcing a reference _Compare
-template <class _RandomAccessIterator, class _Compare>
-inline _LIBCPP_INLINE_VISIBILITY
-void
-sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
-{
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- _VSTD::__sort<_Comp_ref>(__first, __last, _Comp_ref(__comp));
-}
-
-template <class _RandomAccessIterator>
-inline _LIBCPP_INLINE_VISIBILITY
-void
-sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
-{
- _VSTD::sort(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
-}
-
-template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
-void
-sort(_Tp** __first, _Tp** __last)
-{
- _VSTD::sort((uintptr_t*)__first, (uintptr_t*)__last, __less<uintptr_t>());
-}
-
-template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
-void
-sort(__wrap_iter<_Tp*> __first, __wrap_iter<_Tp*> __last)
-{
- _VSTD::sort(__first.base(), __last.base());
-}
-
-template <class _Tp, class _Compare>
+template <class _Compare, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
void
-sort(__wrap_iter<_Tp*> __first, __wrap_iter<_Tp*> __last, _Compare __comp)
+__sort(_Tp** __first, _Tp** __last, __less<_Tp*>&)
{
- typedef typename add_lvalue_reference<_Compare>::type _Comp_ref;
- _VSTD::sort<_Tp*, _Comp_ref>(__first.base(), __last.base(), __comp);
+ __less<uintptr_t> __comp;
+ _VSTD::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
}
_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
_VSTD::nth_element(__first, __nth, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
}
+// sort
+
+template <class _RandomAccessIterator, class _Compare>
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+void
+sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
+{
+ typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
+ if (__libcpp_is_constant_evaluated()) {
+ _VSTD::__partial_sort<_Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
+ } else {
+ _VSTD::__sort<_Comp_ref>(_VSTD::__unwrap_iter(__first), _VSTD::__unwrap_iter(__last), _Comp_ref(__comp));
+ }
+}
+
+template <class _RandomAccessIterator>
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+void
+sort(_RandomAccessIterator __first, _RandomAccessIterator __last)
+{
+ _VSTD::sort(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
+}
+
// includes
template <class _Compare, class _InputIterator1, class _InputIterator2>
diff --git a/libcxx/include/version b/libcxx/include/version
index 77183e54fcfd..9b37c30d2acd 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -294,7 +294,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_char8_t 201811L
# endif
// # define __cpp_lib_concepts 202002L
-// # define __cpp_lib_constexpr_algorithms 201806L
+# define __cpp_lib_constexpr_algorithms 201806L
// # define __cpp_lib_constexpr_complex 201711L
# define __cpp_lib_constexpr_dynamic_alloc 201907L
# define __cpp_lib_constexpr_functional 201907L
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
new file mode 100644
index 000000000000..41ea82cc4845
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr.pass.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// template<RandomAccessIterator Iter>
+// requires ShuffleIterator<Iter>
+// && LessThanComparable<Iter::value_type>
+// void
+// sort(Iter first, Iter last);
+
+#include <algorithm>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "MoveOnly.h"
+
+template<int N, class T, class Iter>
+TEST_CONSTEXPR_CXX20 bool test()
+{
+ int orig[N] = {};
+ unsigned x = 1;
+ for (int i=0; i < N; ++i) {
+ x = (x * 1664525) + 1013904223;
+ orig[i] = x % 1000;
+ }
+ T work[N] = {};
+ std::copy(orig, orig+N, work);
+ std::sort(Iter(work), Iter(work+N));
+ assert(std::is_sorted(work, work+N));
+ assert(std::is_permutation(work, work+N, orig));
+
+ return true;
+}
+
+template<int N, class T, class Iter>
+TEST_CONSTEXPR_CXX20 bool test_pointers()
+{
+ T data[N] = {};
+ T *orig[N] = {};
+ unsigned x = 1;
+ for (int i=0; i < N; ++i) {
+ orig[i] = &data[x % 258];
+ }
+ T *work[N] = {};
+ std::copy(orig, orig+N, work);
+ std::sort(Iter(work), Iter(work+N));
+ assert(std::is_sorted(work, work+N));
+ assert(std::is_permutation(work, work+N, orig));
+
+ return true;
+}
+
+int main(int, char**)
+{
+ test<7, int, int*>();
+ test<7, int, random_access_iterator<int*> >();
+ test<257, int, int*>();
+ test<257, int, random_access_iterator<int*> >();
+
+#if TEST_STD_VER >= 11
+ test<7, MoveOnly, MoveOnly*>();
+ test<7, MoveOnly, random_access_iterator<MoveOnly*> >();
+ test<257, MoveOnly, MoveOnly*>();
+ test<257, MoveOnly, random_access_iterator<MoveOnly*> >();
+#endif
+
+ test_pointers<17, char, char**>();
+ test_pointers<17, char, random_access_iterator<char**> >();
+ test_pointers<17, const char, const char**>();
+ test_pointers<17, const char, random_access_iterator<const char**> >();
+ test_pointers<17, int, int**>();
+ test_pointers<17, int, random_access_iterator<int**> >();
+
+#if TEST_STD_VER >= 20
+ static_assert(test<7, int, int*>());
+ static_assert(test<7, int, random_access_iterator<int*>>());
+ static_assert(test<257, int, int*>());
+ static_assert(test<257, int, random_access_iterator<int*>>());
+
+ static_assert(test<7, MoveOnly, MoveOnly*>());
+ static_assert(test<7, MoveOnly, random_access_iterator<MoveOnly*>>());
+ static_assert(test<257, MoveOnly, MoveOnly*>());
+ static_assert(test<257, MoveOnly, random_access_iterator<MoveOnly*>>());
+
+ static_assert(test_pointers<17, char, char**>());
+ static_assert(test_pointers<17, char, random_access_iterator<char**>>());
+ static_assert(test_pointers<17, const char, const char**>());
+ static_assert(test_pointers<17, const char, random_access_iterator<const char**>>());
+ static_assert(test_pointers<17, int, int**>());
+ static_assert(test_pointers<17, int, random_access_iterator<int**>>());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
new file mode 100644
index 000000000000..48f057ab8a7f
--- /dev/null
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/sort_constexpr_comp.pass.cpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// template<RandomAccessIterator Iter, StrictWeakOrder<auto, Iter::value_type> Compare>
+// requires ShuffleIterator<Iter>
+// && CopyConstructible<Compare>
+// void
+// sort(Iter first, Iter last, Compare comp);
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "MoveOnly.h"
+
+template<int N, class T, class Iter>
+TEST_CONSTEXPR_CXX20 bool test()
+{
+ int orig[N] = {};
+ unsigned x = 1;
+ for (int i=0; i < N; ++i) {
+ x = (x * 1664525) + 1013904223;
+ orig[i] = x % 1000;
+ }
+ T work[N] = {};
+ std::copy(orig, orig+N, work);
+ std::sort(Iter(work), Iter(work+N), std::greater<T>());
+ assert(std::is_sorted(work, work+N, std::greater<T>()));
+ assert(std::is_permutation(work, work+N, orig));
+
+ return true;
+}
+
+template<int N, class T, class Iter>
+TEST_CONSTEXPR_CXX20 bool test_pointers()
+{
+ T data[N] = {};
+ T *orig[N] = {};
+ unsigned x = 1;
+ for (int i=0; i < N; ++i) {
+ orig[i] = &data[x % 258];
+ }
+ T *work[N] = {};
+ std::copy(orig, orig+N, work);
+ std::sort(Iter(work), Iter(work+N), std::greater<T*>());
+ assert(std::is_sorted(work, work+N, std::greater<T*>()));
+ assert(std::is_permutation(work, work+N, orig));
+
+ return true;
+}
+
+int main(int, char**)
+{
+ test<7, int, int*>();
+ test<7, int, random_access_iterator<int*> >();
+ test<257, int, int*>();
+ test<257, int, random_access_iterator<int*> >();
+
+#if TEST_STD_VER >= 11
+ test<7, MoveOnly, MoveOnly*>();
+ test<7, MoveOnly, random_access_iterator<MoveOnly*> >();
+ test<257, MoveOnly, MoveOnly*>();
+ test<257, MoveOnly, random_access_iterator<MoveOnly*> >();
+#endif
+
+ test_pointers<17, char, char**>();
+ test_pointers<17, char, random_access_iterator<char**> >();
+ test_pointers<17, const char, const char**>();
+ test_pointers<17, const char, random_access_iterator<const char**> >();
+ test_pointers<17, int, int**>();
+ test_pointers<17, int, random_access_iterator<int**> >();
+
+#if TEST_STD_VER >= 20
+ static_assert(test<7, int, int*>());
+ static_assert(test<7, int, random_access_iterator<int*>>());
+ static_assert(test<257, int, int*>());
+ static_assert(test<257, int, random_access_iterator<int*>>());
+
+ static_assert(test<7, MoveOnly, MoveOnly*>());
+ static_assert(test<7, MoveOnly, random_access_iterator<MoveOnly*>>());
+ static_assert(test<257, MoveOnly, MoveOnly*>());
+ static_assert(test<257, MoveOnly, random_access_iterator<MoveOnly*>>());
+
+ static_assert(test_pointers<17, char, char**>());
+ static_assert(test_pointers<17, char, random_access_iterator<char**>>());
+ static_assert(test_pointers<17, const char, const char**>());
+ static_assert(test_pointers<17, const char, random_access_iterator<const char**>>());
+ static_assert(test_pointers<17, int, int**>());
+ static_assert(test_pointers<17, int, random_access_iterator<int**>>());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp
index e081ca79f6f0..eb7591540eac 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp
@@ -148,17 +148,11 @@
# error "__cpp_lib_clamp should have the value 201603L in c++20"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should be defined in c++20"
-# endif
-# if __cpp_lib_constexpr_algorithms != 201806L
-# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++20"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_constexpr_algorithms
+# error "__cpp_lib_constexpr_algorithms should be defined in c++20"
+# endif
+# if __cpp_lib_constexpr_algorithms != 201806L
+# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++20"
# endif
# if !defined(_LIBCPP_VERSION)
@@ -217,17 +211,11 @@
# error "__cpp_lib_clamp should have the value 201603L in c++2b"
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should be defined in c++2b"
-# endif
-# if __cpp_lib_constexpr_algorithms != 201806L
-# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++2b"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_constexpr_algorithms
+# error "__cpp_lib_constexpr_algorithms should be defined in c++2b"
+# endif
+# if __cpp_lib_constexpr_algorithms != 201806L
+# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++2b"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
index 2fe0dfc264f7..1bb4928bd552 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
@@ -2389,17 +2389,11 @@
# endif
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should be defined in c++20"
-# endif
-# if __cpp_lib_constexpr_algorithms != 201806L
-# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++20"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_constexpr_algorithms
+# error "__cpp_lib_constexpr_algorithms should be defined in c++20"
+# endif
+# if __cpp_lib_constexpr_algorithms != 201806L
+# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++20"
# endif
# if !defined(_LIBCPP_VERSION)
@@ -3608,17 +3602,11 @@
# endif
# endif
-# if !defined(_LIBCPP_VERSION)
-# ifndef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should be defined in c++2b"
-# endif
-# if __cpp_lib_constexpr_algorithms != 201806L
-# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++2b"
-# endif
-# else // _LIBCPP_VERSION
-# ifdef __cpp_lib_constexpr_algorithms
-# error "__cpp_lib_constexpr_algorithms should not be defined because it is unimplemented in libc++!"
-# endif
+# ifndef __cpp_lib_constexpr_algorithms
+# error "__cpp_lib_constexpr_algorithms should be defined in c++2b"
+# endif
+# if __cpp_lib_constexpr_algorithms != 201806L
+# error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++2b"
# endif
# if !defined(_LIBCPP_VERSION)
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 6abc13208538..5537d9b9f1cc 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -182,7 +182,6 @@ feature_test_macros = [ add_version_header(x) for x in [
"name": "__cpp_lib_constexpr_algorithms",
"values": { "c++20": 201806 },
"headers": ["algorithm"],
- "unimplemented": True,
}, {
"name": "__cpp_lib_constexpr_complex",
"values": { "c++20": 201711 },