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