// iterator standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef _ITERATOR_ #define _ITERATOR_ #include #if _STL_COMPILER_PREPROCESSOR #include #include #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN _EXPORT_STD template class back_insert_iterator { // wrap pushes to back of container as output iterator public: using iterator_category = output_iterator_tag; using value_type = void; using pointer = void; using reference = void; using container_type = _Container; #if _HAS_CXX20 using difference_type = ptrdiff_t; #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv using difference_type = void; #endif // ^^^ !_HAS_CXX20 ^^^ _CONSTEXPR20 explicit back_insert_iterator(_Container& _Cont) noexcept /* strengthened */ : container(_STD addressof(_Cont)) {} _CONSTEXPR20 back_insert_iterator& operator=(const typename _Container::value_type& _Val) { container->push_back(_Val); return *this; } _CONSTEXPR20 back_insert_iterator& operator=(typename _Container::value_type&& _Val) { container->push_back(_STD move(_Val)); return *this; } _NODISCARD _CONSTEXPR20 back_insert_iterator& operator*() noexcept /* strengthened */ { return *this; } _CONSTEXPR20 back_insert_iterator& operator++() noexcept /* strengthened */ { return *this; } _CONSTEXPR20 back_insert_iterator operator++(int) noexcept /* strengthened */ { return *this; } protected: _Container* container; }; _EXPORT_STD template _NODISCARD _CONSTEXPR20 back_insert_iterator<_Container> back_inserter(_Container& _Cont) noexcept /* strengthened */ { // return a back_insert_iterator return back_insert_iterator<_Container>(_Cont); } _EXPORT_STD template class front_insert_iterator { // wrap pushes to front of container as output iterator public: using iterator_category = output_iterator_tag; using value_type = void; using pointer = void; using reference = void; using container_type = _Container; #if _HAS_CXX20 using difference_type = ptrdiff_t; #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv using difference_type = void; #endif // ^^^ !_HAS_CXX20 ^^^ _CONSTEXPR20 explicit front_insert_iterator(_Container& _Cont) : container(_STD addressof(_Cont)) {} _CONSTEXPR20 front_insert_iterator& operator=(const typename _Container::value_type& _Val) { // push value into container container->push_front(_Val); return *this; } _CONSTEXPR20 front_insert_iterator& operator=(typename _Container::value_type&& _Val) { // push value into container container->push_front(_STD move(_Val)); return *this; } _NODISCARD _CONSTEXPR20 front_insert_iterator& operator*() { // pretend to return designated value return *this; } _CONSTEXPR20 front_insert_iterator& operator++() { // pretend to preincrement return *this; } _CONSTEXPR20 front_insert_iterator operator++(int) { // pretend to postincrement return *this; } protected: _Container* container; }; _EXPORT_STD template _NODISCARD _CONSTEXPR20 front_insert_iterator<_Container> front_inserter(_Container& _Cont) { return front_insert_iterator<_Container>(_Cont); } _EXPORT_STD template class insert_iterator { // wrap inserts into container as output iterator public: using iterator_category = output_iterator_tag; using value_type = void; using pointer = void; using reference = void; using container_type = _Container; #if _HAS_CXX20 using difference_type = ptrdiff_t; using _Wrapped_iter = ranges::iterator_t<_Container>; #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv using difference_type = void; using _Wrapped_iter = typename _Container::iterator; #endif // ^^^ !_HAS_CXX20 ^^^ _CONSTEXPR20 insert_iterator(_Container& _Cont, _Wrapped_iter _Where) : container(_STD addressof(_Cont)), iter(_STD move(_Where)) {} _CONSTEXPR20 insert_iterator& operator=(const typename _Container::value_type& _Val) { // insert into container and increment stored iterator iter = container->insert(iter, _Val); ++iter; return *this; } _CONSTEXPR20 insert_iterator& operator=(typename _Container::value_type&& _Val) { // push value into container iter = container->insert(iter, _STD move(_Val)); ++iter; return *this; } _NODISCARD _CONSTEXPR20 insert_iterator& operator*() { // pretend to return designated value return *this; } _CONSTEXPR20 insert_iterator& operator++() { // pretend to preincrement return *this; } _CONSTEXPR20 insert_iterator& operator++(int) { // pretend to postincrement return *this; } protected: _Container* container; _Wrapped_iter iter; }; #if !_HAS_CXX20 template _NODISCARD _CONSTEXPR20 insert_iterator<_Container> inserter(_Container& _Cont, typename _Container::iterator _Where) { return insert_iterator<_Container>(_Cont, _Where); } #else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv _EXPORT_STD template _NODISCARD constexpr insert_iterator<_Container> inserter(_Container& _Cont, _RANGES iterator_t<_Container> _Where) { return insert_iterator<_Container>(_Cont, _Where); } _EXPORT_STD template class move_sentinel { public: constexpr move_sentinel() = default; constexpr explicit move_sentinel(_Se _Val) noexcept(is_nothrow_move_constructible_v<_Se>) // strengthened : _Last(_STD move(_Val)) {} template requires convertible_to constexpr move_sentinel(const move_sentinel<_Se2>& _Val) noexcept(is_nothrow_constructible_v<_Se, const _Se2&>) // strengthened : _Last(_Val._Get_last()) {} template requires assignable_from<_Se&, const _Se2&> constexpr move_sentinel& operator=(const move_sentinel<_Se2>& _Val) noexcept(is_nothrow_assignable_v<_Se&, const _Se2&>) /* strengthened */ { _Last = _Val._Get_last(); return *this; } _NODISCARD constexpr _Se base() const noexcept(is_nothrow_copy_constructible_v<_Se>) /* strengthened */ { return _Last; } _NODISCARD constexpr const _Se& _Get_last() const noexcept { return _Last; } using _Prevent_inheriting_unwrap = move_sentinel; _NODISCARD constexpr move_sentinel<_Unwrapped_t> _Unwrapped() const& noexcept( noexcept(move_sentinel<_Unwrapped_t>{_Last._Unwrapped()})) requires (_RANGES _Weakly_unwrappable_sentinel<_Se>) { return move_sentinel<_Unwrapped_t>{_Last._Unwrapped()}; } _NODISCARD constexpr move_sentinel<_Unwrapped_t<_Se>> _Unwrapped() && noexcept( noexcept(move_sentinel<_Unwrapped_t<_Se>>{_STD move(_Last)._Unwrapped()})) requires (_RANGES _Weakly_unwrappable_sentinel<_Se>) { return move_sentinel<_Unwrapped_t<_Se>>{_STD move(_Last)._Unwrapped()}; } private: _Se _Last{}; }; #endif // ^^^ _HAS_CXX20 ^^^ _EXPORT_STD template , class _Diff = ptrdiff_t> class istream_iterator { public: using iterator_category = input_iterator_tag; using value_type = _Ty; using difference_type = _Diff; using pointer = const _Ty*; using reference = const _Ty&; using char_type = _Elem; using traits_type = _Traits; using istream_type = basic_istream<_Elem, _Traits>; static_assert(conjunction_v, is_copy_constructible<_Ty>, is_copy_assignable<_Ty>>, "istream_iterator requires T to be default constructible, copy constructible, and copy assignable. " "(N4950 [istream.iterator]/2)"); constexpr istream_iterator() noexcept(is_nothrow_default_constructible_v<_Ty>) /* strengthened */ {} #if _HAS_CXX20 constexpr istream_iterator(default_sentinel_t) noexcept(is_nothrow_default_constructible_v<_Ty>) /* strengthened */ {} #endif // _HAS_CXX20 istream_iterator(istream_type& _Istr) : _Myistr(_STD addressof(_Istr)) { _Getval(); } _NODISCARD const _Ty& operator*() const noexcept /* strengthened */ { _STL_ASSERT(_Myistr, "The stored stream pointer in_stream must be non-null"); return _Myval; } _NODISCARD const _Ty* operator->() const noexcept /* strengthened */ { _STL_ASSERT(_Myistr, "The stored stream pointer in_stream must be non-null"); return _STD addressof(_Myval); } istream_iterator& operator++() { _Getval(); return *this; } istream_iterator operator++(int) { istream_iterator _Tmp = *this; _Getval(); return _Tmp; } _NODISCARD bool _Equal(const istream_iterator& _Right) const noexcept { return _Myistr == _Right._Myistr; } #if _HAS_CXX20 _NODISCARD friend bool operator==(const istream_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return !_Left._Myistr; } #endif // _HAS_CXX20 private: void _Getval() { // get a _Ty value if possible _STL_ASSERT(_Myistr, "The stored stream pointer in_stream must be non-null"); if (!(*_Myistr >> _Myval)) { _Myistr = nullptr; } } istream_type* _Myistr{nullptr}; // pointer to input stream _Ty _Myval{}; // lookahead value (valid if _Myistr is not null) }; _EXPORT_STD template _NODISCARD bool operator==(const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left, const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right) noexcept /* strengthened */ { return _Left._Equal(_Right); } #if !_HAS_CXX20 template _NODISCARD bool operator!=(const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Left, const istream_iterator<_Ty, _Elem, _Traits, _Diff>& _Right) noexcept /* strengthened */ { return !(_Left == _Right); } #endif // !_HAS_CXX20 _EXPORT_STD template > class ostream_iterator { public: using iterator_category = output_iterator_tag; using value_type = void; #if _HAS_CXX20 using difference_type = ptrdiff_t; #else using difference_type = void; #endif using pointer = void; using reference = void; using char_type = _Elem; using traits_type = _Traits; using ostream_type = basic_ostream<_Elem, _Traits>; ostream_iterator(ostream_type& _Ostr, const _Elem* const _Delim = nullptr) noexcept /* strengthened */ : _Mydelim(_Delim), _Myostr(_STD addressof(_Ostr)) {} ostream_iterator& operator=(const _Ty& _Val) { // insert value into output stream, followed by delimiter *_Myostr << _Val; if (_Mydelim) { *_Myostr << _Mydelim; } return *this; } _NODISCARD ostream_iterator& operator*() noexcept /* strengthened */ { return *this; } ostream_iterator& operator++() noexcept /* strengthened */ { return *this; } ostream_iterator& operator++(int) noexcept /* strengthened */ { return *this; } private: const _Elem* _Mydelim; // pointer to delimiter string (NB: not freed) ostream_type* _Myostr; // pointer to output stream }; _EXPORT_STD template class istreambuf_iterator { public: using iterator_category = input_iterator_tag; using value_type = _Elem; using difference_type = typename _Traits::off_type; using pointer = const _Elem*; using reference = _Elem; using char_type = _Elem; using traits_type = _Traits; using int_type = typename traits_type::int_type; using streambuf_type = basic_streambuf<_Elem, _Traits>; using istream_type = basic_istream<_Elem, _Traits>; constexpr istreambuf_iterator() noexcept : _Strbuf(nullptr), _Got(true), _Val() {} #if _HAS_CXX20 constexpr istreambuf_iterator(default_sentinel_t) noexcept : _Strbuf(nullptr), _Got(true), _Val() {} #endif // _HAS_CXX20 istreambuf_iterator(istream_type& _Istr) noexcept : _Strbuf(_Istr.rdbuf()), _Got(!_Strbuf), _Val() {} istreambuf_iterator(streambuf_type* _Sb) noexcept : _Strbuf(_Sb), _Got(!_Sb), _Val() {} private: class _Istreambuf_proxy { public: _NODISCARD _Elem operator*() const noexcept(is_nothrow_copy_constructible_v<_Elem>) /* strengthened */ { return _Keep; } private: friend istreambuf_iterator; _Istreambuf_proxy(streambuf_type* _Strbuf_, _Elem _Keep_) noexcept(is_nothrow_copy_constructible_v<_Elem>) // strengthened : _Strbuf(_Strbuf_), _Keep(_Keep_) {} streambuf_type* _Strbuf; _Elem _Keep; }; public: istreambuf_iterator(const _Istreambuf_proxy& _Px) noexcept : _Strbuf(_Px._Strbuf), _Got(!_Strbuf), _Val() {} _NODISCARD _Elem operator*() const { if (!_Got) { _Peek(); } #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_Strbuf, "istreambuf_iterator is not dereferenceable"); #endif // _ITERATOR_DEBUG_LEVEL == 2 return _Val; } istreambuf_iterator& operator++() { #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_Strbuf, "istreambuf_iterator is not incrementable"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Inc(); return *this; } _Istreambuf_proxy operator++(int) { if (!_Got) { _Peek(); } _Istreambuf_proxy _Tmp{_Strbuf, _Val}; ++*this; return _Tmp; } _NODISCARD bool equal(const istreambuf_iterator& _Right) const { if (!_Got) { _Peek(); } if (!_Right._Got) { _Right._Peek(); } return (!_Strbuf && !_Right._Strbuf) || (_Strbuf && _Right._Strbuf); } #if _HAS_CXX20 _NODISCARD friend bool operator==(const istreambuf_iterator& _Left, default_sentinel_t) { if (!_Left._Got) { _Left._Peek(); } return !_Left._Strbuf; } #endif // _HAS_CXX20 private: void _Inc() { // skip to next input element if (!_Strbuf || traits_type::eq_int_type(traits_type::eof(), _Strbuf->sbumpc())) { _Strbuf = nullptr; _Got = true; } else { _Got = false; } } _Elem _Peek() const { // peek at next input element int_type _Meta; if (!_Strbuf || traits_type::eq_int_type(traits_type::eof(), _Meta = _Strbuf->sgetc())) { _Strbuf = nullptr; } else { _Val = traits_type::to_char_type(_Meta); } _Got = true; return _Val; } mutable streambuf_type* _Strbuf; // the wrapped stream buffer mutable bool _Got; // true if _Val is valid mutable _Elem _Val; // next element to deliver }; _EXPORT_STD template _NODISCARD bool operator==( const istreambuf_iterator<_Elem, _Traits>& _Left, const istreambuf_iterator<_Elem, _Traits>& _Right) { return _Left.equal(_Right); } #if !_HAS_CXX20 template _NODISCARD bool operator!=( const istreambuf_iterator<_Elem, _Traits>& _Left, const istreambuf_iterator<_Elem, _Traits>& _Right) { return !(_Left == _Right); } #endif // !_HAS_CXX20 #if _HAS_CXX20 && !defined(__clang__) && !defined(__EDG__) // TRANSITION, /permissive, avoid checking constraints template constexpr bool _Iterator_is_contiguous> = false; #endif // ^^^ workaround ^^^ _EXPORT_STD template class ostreambuf_iterator { public: using iterator_category = output_iterator_tag; using value_type = void; #if _HAS_CXX20 using difference_type = ptrdiff_t; #else using difference_type = void; #endif using pointer = void; using reference = void; using char_type = _Elem; using traits_type = _Traits; using streambuf_type = basic_streambuf<_Elem, _Traits>; using ostream_type = basic_ostream<_Elem, _Traits>; ostreambuf_iterator(streambuf_type* _Sb) noexcept : _Strbuf(_Sb) {} ostreambuf_iterator(ostream_type& _Ostr) noexcept : _Strbuf(_Ostr.rdbuf()) {} ostreambuf_iterator& operator=(_Elem _Right) { // store element and increment if (!_Strbuf || traits_type::eq_int_type(_Traits::eof(), _Strbuf->sputc(_Right))) { _Failed = true; } return *this; } _NODISCARD ostreambuf_iterator& operator*() noexcept /* strengthened */ { return *this; } ostreambuf_iterator& operator++() noexcept /* strengthened */ { return *this; } ostreambuf_iterator& operator++(int) noexcept /* strengthened */ { return *this; } _NODISCARD bool failed() const noexcept { return _Failed; } private: bool _Failed = false; // true if any stores have failed streambuf_type* _Strbuf; }; #if _HAS_CXX20 && !defined(__clang__) && !defined(__EDG__) // TRANSITION, /permissive, avoid checking constraints template constexpr bool _Iterator_is_contiguous> = false; #endif // ^^^ workaround ^^^ #if _HAS_CXX20 enum class _Variantish_state : unsigned char { _Nothing, _Holds_first, _Holds_second }; struct _Variantish_empty_tag { explicit _Variantish_empty_tag() = default; }; template class _Variantish { public: constexpr explicit _Variantish(_Variantish_empty_tag) noexcept : _Contains{_Variantish_state::_Nothing} {} constexpr _Variantish() noexcept(is_nothrow_default_constructible_v<_Ty1>) requires default_initializable<_Ty1> : _First{}, _Contains{_Variantish_state::_Holds_first} {} template constexpr explicit _Variantish(in_place_type_t<_Ty1>, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty1, _Types...>) : _First(_STD forward<_Types>(_Args)...), _Contains{_Variantish_state::_Holds_first} {} template requires _Different_from<_Ty1, _Ty2> constexpr explicit _Variantish(in_place_type_t<_Ty2>, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty2, _Types...>) : _Second(_STD forward<_Types>(_Args)...), _Contains{_Variantish_state::_Holds_second} {} template requires _Different_from<_Variantish<_Uty1, _Uty2>, _Variantish> constexpr _Variantish(const _Variantish<_Uty1, _Uty2>& _That) noexcept(is_nothrow_constructible_v<_Ty1, const _Uty1&> && is_nothrow_constructible_v<_Ty2, const _Uty2&>) : _Contains{_That._Contains} { switch (_That._Contains) { case _Variantish_state::_Holds_first: _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; } } constexpr _Variantish(const _Variantish&) requires is_trivially_copy_constructible_v<_Ty1> && is_trivially_copy_constructible_v<_Ty2> = default; constexpr _Variantish(const _Variantish& _That) noexcept(is_nothrow_copy_constructible_v<_Ty1> && is_nothrow_copy_constructible_v<_Ty2>) : _Contains{_That._Contains} { switch (_Contains) { case _Variantish_state::_Holds_first: _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; } } constexpr _Variantish(_Variantish&&) requires is_trivially_move_constructible_v<_Ty1> && is_trivially_move_constructible_v<_Ty2> = default; constexpr _Variantish(_Variantish&& _That) noexcept(is_nothrow_move_constructible_v<_Ty1> && is_nothrow_move_constructible_v<_Ty2>) : _Contains{_That._Contains} { switch (_Contains) { case _Variantish_state::_Holds_first: _STD _Construct_in_place(_First, _STD move(_That._Get_first())); break; case _Variantish_state::_Holds_second: _STD _Construct_in_place(_Second, _STD move(_That._Get_second())); break; case _Variantish_state::_Nothing: break; } } constexpr ~_Variantish() { _Raw_clear(); } constexpr ~_Variantish() requires is_trivially_destructible_v<_Ty1> && is_trivially_destructible_v<_Ty2> = default; constexpr _Variantish& operator=(const _Variantish&) requires is_trivially_destructible_v<_Ty1> && is_trivially_destructible_v<_Ty2> && is_trivially_copy_constructible_v<_Ty1> && is_trivially_copy_constructible_v<_Ty2> && is_trivially_copy_assignable_v<_Ty1> && is_trivially_copy_assignable_v<_Ty2> = default; constexpr _Variantish& operator=(const _Variantish& _That) noexcept(is_nothrow_copy_constructible_v<_Ty1> && is_nothrow_copy_constructible_v<_Ty2> && is_nothrow_copy_assignable_v<_Ty1> && is_nothrow_copy_assignable_v<_Ty2>) { if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: _Get_first() = _That._Get_first(); break; case _Variantish_state::_Holds_second: _Get_second() = _That._Get_second(); break; case _Variantish_state::_Nothing: break; } return *this; } _Clear(); switch (_That._Contains) { case _Variantish_state::_Holds_first: _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; } _Contains = _That._Contains; return *this; } constexpr _Variantish& operator=(_Variantish&&) requires is_trivially_destructible_v<_Ty1> && is_trivially_destructible_v<_Ty2> && is_trivially_move_constructible_v<_Ty1> && is_trivially_move_constructible_v<_Ty2> && is_trivially_move_assignable_v<_Ty1> && is_trivially_move_assignable_v<_Ty2> = default; constexpr _Variantish& operator=(_Variantish&& _That) noexcept(is_nothrow_move_constructible_v<_Ty1> && is_nothrow_move_constructible_v<_Ty2> && is_nothrow_move_assignable_v<_Ty1> && is_nothrow_move_assignable_v<_Ty2>) { if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: _Get_first() = _STD move(_That._Get_first()); break; case _Variantish_state::_Holds_second: _Get_second() = _STD move(_That._Get_second()); break; case _Variantish_state::_Nothing: break; } return *this; } _Clear(); switch (_That._Contains) { case _Variantish_state::_Holds_first: _STD _Construct_in_place(_First, _STD move(_That._Get_first())); break; case _Variantish_state::_Holds_second: _STD _Construct_in_place(_Second, _STD move(_That._Get_second())); break; case _Variantish_state::_Nothing: break; } _Contains = _That._Contains; return *this; } template requires _Different_from<_Variantish<_Uty1, _Uty2>, _Variantish> constexpr _Variantish& operator=(const _Variantish<_Uty1, _Uty2>& _That) noexcept(is_nothrow_constructible_v<_Ty1, const _Uty1&> && is_nothrow_constructible_v<_Ty2, const _Uty2&> && is_nothrow_assignable_v<_Ty1&, const _Uty1&> && is_nothrow_assignable_v<_Ty2&, const _Uty2&>) { if (_Contains == _That._Contains) { switch (_Contains) { case _Variantish_state::_Holds_first: _Get_first() = _That._Get_first(); break; case _Variantish_state::_Holds_second: _Get_second() = _That._Get_second(); break; case _Variantish_state::_Nothing: break; } return *this; } _Clear(); switch (_That._Contains) { case _Variantish_state::_Holds_first: _STD _Construct_in_place(_First, _That._Get_first()); break; case _Variantish_state::_Holds_second: _STD _Construct_in_place(_Second, _That._Get_second()); break; case _Variantish_state::_Nothing: break; } _Contains = _That._Contains; return *this; } friend constexpr void swap(_Variantish& _Left, _Variantish& _Right) noexcept(is_nothrow_move_constructible_v<_Ty1> && is_nothrow_move_constructible_v<_Ty2> && is_nothrow_swappable_v<_Ty1> && is_nothrow_swappable_v<_Ty2>) requires (!_Is_trivially_swappable_v<_Ty1> || !_Is_trivially_swappable_v<_Ty2>) { if (_Left._Contains == _Right._Contains) { switch (_Left._Contains) { case _Variantish_state::_Holds_first: _RANGES swap(_Left._Get_first(), _Right._Get_first()); break; case _Variantish_state::_Holds_second: _RANGES swap(_Left._Get_second(), _Right._Get_second()); break; case _Variantish_state::_Nothing: break; } return; } auto _Tmp = _STD move(_Left); _Left = _STD move(_Right); _Right = _STD move(_Tmp); } constexpr void _Raw_clear() noexcept { switch (_Contains) { case _Variantish_state::_Holds_first: _First.~_Ty1(); break; case _Variantish_state::_Holds_second: _Second.~_Ty2(); break; case _Variantish_state::_Nothing: break; } } _NODISCARD constexpr _Ty1& _Get_first() noexcept { return _First; } _NODISCARD constexpr const _Ty1& _Get_first() const noexcept { return _First; } _NODISCARD constexpr _Ty2& _Get_second() noexcept { return _Second; } _NODISCARD constexpr const _Ty2& _Get_second() const noexcept { return _Second; } constexpr void _Clear() noexcept { _Raw_clear(); _Contains = _Variantish_state::_Nothing; } template constexpr void _Emplace_first(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty1, _Types...>) { _Clear(); _STD _Construct_in_place(_First, _STD forward<_Types>(_Args)...); _Contains = _Variantish_state::_Holds_first; } template constexpr void _Emplace_second(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty2, _Types...>) { _Clear(); _STD _Construct_in_place(_Second, _STD forward<_Types>(_Args)...); _Contains = _Variantish_state::_Holds_second; } union { remove_cv_t<_Ty1> _First; remove_cv_t<_Ty2> _Second; }; _Variantish_state _Contains; }; template concept _Use_postfix_proxy = !requires(_Iter& __it) { { *__it++ } -> _Can_reference; } && indirectly_readable<_Iter> && constructible_from, iter_reference_t<_Iter>> && move_constructible>; _EXPORT_STD template _Se> requires (!same_as<_Iter, _Se> && copyable<_Iter>) class common_iterator { private: struct _Proxy_base { iter_value_t<_Iter> _Keep; constexpr explicit _Proxy_base(iter_reference_t<_Iter>&& _Right) noexcept(is_nothrow_constructible_v, iter_reference_t<_Iter>>) // strengthened : _Keep(_STD forward>(_Right)) {} }; public: constexpr common_iterator() requires default_initializable<_Iter> = 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(_Variantish_empty_tag _Tag) noexcept : _Val{_Tag} {} template requires convertible_to && convertible_to 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._Get_val()} {} template requires convertible_to && convertible_to && assignable_from<_Iter&, const _OIter&> && assignable_from<_Se&, const _OSe&> constexpr 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 */ { _Val = _Right._Get_val(); return *this; } _NODISCARD constexpr decltype(auto) operator*() { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return *_Val._Get_first(); } _NODISCARD constexpr decltype(auto) operator*() const requires _Dereferenceable { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return *_Val._Get_first(); } _NODISCARD constexpr auto operator->() const requires indirectly_readable && (_Has_member_arrow || is_reference_v> || constructible_from, iter_reference_t<_Iter>>) { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be dereferenced if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Has_member_arrow || is_pointer_v<_Iter>) { return _Val._Get_first(); } else if constexpr (is_reference_v>) { auto&& _Tmp = *_Val._Get_first(); return _STD addressof(_Tmp); } else { class _Arrow_proxy : private _Proxy_base { public: friend common_iterator; using _Proxy_base::_Proxy_base; _NODISCARD constexpr const iter_value_t<_Iter>* operator->() const noexcept { return _STD addressof(this->_Keep); } }; return _Arrow_proxy{*_Val._Get_first()}; } } constexpr common_iterator& operator++() { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "common_iterator can only be incremented if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 ++_Val._Get_first(); return *this; } constexpr decltype(auto) operator++(int) { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Val._Contains == _Variantish_state::_Holds_first, "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._Get_first(); return _Tmp; } else if constexpr (_Use_postfix_proxy<_Iter>) { class _Postfix_proxy : private _Proxy_base { public: friend common_iterator; using _Proxy_base::_Proxy_base; _NODISCARD constexpr const iter_value_t<_Iter>& operator*() const noexcept { return this->_Keep; } }; _Postfix_proxy _Tmp{*_Val._Get_first()}; ++_Val._Get_first(); return _Tmp; } else { return _Val._Get_first()++; } } template _OSe> requires sentinel_for<_Se, _OIter> _NODISCARD friend constexpr bool operator==( const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) { auto& _Right_val = _Right._Get_val(); #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_first) { if (_Right_val._Contains == _Variantish_state::_Holds_first) { if constexpr (equality_comparable_with<_Iter, _OIter>) { return _Left._Val._Get_first() == _Right_val._Get_first(); } else { return true; } } else { return _Left._Val._Get_first() == _Right_val._Get_second(); } } else { if (_Right_val._Contains == _Variantish_state::_Holds_first) { return _Left._Val._Get_second() == _Right_val._Get_first(); } else { return true; } } } template _OIter, sized_sentinel_for<_Iter> _OSe> requires sized_sentinel_for<_Se, _OIter> _NODISCARD friend constexpr iter_difference_t<_OIter> operator-( const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) { auto& _Right_val = _Right._Get_val(); #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_first) { if (_Right_val._Contains == _Variantish_state::_Holds_first) { return _Left._Val._Get_first() - _Right_val._Get_first(); } else { return _Left._Val._Get_first() - _Right_val._Get_second(); } } else { if (_Right_val._Contains == _Variantish_state::_Holds_first) { return _Left._Val._Get_second() - _Right_val._Get_first(); } else { return 0; } } } _NODISCARD friend constexpr decltype(auto) iter_move(const common_iterator& _Right) noexcept(noexcept(_RANGES iter_move(_Right._Val._Get_first()))) requires input_iterator<_Iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Right._Val._Contains == _Variantish_state::_Holds_first, "can only iter_move from common_iterator if it holds an iterator"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return _RANGES iter_move(_Right._Val._Get_first()); } template _OIter, class _OSe> friend constexpr void iter_swap(const common_iterator& _Left, const common_iterator<_OIter, _OSe>& _Right) noexcept(noexcept(_RANGES iter_swap(_Left._Val._Get_first(), _Right._Get_val()._Get_first()))) { auto& _Right_val = _Right._Get_val(); #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left._Val._Contains == _Variantish_state::_Holds_first && _Right_val._Contains == _Variantish_state::_Holds_first, "can only iter_swap common_iterators if both hold iterators"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return _RANGES iter_swap(_Left._Val._Get_first(), _Right_val._Get_first()); } _NODISCARD constexpr _Variantish<_Iter, _Se>& _Get_val() noexcept { return _Val; } _NODISCARD constexpr const _Variantish<_Iter, _Se>& _Get_val() const noexcept { return _Val; } private: _Variantish<_Iter, _Se> _Val; }; template struct incrementable_traits> { using difference_type = iter_difference_t<_Iter>; }; template struct _Common_iterator_pointer_type { using pointer = void; }; template requires _Has_member_arrow&> struct _Common_iterator_pointer_type<_Iter, _Se> { using pointer = decltype(_STD declval&>().operator->()); }; template concept _Has_forward_category = requires { typename _Iter_cat_t<_Iter>; requires derived_from<_Iter_cat_t<_Iter>, forward_iterator_tag>; }; template struct _Common_iterator_category_base {}; template requires is_integral_v> struct _Common_iterator_category_base<_Iter> { using iterator_category = conditional_t<_Has_forward_category<_Iter>, forward_iterator_tag, input_iterator_tag>; }; template struct iterator_traits> : _Common_iterator_category_base<_Iter> { using iterator_concept = conditional_t, forward_iterator_tag, input_iterator_tag>; using value_type = iter_value_t<_Iter>; using difference_type = iter_difference_t<_Iter>; using pointer = _Common_iterator_pointer_type<_Iter, _Se>::pointer; using reference = iter_reference_t<_Iter>; }; template struct _Counted_iterator_value_type_base {}; template struct _Counted_iterator_value_type_base<_Iter> { using value_type = iter_value_t<_Iter>; }; template struct _Counted_iterator_category_base : _Counted_iterator_value_type_base<_Iter> {}; template <_Has_member_iterator_category _Iter> struct _Counted_iterator_category_base<_Iter> : _Counted_iterator_value_type_base<_Iter> { using iterator_category = _Iter::iterator_category; }; template struct _Counted_iterator_concept_base : _Counted_iterator_category_base<_Iter> {}; template <_Has_member_iterator_concept _Iter> struct _Counted_iterator_concept_base<_Iter> : _Counted_iterator_category_base<_Iter> { using iterator_concept = _Iter::iterator_concept; }; _EXPORT_STD template class counted_iterator : public _Counted_iterator_concept_base<_Iter> { public: using iterator_type = _Iter; using difference_type = iter_difference_t<_Iter>; // [counted.iter.const] constexpr counted_iterator() requires default_initializable<_Iter> = default; constexpr counted_iterator(_Iter _Right, const iter_difference_t<_Iter> _Diff) noexcept(is_nothrow_move_constructible_v<_Iter>) // strengthened : _Current(_STD move(_Right)), _Length(_Diff) { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Diff >= 0, "counted_iterator requires non-negative length n"); #endif // _ITERATOR_DEBUG_LEVEL != 0 } template requires convertible_to constexpr counted_iterator(const counted_iterator<_Other>& _Right) noexcept(is_nothrow_constructible_v<_Iter, const _Other&>) // strengthened : _Current(_Right.base()), _Length(_Right.count()) {} template requires assignable_from<_Iter&, const _Other&> constexpr counted_iterator& operator=(const counted_iterator<_Other>& _Right) noexcept(is_nothrow_assignable_v<_Iter&, const _Other&>) /* strengthened */ { _Current = _Right.base(); _Length = _Right.count(); return *this; } // [counted.iter.access] _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 iter_difference_t<_Iter> count() const noexcept { return _Length; } // [counted.iter.elem] _NODISCARD constexpr decltype(auto) operator*() noexcept(noexcept(*_Current)) /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Length > 0, "counted_iterator dereference beyond end of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return *_Current; } _NODISCARD constexpr decltype(auto) operator*() const noexcept(noexcept(*_Current)) /* strengthened */ requires _Dereferenceable { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Length > 0, "counted_iterator dereference beyond end of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return *_Current; } _NODISCARD constexpr auto operator->() const noexcept requires contiguous_iterator<_Iter> { return _STD to_address(_Current); } _NODISCARD constexpr decltype(auto) operator[](const iter_difference_t<_Iter> _Diff) const requires random_access_iterator<_Iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Diff < _Length, "counted_iterator index out of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Current[_Diff]; } // [counted.iter.nav] constexpr counted_iterator& operator++() { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Length > 0, "counted_iterator increment beyond end of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 ++_Current; --_Length; return *this; } constexpr decltype(auto) operator++(int) { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Length > 0, "counted_iterator increment beyond end of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 --_Length; _TRY_BEGIN return _Current++; _CATCH_ALL ++_Length; _RERAISE; _CATCH_END } constexpr counted_iterator operator++(int) requires forward_iterator<_Iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Length > 0, "counted_iterator increment beyond end of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 counted_iterator _Tmp = *this; ++_Current; --_Length; return _Tmp; } constexpr counted_iterator& operator--() requires bidirectional_iterator<_Iter> { --_Current; ++_Length; return *this; } constexpr counted_iterator operator--(int) requires bidirectional_iterator<_Iter> { counted_iterator _Tmp = *this; --_Current; ++_Length; return _Tmp; } _NODISCARD constexpr counted_iterator operator+(const iter_difference_t<_Iter> _Diff) const requires random_access_iterator<_Iter> { return counted_iterator{_Current + _Diff, static_cast>(_Length - _Diff)}; } _NODISCARD friend constexpr counted_iterator operator+( const iter_difference_t<_Iter> _Diff, const counted_iterator& _Right) requires random_access_iterator<_Iter> { return counted_iterator{_Right._Current + _Diff, static_cast>(_Right._Length - _Diff)}; } constexpr counted_iterator& operator+=(const iter_difference_t<_Iter> _Diff) requires random_access_iterator<_Iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Diff <= _Length, "counted_iterator seek beyond end of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 _Current += _Diff; _Length -= _Diff; return *this; } _NODISCARD constexpr counted_iterator operator-(const iter_difference_t<_Iter> _Diff) const requires random_access_iterator<_Iter> { return counted_iterator{_Current - _Diff, static_cast>(_Length + _Diff)}; } template _Other> _NODISCARD friend constexpr iter_difference_t<_Other> operator-( const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _Same_sequence(_Left, _Right); #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Right.count() - _Left._Length; } _NODISCARD friend constexpr iter_difference_t<_Iter> operator-( const counted_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return -_Left._Length; } _NODISCARD friend constexpr iter_difference_t<_Iter> operator-( default_sentinel_t, const counted_iterator& _Right) noexcept /* strengthened */ { return _Right._Length; } constexpr counted_iterator& operator-=(const iter_difference_t<_Iter> _Diff) requires random_access_iterator<_Iter> { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(-_Diff <= _Length, "counted_iterator decrement beyond end of range"); #endif // _ITERATOR_DEBUG_LEVEL != 0 _Current -= _Diff; _Length += _Diff; return *this; } // [counted.iter.cmp] template _Other> _NODISCARD friend constexpr bool operator==( const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _Same_sequence(_Left, _Right); #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Left._Length == _Right.count(); } _NODISCARD friend constexpr bool operator==(const counted_iterator& _Left, default_sentinel_t) noexcept /* strengthened */ { return _Left._Length == 0; } template _Other> _NODISCARD friend constexpr strong_ordering operator<=>( const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _Same_sequence(_Left, _Right); #endif // _ITERATOR_DEBUG_LEVEL != 0 return _Right.count() <=> _Left._Length; } // [counted.iter.cust] _NODISCARD friend constexpr decltype(auto) iter_move(const counted_iterator& _Right) noexcept(noexcept(_RANGES iter_move(_Right._Current))) requires input_iterator<_Iter> { return _RANGES iter_move(_Right._Current); } template _Other> friend constexpr void iter_swap(const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept(noexcept(_RANGES iter_swap(_Left._Current, _Right.base()))) { _RANGES iter_swap(_Left._Current, _Right.base()); } #if _ITERATOR_DEBUG_LEVEL != 0 template _Other> friend constexpr void _Same_sequence( const counted_iterator& _Left, const counted_iterator<_Other>& _Right) noexcept { #ifdef _M_CEE // TRANSITION, VSO-1665606 (void) _Left; (void) _Right; #else // ^^^ workaround / no workaround vvv // Per N4950 [counted.iterator]/3, two counted_iterators x and y refer to elements of the same sequence iff // for some integer n, next(x.base(), x.count() + n) and next(y.base(), y.count() + n) // "refer to the same (possibly past-the-end) element". // Iterator equality is a fair proxy for the vaguely-defined "refer to the same element". if constexpr (forward_iterator<_Iter> && forward_iterator<_Other>) { using _CIter = common_type_t<_Iter, _Other>; using _CDiff = common_type_t, iter_difference_t<_Other>>; const _CDiff _Diff = static_cast<_CDiff>(_Left._Length) - static_cast<_CDiff>(_Right.count()); if (_Diff < 0) { _STL_VERIFY( static_cast<_CIter>(_Left._Current) == _RANGES next(static_cast<_CIter>(_Right.base()), -_Diff), "counted_iterators are from different ranges"); } else { _STL_VERIFY( _RANGES next(static_cast<_CIter>(_Left._Current), _Diff) == static_cast<_CIter>(_Right.base()), "counted_iterators are from different ranges"); } } #endif // ^^^ no workaround ^^^ } #endif // _ITERATOR_DEBUG_LEVEL != 0 template _Other> friend constexpr void _Verify_range(const counted_iterator& _Left, const counted_iterator<_Other>& _Right) { if constexpr (_Range_verifiable_v<_Iter, _Other>) { _Verify_range(_Left._Current, _Right.base()); } #if _ITERATOR_DEBUG_LEVEL != 0 _Same_sequence(_Left, _Right); #endif // _ITERATOR_DEBUG_LEVEL != 0 } constexpr void _Verify_offset(const iter_difference_t<_Iter> _Off) const { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off <= _Length, "Offset larger than counted_iterator length"); #endif // _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Offset_verifiable_v<_Iter>) { _Current._Verify_offset(_Off); } } using _Prevent_inheriting_unwrap = counted_iterator; _NODISCARD constexpr counted_iterator<_Unwrapped_t> _Unwrapped() const& noexcept( noexcept(counted_iterator<_Unwrapped_t>{_Current._Unwrapped(), _Length})) requires _Unwrappable_v { return counted_iterator<_Unwrapped_t>{_Current._Unwrapped(), _Length}; } _NODISCARD constexpr counted_iterator<_Unwrapped_t<_Iter>> _Unwrapped() && noexcept( noexcept(counted_iterator<_Unwrapped_t<_Iter>>{_STD move(_Current)._Unwrapped(), _Length})) requires _Unwrappable_v<_Iter> { return counted_iterator<_Unwrapped_t<_Iter>>{_STD move(_Current)._Unwrapped(), _Length}; } static constexpr bool _Unwrap_when_unverified = _Do_unwrap_when_unverified_v<_Iter>; template requires _Wrapped_seekable_v<_Iter, const _Other&> constexpr void _Seek_to(const counted_iterator<_Other>& _It) { _Current._Seek_to(_It.base()); _Length = _It.count(); } template requires _Wrapped_seekable_v<_Iter, _Other> constexpr void _Seek_to(counted_iterator<_Other>&& _It) { _Current._Seek_to(_STD move(_It).base()); _Length = _It.count(); } private: _Iter _Current{}; iter_difference_t<_Iter> _Length = 0; }; template requires (!_Is_from_primary>) struct iterator_traits> : iterator_traits<_Iter> { using pointer = conditional_t, add_pointer_t>, void>; }; #endif // _HAS_CXX20 _STD_END #pragma push_macro("stdext") #pragma push_macro("checked_array_iterator") #pragma push_macro("make_checked_array_iterator") #pragma push_macro("make_unchecked_array_iterator") #pragma push_macro("unchecked_array_iterator") #undef stdext #undef checked_array_iterator #undef make_checked_array_iterator #undef make_unchecked_array_iterator #undef unchecked_array_iterator _STDEXT_BEGIN template class _DEPRECATE_STDEXT_ARR_ITERS checked_array_iterator { // wrap a pointer with checking private: using _Pointee_type = _STD remove_pointer_t<_Ptr>; static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>, "checked_array_iterator requires pointers to objects"); public: using iterator_category = _STD random_access_iterator_tag; using value_type = _STD remove_cv_t<_Pointee_type>; using difference_type = _STD ptrdiff_t; using pointer = _Ptr; using reference = _Pointee_type&; #if _HAS_CXX20 using iterator_concept = _STD contiguous_iterator_tag; #endif // _HAS_CXX20 constexpr checked_array_iterator() = default; constexpr checked_array_iterator(const _Ptr _Array, const size_t _Size, const size_t _Index = 0) noexcept : _Myarray(_Array), _Mysize(_Size), _Myindex(_Index) { _STL_VERIFY(_Index <= _Size, "checked_array_iterator construction index out of range"); } _STL_DISABLE_DEPRECATED_WARNING template , int> = 0> constexpr operator checked_array_iterator() const noexcept { return checked_array_iterator{_Myarray, _Mysize, _Myindex}; } _STL_RESTORE_DEPRECATED_WARNING _NODISCARD constexpr _Ptr base() const noexcept { return _Myarray + _Myindex; } _NODISCARD constexpr reference operator*() const noexcept { return *operator->(); } _NODISCARD constexpr pointer operator->() const noexcept { _STL_VERIFY(_Myarray, "cannot dereference value-initialized or null checked_array_iterator"); _STL_VERIFY(_Myindex < _Mysize, "cannot dereference end checked_array_iterator"); return _Myarray + _Myindex; } constexpr checked_array_iterator& operator++() noexcept { _STL_VERIFY(_Myarray, "cannot increment value-initialized or null checked_array_iterator"); _STL_VERIFY(_Myindex < _Mysize, "cannot increment checked_array_iterator past end"); ++_Myindex; return *this; } constexpr checked_array_iterator operator++(int) noexcept { checked_array_iterator _Tmp = *this; ++*this; return _Tmp; } constexpr checked_array_iterator& operator--() noexcept { _STL_VERIFY(_Myarray, "cannot decrement value-initialized or null checked_array_iterator"); _STL_VERIFY(_Myindex != 0, "cannot decrement checked_array_iterator before begin"); --_Myindex; return *this; } constexpr checked_array_iterator operator--(int) noexcept { checked_array_iterator _Tmp = *this; --*this; return _Tmp; } constexpr checked_array_iterator& operator+=(const difference_type _Off) noexcept { if (_Off != 0) { _STL_VERIFY(_Myarray, "cannot seek value-initialized or null checked_array_iterator"); } if (_Off < 0) { _STL_VERIFY( _Myindex >= size_t{0} - static_cast(_Off), "cannot seek checked_array_iterator before begin"); } if (_Off > 0) { _STL_VERIFY( _Mysize - _Myindex >= static_cast(_Off), "cannot seek checked_array_iterator after end"); } _Myindex += _Off; return *this; } _NODISCARD constexpr checked_array_iterator operator+(const difference_type _Off) const noexcept { checked_array_iterator _Tmp = *this; _Tmp += _Off; return _Tmp; } _NODISCARD friend constexpr checked_array_iterator operator+( const difference_type _Off, const checked_array_iterator<_Ptr>& _Next) noexcept { return _Next + _Off; } constexpr checked_array_iterator& operator-=(const difference_type _Off) noexcept { if (_Off != 0) { _STL_VERIFY(_Myarray, "cannot seek value-initialized or null checked_array_iterator"); } if (_Off > 0) { _STL_VERIFY(_Myindex >= static_cast(_Off), "cannot seek checked_array_iterator before begin"); } if (_Off < 0) { _STL_VERIFY(_Mysize - _Myindex >= size_t{0} - static_cast(_Off), "cannot seek checked_array_iterator after end"); } _Myindex -= _Off; return *this; } _NODISCARD constexpr checked_array_iterator operator-(const difference_type _Off) const noexcept { checked_array_iterator _Tmp = *this; _Tmp -= _Off; return _Tmp; } _NODISCARD constexpr difference_type operator-(const checked_array_iterator& _Right) const noexcept { _STL_VERIFY(_Myarray == _Right._Myarray && _Mysize == _Right._Mysize, "cannot subtract incompatible checked_array_iterators"); return static_cast(_Myindex - _Right._Myindex); } _NODISCARD constexpr reference operator[](const difference_type _Off) const noexcept { return *(*this + _Off); } _NODISCARD constexpr bool operator==(const checked_array_iterator& _Right) const noexcept { _STL_VERIFY(_Myarray == _Right._Myarray && _Mysize == _Right._Mysize, "cannot compare incompatible checked_array_iterators for equality"); return _Myindex == _Right._Myindex; } #if _HAS_CXX20 _NODISCARD constexpr _STD strong_ordering operator<=>(const checked_array_iterator& _Right) const noexcept { _STL_VERIFY(_Myarray == _Right._Myarray && _Mysize == _Right._Mysize, "cannot compare incompatible checked_array_iterators"); return _Myindex <=> _Right._Myindex; } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD constexpr bool operator!=(const checked_array_iterator& _Right) const noexcept { return !(*this == _Right); } _NODISCARD constexpr bool operator<(const checked_array_iterator& _Right) const noexcept { _STL_VERIFY(_Myarray == _Right._Myarray && _Mysize == _Right._Mysize, "cannot compare incompatible checked_array_iterators"); return _Myindex < _Right._Myindex; } _NODISCARD constexpr bool operator>(const checked_array_iterator& _Right) const noexcept { return _Right < *this; } _NODISCARD constexpr bool operator<=(const checked_array_iterator& _Right) const noexcept { return !(_Right < *this); } _NODISCARD constexpr bool operator>=(const checked_array_iterator& _Right) const noexcept { return !(*this < _Right); } #endif // ^^^ !_HAS_CXX20 ^^^ friend constexpr void _Verify_range( const checked_array_iterator& _First, const checked_array_iterator& _Last) noexcept { _STL_VERIFY(_First._Myarray == _Last._Myarray && _First._Mysize == _Last._Mysize, "mismatching checked_array_iterators"); _STL_VERIFY(_First._Myindex <= _Last._Myindex, "transposed checked_array_iterator range"); } constexpr void _Verify_offset(const difference_type _Off) const noexcept { if (_Off < 0) { _STL_VERIFY(_Myindex >= size_t{0} - static_cast(_Off), "cannot seek checked_array_iterator iterator before begin"); } if (_Off > 0) { _STL_VERIFY(_Mysize - _Myindex >= static_cast(_Off), "cannot seek checked_array_iterator iterator after end"); } } using _Prevent_inheriting_unwrap = checked_array_iterator; _NODISCARD constexpr _Ptr _Unwrapped() const noexcept { return _Myarray + _Myindex; } constexpr void _Seek_to(_Ptr _It) noexcept { _Myindex = static_cast(_It - _Myarray); } private: _Ptr _Myarray = nullptr; // beginning of array size_t _Mysize = 0; // size of array size_t _Myindex = 0; // offset into array }; _STL_DISABLE_DEPRECATED_WARNING template _DEPRECATE_STDEXT_ARR_ITERS _NODISCARD constexpr checked_array_iterator<_Ptr> make_checked_array_iterator( const _Ptr _Array, const size_t _Size, const size_t _Index = 0) noexcept { return checked_array_iterator<_Ptr>(_Array, _Size, _Index); } _STL_RESTORE_DEPRECATED_WARNING template class _DEPRECATE_STDEXT_ARR_ITERS unchecked_array_iterator { // wrap a pointer without checking, to silence warnings private: using _Pointee_type = _STD remove_pointer_t<_Ptr>; static_assert(_STD is_pointer_v<_Ptr> && _STD is_object_v<_Pointee_type>, "unchecked_array_iterator requires pointers to objects"); public: using iterator_category = _STD random_access_iterator_tag; using value_type = _STD remove_cv_t<_Pointee_type>; using difference_type = _STD ptrdiff_t; using pointer = _Ptr; using reference = _Pointee_type&; #if _HAS_CXX20 using iterator_concept = _STD contiguous_iterator_tag; #endif // _HAS_CXX20 constexpr unchecked_array_iterator() = default; constexpr explicit unchecked_array_iterator(const _Ptr _Src) noexcept : _Myptr(_Src) {} _STL_DISABLE_DEPRECATED_WARNING template , int> = 0> constexpr operator unchecked_array_iterator() const noexcept { return unchecked_array_iterator{_Myptr}; } _STL_RESTORE_DEPRECATED_WARNING _NODISCARD constexpr _Ptr base() const noexcept { return _Myptr; } _NODISCARD constexpr reference operator*() const noexcept { return *_Myptr; } _NODISCARD constexpr pointer operator->() const noexcept { return _Myptr; } constexpr unchecked_array_iterator& operator++() noexcept { ++_Myptr; return *this; } constexpr unchecked_array_iterator operator++(int) noexcept { unchecked_array_iterator _Tmp = *this; ++_Myptr; return _Tmp; } constexpr unchecked_array_iterator& operator--() noexcept { --_Myptr; return *this; } constexpr unchecked_array_iterator operator--(int) noexcept { unchecked_array_iterator _Tmp = *this; --_Myptr; return _Tmp; } constexpr unchecked_array_iterator& operator+=(const difference_type _Off) noexcept { _Myptr += _Off; return *this; } _NODISCARD constexpr unchecked_array_iterator operator+(const difference_type _Off) const noexcept { unchecked_array_iterator _Tmp = *this; _Tmp += _Off; return _Tmp; } _NODISCARD friend constexpr unchecked_array_iterator operator+( const difference_type _Off, const unchecked_array_iterator& _Next) noexcept { return _Next + _Off; } constexpr unchecked_array_iterator& operator-=(const difference_type _Off) noexcept { return *this += -_Off; } _NODISCARD constexpr unchecked_array_iterator operator-(const difference_type _Off) const noexcept { unchecked_array_iterator _Tmp = *this; _Tmp -= _Off; return _Tmp; } _NODISCARD constexpr difference_type operator-(const unchecked_array_iterator& _Right) const noexcept { return _Myptr - _Right._Myptr; } _NODISCARD constexpr reference operator[](const difference_type _Off) const noexcept { return *(*this + _Off); } _NODISCARD constexpr bool operator==(const unchecked_array_iterator& _Right) const noexcept { return _Myptr == _Right._Myptr; } #if _HAS_CXX20 _NODISCARD constexpr _STD strong_ordering operator<=>(const unchecked_array_iterator& _Right) const noexcept { return _Myptr <=> _Right._Myptr; } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD constexpr bool operator!=(const unchecked_array_iterator& _Right) const noexcept { return !(*this == _Right); } _NODISCARD constexpr bool operator<(const unchecked_array_iterator& _Right) const noexcept { return _Myptr < _Right._Myptr; } _NODISCARD constexpr bool operator>(const unchecked_array_iterator& _Right) const noexcept { return _Right < *this; } _NODISCARD constexpr bool operator<=(const unchecked_array_iterator& _Right) const noexcept { return !(_Right < *this); } _NODISCARD constexpr bool operator>=(const unchecked_array_iterator& _Right) const noexcept { return !(*this < _Right); } #endif // ^^^ !_HAS_CXX20 ^^^ #if _ITERATOR_DEBUG_LEVEL != 0 friend constexpr void _Verify_range( const unchecked_array_iterator _First, const unchecked_array_iterator _Last) noexcept { _STD _Verify_range(_First._Myptr, _Last._Myptr); } #endif // _ITERATOR_DEBUG_LEVEL != 0 using _Prevent_inheriting_unwrap = unchecked_array_iterator; static constexpr bool _Unwrap_when_unverified = true; _NODISCARD constexpr _Ptr _Unwrapped() const noexcept { return _Myptr; } constexpr void _Seek_to(_Ptr _It) noexcept { _Myptr = _It; } private: _Ptr _Myptr = nullptr; // underlying pointer }; _STL_DISABLE_DEPRECATED_WARNING template _DEPRECATE_STDEXT_ARR_ITERS _NODISCARD unchecked_array_iterator<_Ptr> make_unchecked_array_iterator( const _Ptr _It) noexcept { return unchecked_array_iterator<_Ptr>(_It); } _STL_RESTORE_DEPRECATED_WARNING _STDEXT_END #if _HAS_CXX20 _STD_BEGIN _STL_DISABLE_DEPRECATED_WARNING template struct pointer_traits<_STDEXT checked_array_iterator<_Ty*>> { using pointer = _STDEXT checked_array_iterator<_Ty*>; using element_type = _Ty; using difference_type = ptrdiff_t; _NODISCARD static constexpr element_type* to_address(const pointer _Iter) noexcept { return _Iter._Unwrapped(); } }; _STL_RESTORE_DEPRECATED_WARNING _STD_END #endif // _HAS_CXX20 #pragma pop_macro("unchecked_array_iterator") #pragma pop_macro("make_unchecked_array_iterator") #pragma pop_macro("make_checked_array_iterator") #pragma pop_macro("checked_array_iterator") #pragma pop_macro("stdext") #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _ITERATOR_