1*8200e125SKonstantin Varlamov //===----------------------------------------------------------------------===//
2*8200e125SKonstantin Varlamov //
3*8200e125SKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*8200e125SKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
5*8200e125SKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*8200e125SKonstantin Varlamov //
7*8200e125SKonstantin Varlamov //===----------------------------------------------------------------------===//
8*8200e125SKonstantin Varlamov 
9*8200e125SKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
10*8200e125SKonstantin Varlamov // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11*8200e125SKonstantin Varlamov 
12*8200e125SKonstantin Varlamov // std::views::drop
13*8200e125SKonstantin Varlamov 
14*8200e125SKonstantin Varlamov #include <ranges>
15*8200e125SKonstantin Varlamov 
16*8200e125SKonstantin Varlamov #include <array>
17*8200e125SKonstantin Varlamov #include <cassert>
18*8200e125SKonstantin Varlamov #include <concepts>
19*8200e125SKonstantin Varlamov #include <span>
20*8200e125SKonstantin Varlamov #include <string_view>
21*8200e125SKonstantin Varlamov #include <utility>
22*8200e125SKonstantin Varlamov #include "test_iterators.h"
23*8200e125SKonstantin Varlamov 
24*8200e125SKonstantin Varlamov template <class View, class T>
25*8200e125SKonstantin Varlamov concept CanBePiped = requires (View&& view, T&& t) {
26*8200e125SKonstantin Varlamov   { std::forward<View>(view) | std::forward<T>(t) };
27*8200e125SKonstantin Varlamov };
28*8200e125SKonstantin Varlamov 
29*8200e125SKonstantin Varlamov struct SizedView : std::ranges::view_base {
30*8200e125SKonstantin Varlamov   int* begin_ = nullptr;
31*8200e125SKonstantin Varlamov   int* end_ = nullptr;
SizedViewSizedView32*8200e125SKonstantin Varlamov   constexpr SizedView(int* begin, int* end) : begin_(begin), end_(end) {}
33*8200e125SKonstantin Varlamov 
beginSizedView34*8200e125SKonstantin Varlamov   constexpr auto begin() const { return forward_iterator<int*>(begin_); }
endSizedView35*8200e125SKonstantin Varlamov   constexpr auto end() const { return sized_sentinel<forward_iterator<int*>>(forward_iterator<int*>(end_)); }
36*8200e125SKonstantin Varlamov };
37*8200e125SKonstantin Varlamov static_assert(std::ranges::forward_range<SizedView>);
38*8200e125SKonstantin Varlamov static_assert(std::ranges::sized_range<SizedView>);
39*8200e125SKonstantin Varlamov static_assert(std::ranges::view<SizedView>);
40*8200e125SKonstantin Varlamov 
41*8200e125SKonstantin Varlamov struct SizedViewWithUnsizedSentinel : std::ranges::view_base {
42*8200e125SKonstantin Varlamov   using iterator = random_access_iterator<int*>;
43*8200e125SKonstantin Varlamov   using sentinel = sentinel_wrapper<random_access_iterator<int*>>;
44*8200e125SKonstantin Varlamov 
45*8200e125SKonstantin Varlamov   int* begin_ = nullptr;
46*8200e125SKonstantin Varlamov   int* end_ = nullptr;
SizedViewWithUnsizedSentinelSizedViewWithUnsizedSentinel47*8200e125SKonstantin Varlamov   constexpr SizedViewWithUnsizedSentinel(int* begin, int* end) : begin_(begin), end_(end) {}
48*8200e125SKonstantin Varlamov 
beginSizedViewWithUnsizedSentinel49*8200e125SKonstantin Varlamov   constexpr auto begin() const { return iterator(begin_); }
endSizedViewWithUnsizedSentinel50*8200e125SKonstantin Varlamov   constexpr auto end() const { return sentinel(iterator(end_)); }
sizeSizedViewWithUnsizedSentinel51*8200e125SKonstantin Varlamov   constexpr size_t size() const { return end_ - begin_; }
52*8200e125SKonstantin Varlamov };
53*8200e125SKonstantin Varlamov static_assert(std::ranges::random_access_range<SizedViewWithUnsizedSentinel>);
54*8200e125SKonstantin Varlamov static_assert(std::ranges::sized_range<SizedViewWithUnsizedSentinel>);
55*8200e125SKonstantin Varlamov static_assert(!std::sized_sentinel_for<SizedViewWithUnsizedSentinel::sentinel, SizedViewWithUnsizedSentinel::iterator>);
56*8200e125SKonstantin Varlamov static_assert(std::ranges::view<SizedViewWithUnsizedSentinel>);
57*8200e125SKonstantin Varlamov 
58*8200e125SKonstantin Varlamov template <class T>
test_small_range(const T & input)59*8200e125SKonstantin Varlamov constexpr void test_small_range(const T& input) {
60*8200e125SKonstantin Varlamov   constexpr int N = 100;
61*8200e125SKonstantin Varlamov   auto size = std::ranges::size(input);
62*8200e125SKonstantin Varlamov   assert(size < N);
63*8200e125SKonstantin Varlamov 
64*8200e125SKonstantin Varlamov   auto result = input | std::views::drop(N);
65*8200e125SKonstantin Varlamov   assert(result.empty());
66*8200e125SKonstantin Varlamov }
67*8200e125SKonstantin Varlamov 
test()68*8200e125SKonstantin Varlamov constexpr bool test() {
69*8200e125SKonstantin Varlamov   constexpr int N = 8;
70*8200e125SKonstantin Varlamov   int buf[N] = {1, 2, 3, 4, 5, 6, 7, 8};
71*8200e125SKonstantin Varlamov 
72*8200e125SKonstantin Varlamov   // Test that `std::views::drop` is a range adaptor.
73*8200e125SKonstantin Varlamov   {
74*8200e125SKonstantin Varlamov     using SomeView = SizedView;
75*8200e125SKonstantin Varlamov 
76*8200e125SKonstantin Varlamov     // Test `view | views::drop`
77*8200e125SKonstantin Varlamov     {
78*8200e125SKonstantin Varlamov       SomeView view(buf, buf + N);
79*8200e125SKonstantin Varlamov       std::same_as<std::ranges::drop_view<SomeView>> decltype(auto) result = view | std::views::drop(3);
80*8200e125SKonstantin Varlamov       assert(result.base().begin_ == buf);
81*8200e125SKonstantin Varlamov       assert(result.base().end_ == buf + N);
82*8200e125SKonstantin Varlamov       assert(base(result.begin()) == buf + 3);
83*8200e125SKonstantin Varlamov       assert(base(base(result.end())) == buf + N);
84*8200e125SKonstantin Varlamov       assert(result.size() == 5);
85*8200e125SKonstantin Varlamov     }
86*8200e125SKonstantin Varlamov 
87*8200e125SKonstantin Varlamov     // Test `adaptor | views::drop`
88*8200e125SKonstantin Varlamov     {
89*8200e125SKonstantin Varlamov       SomeView view(buf, buf + N);
90*8200e125SKonstantin Varlamov       auto f = [](int i) { return i; };
91*8200e125SKonstantin Varlamov       auto const partial = std::views::transform(f) | std::views::drop(3);
92*8200e125SKonstantin Varlamov 
93*8200e125SKonstantin Varlamov       using Result = std::ranges::drop_view<std::ranges::transform_view<SomeView, decltype(f)>>;
94*8200e125SKonstantin Varlamov       std::same_as<Result> decltype(auto) result = partial(view);
95*8200e125SKonstantin Varlamov       assert(result.base().base().begin_ == buf);
96*8200e125SKonstantin Varlamov       assert(result.base().base().end_ == buf + N);
97*8200e125SKonstantin Varlamov       assert(base(result.begin().base()) == buf + 3);
98*8200e125SKonstantin Varlamov       assert(base(base(result.end().base())) == buf + N);
99*8200e125SKonstantin Varlamov       assert(result.size() == 5);
100*8200e125SKonstantin Varlamov     }
101*8200e125SKonstantin Varlamov 
102*8200e125SKonstantin Varlamov     // Test `views::drop | adaptor`
103*8200e125SKonstantin Varlamov     {
104*8200e125SKonstantin Varlamov       SomeView view(buf, buf + N);
105*8200e125SKonstantin Varlamov       auto f = [](int i) { return i; };
106*8200e125SKonstantin Varlamov       auto const partial = std::views::drop(3) | std::views::transform(f);
107*8200e125SKonstantin Varlamov 
108*8200e125SKonstantin Varlamov       using Result = std::ranges::transform_view<std::ranges::drop_view<SomeView>, decltype(f)>;
109*8200e125SKonstantin Varlamov       std::same_as<Result> decltype(auto) result = partial(view);
110*8200e125SKonstantin Varlamov       assert(result.base().base().begin_ == buf);
111*8200e125SKonstantin Varlamov       assert(result.base().base().end_ == buf + N);
112*8200e125SKonstantin Varlamov       assert(base(result.begin().base()) == buf + 3);
113*8200e125SKonstantin Varlamov       assert(base(base(result.end().base())) == buf + N);
114*8200e125SKonstantin Varlamov       assert(result.size() == 5);
115*8200e125SKonstantin Varlamov     }
116*8200e125SKonstantin Varlamov 
117*8200e125SKonstantin Varlamov     // Check SFINAE friendliness
118*8200e125SKonstantin Varlamov     {
119*8200e125SKonstantin Varlamov       struct NotAView { };
120*8200e125SKonstantin Varlamov       static_assert(!std::is_invocable_v<decltype(std::views::drop)>);
121*8200e125SKonstantin Varlamov       static_assert(!std::is_invocable_v<decltype(std::views::drop), NotAView, int>);
122*8200e125SKonstantin Varlamov       static_assert( CanBePiped<SomeView&,   decltype(std::views::drop(3))>);
123*8200e125SKonstantin Varlamov       static_assert( CanBePiped<int(&)[10],  decltype(std::views::drop(3))>);
124*8200e125SKonstantin Varlamov       static_assert(!CanBePiped<int(&&)[10], decltype(std::views::drop(3))>);
125*8200e125SKonstantin Varlamov       static_assert(!CanBePiped<NotAView,    decltype(std::views::drop(3))>);
126*8200e125SKonstantin Varlamov 
127*8200e125SKonstantin Varlamov       static_assert(!CanBePiped<SomeView&,   decltype(std::views::drop(/*n=*/NotAView{}))>);
128*8200e125SKonstantin Varlamov     }
129*8200e125SKonstantin Varlamov   }
130*8200e125SKonstantin Varlamov 
131*8200e125SKonstantin Varlamov   {
132*8200e125SKonstantin Varlamov     static_assert(std::same_as<decltype(std::views::drop), decltype(std::ranges::views::drop)>);
133*8200e125SKonstantin Varlamov   }
134*8200e125SKonstantin Varlamov 
135*8200e125SKonstantin Varlamov   // `views::drop(empty_view, n)` returns an `empty_view`.
136*8200e125SKonstantin Varlamov   {
137*8200e125SKonstantin Varlamov     using Result = std::ranges::empty_view<int>;
138*8200e125SKonstantin Varlamov     [[maybe_unused]] std::same_as<Result> decltype(auto) result = std::views::empty<int> | std::views::drop(3);
139*8200e125SKonstantin Varlamov   }
140*8200e125SKonstantin Varlamov 
141*8200e125SKonstantin Varlamov   // `views::drop(span, n)` returns a `span`.
142*8200e125SKonstantin Varlamov   {
143*8200e125SKonstantin Varlamov     std::span<int> s(buf);
144*8200e125SKonstantin Varlamov     std::same_as<decltype(s)> decltype(auto) result = s | std::views::drop(5);
145*8200e125SKonstantin Varlamov     assert(result.size() == 3);
146*8200e125SKonstantin Varlamov   }
147*8200e125SKonstantin Varlamov 
148*8200e125SKonstantin Varlamov   // `views::drop(span, n)` returns a `span` with a dynamic extent, regardless of the input `span`.
149*8200e125SKonstantin Varlamov   {
150*8200e125SKonstantin Varlamov     std::span<int, 8> s(buf);
151*8200e125SKonstantin Varlamov     std::same_as<std::span<int, std::dynamic_extent>> decltype(auto) result = s | std::views::drop(3);
152*8200e125SKonstantin Varlamov     assert(result.size() == 5);
153*8200e125SKonstantin Varlamov   }
154*8200e125SKonstantin Varlamov 
155*8200e125SKonstantin Varlamov   // `views::drop(string_view, n)` returns a `string_view`.
156*8200e125SKonstantin Varlamov   {
157*8200e125SKonstantin Varlamov     {
158*8200e125SKonstantin Varlamov       std::string_view sv = "abcdef";
159*8200e125SKonstantin Varlamov       std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::drop(2);
160*8200e125SKonstantin Varlamov       assert(result.size() == 4);
161*8200e125SKonstantin Varlamov     }
162*8200e125SKonstantin Varlamov 
163*8200e125SKonstantin Varlamov     {
164*8200e125SKonstantin Varlamov       std::u32string_view sv = U"abcdef";
165*8200e125SKonstantin Varlamov       std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::drop(2);
166*8200e125SKonstantin Varlamov       assert(result.size() == 4);
167*8200e125SKonstantin Varlamov     }
168*8200e125SKonstantin Varlamov   }
169*8200e125SKonstantin Varlamov 
170*8200e125SKonstantin Varlamov   // `views::drop(iota_view, n)` returns an `iota_view`.
171*8200e125SKonstantin Varlamov   {
172*8200e125SKonstantin Varlamov     auto iota = std::views::iota(1, 8);
173*8200e125SKonstantin Varlamov     // The second template argument of the resulting `iota_view` is different because it has to be able to hold
174*8200e125SKonstantin Varlamov     // the `range_difference_t` of the input `iota_view`.
175*8200e125SKonstantin Varlamov     using Result = std::ranges::iota_view<int, int>;
176*8200e125SKonstantin Varlamov     std::same_as<Result> decltype(auto) result = iota | std::views::drop(3);
177*8200e125SKonstantin Varlamov     assert(result.size() == 4);
178*8200e125SKonstantin Varlamov     assert(*result.begin() == 4);
179*8200e125SKonstantin Varlamov     assert(*std::ranges::next(result.begin(), 3) == 7);
180*8200e125SKonstantin Varlamov   }
181*8200e125SKonstantin Varlamov 
182*8200e125SKonstantin Varlamov   // `views::drop(subrange, n)` returns a `subrange` when `subrange::StoreSize == false`.
183*8200e125SKonstantin Varlamov   {
184*8200e125SKonstantin Varlamov     auto subrange = std::ranges::subrange(buf, buf + N);
185*8200e125SKonstantin Varlamov     LIBCPP_STATIC_ASSERT(!decltype(subrange)::_StoreSize);
186*8200e125SKonstantin Varlamov 
187*8200e125SKonstantin Varlamov     using Result = std::ranges::subrange<int*>;
188*8200e125SKonstantin Varlamov     std::same_as<Result> decltype(auto) result = subrange | std::views::drop(3);
189*8200e125SKonstantin Varlamov     assert(result.size() == 5);
190*8200e125SKonstantin Varlamov   }
191*8200e125SKonstantin Varlamov 
192*8200e125SKonstantin Varlamov   // `views::drop(subrange, n)` returns a `subrange` when `subrange::StoreSize == true`.
193*8200e125SKonstantin Varlamov   {
194*8200e125SKonstantin Varlamov     using View = SizedViewWithUnsizedSentinel;
195*8200e125SKonstantin Varlamov     View view(buf, buf + N);
196*8200e125SKonstantin Varlamov 
197*8200e125SKonstantin Varlamov     using Subrange = std::ranges::subrange<View::iterator, View::sentinel, std::ranges::subrange_kind::sized>;
198*8200e125SKonstantin Varlamov     auto subrange = Subrange(view.begin(), view.end(), std::ranges::distance(view.begin(), view.end()));
199*8200e125SKonstantin Varlamov     LIBCPP_STATIC_ASSERT(decltype(subrange)::_StoreSize);
200*8200e125SKonstantin Varlamov 
201*8200e125SKonstantin Varlamov     std::same_as<Subrange> decltype(auto) result = subrange | std::views::drop(3);
202*8200e125SKonstantin Varlamov     assert(result.size() == 5);
203*8200e125SKonstantin Varlamov   }
204*8200e125SKonstantin Varlamov 
205*8200e125SKonstantin Varlamov   // `views::drop(subrange, n)` doesn't return a `subrange` if it's not a random access range.
206*8200e125SKonstantin Varlamov   {
207*8200e125SKonstantin Varlamov     SizedView v(buf, buf + N);
208*8200e125SKonstantin Varlamov     auto subrange = std::ranges::subrange(v.begin(), v.end());
209*8200e125SKonstantin Varlamov 
210*8200e125SKonstantin Varlamov     using Result = std::ranges::drop_view<std::ranges::subrange<forward_iterator<int*>,
211*8200e125SKonstantin Varlamov         sized_sentinel<forward_iterator<int*>>>>;
212*8200e125SKonstantin Varlamov     std::same_as<Result> decltype(auto) result = subrange | std::views::drop(3);
213*8200e125SKonstantin Varlamov     assert(result.size() == 5);
214*8200e125SKonstantin Varlamov   }
215*8200e125SKonstantin Varlamov 
216*8200e125SKonstantin Varlamov   // When the size of the input range `s` is shorter than `n`, an `empty_view` is returned.
217*8200e125SKonstantin Varlamov   {
218*8200e125SKonstantin Varlamov     test_small_range(std::span(buf));
219*8200e125SKonstantin Varlamov     test_small_range(std::string_view("abcdef"));
220*8200e125SKonstantin Varlamov     test_small_range(std::ranges::subrange(buf, buf + N));
221*8200e125SKonstantin Varlamov     test_small_range(std::views::iota(1, 8));
222*8200e125SKonstantin Varlamov   }
223*8200e125SKonstantin Varlamov 
224*8200e125SKonstantin Varlamov   // Test that it's possible to call `std::views::drop` with any single argument as long as the resulting closure is
225*8200e125SKonstantin Varlamov   // never invoked. There is no good use case for it, but it's valid.
226*8200e125SKonstantin Varlamov   {
227*8200e125SKonstantin Varlamov     struct X { };
228*8200e125SKonstantin Varlamov     [[maybe_unused]] auto partial = std::views::drop(X{});
229*8200e125SKonstantin Varlamov   }
230*8200e125SKonstantin Varlamov 
231*8200e125SKonstantin Varlamov   return true;
232*8200e125SKonstantin Varlamov }
233*8200e125SKonstantin Varlamov 
main(int,char **)234*8200e125SKonstantin Varlamov int main(int, char**) {
235*8200e125SKonstantin Varlamov   test();
236*8200e125SKonstantin Varlamov   static_assert(test());
237*8200e125SKonstantin Varlamov 
238*8200e125SKonstantin Varlamov   return 0;
239*8200e125SKonstantin Varlamov }
240