//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // template // requires sentinel_for, ziperator> // friend constexpr bool operator==(const iterator& x, const sentinel& y); #include #include #include #include "../types.h" using Iterator = random_access_iterator; using ConstIterator = random_access_iterator; template struct ComparableSentinel { using Iter = std::conditional_t; Iter iter_; explicit ComparableSentinel() = default; constexpr explicit ComparableSentinel(const Iter& it) : iter_(it) {} constexpr friend bool operator==(const Iterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); } constexpr friend bool operator==(const ConstIterator& i, const ComparableSentinel& s) { return base(i) == base(s.iter_); } }; struct ComparableView : IntBufferView { using IntBufferView::IntBufferView; constexpr auto begin() { return Iterator(buffer_); } constexpr auto begin() const { return ConstIterator(buffer_); } constexpr auto end() { return ComparableSentinel(Iterator(buffer_ + size_)); } constexpr auto end() const { return ComparableSentinel(ConstIterator(buffer_ + size_)); } }; struct ConstIncompatibleView : std::ranges::view_base { cpp17_input_iterator begin(); forward_iterator begin() const; sentinel_wrapper> end(); sentinel_wrapper> end() const; }; template concept EqualComparable = std::invocable, const Iter&, const Sent&>; constexpr bool test() { int buffer1[4] = {1, 2, 3, 4}; int buffer2[5] = {1, 2, 3, 4, 5}; int buffer3[8] = {1, 2, 3, 4, 5, 6, 7, 8}; { // const and non-const have different iterator/sentinel types std::ranges::zip_transform_view v{ MakeTuple{}, NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)}; using ZipTransformView = decltype(v); static_assert(!std::ranges::common_range); static_assert(!simple_view); assert(v.begin() != v.end()); assert(v.begin() + 4 == v.end()); // const_iterator (const int*) converted to iterator (int*) assert(v.begin() + 4 == std::as_const(v).end()); using Iter = std::ranges::iterator_t; using ConstIter = std::ranges::iterator_t; static_assert(!std::is_same_v); using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::is_same_v); static_assert(EqualComparable); static_assert(!EqualComparable); static_assert(EqualComparable); static_assert(EqualComparable); } { // underlying const/non-const sentinel can be compared with both const/non-const iterator std::ranges::zip_transform_view v{MakeTuple{}, ComparableView(buffer1), ComparableView(buffer2)}; using ZipTransformView = decltype(v); static_assert(!std::ranges::common_range); static_assert(!simple_view); assert(v.begin() != v.end()); assert(v.begin() + 4 == v.end()); assert(std::as_const(v).begin() + 4 == v.end()); assert(std::as_const(v).begin() + 4 == std::as_const(v).end()); assert(v.begin() + 4 == std::as_const(v).end()); using Iter = std::ranges::iterator_t; using ConstIter = std::ranges::iterator_t; static_assert(!std::is_same_v); using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::is_same_v); static_assert(EqualComparable); static_assert(EqualComparable); static_assert(EqualComparable); static_assert(EqualComparable); } { // underlying const/non-const sentinel cannot be compared with non-const/const iterator std::ranges::zip_transform_view v{MakeTuple{}, ComparableView(buffer1), ConstIncompatibleView{}}; using ZipTransformView = decltype(v); static_assert(!std::ranges::common_range); static_assert(!simple_view); using Iter = std::ranges::iterator_t; using ConstIter = std::ranges::iterator_t; static_assert(!std::is_same_v); using Sentinel = std::ranges::sentinel_t; using ConstSentinel = std::ranges::sentinel_t; static_assert(!std::is_same_v); static_assert(EqualComparable); static_assert(!EqualComparable); static_assert(!EqualComparable); static_assert(EqualComparable); } { // one range std::ranges::zip_transform_view v(MakeTuple{}, ComparableView{buffer1}); assert(v.begin() != v.end()); assert(v.begin() + 4 == v.end()); assert(v.begin() + 4 == std::as_const(v).end()); } { // two ranges std::ranges::zip_transform_view v(GetFirst{}, ComparableView{buffer2}, std::views::iota(0)); assert(v.begin() != v.end()); assert(v.begin() + 5 == v.end()); assert(v.begin() + 5 == std::as_const(v).end()); } { // three ranges std::ranges::zip_transform_view v( Tie{}, ComparableView{buffer1}, SimpleNonCommon{buffer2}, std::ranges::single_view(2.)); assert(v.begin() != v.end()); assert(v.begin() + 1 == v.end()); assert(v.begin() + 1 == std::as_const(v).end()); } { // single empty range std::ranges::zip_transform_view v(MakeTuple{}, ComparableView(nullptr, 0)); assert(v.begin() == v.end()); assert(std::as_const(v).begin() == std::as_const(v).end()); } { // empty range at the beginning std::ranges::zip_transform_view v( MakeTuple{}, std::ranges::empty_view(), ComparableView{buffer1}, SimpleCommon{buffer2}); assert(v.begin() == v.end()); assert(std::as_const(v).begin() == std::as_const(v).end()); } { // empty range in the middle std::ranges::zip_transform_view v( MakeTuple{}, SimpleCommon{buffer1}, std::ranges::empty_view(), ComparableView{buffer2}); assert(v.begin() == v.end()); assert(std::as_const(v).begin() == std::as_const(v).end()); } { // empty range at the end std::ranges::zip_transform_view v( MakeTuple{}, SimpleCommon{buffer1}, ComparableView{buffer2}, std::ranges::empty_view()); assert(v.begin() == v.end()); assert(std::as_const(v).begin() == std::as_const(v).end()); } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }