1 // -*- C++ -*-
2 //===-- sort.pass.cpp -----------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: c++03, c++11, c++14
11 
12 #include "support/pstl_test_config.h"
13 
14 #include <execution>
15 #include <algorithm>
16 
17 #include "support/utils.h"
18 
19 using namespace TestUtils;
20 #define _CRT_SECURE_NO_WARNINGS
21 
22 #include <atomic>
23 
24 static bool Stable;
25 
26 //! Number of extant keys
27 static std::atomic<int32_t> KeyCount;
28 
29 //! One more than highest index in array to be sorted.
30 static uint32_t LastIndex;
31 
32 //! Keeping Equal() static and a friend of ParanoidKey class (C++, paragraphs 3.5/7.1.1)
33 class ParanoidKey;
34 static bool
35 Equal(const ParanoidKey& x, const ParanoidKey& y);
36 
37 //! A key to be sorted, with lots of checking.
38 class ParanoidKey
39 {
40     //! Value used by comparator
41     int32_t value;
42     //! Original position or special value (Empty or Dead)
43     int32_t index;
44     //! Special value used to mark object without a comparable value, e.g. after being moved from.
45     static const int32_t Empty = -1;
46     //! Special value used to mark destroyed objects.
47     static const int32_t Dead = -2;
48     // True if key object has comparable value
49     bool
isLive() const50     isLive() const
51     {
52         return (uint32_t)(index) < LastIndex;
53     }
54     // True if key object has been constructed.
55     bool
isConstructed() const56     isConstructed() const
57     {
58         return isLive() || index == Empty;
59     }
60 
61   public:
ParanoidKey()62     ParanoidKey()
63     {
64         ++KeyCount;
65         index = Empty;
66         value = Empty;
67     }
ParanoidKey(const ParanoidKey & k)68     ParanoidKey(const ParanoidKey& k) : value(k.value), index(k.index)
69     {
70         EXPECT_TRUE(k.isLive(), "source for copy-constructor is dead");
71         ++KeyCount;
72     }
~ParanoidKey()73     ~ParanoidKey()
74     {
75         EXPECT_TRUE(isConstructed(), "double destruction");
76         index = Dead;
77         --KeyCount;
78     }
79     ParanoidKey&
operator =(const ParanoidKey & k)80     operator=(const ParanoidKey& k)
81     {
82         EXPECT_TRUE(k.isLive(), "source for copy-assignment is dead");
83         EXPECT_TRUE(isConstructed(), "destination for copy-assignment is dead");
84         value = k.value;
85         index = k.index;
86         return *this;
87     }
ParanoidKey(int32_t index,int32_t value,OddTag)88     ParanoidKey(int32_t index, int32_t value, OddTag) : value(value), index(index) {}
ParanoidKey(ParanoidKey && k)89     ParanoidKey(ParanoidKey&& k) : value(k.value), index(k.index)
90     {
91         EXPECT_TRUE(k.isConstructed(), "source for move-construction is dead");
92 // std::stable_sort() fails in move semantics on paranoid test before VS2015
93 #if !defined(_MSC_VER) || _MSC_VER >= 1900
94         k.index = Empty;
95 #endif
96         ++KeyCount;
97     }
98     ParanoidKey&
operator =(ParanoidKey && k)99     operator=(ParanoidKey&& k)
100     {
101         EXPECT_TRUE(k.isConstructed(), "source for move-assignment is dead");
102         EXPECT_TRUE(isConstructed(), "destination for move-assignment is dead");
103         value = k.value;
104         index = k.index;
105 // std::stable_sort() fails in move semantics on paranoid test before VS2015
106 #if !defined(_MSC_VER) || _MSC_VER >= 1900
107         k.index = Empty;
108 #endif
109         return *this;
110     }
111     friend class KeyCompare;
112     friend bool
113     Equal(const ParanoidKey& x, const ParanoidKey& y);
114 };
115 
116 class KeyCompare
117 {
118     enum statusType
119     {
120         //! Special value used to mark defined object.
121         Live = 0xabcd,
122         //! Special value used to mark destroyed objects.
123         Dead = -1
124     } status;
125 
126   public:
KeyCompare(OddTag)127     KeyCompare(OddTag) : status(Live) {}
~KeyCompare()128     ~KeyCompare() { status = Dead; }
129     bool
operator ()(const ParanoidKey & j,const ParanoidKey & k) const130     operator()(const ParanoidKey& j, const ParanoidKey& k) const
131     {
132         EXPECT_TRUE(status == Live, "key comparison object not defined");
133         EXPECT_TRUE(j.isLive(), "first key to operator() is not live");
134         EXPECT_TRUE(k.isLive(), "second key to operator() is not live");
135         return j.value < k.value;
136     }
137 };
138 
139 // Equal is equality comparison used for checking result of sort against expected result.
140 static bool
Equal(const ParanoidKey & x,const ParanoidKey & y)141 Equal(const ParanoidKey& x, const ParanoidKey& y)
142 {
143     return (x.value == y.value && !Stable) || (x.index == y.index);
144 }
145 
146 static bool
Equal(float32_t x,float32_t y)147 Equal(float32_t x, float32_t y)
148 {
149     return x == y;
150 }
151 
152 static bool
Equal(int32_t x,int32_t y)153 Equal(int32_t x, int32_t y)
154 {
155     return x == y;
156 }
157 
158 struct test_sort_with_compare
159 {
160     template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
161               typename Compare>
162     typename std::enable_if<is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
163                             void>::type
operator ()test_sort_with_compare164     operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first,
165                OutputIterator2 expected_last, InputIterator first, InputIterator, Size n, Compare compare)
166     {
167         using namespace std;
168         copy_n(first, n, expected_first);
169         copy_n(first, n, tmp_first);
170         if (Stable)
171             std::stable_sort(expected_first + 1, expected_last - 1, compare);
172         else
173             std::sort(expected_first + 1, expected_last - 1, compare);
174         int32_t count0 = KeyCount;
175         if (Stable)
176             stable_sort(exec, tmp_first + 1, tmp_last - 1, compare);
177         else
178             sort(exec, tmp_first + 1, tmp_last - 1, compare);
179 
180         for (size_t i = 0; i < n; ++i, ++expected_first, ++tmp_first)
181         {
182             // Check that expected[i] is equal to tmp[i]
183             EXPECT_TRUE(Equal(*expected_first, *tmp_first), "bad sort");
184         }
185         int32_t count1 = KeyCount;
186         EXPECT_EQ(count0, count1, "key cleanup error");
187     }
188     template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
189               typename Compare>
190     typename std::enable_if<!is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
191                             void>::type
operator ()test_sort_with_compare192     operator()(Policy&&, OutputIterator, OutputIterator, OutputIterator2, OutputIterator2, InputIterator, InputIterator,
193                Size, Compare)
194     {
195     }
196 };
197 
198 template <typename T, typename Compare, typename Convert>
199 void
test_sort(Compare compare,Convert convert)200 test_sort(Compare compare, Convert convert)
201 {
202     for (size_t n = 0; n < 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
203     {
204         LastIndex = n + 2;
205         // The rand()%(2*n+1) encourages generation of some duplicates.
206         // Sequence is padded with an extra element at front and back, to detect overwrite bugs.
207         Sequence<T> in(n + 2, [=](size_t k) { return convert(k, rand() % (2 * n + 1)); });
208         Sequence<T> expected(in);
209         Sequence<T> tmp(in);
210         invoke_on_all_policies(test_sort_with_compare(), tmp.begin(), tmp.end(), expected.begin(), expected.end(),
211                                in.begin(), in.end(), in.size(), compare);
212     }
213 }
214 
215 template <typename T>
216 struct test_non_const
217 {
218     template <typename Policy, typename Iterator>
219     void
operator ()test_non_const220     operator()(Policy&& exec, Iterator iter)
221     {
222         sort(exec, iter, iter, non_const(std::less<T>()));
223         stable_sort(exec, iter, iter, non_const(std::less<T>()));
224     }
225 };
226 
227 int
main()228 main()
229 {
230     std::srand(42);
231     for (int32_t kind = 0; kind < 2; ++kind)
232     {
233         Stable = kind != 0;
234         test_sort<ParanoidKey>(KeyCompare(OddTag()),
235                                [](size_t k, size_t val) { return ParanoidKey(k, val, OddTag()); });
236         test_sort<float32_t>([](float32_t x, float32_t y) { return x < y; },
237                              [](size_t, size_t val) { return float32_t(val); });
238         test_sort<int32_t>(
239             [](int32_t x, int32_t y) { return x > y; }, // Reversed so accidental use of < will be detected.
240             [](size_t, size_t val) { return int32_t(val); });
241     }
242 
243     test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
244 
245     std::cout << done() << std::endl;
246     return 0;
247 }
248