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

P2278R4: cbegin should always return a constant iterator ("Iterators" section only) #3043

Merged
merged 28 commits into from
Oct 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0ff884e
Implement `std::const_iterator`
JMazurkiewicz Aug 19, 2022
ea5f25c
Add P2278R4_ranges_const_iterator_machinery to `test.lst`
JMazurkiewicz Aug 19, 2022
377c851
CR suggestion + replace `_Implicitly_convert_to` with `_Fake_copy_init`
JMazurkiewicz Aug 23, 2022
b867123
Merge branch 'main' into const_iterator
JMazurkiewicz Sep 1, 2022
59db1c9
Add visualizer
JMazurkiewicz Sep 1, 2022
fdc2b29
Implement test coverage
JMazurkiewicz Sep 8, 2022
57c17d7
NON CONFORMING: remove most of comparison functions and *dissolve* so…
JMazurkiewicz Sep 8, 2022
2f9fe81
Replace bespoke _Is_basic_const_iterator_v with _Is_specialization_v
CaseyCarter Sep 15, 2022
1a6f08e
Fix comment typo
CaseyCarter Sep 15, 2022
9771706
Add missing `_Fake_copy_init<bool>` to account for conversion to bool…
CaseyCarter Sep 15, 2022
b87697b
Implement comparisons per the proposed resolution of LWG-3769
CaseyCarter Sep 15, 2022
66a41b8
Factor out some requirements into named concepts to workaround LLVM-5…
CaseyCarter Sep 15, 2022
f1e813a
Cleanup const iterator machinery tests
JMazurkiewicz Sep 16, 2022
5b63c7e
Cleanup comments from `basic_const_iterator` test
JMazurkiewicz Sep 16, 2022
85b0a2d
Test `common_type` too
JMazurkiewicz Sep 16, 2022
ba296a3
Merge branch 'main' into const_iterator
JMazurkiewicz Sep 19, 2022
5f2b197
_EXPORT_STD!
JMazurkiewicz Sep 19, 2022
fd9e817
`.base()` -> `._Current`
JMazurkiewicz Sep 20, 2022
1967b0d
Merge branch 'main' into const_iterator
JMazurkiewicz Oct 15, 2022
f9cb24a
Update formatting
JMazurkiewicz Oct 15, 2022
ed53e6b
Implement LWG-3765
JMazurkiewicz Oct 20, 2022
94828be
Say TRANSITION in the compiler bug workaround comment.
StephanTLavavej Oct 20, 2022
6f5eb31
Drop std:: qualification.
StephanTLavavej Oct 20, 2022
65c2793
Drop forced wrapping - clang-format 15 is ok.
StephanTLavavej Oct 20, 2022
ab3ae63
Include more headers.
StephanTLavavej Oct 20, 2022
e370870
Fix test: istream_view's iterator isn't semiregular, so it can't supp…
StephanTLavavej Oct 20, 2022
2872f22
make_const_meow() constructs from lvalues.
StephanTLavavej Oct 20, 2022
00e9299
Fix test coverage
JMazurkiewicz Oct 21, 2022
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
8 changes: 8 additions & 0 deletions stl/debugger/STL.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,14 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
</Type>


<Type Name="std::basic_const_iterator&lt;*&gt;">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding a visualizer! 😸

Mirroring note: As usual, this will need to be triple-mirrored to the VS repo, but I'm ok with deferring that until the next time we have a decent-sized batch of visualizer updates.

<DisplayString>basic_const_iterator {_Current}</DisplayString>
<Expand>
<Item Name="current">_Current</Item>
</Expand>
</Type>


<Type Name="std::complex&lt;*&gt;">
<DisplayString Condition="(_Val[1] &lt; 0) &amp;&amp; (_Val[0] == 0)">-i*{-_Val[1]}</DisplayString>
<DisplayString Condition="(_Val[1] &lt; 0) &amp;&amp; (_Val[0] != 0)">{_Val[0]}-i*{-_Val[1]}</DisplayString>
Expand Down
339 changes: 339 additions & 0 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,345 @@ _NODISCARD constexpr const _Elem* data(initializer_list<_Elem> _Ilist) noexcept
template <class _Ty1, class _Ty2>
concept _Not_same_as = (!same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>);

#if _HAS_CXX23
_EXPORT_STD template <indirectly_readable _Ty>
using iter_const_reference_t = common_reference_t<const iter_value_t<_Ty>&&, iter_reference_t<_Ty>>;

template <class _Ty>
concept _Constant_iterator = input_iterator<_Ty> && same_as<iter_const_reference_t<_Ty>, iter_reference_t<_Ty>>;

