144 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// friend constexpr bool operator==(const CI<Const>& y, const sentinel& x);12// template<bool OtherConst = !Const>13// requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>14// friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x);15 16#include <cassert>17#include <cstddef>18#include <ranges>19#include <type_traits>20#include <utility>21 22#include "test_comparisons.h"23#include "test_iterators.h"24#include "test_range.h"25 26template <bool Const>27using MaybeConstIterator = cpp20_input_iterator<std::conditional_t<Const, const int*, int*>>;28 29template <bool Const>30class CrossConstComparableSentinel {31 using Base = std::conditional_t<Const, const int*, int*>;32 Base base_;33 34public:35 CrossConstComparableSentinel() = default;36 constexpr explicit CrossConstComparableSentinel(Base base) : base_(base) {}37 38 friend constexpr bool operator==(const MaybeConstIterator<Const>& it, const CrossConstComparableSentinel& se) {39 return base(it) == se.base_;40 }41 42 friend constexpr bool operator==(const MaybeConstIterator<!Const>& it, const CrossConstComparableSentinel& se) {43 return base(it) == se.base_;44 }45};46 47static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<false>>);48static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<true>>);49static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<false>>);50static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<true>>);51 52struct CrossConstComparableView : std::ranges::view_base {53 template <std::size_t N>54 constexpr explicit CrossConstComparableView(int (&arr)[N]) : b_(arr), e_(arr + N) {}55 56 constexpr MaybeConstIterator<false> begin() { return MaybeConstIterator<false>{b_}; }57 constexpr CrossConstComparableSentinel<false> end() { return CrossConstComparableSentinel<false>{e_}; }58 59 constexpr MaybeConstIterator<true> begin() const { return MaybeConstIterator<true>{b_}; }60 constexpr CrossConstComparableSentinel<true> end() const { return CrossConstComparableSentinel<true>{e_}; }61 62private:63 int* b_;64 int* e_;65};66 67static_assert(std::ranges::range<CrossConstComparableView>);68static_assert(std::ranges::range<const CrossConstComparableView>);69 70struct NonCrossConstComparableView : std::ranges::view_base {71 int* begin();72 sentinel_wrapper<int*> end();73 74 long* begin() const;75 sentinel_wrapper<long*> end() const;76};77 78static_assert(std::ranges::range<NonCrossConstComparableView>);79static_assert(std::ranges::range<const NonCrossConstComparableView>);80 81constexpr bool test() {82 int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};83 using CrossConstComparableTakeView = std::ranges::take_view<CrossConstComparableView>;84 85 { // Compare CI<Const> with sentinel<Const>86 { // Const == true87 AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>,88 std::ranges::sentinel_t<const CrossConstComparableTakeView>>();89 const CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);90 assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true));91 assert(testEquality(tv.begin(), tv.end(), false));92 }93 94 { // Const == false95 AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>,96 std::ranges::sentinel_t<CrossConstComparableTakeView>>();97 CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);98 assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true));99 assert(testEquality(std::ranges::next(tv.begin(), 1), tv.end(), false));100 }101 }102 103 { // Compare CI<Const> with sentinel<!Const>104 { // Const == true105 AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>,106 std::ranges::sentinel_t<CrossConstComparableTakeView>>();107 CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);108 assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 4), tv.end(), true));109 assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 2), tv.end(), false));110 }111 112 { // Const == false113 AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>,114 std::ranges::sentinel_t<const CrossConstComparableTakeView>>();115 CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);116 assert(testEquality(std::ranges::next(tv.begin(), 4), std::as_const(tv).end(), true));117 assert(testEquality(std::ranges::next(tv.begin(), 3), std::as_const(tv).end(), false));118 }119 }120 121 { // Check invalid comparisons between CI<Const> and sentinel<!Const>122 using TakeView = std::ranges::take_view<NonCrossConstComparableView>;123 static_assert(124 !weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>, std::ranges::sentinel_t<TakeView>>);125 static_assert(126 !weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<const TakeView>>);127 128 // Those should be valid129 static_assert(130 weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<TakeView>>);131 static_assert(weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>,132 std::ranges::sentinel_t<const TakeView>>);133 }134 135 return true;136}137 138int main(int, char**) {139 test();140 static_assert(test());141 142 return 0;143}144