174 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 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 21struct View : std::ranges::view_base {22 int* begin() const;23 int* end() const;24};25 26// Test that begin is not const27template <class T>28concept HasBegin = requires(T t) { t.begin(); };29 30static_assert(HasBegin<std::ranges::split_view<View, View>>);31static_assert(!HasBegin<const std::ranges::split_view<View, View>>);32 33template <template <class> class MakeIter>34constexpr 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 view46 {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 pattern57 {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 pattern68 {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 beginning79 {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 middle92 {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 end105 {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 found118 {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 calls131 {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 160constexpr 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 169int main(int, char**) {170 test();171 static_assert(test());172 return 0;173}174