_EXPORT_STD template <input_iterator _Iter>
class basic_const_iterator;

_EXPORT_STD template <input_iterator _Iter>
using const_iterator = conditional_t<_Constant_iterator<_Iter>, _Iter, basic_const_iterator<_Iter>>;
JMazurkiewicz marked this conversation as resolved.
Show resolved Hide resolved

template <class _Sent>
struct _Const_sentinel {
using type = _Sent;
};

template <input_iterator _Sent>
struct _Const_sentinel<_Sent> {
using type = const_iterator<_Sent>;
};

_EXPORT_STD template <semiregular _Sent>
using const_sentinel = typename _Const_sentinel<_Sent>::type;

// clang-format off
template <class _Ty>
concept _Not_a_const_iterator = !_Is_specialization_v<_Ty, basic_const_iterator>;
// clang-format on

template <class>
struct _Basic_const_iterator_category {};

template <forward_iterator _Iter>
struct _Basic_const_iterator_category<_Iter> {
using iterator_category = typename iterator_traits<_Iter>::iterator_category;
};

// TRANSITION, LLVM-55945: These are distinct concepts as a workaround
template <class _Ty, class _Iter>
concept _Bci_order =
_Not_same_as<_Ty, basic_const_iterator<_Iter>> && random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Ty>;

template <class _Ty, class _Iter>
concept _Bci_order_3way = _Bci_order<_Ty, _Iter> && three_way_comparable_with<_Iter, _Ty>;

template <class _Ty, class _Iter>
concept _Not_bci_order =
_Not_a_const_iterator<_Ty> && random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Ty>;

_EXPORT_STD template <input_iterator _Iter>
class basic_const_iterator : public _Basic_const_iterator_category<_Iter> {
private:
/* [[no_unique_address]] */ _Iter _Current{};

using _Reference = iter_const_reference_t<_Iter>;

_NODISCARD static _CONSTEVAL auto _Get_iter_concept() noexcept {
if constexpr (contiguous_iterator<_Iter>) {
return contiguous_iterator_tag{};
} else if constexpr (random_access_iterator<_Iter>) {
return random_access_iterator_tag{};
} else if constexpr (bidirectional_iterator<_Iter>) {
return bidirectional_iterator_tag{};
} else if constexpr (forward_iterator<_Iter>) {
return forward_iterator_tag{};
} else {
return input_iterator_tag{};
}
}

public:
using iterator_concept = decltype(_Get_iter_concept());
using value_type = iter_value_t<_Iter>;
using difference_type = iter_difference_t<_Iter>;

// clang-format off
basic_const_iterator() requires default_initializable<_Iter> = default;
// clang-format on

constexpr basic_const_iterator(_Iter _Current_) noexcept(is_nothrow_move_constructible_v<_Iter>) // strengthened
: _Current(_STD move(_Current_)) {}

template <convertible_to<_Iter> _Other>
constexpr basic_const_iterator(basic_const_iterator<_Other> _Current_) noexcept(
is_nothrow_constructible_v<_Iter, _Other>) // strengthened
: _Current(_STD move(_Current_._Current)) {}

template <_Not_same_as<basic_const_iterator> _Other>
requires convertible_to<_Other, _Iter>
constexpr basic_const_iterator(_Other&& _Current_) noexcept(
is_nothrow_constructible_v<_Iter, _Other>) // strengthened
: _Current(_STD forward<_Other>(_Current_)) {}

_NODISCARD constexpr const _Iter& base() const& noexcept {
return _Current;
}

_NODISCARD constexpr _Iter base() && noexcept(is_nothrow_move_constructible_v<_Iter>) /* strengthened */ {
return _STD move(_Current);
}

_NODISCARD constexpr _Reference operator*() const
noexcept(noexcept(static_cast<_Reference>(*_Current))) /* strengthened */ {
return static_cast<_Reference>(*_Current);
}

_NODISCARD constexpr const value_type* operator->() const
noexcept(contiguous_iterator<_Iter> || noexcept(*_Current)) /* strengthened */
requires is_lvalue_reference_v<iter_reference_t<_Iter>>
&& same_as<remove_cvref_t<iter_reference_t<_Iter>>, value_type>
{
if constexpr (contiguous_iterator<_Iter>) {
return _STD to_address(_Current);
} else {
return _STD addressof(*_Current);
}
}

constexpr basic_const_iterator& operator++() noexcept(noexcept(++_Current)) /* strengthened */ {
++_Current;
return *this;
}

constexpr void operator++(int) noexcept(noexcept(++_Current)) /* strengthened */ {
++_Current;
}

constexpr basic_const_iterator operator++(int) noexcept(
noexcept(++*this) && is_nothrow_copy_constructible_v<basic_const_iterator>) // strengthened
requires forward_iterator<_Iter>
{
auto _Tmp = *this;
++*this;
return _Tmp;
}

constexpr basic_const_iterator& operator--() noexcept(noexcept(--_Current)) // strengthened
requires bidirectional_iterator<_Iter>
{
--_Current;
return *this;
}

constexpr basic_const_iterator operator--(int) noexcept(
noexcept(--*this) && is_nothrow_copy_constructible_v<basic_const_iterator>) // strengthened
requires bidirectional_iterator<_Iter>
{
auto _Tmp = *this;
--*this;
return _Tmp;
}

constexpr basic_const_iterator& operator+=(const difference_type _Off) noexcept(
noexcept(_Current += _Off)) // strengthened
requires random_access_iterator<_Iter>
{
_Current += _Off;
return *this;
}

constexpr basic_const_iterator& operator-=(const difference_type _Off) noexcept(
noexcept(_Current -= _Off)) // strengthened
requires random_access_iterator<_Iter>
{
_Current -= _Off;
return *this;
}

_NODISCARD constexpr _Reference operator[](const difference_type _Idx) const
noexcept(noexcept(static_cast<_Reference>(_Current[_Idx]))) // strengthened
requires random_access_iterator<_Iter>
{
return static_cast<_Reference>(_Current[_Idx]);
}

template <sentinel_for<_Iter> _Sent>
_NODISCARD constexpr bool operator==(const _Sent& _Se) const // per LWG-3769
noexcept(noexcept(_Fake_copy_init<bool>(_Current == _Se))) /* strengthened */ {
return _Current == _Se;
}

_NODISCARD_FRIEND constexpr bool
operator<(const basic_const_iterator& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current < _Right._Current))) // strengthened
requires random_access_iterator<_Iter>
{
return _Left._Current < _Right._Current;
}

