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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11
12 // constexpr View base() const& requires copy_constructible<_View>;
13 // constexpr View base() &&;
14
15 #include <ranges>
16
17 #include <cassert>
18 #include <string_view>
19 #include <utility>
20 #include "types.h"
21
22 struct MoveOnlyView : std::ranges::view_base {
23 std::string_view view_;
24 constexpr MoveOnlyView() = default;
MoveOnlyViewMoveOnlyView25 constexpr MoveOnlyView(const char* ptr) : view_(ptr) {}
MoveOnlyViewMoveOnlyView26 constexpr MoveOnlyView(std::string_view v) : view_(v) {}
27 constexpr MoveOnlyView(MoveOnlyView&&) = default;
28 constexpr MoveOnlyView& operator=(MoveOnlyView&&) = default;
beginMoveOnlyView29 constexpr const char* begin() const { return view_.begin(); }
endMoveOnlyView30 constexpr const char* end() const { return view_.end(); }
operator ==MoveOnlyView31 constexpr bool operator==(MoveOnlyView rhs) const { return view_ == rhs.view_; }
32 };
33 static_assert( std::ranges::view<MoveOnlyView>);
34 static_assert( std::ranges::contiguous_range<MoveOnlyView>);
35 static_assert(!std::copyable<MoveOnlyView>);
36
37 struct ViewWithInitTracking : std::ranges::view_base {
38 enum class InitializedBy {
39 Copy,
40 Move,
41 Invalid
42 };
43
44 std::string_view v_;
45 InitializedBy initialized_by = InitializedBy::Invalid;
ViewWithInitTrackingViewWithInitTracking46 constexpr ViewWithInitTracking(std::string_view v) : v_(v) {}
47
beginViewWithInitTracking48 constexpr auto begin() const { return v_.begin(); }
endViewWithInitTracking49 constexpr auto end() const { return v_.end(); }
50
ViewWithInitTrackingViewWithInitTracking51 constexpr ViewWithInitTracking(const ViewWithInitTracking& rhs) : v_(rhs.v_) { initialized_by = InitializedBy::Copy; }
ViewWithInitTrackingViewWithInitTracking52 constexpr ViewWithInitTracking(ViewWithInitTracking&& rhs) : v_(rhs.v_) { initialized_by = InitializedBy::Move; }
53 constexpr ViewWithInitTracking& operator=(const ViewWithInitTracking& rhs) = default;
54 constexpr ViewWithInitTracking& operator=(ViewWithInitTracking&& rhs) = default;
operator ==ViewWithInitTracking55 constexpr bool operator==(const ViewWithInitTracking& rhs) const { return v_ == rhs.v_; }
56 };
57
58 template <class View>
59 concept CanCallBase = requires(View v) { std::forward<View>(v).base(); };
60
61 static_assert( CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView>&&>);
62 static_assert(!CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView>&>);
63 static_assert(!CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView> const &>);
64 static_assert(!CanCallBase<std::ranges::lazy_split_view<MoveOnlyView, ForwardView> const &&>);
65
test()66 constexpr bool test() {
67 using View = ViewWithInitTracking;
68
69 // Copyable input -- both lvalue and rvalue overloads of `base` are available.
70 {
71 // Non-const lvalue.
72 {
73 View str{"abc def"};
74 std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
75
76 std::same_as<View> decltype(auto) result = v.base();
77 assert(result == str);
78 assert(result.initialized_by == View::InitializedBy::Copy);
79 }
80
81 // Const lvalue.
82 {
83 View str{"abc def"};
84 const std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
85
86 std::same_as<View> decltype(auto) result = v.base();
87 assert(result == str);
88 assert(result.initialized_by == View::InitializedBy::Copy);
89 }
90
91 // Non-const rvalue.
92 {
93 View str{"abc def"};
94 std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
95
96 std::same_as<View> decltype(auto) result = std::move(v).base();
97 assert(result == str);
98 assert(result.initialized_by == View::InitializedBy::Move);
99 }
100
101 // Const rvalue.
102 {
103 View str{"abc def"};
104 const std::ranges::lazy_split_view<View, std::string_view> v(str, " ");
105
106 std::same_as<View> decltype(auto) result = std::move(v).base();
107 assert(result == str);
108 assert(result.initialized_by == View::InitializedBy::Copy);
109 }
110 }
111
112 // Move-only input -- only the rvalue overload of `base` is available.
113 {
114 std::ranges::lazy_split_view<MoveOnlyView, ForwardView> v;
115 assert(std::move(v).base() == MoveOnlyView());
116 }
117
118 return true;
119 }
120
main(int,char **)121 int main(int, char**) {
122 test();
123 static_assert(test());
124
125 return 0;
126 }
127