xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.as.rvalue/end.pass.cpp (revision f56dfb78aa3fcc96bf7e5b6c3bdff8fa620aefd1)
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, c++20
10 
11 // constexpr auto end()
12 // constexpr auto end() const
13 
14 #include <array>
15 #include <cassert>
16 #include <ranges>
17 
18 #include "test_iterators.h"
19 
20 struct DefaultConstructibleView : std::ranges::view_base {
21   int* begin() const;
22   int* end() const;
23 };
24 
25 struct CVCallView : std::ranges::view_base {
26   mutable bool const_called = false;
27   mutable int i[1];
beginCVCallView28   constexpr int* begin() {
29     const_called = false;
30     return i;
31   }
32 
beginCVCallView33   constexpr int* begin() const {
34     const_called = true;
35     return i;
36   }
37 
endCVCallView38   constexpr int* end() {
39     const_called = false;
40     return i + 1;
41   }
42 
endCVCallView43   constexpr int* end() const {
44     const_called = true;
45     return i + 1;
46   }
47 };
48 
49 struct NonConstCommonRange : std::ranges::view_base {
50   int* begin();
51   int* end();
52 
53   int* begin() const;
54   sentinel_wrapper<int*> end() const;
55 };
56 
57 struct NonConstView : std::ranges::view_base {
58   int* begin();
59   int* end();
60 };
61 
62 template <class T>
63 concept HasEnd = requires(T t) { t.end(); };
64 
65 static_assert(HasEnd<std::ranges::as_rvalue_view<DefaultConstructibleView>>);
66 static_assert(HasEnd<const std::ranges::as_rvalue_view<DefaultConstructibleView>>);
67 static_assert(HasEnd<std::ranges::as_rvalue_view<NonConstView>>);
68 static_assert(!HasEnd<const std::ranges::as_rvalue_view<NonConstView>>);
69 
70 static_assert(std::is_same_v<decltype(std::declval<std::ranges::as_rvalue_view<DefaultConstructibleView>>().end()),
71                              std::move_iterator<int*>>);
72 static_assert(std::is_same_v<decltype(std::declval<const std::ranges::as_rvalue_view<NonConstCommonRange>>().end()),
73                              std::move_sentinel<sentinel_wrapper<int*>>>);
74 
75 template <class Iter, class Sent, bool is_common>
test_range()76 constexpr void test_range() {
77   using Expected = std::conditional_t<is_common, std::move_iterator<Sent>, std::move_sentinel<Sent>>;
78   int a[]        = {1, 2};
79   std::ranges::subrange range(Iter(std::begin(a)), Sent(Iter(std::end(a))));
80   std::ranges::as_rvalue_view view(std::move(range));
81   std::same_as<Expected> decltype(auto) iter = view.end();
82   assert(base(base(iter.base())) == std::end(a));
83 }
84 
85 template <class Iter, class Sent>
86 class WrapRange {
87   Iter iter_;
88   Sent sent_;
89 
90 public:
WrapRange(Iter iter,Sent sent)91   constexpr WrapRange(Iter iter, Sent sent) : iter_(std::move(iter)), sent_(std::move(sent)) {}
92 
begin() const93   constexpr Iter begin() const { return iter_; }
end() const94   constexpr Sent end() const { return sent_; }
95 };
96 
97 template <class Iter, class Sent>
98 WrapRange(Iter, Sent) -> WrapRange<Iter, Sent>;
99 
100 template <class Iter, class Sent, bool is_common>
test_const_range()101 constexpr void test_const_range() {
102   using Expected = std::conditional_t<is_common, std::move_iterator<Sent>, std::move_sentinel<Sent>>;
103   int a[]        = {1, 2};
104   auto range = WrapRange{Iter(a), Sent(Iter(a + 2))};
105   const std::ranges::as_rvalue_view view(std::move(range));
106   std::same_as<Expected> decltype(auto) iter = view.end();
107   assert(base(base(iter.base())) == std::end(a));
108 }
109 
110 struct move_iterator_view : std::ranges::view_base {
beginmove_iterator_view111   constexpr std::move_iterator<int*> begin() const { return {}; }
endmove_iterator_view112   constexpr std::move_iterator<int*> end() const { return {}; }
113 };
114 
test()115 constexpr bool test() {
116   test_range<cpp17_input_iterator<int*>, sentinel_wrapper<cpp17_input_iterator<int*>>, false>();
117   test_range<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>, false>();
118   test_range<cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>, false>();
119   test_range<cpp20_input_iterator<int*>, sized_sentinel<cpp20_input_iterator<int*>>, false>();
120 
121   types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {
122     test_range<Iter, Iter, true>();
123     test_range<Iter, sentinel_wrapper<Iter>, false>();
124     test_range<Iter, sized_sentinel<Iter>, false>();
125   });
126 
127   {
128     std::ranges::as_rvalue_view view(CVCallView{});
129     (void)view.end();
130     assert(view.base().const_called);
131   }
132 
133   { // check that with a std::move_iterator begin() doesn't return move_iterator<move_iterator<T>>
134     std::ranges::as_rvalue_view view{move_iterator_view{}};
135     std::same_as<std::move_iterator<int*>> decltype(auto) it = view.end();
136     assert(it == std::move_iterator<int*>{});
137   }
138 
139   return true;
140 }
141 
main(int,char **)142 int main(int, char**) {
143   test();
144 
145 // gcc cannot have mutable member in constant expression
146 #if !defined(TEST_COMPILER_GCC)
147   static_assert(test());
148 #endif
149 
150   return 0;
151 }
152