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 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 11 12 // <algorithm> 13 14 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity, 15 // indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to> 16 // requires indirectly_copyable<I, O> && 17 // (forward_iterator<I> || 18 // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) || 19 // indirectly_copyable_storable<I, O>) 20 // constexpr unique_copy_result<I, O> 21 // unique_copy(I first, S last, O result, C comp = {}, Proj proj = {}); // Since C++20 22 // 23 // template<input_range R, weakly_incrementable O, class Proj = identity, 24 // indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to> 25 // requires indirectly_copyable<iterator_t<R>, O> && 26 // (forward_iterator<iterator_t<R>> || 27 // (input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) || 28 // indirectly_copyable_storable<iterator_t<R>, O>) 29 // constexpr unique_copy_result<borrowed_iterator_t<R>, O> 30 // unique_copy(R&& r, O result, C comp = {}, Proj proj = {}); // Since C++20 31 32 #include <algorithm> 33 #include <array> 34 #include <concepts> 35 #include <functional> 36 #include <ranges> 37 38 #include "almost_satisfies_types.h" 39 #include "counting_predicates.h" 40 #include "counting_projection.h" 41 #include "MoveOnly.h" 42 #include "test_iterators.h" 43 44 template < 45 class InIter = int*, 46 class Sent = int*, 47 class OutIter = int*, 48 class Comp = std::ranges::equal_to, 49 class Proj = std::identity> 50 concept HasUniqueCopyIter = 51 requires(InIter&& in, Sent&& sent, OutIter&& out, Comp&& comp, Proj&& proj) { 52 std::ranges::unique_copy( 53 std::forward<InIter>(in), 54 std::forward<Sent>(sent), 55 std::forward<OutIter>(out), 56 std::forward<Comp>(comp), 57 std::forward<Proj>(proj)); 58 }; 59 60 static_assert(HasUniqueCopyIter<int*, int*, int*>); 61 62 // !input_iterator<I> 63 static_assert(!HasUniqueCopyIter<InputIteratorNotDerivedFrom, sentinel_wrapper<InputIteratorNotDerivedFrom>>); 64 65 // !sentinel_for<S, I> 66 static_assert(!HasUniqueCopyIter<int*, SentinelForNotSemiregular>); 67 68 // !weakly_incrementable<O> 69 static_assert(!HasUniqueCopyIter<int*, int*, WeaklyIncrementableNotMovable>); 70 71 // !indirect_equivalence_relation<Comp, projected<I, Proj>> 72 static_assert(!HasUniqueCopyIter<int*, int*, int*, ComparatorNotCopyable<int>>); 73 74 // !indirectly_copyable<I, O> 75 static_assert(!HasUniqueCopyIter<const int*, const int*, const int*>); 76 77 // forward_iterator<I> 78 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) 79 // !indirectly_copyable_storable<I, O> 80 struct AssignableFromMoveOnly { 81 int data; 82 constexpr AssignableFromMoveOnly& operator=(MoveOnly const& m) { 83 data = m.get(); 84 return *this; 85 } 86 }; 87 static_assert(HasUniqueCopyIter<MoveOnly*, MoveOnly*, AssignableFromMoveOnly*>); 88 // because: 89 static_assert(std::forward_iterator<MoveOnly*>); 90 static_assert(!std::same_as<std::iter_value_t<MoveOnly*>, std::iter_value_t<AssignableFromMoveOnly*>>); 91 static_assert(!std::indirectly_copyable_storable<MoveOnly*, AssignableFromMoveOnly*>); 92 93 // !forward_iterator<I> 94 // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) 95 // !indirectly_copyable_storable<I, O> 96 struct CopyAssignableNotCopyConstructible { 97 int data; 98 constexpr CopyAssignableNotCopyConstructible(int i = 0) : data(i) {} 99 CopyAssignableNotCopyConstructible(const CopyAssignableNotCopyConstructible&) = delete; 100 CopyAssignableNotCopyConstructible& operator=(const CopyAssignableNotCopyConstructible&) = default; 101 friend constexpr bool 102 operator==(CopyAssignableNotCopyConstructible const&, CopyAssignableNotCopyConstructible const&) = default; 103 }; 104 105 using InputAndOutputIterator = cpp17_input_iterator<CopyAssignableNotCopyConstructible*>; 106 static_assert(std::input_iterator<InputAndOutputIterator>); 107 static_assert(std::output_iterator<InputAndOutputIterator, CopyAssignableNotCopyConstructible>); 108 109 static_assert( 110 HasUniqueCopyIter< 111 cpp20_input_iterator<CopyAssignableNotCopyConstructible*>, 112 sentinel_wrapper<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>, 113 InputAndOutputIterator>); 114 // because: 115 static_assert(!std::forward_iterator< cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>); 116 static_assert( 117 std::input_iterator<InputAndOutputIterator> && 118 std::same_as<std::iter_value_t<cpp20_input_iterator<CopyAssignableNotCopyConstructible*>>, 119 std::iter_value_t<InputAndOutputIterator>>); 120 static_assert( 121 !std::indirectly_copyable_storable< 122 cpp20_input_iterator<CopyAssignableNotCopyConstructible*>, 123 InputAndOutputIterator>); 124 125 // !forward_iterator<I> 126 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) 127 // indirectly_copyable_storable<I, O> 128 static_assert( 129 HasUniqueCopyIter< 130 cpp20_input_iterator<int*>, 131 sentinel_wrapper<cpp20_input_iterator<int*>>, 132 cpp20_output_iterator<int*>>); 133 // because: 134 static_assert(!std::forward_iterator<cpp20_input_iterator<int*>>); 135 static_assert(!std::input_iterator<cpp20_output_iterator<int*>>); 136 static_assert(std::indirectly_copyable_storable<cpp20_input_iterator<int*>, cpp20_output_iterator<int*>>); 137 138 // !forward_iterator<I> 139 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) 140 // !indirectly_copyable_storable<I, O> 141 static_assert( 142 !HasUniqueCopyIter< 143 cpp20_input_iterator<MoveOnly*>, 144 sentinel_wrapper<cpp20_input_iterator<MoveOnly*>>, 145 cpp20_output_iterator<AssignableFromMoveOnly*>>); 146 // because: 147 static_assert(!std::forward_iterator<cpp20_input_iterator<MoveOnly*>>); 148 static_assert(!std::input_iterator<cpp20_output_iterator<MoveOnly*>>); 149 static_assert( 150 !std:: 151 indirectly_copyable_storable<cpp20_input_iterator<MoveOnly*>, cpp20_output_iterator<AssignableFromMoveOnly*>>); 152 153 template < class Range, class OutIter = int*, class Comp = std::ranges::equal_to, class Proj = std::identity> 154 concept HasUniqueCopyRange = 155 requires(Range&& range, OutIter&& out, Comp&& comp, Proj&& proj) { 156 std::ranges::unique_copy( 157 std::forward<Range>(range), std::forward<OutIter>(out), std::forward<Comp>(comp), std::forward<Proj>(proj)); 158 }; 159 160 template <class T> 161 using R = UncheckedRange<T>; 162 163 static_assert(HasUniqueCopyRange<R<int*>, int*>); 164 165 // !input_range<R> 166 static_assert(!HasUniqueCopyRange<R<InputIteratorNotDerivedFrom>>); 167 168 // !weakly_incrementable<O> 169 static_assert(!HasUniqueCopyIter<R<int*>, WeaklyIncrementableNotMovable>); 170 171 // !indirect_equivalence_relation<Comp, projected<I, Proj>> 172 static_assert(!HasUniqueCopyIter<R<int*>, int*, ComparatorNotCopyable<int>>); 173 174 // !indirectly_copyable<I, O> 175 static_assert(!HasUniqueCopyIter<R<const int*>, const int*>); 176 177 // !forward_iterator<iterator_t<R>> 178 // !(input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) 179 // !indirectly_copyable_storable<iterator_t<R>, O> 180 static_assert(!HasUniqueCopyIter< R<cpp20_input_iterator<MoveOnly*>>, cpp20_output_iterator<AssignableFromMoveOnly*>>); 181 182 template <class InIter, class OutIter, template <class> class SentWrapper, std::size_t N1, std::size_t N2> 183 constexpr void testUniqueCopyImpl(std::array<int, N1> in, std::array<int, N2> expected) { 184 using Sent = SentWrapper<InIter>; 185 186 // iterator overload 187 { 188 std::array<int, N2> out; 189 std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result = 190 std::ranges::unique_copy(InIter{in.data()}, Sent{InIter{in.data() + in.size()}}, OutIter{out.begin()}); 191 assert(std::ranges::equal(out, expected)); 192 assert(base(result.in) == in.data() + in.size()); 193 assert(base(result.out) == out.data() + out.size()); 194 } 195 196 // range overload 197 { 198 std::array<int, N2> out; 199 std::ranges::subrange r{InIter{in.data()}, Sent{InIter{in.data() + in.size()}}}; 200 std::same_as<std::ranges::unique_copy_result<InIter, OutIter>> decltype(auto) result = 201 std::ranges::unique_copy(r, OutIter{out.begin()}); 202 assert(std::ranges::equal(out, expected)); 203 assert(base(result.in) == in.data() + in.size()); 204 assert(base(result.out) == out.data() + out.size()); 205 } 206 } 207 208 template <class InIter, class OutIter, template <class> class SentWrapper> 209 constexpr void testImpl() { 210 // no consecutive elements 211 { 212 std::array in{1, 2, 3, 2, 1}; 213 std::array expected{1, 2, 3, 2, 1}; 214 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected); 215 } 216 217 // one group of consecutive elements 218 { 219 std::array in{2, 3, 3, 3, 4, 3}; 220 std::array expected{2, 3, 4, 3}; 221 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected); 222 } 223 224 // multiple groups of consecutive elements 225 { 226 std::array in{2, 3, 3, 3, 4, 3, 3, 5, 5, 5}; 227 std::array expected{2, 3, 4, 3, 5}; 228 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected); 229 } 230 231 // all the same 232 { 233 std::array in{1, 1, 1, 1, 1, 1}; 234 std::array expected{1}; 235 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected); 236 } 237 238 // empty range 239 { 240 std::array<int, 0> in{}; 241 std::array<int, 0> expected{}; 242 testUniqueCopyImpl<InIter, OutIter, SentWrapper>(in, expected); 243 } 244 } 245 246 template <class OutIter, template <class> class SentWrapper> 247 constexpr void withAllPermutationsOfInIter() { 248 testImpl<cpp20_input_iterator<int*>, OutIter, sentinel_wrapper>(); 249 testImpl<forward_iterator<int*>, OutIter, SentWrapper>(); 250 testImpl<bidirectional_iterator<int*>, OutIter, SentWrapper>(); 251 testImpl<random_access_iterator<int*>, OutIter, SentWrapper>(); 252 testImpl<contiguous_iterator<int*>, OutIter, SentWrapper>(); 253 testImpl<int*, OutIter, SentWrapper>(); 254 } 255 256 template <template <class> class SentWrapper> 257 constexpr void withAllPermutationsOfInIterAndOutIter() { 258 withAllPermutationsOfInIter<cpp20_output_iterator<int*>, SentWrapper>(); 259 withAllPermutationsOfInIter<forward_iterator<int*>, SentWrapper>(); 260 withAllPermutationsOfInIter<bidirectional_iterator<int*>, SentWrapper>(); 261 withAllPermutationsOfInIter<random_access_iterator<int*>, SentWrapper>(); 262 withAllPermutationsOfInIter<contiguous_iterator<int*>, SentWrapper>(); 263 withAllPermutationsOfInIter<int*, SentWrapper>(); 264 } 265 266 constexpr bool test() { 267 withAllPermutationsOfInIterAndOutIter<std::type_identity_t>(); 268 withAllPermutationsOfInIterAndOutIter<sentinel_wrapper>(); 269 270 // Test the overload that re-reads from the input iterator 271 // forward_iterator<I> 272 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) 273 // !indirectly_copyable_storable<I, O> 274 { 275 MoveOnly in[5] = {1, 3, 3, 3, 1}; 276 // iterator overload 277 { 278 AssignableFromMoveOnly out[3] = {}; 279 auto result = std::ranges::unique_copy(in, in + 5, out); 280 assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data)); 281 assert(result.in == in + 5); 282 assert(result.out == out + 3); 283 } 284 // range overload 285 { 286 AssignableFromMoveOnly out[3] = {}; 287 auto result = std::ranges::unique_copy(std::ranges::subrange{in, in + 5}, out); 288 assert(std::ranges::equal(out, std::array{1, 3, 1}, {}, &AssignableFromMoveOnly::data)); 289 assert(result.in == in + 5); 290 assert(result.out == out + 3); 291 } 292 } 293 294 // Test the overload that re-reads from the output iterator 295 // !forward_iterator<I> 296 // (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) 297 // !indirectly_copyable_storable<I, O> 298 { 299 using InIter = cpp20_input_iterator<CopyAssignableNotCopyConstructible*>; 300 using Sent = sentinel_wrapper<InIter>; 301 CopyAssignableNotCopyConstructible in[6] = {1, 1, 2, 2, 3, 3}; 302 // iterator overload 303 { 304 CopyAssignableNotCopyConstructible out[3]; 305 auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 6}}, InputAndOutputIterator{out}); 306 assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data)); 307 assert(base(result.in) == in + 6); 308 assert(base(result.out) == out + 3); 309 } 310 // range overload 311 { 312 CopyAssignableNotCopyConstructible out[3]; 313 auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 6}}); 314 auto result = std::ranges::unique_copy(r, InputAndOutputIterator{out}); 315 assert(std::ranges::equal(out, std::array{1, 2, 3}, {}, &CopyAssignableNotCopyConstructible::data)); 316 assert(base(result.in) == in + 6); 317 assert(base(result.out) == out + 3); 318 } 319 } 320 321 // Test the overload that reads from the temporary copy of the value 322 // !forward_iterator<I> 323 // !(input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) 324 // indirectly_copyable_storable<I, O> 325 { 326 using InIter = cpp20_input_iterator<int*>; 327 using Sent = sentinel_wrapper<InIter>; 328 int in[4] = {1, 1, 1, 2}; 329 // iterator overload 330 { 331 int out[2]; 332 auto result = std::ranges::unique_copy(InIter{in}, Sent{InIter{in + 4}}, cpp20_output_iterator<int*>{out}); 333 assert(std::ranges::equal(out, std::array{1, 2})); 334 assert(base(result.in) == in + 4); 335 assert(base(result.out) == out + 2); 336 } 337 // range overload 338 { 339 int out[2]; 340 auto r = std::ranges::subrange(InIter{in}, Sent{InIter{in + 4}}); 341 auto result = std::ranges::unique_copy(r, cpp20_output_iterator<int*>{out}); 342 assert(std::ranges::equal(out, std::array{1, 2})); 343 assert(base(result.in) == in + 4); 344 assert(base(result.out) == out + 2); 345 } 346 } 347 348 struct Data { 349 int data; 350 }; 351 352 // Test custom comparator 353 { 354 std::array in{Data{4}, Data{8}, Data{8}, Data{8}}; 355 std::array expected{Data{4}, Data{8}}; 356 const auto comp = [](const Data& x, const Data& y) { return x.data == y.data; }; 357 358 // iterator overload 359 { 360 std::array<Data, 2> out; 361 auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), comp); 362 assert(std::ranges::equal(out, expected, comp)); 363 assert(base(result.in) == in.begin() + 4); 364 assert(base(result.out) == out.begin() + 2); 365 } 366 367 // range overload 368 { 369 std::array<Data, 2> out; 370 auto result = std::ranges::unique_copy(in, out.begin(), comp); 371 assert(std::ranges::equal(out, expected, comp)); 372 assert(base(result.in) == in.begin() + 4); 373 assert(base(result.out) == out.begin() + 2); 374 } 375 } 376 377 // Test custom projection 378 { 379 std::array in{Data{4}, Data{8}, Data{8}, Data{8}}; 380 std::array expected{Data{4}, Data{8}}; 381 382 const auto proj = &Data::data; 383 384 // iterator overload 385 { 386 std::array<Data, 2> out; 387 auto result = std::ranges::unique_copy(in.begin(), in.end(), out.begin(), {}, proj); 388 assert(std::ranges::equal(out, expected, {}, proj, proj)); 389 assert(base(result.in) == in.begin() + 4); 390 assert(base(result.out) == out.begin() + 2); 391 } 392 393 // range overload 394 { 395 std::array<Data, 2> out; 396 auto result = std::ranges::unique_copy(in, out.begin(), {}, proj); 397 assert(std::ranges::equal(out, expected, {}, proj, proj)); 398 assert(base(result.in) == in.begin() + 4); 399 assert(base(result.out) == out.begin() + 2); 400 } 401 } 402 403 // Exactly last - first - 1 applications of the corresponding predicate and no 404 // more than twice as many applications of any projection. 405 { 406 std::array in{1, 2, 3, 3, 3, 4, 3, 3, 5, 5, 6, 6, 1}; 407 std::array expected{1, 2, 3, 4, 3, 5, 6, 1}; 408 // iterator overload 409 { 410 std::array<int, 8> out; 411 int numberOfComp = 0; 412 int numberOfProj = 0; 413 auto result = std::ranges::unique_copy( 414 in.begin(), 415 in.end(), 416 out.begin(), 417 counting_predicate{std::ranges::equal_to{}, numberOfComp}, 418 counting_projection{numberOfProj}); 419 assert(std::ranges::equal(out, expected)); 420 assert(base(result.in) == in.end()); 421 assert(base(result.out) == out.end()); 422 assert(numberOfComp == in.size() - 1); 423 assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1))); 424 } 425 // range overload 426 { 427 std::array<int, 8> out; 428 int numberOfComp = 0; 429 int numberOfProj = 0; 430 auto result = std::ranges::unique_copy( 431 in, 432 out.begin(), 433 counting_predicate{std::ranges::equal_to{}, numberOfComp}, 434 counting_projection{numberOfProj}); 435 assert(std::ranges::equal(out, expected)); 436 assert(base(result.in) == in.end()); 437 assert(base(result.out) == out.end()); 438 assert(numberOfComp == in.size() - 1); 439 assert(numberOfProj <= static_cast<int>(2 * (in.size() - 1))); 440 } 441 } 442 return true; 443 } 444 445 int main(int, char**) { 446 test(); 447 static_assert(test()); 448 449 return 0; 450 } 451