_NODISCARD_FRIEND constexpr bool
operator>(const basic_const_iterator& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current > _Right._Current))) // strengthened
requires random_access_iterator<_Iter>
{
return _Left._Current > _Right._Current;
}

_NODISCARD_FRIEND constexpr bool
operator<=(const basic_const_iterator& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current <= _Right._Current))) // strengthened
requires random_access_iterator<_Iter>
{
return _Left._Current <= _Right._Current;
}

_NODISCARD_FRIEND constexpr bool
operator>=(const basic_const_iterator& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current >= _Right._Current))) // strengthened
requires random_access_iterator<_Iter>
{
return _Left._Current >= _Right._Current;
}

_NODISCARD_FRIEND constexpr auto operator<=>(const basic_const_iterator& _Left,
const basic_const_iterator& _Right) noexcept(noexcept(_Left._Current <=> _Right._Current)) // strengthened
requires random_access_iterator<_Iter> && three_way_comparable<_Iter>
{
return _Left._Current <=> _Right._Current;
}

template <_Bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator<(const basic_const_iterator& _Left, const _Other& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current < _Right))) /* strengthened */ {
return _Left._Current < _Right;
}

template <_Bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator>(const basic_const_iterator& _Left, const _Other& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current > _Right))) /* strengthened */ {
return _Left._Current > _Right;
}

template <_Bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator<=(const basic_const_iterator& _Left, const _Other& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current <= _Right))) /* strengthened */ {
return _Left._Current <= _Right;
}

template <_Bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator>=(const basic_const_iterator& _Left, const _Other& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left._Current >= _Right))) /* strengthened */ {
return _Left._Current >= _Right;
}

template <_Not_bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator<(const _Other& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left < _Right._Current))) /* strengthened */ {
return _Left < _Right._Current;
}

template <_Not_bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator>(const _Other& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left > _Right._Current))) /* strengthened */ {
return _Left > _Right._Current;
}

template <_Not_bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator<=(const _Other& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left <= _Right._Current))) /* strengthened */ {
return _Left <= _Right._Current;
}

template <_Not_bci_order<_Iter> _Other>
_NODISCARD_FRIEND constexpr bool operator>=(const _Other& _Left, const basic_const_iterator& _Right) noexcept(
noexcept(_Fake_copy_init<bool>(_Left >= _Right._Current))) /* strengthened */ {
return _Left >= _Right._Current;
}

template <_Bci_order_3way<_Iter> _Other>
_NODISCARD_FRIEND constexpr auto operator<=>(const basic_const_iterator& _Left, const _Other& _Right) noexcept(
noexcept(_Left._Current <=> _Right)) /* strengthened */ {
return _Left._Current <=> _Right;
}

