xref: /llvm-project/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp (revision c6b192ac2e1441b3484781488adef2986408ebdf)
104760bfaSnicole mazzuca //===----------------------------------------------------------------------===//
204760bfaSnicole mazzuca //
304760bfaSnicole mazzuca // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
404760bfaSnicole mazzuca // See https://llvm.org/LICENSE.txt for license information.
504760bfaSnicole mazzuca // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
604760bfaSnicole mazzuca //
704760bfaSnicole mazzuca //===----------------------------------------------------------------------===//
804760bfaSnicole mazzuca 
904760bfaSnicole mazzuca // <algorithm>
1004760bfaSnicole mazzuca 
1104760bfaSnicole mazzuca // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
1204760bfaSnicole mazzuca 
1304760bfaSnicole mazzuca // ADDITIONAL_COMPILE_FLAGS(gcc-style-warnings): -Wno-sign-compare
1404760bfaSnicole mazzuca // MSVC warning C4242: 'argument': conversion from 'const _Ty' to 'ElementT', possible loss of data
1504760bfaSnicole mazzuca // MSVC warning C4244: 'argument': conversion from 'const _Ty' to 'ElementT', possible loss of data
1604760bfaSnicole mazzuca // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4242 /wd4244
1704760bfaSnicole mazzuca 
1804760bfaSnicole mazzuca // template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity>
1904760bfaSnicole mazzuca //   requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
2004760bfaSnicole mazzuca //   constexpr subrange<I> ranges::find_last(I first, S last, const T& value, Proj proj = {});
2104760bfaSnicole mazzuca // template<forward_range R, class T, class Proj = identity>
2204760bfaSnicole mazzuca //   requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
2304760bfaSnicole mazzuca //   constexpr borrowed_subrange_t<R> ranges::find_last(R&& r, const T& value, Proj proj = {});
2404760bfaSnicole mazzuca 
2504760bfaSnicole mazzuca #include <algorithm>
2604760bfaSnicole mazzuca #include <array>
2704760bfaSnicole mazzuca #include <cassert>
28*c6b192acSnicole mazzuca #include <memory>
2904760bfaSnicole mazzuca #include <ranges>
3004760bfaSnicole mazzuca #include <vector>
3104760bfaSnicole mazzuca 
3204760bfaSnicole mazzuca #include "almost_satisfies_types.h"
3304760bfaSnicole mazzuca #include "test_iterators.h"
3404760bfaSnicole mazzuca 
3504760bfaSnicole mazzuca struct NotEqualityComparable {};
3604760bfaSnicole mazzuca 
3704760bfaSnicole mazzuca template <class It, class Sent = It>
3804760bfaSnicole mazzuca concept HasFindLastIt = requires(It it, Sent sent) { std::ranges::find_last(it, sent, *it); };
3904760bfaSnicole mazzuca static_assert(HasFindLastIt<int*>);
4004760bfaSnicole mazzuca static_assert(HasFindLastIt<forward_iterator<int*>>);
4104760bfaSnicole mazzuca static_assert(!HasFindLastIt<cpp20_input_iterator<int*>>);
4204760bfaSnicole mazzuca static_assert(!HasFindLastIt<NotEqualityComparable*>);
4304760bfaSnicole mazzuca static_assert(!HasFindLastIt<ForwardIteratorNotDerivedFrom>);
4404760bfaSnicole mazzuca static_assert(!HasFindLastIt<ForwardIteratorNotIncrementable>);
4504760bfaSnicole mazzuca static_assert(!HasFindLastIt<forward_iterator<int*>, SentinelForNotSemiregular>);
4604760bfaSnicole mazzuca static_assert(!HasFindLastIt<forward_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
4704760bfaSnicole mazzuca 
4804760bfaSnicole mazzuca static_assert(!HasFindLastIt<int*, int>);
4904760bfaSnicole mazzuca static_assert(!HasFindLastIt<int, int*>);
5004760bfaSnicole mazzuca 
5104760bfaSnicole mazzuca template <class Range, class ValT>
5204760bfaSnicole mazzuca concept HasFindLastR = requires(Range r) { std::ranges::find_last(r, ValT{}); };
5304760bfaSnicole mazzuca static_assert(HasFindLastR<std::array<int, 1>, int>);
5404760bfaSnicole mazzuca static_assert(!HasFindLastR<int, int>);
5504760bfaSnicole mazzuca static_assert(!HasFindLastR<std::array<NotEqualityComparable, 1>, NotEqualityComparable>);
5604760bfaSnicole mazzuca static_assert(!HasFindLastR<ForwardRangeNotDerivedFrom, int>);
5704760bfaSnicole mazzuca static_assert(!HasFindLastR<ForwardRangeNotIncrementable, int>);
5804760bfaSnicole mazzuca static_assert(!HasFindLastR<ForwardRangeNotSentinelSemiregular, int>);
5904760bfaSnicole mazzuca static_assert(!HasFindLastR<ForwardRangeNotSentinelEqualityComparableWith, int>);
6004760bfaSnicole mazzuca 
6104760bfaSnicole mazzuca template <class It, class Sent = It>
6204760bfaSnicole mazzuca constexpr void test_iterators() {
6304760bfaSnicole mazzuca   using ValueT    = std::iter_value_t<It>;
6404760bfaSnicole mazzuca   auto make_range = [](auto& a) {
65*c6b192acSnicole mazzuca     return std::ranges::subrange(
66*c6b192acSnicole mazzuca         It(std::to_address(std::ranges::begin(a))), Sent(It(std::to_address(std::ranges::end(a)))));
6704760bfaSnicole mazzuca   };
6804760bfaSnicole mazzuca   { // simple test
6904760bfaSnicole mazzuca     {
7004760bfaSnicole mazzuca       ValueT a[] = {1, 2, 3, 4};
7104760bfaSnicole mazzuca 
7204760bfaSnicole mazzuca       std::same_as<std::ranges::subrange<It>> auto ret = std::ranges::find_last(It(a), Sent(It(a + 4)), 2);
7304760bfaSnicole mazzuca       assert(base(ret.begin()) == a + 1);
7404760bfaSnicole mazzuca       assert(*ret.begin() == 2);
7504760bfaSnicole mazzuca     }
7604760bfaSnicole mazzuca     {
7704760bfaSnicole mazzuca       ValueT a[] = {1, 2, 3, 4};
7804760bfaSnicole mazzuca 
7904760bfaSnicole mazzuca       std::same_as<std::ranges::subrange<It>> auto ret = std::ranges::find_last(make_range(a), 2);
8004760bfaSnicole mazzuca       assert(base(ret.begin()) == a + 1);
8104760bfaSnicole mazzuca       assert(*ret.begin() == 2);
8204760bfaSnicole mazzuca     }
8304760bfaSnicole mazzuca   }
8404760bfaSnicole mazzuca 
8504760bfaSnicole mazzuca   { // check that an empty range works
8604760bfaSnicole mazzuca     {
8704760bfaSnicole mazzuca       std::array<ValueT, 0> a = {};
8804760bfaSnicole mazzuca 
8904760bfaSnicole mazzuca       auto ret = std::ranges::find_last(It(a.data()), Sent(It(a.data())), 1).begin();
9004760bfaSnicole mazzuca       assert(ret == It(a.data()));
9104760bfaSnicole mazzuca     }
9204760bfaSnicole mazzuca     {
9304760bfaSnicole mazzuca       std::array<ValueT, 0> a = {};
9404760bfaSnicole mazzuca 
9504760bfaSnicole mazzuca       auto ret = std::ranges::find_last(make_range(a), 1).begin();
96*c6b192acSnicole mazzuca       assert(ret == It(a.data()));
9704760bfaSnicole mazzuca     }
9804760bfaSnicole mazzuca   }
9904760bfaSnicole mazzuca 
10004760bfaSnicole mazzuca   { // check that last is returned with no match
10104760bfaSnicole mazzuca     {
10204760bfaSnicole mazzuca       ValueT a[] = {1, 1, 1};
10304760bfaSnicole mazzuca 
10404760bfaSnicole mazzuca       auto ret = std::ranges::find_last(It(a), Sent(It(a + 3)), 0).begin();
10504760bfaSnicole mazzuca       assert(ret == It(a + 3));
10604760bfaSnicole mazzuca     }
10704760bfaSnicole mazzuca     {
10804760bfaSnicole mazzuca       ValueT a[] = {1, 1, 1};
10904760bfaSnicole mazzuca 
11004760bfaSnicole mazzuca       auto ret = std::ranges::find_last(make_range(a), 0).begin();
11104760bfaSnicole mazzuca       assert(ret == It(a + 3));
11204760bfaSnicole mazzuca     }
11304760bfaSnicole mazzuca   }
11404760bfaSnicole mazzuca }
11504760bfaSnicole mazzuca 
11604760bfaSnicole mazzuca template <template <class> class IteratorT>
11704760bfaSnicole mazzuca constexpr void test_iterator_classes() {
11804760bfaSnicole mazzuca   { // check that the last element is returned
11904760bfaSnicole mazzuca     struct S {
12004760bfaSnicole mazzuca       int comp;
12104760bfaSnicole mazzuca       int other;
12204760bfaSnicole mazzuca     };
12304760bfaSnicole mazzuca     using it = IteratorT<S*>;
12404760bfaSnicole mazzuca     S a[]    = {{0, 0}, {0, 2}, {0, 1}};
12504760bfaSnicole mazzuca 
12604760bfaSnicole mazzuca     auto ret = std::ranges::find_last(it(std::begin(a)), it(std::end(a)), 0, &S::comp).begin();
12704760bfaSnicole mazzuca     assert(ret == it(a + 2));
12804760bfaSnicole mazzuca     assert((*ret).comp == 0);
12904760bfaSnicole mazzuca     assert((*ret).other == 1);
13004760bfaSnicole mazzuca   }
13104760bfaSnicole mazzuca 
13204760bfaSnicole mazzuca   {
13304760bfaSnicole mazzuca     // count invocations of the projection
13404760bfaSnicole mazzuca     using it = IteratorT<int*>;
13504760bfaSnicole mazzuca 
13604760bfaSnicole mazzuca     int a[]              = {1, 2, 3, 4};
13704760bfaSnicole mazzuca     int projection_count = 0;
13804760bfaSnicole mazzuca 
13904760bfaSnicole mazzuca     auto ret = std::ranges::find_last(it(std::begin(a)), it(std::end(a)), 2, [&](int i) {
14004760bfaSnicole mazzuca                  ++projection_count;
14104760bfaSnicole mazzuca                  return i;
14204760bfaSnicole mazzuca                }).begin();
14304760bfaSnicole mazzuca     assert(ret == it(a + 1));
14404760bfaSnicole mazzuca     assert(*ret == 2);
14504760bfaSnicole mazzuca     if (std::bidirectional_iterator<it>) {
14604760bfaSnicole mazzuca       assert(projection_count == 3);
14704760bfaSnicole mazzuca     } else {
14804760bfaSnicole mazzuca       assert(projection_count == 4); // must go through entire list
14904760bfaSnicole mazzuca     }
15004760bfaSnicole mazzuca   }
15104760bfaSnicole mazzuca }
15204760bfaSnicole mazzuca 
15304760bfaSnicole mazzuca template <class ElementT>
15404760bfaSnicole mazzuca class TriviallyComparable {
15504760bfaSnicole mazzuca   ElementT el_;
15604760bfaSnicole mazzuca 
15704760bfaSnicole mazzuca public:
15804760bfaSnicole mazzuca   constexpr TriviallyComparable(ElementT el) : el_(el) {}
15904760bfaSnicole mazzuca   bool operator==(const TriviallyComparable&) const = default;
16004760bfaSnicole mazzuca };
16104760bfaSnicole mazzuca 
16204760bfaSnicole mazzuca constexpr bool test() {
16304760bfaSnicole mazzuca   types::for_each(types::type_list<char, int, TriviallyComparable<char>>{}, []<class T> {
16404760bfaSnicole mazzuca     types::for_each(types::forward_iterator_list<T*>{}, []<class Iter> {
16504760bfaSnicole mazzuca       test_iterators<Iter>();
16604760bfaSnicole mazzuca       test_iterators<Iter, sentinel_wrapper<Iter>>();
16704760bfaSnicole mazzuca       test_iterators<Iter, sized_sentinel<Iter>>();
16804760bfaSnicole mazzuca     });
16904760bfaSnicole mazzuca   });
17004760bfaSnicole mazzuca 
17104760bfaSnicole mazzuca   test_iterator_classes<forward_iterator>();
17204760bfaSnicole mazzuca   test_iterator_classes<bidirectional_iterator>();
17304760bfaSnicole mazzuca   test_iterator_classes<random_access_iterator>();
17404760bfaSnicole mazzuca   test_iterator_classes<std::type_identity_t>();
17504760bfaSnicole mazzuca 
17604760bfaSnicole mazzuca   {
17704760bfaSnicole mazzuca     std::vector<std::vector<int>> vec = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
17804760bfaSnicole mazzuca 
17904760bfaSnicole mazzuca     auto view = vec | std::views::join;
18004760bfaSnicole mazzuca     assert(std::ranges::find_last(view.begin(), view.end(), 4).begin() == std::next(view.begin(), 3));
18104760bfaSnicole mazzuca     assert(std::ranges::find_last(view, 4).begin() == std::next(view.begin(), 3));
18204760bfaSnicole mazzuca   }
18304760bfaSnicole mazzuca 
18404760bfaSnicole mazzuca   {
18504760bfaSnicole mazzuca     // check that an iterator is returned with a borrowing range
18604760bfaSnicole mazzuca     int a[] = {1, 2, 3, 4};
18704760bfaSnicole mazzuca 
18804760bfaSnicole mazzuca     std::same_as<std::ranges::subrange<int*>> auto ret = std::ranges::find_last(std::views::all(a), 1);
18904760bfaSnicole mazzuca     assert(ret.begin() == a);
19004760bfaSnicole mazzuca     assert(*ret.begin() == 1);
19104760bfaSnicole mazzuca   }
19204760bfaSnicole mazzuca 
19304760bfaSnicole mazzuca   {
19404760bfaSnicole mazzuca     // check that dangling ranges are dangling
19504760bfaSnicole mazzuca     std::same_as<std::ranges::dangling> auto ret = std::ranges::find_last(std::vector<int>(), 0);
19604760bfaSnicole mazzuca     (void)ret;
19704760bfaSnicole mazzuca   }
19804760bfaSnicole mazzuca 
19904760bfaSnicole mazzuca   return true;
20004760bfaSnicole mazzuca }
20104760bfaSnicole mazzuca 
20204760bfaSnicole mazzuca int main(int, char**) {
20304760bfaSnicole mazzuca   test();
20404760bfaSnicole mazzuca   static_assert(test());
20504760bfaSnicole mazzuca   return 0;
20604760bfaSnicole mazzuca }
207