[libc++][ranges] P3059R2: Making user-defined constructors of view iterators/sentinels private (#193891)

Implements https://wg21.link/P3059R2 (DR)

Closes #189599

1. Made constructors of iterator and sentinel types of the following
views private:
  - `iota_view`
  - `basic_istream_view`
  - `filter_view`
  - `transform_view`
  - `take_view`
  - `take_while_view`
  - `join_view`
  - `lazy_split_view`
  - `split_view`
  - `elements_view`
2. Updated all relevant tests to fix the usages of the now private
constructor, including:
   1. Removed now obsolete tests (files and cases).
2. Updated all relevant tests to get the iterators and the sentinels via
`begin()` and `end()`, wherever applicable .
   3. Added test cases to confirm that P3059R2 was implemented properly.
   4. Minor other (necessary) tweaks.

---------

Co-authored-by: Hristo Hristov <zingam@outlook.com>
Co-authored-by: A. Jiang <de34@live.cn>
This commit is contained in:
Hristo Hristov 2026-07-30 17:57:11 +03:00 committed by GitHub
parent 2f08dff513
commit 11b58f0e4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 503 additions and 698 deletions

View file

@ -39,6 +39,7 @@ Implemented Papers
------------------
- P0493R5: Atomic minimum/maximum (`Github <https://llvm.org/PR105418>`__)
- P3059R2: Making user-defined constructors of view iterators/sentinels private (`Github <https://github.com/llvm/llvm-project/issues/189599>`__)
- P0792R14: ``function_ref`` : a type-erased callable reference (`Github <https://llvm.org/PR105376>`__)
- P3948R1: ``constant_wrapper`` is the only tool needed for passing constant expressions via function arguments (`Github <https://llvm.org/PR189604>`__)
- P3961R1: Less double indirection in ``function_ref`` (RU-220) (`Github <https://llvm.org/PR189606>`__)

View file

@ -188,7 +188,7 @@
"`P4140R0 <https://wg21.link/P4140R0>`__","Proposed resolution for US70-126: allow incomplete types in type_order","2026-03 (Croydon)","","","`#189595 <https://github.com/llvm/llvm-project/issues/189595>`__",""
"`P3373R4 <https://wg21.link/P3373R4>`__","Of Operation States and Their Lifetimes","2026-03 (Croydon)","","","`#189597 <https://github.com/llvm/llvm-project/issues/189597>`__",""
"`P3986R1 <https://wg21.link/P3986R1>`__","A Wording Strategy for Inlinable Receivers","2026-03 (Croydon)","","","`#189598 <https://github.com/llvm/llvm-project/issues/189598>`__",""
"`P3059R2 <https://wg21.link/P3059R2>`__","Making user-defined constructors of view iterators/sentinels private","2026-03 (Croydon)","","","`#189599 <https://github.com/llvm/llvm-project/issues/189599>`__",""
"`P3059R2 <https://wg21.link/P3059R2>`__","Making user-defined constructors of view iterators/sentinels private","2026-03 (Croydon)","|Complete|","24","`#189599 <https://github.com/llvm/llvm-project/issues/189599>`__",""
"`P3725R3 <https://wg21.link/P3725R3>`__","Filter View Extensions for Safer Use, Rev 3","2026-03 (Croydon)","","","`#189601 <https://github.com/llvm/llvm-project/issues/189601>`__",""
"`P3828R1 <https://wg21.link/P3828R1>`__","Rename the to_input view to as_input","2026-03 (Croydon)","","","`#189602 <https://github.com/llvm/llvm-project/issues/189602>`__",""
"`P3795R2 <https://wg21.link/P3795R2>`__","Miscellaneous Reflection Cleanup","2026-03 (Croydon)","","","`#189603 <https://github.com/llvm/llvm-project/issues/189603>`__",""

1 Paper # Paper Name Meeting Status First released version GitHub issue Notes
188 `P4140R0 <https://wg21.link/P4140R0>`__ Proposed resolution for US70-126: allow incomplete types in type_order 2026-03 (Croydon) `#189595 <https://github.com/llvm/llvm-project/issues/189595>`__
189 `P3373R4 <https://wg21.link/P3373R4>`__ Of Operation States and Their Lifetimes 2026-03 (Croydon) `#189597 <https://github.com/llvm/llvm-project/issues/189597>`__
190 `P3986R1 <https://wg21.link/P3986R1>`__ A Wording Strategy for Inlinable Receivers 2026-03 (Croydon) `#189598 <https://github.com/llvm/llvm-project/issues/189598>`__
191 `P3059R2 <https://wg21.link/P3059R2>`__ Making user-defined constructors of view iterators/sentinels private 2026-03 (Croydon) |Complete| 24 `#189599 <https://github.com/llvm/llvm-project/issues/189599>`__
192 `P3725R3 <https://wg21.link/P3725R3>`__ Filter View Extensions for Safer Use, Rev 3 2026-03 (Croydon) `#189601 <https://github.com/llvm/llvm-project/issues/189601>`__
193 `P3828R1 <https://wg21.link/P3828R1>`__ Rename the to_input view to as_input 2026-03 (Croydon) `#189602 <https://github.com/llvm/llvm-project/issues/189602>`__
194 `P3795R2 <https://wg21.link/P3795R2>`__ Miscellaneous Reflection Cleanup 2026-03 (Croydon) `#189603 <https://github.com/llvm/llvm-project/issues/189603>`__

View file

@ -165,6 +165,8 @@ template <input_range _View, size_t _Np>
template <bool _Const>
class elements_view<_View, _Np>::__iterator
: public __elements_view_iterator_category_base<__maybe_const<_Const, _View>, _Np> {
friend class elements_view<_View, _Np>;
template <bool>
friend class __iterator;
@ -175,6 +177,8 @@ class elements_view<_View, _Np>::__iterator
iterator_t<_Base> __current_ = iterator_t<_Base>();
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current) : __current_(std::move(__current)) {}
_LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_element(const iterator_t<_Base>& __i) {
if constexpr (is_reference_v<range_reference_t<_Base>>) {
return std::get<_Np>(*__i);
@ -205,8 +209,6 @@ public:
requires default_initializable<iterator_t<_Base>>
= default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(iterator_t<_Base> __current) : __current_(std::move(__current)) {}
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
: __current_(std::move(__i.__current_)) {}
@ -339,6 +341,10 @@ private:
using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>;
_LIBCPP_NO_UNIQUE_ADDRESS sentinel_t<_Base> __end_ = sentinel_t<_Base>();
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {}
friend class elements_view<_View, _Np>;
template <bool>
friend class __sentinel;
@ -350,8 +356,6 @@ private:
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {}
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __other)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__other.__end_)) {}

