Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt LWG-3533 Make base() const & consistent across iterator wrappers that support input_iterators #1993

Merged
merged 8 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,7 @@ namespace ranges {
#endif // _ITERATOR_DEBUG_LEVEL != 0
}

_NODISCARD constexpr iterator_t<_Vw> base() const& noexcept(is_nothrow_copy_constructible_v<
_NODISCARD constexpr const iterator_t<_Vw>& base() const& noexcept(is_nothrow_copy_constructible_v<
iterator_t<_Vw>>) /* strengthened */ requires copyable<iterator_t<_Vw>> {
miscco marked this conversation as resolved.
Show resolved Hide resolved
return _Current;
}
Expand Down Expand Up @@ -1433,7 +1433,7 @@ namespace ranges {
: _Current{_STD move(_It._Current)}, _Parent{_It._Parent} {}
// clang-format on

_NODISCARD constexpr iterator_t<_Base> base() const& noexcept(is_nothrow_copy_constructible_v<
_NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept(is_nothrow_copy_constructible_v<
iterator_t<_Base>>) /* strengthened */ requires copyable<iterator_t<_Base>> {
miscco marked this conversation as resolved.
Show resolved Hide resolved
return _Current;
}
Expand Down Expand Up @@ -3775,7 +3775,7 @@ namespace ranges {
: _Current{_STD move(_It._Current)} {}
// clang-format on

_NODISCARD constexpr iterator_t<_Base> base() const& noexcept(
_NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept(
is_nothrow_copy_constructible_v<iterator_t<_Base>>) /* strengthened */
requires copyable<iterator_t<_Base>> {
miscco marked this conversation as resolved.
Show resolved Hide resolved
return _Current;
Expand Down
2 changes: 2 additions & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ tests\P0896R4_views_elements
tests\P0896R4_views_empty
tests\P0896R4_views_filter
tests\P0896R4_views_filter_death
tests\P0896R4_views_filter_iterator
tests\P0896R4_views_iota
tests\P0896R4_views_join
tests\P0896R4_views_reverse
Expand All @@ -395,6 +396,7 @@ tests\P0896R4_views_take_while
tests\P0896R4_views_take_while_death
tests\P0896R4_views_transform
tests\P0896R4_views_transform_death
tests\P0896R4_views_transform_iterator
tests\P0898R3_concepts
tests\P0898R3_identity
tests\P0912R5_coroutine
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_views_filter_iterator/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\strict_concepts_latest_matrix.lst
miscco marked this conversation as resolved.
Show resolved Hide resolved
187 changes: 187 additions & 0 deletions tests/std/tests/P0896R4_views_filter_iterator/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <cassert>
#include <ranges>
#include <type_traits>
#include <utility>

#include <range_algorithm_support.hpp>
using namespace std;

#if _ITERATOR_DEBUG_LEVEL == 0
#define NOEXCEPT_IDL0(...) noexcept(__VA_ARGS__)
#else
#define NOEXCEPT_IDL0(...) true
#endif // _ITERATOR_DEBUG_LEVEL == 0
miscco marked this conversation as resolved.
Show resolved Hide resolved

constexpr auto is_even = [](const auto& x) { return x % 2 == 0; };
miscco marked this conversation as resolved.
Show resolved Hide resolved
using Pred = remove_const_t<decltype(is_even)>;

struct iterator_instantiator {
template <input_iterator Iter>
static constexpr void call() {
// Pre: Iter is a specialization of test::iterator whose element type is const int
int mutable_ints[] = {0, 1, 2, 3, 4, 5, 6, 7};
const auto make_view = [&] {
return views::filter(
ranges::subrange{Iter{mutable_ints}, test::sentinel<int>{ranges::end(mutable_ints)}}, is_even);
};
using R = decltype(make_view());
using I = ranges::iterator_t<R>;
using S = ranges::sentinel_t<R>;

// Validate nested types
static_assert(is_same_v<typename I::iterator_concept,
conditional_t<bidirectional_iterator<Iter>, bidirectional_iterator_tag,
conditional_t<forward_iterator<Iter>, forward_iterator_tag, input_iterator_tag>>>);

using C = typename iterator_traits<Iter>::iterator_category;
static_assert(is_same_v<typename I::iterator_category,
conditional_t<derived_from<C, bidirectional_iterator_tag>, bidirectional_iterator_tag,
conditional_t<derived_from<C, forward_iterator_tag>, forward_iterator_tag, input_iterator_tag>>>);

{ // Validate iterator special member functions and base
I defaultConstructed{};
assert(std::move(defaultConstructed).base().peek() == nullptr);
static_assert(is_nothrow_default_constructible_v<I>);

auto r0 = make_view();
I valueConstructed{r0, Iter{mutable_ints}};
static_assert(is_nothrow_constructible_v<I, R&, Iter>);

if constexpr (copyable<Iter>) {
I copyConstructed{valueConstructed};
assert(copyConstructed == valueConstructed);
static_assert(is_nothrow_copy_constructible_v<I>);

defaultConstructed = copyConstructed;
assert(defaultConstructed == valueConstructed);
static_assert(is_nothrow_copy_assignable_v<I>);
static_assert(same_as<const Iter&, decltype(as_const(copyConstructed).base())>);
}
assert(std::move(valueConstructed).base().peek() == mutable_ints);
static_assert(same_as<Iter, decltype(move(valueConstructed).base())>);
}

{ // Validate sentinel constructors and base
S defaultConstructed{};
assert(defaultConstructed.base().peek() == nullptr);
static_assert(is_nothrow_default_constructible_v<S>);

auto r0 = make_view();
S valueConstructed{r0};
assert(valueConstructed.base().peek() == end(mutable_ints));

S copyConstructed{valueConstructed};
assert(copyConstructed.base().peek() == valueConstructed.base().peek());
static_assert(is_nothrow_copy_constructible_v<S>);

defaultConstructed = copyConstructed;
assert(defaultConstructed.base().peek() == valueConstructed.base().peek());
static_assert(is_nothrow_copy_assignable_v<S>);
}

{ // Validate dereference ops
auto r0 = make_view();
auto i0 = r0.begin();
assert(*i0 == 0);
static_assert(NOEXCEPT_IDL0(*i0));

assert(ranges::iter_move(i0) == 0); // NB: moving from int leaves it unchanged
// static_assert(NOEXCEPT_IDL0(ranges::iter_move(i0)));

if constexpr (forward_iterator<Iter>) {
auto i1 = ranges::next(i0);
ranges::iter_swap(i0, i1);
assert(mutable_ints[0] == 2);
assert(mutable_ints[2] == 0);
ranges::iter_swap(i1, i0);
assert(mutable_ints[0] == 0);
assert(mutable_ints[2] == 2);
static_assert(NOEXCEPT_IDL0(ranges::iter_swap(i0, i1)));
}
}

{ // Validate increments
auto r0 = make_view();
auto i0 = r0.begin();
assert(&++i0 == &i0);
assert(std::move(i0).base().peek() == mutable_ints + 2);

auto r1 = make_view();
auto i1 = r1.begin();
if constexpr (forward_iterator<Iter>) {
assert(i1++ == r1.begin());
} else {
i1++;
}
assert(std::move(i1).base().peek() == mutable_ints + 2);
}

if constexpr (bidirectional_iterator<Iter>) { // Validate decrements
auto r = make_view();
const auto second = ranges::next(r.begin());
auto i = second;
assert(&--i == &i);
assert(i.base().peek() == mutable_ints);

i = second;
assert(i-- == second);
assert(i.base().peek() == mutable_ints);
}

if constexpr (equality_comparable<Iter>) {
// Validate == and !=
auto r = make_view();
const auto first = r.begin();
const auto last = r.end();

assert(first == first);
assert(I{} == I{});

assert(!(first == last));
assert(!(last == first));

assert(!(first != first));
assert(!(I{} != I{}));

if constexpr (forward_iterator<Iter>) {
const auto final = ranges::next(first, last);
assert(!(first == final));
assert(first != final);

assert(last == final);
assert(final == last);

assert(!(last != final));
assert(!(final != last));
}
}
}
};

template <class Category, test::CanDifference Diff>
using test_iterator =
test::iterator<Category, int, Diff, test::CanCompare{derived_from<Category, forward_iterator_tag>},
test::ProxyRef{!derived_from<Category, contiguous_iterator_tag>}>;

constexpr void iterator_instantiation_test() {
using test::CanDifference;

iterator_instantiator::call<test_iterator<input_iterator_tag, CanDifference::no>>();

iterator_instantiator::call<test_iterator<forward_iterator_tag, CanDifference::no>>();
iterator_instantiator::call<test_iterator<forward_iterator_tag, CanDifference::yes>>();

iterator_instantiator::call<test_iterator<bidirectional_iterator_tag, CanDifference::no>>();
iterator_instantiator::call<test_iterator<bidirectional_iterator_tag, CanDifference::yes>>();

iterator_instantiator::call<test_iterator<random_access_iterator_tag, CanDifference::yes>>();
iterator_instantiator::call<test_iterator<contiguous_iterator_tag, CanDifference::yes>>();
}

int main() {
static_assert((iterator_instantiation_test(), true));
iterator_instantiation_test();
}
Loading