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// REQUIRES: std-at-least-c++23
10
11// <ranges>
12
13// constexpr View base() const& requires copy_constructible<View>;
14// constexpr View base() &&;
15
16#include <ranges>
17
18#include <cassert>
19#include <utility>
20#include <vector>
21
22using InnerRange = std::vector<int>;
23
24struct Range : std::ranges::view_base {
25 constexpr explicit Range(InnerRange* b, InnerRange* e) : begin_(b), end_(e) {}
26 constexpr Range(const Range& other) : begin_(other.begin_), end_(other.end_), was_copy_initialized_(true) {}
27 constexpr Range(Range&& other) : begin_(other.begin_), end_(other.end_), was_move_initialized_(true) {}
28 Range& operator=(const Range&) = default;
29 Range& operator=(Range&&) = default;
30 constexpr InnerRange* begin() const { return begin_; }
31 constexpr InnerRange* end() const { return end_; }
32
33 InnerRange* begin_;
34 InnerRange* end_;
35 bool was_copy_initialized_ = false;
36 bool was_move_initialized_ = false;
37};
38
39static_assert(std::ranges::view<Range>);
40static_assert(std::ranges::input_range<Range>);
41
42struct Pattern : std::ranges::view_base {
43 static constexpr int pat[2] = {0, 0};
44 constexpr const int* begin() const { return pat; }
45 constexpr const int* end() const { return pat + 2; }
46};
47
48static_assert(std::ranges::view<Pattern>);
49static_assert(std::ranges::forward_range<Pattern>);
50
51template <class Tp>
52struct NonCopyableRange : std::ranges::view_base {
53 NonCopyableRange(const NonCopyableRange&) = delete;
54 NonCopyableRange(NonCopyableRange&&) = default;
55 NonCopyableRange& operator=(const NonCopyableRange&) = default;
56 NonCopyableRange& operator=(NonCopyableRange&&) = default;
57 Tp* begin() const;
58 Tp* end() const;
59};
60
61static_assert(!std::copy_constructible<NonCopyableRange<InnerRange>>);
62static_assert(!std::copy_constructible<NonCopyableRange<int>>);
63
64template <typename T>
65concept CanCallBaseOn = requires(T&& t) { std::forward<T>(t).base(); };
66
67constexpr bool test() {
68 InnerRange buff[3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
69 Pattern pattern;
70
71 { // Check the const& overload
72 Range range(buff, buff + 3);
73 std::ranges::join_with_view<Range, Pattern> view(range, pattern);
74 std::same_as<Range> decltype(auto) result = view.base();
75 assert(result.was_copy_initialized_);
76 assert(result.begin() == buff);
77 assert(result.end() == buff + 3);
78 }
79
80 { // Check the const& overload on const `view`
81 Range range(buff, buff + 3);
82 const std::ranges::join_with_view<Range, Pattern> view(range, pattern);
83 std::same_as<Range> decltype(auto) result = view.base();
84 assert(result.was_copy_initialized_);
85 assert(result.begin() == buff);
86 assert(result.end() == buff + 3);
87 }
88
89 { // Check the && overload
90 Range range(buff, buff + 3);
91 std::ranges::join_with_view<Range, Pattern> view(range, pattern);
92 std::same_as<Range> decltype(auto) result = std::move(view).base();
93 assert(result.was_move_initialized_);
94 assert(result.begin() == buff);
95 assert(result.end() == buff + 3);
96 }
97
98 { // Ensure the const& overload is not considered when the base is not copy-constructible
99 static_assert(!CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&>);
100 static_assert(!CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&>);
101 static_assert(!CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&&>);
102 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>&&>);
103 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, Pattern>>);
104 }
105
106 { // Ensure the const& overload does not depend on Pattern's copy-constructability
107 static_assert(CanCallBaseOn<const std::ranges::join_with_view<Range, NonCopyableRange<int>>&>);
108 static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>&>);
109 static_assert(CanCallBaseOn<const std::ranges::join_with_view<Range, NonCopyableRange<int>>&&>);
110 static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>&&>);
111 static_assert(CanCallBaseOn<std::ranges::join_with_view<Range, NonCopyableRange<int>>>);
112 }
113
114 { // Check above two at the same time
115 static_assert(
116 !CanCallBaseOn<const std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&>);
117 static_assert(!CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&>);
118 static_assert(
119 !CanCallBaseOn<const std::ranges::join_with_view< NonCopyableRange<InnerRange>, NonCopyableRange<int>>&&>);
120 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>&&>);
121 static_assert(CanCallBaseOn<std::ranges::join_with_view<NonCopyableRange<InnerRange>, NonCopyableRange<int>>>);
122 }
123
124 return true;
125}
126
127int main(int, char**) {
128 test();
129 static_assert(test());
130
131 return 0;
132}
133

source code of libcxx/test/std/ranges/range.adaptors/range.join.with/range.join.with.view/base.pass.cpp