200 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 sentinel_for<zentinel<Const>, ziperator<OtherConst>>13// friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);14 15#include <cassert>16#include <compare>17#include <ranges>18 19#include "../types.h"20 21using Iterator = random_access_iterator<int*>;22using ConstIterator = random_access_iterator<const int*>;23 24template <bool Const>25struct ComparableSentinel {26 using Iter = std::conditional_t<Const, ConstIterator, Iterator>;27 Iter iter_;28 29 explicit ComparableSentinel() = default;30 constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {}31 32 constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); }33 34 constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) {35 return base(i) == base(s.iter_);36 }37};38 39struct ComparableView : IntBufferView {40 using IntBufferView::IntBufferView;41 42 constexpr auto begin() { return Iterator(buffer_); }43 constexpr auto begin() const { return ConstIterator(buffer_); }44 constexpr auto end() { return ComparableSentinel<false>(Iterator(buffer_ + size_)); }45 constexpr auto end() const { return ComparableSentinel<true>(ConstIterator(buffer_ + size_)); }46};47 48struct ConstIncompatibleView : std::ranges::view_base {49 cpp17_input_iterator<int*> begin();50 forward_iterator<const int*> begin() const;51 sentinel_wrapper<cpp17_input_iterator<int*>> end();52 sentinel_wrapper<forward_iterator<const int*>> end() const;53};54 55template <class Iter, class Sent>56concept EqualComparable = std::invocable<std::equal_to<>, const Iter&, const Sent&>;57 58constexpr bool test() {59 int buffer1[4] = {1, 2, 3, 4};60 int buffer2[5] = {1, 2, 3, 4, 5};61 int buffer3[8] = {1, 2, 3, 4, 5, 6, 7, 8};62 {63 // const and non-const have different iterator/sentinel types64 std::ranges::zip_transform_view v{65 MakeTuple{}, NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)};66 using ZipTransformView = decltype(v);67 static_assert(!std::ranges::common_range<ZipTransformView>);68 static_assert(!simple_view<ZipTransformView>);69 70 assert(v.begin() != v.end());71 assert(v.begin() + 4 == v.end());72 73 // const_iterator (const int*) converted to iterator (int*)74 assert(v.begin() + 4 == std::as_const(v).end());75 76 using Iter = std::ranges::iterator_t<decltype(v)>;77 using ConstIter = std::ranges::iterator_t<const decltype(v)>;78 static_assert(!std::is_same_v<Iter, ConstIter>);79 using Sentinel = std::ranges::sentinel_t<decltype(v)>;80 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;81 static_assert(!std::is_same_v<Sentinel, ConstSentinel>);82 83 static_assert(EqualComparable<Iter, Sentinel>);84 static_assert(!EqualComparable<ConstIter, Sentinel>);85 static_assert(EqualComparable<Iter, ConstSentinel>);86 static_assert(EqualComparable<ConstIter, ConstSentinel>);87 }88 89 {90 // underlying const/non-const sentinel can be compared with both const/non-const iterator91 std::ranges::zip_transform_view v{MakeTuple{}, ComparableView(buffer1), ComparableView(buffer2)};92 using ZipTransformView = decltype(v);93 static_assert(!std::ranges::common_range<ZipTransformView>);94 static_assert(!simple_view<ZipTransformView>);95 96 assert(v.begin() != v.end());97 assert(v.begin() + 4 == v.end());98 assert(std::as_const(v).begin() + 4 == v.end());99 assert(std::as_const(v).begin() + 4 == std::as_const(v).end());100 assert(v.begin() + 4 == std::as_const(v).end());101 102 using Iter = std::ranges::iterator_t<decltype(v)>;103 using ConstIter = std::ranges::iterator_t<const decltype(v)>;104 static_assert(!std::is_same_v<Iter, ConstIter>);105 using Sentinel = std::ranges::sentinel_t<decltype(v)>;106 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;107 static_assert(!std::is_same_v<Sentinel, ConstSentinel>);108 109 static_assert(EqualComparable<Iter, Sentinel>);110 static_assert(EqualComparable<ConstIter, Sentinel>);111 static_assert(EqualComparable<Iter, ConstSentinel>);112 static_assert(EqualComparable<ConstIter, ConstSentinel>);113 }114 115 {116 // underlying const/non-const sentinel cannot be compared with non-const/const iterator117 std::ranges::zip_transform_view v{MakeTuple{}, ComparableView(buffer1), ConstIncompatibleView{}};118 using ZipTransformView = decltype(v);119 static_assert(!std::ranges::common_range<ZipTransformView>);120 static_assert(!simple_view<ZipTransformView>);121 122 using Iter = std::ranges::iterator_t<decltype(v)>;123 using ConstIter = std::ranges::iterator_t<const decltype(v)>;124 static_assert(!std::is_same_v<Iter, ConstIter>);125 using Sentinel = std::ranges::sentinel_t<decltype(v)>;126 using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;127 static_assert(!std::is_same_v<Sentinel, ConstSentinel>);128 129 static_assert(EqualComparable<Iter, Sentinel>);130 static_assert(!EqualComparable<ConstIter, Sentinel>);131 static_assert(!EqualComparable<Iter, ConstSentinel>);132 static_assert(EqualComparable<ConstIter, ConstSentinel>);133 }134 135 {136 // one range137 std::ranges::zip_transform_view v(MakeTuple{}, ComparableView{buffer1});138 assert(v.begin() != v.end());139 assert(v.begin() + 4 == v.end());140 assert(v.begin() + 4 == std::as_const(v).end());141 }142 143 {144 // two ranges145 std::ranges::zip_transform_view v(GetFirst{}, ComparableView{buffer2}, std::views::iota(0));146 assert(v.begin() != v.end());147 assert(v.begin() + 5 == v.end());148 assert(v.begin() + 5 == std::as_const(v).end());149 }150 151 {152 // three ranges153 std::ranges::zip_transform_view v(154 Tie{}, ComparableView{buffer1}, SimpleNonCommon{buffer2}, std::ranges::single_view(2.));155 assert(v.begin() != v.end());156 assert(v.begin() + 1 == v.end());157 assert(v.begin() + 1 == std::as_const(v).end());158 }159 160 {161 // single empty range162 std::ranges::zip_transform_view v(MakeTuple{}, ComparableView(nullptr, 0));163 assert(v.begin() == v.end());164 assert(std::as_const(v).begin() == std::as_const(v).end());165 }166 167 {168 // empty range at the beginning169 std::ranges::zip_transform_view v(170 MakeTuple{}, std::ranges::empty_view<int>(), ComparableView{buffer1}, SimpleCommon{buffer2});171 assert(v.begin() == v.end());172 assert(std::as_const(v).begin() == std::as_const(v).end());173 }174 175 {176 // empty range in the middle177 std::ranges::zip_transform_view v(178 MakeTuple{}, SimpleCommon{buffer1}, std::ranges::empty_view<int>(), ComparableView{buffer2});179 assert(v.begin() == v.end());180 assert(std::as_const(v).begin() == std::as_const(v).end());181 }182 183 {184 // empty range at the end185 std::ranges::zip_transform_view v(186 MakeTuple{}, SimpleCommon{buffer1}, ComparableView{buffer2}, std::ranges::empty_view<int>());187 assert(v.begin() == v.end());188 assert(std::as_const(v).begin() == std::as_const(v).end());189 }190 191 return true;192}193 194int main(int, char**) {195 test();196 static_assert(test());197 198 return 0;199}200