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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges
119924d8d6SKonstantin Varlamov
129924d8d6SKonstantin Varlamov // std::views::take
139924d8d6SKonstantin Varlamov
149924d8d6SKonstantin Varlamov #include <ranges>
159924d8d6SKonstantin Varlamov
169924d8d6SKonstantin Varlamov #include <cassert>
179924d8d6SKonstantin Varlamov #include <concepts>
18*8200e125SKonstantin Varlamov #include <span>
199924d8d6SKonstantin Varlamov #include <string_view>
209924d8d6SKonstantin Varlamov #include <utility>
219924d8d6SKonstantin Varlamov #include "test_iterators.h"
229924d8d6SKonstantin Varlamov
239924d8d6SKonstantin Varlamov template <class View, class T>
249924d8d6SKonstantin Varlamov concept CanBePiped = requires (View&& view, T&& t) {
259924d8d6SKonstantin Varlamov { std::forward<View>(view) | std::forward<T>(t) };
269924d8d6SKonstantin Varlamov };
279924d8d6SKonstantin Varlamov
289924d8d6SKonstantin Varlamov struct SizedView : std::ranges::view_base {
299924d8d6SKonstantin Varlamov int* begin_ = nullptr;
309924d8d6SKonstantin Varlamov int* end_ = nullptr;
SizedViewSizedView319924d8d6SKonstantin Varlamov constexpr SizedView(int* begin, int* end) : begin_(begin), end_(end) {}
329924d8d6SKonstantin Varlamov
beginSizedView339924d8d6SKonstantin Varlamov constexpr auto begin() const { return forward_iterator<int*>(begin_); }
endSizedView349924d8d6SKonstantin Varlamov constexpr auto end() const { return sized_sentinel<forward_iterator<int*>>(forward_iterator<int*>(end_)); }
359924d8d6SKonstantin Varlamov };
369924d8d6SKonstantin Varlamov static_assert(std::ranges::forward_range<SizedView>);
379924d8d6SKonstantin Varlamov static_assert(std::ranges::sized_range<SizedView>);
389924d8d6SKonstantin Varlamov static_assert(std::ranges::view<SizedView>);
399924d8d6SKonstantin Varlamov
409924d8d6SKonstantin Varlamov template <class T>
test_small_range(const T & input)419924d8d6SKonstantin Varlamov constexpr void test_small_range(const T& input) {
429924d8d6SKonstantin Varlamov constexpr int N = 100;
439924d8d6SKonstantin Varlamov auto size = std::ranges::size(input);
449924d8d6SKonstantin Varlamov
459924d8d6SKonstantin Varlamov auto result = input | std::views::take(N);
469924d8d6SKonstantin Varlamov assert(size < N);
479924d8d6SKonstantin Varlamov assert(result.size() == size);
489924d8d6SKonstantin Varlamov }
499924d8d6SKonstantin Varlamov
test()509924d8d6SKonstantin Varlamov constexpr bool test() {
519924d8d6SKonstantin Varlamov constexpr int N = 8;
529924d8d6SKonstantin Varlamov int buf[N] = {1, 2, 3, 4, 5, 6, 7, 8};
539924d8d6SKonstantin Varlamov
549924d8d6SKonstantin Varlamov // Test that `std::views::take` is a range adaptor.
559924d8d6SKonstantin Varlamov {
569924d8d6SKonstantin Varlamov using SomeView = SizedView;
579924d8d6SKonstantin Varlamov
589924d8d6SKonstantin Varlamov // Test `view | views::take`
599924d8d6SKonstantin Varlamov {
609924d8d6SKonstantin Varlamov SomeView view(buf, buf + N);
619924d8d6SKonstantin Varlamov std::same_as<std::ranges::take_view<SomeView>> decltype(auto) result = view | std::views::take(3);
629924d8d6SKonstantin Varlamov assert(result.base().begin_ == buf);
639924d8d6SKonstantin Varlamov assert(result.base().end_ == buf + N);
649924d8d6SKonstantin Varlamov assert(result.size() == 3);
659924d8d6SKonstantin Varlamov }
669924d8d6SKonstantin Varlamov
679924d8d6SKonstantin Varlamov // Test `adaptor | views::take`
689924d8d6SKonstantin Varlamov {
699924d8d6SKonstantin Varlamov SomeView view(buf, buf + N);
709924d8d6SKonstantin Varlamov auto f = [](int i) { return i; };
719924d8d6SKonstantin Varlamov auto const partial = std::views::transform(f) | std::views::take(3);
729924d8d6SKonstantin Varlamov
739924d8d6SKonstantin Varlamov using Result = std::ranges::take_view<std::ranges::transform_view<SomeView, decltype(f)>>;
749924d8d6SKonstantin Varlamov std::same_as<Result> decltype(auto) result = partial(view);
759924d8d6SKonstantin Varlamov assert(result.base().base().begin_ == buf);
769924d8d6SKonstantin Varlamov assert(result.base().base().end_ == buf + N);
779924d8d6SKonstantin Varlamov assert(result.size() == 3);
789924d8d6SKonstantin Varlamov }
799924d8d6SKonstantin Varlamov
809924d8d6SKonstantin Varlamov // Test `views::take | adaptor`
819924d8d6SKonstantin Varlamov {
829924d8d6SKonstantin Varlamov SomeView view(buf, buf + N);
839924d8d6SKonstantin Varlamov auto f = [](int i) { return i; };
849924d8d6SKonstantin Varlamov auto const partial = std::views::take(3) | std::views::transform(f);
859924d8d6SKonstantin Varlamov
869924d8d6SKonstantin Varlamov using Result = std::ranges::transform_view<std::ranges::take_view<SomeView>, decltype(f)>;
879924d8d6SKonstantin Varlamov std::same_as<Result> decltype(auto) result = partial(view);
889924d8d6SKonstantin Varlamov assert(result.base().base().begin_ == buf);
899924d8d6SKonstantin Varlamov assert(result.base().base().end_ == buf + N);
909924d8d6SKonstantin Varlamov assert(result.size() == 3);
919924d8d6SKonstantin Varlamov }
929924d8d6SKonstantin Varlamov
939924d8d6SKonstantin Varlamov // Check SFINAE friendliness
949924d8d6SKonstantin Varlamov {
959924d8d6SKonstantin Varlamov struct NotAView { };
969924d8d6SKonstantin Varlamov static_assert(!std::is_invocable_v<decltype(std::views::take)>);
979924d8d6SKonstantin Varlamov static_assert(!std::is_invocable_v<decltype(std::views::take), NotAView, int>);
989924d8d6SKonstantin Varlamov static_assert( CanBePiped<SomeView&, decltype(std::views::take(3))>);
999924d8d6SKonstantin Varlamov static_assert( CanBePiped<int(&)[10], decltype(std::views::take(3))>);
1009924d8d6SKonstantin Varlamov static_assert(!CanBePiped<int(&&)[10], decltype(std::views::take(3))>);
1019924d8d6SKonstantin Varlamov static_assert(!CanBePiped<NotAView, decltype(std::views::take(3))>);
1029924d8d6SKonstantin Varlamov
1039924d8d6SKonstantin Varlamov static_assert(!CanBePiped<SomeView&, decltype(std::views::take(/*n=*/NotAView{}))>);
1049924d8d6SKonstantin Varlamov }
1059924d8d6SKonstantin Varlamov }
1069924d8d6SKonstantin Varlamov
1079924d8d6SKonstantin Varlamov {
1089924d8d6SKonstantin Varlamov static_assert(std::same_as<decltype(std::views::take), decltype(std::ranges::views::take)>);
1099924d8d6SKonstantin Varlamov }
1109924d8d6SKonstantin Varlamov
1119924d8d6SKonstantin Varlamov // `views::take(empty_view, n)` returns an `empty_view`.
1129924d8d6SKonstantin Varlamov {
1139924d8d6SKonstantin Varlamov using Result = std::ranges::empty_view<int>;
1149924d8d6SKonstantin Varlamov [[maybe_unused]] std::same_as<Result> decltype(auto) result = std::views::empty<int> | std::views::take(3);
1159924d8d6SKonstantin Varlamov }
1169924d8d6SKonstantin Varlamov
1179924d8d6SKonstantin Varlamov // `views::take(span, n)` returns a `span`.
1189924d8d6SKonstantin Varlamov {
1199924d8d6SKonstantin Varlamov std::span<int> s(buf);
1209924d8d6SKonstantin Varlamov std::same_as<decltype(s)> decltype(auto) result = s | std::views::take(3);
1219924d8d6SKonstantin Varlamov assert(result.size() == 3);
1229924d8d6SKonstantin Varlamov }
1239924d8d6SKonstantin Varlamov
1249924d8d6SKonstantin Varlamov // `views::take(span, n)` returns a `span` with a dynamic extent, regardless of the input `span`.
1259924d8d6SKonstantin Varlamov {
1269924d8d6SKonstantin Varlamov std::span<int, 8> s(buf);
1279924d8d6SKonstantin Varlamov std::same_as<std::span<int, std::dynamic_extent>> decltype(auto) result = s | std::views::take(3);
1289924d8d6SKonstantin Varlamov assert(result.size() == 3);
1299924d8d6SKonstantin Varlamov }
1309924d8d6SKonstantin Varlamov
1319924d8d6SKonstantin Varlamov // `views::take(string_view, n)` returns a `string_view`.
1329924d8d6SKonstantin Varlamov {
1339924d8d6SKonstantin Varlamov {
1349924d8d6SKonstantin Varlamov std::string_view sv = "abcdef";
1359924d8d6SKonstantin Varlamov std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);
1369924d8d6SKonstantin Varlamov assert(result.size() == 3);
1379924d8d6SKonstantin Varlamov }
1389924d8d6SKonstantin Varlamov
1399924d8d6SKonstantin Varlamov {
1409924d8d6SKonstantin Varlamov std::u32string_view sv = U"abcdef";
1419924d8d6SKonstantin Varlamov std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);
1429924d8d6SKonstantin Varlamov assert(result.size() == 3);
1439924d8d6SKonstantin Varlamov }
1449924d8d6SKonstantin Varlamov }
1459924d8d6SKonstantin Varlamov
1469924d8d6SKonstantin Varlamov // `views::take(subrange, n)` returns a `subrange`.
1479924d8d6SKonstantin Varlamov {
1489924d8d6SKonstantin Varlamov auto subrange = std::ranges::subrange(buf, buf + N);
1499924d8d6SKonstantin Varlamov using Result = std::ranges::subrange<int*>;
1509924d8d6SKonstantin Varlamov std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
1519924d8d6SKonstantin Varlamov assert(result.size() == 3);
1529924d8d6SKonstantin Varlamov }
1539924d8d6SKonstantin Varlamov
1549924d8d6SKonstantin Varlamov // `views::take(subrange, n)` doesn't return a `subrange` if it's not a random access range.
1559924d8d6SKonstantin Varlamov {
1569924d8d6SKonstantin Varlamov SizedView v(buf, buf + N);
1579924d8d6SKonstantin Varlamov auto subrange = std::ranges::subrange(v.begin(), v.end());
1589924d8d6SKonstantin Varlamov
1599924d8d6SKonstantin Varlamov using Result = std::ranges::take_view<std::ranges::subrange<forward_iterator<int*>,
1609924d8d6SKonstantin Varlamov sized_sentinel<forward_iterator<int*>>>>;
1619924d8d6SKonstantin Varlamov std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
1629924d8d6SKonstantin Varlamov assert(result.size() == 3);
1639924d8d6SKonstantin Varlamov }
1649924d8d6SKonstantin Varlamov
1659924d8d6SKonstantin Varlamov // `views::take(subrange, n)` returns a `subrange` with all default template arguments.
1669924d8d6SKonstantin Varlamov {
1679924d8d6SKonstantin Varlamov std::ranges::subrange<int*, sized_sentinel<int*>, std::ranges::subrange_kind::sized> subrange;
1689924d8d6SKonstantin Varlamov
1699924d8d6SKonstantin Varlamov using Result = std::ranges::subrange<int*, int*, std::ranges::subrange_kind::sized>;
1709924d8d6SKonstantin Varlamov [[maybe_unused]] std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);
1719924d8d6SKonstantin Varlamov }
1729924d8d6SKonstantin Varlamov
1739924d8d6SKonstantin Varlamov // `views::take(iota_view, n)` returns an `iota_view`.
1749924d8d6SKonstantin Varlamov {
1759924d8d6SKonstantin Varlamov auto iota = std::views::iota(1, 8);
1769924d8d6SKonstantin Varlamov // The second template argument of the resulting `iota_view` is different because it has to be able to hold
1779924d8d6SKonstantin Varlamov // the `range_difference_t` of the input `iota_view`.
1789924d8d6SKonstantin Varlamov using Result = std::ranges::iota_view<int, std::ranges::range_difference_t<decltype(iota)>>;
1799924d8d6SKonstantin Varlamov std::same_as<Result> decltype(auto) result = iota | std::views::take(3);
1809924d8d6SKonstantin Varlamov assert(result.size() == 3);
1819924d8d6SKonstantin Varlamov }
1829924d8d6SKonstantin Varlamov
1839924d8d6SKonstantin Varlamov // When the size of the input range `s` is shorter than `n`, only `s` elements are taken.
1849924d8d6SKonstantin Varlamov {
1859924d8d6SKonstantin Varlamov test_small_range(std::span(buf));
1869924d8d6SKonstantin Varlamov test_small_range(std::string_view("abcdef"));
1879924d8d6SKonstantin Varlamov test_small_range(std::ranges::subrange(buf, buf + N));
1889924d8d6SKonstantin Varlamov test_small_range(std::views::iota(1, 8));
1899924d8d6SKonstantin Varlamov }
1909924d8d6SKonstantin Varlamov
1919924d8d6SKonstantin Varlamov // Test that it's possible to call `std::views::take` with any single argument as long as the resulting closure is
1929924d8d6SKonstantin Varlamov // never invoked. There is no good use case for it, but it's valid.
1939924d8d6SKonstantin Varlamov {
1949924d8d6SKonstantin Varlamov struct X { };
1959924d8d6SKonstantin Varlamov [[maybe_unused]] auto partial = std::views::take(X{});
1969924d8d6SKonstantin Varlamov }
1979924d8d6SKonstantin Varlamov
1989924d8d6SKonstantin Varlamov return true;
1999924d8d6SKonstantin Varlamov }
2009924d8d6SKonstantin Varlamov
main(int,char **)2019924d8d6SKonstantin Varlamov int main(int, char**) {
2029924d8d6SKonstantin Varlamov test();
2039924d8d6SKonstantin Varlamov static_assert(test());
2049924d8d6SKonstantin Varlamov
2059924d8d6SKonstantin Varlamov return 0;
2069924d8d6SKonstantin Varlamov }
207