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

Implement common_iterator #1092

Merged
merged 44 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
759153f
Implement common_iterator
miscco Jul 25, 2020
e1fca3b
Fix swap implementation of death test
miscco Jul 26, 2020
24b54ac
Add tests for iter_traits
miscco Jul 26, 2020
ea8bd71
Fix swapped constructors
miscco Jul 27, 2020
b683fda
Add indirection for common_iterator pointer type
miscco Jul 27, 2020
d0787c2
Some test fixes
miscco Jul 27, 2020
7246ac4
Fix death tests more
miscco Jul 27, 2020
967faa0
Fix assignment operator
miscco Jul 28, 2020
5793a21
Writing is hard
miscco Jul 28, 2020
487123e
Swapping elements of a const range...
miscco Jul 28, 2020
634fbde
typename
miscco Jul 28, 2020
9d9a8ff
Actually test the common_iterator
miscco Jul 28, 2020
948b810
Ramp up exception safety
miscco Jul 29, 2020
c01e72d
Merge branch 'master' into common_iterator
miscco Jul 29, 2020
27e7a8a
Guard _Nontrivial_dummy_type by C++17
miscco Jul 29, 2020
56a5f01
Fix typo
miscco Jul 29, 2020
5830ada
Merge branch 'master' into common_iterator
miscco Jul 30, 2020
78aa4b7
Cleanup death tests as we cannot test throwing iteratos currently
miscco Jul 30, 2020
4fe35d3
Apply STLs review comments
miscco Jul 31, 2020
d038ce7
Fix noexcept
miscco Jul 31, 2020
b40233d
Remove // strengthened from default constructor
miscco Jul 31, 2020
979900c
Remove unneeded exception handling in case of the same alternative
miscco Jul 31, 2020
b64c7c8
Move common_iterator to <iterator> and the helpers to top
miscco Jul 31, 2020
5497ebb
Add winsdk_concepts_matrix.lst for counted_iterator death test
CaseyCarter Aug 4, 2020
bca3712
Minor cleanup
miscco Aug 4, 2020
00f8f4a
Merge branch 'master' into common_iterator
miscco Aug 15, 2020
cf843f7
Implement move assignment/construction
miscco Aug 16, 2020
1e55afc
Make common_iterator explicitly default constructed
miscco Aug 17, 2020
b0f9193
Factor variant-like type out of common_iterator
CaseyCarter Aug 17, 2020
5cb0827
WIP
CaseyCarter Aug 17, 2020
6b34db2
WIP
CaseyCarter Aug 17, 2020
23865b8
Avoid VSO-1174090 in _Variantish
CaseyCarter Aug 18, 2020
2a99dbe
Return _Nontrivial_dummy_type to <optional>
CaseyCarter Aug 18, 2020
73ed871
Properly constrain test::iterator::iter_swap
CaseyCarter Aug 18, 2020
df4b5c3
Remove commented-out warning suppression
CaseyCarter Aug 19, 2020
f245661
Remove unneeded C++17 guard
miscco Aug 19, 2020
c86f4ea
Merge branch 'master' into common_iterator
miscco Aug 28, 2020
a41d984
Address review comments and experiment with conversions
miscco Aug 28, 2020
91922ed
Conversions actually work
miscco Aug 28, 2020
1e1a890
Create a tag type to test valueless common_iterator in death tests
miscco Aug 29, 2020
cd1eb5c
Test operator->() for wrapped and proxy iterators
miscco Aug 31, 2020
1a7e598
Add tests for the first codepathes of operator->
miscco Aug 31, 2020
e9d82a6
Casey's review comments
CaseyCarter Sep 3, 2020
aa63981
STL's review comments
CaseyCarter Sep 4, 2020
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
505 changes: 505 additions & 0 deletions stl/inc/iterator

Large diffs are not rendered by default.

7 changes: 0 additions & 7 deletions stl/inc/xmemory
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,6 @@ void _Deallocate(void* _Ptr, size_t _Bytes) noexcept {

#undef _HAS_ALIGNED_NEW

// FUNCTION TEMPLATE _Construct_in_place
template <class _Ty, class... _Types>
void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) {
::new (const_cast<void*>(static_cast<const volatile void*>(_STD addressof(_Obj))))
_Ty(_STD forward<_Types>(_Args)...);
}

// FUNCTION TEMPLATE _Global_new
template <class _Ty, class... _Types>
_Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection
Expand Down
15 changes: 11 additions & 4 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@ struct _Get_rebind_alias<_Ty, _Other, void_t<typename _Ty::template rebind<_Othe
using type = typename _Ty::template rebind<_Other>;
};

// FUNCTION TEMPLATE _Construct_in_place
template <class _Ty, class... _Types>
void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) {
::new (const_cast<void*>(static_cast<const volatile void*>(_STD addressof(_Obj))))
_Ty(_STD forward<_Types>(_Args)...);
}