View file

@ -127,10 +127,16 @@ struct __filter_iterator_category<_View> {
template <input_range _View, indirect_unary_predicate<iterator_t<_View>> _Pred>
requires view<_View> && is_object_v<_Pred>
class filter_view<_View, _Pred>::__iterator : public __filter_iterator_category<_View> {
public:
private:
_LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_View> __current_ = iterator_t<_View>();
_LIBCPP_NO_UNIQUE_ADDRESS filter_view* __parent_ = nullptr;
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(filter_view& __parent, iterator_t<_View> __current)
: __current_(std::move(__current)), __parent_(std::addressof(__parent)) {}
friend class filter_view<_View, _Pred>;
public:
using iterator_concept =
_If<bidirectional_range<_View>,
bidirectional_iterator_tag,
@ -145,9 +151,6 @@ public:
requires default_initializable<iterator_t<_View>>
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(filter_view& __parent, iterator_t<_View> __current)
: __current_(std::move(__current)), __parent_(std::addressof(__parent)) {}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> const& base() const& noexcept { return __current_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); }
@ -211,13 +214,16 @@ public:
template <input_range _View, indirect_unary_predicate<iterator_t<_View>> _Pred>
requires view<_View> && is_object_v<_Pred>
class filter_view<_View, _Pred>::__sentinel {
public:
private:
sentinel_t<_View> __end_ = sentinel_t<_View>();
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(filter_view& __parent) : __end_(ranges::end(__parent.__base_)) {}
friend class filter_view<_View, _Pred>;
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; }
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, __sentinel const& __y) {

View file

@ -110,6 +110,12 @@ template <weakly_incrementable _Start, semiregular _BoundSentinel = unreachable_
requires __weakly_equality_comparable_with<_Start, _BoundSentinel> && copyable<_Start>
class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
struct __iterator : public __iota_iterator_category<_Start> {
private:
_Start __value_ = _Start();
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Start __value) : __value_(std::move(__value)) {}
public:
friend class iota_view;
using iterator_concept =
@ -124,14 +130,10 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
using value_type = _Start;
using difference_type = _IotaDiffT<_Start>;
_Start __value_ = _Start();
_LIBCPP_HIDE_FROM_ABI __iterator()
requires default_initializable<_Start>
= default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Start __value) : __value_(std::move(__value)) {}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Start operator*() const
noexcept(is_nothrow_copy_constructible_v<_Start>) {
return __value_;
@ -282,11 +284,12 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> {
private:
_BoundSentinel __bound_sentinel_ = _BoundSentinel();
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(_BoundSentinel __bound_sentinel)
: __bound_sentinel_(std::move(__bound_sentinel)) {}
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __sentinel& __y) {
return __x.__value_ == __y.__bound_sentinel_;
}

View file

@ -66,9 +66,6 @@ public:
using difference_type = ptrdiff_t;
using value_type = _Val;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(basic_istream_view<_Val, _CharT, _Traits>& __parent) noexcept
: __parent_(std::addressof(__parent)) {}
__iterator(const __iterator&) = delete;
_LIBCPP_HIDE_FROM_ABI __iterator(__iterator&&) = default;
@ -91,9 +88,14 @@ public:
private:
basic_istream_view<_Val, _CharT, _Traits>* __parent_;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(basic_istream_view<_Val, _CharT, _Traits>& __parent) noexcept
: __parent_(std::addressof(__parent)) {}
_LIBCPP_HIDE_FROM_ABI constexpr basic_istream<_CharT, _Traits>* __get_parent_stream() const {
return __parent_->__stream_;
}
friend class basic_istream_view<_Val, _CharT, _Traits>;
};
template <class _Val>

View file

@ -160,11 +160,13 @@ private:
using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>;
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(_Parent& __parent) : __end_(ranges::end(__parent.__base_)) {}
friend class join_view<_View>;
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(_Parent& __parent) : __end_(ranges::end(__parent.__base_)) {}
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __s)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__s.__end_)) {}

View file

