brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.7 KiB · fc29a00 Raw
280 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++17, c++2010 11// template<bool OtherConst>12//   requires sized_sentinel_for<zentinel<Const>, ziperator<OtherConst>>13// friend constexpr range_difference_t<maybe-const<OtherConst, InnerView>>14//   operator-(const sentinel& x, const iterator<OtherConst>& y);15 16#include <cassert>17#include <concepts>18#include <functional>19#include <ranges>20#include <tuple>21 22#include "../types.h"23 24template <class Base = int*>25struct convertible_forward_sized_iterator {26  Base it_ = nullptr;27 28  using iterator_category = std::forward_iterator_tag;29  using value_type        = int;30  using difference_type   = std::intptr_t;31 32  convertible_forward_sized_iterator() = default;33  constexpr convertible_forward_sized_iterator(Base it) : it_(it) {}34 35  template <std::convertible_to<Base> U>36  constexpr convertible_forward_sized_iterator(const convertible_forward_sized_iterator<U>& it) : it_(it.it_) {}37 38  constexpr decltype(*Base{}) operator*() const { return *it_; }39 40  constexpr convertible_forward_sized_iterator& operator++() {41    ++it_;42    return *this;43  }44  constexpr convertible_forward_sized_iterator operator++(int) { return forward_sized_iterator(it_++); }45 46  friend constexpr bool47  operator==(const convertible_forward_sized_iterator&, const convertible_forward_sized_iterator&) = default;48 49  friend constexpr difference_type50  operator-(const convertible_forward_sized_iterator& x, const convertible_forward_sized_iterator& y) {51    return x.it_ - y.it_;52  }53};54static_assert(std::forward_iterator<convertible_forward_sized_iterator<>>);55 56template <class Base>57struct convertible_sized_sentinel {58  Base base_;59  explicit convertible_sized_sentinel() = default;60  constexpr convertible_sized_sentinel(const Base& it) : base_(it) {}61 62  template <std::convertible_to<Base> U>63  constexpr convertible_sized_sentinel(const convertible_sized_sentinel<U>& other) : base_(other.base_) {}64 65  template <class U>66    requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)67  friend constexpr bool operator==(const convertible_sized_sentinel& s, const U& base) {68    return s.base_ == base;69  }70  template <class U>71    requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)72  friend constexpr auto operator-(const convertible_sized_sentinel& s, const U& i) {73    return s.base_ - i;74  }75 76  template <class U>77    requires(std::convertible_to<Base, U> || std::convertible_to<U, Base>)78  friend constexpr auto operator-(const U& i, const convertible_sized_sentinel& s) {79    return i - s.base_;80  }81};82static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<>>,83                                      convertible_forward_sized_iterator<>>);84static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<const int*>>,85                                      convertible_forward_sized_iterator<int*>>);86static_assert(std::sized_sentinel_for<convertible_sized_sentinel<convertible_forward_sized_iterator<int*>>,87                                      convertible_forward_sized_iterator<const int*>>);88 89struct ConstCompatibleForwardSized : IntBufferView {90  using IntBufferView::IntBufferView;91 92  using iterator       = convertible_forward_sized_iterator<int*>;93  using const_iterator = convertible_forward_sized_iterator<const int*>;94 95  constexpr iterator begin() { return {buffer_}; }96  constexpr const_iterator begin() const { return {buffer_}; }97  constexpr convertible_sized_sentinel<iterator> end() { return iterator{buffer_ + size_}; }98  constexpr convertible_sized_sentinel<const_iterator> end() const { return const_iterator{buffer_ + size_}; }99};100 101template <class T, class U>102concept HasMinus = std::invocable<std::minus<>, const T&, const U&>;103 104template <class T>105concept SentinelHasMinus = HasMinus<std::ranges::sentinel_t<T>, std::ranges::iterator_t<T>>;106 107constexpr bool test() {108  int buffer1[5] = {1, 2, 3, 4, 5};109  int buffer2[3] = {1, 2, 3};110 111  {112    // shortest range113    std::ranges::zip_transform_view v(MakeTuple{}, std::views::iota(0, 3), ForwardSizedNonCommon(buffer1));114    static_assert(!std::ranges::common_range<decltype(v)>);115    auto it = v.begin();116    auto st = v.end();117    assert(st - it == 3);118    assert(st - std::ranges::next(it, 1) == 2);119 120    assert(it - st == -3);121    assert(std::ranges::next(it, 1) - st == -2);122    static_assert(SentinelHasMinus<decltype(v)>);123  }124 125  {126    // underlying sentinel does not model sized_sentinel_for127    std::ranges::zip_transform_view v(MakeTuple{}, std::views::iota(0), SizedRandomAccessView(buffer1));128    static_assert(!std::ranges::common_range<decltype(v)>);129    static_assert(!SentinelHasMinus<decltype(v)>);130  }131 132  {133    // const incompatible:134    // underlying const sentinels cannot subtract underlying iterators135    // underlying sentinels cannot subtract underlying const iterators136    std::ranges::zip_transform_view v(MakeTuple{}, NonSimpleForwardSizedNonCommon{buffer1});137    static_assert(!std::ranges::common_range<decltype(v)>);138    static_assert(!simple_view<decltype(v)>);139 140    using Iter      = std::ranges::iterator_t<decltype(v)>;141    using ConstIter = std::ranges::iterator_t<const decltype(v)>;142    static_assert(!std::is_same_v<Iter, ConstIter>);143    using Sentinel      = std::ranges::sentinel_t<decltype(v)>;144    using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;145    static_assert(!std::is_same_v<Sentinel, ConstSentinel>);146 147    static_assert(HasMinus<Iter, Sentinel>);148    static_assert(HasMinus<Sentinel, Iter>);149    static_assert(HasMinus<ConstIter, ConstSentinel>);150    static_assert(HasMinus<ConstSentinel, ConstIter>);151    auto it       = v.begin();152    auto const_it = std::as_const(v).begin();153    auto st       = v.end();154    auto const_st = std::as_const(v).end();155    assert(it - st == -5);156    assert(st - it == 5);157    assert(const_it - const_st == -5);158    assert(const_st - const_it == 5);159 160    static_assert(!HasMinus<Iter, ConstSentinel>);161    static_assert(!HasMinus<ConstSentinel, Iter>);162    static_assert(!HasMinus<ConstIter, Sentinel>);163    static_assert(!HasMinus<Sentinel, ConstIter>);164  }165 166  {167    // const compatible allow non-const to const conversion168    std::ranges::zip_transform_view v(MakeTuple{}, ConstCompatibleForwardSized{buffer1});169    static_assert(!std::ranges::common_range<decltype(v)>);170    static_assert(!simple_view<decltype(v)>);171 172    using Iter      = std::ranges::iterator_t<decltype(v)>;173    using ConstIter = std::ranges::iterator_t<const decltype(v)>;174    static_assert(!std::is_same_v<Iter, ConstIter>);175    using Sentinel      = std::ranges::sentinel_t<decltype(v)>;176    using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;177    static_assert(!std::is_same_v<Sentinel, ConstSentinel>);178 179    static_assert(HasMinus<Iter, Sentinel>);180    static_assert(HasMinus<Sentinel, Iter>);181    static_assert(HasMinus<ConstIter, ConstSentinel>);182    static_assert(HasMinus<ConstSentinel, ConstIter>);183    static_assert(HasMinus<Iter, ConstSentinel>);184    static_assert(HasMinus<ConstSentinel, Iter>);185    static_assert(HasMinus<ConstIter, Sentinel>);186    static_assert(HasMinus<Sentinel, ConstIter>);187 188    auto it       = v.begin();189    auto const_it = std::as_const(v).begin();190    auto st       = v.end();191    auto const_st = std::as_const(v).end();192 193    assert(it - st == -5);194    assert(st - it == 5);195    assert(const_it - const_st == -5);196    assert(const_st - const_it == 5);197    assert(it - const_st == -5);198    assert(const_st - it == 5);199    assert(const_it - st == -5);200    assert(st - const_it == 5);201  }202 203  auto testMinus = [](auto&& v, auto distance) {204    auto it       = v.begin();205    auto const_it = std::as_const(v).begin();206    auto st       = v.end();207    auto const_st = std::as_const(v).end();208 209    assert(it - st == -distance);210    assert(st - it == distance);211    assert(const_it - const_st == -distance);212    assert(const_st - const_it == distance);213    assert(it - const_st == -distance);214    assert(const_st - it == distance);215    assert(const_it - st == -distance);216    assert(st - const_it == distance);217  };218 219  {220    // one range221    std::ranges::zip_transform_view v(MakeTuple{}, ConstCompatibleForwardSized{buffer1});222    testMinus(v, 5);223  }224 225  {226    // two ranges227    std::ranges::zip_transform_view v(GetFirst{}, ConstCompatibleForwardSized{buffer1}, std::views::iota(0, 100));228    testMinus(v, 5);229  }230 231  {232    // three ranges233    std::ranges::zip_transform_view v(234        Tie{},235        ConstCompatibleForwardSized{buffer1},236        ConstCompatibleForwardSized{buffer2},237        std::ranges::single_view(2.));238    testMinus(v, 1);239  }240 241  {242    // single empty range243    std::ranges::zip_transform_view v(MakeTuple{}, ConstCompatibleForwardSized(nullptr, 0));244    testMinus(v, 0);245  }246 247  {248    // empty range at the beginning249    std::ranges::zip_transform_view v(250        MakeTuple{}, std::ranges::empty_view<int>(), ConstCompatibleForwardSized{buffer1}, SimpleCommon{buffer2});251    testMinus(v, 0);252  }253 254  {255    // empty range in the middle256    std::ranges::zip_transform_view v(257        MakeTuple{},258        ConstCompatibleForwardSized{buffer1},259        std::ranges::empty_view<int>(),260        ConstCompatibleForwardSized{buffer2});261    testMinus(v, 0);262  }263 264  {265    // empty range at the end266    std::ranges::zip_transform_view v(267        MakeTuple{}, SimpleCommon{buffer1}, ConstCompatibleForwardSized{buffer2}, std::ranges::empty_view<int>());268    testMinus(v, 0);269  }270 271  return true;272}273 274int main(int, char**) {275  test();276  static_assert(test());277 278  return 0;279}280