Co-authored-by: Casey Carter <cacarter@microsoft.com>
This commit is contained in:
Michael Schellenberger Costa 2020-09-04 20:12:50 +02:00 коммит произвёл GitHub
Родитель d19446293a
Коммит 30e7a1bab3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 926 добавлений и 13 удалений

Просмотреть файл

@ -513,6 +513,511 @@ private:
};
#ifdef __cpp_lib_concepts
// CLASS TEMPLATE common_iterator
enum class _Variantish_state : unsigned char { _Nothing, _Holds_iter, _Holds_sentinel };
struct _Common_iterator_construct_tag {
explicit _Common_iterator_construct_tag() = default;
};
template <input_or_output_iterator _It, sentinel_for<_It> _Se>
class _Variantish {
public:
constexpr explicit _Variantish(_Common_iterator_construct_tag) noexcept : _Contains{_Variantish_state::_Nothing} {}
constexpr _Variantish() noexcept(is_nothrow_default_constructible_v<_It>)
: _Iterator{}, _Contains{_Variantish_state::_Holds_iter} {}
template <class... _Types>
constexpr explicit _Variantish(in_place_type_t<_It>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_It, _Types...>)
: _Iterator(_STD forward<_Types>(_Args)...), _Contains{_Variantish_state::_Holds_iter} {}
template <class... _Types>
constexpr explicit _Variantish(in_place_type_t<_Se>, _Types&&... _Args) noexcept(
is_nothrow_constructible_v<_Se, _Types...>)
: _Sentinel(_STD forward<_Types>(_Args)...), _Contains{_Variantish_state::_Holds_sentinel} {}
// clang-format off
template <class _OIter, class _OSe>
requires _Not_same_as<_Variantish<_OIter, _OSe>, _Variantish>
_Variantish(const _Variantish<_OIter, _OSe>& _That) noexcept(
is_nothrow_constructible_v<_It, const _OIter&> && is_nothrow_constructible_v<_Se, const _OSe&>)
: _Contains{_That._Contains} {
// clang-format on
switch (_That._Contains) {
case _Variantish_state::_Holds_iter:
_Construct_in_place(_Iterator, _That._Iterator);
break;
case _Variantish_state::_Holds_sentinel:
_Construct_in_place(_Sentinel, _That._Sentinel);
break;
case _Variantish_state::_Nothing:
break;
}
}
#if 0 // TRANSITION, VSO-1174090
// clang-format off
_Variantish(const _Variantish&) requires is_trivially_copy_constructible_v<_It>
&& is_trivially_copy_constructible_v<_Se> = default;
// clang-format on
#endif // TRANSITION, VSO-1174090
_Variantish(const _Variantish& _That) noexcept(
noexcept(is_nothrow_copy_constructible_v<_It>&& is_nothrow_copy_constructible_v<_Se>))
: _Contains{_That._Contains} {
switch (_Contains) {
case _Variantish_state::_Holds_iter:
_Construct_in_place(_Iterator, _That._Iterator);
break;
case _Variantish_state::_Holds_sentinel:
_Construct_in_place(_Sentinel, _That._Sentinel);
break;
case _Variantish_state::_Nothing:
break;
}
}
#if 0 // TRANSITION, VSO-1174090
// clang-format off
_Variantish(_Variantish&&) requires is_trivially_move_constructible_v<_It>
&& is_trivially_move_constructible_v<_Se> = default;
// clang-format on
#endif // TRANSITION, VSO-1174090
_Variantish(_Variantish&& _That) noexcept(
is_nothrow_move_constructible_v<_It>&& is_nothrow_move_constructible_v<_Se>)
: _Contains{_That._Contains} {
switch (_Contains) {
case _Variantish_state::_Holds_iter:
_Construct_in_place(_Iterator, _STD move(_That._Iterator));
break;
case _Variantish_state::_Holds_sentinel:
_Construct_in_place(_Sentinel, _STD move(_That._Sentinel));
break;
case _Variantish_state::_Nothing:
break;
}
}
#if 0 // TRANSITION, VSO-1174090
// clang-format off
~_Variantish() requires is_trivially_destructible_v<_It> && is_trivially_destructible_v<_Se> = default;
// clang-format on
#endif // TRANSITION, VSO-1174090
~_Variantish() {
_Raw_clear();
}
#if 0 // TRANSITION, VSO-1174090
// clang-format off
_Variantish& operator=(const _Variantish&) requires is_trivially_destructible_v<_It>
&& is_trivially_destructible_v<_Se>
&& is_trivially_copy_constructible_v<_It>
&& is_trivially_copy_constructible_v<_Se>
&& is_trivially_copy_assignable_v<_It>
&& is_trivially_copy_assignable_v<_Se> = default;
// clang-format on
#endif // TRANSITION, VSO-1174090
_Variantish& operator=(const _Variantish& _That) noexcept(
is_nothrow_copy_constructible_v<_It>&& is_nothrow_copy_constructible_v<_Se>&&
is_nothrow_copy_assignable_v<_It>&& is_nothrow_copy_assignable_v<_Se>) {
if (_Contains == _That._Contains) {
switch (_Contains) {
case _Variantish_state::_Holds_iter:
_Iterator = _That._Iterator;
break;
case _Variantish_state::_Holds_sentinel:
_Sentinel = _That._Sentinel;
break;
case _Variantish_state::_Nothing:
break;
}
return *this;
}
_Clear();
switch (_That._Contains) {
case _Variantish_state::_Holds_iter:
_Construct_in_place(_Iterator, _That._Iterator);
break;
case _Variantish_state::_Holds_sentinel:
_Construct_in_place(_Sentinel, _That._Sentinel);
break;
case _Variantish_state::_Nothing:
break;
}
_Contains = _That._Contains;
return *this;
}
#if 0 // TRANSITION, VSO-1174090
// clang-format off
_Variantish& operator=(_Variantish&&) requires is_trivially_destructible_v<_It>
&& is_trivially_destructible_v<_Se>
&& is_trivially_move_constructible_v<_It>
&& is_trivially_move_constructible_v<_Se>
&& is_trivially_move_assignable_v<_It>
&& is_trivially_move_assignable_v<_Se> = default;
// clang-format on
#endif // TRANSITION, VSO-1174090
_Variantish& operator=(_Variantish&& _That) noexcept(
is_nothrow_move_constructible_v<_It>&& is_nothrow_move_constructible_v<_Se>&&
is_nothrow_move_assignable_v<_It>&& is_nothrow_move_assignable_v<_Se>) {
if (_Contains == _That._Contains) {
switch (_Contains) {
case _Variantish_state::_Holds_iter:
_Iterator = _STD move(_That._Iterator);
break;
case _Variantish_state::_Holds_sentinel:
_Sentinel = _STD move(_That._Sentinel);
break;
case _Variantish_state::_Nothing:
break;
}
return *this;
}
_Clear();
switch (_That._Contains) {
case _Variantish_state::_Holds_iter:
_Construct_in_place(_Iterator, _STD move(_That._Iterator));
break;
case _Variantish_state::_Holds_sentinel:
_Construct_in_place(_Sentinel, _STD move(_That._Sentinel));
break;
case _Variantish_state::_Nothing:
break;
}
_Contains = _That._Contains;
return *this;
}
// clang-format off
template <class _OIter, class _OSe>
requires _Not_same_as<_Variantish<_OIter, _OSe>, _Variantish>
_Variantish& operator=(const _Variantish<_OIter, _OSe>& _That) noexcept(
is_nothrow_constructible_v<_It, const _OIter&> && is_nothrow_constructible_v<_Se, const _OSe&>
&& is_nothrow_assignable_v<_It&, const _OIter&> && is_nothrow_assignable_v<_Se&, const _OSe&>) {
// clang-format on
if (_Contains == _That._Contains) {
switch (_Contains) {
case _Variantish_state::_Holds_iter:
_Iterator = _That._Iterator;
break;
case _Variantish_state::_Holds_sentinel:
_Sentinel = _That._Sentinel;
break;
case _Variantish_state::_Nothing:
break;
}
return *this;
}
_Clear();
switch (_That._Contains) {
case _Variantish_state::_Holds_iter:
_Construct_in_place(_Iterator, _That._Iterator);
break;
case _Variantish_state::_Holds_sentinel:
_Construct_in_place(_Sentinel, _That._Sentinel);
break;
case _Variantish_state::_Nothing:
break;
}
_Contains = _That._Contains;
return *this;
}
// clang-format off
constexpr friend void swap(_Variantish& _Left, _Variantish& _Right) noexcept(
is_nothrow_move_constructible_v<_It> && is_nothrow_move_constructible_v<_Se>
&& is_nothrow_swappable_v<_It> && is_nothrow_swappable_v<_Se>)
requires (!_Is_trivially_swappable_v<_It> || !_Is_trivially_swappable_v<_Se>) {
// clang-format on
if (_Left._Contains == _Right._Contains) {
switch (_Left._Contains) {
case _Variantish_state::_Holds_iter:
_RANGES swap(_Left._Iterator, _Right._Iterator);
break;
case _Variantish_state::_Holds_sentinel:
_RANGES swap(_Left._Sentinel, _Right._Sentinel);
break;
case _Variantish_state::_Nothing:
break;
}
return;
}
auto _Tmp = _STD move(_Left);
_Left = _STD move(_Right);
_Right = _STD move(_Tmp);
}
void _Raw_clear() noexcept {
switch (_Contains) {
case _Variantish_state::_Holds_iter:
_Iterator.~_It();
break;
case _Variantish_state::_Holds_sentinel:
_Sentinel.~_Se();
break;
case _Variantish_state::_Nothing:
break;
}
}
void _Clear() noexcept {
_Raw_clear();
_Contains = _Variantish_state::_Nothing;
}
union {
_It _Iterator;
_Se _Sentinel;
};
_Variantish_state _Contains;
};
// clang-format off
template <input_or_output_iterator _Iter, sentinel_for<_Iter> _Se>
requires (!same_as<_Iter, _Se> && copyable<_Iter>)
class common_iterator {
// clang-format on
private:
class _Proxy {
private:
iter_value_t<_Iter> _Keep;
public:
explicit _Proxy(iter_reference_t<_Iter>&& _Right) noexcept(
is_nothrow_move_constructible_v<iter_value_t<_Iter>>) // strengthened
: _Keep(_STD move(_Right)) {}
_NODISCARD const iter_value_t<_Iter>* operator->() const noexcept /* strengthened */ {
return _STD addressof(_Keep);
}
};
public:
constexpr common_iterator() = default;
constexpr common_iterator(_Iter _Right) noexcept(is_nothrow_move_constructible_v<_Iter>) // strengthened
: _Val{in_place_type<_Iter>, _STD move(_Right)} {}
constexpr common_iterator(_Se _Right) noexcept(is_nothrow_move_constructible_v<_Se>) // strengthened
: _Val{in_place_type<_Se>, _STD move(_Right)} {}
constexpr explicit common_iterator(_Common_iterator_construct_tag _Tag) noexcept : _Val{_Tag} {}
// clang-format off
template <class _OIter, class _OSe>
requires convertible_to<const _OIter&, _Iter> && convertible_to<const _OSe&, _Se>
constexpr common_iterator(const common_iterator<_OIter, _OSe>& _Right) noexcept(
is_nothrow_constructible_v<_Iter, const _OIter&>&& is_nothrow_constructible_v<_Se, const _OSe&>) // strengthened
: _Val{_Right._Val} {}
template <class _OIter, class _OSe>
requires convertible_to<const _OIter&, _Iter> && convertible_to<const _OSe&, _Se>
&& assignable_from<_Iter&, const _OIter&> && assignable_from<_Se&, const _OSe&>
common_iterator& operator=(const common_iterator<_OIter, _OSe>& _Right) noexcept(
is_nothrow_constructible_v<_Iter, const _OIter&> && is_nothrow_constructible_v<_Se, const _OSe&>
&& is_nothrow_assignable_v<_Iter&, const _OIter&>
&& is_nothrow_assignable_v<_Se&, const _OSe&>) /* strengthened */ {
// clang-format on
_Val = _Right._Val;
return *this;
}
_NODISCARD decltype(auto) operator*() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_iter,
"common_iterator can only be dereferenced if it holds an iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *_Val._Iterator;
}
_NODISCARD decltype(auto) operator*() const requires _Dereferenceable<const _Iter> {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_iter,
"common_iterator can only be dereferenced if it holds an iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *_Val._Iterator;
}
// clang-format off
_NODISCARD decltype(auto) operator->() const
requires indirectly_readable<const _Iter>
&& (_Has_op_arrow<_Iter> || is_reference_v<iter_reference_t<_Iter>>
|| constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>>) {
// clang-format on
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_iter,
"common_iterator can only be dereferenced if it holds an iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
if constexpr (is_pointer_v<_Iter> || _Has_op_arrow<_Iter>) {
return (_Val._Iterator); // NB: () are necessary for decltype(auto)
} else if constexpr (is_reference_v<iter_reference_t<_Iter>>) {
auto&& _Tmp = *_Val._Iterator;
return _STD addressof(_Tmp);
} else {
return _Proxy{*_Val._Iterator};
}
}
common_iterator& operator++() {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_iter,
"common_iterator can only be incremented if it holds an iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
++_Val._Iterator;
return *this;
}
decltype(auto) operator++(int) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_iter,
"common_iterator can only be incremented if it holds an iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
if constexpr (forward_iterator<_Iter>) {
common_iterator _Tmp = *this;
++_Val._Iterator;
return _Tmp;
} else {
return _Val._Iterator++;
}
}
// clang-format off
template <class _OIter, sentinel_for<_Iter> _OSe>
requires sentinel_for<_Se, _OIter>
_NODISCARD friend bool operator==(const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) {
// clang-format on
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(
_Left._Val._Contains != _Variantish_state::_Nothing && _Right._Val._Contains != _Variantish_state::_Nothing,
"common_iterators can only be compared if both hold a value");
#endif // _ITERATOR_DEBUG_LEVEL != 0
if (_Left._Val._Contains == _Variantish_state::_Holds_iter) {
if (_Right._Val._Contains == _Variantish_state::_Holds_iter) {
if constexpr (equality_comparable_with<_Iter, _OIter>) {
return _Left._Val._Iterator == _Right._Val._Iterator;
} else {
return true;
}
} else {
return _Left._Val._Iterator == _Right._Val._Sentinel;
}
} else {
if (_Right._Val._Contains == _Variantish_state::_Holds_iter) {
return _Left._Val._Sentinel == _Right._Val._Iterator;
} else {
return true;
}
}
}
// clang-format off
template <sized_sentinel_for<_Iter> _OIter, sized_sentinel_for<_Iter> _OSe>
requires sized_sentinel_for<_Se, _OIter>
_NODISCARD friend iter_difference_t<_OIter> operator-(
const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) {
// clang-format on
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(
_Left._Val._Contains != _Variantish_state::_Nothing && _Right._Val._Contains != _Variantish_state::_Nothing,
"Cannot take difference of valueless common_iterators");
#endif // _ITERATOR_DEBUG_LEVEL != 0
if (_Left._Val._Contains == _Variantish_state::_Holds_iter) {
if (_Right._Val._Contains == _Variantish_state::_Holds_iter) {
return _Left._Val._Iterator - _Right._Val._Iterator;
} else {
return _Left._Val._Iterator - _Right._Val._Sentinel;
}
} else {
if (_Right._Val._Contains == _Variantish_state::_Holds_iter) {
return _Left._Val._Sentinel - _Right._Val._Iterator;
} else {
return 0;
}
}
}
_NODISCARD friend iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& _Right) noexcept(
noexcept(_RANGES iter_move(_Right._Val._Iterator))) requires input_iterator<_Iter> {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Right._Val._Contains == _Variantish_state::_Holds_iter,
"can only iter_move from common_iterator if it holds an iterator");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _RANGES iter_move(_Right._Val._Iterator);
}
template <indirectly_swappable<_Iter> _OIter, class _OSe>
friend void iter_swap(const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) noexcept(
noexcept(_RANGES iter_swap(_Left._Val._Iterator, _Right._Val._Iterator))) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Left._Val._Contains == _Variantish_state::_Holds_iter
&& _Right._Val._Contains == _Variantish_state::_Holds_iter,
"can only iter_swap common_iterators if both hold iterators");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return _RANGES iter_swap(_Left._Val._Iterator, _Right._Val._Iterator);
}
private:
// clang-format off
template <input_or_output_iterator _OIter, sentinel_for<_OIter> _OSe>
requires (!same_as<_OIter, _OSe> && copyable<_OIter>)
friend class common_iterator;
// clang-format on
_Variantish<_Iter, _Se> _Val;
};
template <class _Iter, class _Se>
struct incrementable_traits<common_iterator<_Iter, _Se>> {
using difference_type = iter_difference_t<_Iter>;
};
template <class>
struct _Common_iterator_pointer_type {
using pointer = void;
};
template <_Has_op_arrow _Iter>
struct _Common_iterator_pointer_type<_Iter> {
using pointer = decltype(_STD declval<_Iter&>().operator->());
};
template <input_iterator _Iter, class _Se>
struct iterator_traits<common_iterator<_Iter, _Se>> {
using iterator_concept = conditional_t<forward_iterator<_Iter>, forward_iterator_tag, input_iterator_tag>;
using iterator_category =
conditional_t<derived_from<_Iter_cat_t<_Iter>, forward_iterator_tag>, forward_iterator_tag, input_iterator_tag>;
using value_type = iter_value_t<_Iter>;
using difference_type = iter_difference_t<_Iter>;
using pointer = typename _Common_iterator_pointer_type<_Iter>::pointer;
using reference = iter_reference_t<_Iter>;
};
// CLASS TEMPLATE counted_iterator
template <input_or_output_iterator _Iter>
class counted_iterator {

Просмотреть файл

@ -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

Просмотреть файл

@ -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 {
@ -2329,6 +2336,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>
@ -3411,10 +3422,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>

Просмотреть файл

@ -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)) {
@ -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_);
}

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\strict_concepts_matrix.lst

