157 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++17, c++2010 11// <ranges>12 13// constexpr iterator begin();14 15#include <ranges>16 17#include <cassert>18#include <utility>19 20#include "test_iterators.h"21#include "types.h"22 23struct Range : std::ranges::view_base {24 using Iterator = forward_iterator<int*>;25 using Sentinel = sentinel_wrapper<Iterator>;26 constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) {}27 constexpr Iterator begin() const { return Iterator(begin_); }28 constexpr Sentinel end() const { return Sentinel(Iterator(end_)); }29 30private:31 int* begin_;32 int* end_;33};34 35struct TrackingPred : TrackInitialization {36 using TrackInitialization::TrackInitialization;37 constexpr bool operator()(int x, int y) { return x != -y; }38};39 40template <class T>41concept HasBegin = requires(T t) { t.begin(); };42 43static_assert(HasBegin<std::ranges::chunk_by_view<Range, TrackingPred>>);44static_assert(!HasBegin<const std::ranges::chunk_by_view<Range, TrackingPred>>);45 46constexpr bool test() {47 int buff[] = {-4, -3, -2, -1, 1, 2, 3, 4};48 49 // Check the return type of `begin()`50 {51 Range range(buff, buff + 1);52 auto pred = [](int, int) { return true; };53 std::ranges::chunk_by_view view(range, pred);54 using ChunkByIterator = std::ranges::iterator_t<decltype(view)>;55 ASSERT_SAME_TYPE(ChunkByIterator, decltype(view.begin()));56 }57 58 // begin() over an empty range59 {60 Range range(buff, buff);61 auto pred = [](int, int) { return true; };62 std::ranges::chunk_by_view view(range, pred);63 auto it = view.begin();64 assert(it == view.begin());65 assert(it == view.end());66 }67 68 // begin() over a 1-element range69 {70 Range range(buff, buff + 1);71 auto pred = [](int x, int y) { return x == y; };72 std::ranges::chunk_by_view view(range, pred);73 auto it = view.begin();74 assert(base((*it).begin()) == buff);75 assert(base((*it).end()) == buff + 1);76 }77 78 // begin() over a 2-element range79 {80 Range range(buff, buff + 2);81 auto pred = [](int x, int y) { return x == y; };82 std::ranges::chunk_by_view view(range, pred);83 auto it = view.begin();84 assert(base((*it).begin()) == buff);85 assert(base((*it).end()) == buff + 1);86 assert(base((*++it).begin()) == buff + 1);87 assert(base((*it).end()) == buff + 2);88 }89 90 // begin() over a longer range91 {92 Range range(buff, buff + 8);93 auto pred = [](int x, int y) { return x != -y; };94 std::ranges::chunk_by_view view(range, pred);95 auto it = view.begin();96 assert(base((*it).end()) == buff + 4);97 }98 99 // Make sure we do not make a copy of the predicate when we call begin()100 // (we should be passing it to ranges::adjacent_find using std::ref)101 {102 bool moved = false, copied = false;103 Range range(buff, buff + 2);104 std::ranges::chunk_by_view view(range, TrackingPred(&moved, &copied));105 std::exchange(moved, false);106 [[maybe_unused]] auto it = view.begin();107 assert(!moved);108 assert(!copied);109 }110 111 // Test with a non-const predicate112 {113 Range range(buff, buff + 8);114 auto pred = [](int x, int y) mutable { return x != -y; };115 std::ranges::chunk_by_view view(range, pred);116 auto it = view.begin();117 assert(base((*it).end()) == buff + 4);118 }119 120 // Test with a predicate that takes by non-const reference121 {122 Range range(buff, buff + 8);123 auto pred = [](int& x, int& y) { return x != -y; };124 std::ranges::chunk_by_view view(range, pred);125 auto it = view.begin();126 assert(base((*it).end()) == buff + 4);127 }128 129 // Test caching130 {131 // Make sure that we cache the result of begin() on subsequent calls132 Range range(buff, buff + 8);133 int called = 0;134 auto pred = [&](int x, int y) {135 ++called;136 return x != -y;137 };138 139 std::ranges::chunk_by_view view(range, pred);140 assert(called == 0);141 for (int k = 0; k != 3; ++k) {142 auto it = view.begin();143 assert(base((*it).end()) == buff + 4);144 assert(called == 4); // 4, because the cached iterator is 'buff + 4' (end of the first chunk)145 }146 }147 148 return true;149}150 151int main(int, char**) {152 test();153 static_assert(test());154 155 return 0;156}157