// STRUCT TEMPLATE pointer_traits
template <class _Ty>
struct pointer_traits {
Expand Down Expand Up @@ -2327,6 +2334,10 @@ _NODISCARD _Ty _Fake_decay_copy(_Ty) noexcept;
// (2) is well-formed if and only if E is implicitly convertible to T and T is destructible, and
// (3) is non-throwing if and only if both conversion from decltype((E)) to T and destruction of T are non-throwing.

// CONCEPT _Not_same_as
template <class _Ty1, class _Ty2>
concept _Not_same_as = !same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>;

namespace ranges {
// VARIABLE TEMPLATE _Has_complete_elements
template <class>
Expand Down Expand Up @@ -3394,10 +3405,6 @@ namespace ranges {
using is_transparent = int;
};

// CONCEPT _Not_same_as
template <class _Ty1, class _Ty2>
concept _Not_same_as = !same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>;

// CONCEPT ranges::common_range
// clang-format off
template <class _Rng>
Expand Down
14 changes: 12 additions & 2 deletions tests/std/include/range_algorithm_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,16 @@ namespace test {

using _Prevent_inheriting_unwrap = sentinel;

using unwrap = sentinel<Element, IsWrapped::no>;
using unwrap = sentinel<Element, IsWrapped::no>;
using Constinel = sentinel<const Element, Wrapped>;

constexpr operator Constinel() && noexcept {
return Constinel{exchange(ptr_, nullptr)};
}

constexpr operator Constinel() const& noexcept {
return Constinel{ptr_};
}

// clang-format off
[[nodiscard]] constexpr auto _Unwrapped() const noexcept requires (to_bool(Wrapped)) {
Expand Down Expand Up @@ -424,7 +433,8 @@ namespace test {
return std::move(*i.ptr_);
}

constexpr friend void iter_swap(iterator const& x, iterator const& y) requires at_least<input> {
constexpr friend void iter_swap(
iterator const& x, iterator const& y) requires at_least<input> && std::swappable<Element> {
ranges::iter_swap(x.ptr_, y.ptr_);
}

Expand Down
2 changes: 2 additions & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ tests\P0768R1_spaceship_operator
tests\P0769R2_shift_left_shift_right
tests\P0784R7_library_support_for_more_constexpr_containers
tests\P0811R3_midpoint_lerp
tests\P0896R4_common_iterator
tests\P0896R4_common_iterator_death
tests\P0896R4_counted_iterator
tests\P0896R4_counted_iterator_death
tests\P0896R4_P1614R2_comparisons
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_common_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_matrix.lst
201 changes: 201 additions & 0 deletions tests/std/tests/P0896R4_common_iterator/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <cassert>
#include <concepts>
#include <iterator>
#include <type_traits>
#include <utility>
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved

#include <range_algorithm_support.hpp>
using namespace std;
using P = pair<int, int>;

// clang-format off
template <class Iter>
concept CanDifference = requires(Iter it) {
{ it - it };
};

template <class Iter>
concept HasProxy = !is_reference_v<iter_reference_t<Iter>>;
// clang-format on

struct instantiator {
template <input_or_output_iterator Iter>
static constexpr void call() {
if constexpr (copyable<Iter>) {
using ConstIter = typename Iter::Consterator;
using Sen = test::sentinel<iter_value_t<Iter>>;
using OSen = test::sentinel<const iter_value_t<Iter>>;
using Cit = common_iterator<Iter, Sen>;
using OCit = common_iterator<ConstIter, OSen>;
P input[3] = {{0, 1}, {0, 2}, {0, 3}};

// [common.iter.types]
{
using iconcept = typename iterator_traits<Cit>::iterator_concept;
if constexpr (forward_iterator<Iter>) {
STATIC_ASSERT(same_as<iconcept, forward_iterator_tag>);
} else {
STATIC_ASSERT(same_as<typename iterator_traits<Cit>::iterator_concept, input_iterator_tag>);
}

using icat = typename iterator_traits<Cit>::iterator_category;
if constexpr (derived_from<icat, forward_iterator_tag>) {
STATIC_ASSERT(same_as<icat, forward_iterator_tag>);
} else {
STATIC_ASSERT(same_as<icat, input_iterator_tag>);
}

using ipointer = typename iterator_traits<Cit>::pointer;
if constexpr (_Has_op_arrow<Iter>) {
STATIC_ASSERT(same_as<ipointer, decltype(declval<const Iter&>().operator->())>);
} else {
STATIC_ASSERT(same_as<ipointer, void>);
}
}

{ // [common.iter.const]
Cit defaultConstructed{};
Cit iterConstructed{Iter{input}};
Cit sentinelConstructed(Sen{});
Cit copyConstructed{defaultConstructed};
copyConstructed = iterConstructed;

OCit conversionConstructed{defaultConstructed};
conversionConstructed = iterConstructed;

OCit conversionConstructedSentinel{sentinelConstructed};
conversionConstructed = iterConstructed;
}
miscco marked this conversation as resolved.
Show resolved Hide resolved
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved

{ // [common.iter.access]
Cit iter{Iter{input}};
assert(*iter == P(0, 1));
assert(iter->first == 0);
assert(iter->second == 1);
if constexpr (HasProxy<Iter>) {
// We return a proxy class here
static_assert(is_class_v<decltype(iter.operator->())>);
} else {
// Either a pointer or the wrapped iterator
static_assert(!is_class_v<decltype(iter.operator->())>);
}

const Cit constIter{Iter{input}};
assert(*constIter == P(0, 1));
assert(constIter->first == 0);
assert(constIter->second == 1);
if constexpr (HasProxy<Iter>) {
// We return a proxy class here
static_assert(is_class_v<decltype(constIter.operator->())>);
} else {
// Either a pointer or the wrapped iterator
static_assert(!is_class_v<decltype(constIter.operator->())>);
}
}
miscco marked this conversation as resolved.
Show resolved Hide resolved

{ // [common.iter.nav]
Cit iter{Iter{input}};
++iter;
assert(*iter == P(0, 2));

assert(*iter++ == P(0, 2));
assert(*iter == P(0, 3));
}

{ // [common.iter.cmp]
// Compare iterator / iterator
assert(Cit{Iter{input}} == Cit{Iter{input}});
assert(Cit{Iter{input}} != Cit{Iter{input + 1}});

// Compare iterator / sentinel
assert(Cit{Iter{input}} == Cit{Sen{input}});
assert(Cit{Sen{input}} != Cit{Iter{input + 1}});

// Compare sentinel / sentinel
assert(Cit{Sen{input}} == Cit{Sen{input}});
assert(Cit{Sen{input}} == Cit{Sen{input + 1}});

if constexpr (CanDifference<Iter>) {
// Difference iterator / iterator
const same_as<iter_difference_t<Iter>> auto diff_it_it = Cit{Iter{input}} - Cit{Iter{input + 1}};
assert(diff_it_it == -1);

// Difference iterator / sentinel
const same_as<iter_difference_t<Iter>> auto diff_it_sen = Cit{Iter{input}} - Cit{Sen{input + 1}};
const same_as<iter_difference_t<Iter>> auto diff_sen_it = Cit{Sen{input + 1}} - Cit{Iter{input}};
assert(diff_it_sen == -1);
assert(diff_sen_it == 1);

// Difference sentinel / sentinel
const same_as<iter_difference_t<Iter>> auto diff_sen_sen = Cit{Sen{input}} - Cit{Sen{input + 1}};
assert(diff_sen_sen == 0);

// Difference iterator / other iterator
const same_as<iter_difference_t<Iter>> auto diff_it_oit = Cit{Iter{input}} - OCit{Iter{input + 1}};
assert(diff_it_oit == -1);

// Difference iterator / other sentinel
const same_as<iter_difference_t<Iter>> auto diff_it_osen = Cit{Iter{input}} - OCit{OSen{input + 1}};
assert(diff_it_osen == -1);

// Difference other iterator / sentinel
const same_as<iter_difference_t<Iter>> auto diff_sen_oit = Cit{Sen{input + 1}} - OCit{Iter{input}};
assert(diff_sen_oit == 1);

// Difference sentinel / other sentinel
const same_as<iter_difference_t<Iter>> auto diff_sen_osen = Cit{Sen{input}} - OCit{OSen{input + 1}};
assert(diff_sen_osen == 0);
}
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
}

miscco marked this conversation as resolved.
Show resolved Hide resolved
{ // [common.iter.cust]
if constexpr (input_iterator<Iter>) { // iter_move
Cit iter1{Iter{input}};

const same_as<iter_value_t<Iter>> auto element1 = ranges::iter_move(iter1);
assert(element1 == P(0, 1));
}

if constexpr (indirectly_swappable<Iter>) { // iter_swap
CaseyCarter marked this conversation as resolved.
Show resolved Hide resolved
Cit iter1{Iter{input}};
Cit iter2{Iter{input + 1}};

ranges::iter_swap(iter1, iter2);
assert(*iter1 == P(0, 2));
assert(*iter2 == P(0, 1));
}
}
}
}
};

bool test_operator_arrow() {
P input[3] = {{0, 1}, {0, 2}, {0, 3}};

using pointerTest = common_iterator<P*, void*>;
pointerTest pointerIter{input};

assert(*pointerIter == P(0, 1));
assert(pointerIter->first == 0);
assert(pointerIter->second == 1);
static_assert(is_same_v<decltype(pointerIter.operator->()), P* const&>);

using countedTest = common_iterator<counted_iterator<P*>, default_sentinel_t>;
countedTest countedIter{counted_iterator{input, 3}};

assert(*countedIter == P(0, 1));
assert(countedIter->first == 0);
assert(countedIter->second == 1);
static_assert(is_same_v<decltype(countedIter.operator->()), P*>);

return true;
}

int main() {
with_writable_iterators<instantiator, P>::call();

test_operator_arrow();
}
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_common_iterator_death/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_winsdk_concepts_matrix.lst
Loading