Просмотреть файл

@ -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>
#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;
}
{ // [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->())>);
}
}
{ // [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);
}
}
{ // [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
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();
}

Просмотреть файл

@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
RUNALL_INCLUDE ..\strict_winsdk_concepts_matrix.lst

Просмотреть файл

@ -0,0 +1,187 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#define _CONTAINER_DEBUG_LEVEL 1
#include <algorithm>
#include <cassert>
#include <concepts>
#include <iterator>
#include <test_death.hpp>
using namespace std;
struct simple_input_iter {
using value_type = int;
using difference_type = int;
value_type operator*() const {
return 0;
}
value_type operator->() const {
return 0;
}
simple_input_iter& operator++() {
return *this;
}
simple_input_iter operator++(int) {
return *this;
}
bool operator==(const simple_input_iter&) const = default;
bool operator==(const default_sentinel_t&) const {
return true;
}
difference_type operator-(const simple_input_iter&) const {
return 42;
}
friend difference_type operator-(const simple_input_iter&, const default_sentinel_t&) {
return 42;
}
friend difference_type operator-(const default_sentinel_t&, const simple_input_iter&) {
return 42;
}
friend void iter_swap(const simple_input_iter&, const simple_input_iter&) {}
};
using CIT = common_iterator<simple_input_iter, default_sentinel_t>;
void test_case_operator_dereference_sentinel() {
CIT cit{default_sentinel};
(void) (*cit); // common_iterator can only be dereferenced if it holds an iterator
}
void test_case_operator_dereference_valueless() {
CIT cit{_Common_iterator_construct_tag{}};
(void) (*cit); // common_iterator can only be dereferenced if it holds an iterator
}
void test_case_operator_dereference_const_sentinel() {
const CIT cit{default_sentinel};
(void) (*cit); // common_iterator can only be dereferenced if it holds an iterator
}
void test_case_operator_dereference_const_valueless() {
const CIT cit{_Common_iterator_construct_tag{}};
(void) (*cit); // common_iterator can only be dereferenced if it holds an iterator
}
void test_case_operator_arrow_sentinel() {
CIT cit{default_sentinel};
(void) (cit.operator->()); // common_iterator can only be dereferenced if it holds an iterator
}
void test_case_operator_arrow_valueless() {
CIT cit{_Common_iterator_construct_tag{}};
(void) (cit.operator->()); // common_iterator can only be dereferenced if it holds an iterator
}
void test_case_operator_preincrement_sentinel() {
CIT cit{default_sentinel};
++cit; // common_iterator can only be preincremented if it holds an iterator
}
void test_case_operator_preincrement_valueless() {
CIT cit{_Common_iterator_construct_tag{}};
++cit; // common_iterator can only be preincremented if it holds an iterator
}
void test_case_operator_postincrement_sentinel() {
CIT cit{default_sentinel};
cit++; // common_iterator can only be postincremented if it holds an iterator
}
void test_case_operator_postincrement_valueless() {
CIT cit{_Common_iterator_construct_tag{}};
cit++; // common_iterator can only be postincremented if it holds an iterator
}
void test_case_equality_left_valueless() {
CIT cit1{_Common_iterator_construct_tag{}};
CIT cit2{};
(void) (cit1 == cit2); // common_iterator can only be compared if it holds a value
}
void test_case_equality_right_valueless() {
CIT cit1{};
CIT cit2{_Common_iterator_construct_tag{}};
(void) (cit1 == cit2); // common_iterator can only be compared if it holds a value
}
void test_case_difference_left_valueless() {
CIT cit1{_Common_iterator_construct_tag{}};
CIT cit2{};
(void) (cit1 - cit2); // common_iterator can only be subtracted if it holds a value
}
void test_case_difference_right_valueless() {
CIT cit1{};
CIT cit2{_Common_iterator_construct_tag{}};
(void) (cit1 - cit2); // common_iterator can only be subtracted if it holds a value
}
void test_case_iter_move_sentinel() {
CIT cit{default_sentinel};
(void) ranges::iter_move(cit); // can only iter_move from common_iterator if it holds an iterator
}
void test_case_iter_move_valueless() {
CIT cit{_Common_iterator_construct_tag{}};
(void) ranges::iter_move(cit); // can only iter_move from common_iterator if it holds an iterator
}
void test_case_iter_swap_sentinel_left_sentinel() {
CIT cit1{default_sentinel};
CIT cit2{};
(void) ranges::iter_swap(cit1, cit2); // can only iter_swap common_iterators if both hold iterators
}
void test_case_iter_swap_sentinel_left_valueless() {
CIT cit1{_Common_iterator_construct_tag{}};
CIT cit2{};
(void) ranges::iter_swap(cit1, cit2); // can only iter_swap common_iterators if both hold iterators
}
void test_case_iter_swap_sentinel_right_sentinel() {
CIT cit1{};
CIT cit2{default_sentinel};
(void) ranges::iter_swap(cit1, cit2); // can only iter_swap common_iterators if both hold iterators
}
void test_case_iter_swap_sentinel_right_valueless() {
CIT cit1{};
CIT cit2{_Common_iterator_construct_tag{}};
(void) ranges::iter_swap(cit1, cit2); // can only iter_swap common_iterators if both hold iterators
}
int main(int argc, char* argv[]) {
std_testing::death_test_executive exec([] {});
#if _ITERATOR_DEBUG_LEVEL != 0
exec.add_death_tests({
test_case_operator_dereference_sentinel,
test_case_operator_dereference_valueless,
test_case_operator_dereference_const_sentinel,
test_case_operator_dereference_const_valueless,
test_case_operator_arrow_sentinel,
test_case_operator_arrow_valueless,
test_case_operator_preincrement_sentinel,
test_case_operator_preincrement_valueless,
test_case_operator_postincrement_sentinel,
test_case_operator_postincrement_valueless,
test_case_equality_left_valueless,
test_case_equality_right_valueless,
test_case_difference_left_valueless,
test_case_difference_right_valueless,
test_case_iter_move_sentinel,
test_case_iter_move_valueless,
test_case_iter_swap_sentinel_left_sentinel,
test_case_iter_swap_sentinel_left_valueless,
test_case_iter_swap_sentinel_right_sentinel,
test_case_iter_swap_sentinel_right_valueless,
});
#endif // _ITERATOR_DEBUG_LEVEL != 0
return exec.run(argc, argv);
}