99// <algorithm>
1010
1111// template <class RandomAccessIterator>
12- // constexpr void // constexpr in C++26
12+ // constexpr void // constexpr since C++26
1313// stable_sort(RandomAccessIterator first, RandomAccessIterator last);
1414
1515// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000
1616// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000
1717
1818#include < algorithm>
19- #include < array>
2019#include < cassert>
2120#include < iterator>
2221#include < random>
2524#include " count_new.h"
2625#include " test_macros.h"
2726
28- template <class RI >
29- void
30- test_sort_helper (RI f, RI l)
31- {
32- typedef typename std::iterator_traits<RI>::value_type value_type;
33- typedef typename std::iterator_traits<RI>::difference_type difference_type;
34-
35- if (f != l)
36- {
37- difference_type len = l - f;
38- value_type* save (new value_type[len]);
39- do
40- {
41- std::copy (f, l, save);
42- std::stable_sort (save, save+len);
43- assert (std::is_sorted (save, save+len));
44- } while (std::next_permutation (f, l));
45- delete [] save;
46- }
27+ template <class Iterator >
28+ TEST_CONSTEXPR_CXX26 void test_all_permutations (Iterator first, Iterator last) {
29+ using T = typename std::iterator_traits<Iterator>::value_type;
30+
31+ do {
32+ std::vector<T> save (first, last);
33+ std::stable_sort (save.begin (), save.end ());
34+ assert (std::is_sorted (save.begin (), save.end ()));
35+ } while (std::next_permutation (first, last));
4736}
4837
49- template <class RI >
50- void
51- test_sort_driver_driver (RI f, RI l, int start, RI real_last)
52- {
53- using value_type = typename std::iterator_traits<RI>::value_type;
38+ template <class Iterator >
39+ TEST_CONSTEXPR_CXX26 void test_sort_exhaustive_impl (Iterator first, Iterator last, int start, Iterator real_last) {
40+ using T = typename std::iterator_traits<Iterator>::value_type;
5441
55- for (RI i = l ; i > f + start;) {
56- *--i = static_cast <value_type >(start);
57- if (f == i) {
58- test_sort_helper (f , real_last);
42+ for (Iterator i = last ; i > first + start;) {
43+ *--i = static_cast <T >(start);
44+ if (first == i) {
45+ test_all_permutations (first , real_last);
5946 }
6047 if (start > 0 )
61- test_sort_driver_driver (f , i, start- 1 , real_last);
48+ test_sort_exhaustive_impl (first , i, start - 1 , real_last);
6249 }
6350}
6451
65- template <class RI >
66- void
67- test_sort_driver (RI f, RI l, int start)
68- {
69- test_sort_driver_driver (f, l, start, l);
70- }
71-
72- template <int sa, class V >
73- void test_sort_ () {
74- V ia[sa];
75- for (int i = 0 ; i < sa; ++i) {
76- test_sort_driver (ia, ia + sa, i);
52+ template <class T >
53+ TEST_CONSTEXPR_CXX26 void test_sort_exhaustive (int N) {
54+ std::vector<T> vec;
55+ vec.resize (N);
56+ for (int i = 0 ; i < N; ++i) {
57+ test_sort_exhaustive_impl (vec.begin (), vec.end (), i, vec.end ());
7758 }
7859}
7960
80- template <int sa>
81- void test_sort_ () {
82- test_sort_<sa, int >();
83- test_sort_<sa, float >();
84- }
85-
86- template <class V >
87- void test_larger_sorts (int N, int M) {
88- assert (N != 0 );
89- assert (M != 0 );
90- // create array length N filled with M different numbers
91- V* array = new V[N];
92- int x = 0 ;
61+ template <class T >
62+ TEST_CONSTEXPR_CXX26 std::vector<T> generate_sawtooth (int N, int M) {
63+ // Populate a sequence of length N with M different numbers
64+ std::vector<T> v;
65+ T x = 0 ;
9366 for (int i = 0 ; i < N; ++i) {
94- array[i] = static_cast <V> (x);
67+ v. push_back (x);
9568 if (++x == M)
9669 x = 0 ;
9770 }
71+ return v;
72+ }
73+
74+ template <class T >
75+ TEST_CONSTEXPR_CXX26 void test_larger_sorts (int N, int M) {
76+ assert (N != 0 );
77+ assert (M != 0 );
78+
9879 // test saw tooth pattern
99- std::stable_sort (array, array + N);
100- assert (std::is_sorted (array, array + N));
80+ {
81+ auto v = generate_sawtooth<T>(N, M);
82+ std::stable_sort (v.begin (), v.end ());
83+ assert (std::is_sorted (v.begin (), v.end ()));
84+ }
85+
10186 // test random pattern
102- std::shuffle (array, array + N, randomness);
103- std::stable_sort (array, array + N);
104- assert (std::is_sorted (array, array + N));
87+ {
88+ if (!TEST_IS_CONSTANT_EVALUATED) {
89+ auto v = generate_sawtooth<T>(N, M);
90+ std::mt19937 randomness;
91+ std::shuffle (v.begin (), v.end (), randomness);
92+ std::stable_sort (v.begin (), v.end ());
93+ assert (std::is_sorted (v.begin (), v.end ()));
94+ }
95+ }
96+
10597 // test sorted pattern
106- std::stable_sort (array, array + N);
107- assert (std::is_sorted (array, array + N));
98+ {
99+ auto v = generate_sawtooth<T>(N, M);
100+ std::sort (v.begin (), v.end ());
101+
102+ std::stable_sort (v.begin (), v.end ());
103+ assert (std::is_sorted (v.begin (), v.end ()));
104+ }
105+
108106 // test reverse sorted pattern
109- std::reverse (array, array + N);
110- std::stable_sort (array, array + N);
111- assert (std::is_sorted (array, array + N));
107+ {
108+ auto v = generate_sawtooth<T>(N, M);
109+ std::sort (v.begin (), v.end ());
110+ std::reverse (v.begin (), v.end ());
111+
112+ std::stable_sort (v.begin (), v.end ());
113+ assert (std::is_sorted (v.begin (), v.end ()));
114+ }
115+
112116 // test swap ranges 2 pattern
113- std::swap_ranges (array, array + N / 2 , array + N / 2 );
114- std::stable_sort (array, array + N);
115- assert (std::is_sorted (array, array + N));
116- // test reverse swap ranges 2 pattern
117- std::reverse (array, array + N);
118- std::swap_ranges (array, array + N / 2 , array + N / 2 );
119- std::stable_sort (array, array + N);
120- assert (std::is_sorted (array, array + N));
121- delete[] array;
122- }
117+ {
118+ auto v = generate_sawtooth<T>(N, M);
119+ std::sort (v.begin (), v.end ());
120+ std::swap_ranges (v.begin (), v.begin () + (N / 2 ), v.begin () + (N / 2 ));
121+
122+ std::stable_sort (v.begin (), v.end ());
123+ assert (std::is_sorted (v.begin (), v.end ()));
124+ }
123125
124- void test_larger_sorts (int N, int M) {
125- test_larger_sorts<int >(N, M);
126- test_larger_sorts<float >(N, M);
126+ // test reverse swap ranges 2 pattern
127+ {
128+ auto v = generate_sawtooth<T>(N, M);
129+ std::sort (v.begin (), v.end ());
130+ std::reverse (v.begin (), v.end ());
131+ std::swap_ranges (v.begin (), v.begin () + (N / 2 ), v.begin () + (N / 2 ));
132+
133+ std::stable_sort (v.begin (), v.end ());
134+ assert (std::is_sorted (v.begin (), v.end ()));
135+ }
127136}
128137
129- template <int N >
130- TEST_CONSTEXPR_CXX26 void test_larger_sorts () {
131- test_larger_sorts<N, 1 >( );
132- test_larger_sorts<N, 2 >( );
133- test_larger_sorts<N, 3 >( );
134- test_larger_sorts<N, N / 2 - 1 >( );
135- test_larger_sorts<N, N / 2 >( );
136- test_larger_sorts<N, N / 2 + 1 >( );
137- test_larger_sorts<N, N - 2 >( );
138- test_larger_sorts<N, N - 1 >( );
139- test_larger_sorts<N, N>( );
138+ template <class T >
139+ TEST_CONSTEXPR_CXX26 void test_larger_sorts (int N ) {
140+ test_larger_sorts<T>( N, 1 );
141+ test_larger_sorts<T>( N, 2 );
142+ test_larger_sorts<T>( N, 3 );
143+ test_larger_sorts<T>( N, N / 2 - 1 );
144+ test_larger_sorts<T>( N, N / 2 );
145+ test_larger_sorts<T>( N, N / 2 + 1 );
146+ test_larger_sorts<T>( N, N - 2 );
147+ test_larger_sorts<T>( N, N - 1 );
148+ test_larger_sorts<T>( N, N);
140149}
141150
151+ template <class T >
142152TEST_CONSTEXPR_CXX26 bool test () {
143153 // test null range
144- int d = 0 ;
145- std::stable_sort (&d, &d);
154+ {
155+ T value = 0 ;
156+ std::stable_sort (&value, &value);
157+ }
146158
147159 // exhaustively test all possibilities up to length 8
148160 if (!TEST_IS_CONSTANT_EVALUATED) {
149- test_sort_< 1 >( );
150- test_sort_< 2 >( );
151- test_sort_< 3 >( );
152- test_sort_< 4 >( );
153- test_sort_< 5 >( );
154- test_sort_< 6 >( );
155- test_sort_< 7 >( );
156- test_sort_< 8 >( );
161+ test_sort_exhaustive<T>( 1 );
162+ test_sort_exhaustive<T>( 2 );
163+ test_sort_exhaustive<T>( 3 );
164+ test_sort_exhaustive<T>( 4 );
165+ test_sort_exhaustive<T>( 5 );
166+ test_sort_exhaustive<T>( 6 );
167+ test_sort_exhaustive<T>( 7 );
168+ test_sort_exhaustive<T>( 8 );
157169 }
158170
159- test_larger_sorts (256 );
160- test_larger_sorts (257 );
171+ test_larger_sorts<T> (256 );
172+ test_larger_sorts<T> (257 );
161173 if (!TEST_IS_CONSTANT_EVALUATED) { // avoid blowing past constexpr evaluation limit
162- test_larger_sorts (499 );
163- test_larger_sorts (500 );
164- test_larger_sorts (997 );
165- test_larger_sorts (1000 );
166- test_larger_sorts (1009 );
167- test_larger_sorts (1024 );
168- test_larger_sorts (1031 );
169- test_larger_sorts (2053 );
174+ test_larger_sorts<T> (499 );
175+ test_larger_sorts<T> (500 );
176+ test_larger_sorts<T> (997 );
177+ test_larger_sorts<T> (1000 );
178+ test_larger_sorts<T> (1009 );
179+ test_larger_sorts<T> (1024 );
180+ test_larger_sorts<T> (1031 );
181+ test_larger_sorts<T> (2053 );
170182 }
171183
172184 // check that the algorithm works without memory
173185#ifndef TEST_HAS_NO_EXCEPTIONS
174186 if (!TEST_IS_CONSTANT_EVALUATED) {
175- std::vector<int > vec (150 , 3 );
187+ std::vector<T > vec (150 , T ( 3 ) );
176188 getGlobalMemCounter ()->throw_after = 0 ;
177189 std::stable_sort (vec.begin (), vec.end ());
178190 }
@@ -182,9 +194,11 @@ TEST_CONSTEXPR_CXX26 bool test() {
182194}
183195
184196int main (int , char **) {
185- test ();
197+ test<int >();
198+ test<float >();
186199#if TEST_STD_VER >= 26
187- static_assert (test ());
200+ static_assert (test<int >());
201+ static_assert (test<float >());
188202#endif
189203 return 0 ;
190204}
0 commit comments