@ -143,6 +143,8 @@ private:
template <bool _Const>
struct __outer_iterator : __outer_iterator_category<__maybe_const<_Const, _View>> {
private:
friend class lazy_split_view<_View, _Pattern>;
template <bool>
friend struct __inner_iterator;
friend __outer_iterator<true>;
@ -155,6 +157,14 @@ private:
_LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent();
bool __trailing_empty_ = false;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __outer_iterator(_Parent& __parent)
requires(!forward_range<_Base>)
: __parent_(std::addressof(__parent)) {}
_LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator(_Parent& __parent, iterator_t<_Base> __current)
requires forward_range<_Base>
: __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto& __current() noexcept {
if constexpr (forward_range<_View>) {
return __current_;
@ -196,14 +206,6 @@ private:
_LIBCPP_HIDE_FROM_ABI __outer_iterator() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __outer_iterator(_Parent& __parent)
requires(!forward_range<_Base>)
: __parent_(std::addressof(__parent)) {}
_LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator(_Parent& __parent, iterator_t<_Base> __current)
requires forward_range<_Base>
: __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
_LIBCPP_HIDE_FROM_ABI constexpr __outer_iterator(__outer_iterator<!_Const> __i)
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
: __parent_(__i.__parent_), __current_(std::move(__i.__current_)) {}
@ -286,12 +288,16 @@ private:
template <bool _Const>
struct __inner_iterator : __inner_iterator_category<__maybe_const<_Const, _View>> {
private:
friend class lazy_split_view<_View, _Pattern>;
using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>;
// Workaround for a GCC issue.
static constexpr bool _OuterConst = _Const;
__outer_iterator<_Const> __i_ = __outer_iterator<_OuterConst>();
bool __incremented_ = false;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __inner_iterator(__outer_iterator<_Const> __i) : __i_(std::move(__i)) {}
// Note: these private functions are necessary because GCC doesn't allow calls to private members of `__i_` from
// free functions that are friends of `inner-iterator`.
@ -342,8 +348,6 @@ private:
_LIBCPP_HIDE_FROM_ABI __inner_iterator() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __inner_iterator(__outer_iterator<_Const> __i) : __i_(std::move(__i)) {}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_Base>& base() const& noexcept {
return __i_.__current();
}

View file

@ -127,6 +127,12 @@ private:
_LIBCPP_NO_UNIQUE_ADDRESS subrange<iterator_t<_View>> __next_ = subrange<iterator_t<_View>>();
bool __trailing_empty_ = false;
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(
split_view<_View, _Pattern>& __parent, iterator_t<_View> __current, subrange<iterator_t<_View>> __next)
: __parent_(std::addressof(__parent)), __cur_(std::move(__current)), __next_(std::move(__next)) {}
friend class split_view<_View, _Pattern>;
friend struct __sentinel;
public:
@ -137,10 +143,6 @@ public:
_LIBCPP_HIDE_FROM_ABI __iterator() = default;
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(
split_view<_View, _Pattern>& __parent, iterator_t<_View> __current, subrange<iterator_t<_View>> __next)
: __parent_(std::addressof(__parent)), __cur_(std::move(__current)), __next_(std::move(__next)) {}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() const { return __cur_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const { return {__cur_, __next_.begin()}; }
@ -179,16 +181,18 @@ struct split_view<_View, _Pattern>::__sentinel {
private:
_LIBCPP_NO_UNIQUE_ADDRESS sentinel_t<_View> __end_ = sentinel_t<_View>();
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(split_view<_View, _Pattern>& __parent)
: __end_(ranges::end(__parent.__base_)) {}
_LIBCPP_HIDE_FROM_ABI static constexpr bool __equals(const __iterator& __x, const __sentinel& __y) {
return __x.__cur_ == __y.__end_ && !__x.__trailing_empty_;
}
friend class split_view<_View, _Pattern>;
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(split_view<_View, _Pattern>& __parent)
: __end_(ranges::end(__parent.__base_)) {}
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __sentinel& __y) {
return __equals(__x, __y);
}

View file

@ -165,14 +165,16 @@ class take_view<_View>::__sentinel {
using _Iter _LIBCPP_NODEBUG = counted_iterator<iterator_t<__maybe_const<_OtherConst, _View>>>;
_LIBCPP_NO_UNIQUE_ADDRESS sentinel_t<_Base> __end_ = sentinel_t<_Base>();
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {}
friend class take_view<_View>;
template <bool>
friend class take_view<_View>::__sentinel;
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(std::move(__end)) {}
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __s)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__s.__end_)) {}

View file

@ -108,14 +108,16 @@ class take_while_view<_View, _Pred>::__sentinel {
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
const _Pred* __pred_ = nullptr;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end, const _Pred* __pred)
: __end_(std::move(__end)), __pred_(__pred) {}
friend class take_while_view<_View, _Pred>;
friend class __sentinel<!_Const>;
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end, const _Pred* __pred)
: __end_(std::move(__end)), __pred_(__pred) {}
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __s)
requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
: __end_(std::move(__s.__end_)), __pred_(__s.__pred_) {}

View file

@ -192,6 +192,11 @@ class transform_view<_View, _Fn>::__iterator
_Parent* __parent_ = nullptr;
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, iterator_t<_Base> __current)
: __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
friend class transform_view<_View, _Fn>;
template <bool>
friend class transform_view<_View, _Fn>::__iterator;
@ -209,9 +214,6 @@ public:
requires default_initializable<iterator_t<_Base>>
= default;
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, iterator_t<_Base> __current)
: __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
// Note: `__i` should always be `__iterator<false>`, but directly using
// `__iterator<false>` is ill-formed when `_Const` is false
// (see http://wg21.link/class.copy.ctor#5).
@ -354,6 +356,10 @@ class transform_view<_View, _Fn>::__sentinel {
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(__end) {}
friend class transform_view<_View, _Fn>;
template <bool>
friend class transform_view<_View, _Fn>::__iterator;
@ -363,8 +369,6 @@ class transform_view<_View, _Fn>::__sentinel {
public:
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) : __end_(__end) {}
// Note: `__i` should always be `__sentinel<false>`, but directly using
// `__sentinel<false>` is ill-formed when `_Const` is false
// (see http://wg21.link/class.copy.ctor#5).

View file

@ -37,17 +37,19 @@ LIBCPP_STATIC_ASSERT(!IsBaseNoexcept<ElementsIter&&>);
constexpr bool test() {
std::tuple<int> t{5};
std::ranges::elements_view<BaseView, 0> ev{BaseView{&t, &t + 1}};
// const &
{
const ElementsIter it{&t};
decltype(auto) base = it.base();
const ElementsIter it = ev.begin();
decltype(auto) base = it.base();
static_assert(std::is_same_v<decltype(base), std::tuple<int>* const&>);
assert(base == &t);
}
// &
{
ElementsIter it{&t};
ElementsIter it = ev.begin();
decltype(auto) base = it.base();
static_assert(std::is_same_v<decltype(base), std::tuple<int>* const&>);
assert(base == &t);
@ -55,7 +57,7 @@ constexpr bool test() {
// &&
{
ElementsIter it{&t};
ElementsIter it = ev.begin();
decltype(auto) base = std::move(it).base();
static_assert(std::is_same_v<decltype(base), std::tuple<int>*>);
assert(base == &t);
@ -63,8 +65,8 @@ constexpr bool test() {
// const &&
{
const ElementsIter it{&t};
decltype(auto) base = std::move(it).base();
const ElementsIter it = ev.begin();
decltype(auto) base = std::move(it).base();
static_assert(std::is_same_v<decltype(base), std::tuple<int>* const&>);
assert(base == &t);
}
@ -78,10 +80,10 @@ constexpr bool test() {
constexpr bool operator==(const MoveOnlyIter&) const { return true; }
};
using MoveOnlyElemIter =
std::ranges::iterator_t<std::ranges::elements_view<std::ranges::subrange<MoveOnlyIter, Sent>, 0>>;
std::ranges::elements_view<std::ranges::subrange<MoveOnlyIter, Sent>, 0> mev{
std::ranges::subrange{MoveOnlyIter{{}, MoveOnly{5}}, Sent{}}};
auto it = mev.begin();
MoveOnlyElemIter it{MoveOnlyIter{{}, MoveOnly{5}}};
decltype(auto) base = std::move(it).base();
static_assert(std::is_same_v<decltype(base), MoveOnlyIter>);
assert(base.mo.get() == 5);

View file

@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit iterator(iterator_t<Base> current);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <tuple>
#include <type_traits>
using BaseIter = std::tuple<int>*;
using ElementsIter = std::ranges::iterator_t<std::ranges::elements_view<std::ranges::subrange<BaseIter, BaseIter>, 0>>;
static_assert(!std::is_constructible_v<ElementsIter, BaseIter>);
static_assert(!std::is_convertible_v<BaseIter, ElementsIter>);

View file

@ -1,54 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr explicit iterator(iterator_t<Base> current);
#include <cassert>
#include <ranges>
#include <tuple>
#include "../types.h"
// Test explicit
using BaseIter = std::tuple<int>*;
using ElementsIter = std::ranges::iterator_t<std::ranges::elements_view<std::ranges::subrange<BaseIter, BaseIter>, 0>>;
static_assert(std::is_constructible_v<ElementsIter, BaseIter>);
static_assert(!std::is_convertible_v<BaseIter, ElementsIter>);
struct TracedMoveIter : IterBase<TracedMoveIter>{
bool moved = false;
constexpr TracedMoveIter() = default;
constexpr TracedMoveIter(const TracedMoveIter&) = default;
constexpr TracedMoveIter(TracedMoveIter&&) : moved{true} {}
constexpr TracedMoveIter& operator=(TracedMoveIter&&) = default;
constexpr TracedMoveIter& operator=(const TracedMoveIter&) = default;
};
struct TracedMoveView : std::ranges::view_base {
TracedMoveIter begin() const;
TracedMoveIter end() const;
};
constexpr bool test() {
using Iter = std::ranges::iterator_t<std::ranges::elements_view<TracedMoveView, 0>>;
Iter iter{TracedMoveIter{}};
assert(iter.base().moved);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View file

@ -57,8 +57,16 @@ static_assert(!std::is_constructible_v<ConstElemIter<NonConvertibleView>, ElemIt
static_assert(!std::is_constructible_v<ElemIter<NonConvertibleView>, ConstElemIter<NonConvertibleView>>);
constexpr bool test() {
ElemIter<ConvertibleView> iter{ConvertibleIter<false>{5}};
ConstElemIter<ConvertibleView> constIter = iter; // implicit
struct TestRange : std::ranges::view_base {
constexpr auto begin() { return ConvertibleIter<false>{5}; }
constexpr auto end() { return ConvertibleIter<false>{5}; }
constexpr auto begin() const { return ConvertibleIter<true>{5}; }
constexpr auto end() const { return ConvertibleIter<true>{5}; }
};
std::ranges::elements_view<TestRange, 0> ev{TestRange{}};
ElemIter<TestRange> iter = ev.begin();
ConstElemIter<TestRange> constIter = iter; // implicit
assert(constIter.base().movedFromOtherConst);
assert(constIter.base().i == 5);

View file

@ -17,7 +17,7 @@
#include <utility>
struct Sent {
int i;
int i = 5;
friend constexpr bool operator==(std::tuple<int>*, const Sent&) { return true; }
};
@ -27,7 +27,8 @@ constexpr bool test() {
using EleRange = std::ranges::elements_view<BaseRange, 0>;
using EleSent = std::ranges::sentinel_t<EleRange>;
const EleSent st{Sent{5}};
const EleRange ev;
const EleSent st = ev.end();
std::same_as<Sent> decltype(auto) base = st.base();
assert(base.i == 5);

View file

@ -6,14 +6,14 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(sentinel_t<Base> end);
#include <cassert>
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <tuple>
#include <utility>
#include <type_traits>
struct Sent {
int i;
@ -26,27 +26,7 @@ struct Range : std::ranges::view_base {
Sent end();
};
// Test explicit
using ElementsView = std::ranges::elements_view<Range, 0>;
static_assert(std::is_constructible_v<std::ranges::sentinel_t<std::ranges::elements_view<Range, 0>>, Sent>);
static_assert(!std::is_convertible_v<Sent, std::ranges::sentinel_t<std::ranges::elements_view<Range, 0>>>);
constexpr bool test() {
// base is init correctly
{
using R = std::ranges::elements_view<Range, 0>;
using Sentinel = std::ranges::sentinel_t<R>;
Sentinel s1(Sent{5});
assert(s1.base().i == 5);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}
static_assert(!std::is_constructible_v<std::ranges::sentinel_t<ElementsView>, Sent>);
static_assert(!std::is_convertible_v<Sent, std::ranges::sentinel_t<ElementsView>>);

View file

@ -67,12 +67,19 @@ static_assert(
constexpr bool test() {
// base is init correctly
{
using R = std::ranges::elements_view<Range, 0>;
struct TestRange : std::ranges::view_base {
constexpr std::tuple<int>* begin() const { return nullptr; }
constexpr Sent end() { return Sent{5}; }
constexpr ConstSent end() const { return ConstSent{5}; }
};
using R = std::ranges::elements_view<TestRange, 0>;
using Sentinel = std::ranges::sentinel_t<R>;
using ConstSentinel = std::ranges::sentinel_t<const R>;
static_assert(!std::same_as<Sentinel, ConstSentinel>);
Sentinel s1(Sent{5});
R r{TestRange{}};
Sentinel s1 = r.end();
ConstSentinel s2 = s1;
assert(s2.base().i == 5);
}

View file

@ -87,7 +87,9 @@ constexpr void test() {
for (std::ptrdiff_t n = 0; n != 5; ++n) {
FilterView view = make_filter_view(array.data(), array.data() + array.size(), AlwaysTrue{});
FilterIterator const iter(view, Iter(array.data() + n));
FilterIterator iter = view.begin();
for (std::ptrdiff_t i = 0; i < n; ++i)
++iter;
std::same_as<Iter> decltype(auto) result = iter.operator->();
assert(base(result) == array.data() + n);
assert(iter->x == n);

View file

@ -37,7 +37,7 @@ constexpr void test() {
// Test the const& version
{
FilterIterator const iter(view, Iter(array.data()));
FilterIterator const iter = view.begin();
Iter const& result = iter.base();
ASSERT_SAME_TYPE(Iter const&, decltype(iter.base()));
ASSERT_NOEXCEPT(iter.base());
@ -46,7 +46,7 @@ constexpr void test() {
// Test the && version
{
FilterIterator iter(view, Iter(array.data()));
FilterIterator iter = view.begin();
Iter result = std::move(iter).base();
ASSERT_SAME_TYPE(Iter, decltype(std::move(iter).base()));
assert(base(result) == array.data());

View file

@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr std::ranges::filter_view::<iterator>(filter_view&, iterator_t<V>);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include "test_iterators.h"
#include "../types.h"
using View = minimal_view<int*, sentinel_wrapper<int*>>;
using ViewIter = std::ranges::iterator_t<View>;
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
using FilterIterator = std::ranges::iterator_t<FilterView>;
static_assert(!std::constructible_from<FilterIterator, FilterView&, ViewIter>);

View file

@ -1,51 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr std::ranges::filter_view::<iterator>(filter_view&, iterator_t<V>);
#include <ranges>
#include <array>
#include <cassert>
#include <utility>
#include "test_iterators.h"
#include "../types.h"
template <class Iter, class Sent = sentinel_wrapper<Iter>>
constexpr void test() {
using View = minimal_view<Iter, Sent>;
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
using FilterIterator = std::ranges::iterator_t<FilterView>;
std::array<int, 10> array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
View view(Iter(array.data()), Sent(Iter(array.data() + array.size())));
Iter iter = view.begin();
FilterView filter_view(std::move(view), AlwaysTrue{});
FilterIterator filter_iter(filter_view, std::move(iter));
assert(base(filter_iter.base()) == array.data());
}
constexpr bool tests() {
test<cpp17_input_iterator<int*>>();
test<cpp20_input_iterator<int*>>();
test<forward_iterator<int*>>();
test<bidirectional_iterator<int*>>();
test<random_access_iterator<int*>>();
test<contiguous_iterator<int*>>();
test<int*>();
return true;
}
int main(int, char**) {
tests();
static_assert(tests());
return 0;
}

View file

@ -36,7 +36,9 @@ constexpr void test() {
FilterView view = make_filter_view(array.data(), array.data() + array.size(), AlwaysTrue{});
for (std::size_t n = 0; n != array.size(); ++n) {
FilterIterator const iter(view, Iter(array.data() + n));
FilterIterator iter = view.begin();
for (std::size_t i = 0; i < n; ++i)
++iter;
ValueType& result = *iter;
ASSERT_SAME_TYPE(ValueType&, decltype(*iter));
assert(&result == array.data() + n);

View file

@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(filter_view&);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include "test_iterators.h"
#include "../types.h"
using View = minimal_view<int*, sentinel_wrapper<int*>>;
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
using FilterSentinel = std::ranges::sentinel_t<FilterView>;
static_assert(!std::constructible_from<FilterSentinel, FilterView>);
static_assert(!std::convertible_to<FilterView, FilterSentinel>);

View file

@ -1,60 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr explicit sentinel(filter_view&);
#include <ranges>
#include <array>
#include <cassert>
#include <type_traits>
#include <utility>
#include "test_iterators.h"
#include "../types.h"
template <class Iter, class Sent = sentinel_wrapper<Iter>>
constexpr void test() {
using View = minimal_view<Iter, Sent>;
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
using FilterSentinel = std::ranges::sentinel_t<FilterView>;
auto make_filter_view = [](auto begin, auto end, auto pred) {
View view{Iter(begin), Sent(Iter(end))};
return FilterView(std::move(view), pred);
};
std::array<int, 5> array{0, 1, 2, 3, 4};
FilterView view = make_filter_view(array.data(), array.data() + array.size(), AlwaysTrue{});
FilterSentinel sent(view);
assert(base(base(sent.base())) == base(base(view.end().base())));
static_assert(!std::is_constructible_v<FilterSentinel, FilterView const&>);
static_assert(!std::is_constructible_v<FilterSentinel, FilterView>);
static_assert( std::is_constructible_v<FilterSentinel, FilterView&> &&
!std::is_convertible_v<FilterView&, FilterSentinel>);
}
constexpr bool tests() {
test<cpp17_input_iterator<int*>>();
test<cpp20_input_iterator<int*>>();
test<forward_iterator<int*>>();
test<bidirectional_iterator<int*>>();
test<random_access_iterator<int*>>();
test<contiguous_iterator<int*>>();
test<int*>();
return true;
}
int main(int, char**) {
tests();
static_assert(tests());
return 0;
}

View file

@ -0,0 +1,21 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(Parent& parent);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include "../types.h"
using Parent = std::ranges::join_view<ParentView<ChildView>>;
static_assert(!std::is_constructible_v<std::ranges::sentinel_t<Parent>, Parent&>);
static_assert(!std::is_convertible_v<std::ranges::sentinel_t<Parent>, Parent&>);

View file

@ -1,43 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr explicit sentinel(Parent& parent);
#include <cassert>
#include <ranges>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
int buffer[4][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
CopyableChild children[4] = {CopyableChild(buffer[0]), CopyableChild(buffer[1]), CopyableChild(buffer[2]), CopyableChild(buffer[3])};
CopyableParent parent{children};
std::ranges::join_view jv(parent);
std::ranges::sentinel_t<decltype(jv)> sent(jv);
assert(sent == std::ranges::next(jv.begin(), 16));
return true;
}
int main(int, char**) {
test();
static_assert(test());
{
// Test explicitness.
using Parent = std::ranges::join_view<ParentView<ChildView>>;
static_assert( std::is_constructible_v<std::ranges::sentinel_t<Parent>, Parent&>);
static_assert(!std::is_convertible_v<std::ranges::sentinel_t<Parent>, Parent&>);
}
return 0;
}

View file

@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit inner-iterator::inner-iterator(outer-iterator<Const> i);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include "../types.h"
static_assert(!std::is_constructible_v<InnerIterConst, OuterIterConst>);
static_assert(!std::is_convertible_v<InnerIterConst, OuterIterConst>);
static_assert(!std::is_constructible_v<InnerIterNonConst, OuterIterNonConst>);
static_assert(!std::is_convertible_v<InnerIterNonConst, OuterIterNonConst>);

View file

@ -1,43 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr explicit inner-iterator::inner-iterator(outer-iterator<Const> i);
#include <ranges>
#include "../types.h"
static_assert(!std::is_constructible_v<InnerIterNonConst, OuterIterConst>);
template <class Inner, class Outer>
constexpr void test_impl() {
[[maybe_unused]] Inner i(Outer{});
// Verify that the constructor is `explicit`.
static_assert(!std::is_convertible_v<Outer, Inner>);
}
constexpr bool test() {
test_impl<InnerIterForward, OuterIterForward>();
test_impl<InnerIterInput, OuterIterInput>();
// Is only constructible if both the outer and the inner iterators have the same constness.
test_impl<InnerIterConst, OuterIterConst>();
// Note: this works because of an implicit conversion (`OuterIterNonConst` is converted to `OuterIterConst`).
test_impl<InnerIterConst, OuterIterNonConst>();
test_impl<InnerIterNonConst, OuterIterNonConst>();
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View file

@ -6,31 +6,17 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: std-at-least-c++20
// constexpr outer-iterator(Parent& parent, iterator_t<Base> current);
// requires forward_range<Base>
#include <ranges>
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
#include <utility>
#include "../types.h"
static_assert(!std::ranges::forward_range<SplitViewInput>);
static_assert(!std::is_constructible_v<OuterIterInput, SplitViewInput&, std::ranges::iterator_t<InputView>>);
constexpr bool test() {
ForwardView input("abc");
SplitViewForward v(std::move(input), " ");
[[maybe_unused]] OuterIterForward i(v, input.begin());
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}
static_assert(std::ranges::forward_range<SplitViewForward>);
static_assert(!std::is_constructible_v<OuterIterForward, SplitViewForward&, std::ranges::iterator_t<ForwardView>>);

View file

@ -6,34 +6,18 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: std-at-least-c++20
// explicit std::ranges::lazy_split_view::outer-iterator::outer-iterator(Parent& parent)
// requires (!forward_range<Base>)
#include <ranges>
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
#include <utility>
#include "../types.h"
// Verify that the constructor is `explicit`.
static_assert(!std::ranges::forward_range<SplitViewInput>);
static_assert(!std::is_constructible_v<OuterIterInput, SplitViewInput&>);
static_assert(!std::is_convertible_v<SplitViewInput&, OuterIterInput>);
static_assert( std::ranges::forward_range<SplitViewForward>);
static_assert(!std::is_constructible_v<OuterIterForward, SplitViewForward&>);
constexpr bool test() {
InputView input;
SplitViewInput v(input, ForwardTinyView());
[[maybe_unused]] OuterIterInput i(v);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View file

@ -16,9 +16,20 @@
#include "../types.h"
struct Iter : ForwardIterBase<Iter> {
int i;
int i = 0;
constexpr Iter() = default;
constexpr Iter(int ii) : i(ii) {}
constexpr int operator*() const { return i; }
constexpr Iter& operator++() {
++i;
return *this;
}
constexpr Iter operator++(int) {
Iter tmp = *this;
++*this;
return tmp;
}
friend constexpr bool operator==(const Iter& x, const Iter& y) { return x.i == y.i; }
};
constexpr bool test() {
@ -26,34 +37,32 @@ constexpr bool test() {
using SplitView = std::ranges::split_view<std::ranges::subrange<Iter>, std::ranges::subrange<Iter>>;
using SplitIter = std::ranges::iterator_t<SplitView>;
SplitView sv{std::ranges::subrange<Iter>{Iter{5}, Iter{8}}, std::ranges::subrange<Iter>{Iter{8}, Iter{9}}};
// const &
{
SplitView sv;
const SplitIter it{sv, Iter{5}, {}};
const SplitIter it = sv.begin();
std::same_as<Iter> decltype(auto) base = it.base();
assert(base.i == 5);
}
// &
{
SplitView sv;
SplitIter it{sv, Iter{5}, {}};
SplitIter it = sv.begin();
std::same_as<Iter> decltype(auto) base = it.base();
assert(base.i == 5);
}
// &&
{
SplitView sv;
SplitIter it{sv, Iter{5}, {}};
SplitIter it = sv.begin();
std::same_as<Iter> decltype(auto) base = std::move(it).base();
assert(base.i == 5);
}
// const &&
{
SplitView sv;
const SplitIter it{sv, Iter{5}, {}};
const SplitIter it = sv.begin();
std::same_as<Iter> decltype(auto) base = std::move(it).base();
assert(base.i == 5);
}

View file

@ -6,12 +6,14 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: std-at-least-c++20
// constexpr iterator(split_view& parent, iterator_t<V> current, subrange<iterator_t<V>> next);
#include <cassert>
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
#include "../types.h"
@ -30,24 +32,7 @@ struct TracedMoveView : std::ranges::view_base {
constexpr TracedMoveIter end() const { return {}; }
};
constexpr bool test() {
using SplitView = std::ranges::split_view<TracedMoveView, TracedMoveView>;
using SplitIter = std::ranges::iterator_t<SplitView>;
using SplitView = std::ranges::split_view<TracedMoveView, TracedMoveView>;
using SplitIter = std::ranges::iterator_t<SplitView>;
SplitView sv{TracedMoveView{}, TracedMoveView{}};
SplitIter iter = {sv, sv.base().begin(), std::ranges::subrange<TracedMoveIter>{sv.base().begin(), sv.base().end()}};
assert(iter.base().moved);
auto subRange = *iter;
assert(subRange.begin().moved);
assert(subRange.end().moved);
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}
static_assert(!std::is_constructible_v<SplitIter, SplitView, TracedMoveIter, std::ranges::subrange<TracedMoveIter>>);

View file

@ -17,24 +17,31 @@
#include "../types.h"
struct Iter : ForwardIterBase<Iter> {
int i;
int i = 0;
constexpr Iter() = default;
constexpr Iter(int ii) : i(ii) {}
constexpr int operator*() const { return i; }
constexpr Iter& operator++() {
++i;
return *this;
}
constexpr Iter operator++(int) {
Iter tmp = *this;
++*this;
return tmp;
}
friend constexpr bool operator==(const Iter& x, const Iter& y) { return x.i == y.i; }
};
constexpr bool test() {
using SplitView = std::ranges::split_view<std::ranges::subrange<Iter>, std::ranges::subrange<Iter>>;
using SplitIter = std::ranges::iterator_t<SplitView>;
{
SplitView sv;
Iter current{5};
std::ranges::subrange next{Iter{6}, Iter{7}};
const SplitIter it{sv, current, next};
std::same_as<std::ranges::subrange<Iter>> decltype(auto) value = *it;
assert(value.begin().i == 5);
assert(value.end().i == 6);
}
SplitView sv{std::ranges::subrange<Iter>{Iter{5}, Iter{8}}, std::ranges::subrange<Iter>{Iter{7}, Iter{8}}};
const SplitIter it = sv.begin();
std::same_as<std::ranges::subrange<Iter>> decltype(auto) value = *it;
assert(value.begin().i == 5);
assert(value.end().i == 7);
return true;
}

View file

@ -6,44 +6,19 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(split_view& parent);
#include <cassert>
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
#include "test_iterators.h"
#include "../types.h"
// test explicit
using Range = std::ranges::subrange<int*, sentinel_wrapper<int*>>;
using SplitView = std::ranges::split_view<Range, std::ranges::single_view<int>>;
using SplitSent = std::ranges::sentinel_t<SplitView>;
static_assert(std::is_constructible_v<SplitSent, SplitView&>);
static_assert(!std::is_constructible_v<SplitSent, SplitView&>);
static_assert(!std::is_convertible_v<SplitView&, SplitSent>);
constexpr bool test() {
{
int buffer[] = {0, 1, 2};
Range input{buffer, sentinel_wrapper<int*>(buffer + 3)};
SplitView sv(input, -1);
auto it = sv.begin();
SplitSent sent(sv);
assert(sent != it);
++it;
assert(sent == it);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View file

@ -1,86 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr explicit sentinel(sentinel_t<Base> end, const Pred* pred);
#include <cassert>
#include <ranges>
#include <utility>
#include "../types.h"
struct Sent {
int i;
friend constexpr bool operator==(int* iter, const Sent& s) { return s.i > *iter; }
};
struct Range : std::ranges::view_base {
int* begin() const;
Sent end();
};
struct Pred {
bool operator()(int i) const;
};
// Test explicit
template <class T>
void conversion_test(T);
template <class T, class... Args>
concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };
static_assert(ImplicitlyConstructible<int, int>);
static_assert(std::is_constructible_v<std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>,
std::ranges::sentinel_t<Range>,
const Pred*>);
static_assert(!ImplicitlyConstructible<std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>,
std::ranges::sentinel_t<Range>,
const Pred*>);
constexpr bool test() {
// base is init correctly
{
using R = std::ranges::take_while_view<Range, bool (*)(int)>;
using Sentinel = std::ranges::sentinel_t<R>;
Sentinel s1(Sent{5}, nullptr);
assert(s1.base().i == 5);
}
// pred is init correctly
{
bool called = false;
auto pred = [&](int) {
called = true;
return false;
};
using R = std::ranges::take_while_view<Range, decltype(pred)>;
using Sentinel = std::ranges::sentinel_t<R>;
int i = 10;
int* iter = &i;
Sentinel s(Sent{0}, &pred);
bool b = iter == s;
assert(called);
assert(b);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View file

@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(sentinel_t<Base> end, const Pred* pred);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
struct Sent {
int i;
friend constexpr bool operator==(int* iter, const Sent& s) { return s.i > *iter; }
};
struct Range : std::ranges::view_base {
int* begin() const;
Sent end();
};
struct Pred {
bool operator()(int i) const;
};
using Sentinel = std::ranges::sentinel_t<std::ranges::take_while_view<Range, Pred>>;
static_assert(!std::is_constructible_v<Sentinel, std::ranges::sentinel_t<Range>, const Pred*>);

View file

@ -70,34 +70,48 @@ static_assert(!std::is_constructible_v<
constexpr bool test() {
// base is init correctly
{
using R = std::ranges::take_while_view<Range, bool (*)(int)>;
struct TestRng : std::ranges::view_base {
constexpr int* begin() const { return nullptr; }
constexpr Sent end() { return Sent{5}; }
constexpr ConstSent end() const { return ConstSent{5}; }
};
using R = std::ranges::take_while_view<TestRng, bool (*)(int)>;
using Sentinel = std::ranges::sentinel_t<R>;
using ConstSentinel = std::ranges::sentinel_t<const R>;
static_assert(!std::same_as<Sentinel, ConstSentinel>);
Sentinel s1(Sent{5}, nullptr);
R r{TestRng{}, nullptr};
Sentinel s1 = r.end();
ConstSentinel s2 = s1;
assert(s2.base().i == 5);
}
// pred is init correctly
{
struct TestRng : std::ranges::view_base {
constexpr int* begin() const { return nullptr; }
constexpr Sent end() { return Sent{0}; }
constexpr ConstSent end() const { return ConstSent{0}; }
};
bool called = false;
auto pred = [&](int) {
called = true;
return false;
};
using R = std::ranges::take_while_view<Range, decltype(pred)>;
using R = std::ranges::take_while_view<TestRng, decltype(pred)>;
using Sentinel = std::ranges::sentinel_t<R>;
using ConstSentinel = std::ranges::sentinel_t<const R>;
static_assert(!std::same_as<Sentinel, ConstSentinel>);
int i = 10;
int* iter = &i;
Sentinel s1(Sent{0}, &pred);
R r{TestRng{}, pred};
Sentinel s1 = r.end();
ConstSentinel s2 = s1;
int i = 10;
int* iter = &i;
[[maybe_unused]] bool b = iter == s2;
assert(called);
}
@ -111,20 +125,25 @@ constexpr bool test() {
constexpr bool operator==(int* iter) const { return i > *iter; }
};
struct Rng : std::ranges::view_base {
int* begin() const;
Sent end();
MoveOnlyConvert end() const;
struct TestPred {
constexpr bool operator()(int) const { return false; }
};
using R = std::ranges::take_while_view<Rng, Pred>;
struct Rng : std::ranges::view_base {
constexpr int* begin() const { return nullptr; }
constexpr Sent end() { return Sent{0}; }
constexpr MoveOnlyConvert end() const { return MoveOnlyConvert(Sent{0}); }
};
using R = std::ranges::take_while_view<Rng, TestPred>;
using Sentinel = std::ranges::sentinel_t<R>;
using ConstSentinel = std::ranges::sentinel_t<const R>;
static_assert(!std::same_as<Sentinel, ConstSentinel>);
Sentinel s1(Sent{5}, nullptr);
R r{Rng{}, TestPred{}};
Sentinel s1 = r.end();
ConstSentinel s2 = s1;
assert(s2.base().i == 5);
assert(s2.base().i == 0);
}
return true;

View file

@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(sentinel_t<Base> end);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
#include "test_iterators.h"
#include "../types.h"
using TakeView = std::ranges::take_view<MoveOnlyView>;
using Sentinel = std::ranges::sentinel_t<TakeView>;
static_assert(!std::is_constructible_v<Sentinel, sentinel_wrapper<int*>>);
static_assert(!std::is_convertible_v<sentinel_wrapper<int*>, Sentinel>);

View file

@ -9,7 +9,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// sentinel() = default;
// constexpr explicit sentinel(sentinel_t<Base> end);
// constexpr sentinel(sentinel<!Const> s)
// requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
@ -49,18 +48,6 @@ constexpr bool test() {
assert(std::as_const(tv).begin() + 4 == cs);
}
{
// Test the constructor from "base-sentinel" to "sentinel".
using TakeView = std::ranges::take_view<MoveOnlyView>;
using Sentinel = std::ranges::sentinel_t<TakeView>;
sentinel_wrapper<int*> sw1 = MoveOnlyView(buffer).end();
static_assert(std::is_constructible_v<Sentinel, sentinel_wrapper<int*>>);
static_assert(!std::is_convertible_v<sentinel_wrapper<int*>, Sentinel>);
auto s = Sentinel(sw1);
std::same_as<sentinel_wrapper<int*>> auto sw2 = s.base();
assert(base(sw2) == base(sw1));
}
return true;
}

View file

@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr iterator(Parent& parent, iterator_t<Base> current);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include "../types.h"
using TransformView = std::ranges::transform_view<MoveOnlyView, PlusOne>;
using TransformViewBaseIter = std::ranges::iterator_t<MoveOnlyView>;
using TransformIter = std::ranges::iterator_t<TransformView>;
static_assert(!std::is_constructible_v<TransformIter, TransformView&, TransformViewBaseIter>);

View file

@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(sentinel_t<Base> end);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include "test_iterators.h"
#include "../types.h"
using BaseSent = std::ranges::sentinel_t<SizedSentinelView>;
using TransformView = std::ranges::transform_view<SizedSentinelView, PlusOne>;
using TransformSent = std::ranges::sentinel_t<TransformView>;
static_assert(!std::is_constructible_v<TransformSent, BaseSent>);
static_assert(!std::is_convertible_v<BaseSent, TransformSent>);

View file

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit iterator(W value);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
#include "../types.h"
static_assert(!std::is_constructible_v<std::ranges::iterator_t<std::ranges::iota_view<int>>, int>);
using Iter = std::ranges::iterator_t<std::ranges::iota_view<SomeInt>>;
static_assert(!std::is_constructible_v<Iter, SomeInt>);
static_assert(!std::is_convertible_v<SomeInt, Iter>);

View file

@ -1,45 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr explicit iterator(W value);
#include <cassert>
#include <ranges>
#include <type_traits>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
{
using Iter = std::ranges::iterator_t<std::ranges::iota_view<int>>;
auto iter = Iter(42);
assert(*iter == 42);
}
{
using Iter = std::ranges::iterator_t<std::ranges::iota_view<SomeInt>>;
auto iter = Iter(SomeInt(42));
assert(*iter == SomeInt(42));
}
{
using Iter = std::ranges::iterator_t<std::ranges::iota_view<SomeInt>>;
static_assert(!std::is_convertible_v<Iter, SomeInt>);
static_assert( std::is_constructible_v<Iter, SomeInt>);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View file

@ -0,0 +1,22 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// constexpr explicit sentinel(Bound bound);
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <type_traits>
#include "../types.h"
using Sent = std::ranges::sentinel_t<std::ranges::iota_view<SomeInt, IntSentinelWith<SomeInt>>>;
static_assert(!std::is_constructible_v<Sent, IntSentinelWith<SomeInt>>);
static_assert(!std::is_convertible_v<IntSentinelWith<SomeInt>, Sent>);

View file

@ -1,47 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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
// constexpr explicit sentinel(Bound bound);
#include <cassert>
#include <ranges>
#include <type_traits>
#include "test_macros.h"
#include "../types.h"
constexpr bool test() {
{
using Sent = std::ranges::sentinel_t<std::ranges::iota_view<int, IntSentinelWith<int>>>;
using Iter = std::ranges::iterator_t<std::ranges::iota_view<int, IntSentinelWith<int>>>;
auto sent = Sent(IntSentinelWith<int>(42));
assert(sent == Iter(42));
}
{
using Sent = std::ranges::sentinel_t<std::ranges::iota_view<SomeInt, IntSentinelWith<SomeInt>>>;
using Iter = std::ranges::iterator_t<std::ranges::iota_view<SomeInt, IntSentinelWith<SomeInt>>>;
auto sent = Sent(IntSentinelWith<SomeInt>(SomeInt(42)));
assert(sent == Iter(SomeInt(42)));
}
{
using Sent = std::ranges::sentinel_t<std::ranges::iota_view<SomeInt, IntSentinelWith<SomeInt>>>;
static_assert(!std::is_convertible_v<Sent, IntSentinelWith<SomeInt>>);
static_assert( std::is_constructible_v<Sent, IntSentinelWith<SomeInt>>);
}
return true;
}
int main(int, char**) {
test();
static_assert(test());
return 0;
}

View file

@ -39,10 +39,9 @@ void test() {
// LWG 3568. basic_istream_view needs to initialize value_
{
auto iss = make_string_stream<CharT>("123");
auto iss = make_string_stream<CharT>("");
std::ranges::basic_istream_view<int, CharT> isv{iss};
using Iter = std::ranges::iterator_t<decltype(isv)>;
Iter iter{isv};
auto iter = isv.begin();
assert(*iter == 0);
}
}

View file

@ -6,18 +6,18 @@
//
//===----------------------------------------------------------------------===//
// REQUIRES: std-at-least-c++20
// UNSUPPORTED: no-localization
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr explicit iterator(basic_istream_view& parent) noexcept;
#include <cassert>
// The constructor is now `private` (exposition-only) per P3059R2.
#include <ranges>
#include <sstream>
#include <type_traits>
#include "test_macros.h"
#include "../utils.h"
// test that the constructor is explicit
template <class CharT>
@ -25,34 +25,10 @@ using IstreamView = std::ranges::basic_istream_view<int, CharT>;
template <class CharT>
using Iter = std::ranges::iterator_t<IstreamView<CharT>>;
static_assert(std::constructible_from<Iter<char>, IstreamView<char>&>);
static_assert(!std::constructible_from<Iter<char>, IstreamView<char>&>);
static_assert(!std::convertible_to<IstreamView<char>&, Iter<char>>);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
static_assert(std::constructible_from<Iter<wchar_t>, IstreamView<wchar_t>&>);
static_assert(!std::constructible_from<Iter<wchar_t>, IstreamView<wchar_t>&>);
static_assert(!std::convertible_to<IstreamView<wchar_t>&, Iter<wchar_t>>);
#endif
// test that the constructor is noexcept
static_assert(std::is_nothrow_constructible_v<Iter<char>, IstreamView<char>&>);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
static_assert(std::is_nothrow_constructible_v<Iter<wchar_t>, IstreamView<wchar_t>&>);
#endif
template <class CharT>
void test() {
auto iss = make_string_stream<CharT>("123");
std::ranges::basic_istream_view<int, CharT> isv{iss};
Iter<CharT> it{isv};
++it;
assert(*it == 123);
}
int main(int, char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif
return 0;
}

View file

@ -35,8 +35,8 @@ void test() {
std::ranges::basic_istream_view<int, CharT> isv{iss};
using Iter = std::ranges::iterator_t<decltype(isv)>;
Iter it1{isv};
Iter it2{isv};
Iter it1 = isv.begin();
Iter it2 = isv.begin();
assert(&*it1 == &*it2);
}
}