зеркало из https://github.com/microsoft/STL.git
Implement common_iterator (#1092)
Co-authored-by: Casey Carter <cacarter@microsoft.com>
This commit is contained in:
Родитель
d19446293a
Коммит
30e7a1bab3
505
stl/inc/iterator
505
stl/inc/iterator
|
@ -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);
|
||||
}
|
Загрузка…
Ссылка в новой задаче