brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · b30c4fb Raw
236 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++14, c++1710 11// std::views::take12 13#include <ranges>14 15#include <cassert>16#include <concepts>17#include <span>18#include <string_view>19#include <utility>20 21#include "test_iterators.h"22#include "test_range.h"23 24struct SizedView : std::ranges::view_base {25  int* begin_ = nullptr;26  int* end_ = nullptr;27  constexpr SizedView(int* begin, int* end) : begin_(begin), end_(end) {}28 29  constexpr auto begin() const { return forward_iterator<int*>(begin_); }30  constexpr auto end() const { return sized_sentinel<forward_iterator<int*>>(forward_iterator<int*>(end_)); }31};32static_assert(std::ranges::forward_range<SizedView>);33static_assert(std::ranges::sized_range<SizedView>);34static_assert(std::ranges::view<SizedView>);35 36template <class T>37constexpr void test_small_range(const T& input) {38  constexpr int N = 100;39  auto size = std::ranges::size(input);40 41  auto result = input | std::views::take(N);42  assert(size < N);43  assert(result.size() == size);44}45 46constexpr bool test() {47  constexpr int N = 8;48  int buf[N] = {1, 2, 3, 4, 5, 6, 7, 8};49 50  // Test that `std::views::take` is a range adaptor.51  {52    using SomeView = SizedView;53 54    // Test `view | views::take`55    {56      SomeView view(buf, buf + N);57      std::same_as<std::ranges::take_view<SomeView>> decltype(auto) result = view | std::views::take(3);58      assert(result.base().begin_ == buf);59      assert(result.base().end_ == buf + N);60      assert(result.size() == 3);61    }62 63    // Test `adaptor | views::take`64    {65      SomeView view(buf, buf + N);66      auto f = [](int i) { return i; };67      auto const partial = std::views::transform(f) | std::views::take(3);68 69      using Result = std::ranges::take_view<std::ranges::transform_view<SomeView, decltype(f)>>;70      std::same_as<Result> decltype(auto) result = partial(view);71      assert(result.base().base().begin_ == buf);72      assert(result.base().base().end_ == buf + N);73      assert(result.size() == 3);74    }75 76    // Test `views::take | adaptor`77    {78      SomeView view(buf, buf + N);79      auto f = [](int i) { return i; };80      auto const partial = std::views::take(3) | std::views::transform(f);81 82      using Result = std::ranges::transform_view<std::ranges::take_view<SomeView>, decltype(f)>;83      std::same_as<Result> decltype(auto) result = partial(view);84      assert(result.base().base().begin_ == buf);85      assert(result.base().base().end_ == buf + N);86      assert(result.size() == 3);87    }88 89    // Check SFINAE friendliness90    {91      struct NotAView { };92      static_assert(!std::is_invocable_v<decltype(std::views::take)>);93      static_assert(!std::is_invocable_v<decltype(std::views::take), NotAView, int>);94      static_assert( CanBePiped<SomeView&,   decltype(std::views::take(3))>);95      static_assert( CanBePiped<int(&)[10],  decltype(std::views::take(3))>);96      static_assert(!CanBePiped<int(&&)[10], decltype(std::views::take(3))>);97      static_assert(!CanBePiped<NotAView,    decltype(std::views::take(3))>);98 99      static_assert(!CanBePiped<SomeView&,   decltype(std::views::take(/*n=*/NotAView{}))>);100    }101  }102 103  {104    static_assert(std::same_as<decltype(std::views::take), decltype(std::ranges::views::take)>);105  }106 107  // `views::take(empty_view, n)` returns an `empty_view`.108  {109    using Result = std::ranges::empty_view<int>;110    [[maybe_unused]] std::same_as<Result> decltype(auto) result = std::views::empty<int> | std::views::take(3);111  }112 113  // `views::take(span, n)` returns a `span`.114  {115    std::span<int> s(buf);116    std::same_as<decltype(s)> decltype(auto) result = s | std::views::take(3);117    assert(result.size() == 3);118  }119 120  // `views::take(span, n)` returns a `span` with a dynamic extent, regardless of the input `span`.121  {122    std::span<int, 8> s(buf);123    std::same_as<std::span<int, std::dynamic_extent>> decltype(auto) result = s | std::views::take(3);124    assert(result.size() == 3);125  }126 127  // `views::take(string_view, n)` returns a `string_view`.128  {129    {130      std::string_view sv = "abcdef";131      std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);132      assert(result.size() == 3);133    }134 135    {136      std::u32string_view sv = U"abcdef";137      std::same_as<decltype(sv)> decltype(auto) result = sv | std::views::take(3);138      assert(result.size() == 3);139    }140  }141 142  // `views::take(subrange, n)` returns a `subrange`.143  {144    auto subrange = std::ranges::subrange(buf, buf + N);145    using Result = std::ranges::subrange<int*>;146    std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);147    assert(result.size() == 3);148  }149 150  // `views::take(subrange, n)` doesn't return a `subrange` if it's not a random access range.151  {152    SizedView v(buf, buf + N);153    auto subrange = std::ranges::subrange(v.begin(), v.end());154 155    using Result = std::ranges::take_view<std::ranges::subrange<forward_iterator<int*>,156        sized_sentinel<forward_iterator<int*>>>>;157    std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);158    assert(result.size() == 3);159  }160 161  // `views::take(subrange, n)` returns a `subrange` with all default template arguments.162  {163    std::ranges::subrange<int*, sized_sentinel<int*>, std::ranges::subrange_kind::sized> subrange;164 165    using Result = std::ranges::subrange<int*, int*, std::ranges::subrange_kind::sized>;166    [[maybe_unused]] std::same_as<Result> decltype(auto) result = subrange | std::views::take(3);167  }168 169  // `views::take(iota_view, n)` returns an `iota_view`.170  {171    auto iota = std::views::iota(1, 8);172    // The second template argument of the resulting `iota_view` is same as the first.173    using Result                               = std::ranges::iota_view<int, int>;174    std::same_as<Result> decltype(auto) result = iota | std::views::take(3);175    assert(result.size() == 3);176  }177 178#if TEST_STD_VER >= 23179  // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` models `sized_range`.180  {181    auto repeat                                = std::ranges::repeat_view<int, int>(1, 8);182    using Result                               = std::ranges::repeat_view<int, int>;183    std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);184    static_assert(std::ranges::sized_range<Result>);185    assert(result.size() == 3);186    assert(*result.begin() == 1);187  }188 189  // `views::take(repeat_view, n)` returns a `repeat_view` when `repeat_view` doesn't model `sized_range`.190  {191    auto repeat  = std::ranges::repeat_view<int>(1);192    using Result = std::ranges::repeat_view<int, std::ranges::range_difference_t<decltype(repeat)>>;193    std::same_as<Result> decltype(auto) result = repeat | std::views::take(3);194    assert(result.size() == 3);195    assert(*result.begin() == 1);196  }197#endif198 199  // When the size of the input range `s` is shorter than `n`, only `s` elements are taken.200  {201    test_small_range(std::span(buf));202    test_small_range(std::string_view("abcdef"));203    test_small_range(std::ranges::subrange(buf, buf + N));204    test_small_range(std::views::iota(1, 8));205  }206 207  // Test that it's possible to call `std::views::take` with any single argument as long as the resulting closure is208  // never invoked. There is no good use case for it, but it's valid.209  {210    struct X { };211    [[maybe_unused]] auto partial = std::views::take(X{});212  }213 214  // Test when `subrange<Iter>` is not well formed215  {216    int input[] = {1, 2, 3};217    using Iter  = cpp20_input_iterator<int*>;218    using Sent  = sentinel_wrapper<Iter>;219    std::ranges::subrange r{Iter{input}, Sent{Iter{input + 3}}};220    auto tv = std::views::take(std::move(r), 1);221    auto it                  = tv.begin();222    assert(*it == 1);223    ++it;224    assert(it == tv.end());225  }226 227  return true;228}229 230int main(int, char**) {231  test();232  static_assert(test());233 234  return 0;235}236