blob: b42ec78cbb7f08e6d28fb9cdbf143dc2fc9efcc7 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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<bool OtherConst>
// requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
// friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
#include <cassert>
#include <compare>
#include <ranges>
#include <tuple>
#include "../types.h"
using Iterator = random_access_iterator<int*>;
using ConstIterator = random_access_iterator<const int*>;
template <bool Const>
struct ComparableSentinel {
using Iter = std::conditional_t<Const, ConstIterator, Iterator>;
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<false>(Iterator(buffer_ + size_)); }
constexpr auto end() const { return ComparableSentinel<true>(ConstIterator(buffer_ + size_)); }
};
struct ConstIncompatibleView : std::ranges::view_base {
cpp17_input_iterator<int*> begin();
forward_iterator<const int*> begin() const;
sentinel_wrapper<cpp17_input_iterator<int*>> end();
sentinel_wrapper<forward_iterator<const int*>> end() const;
};
// clang-format off
template <class Iter, class Sent>
concept EqualComparable = std::invocable<std::equal_to<>, const Iter&, const Sent&>;
// clang-format on
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};
{
// simple-view: const and non-const have the same iterator/sentinel type
std::ranges::zip_view v{SimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)};
static_assert(!std::ranges::common_range<decltype(v)>);
LIBCPP_STATIC_ASSERT(std::ranges::__simple_view<decltype(v)>);
assert(v.begin() != v.end());
assert(v.begin() + 1 != v.end());
assert(v.begin() + 2 != v.end());
assert(v.begin() + 3 != v.end());
assert(v.begin() + 4 == v.end());
}
{
// !simple-view: const and non-const have different iterator/sentinel types
std::ranges::zip_view v{NonSimpleNonCommon(buffer1), SimpleNonCommon(buffer2), SimpleNonCommon(buffer3)};
static_assert(!std::ranges::common_range<decltype(v)>);
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>);
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<decltype(v)>;
using ConstIter = std::ranges::iterator_t<const decltype(v)>;
static_assert(!std::is_same_v<Iter, ConstIter>);
using Sentinel = std::ranges::sentinel_t<decltype(v)>;
using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
static_assert(EqualComparable<Iter, Sentinel>);
static_assert(!EqualComparable<ConstIter, Sentinel>);
static_assert(EqualComparable<Iter, ConstSentinel>);
static_assert(EqualComparable<ConstIter, ConstSentinel>);
}
{
// underlying const/non-const sentinel can be compared with both const/non-const iterator
std::ranges::zip_view v{ComparableView(buffer1), ComparableView(buffer2)};
static_assert(!std::ranges::common_range<decltype(v)>);
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>);
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<decltype(v)>;
using ConstIter = std::ranges::iterator_t<const decltype(v)>;
static_assert(!std::is_same_v<Iter, ConstIter>);
using Sentinel = std::ranges::sentinel_t<decltype(v)>;
using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
static_assert(EqualComparable<Iter, Sentinel>);
static_assert(EqualComparable<ConstIter, Sentinel>);
static_assert(EqualComparable<Iter, ConstSentinel>);
static_assert(EqualComparable<ConstIter, ConstSentinel>);
}
{
// underlying const/non-const sentinel cannot be compared with non-const/const iterator
std::ranges::zip_view v{ComparableView(buffer1), ConstIncompatibleView{}};
static_assert(!std::ranges::common_range<decltype(v)>);
LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view<decltype(v)>);
using Iter = std::ranges::iterator_t<decltype(v)>;
using ConstIter = std::ranges::iterator_t<const decltype(v)>;
static_assert(!std::is_same_v<Iter, ConstIter>);
using Sentinel = std::ranges::sentinel_t<decltype(v)>;
using ConstSentinel = std::ranges::sentinel_t<const decltype(v)>;
static_assert(!std::is_same_v<Sentinel, ConstSentinel>);
static_assert(EqualComparable<Iter, Sentinel>);
static_assert(!EqualComparable<ConstIter, Sentinel>);
static_assert(!EqualComparable<Iter, ConstSentinel>);
static_assert(EqualComparable<ConstIter, ConstSentinel>);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}