xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.take/adaptor.pass.cpp (revision ba2236d3000645d3127f972aa7ac1844c47e299c)
19924d8d6SKonstantin Varlamov //===----------------------------------------------------------------------===//
29924d8d6SKonstantin Varlamov //
39924d8d6SKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49924d8d6SKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
59924d8d6SKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69924d8d6SKonstantin Varlamov //
79924d8d6SKonstantin Varlamov //===----------------------------------------------------------------------===//
89924d8d6SKonstantin Varlamov 
99924d8d6SKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
109924d8d6SKonstantin Varlamov 
119924d8d6SKonstantin Varlamov // std::views::take
129924d8d6SKonstantin Varlamov 
139924d8d6SKonstantin Varlamov #include <ranges>
149924d8d6SKonstantin Varlamov 
159924d8d6SKonstantin Varlamov #include <cassert>
169924d8d6SKonstantin Varlamov #include <concepts>
178200e125SKonstantin Varlamov #include <span>
189924d8d6SKonstantin Varlamov #include <string_view>
199924d8d6SKonstantin Varlamov #include <utility>
209924d8d6SKonstantin Varlamov 
21*ba2236d3SWill Hawkins #include "test_iterators.h"
22*ba2236d3SWill Hawkins #include "test_range.h"
239924d8d6SKonstantin Varlamov 
249924d8d6SKonstantin Varlamov struct SizedView : std::ranges::view_base {
259924d8d6SKonstantin Varlamov   int* begin_ = nullptr;
269924d8d6SKonstantin Varlamov   int* end_ = nullptr;
SizedViewSizedView279924d8d6SKonstantin Varlamov   constexpr SizedView(int* begin, int* end) : begin_(begin), end_(end) {}
289924d8d6SKonstantin Varlamov 
beginSizedView299924d8d6SKonstantin Varlamov   constexpr auto begin() const { return forward_iterator<int*>(begin_); }
endSizedView309924d8d6SKonstantin Varlamov   constexpr auto end() const { return sized_sentinel<forward_iterator<int*>>(forward_iterator<int*>(end_)); }
319924d8d6SKonstantin Varlamov };
329924d8d6SKonstantin Varlamov static_assert(std::ranges::forward_range<SizedView>);
339924d8d6SKonstantin Varlamov static_assert(std::ranges::sized_range<SizedView>);
349924d8d6SKonstantin Varlamov static_assert(std::ranges::view<SizedView>);
359924d8d6SKonstantin Varlamov 
369924d8d6SKonstantin Varlamov template <class T>
test_small_range(const T & input)379924d8d6SKonstantin Varlamov constexpr void test_small_range(const T& input) {
389924d8d6SKonstantin Varlamov   constexpr int N = 100;
399924d8d6SKonstantin Varlamov   auto size = std::ranges::size(input);
409924d8d6SKonstantin Varlamov 
419924d8d6SKonstantin Varlamov   auto result = input | std::views::take(N);
429924d8d6SKonstantin Varlamov   assert(size < N);
439924d8d6SKonstantin Varlamov   assert(result.size() == size);
449924d8d6SKonstantin Varlamov }
459924d8d6SKonstantin Varlamov 
test()469924d8d6SKonstantin Varlamov constexpr bool test() {
479924d8d6SKonstantin Varlamov   constexpr int N = 8;
489924d8d6SKonstantin Varlamov   int buf[N] = {1, 2, 3, 4, 5, 6, 7, 8};
499924d8d6SKonstantin Varlamov 
509924d8d6SKonstantin Varlamov   // Test that `std::views::take` is a range adaptor.
519924d8d6SKonstantin Varlamov   {
529924d8d6SKonstantin Varlamov     using SomeView = SizedView;
539924d8d6SKonstantin Varlamov 
549924d8d6SKonstantin Varlamov     // Test `view | views::take`
559924d8d6SKonstantin Varlamov     {
569924d8d6SKonstantin Varlamov       SomeView view(buf, buf + N);
579924d8d6SKonstantin Varlamov       std::same_as<std::ranges::take_view<SomeView>> decltype(auto) result = view | std::views::take(3);
589924d8d6SKonstantin Varlamov       assert(result.base().begin_ == buf);
599924d8d6SKonstantin Varlamov       assert(result.base().end_ == buf + N);
609924d8d6SKonstantin Varlamov       assert(result.size() == 3);
619924d8d6SKonstantin Varlamov     }
629924d8d6SKonstantin Varlamov 
639924d8d6SKonstantin Varlamov     // Test `adaptor | views::take`
649924d8d6SKonstantin Varlamov     {
659924d8d6SKonstantin Varlamov       SomeView view(buf, buf + N);
669924d8d6SKonstantin Varlamov       auto f = [](int i) { return i; };
679924d8d6SKonstantin Varlamov       auto const partial = std::views::transform(f) | std::views::take(3);
689924d8d6SKonstantin Varlamov 
699924d8d6SKonstantin Varlamov       using Result = std::ranges::take_view<std::ranges::transform_view<SomeView, decltype(f)>>;
709924d8d6SKonstantin Varlamov       std::same_as<Result> decltype(auto) result = partial(view);
719924d8d6SKonstantin Varlamov       assert(result.base().base().begin_ == buf);
729924d8d6SKonstantin Varlamov       assert(result.base().base().end_ == buf + N);
739924d8d6SKonstantin Varlamov       assert(result.size() == 3);
749924d8d6SKonstantin Varlamov     }
759924d8d6SKonstantin Varlamov 
769924d8d6SKonstantin Varlamov     // Test `views::take | adaptor`
779924d8d6SKonstantin Varlamov     {
789924d8d6SKonstantin Varlamov       SomeView view(buf, buf + N);
799924d8d6SKonstantin Varlamov       auto f = [](int i) { return i; };
809924d8d6SKonstantin Varlamov       auto const partial = std::views::take(3) | std::views::transform(f);
819924d8d6SKonstantin Varlamov 
829924d8d6SKonstantin Varlamov       using Result = std::ranges::transform_view<std::ranges::take_view<SomeView>, decltype(f)>;
839924d8d6SKonstantin Varlamov       std::same_as<Result> decltype(auto) result = partial(view);
849924d8d6SKonstantin Varlamov       assert(result.base().base().begin_ == buf);
859924d8d6SKonstantin Varlamov       assert(result.base().base().end_ == buf + N);
869924d8d6SKonstantin Varlamov       assert(result.size() == 3);
879924d8d6SKonstantin Varlamov     }
889924d8d6SKonstantin Varlamov 
899924d8d6SKonstantin Varlamov     // Check SFINAE friendliness
909924d8d6SKonstantin Varlamov     {
919924d8d6SKonstantin Varlamov       struct NotAView { };
929924d8d6SKonstantin Varlamov       static_assert(!std::is_invocable_v<decltype(std::views::take)>);
939924d8d6SKonstantin Varlamov       static_assert(!std::is_invocable_v<decltype(std::views::take), NotAView, int>);
949924d8d6SKonstantin Varlamov       static_assert( CanBePiped<SomeView&,   decltype(std::views::take(3))>);
959924d8d6SKonstantin Varlamov       static_assert( CanBePiped<int(&)[10],  decltype(std::views::take(3))>);
969924d8d6SKonstantin Varlamov       static_assert(!CanBePiped<int(&&)[10], decltype(std::views::take(3))>);
979924d8d6SKonstantin Varlamov       static_assert(!CanBePiped<NotAView,    decltype(std::views::take(3))>);
989924d8d6SKonstantin Varlamov 
999924d8d6SKonstantin Varlamov       static_assert(!CanBePiped<SomeView&,   decltype(std::views::take(/*n=*/NotAView{}))>);
1009924d8d6SKonstantin Varlamov     }
1019924d8d6SKonstantin Varlamov   }
1029924d8d6SKonstantin Varlamov 
1039924d8d6SKonstantin Varlamov   {
1049924d8d6SKonstantin Varlamov     static_assert(std::same_as<decltype(std::views::take), decltype(std::ranges::views::take)>);
1059924d8d6SKonstantin Varlamov   }
1069924d8d6SKonstantin Varlamov 
1079924d8d6SKonstantin Varlamov   // `views::take(empty_view, n)` returns an `empty_view`.
1089924d8d6SKonstantin Varlamov   {
1099924d8d6SKonstantin Varlamov     using Result = std::ranges::empty_view<int>;
1109924d8d6SKonstantin Varlamov     [[maybe_unused]] std::same_as<Result> decltype(auto) result = std::views::empty<int> | std::views::take(3);
1119924d8d6SKonstantin Varlamov   }
1129924d8d6SKonstantin Varlamov 
1139924d8d6SKonstantin Varlamov   // `views::take(span, n)` returns a `span`.
1149924d8d6SKonstantin Varlamov   {
1159924d8d6SKonstantin Varlamov     std::span<int> s(buf);
1169924d8d6SKonstantin Varlamov     std::same_as<decltype(s)> decltype(auto) result = s | std::views::take(3);
1179924d8d6SKonstantin Varlamov     assert(result.size() == 3);
1189924d8d6SKonstantin Varlamov   }
1199924d8d6SKonstantin Varlamov 
1209924d8d6SKonstantin Varlamov   // `views::take(span, n)` returns a `span` with a dynamic extent, regardless of the input `span`.
1219924d8d6SKonstantin Varlamov   {
1229924d8d6SKonstantin Varlamov     std::span<int, 8> s(buf);
1239924d8d6SKonstantin Varlamov     std::same_as<std::span<int, std::dynamic_extent>> decltype(auto) result = s | std::views::take(3);
1249924d8d6SKonstantin Varlamov     assert(result.size() == 3);
1259924d8d6SKonstantin Varlamov   }
1269924d8d6SKonstantin Varlamov 
1279924d8d6SKonstantin Varlamov   // `views::take(string_view, n)` returns a `string_view`.
1289924d8d6SKonstantin Varlamov   {
1299924d8d6SKonstantin Varlamov     {
1309924d8d6SKonstantin Varlamov       std::string_view sv = "abcdef";
1319924d8d6SKonstantin Varlamov       std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);
1329924d8d6SKonstantin Varlamov       assert(result.size() == 3);
1339924d8d6SKonstantin Varlamov     }
1349924d8d6SKonstantin Varlamov 
1359924d8d6SKonstantin Varlamov     {
1369924d8d6SKonstantin Varlamov       std::u32string_view sv = U"abcdef";
1379924d8d6SKonstantin Varlamov       std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);
1389924d8d6SKonstantin Varlamov       assert(result.size() == 3);
1399924d8d6SKonstantin Varlamov     }
1409924d8d6SKonstantin Varlamov   }
1419924d8d6SKonstantin Varlamov 
1429924d8d6SKonstantin Varlamov   // `views::take(subrange, n)` returns a `subrange`.
1439924d8d6SKonstantin Varlamov   {
1449924d8d6SKonstantin Varlamov     auto subrange = std::ranges::subrange(buf, buf + N);
1459924d8d6SKonstantin Varlamov     using Result = std::ranges::subrange<int*>;
1469924d8d6SKonstantin Varlamov     std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
1479924d8d6SKonstantin Varlamov     assert(result.size() == 3);
1489924d8d6SKonstantin Varlamov   }
1499924d8d6SKonstantin Varlamov 
1509924d8d6SKonstantin Varlamov   // `views::take(subrange, n)` doesn't return a `subrange` if it's not a random access range.
1519924d8d6SKonstantin Varlamov   {
1529924d8d6SKonstantin Varlamov     SizedView v(buf, buf + N);
1539924d8d6SKonstantin Varlamov     auto subrange = std::ranges::subrange(v.begin(), v.end());
1549924d8d6SKonstantin Varlamov 
1559924d8d6SKonstantin Varlamov     using Result = std::ranges::take_view<std::ranges::subrange<forward_iterator<int*>,
1569924d8d6SKonstantin Varlamov         sized_sentinel<forward_iterator<int*>>>>;
1579924d8d6SKonstantin Varlamov     std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
1589924d8d6SKonstantin Varlamov     assert(result.size() == 3);
1599924d8d6SKonstantin Varlamov   }
1609924d8d6SKonstantin Varlamov 
1619924d8d6SKonstantin Varlamov   // `views::take(subrange, n)` returns a `subrange` with all default template arguments.
1629924d8d6SKonstantin Varlamov   {
1639924d8d6SKonstantin Varlamov     std::ranges::subrange<int*, sized_sentinel<int*>, std::ranges::subrange_kind::sized> subrange;
1649924d8d6SKonstantin Varlamov 
1659924d8d6SKonstantin Varlamov     using Result = std::ranges::subrange<int*, int*, std::ranges::subrange_kind::sized>;
1669924d8d6SKonstantin Varlamov     [[maybe_unused]] std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
1679924d8d6SKonstantin Varlamov   }
1689924d8d6SKonstantin Varlamov 
1699924d8d6SKonstantin Varlamov   // `views::take(iota_view, n)` returns an `iota_view`.
1709924d8d6SKonstantin Varlamov   {
1719924d8d6SKonstantin Varlamov     auto iota = std::views::iota(1, 8);
1721821bc1eSA. Jiang     // The second template argument of the resulting `iota_view` is same as the first.
1731821bc1eSA. Jiang     using Result                               = std::ranges::iota_view<int, int>;
1749924d8d6SKonstantin Varlamov     std::same_as<Result> decltype(auto) result = iota | std::views::take(3);
1759924d8d6SKonstantin Varlamov     assert(result.size() == 3);
1769924d8d6SKonstantin Varlamov   }
1779924d8d6SKonstantin Varlamov 
178a2160dd3Syrong #if TEST_STD_VER >= 23
179a2160dd3Syrong   // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` models `sized_range`.
180a2160dd3Syrong   {
181a2160dd3Syrong     auto repeat                                = std::ranges::repeat_view<int, int>(1, 8);
182a2160dd3Syrong     using Result                               = std::ranges::repeat_view<int, int>;
183a2160dd3Syrong     std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);
184a2160dd3Syrong     static_assert(std::ranges::sized_range<Result>);
185a2160dd3Syrong     assert(result.size() == 3);
186a2160dd3Syrong     assert(*result.begin() == 1);
187a2160dd3Syrong   }
188a2160dd3Syrong 
189a2160dd3Syrong   // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` doesn't model `sized_range`.
190a2160dd3Syrong   {
191a2160dd3Syrong     auto repeat  = std::ranges::repeat_view<int>(1);
192a2160dd3Syrong     using Result = std::ranges::repeat_view<int, std::ranges::range_difference_t<decltype(repeat)>>;
193a2160dd3Syrong     std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);
194a2160dd3Syrong     assert(result.size() == 3);
195a2160dd3Syrong     assert(*result.begin() == 1);
196a2160dd3Syrong   }
197a2160dd3Syrong #endif
198a2160dd3Syrong 
1999924d8d6SKonstantin Varlamov   // When the size of the input range `s` is shorter than `n`, only `s` elements are taken.
2009924d8d6SKonstantin Varlamov   {
2019924d8d6SKonstantin Varlamov     test_small_range(std::span(buf));
2029924d8d6SKonstantin Varlamov     test_small_range(std::string_view("abcdef"));
2039924d8d6SKonstantin Varlamov     test_small_range(std::ranges::subrange(buf, buf + N));
2049924d8d6SKonstantin Varlamov     test_small_range(std::views::iota(1, 8));
2059924d8d6SKonstantin Varlamov   }
2069924d8d6SKonstantin Varlamov 
2079924d8d6SKonstantin Varlamov   // Test that it's possible to call `std::views::take` with any single argument as long as the resulting closure is
2089924d8d6SKonstantin Varlamov   // never invoked. There is no good use case for it, but it's valid.
2099924d8d6SKonstantin Varlamov   {
2109924d8d6SKonstantin Varlamov     struct X { };
2119924d8d6SKonstantin Varlamov     [[maybe_unused]] auto partial = std::views::take(X{});
2129924d8d6SKonstantin Varlamov   }
2139924d8d6SKonstantin Varlamov 
2144851fbc3SHui Xie   // Test when `subrange<Iter>` is not well formed
2154851fbc3SHui Xie   {
2164851fbc3SHui Xie     int input[] = {1, 2, 3};
2174851fbc3SHui Xie     using Iter  = cpp20_input_iterator<int*>;
2184851fbc3SHui Xie     using Sent  = sentinel_wrapper<Iter>;
2194851fbc3SHui Xie     std::ranges::subrange r{Iter{input}, Sent{Iter{input + 3}}};
2204851fbc3SHui Xie     auto tv = std::views::take(std::move(r), 1);
2214851fbc3SHui Xie     auto it                  = tv.begin();
2224851fbc3SHui Xie     assert(*it == 1);
2234851fbc3SHui Xie     ++it;
2244851fbc3SHui Xie     assert(it == tv.end());
2254851fbc3SHui Xie   }
2264851fbc3SHui Xie 
2279924d8d6SKonstantin Varlamov   return true;
2289924d8d6SKonstantin Varlamov }
2299924d8d6SKonstantin Varlamov 
main(int,char **)2309924d8d6SKonstantin Varlamov int main(int, char**) {
2319924d8d6SKonstantin Varlamov   test();
2329924d8d6SKonstantin Varlamov   static_assert(test());
2339924d8d6SKonstantin Varlamov 
2349924d8d6SKonstantin Varlamov   return 0;
2359924d8d6SKonstantin Varlamov }
236