209 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// template<range R>12// requires is_object_v<R>13// class ref_view;14 15#include <ranges>16 17#include <cassert>18#include "test_macros.h"19#include "test_iterators.h"20 21int globalBuff[8];22 23template<class T>24concept ValidRefView = requires { typename std::ranges::ref_view<T>; };25 26struct Range {27 int start = 0;28 friend constexpr int* begin(Range const& range) { return globalBuff + range.start; }29 friend constexpr int* end(Range const&) { return globalBuff + 8; }30 friend constexpr int* begin(Range& range) { return globalBuff + range.start; }31 friend constexpr int* end(Range&) { return globalBuff + 8; }32};33 34struct BeginOnly {35 friend int* begin(BeginOnly const&);36 friend int* begin(BeginOnly &);37};38 39static_assert( ValidRefView<Range>);40static_assert(!ValidRefView<BeginOnly>);41static_assert(!ValidRefView<int (&)[4]>);42static_assert( ValidRefView<int[4]>);43 44static_assert(std::derived_from<std::ranges::ref_view<Range>, std::ranges::view_interface<std::ranges::ref_view<Range>>>);45 46struct RangeConvertible {47 operator Range& ();48};49 50struct RValueRangeConvertible {51 operator Range&& ();52};53 54static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, Range&>);55static_assert( std::is_constructible_v<std::ranges::ref_view<Range>, RangeConvertible>);56static_assert(!std::is_constructible_v<std::ranges::ref_view<Range>, RValueRangeConvertible>);57 58struct ConstConvertibleToLValueAndRValue {59 operator Range& () const;60 operator Range&& () const;61};62static_assert( std::is_convertible_v<RangeConvertible, std::ranges::ref_view<Range>>);63static_assert(!std::is_convertible_v<RValueRangeConvertible, std::ranges::ref_view<Range>>);64static_assert(!std::is_convertible_v<ConstConvertibleToLValueAndRValue, std::ranges::ref_view<Range>>);65 66struct ForwardRange {67 constexpr forward_iterator<int*> begin() const { return forward_iterator<int*>(globalBuff); }68 constexpr forward_iterator<int*> end() const { return forward_iterator<int*>(globalBuff + 8); }69};70 71struct Cpp17InputRange {72 struct sentinel {73 friend constexpr bool operator==(sentinel, cpp17_input_iterator<int*> iter) { return base(iter) == globalBuff + 8; }74 friend constexpr std::ptrdiff_t operator-(sentinel, cpp17_input_iterator<int*>) { return -8; }75 friend constexpr std::ptrdiff_t operator-(cpp17_input_iterator<int*>, sentinel) { return 8; }76 };77 78 constexpr cpp17_input_iterator<int*> begin() const {79 return cpp17_input_iterator<int*>(globalBuff);80 }81 constexpr sentinel end() const { return {}; }82};83 84struct Cpp20InputRange {85 struct sentinel {86 friend constexpr bool operator==(sentinel, const cpp20_input_iterator<int*> &iter) { return base(iter) == globalBuff + 8; }87 friend constexpr std::ptrdiff_t operator-(sentinel, const cpp20_input_iterator<int*>&) { return -8; }88 };89 90 constexpr cpp20_input_iterator<int*> begin() const {91 return cpp20_input_iterator<int*>(globalBuff);92 }93 constexpr sentinel end() const { return {}; }94};95 96template<>97inline constexpr bool std::ranges::enable_borrowed_range<Cpp20InputRange> = true;98 99template<class R>100concept EmptyIsInvocable = requires (std::ranges::ref_view<R> view) { view.empty(); };101 102template<class R>103concept SizeIsInvocable = requires (std::ranges::ref_view<R> view) { view.size(); };104 105template<class R>106concept DataIsInvocable = requires (std::ranges::ref_view<R> view) { view.data(); };107 108// Testing ctad.109static_assert(std::same_as<decltype(std::ranges::ref_view(std::declval<Range&>())),110 std::ranges::ref_view<Range>>);111 112constexpr bool test() {113 {114 // ref_view::base115 Range range;116 std::ranges::ref_view<Range> view{range};117 assert(view.begin() == globalBuff);118 view.base() = Range{2};119 assert(view.begin() == globalBuff + 2);120 }121 122 {123 // ref_view::begin124 Range range1;125 std::ranges::ref_view<Range> view1 = range1;126 assert(view1.begin() == globalBuff);127 128 ForwardRange range2;129 std::ranges::ref_view<ForwardRange> view2 = range2;130 assert(base(view2.begin()) == globalBuff);131 132 Cpp17InputRange range3;133 std::ranges::ref_view<Cpp17InputRange> view3 = range3;134 assert(base(view3.begin()) == globalBuff);135 136 Cpp20InputRange range4;137 std::ranges::ref_view<Cpp20InputRange> view4 = range4;138 assert(base(view4.begin()) == globalBuff);139 }140 141 {142 // ref_view::end143 Range range1;144 std::ranges::ref_view<Range> view1 = range1;145 assert(view1.end() == globalBuff + 8);146 147 ForwardRange range2;148 std::ranges::ref_view<ForwardRange> view2 = range2;149 assert(base(view2.end()) == globalBuff + 8);150 151 Cpp17InputRange range3;152 std::ranges::ref_view<Cpp17InputRange> view3 = range3;153 assert(view3.end() == cpp17_input_iterator(globalBuff + 8));154 155 Cpp20InputRange range4;156 std::ranges::ref_view<Cpp20InputRange> view4 = range4;157 assert(view4.end() == cpp20_input_iterator(globalBuff + 8));158 }159 160 {161 // ref_view::empty162 Range range{8};163 std::ranges::ref_view<Range> view1 = range;164 assert(view1.empty());165 166 ForwardRange range2;167 std::ranges::ref_view<ForwardRange> view2 = range2;168 assert(!view2.empty());169 170 static_assert(!EmptyIsInvocable<Cpp17InputRange>);171 static_assert(!EmptyIsInvocable<Cpp20InputRange>);172 }173 174 {175 // ref_view::size176 Range range1{8};177 std::ranges::ref_view<Range> view1 = range1;178 assert(view1.size() == 0);179 180 Range range2{2};181 std::ranges::ref_view<Range> view2 = range2;182 assert(view2.size() == 6);183 184 static_assert(!SizeIsInvocable<ForwardRange>);185 }186 187 {188 // ref_view::data189 Range range1;190 std::ranges::ref_view<Range> view1 = range1;191 assert(view1.data() == globalBuff);192 193 Range range2{2};194 std::ranges::ref_view<Range> view2 = range2;195 assert(view2.data() == globalBuff + 2);196 197 static_assert(!DataIsInvocable<ForwardRange>);198 }199 200 return true;201}202 203int main(int, char**) {204 test();205 static_assert(test());206 207 return 0;208}209