_NODISCARD_FRIEND constexpr basic_const_iterator operator+(const basic_const_iterator& _It,
const difference_type _Off) noexcept(noexcept(basic_const_iterator{_It._Current + _Off})) // strengthened
requires random_access_iterator<_Iter>
{
return basic_const_iterator{_It._Current + _Off};
}

_NODISCARD_FRIEND constexpr basic_const_iterator operator+(const difference_type _Off,
const basic_const_iterator& _It) noexcept(noexcept(basic_const_iterator{_It._Current + _Off})) // strengthened
requires random_access_iterator<_Iter>
{
return basic_const_iterator{_It._Current + _Off};
}

_NODISCARD_FRIEND constexpr basic_const_iterator operator-(const basic_const_iterator& _It,
const difference_type _Off) noexcept(noexcept(basic_const_iterator{_It._Current - _Off})) // strengthened
requires random_access_iterator<_Iter>
{
return basic_const_iterator{_It._Current - _Off};
}

template <sized_sentinel_for<_Iter> _Sent>
_NODISCARD constexpr difference_type operator-(const _Sent& _Se) const // per LWG-3769
noexcept(noexcept(_Current - _Se)) /* strengthened */ {
return _Current - _Se;
}

template <_Not_a_const_iterator _Sent>
requires sized_sentinel_for<_Sent, _Iter>
_NODISCARD_FRIEND constexpr difference_type operator-(const _Sent& _Se, const basic_const_iterator& _It) noexcept(
noexcept(_Se - _It._Current)) /* strengthened */ { // per LWG-3769
return _Se - _It._Current;
}
};

template <class _Ty1, common_with<_Ty1> _Ty2>
struct common_type<basic_const_iterator<_Ty1>, _Ty2> {
using type = basic_const_iterator<common_type_t<_Ty1, _Ty2>>;
};

template <class _Ty1, common_with<_Ty1> _Ty2>
struct common_type<_Ty2, basic_const_iterator<_Ty1>> {
using type = basic_const_iterator<common_type_t<_Ty1, _Ty2>>;
};

template <class _Ty1, common_with<_Ty1> _Ty2>
struct common_type<basic_const_iterator<_Ty1>, basic_const_iterator<_Ty2>> {
using type = basic_const_iterator<common_type_t<_Ty1, _Ty2>>;
};

_EXPORT_STD template <input_iterator _Iter>
_NODISCARD constexpr const_iterator<_Iter> make_const_iterator(_Iter _It) noexcept(
is_nothrow_constructible_v<const_iterator<_Iter>, _Iter&>) /* strengthened */ {
return _It;
}

_EXPORT_STD template <semiregular _Sent>
_NODISCARD constexpr const_sentinel<_Sent> make_const_sentinel(_Sent _Se) noexcept(
is_nothrow_constructible_v<const_sentinel<_Sent>, _Sent&>) /* strengthened */ {
return _Se;
}
#endif // _HAS_CXX23

namespace ranges {
template <class>
inline constexpr bool _Has_complete_elements = false;
Expand Down
2 changes: 2 additions & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@
// P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr
// P2186R2 Removing Garbage Collection Support
// P2273R3 constexpr unique_ptr
// P2278R4 cbegin Should Always Return A Constant Iterator
// ("Iterators" section from the paper only)
// P2291R3 constexpr Integral <charconv>
// P2302R4 ranges::contains, ranges::contains_subrange
// P2321R2 zip
Expand Down
2 changes: 1 addition & 1 deletion tests/std/include/range_algorithm_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ namespace test {
template <class Category, class Element,
// Model sized_sentinel_for along with sentinel?
CanDifference Diff = CanDifference{derived_from<Category, random>},
// Model sentinel_for with self (and sized_sentinel_for if Diff; implies copyable)?
// Model sentinel_for with self (and sized_sentinel_for if Diff implies copyable)?
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
CanCompare Eq = CanCompare{derived_from<Category, fwd>},
// Use a ProxyRef reference type (instead of Element&)?
ProxyRef Proxy = ProxyRef{!derived_from<Category, contiguous>},
Expand Down
2 changes: 2 additions & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,8 @@ tests\P2136R3_invoke_r
tests\P2162R2_std_visit_for_derived_classes_from_variant
tests\P2231R1_complete_constexpr_optional_variant
tests\P2273R3_constexpr_unique_ptr
tests\P2278R4_basic_const_iterator
tests\P2278R4_ranges_const_iterator_machinery
tests\P2302R4_ranges_alg_contains
tests\P2302R4_ranges_alg_contains_subrange
tests\P2321R2_proxy_reference
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P2278R4_basic_const_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 ..\concepts_latest_matrix.lst
Loading