1a2b3ab8fSHui //===----------------------------------------------------------------------===// 2a2b3ab8fSHui // 3a2b3ab8fSHui // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a2b3ab8fSHui // See https://llvm.org/LICENSE.txt for license information. 5a2b3ab8fSHui // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a2b3ab8fSHui // 7a2b3ab8fSHui //===----------------------------------------------------------------------===// 8a2b3ab8fSHui 9a2b3ab8fSHui // UNSUPPORTED: c++03, c++11, c++14, c++17 10a2b3ab8fSHui 11a2b3ab8fSHui // constexpr auto begin(); 12a2b3ab8fSHui 13a2b3ab8fSHui #include <array> 14a2b3ab8fSHui #include <cassert> 15a2b3ab8fSHui #include <ranges> 16a2b3ab8fSHui #include <type_traits> 17a2b3ab8fSHui #include <utility> 18a2b3ab8fSHui 19a2b3ab8fSHui #include "test_iterators.h" 20a2b3ab8fSHui 21a2b3ab8fSHui struct View : std::ranges::view_base { 22a2b3ab8fSHui int* begin() const; 23a2b3ab8fSHui int* end() const; 24a2b3ab8fSHui }; 25a2b3ab8fSHui 26a2b3ab8fSHui // Test that begin is not const 27a2b3ab8fSHui template <class T> 28a2b3ab8fSHui concept HasBegin = requires(T t) { t.begin(); }; 29a2b3ab8fSHui 30a2b3ab8fSHui static_assert(HasBegin<std::ranges::split_view<View, View>>); 31a2b3ab8fSHui static_assert(!HasBegin<const std::ranges::split_view<View, View>>); 32a2b3ab8fSHui 33a2b3ab8fSHui template <template <class> class MakeIter> 34a2b3ab8fSHui constexpr void testOne() { 35a2b3ab8fSHui constexpr auto make_subrange = []<class T, std::size_t N>(T(&buffer)[N]) { 36a2b3ab8fSHui using Iter = MakeIter<T*>; 37a2b3ab8fSHui using Sent = sentinel_wrapper<Iter>; 38a2b3ab8fSHui return std::ranges::subrange<Iter, Sent>{Iter{buffer}, Sent{Iter{buffer + N}}}; 39a2b3ab8fSHui }; 40a2b3ab8fSHui 41a2b3ab8fSHui using Iter = MakeIter<int*>; 42a2b3ab8fSHui using Sent = sentinel_wrapper<Iter>; 43a2b3ab8fSHui using Range = std::ranges::subrange<Iter, Sent>; 44a2b3ab8fSHui 45a2b3ab8fSHui // empty view 46a2b3ab8fSHui { 47a2b3ab8fSHui std::array<int, 0> a; 48a2b3ab8fSHui Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}}; 49a2b3ab8fSHui std::ranges::split_view sv{std::move(range), 1}; 50a2b3ab8fSHui auto it = sv.begin(); 51a2b3ab8fSHui auto firstRange = *it; 52*f73050e7SLouis Dionne assert(firstRange.begin() == Iter(a.data())); 53*f73050e7SLouis Dionne assert(firstRange.end() == Sent(Iter(a.data()))); 54a2b3ab8fSHui } 55a2b3ab8fSHui 56a2b3ab8fSHui // empty pattern 57a2b3ab8fSHui { 58a2b3ab8fSHui int buffer[] = {1, 2, 3}; 59a2b3ab8fSHui auto range = make_subrange(buffer); 60a2b3ab8fSHui std::ranges::split_view sv{std::move(range), std::views::empty<int>}; 61a2b3ab8fSHui auto it = sv.begin(); 62a2b3ab8fSHui auto firstRange = *it; 63*f73050e7SLouis Dionne assert(firstRange.begin() == Iter(buffer)); 64*f73050e7SLouis Dionne assert(firstRange.end() == Sent(Iter(buffer + 1))); 65a2b3ab8fSHui } 66a2b3ab8fSHui 67a2b3ab8fSHui // empty view and empty pattern 68a2b3ab8fSHui { 69a2b3ab8fSHui std::array<int, 0> a; 70a2b3ab8fSHui Range range{Iter{a.data()}, Sent{Iter{a.data() + a.size()}}}; 71a2b3ab8fSHui std::ranges::split_view sv{std::move(range), std::views::empty<int>}; 72a2b3ab8fSHui auto it = sv.begin(); 73a2b3ab8fSHui auto firstRange = *it; 74*f73050e7SLouis Dionne assert(firstRange.begin() == Iter(a.data())); 75*f73050e7SLouis Dionne assert(firstRange.end() == Sent(Iter(a.data()))); 76a2b3ab8fSHui } 77a2b3ab8fSHui 78a2b3ab8fSHui // pattern found at the beginning 79a2b3ab8fSHui { 80a2b3ab8fSHui int buffer[] = {1, 2, 3}; 81a2b3ab8fSHui auto range = make_subrange(buffer); 82a2b3ab8fSHui int pattern[] = {1, 2}; 83a2b3ab8fSHui std::ranges::split_view sv{range, pattern}; 84a2b3ab8fSHui 85a2b3ab8fSHui auto it = sv.begin(); 86a2b3ab8fSHui auto firstRange = *it; 87*f73050e7SLouis Dionne assert(firstRange.begin() == Iter(buffer)); 88*f73050e7SLouis Dionne assert(firstRange.end() == Sent(Iter(buffer))); 89a2b3ab8fSHui } 90a2b3ab8fSHui 91a2b3ab8fSHui // pattern found in the middle 92a2b3ab8fSHui { 93a2b3ab8fSHui int buffer[] = {1, 2, 3, 4}; 94a2b3ab8fSHui auto range = make_subrange(buffer); 95a2b3ab8fSHui int pattern[] = {2, 3}; 96a2b3ab8fSHui std::ranges::split_view sv{range, pattern}; 97a2b3ab8fSHui 98a2b3ab8fSHui auto it = sv.begin(); 99a2b3ab8fSHui auto firstRange = *it; 100*f73050e7SLouis Dionne assert(firstRange.begin() == Iter(buffer)); 101*f73050e7SLouis Dionne assert(firstRange.end() == Sent(Iter(buffer + 1))); 102a2b3ab8fSHui } 103a2b3ab8fSHui 104a2b3ab8fSHui // pattern found at the end 105a2b3ab8fSHui { 106a2b3ab8fSHui int buffer[] = {1, 2, 3}; 107a2b3ab8fSHui auto range = make_subrange(buffer); 108a2b3ab8fSHui int pattern[] = {2, 3}; 109a2b3ab8fSHui std::ranges::split_view sv{range, pattern}; 110a2b3ab8fSHui 111a2b3ab8fSHui auto it = sv.begin(); 112a2b3ab8fSHui auto firstRange = *it; 113*f73050e7SLouis Dionne assert(firstRange.begin() == Iter(buffer)); 114*f73050e7SLouis Dionne assert(firstRange.end() == Sent(Iter(buffer + 1))); 115a2b3ab8fSHui } 116a2b3ab8fSHui 117a2b3ab8fSHui // pattern not found 118a2b3ab8fSHui { 119a2b3ab8fSHui int buffer[] = {1, 2, 3}; 120a2b3ab8fSHui auto range = make_subrange(buffer); 121a2b3ab8fSHui int pattern[] = {1, 3}; 122a2b3ab8fSHui std::ranges::split_view sv{range, pattern}; 123a2b3ab8fSHui 124a2b3ab8fSHui auto it = sv.begin(); 125a2b3ab8fSHui auto firstRange = *it; 126*f73050e7SLouis Dionne assert(firstRange.begin() == Iter(buffer)); 127*f73050e7SLouis Dionne assert(firstRange.end() == Sent(Iter(buffer + 3))); 128a2b3ab8fSHui } 129a2b3ab8fSHui 130a2b3ab8fSHui // Make sure that we cache the result of begin() on subsequent calls 131a2b3ab8fSHui { 132a2b3ab8fSHui struct Foo { 133a2b3ab8fSHui int& equalsCalledTimes; 134a2b3ab8fSHui 135a2b3ab8fSHui constexpr bool operator==(const Foo&) const { 136a2b3ab8fSHui ++equalsCalledTimes; 137a2b3ab8fSHui return true; 138a2b3ab8fSHui } 139a2b3ab8fSHui }; 140a2b3ab8fSHui 141a2b3ab8fSHui int equalsCalledTimes = 0; 142a2b3ab8fSHui Foo buffer[] = {Foo{equalsCalledTimes}, Foo{equalsCalledTimes}}; 143a2b3ab8fSHui auto range = make_subrange(buffer); 144a2b3ab8fSHui 145a2b3ab8fSHui std::ranges::split_view sv{range, Foo{equalsCalledTimes}}; 146a2b3ab8fSHui 147a2b3ab8fSHui assert(equalsCalledTimes == 0); 148a2b3ab8fSHui 149a2b3ab8fSHui [[maybe_unused]] auto it1 = sv.begin(); 150a2b3ab8fSHui auto calledTimesAfterFirstBegin = equalsCalledTimes; 151a2b3ab8fSHui assert(calledTimesAfterFirstBegin != 0); 152a2b3ab8fSHui 153a2b3ab8fSHui for (int i = 0; i < 10; ++i) { 154a2b3ab8fSHui [[maybe_unused]] auto it2 = sv.begin(); 155a2b3ab8fSHui assert(equalsCalledTimes == calledTimesAfterFirstBegin); 156a2b3ab8fSHui } 157a2b3ab8fSHui } 158a2b3ab8fSHui } 159a2b3ab8fSHui 160a2b3ab8fSHui constexpr bool test() { 161a2b3ab8fSHui testOne<forward_iterator>(); 162a2b3ab8fSHui testOne<bidirectional_iterator>(); 163a2b3ab8fSHui testOne<random_access_iterator>(); 164a2b3ab8fSHui testOne<contiguous_iterator>(); 165a2b3ab8fSHui testOne<std::type_identity_t>(); 166a2b3ab8fSHui return true; 167a2b3ab8fSHui } 168a2b3ab8fSHui 169a2b3ab8fSHui int main(int, char**) { 170a2b3ab8fSHui test(); 171a2b3ab8fSHui static_assert(test()); 172a2b3ab8fSHui return 0; 173a2b3ab8fSHui } 174