brintos

brintos / llvm-project-archived public Read only

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