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