| 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 |
| 50 | isLive() const |
| 51 | { |
| 52 | return (uint32_t)(index) < LastIndex; |
| 53 | } |
| 54 | // True if key object has been constructed. |
| 55 | bool |
| 56 | isConstructed() const |
| 57 | { |
| 58 | return isLive() || index == Empty; |
| 59 | } |
| 60 | |
| 61 | public: |
| 62 | ParanoidKey() |
| 63 | { |
| 64 | ++KeyCount; |
| 65 | index = Empty; |
| 66 | value = Empty; |
| 67 | } |
| 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 | } |
| 73 | ~ParanoidKey() |
| 74 | { |
| 75 | EXPECT_TRUE(isConstructed(), "double destruction" ); |
| 76 | index = Dead; |
| 77 | --KeyCount; |
| 78 | } |
| 79 | ParanoidKey& |
| 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 | } |
| 88 | ParanoidKey(int32_t index, int32_t value, OddTag) : value(value), index(index) {} |
| 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& |
| 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: |
| 127 | KeyCompare(OddTag) : status(Live) {} |
| 128 | ~KeyCompare() { status = Dead; } |
| 129 | bool |
| 130 | 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 |
| 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 |
| 147 | Equal(float32_t x, float32_t y) |
| 148 | { |
| 149 | return x == y; |
| 150 | } |
| 151 | |
| 152 | static bool |
| 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 |
| 164 | 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 |
| 192 | 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 |
| 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 |
| 220 | 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 |
| 228 | main() |
| 229 | { |
| 230 | std::srand(seed: 42); |
| 231 | for (int32_t kind = 0; kind < 2; ++kind) |
| 232 | { |
| 233 | Stable = kind != 0; |
| 234 | test_sort<ParanoidKey>(compare: KeyCompare(OddTag()), |
| 235 | convert: [](size_t k, size_t val) { return ParanoidKey(k, val, OddTag()); }); |
| 236 | test_sort<float32_t>(compare: [](float32_t x, float32_t y) { return x < y; }, |
| 237 | convert: [](size_t, size_t val) { return float32_t(val); }); |
| 238 | test_sort<int32_t>( |
| 239 | compare: [](int32_t x, int32_t y) { return x > y; }, // Reversed so accidental use of < will be detected. |
| 240 | convert: [](size_t, size_t val) { return int32_t(val); }); |
| 241 | } |
| 242 | |
| 243 | test_algo_basic_single<int32_t>(f: run_for_rnd<test_non_const<int32_t>>()); |
| 244 | |
| 245 | std::cout << done() << std::endl; |
| 246 | return 0; |
| 247 | } |
| 248 | |