diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -73,6 +73,13 @@ template concept sentinel_for = see below; // since C++20 +// [iterator.concept.sizedsentinel], concept sized_sentinel_for +template + inline constexpr bool disable_sized_sentinel_for = false; + +template + concept sized_sentinel_for = see below; + template struct iterator @@ -2587,6 +2594,18 @@ input_or_output_iterator<_Ip> && __weakly_equality_comparable_with<_Sp, _Ip>; +template +inline constexpr bool disable_sized_sentinel_for = false; + +template +concept sized_sentinel_for = + sentinel_for<_Sp, _Ip> && + !disable_sized_sentinel_for, remove_cv_t<_Ip>> && + requires(const _Ip& __i, const _Sp& __s) { + { __s - __i } -> same_as>; + { __i - __s } -> same_as>; + }; + #undef _LIBCPP_NOEXCEPT_RETURN #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.sentinel/sized_sentinel_for.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.sentinel/sized_sentinel_for.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.sentinel/sized_sentinel_for.compile.pass.cpp @@ -0,0 +1,154 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// [iterator.concept.sizedsentinel], concept sized_sentinel_for +// +// template +// inline constexpr bool disable_sized_sentinel_for = false; +// +// template +// concept sized_sentinel_for = see below; + +#include + +#include +#include +#include +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +static_assert(std::sized_sentinel_for, + random_access_iterator >); +static_assert(!std::sized_sentinel_for, + bidirectional_iterator >); + +struct int_sized_sentinel { + friend constexpr bool operator==(int_sized_sentinel, int*); + friend constexpr long operator-(int_sized_sentinel, int*); + friend constexpr long operator-(int*, int_sized_sentinel); +}; +static_assert(std::sized_sentinel_for); +static_assert( + !std::sized_sentinel_for< + int*, int_sized_sentinel>); // int_sized_sentinel is not an iterator. + +struct no_default_ctor { + no_default_ctor() = delete; + bool operator==(std::input_or_output_iterator auto) const; +}; +static_assert( + !std::sized_sentinel_for::iterator>); + +struct not_copyable { + not_copyable(not_copyable const&) = delete; + bool operator==(std::input_or_output_iterator auto) const; +}; +static_assert( + !std::sized_sentinel_for::iterator>); + +struct double_sized_sentinel { + friend bool operator==(double_sized_sentinel, double*); + friend int operator-(double_sized_sentinel, double*); + friend int operator-(double*, double_sized_sentinel); +}; +template <> +inline constexpr bool + std::disable_sized_sentinel_for = true; + +static_assert(!std::sized_sentinel_for); + +struct only_one_sub_op { + friend constexpr bool operator==(only_one_sub_op, + std::input_or_output_iterator auto); + friend constexpr long operator-(only_one_sub_op, + std::input_or_output_iterator auto); +}; +static_assert(!std::sized_sentinel_for); + +struct wrong_return_type { + friend constexpr bool operator==(wrong_return_type, + std::input_or_output_iterator auto); + friend constexpr long operator-(wrong_return_type, + std::input_or_output_iterator auto); + friend constexpr void operator-(std::input_or_output_iterator auto, + wrong_return_type); +}; +static_assert(!std::sized_sentinel_for); + +namespace standard_types { +static_assert(std::sized_sentinel_for); + +template +constexpr bool check_sized_sentinel_for() { + using iterator = typename T::iterator; + using const_iterator = typename T::const_iterator; + + static_assert(std::sized_sentinel_for); + static_assert(std::sized_sentinel_for); + static_assert(std::sized_sentinel_for); + static_assert(std::sized_sentinel_for); + + return true; +} + +template +constexpr bool check_sized_sentinel_for_with_reverse_iterators() { + check_sized_sentinel_for(); + + using iterator = typename T::iterator; + using const_iterator = typename T::const_iterator; + using reverse_iterator = typename T::reverse_iterator; + using const_reverse_iterator = typename T::const_reverse_iterator; + + static_assert(!std::sized_sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert( + !std::sized_sentinel_for); + + static_assert(!std::sized_sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert(std::sized_sentinel_for); + static_assert( + std::sized_sentinel_for); + + static_assert(!std::sized_sentinel_for); + static_assert( + !std::sized_sentinel_for); + static_assert( + std::sized_sentinel_for); + static_assert( + std::sized_sentinel_for); + + return true; +} + +static_assert( + std::sized_sentinel_for::iterator>, + std::move_iterator::iterator> >); + +static_assert( + check_sized_sentinel_for_with_reverse_iterators >()); +static_assert( + check_sized_sentinel_for_with_reverse_iterators >()); +static_assert( + check_sized_sentinel_for_with_reverse_iterators >()); + +static_assert(check_sized_sentinel_for_with_reverse_iterators()); +static_assert( + check_sized_sentinel_for_with_reverse_iterators()); + +} // namespace standard_types