10b46606cSJakub Mazurkiewicz //===----------------------------------------------------------------------===//
20b46606cSJakub Mazurkiewicz //
30b46606cSJakub Mazurkiewicz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b46606cSJakub Mazurkiewicz // See https://llvm.org/LICENSE.txt for license information.
50b46606cSJakub Mazurkiewicz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b46606cSJakub Mazurkiewicz //
70b46606cSJakub Mazurkiewicz //===----------------------------------------------------------------------===//
80b46606cSJakub Mazurkiewicz
90b46606cSJakub Mazurkiewicz // UNSUPPORTED: c++03, c++11, c++14, c++17
100b46606cSJakub Mazurkiewicz
110b46606cSJakub Mazurkiewicz // friend constexpr bool operator==(const CI<Const>& y, const sentinel& x);
120b46606cSJakub Mazurkiewicz // template<bool OtherConst = !Const>
130b46606cSJakub Mazurkiewicz // requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
140b46606cSJakub Mazurkiewicz // friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x);
150b46606cSJakub Mazurkiewicz
160b46606cSJakub Mazurkiewicz #include <cassert>
170b46606cSJakub Mazurkiewicz #include <cstddef>
180b46606cSJakub Mazurkiewicz #include <ranges>
190b46606cSJakub Mazurkiewicz #include <type_traits>
200b46606cSJakub Mazurkiewicz #include <utility>
210b46606cSJakub Mazurkiewicz
220b46606cSJakub Mazurkiewicz #include "test_comparisons.h"
230b46606cSJakub Mazurkiewicz #include "test_iterators.h"
24*808d794aSWill Hawkins #include "test_range.h"
250b46606cSJakub Mazurkiewicz
260b46606cSJakub Mazurkiewicz template <bool Const>
270b46606cSJakub Mazurkiewicz using MaybeConstIterator = cpp20_input_iterator<std::conditional_t<Const, const int*, int*>>;
280b46606cSJakub Mazurkiewicz
290b46606cSJakub Mazurkiewicz template <bool Const>
300b46606cSJakub Mazurkiewicz class CrossConstComparableSentinel {
310b46606cSJakub Mazurkiewicz using Base = std::conditional_t<Const, const int*, int*>;
320b46606cSJakub Mazurkiewicz Base base_;
330b46606cSJakub Mazurkiewicz
340b46606cSJakub Mazurkiewicz public:
350b46606cSJakub Mazurkiewicz CrossConstComparableSentinel() = default;
CrossConstComparableSentinel(Base base)360b46606cSJakub Mazurkiewicz constexpr explicit CrossConstComparableSentinel(Base base) : base_(base) {}
370b46606cSJakub Mazurkiewicz
operator ==(const MaybeConstIterator<Const> & it,const CrossConstComparableSentinel & se)380b46606cSJakub Mazurkiewicz friend constexpr bool operator==(const MaybeConstIterator<Const>& it, const CrossConstComparableSentinel& se) {
390b46606cSJakub Mazurkiewicz return base(it) == se.base_;
400b46606cSJakub Mazurkiewicz }
410b46606cSJakub Mazurkiewicz
operator ==(const MaybeConstIterator<!Const> & it,const CrossConstComparableSentinel & se)420b46606cSJakub Mazurkiewicz friend constexpr bool operator==(const MaybeConstIterator<!Const>& it, const CrossConstComparableSentinel& se) {
430b46606cSJakub Mazurkiewicz return base(it) == se.base_;
440b46606cSJakub Mazurkiewicz }
450b46606cSJakub Mazurkiewicz };
460b46606cSJakub Mazurkiewicz
470b46606cSJakub Mazurkiewicz static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<false>>);
480b46606cSJakub Mazurkiewicz static_assert(std::sentinel_for<CrossConstComparableSentinel<true>, MaybeConstIterator<true>>);
490b46606cSJakub Mazurkiewicz static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<false>>);
500b46606cSJakub Mazurkiewicz static_assert(std::sentinel_for<CrossConstComparableSentinel<false>, MaybeConstIterator<true>>);
510b46606cSJakub Mazurkiewicz
520b46606cSJakub Mazurkiewicz struct CrossConstComparableView : std::ranges::view_base {
530b46606cSJakub Mazurkiewicz template <std::size_t N>
CrossConstComparableViewCrossConstComparableView540b46606cSJakub Mazurkiewicz constexpr explicit CrossConstComparableView(int (&arr)[N]) : b_(arr), e_(arr + N) {}
550b46606cSJakub Mazurkiewicz
beginCrossConstComparableView560b46606cSJakub Mazurkiewicz constexpr MaybeConstIterator<false> begin() { return MaybeConstIterator<false>{b_}; }
endCrossConstComparableView570b46606cSJakub Mazurkiewicz constexpr CrossConstComparableSentinel<false> end() { return CrossConstComparableSentinel<false>{e_}; }
580b46606cSJakub Mazurkiewicz
beginCrossConstComparableView590b46606cSJakub Mazurkiewicz constexpr MaybeConstIterator<true> begin() const { return MaybeConstIterator<true>{b_}; }
endCrossConstComparableView600b46606cSJakub Mazurkiewicz constexpr CrossConstComparableSentinel<true> end() const { return CrossConstComparableSentinel<true>{e_}; }
610b46606cSJakub Mazurkiewicz
620b46606cSJakub Mazurkiewicz private:
630b46606cSJakub Mazurkiewicz int* b_;
640b46606cSJakub Mazurkiewicz int* e_;
650b46606cSJakub Mazurkiewicz };
660b46606cSJakub Mazurkiewicz
670b46606cSJakub Mazurkiewicz static_assert(std::ranges::range<CrossConstComparableView>);
680b46606cSJakub Mazurkiewicz static_assert(std::ranges::range<const CrossConstComparableView>);
690b46606cSJakub Mazurkiewicz
700b46606cSJakub Mazurkiewicz struct NonCrossConstComparableView : std::ranges::view_base {
710b46606cSJakub Mazurkiewicz int* begin();
720b46606cSJakub Mazurkiewicz sentinel_wrapper<int*> end();
730b46606cSJakub Mazurkiewicz
740b46606cSJakub Mazurkiewicz long* begin() const;
750b46606cSJakub Mazurkiewicz sentinel_wrapper<long*> end() const;
760b46606cSJakub Mazurkiewicz };
770b46606cSJakub Mazurkiewicz
780b46606cSJakub Mazurkiewicz static_assert(std::ranges::range<NonCrossConstComparableView>);
790b46606cSJakub Mazurkiewicz static_assert(std::ranges::range<const NonCrossConstComparableView>);
800b46606cSJakub Mazurkiewicz
test()810b46606cSJakub Mazurkiewicz constexpr bool test() {
820b46606cSJakub Mazurkiewicz int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
830b46606cSJakub Mazurkiewicz using CrossConstComparableTakeView = std::ranges::take_view<CrossConstComparableView>;
840b46606cSJakub Mazurkiewicz
850b46606cSJakub Mazurkiewicz { // Compare CI<Const> with sentinel<Const>
860b46606cSJakub Mazurkiewicz { // Const == true
870b46606cSJakub Mazurkiewicz AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>,
880b46606cSJakub Mazurkiewicz std::ranges::sentinel_t<const CrossConstComparableTakeView>>();
890b46606cSJakub Mazurkiewicz const CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
900b46606cSJakub Mazurkiewicz assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true));
910b46606cSJakub Mazurkiewicz assert(testEquality(tv.begin(), tv.end(), false));
920b46606cSJakub Mazurkiewicz }
930b46606cSJakub Mazurkiewicz
940b46606cSJakub Mazurkiewicz { // Const == false
950b46606cSJakub Mazurkiewicz AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>,
960b46606cSJakub Mazurkiewicz std::ranges::sentinel_t<CrossConstComparableTakeView>>();
970b46606cSJakub Mazurkiewicz CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
980b46606cSJakub Mazurkiewicz assert(testEquality(std::ranges::next(tv.begin(), 4), tv.end(), true));
990b46606cSJakub Mazurkiewicz assert(testEquality(std::ranges::next(tv.begin(), 1), tv.end(), false));
1000b46606cSJakub Mazurkiewicz }
1010b46606cSJakub Mazurkiewicz }
1020b46606cSJakub Mazurkiewicz
1030b46606cSJakub Mazurkiewicz { // Compare CI<Const> with sentinel<!Const>
1040b46606cSJakub Mazurkiewicz { // Const == true
1050b46606cSJakub Mazurkiewicz AssertEqualityReturnBool<std::ranges::iterator_t<const CrossConstComparableTakeView>,
1060b46606cSJakub Mazurkiewicz std::ranges::sentinel_t<CrossConstComparableTakeView>>();
1070b46606cSJakub Mazurkiewicz CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
1080b46606cSJakub Mazurkiewicz assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 4), tv.end(), true));
1090b46606cSJakub Mazurkiewicz assert(testEquality(std::ranges::next(std::as_const(tv).begin(), 2), tv.end(), false));
1100b46606cSJakub Mazurkiewicz }
1110b46606cSJakub Mazurkiewicz
1120b46606cSJakub Mazurkiewicz { // Const == false
1130b46606cSJakub Mazurkiewicz AssertEqualityReturnBool<std::ranges::iterator_t<CrossConstComparableTakeView>,
1140b46606cSJakub Mazurkiewicz std::ranges::sentinel_t<const CrossConstComparableTakeView>>();
1150b46606cSJakub Mazurkiewicz CrossConstComparableTakeView tv(CrossConstComparableView{buffer}, 4);
1160b46606cSJakub Mazurkiewicz assert(testEquality(std::ranges::next(tv.begin(), 4), std::as_const(tv).end(), true));
1170b46606cSJakub Mazurkiewicz assert(testEquality(std::ranges::next(tv.begin(), 3), std::as_const(tv).end(), false));
1180b46606cSJakub Mazurkiewicz }
1190b46606cSJakub Mazurkiewicz }
1200b46606cSJakub Mazurkiewicz
1210b46606cSJakub Mazurkiewicz { // Check invalid comparisons between CI<Const> and sentinel<!Const>
1220b46606cSJakub Mazurkiewicz using TakeView = std::ranges::take_view<NonCrossConstComparableView>;
1230b46606cSJakub Mazurkiewicz static_assert(
1240b46606cSJakub Mazurkiewicz !weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>, std::ranges::sentinel_t<TakeView>>);
1250b46606cSJakub Mazurkiewicz static_assert(
1260b46606cSJakub Mazurkiewicz !weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<const TakeView>>);
1270b46606cSJakub Mazurkiewicz
1280b46606cSJakub Mazurkiewicz // Those should be valid
1290b46606cSJakub Mazurkiewicz static_assert(
1300b46606cSJakub Mazurkiewicz weakly_equality_comparable_with<std::ranges::iterator_t<TakeView>, std::ranges::sentinel_t<TakeView>>);
1310b46606cSJakub Mazurkiewicz static_assert(weakly_equality_comparable_with<std::ranges::iterator_t<const TakeView>,
1320b46606cSJakub Mazurkiewicz std::ranges::sentinel_t<const TakeView>>);
1330b46606cSJakub Mazurkiewicz }
1340b46606cSJakub Mazurkiewicz
1350b46606cSJakub Mazurkiewicz return true;
1360b46606cSJakub Mazurkiewicz }
1370b46606cSJakub Mazurkiewicz
main(int,char **)1380b46606cSJakub Mazurkiewicz int main(int, char**) {
1390b46606cSJakub Mazurkiewicz test();
1400b46606cSJakub Mazurkiewicz static_assert(test());
1410b46606cSJakub Mazurkiewicz
1420b46606cSJakub Mazurkiewicz return 0;
1430b46606cSJakub Mazurkiewicz }
144