// forward_list standard header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _FORWARD_LIST_ #define _FORWARD_LIST_ #include #if _STL_COMPILER_PREPROCESSOR #include #if _HAS_CXX17 #include #endif // _HAS_CXX17 #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 // CLASS TEMPLATE _Flist_unchecked_const_iterator template class _Flist_unchecked_const_iterator : public _Base { public: using iterator_category = forward_iterator_tag; using _Nodeptr = typename _Mylist::_Nodeptr; using value_type = typename _Mylist::value_type; using difference_type = typename _Mylist::difference_type; using pointer = typename _Mylist::const_pointer; using reference = const value_type&; _Flist_unchecked_const_iterator() noexcept : _Ptr() {} _Flist_unchecked_const_iterator(_Nodeptr _Pnode, const _Mylist* _Plist) noexcept : _Ptr(_Pnode) { this->_Adopt(_Plist); } _NODISCARD reference operator*() const { return _Ptr->_Myval; } _NODISCARD pointer operator->() const { return pointer_traits::pointer_to(**this); } _Flist_unchecked_const_iterator& operator++() { _Ptr = _Ptr->_Next; return *this; } _Flist_unchecked_const_iterator operator++(int) { _Flist_unchecked_const_iterator _Tmp = *this; _Ptr = _Ptr->_Next; return _Tmp; } _NODISCARD bool operator==(const _Flist_unchecked_const_iterator& _Right) const { return _Ptr == _Right._Ptr; } _NODISCARD bool operator!=(const _Flist_unchecked_const_iterator& _Right) const { return !(*this == _Right); } _NODISCARD bool operator==(_Default_sentinel) const noexcept { return _Ptr == nullptr; } _NODISCARD bool operator!=(_Default_sentinel) const noexcept { return _Ptr != nullptr; } _Nodeptr _Ptr; // pointer to node }; // CLASS TEMPLATE _Flist_unchecked_iterator template class _Flist_unchecked_iterator : public _Flist_unchecked_const_iterator<_Mylist> { public: using _Mybase = _Flist_unchecked_const_iterator<_Mylist>; using iterator_category = forward_iterator_tag; using _Nodeptr = typename _Mylist::_Nodeptr; using value_type = typename _Mylist::value_type; using difference_type = typename _Mylist::difference_type; using pointer = typename _Mylist::pointer; using reference = value_type&; using _Mybase::_Mybase; _NODISCARD reference operator*() const { return const_cast(_Mybase::operator*()); } _NODISCARD pointer operator->() const { return pointer_traits::pointer_to(**this); } _Flist_unchecked_iterator& operator++() { _Mybase::operator++(); return *this; } _Flist_unchecked_iterator operator++(int) { _Flist_unchecked_iterator _Tmp = *this; _Mybase::operator++(); return _Tmp; } }; // CLASS TEMPLATE _Flist_const_iterator template class _Flist_const_iterator : public _Flist_unchecked_const_iterator<_Mylist, _Iterator_base> { public: using _Mybase = _Flist_unchecked_const_iterator<_Mylist, _Iterator_base>; using iterator_category = forward_iterator_tag; using _Nodeptr = typename _Mylist::_Nodeptr; using value_type = typename _Mylist::value_type; using difference_type = typename _Mylist::difference_type; using pointer = typename _Mylist::const_pointer; using reference = const value_type&; using _Mybase::_Mybase; _NODISCARD reference operator*() const { #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Mycont = static_cast(this->_Getcont()); _STL_ASSERT(_Mycont, "cannot dereference value-initialized forward_list iterator"); _STL_VERIFY(this->_Ptr != _Mycont->_Before_head(), "cannot dereference forward_list before_begin"); #endif // _ITERATOR_DEBUG_LEVEL == 2 return this->_Ptr->_Myval; } _Flist_const_iterator& operator++() { #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(this->_Getcont(), "forward_list iterator not incrementable"); #endif // _ITERATOR_DEBUG_LEVEL == 2 this->_Ptr = this->_Ptr->_Next; return *this; } _Flist_const_iterator operator++(int) { _Flist_const_iterator _Tmp = *this; this->_Ptr = this->_Ptr->_Next; return _Tmp; } _NODISCARD bool operator==(const _Flist_const_iterator& _Right) const { #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(this->_Getcont() == _Right._Getcont(), "forward_list iterators incompatible"); #endif // _ITERATOR_DEBUG_LEVEL == 2 return this->_Ptr == _Right._Ptr; } _NODISCARD bool operator!=(const _Flist_const_iterator& _Right) const { return !(*this == _Right); } #if _ITERATOR_DEBUG_LEVEL == 2 friend void _Verify_range(const _Flist_const_iterator& _First, const _Flist_const_iterator& _Last) { _STL_VERIFY( _First._Getcont() == _Last._Getcont(), "forward_list iterators in range are from different containers"); } #endif // _ITERATOR_DEBUG_LEVEL == 2 using _Prevent_inheriting_unwrap = _Flist_const_iterator; _NODISCARD _Flist_unchecked_const_iterator<_Mylist> _Unwrapped() const noexcept { return _Flist_unchecked_const_iterator<_Mylist>(this->_Ptr, static_cast(this->_Getcont())); } void _Seek_to(const _Flist_unchecked_const_iterator<_Mylist> _It) { this->_Ptr = _It._Ptr; } }; // CLASS TEMPLATE _Flist_iterator template class _Flist_iterator : public _Flist_const_iterator<_Mylist> { public: using _Mybase = _Flist_const_iterator<_Mylist>; using iterator_category = forward_iterator_tag; using _Nodeptr = typename _Mylist::_Nodeptr; using value_type = typename _Mylist::value_type; using difference_type = typename _Mylist::difference_type; using pointer = typename _Mylist::pointer; using reference = value_type&; using _Mybase::_Mybase; _NODISCARD reference operator*() const { return const_cast(_Mybase::operator*()); } _NODISCARD pointer operator->() const { return pointer_traits::pointer_to(**this); } _Flist_iterator& operator++() { _Mybase::operator++(); return *this; } _Flist_iterator operator++(int) { _Flist_iterator _Tmp = *this; _Mybase::operator++(); return _Tmp; } using _Prevent_inheriting_unwrap = _Flist_iterator; _NODISCARD _Flist_unchecked_iterator<_Mylist> _Unwrapped() const noexcept { return _Flist_unchecked_iterator<_Mylist>(this->_Ptr, static_cast(this->_Getcont())); } }; // forward_list TYPE WRAPPERS template struct _Flist_iter_types { using value_type = _Value_type; using size_type = _Size_type; using difference_type = _Difference_type; using pointer = _Pointer; using const_pointer = _Const_pointer; using _Nodeptr = _Nodeptr_type; }; template struct _Flist_node { // forward_list node using _Nodeptr = _Rebind_pointer_t<_Voidptr, _Flist_node>; _Nodeptr _Next; // successor node _Value_type _Myval; // the stored value _Flist_node(const _Flist_node&) = delete; _Flist_node& operator=(const _Flist_node&) = delete; template static void _Freenode(_Alnode& _Al, _Nodeptr _Pnode) noexcept { _Destroy_in_place(_Pnode->_Next); allocator_traits<_Alnode>::destroy(_Al, _STD addressof(_Pnode->_Myval)); _Al.deallocate(_Pnode, 1); } }; template struct _Flist_simple_types : _Simple_types<_Ty> { using _Node = _Flist_node<_Ty, void*>; using _Nodeptr = _Node*; }; // CLASS TEMPLATE _Flist_val template class _Flist_val : public _Container_base { public: using _Nodeptr = typename _Val_types::_Nodeptr; using _Node = typename pointer_traits<_Nodeptr>::element_type; using value_type = typename _Val_types::value_type; using size_type = typename _Val_types::size_type; using difference_type = typename _Val_types::difference_type; using pointer = typename _Val_types::pointer; using const_pointer = typename _Val_types::const_pointer; using reference = value_type&; using const_reference = const value_type&; _Flist_val() noexcept : _Myhead() { // initialize data } _Nodeptr _Before_head() const noexcept { // return pointer to the "before begin" pseudo node return pointer_traits<_Nodeptr>::pointer_to(reinterpret_cast<_Node&>(const_cast<_Nodeptr&>(_Myhead))); } #if _ITERATOR_DEBUG_LEVEL == 2 void _Orphan_ptr(_Nodeptr _Ptr) noexcept { // orphan iterators with specified node pointers const auto _BHead = _Before_head(); _Lockit _Lock(_LOCK_DEBUG); _Iterator_base12** _Pnext = &this->_Myproxy->_Myfirstiter; while (*_Pnext) { const auto _Pnextptr = static_cast<_Flist_const_iterator<_Flist_val>&>(**_Pnext)._Ptr; if (_Pnextptr == _BHead || (_Ptr != nullptr && _Pnextptr != _Ptr)) { _Pnext = &(*_Pnext)->_Mynextiter; } else { // orphan the iterator (*_Pnext)->_Myproxy = nullptr; *_Pnext = (*_Pnext)->_Mynextiter; } } } #endif // _ITERATOR_DEBUG_LEVEL == 2 template static _Nodeptr _Inplace_merge(_Nodeptr _BFirst1, const _Nodeptr _BMid, const _Nodeptr _BLast, _Pr2 _Pred) { // Merge the sorted ranges (_BFirst1, _BMid] and (_BMid, _BLast) // Returns one before the new logical end of the range. auto _First2 = _BMid->_Next; for (;;) { // process 1 splice _Nodeptr _First1; for (;;) { // advance _BFirst1 over elements already in position if (_BFirst1 == _BMid) { return _BLast; } _First1 = _BFirst1->_Next; if (_DEBUG_LT_PRED(_Pred, _First2->_Myval, _First1->_Myval)) { // _First2->_Myval is out of order break; } // _First1->_Myval is already in position; advance _BFirst1 = _First1; } // find the end of the "run" of elements less than _First1->_Myval in the 2nd range auto _BRun_end = _First2; _Nodeptr _Run_end; for (;;) { _Run_end = _BRun_end->_Next; if (_BRun_end == _BLast) { break; } if (!_DEBUG_LT_PRED(_Pred, _Run_end->_Myval, _First1->_Myval)) { // _Run_end is the first element in (_BMid->_Myval, _BLast->_Myval) that shouldn't precede // _First1->_Myval. // After the splice _First1->_Myval will be in position and must not be compared again. break; } _BRun_end = _Run_end; } _BMid->_Next = _Run_end; // snip out the run from its old position _BFirst1->_Next = _First2; // insert into new position _BRun_end->_Next = _First1; if (_BRun_end == _BLast) { return _BMid; } _BFirst1 = _First1; _First2 = _Run_end; } } template static _Nodeptr _Sort2(const _Nodeptr _BFirst, _Pr2 _Pred) { // Sort (_BFirst, _BFirst + 2], unless nullptr is encountered. // Returns a pointer one before the end of the sorted region. const auto _First1 = _BFirst->_Next; if (!_First1) { return _BFirst; } auto _First2 = _First1->_Next; if (!_First2 || !_DEBUG_LT_PRED(_Pred, _First2->_Myval, _First1->_Myval)) { return _First1; } // swap _First2 and _First1 _First1->_Next = _First2->_Next; // snip out *_First2 _BFirst->_Next = _First2; // insert *_First2 before *_First1 _First2->_Next = _First1; return _First2; } template static _Nodeptr _Sort(const _Nodeptr _BFirst, size_type _Bound, _Pr2 _Pred) { // Sort (_BFirst, _BFirst + _Bound), unless nullptr is encountered. // Returns a pointer one before the end of the sorted region. if (_Bound <= 2) { return _Sort2(_BFirst, _Pred); } const auto _Half_bound = _Bound / 2; const auto _BMid = _Sort(_BFirst, _Half_bound, _Pred); if (!_BMid->_Next) { return _BMid; } const auto _BLast = _Sort(_BMid, _Half_bound, _Pred); return _Inplace_merge(_BFirst, _BMid, _BLast, _Pred); } template static void _Sort(_Nodeptr _BFirst, _Pr2 _Pred) { auto _BMid = _Sort2(_BFirst, _Pred); size_type _Bound = 2; do { if (!_BMid->_Next) { return; } const auto _BLast = _Sort(_BMid, _Bound, _Pred); _BMid = _Inplace_merge(_BFirst, _BMid, _BLast, _Pred); _Bound <<= 1; } while (_Bound != 0); } _Nodeptr _Myhead; // pointer to head node }; template struct _Flist_insert_after_op2 { // forward_list insert-after operation which maintains exception safety using _Alnode_traits = allocator_traits<_Alnode>; using pointer = typename _Alnode_traits::pointer; using value_type = typename _Alnode_traits::value_type; explicit _Flist_insert_after_op2(_Alnode& _Al_) : _Al(_Al_), _Tail() {} _Flist_insert_after_op2(const _Flist_insert_after_op2&) = delete; _Flist_insert_after_op2& operator=(const _Flist_insert_after_op2&) = delete; template void _Append_n(typename _Alnode_traits::size_type _Count, const _CArgT&... _Carg) { // Append _Count elements, constructed from _Carg if (_Count <= 0) { return; } _Alloc_construct_ptr<_Alnode> _Newnode(_Al); if (_Tail == pointer{}) { _Newnode._Allocate(); // throws _Alnode_traits::construct(_Al, _STD addressof(_Newnode._Ptr->_Myval), _Carg...); // throws _Head = _Newnode._Ptr; _Tail = _Newnode._Ptr; --_Count; } for (; 0 < _Count; --_Count) { _Newnode._Allocate(); // throws _Alnode_traits::construct(_Al, _STD addressof(_Newnode._Ptr->_Myval), _Carg...); // throws _Construct_in_place(_Tail->_Next, _Newnode._Ptr); _Tail = _Newnode._Ptr; } (void) _Newnode._Release(); } template void _Append_range_unchecked(_InIt _First, const _Sentinel _Last) { // Append the values in [_First, _Last) if (_First == _Last) { // throws return; } _Alloc_construct_ptr<_Alnode> _Newnode(_Al); if (_Tail == pointer{}) { _Newnode._Allocate(); // throws _Alnode_traits::construct(_Al, _STD addressof(_Newnode._Ptr->_Myval), *_First); // throws const auto _Newhead = _Newnode._Release(); _Head = _Newhead; _Tail = _Newhead; ++_First; // throws } while (_First != _Last) { // throws _Newnode._Allocate(); // throws _Alnode_traits::construct(_Al, _STD addressof(_Newnode._Ptr->_Myval), *_First); // throws const auto _Newtail = _Newnode._Release(); _Construct_in_place(_Tail->_Next, _Newtail); _Tail = _Newtail; ++_First; // throws } } pointer _Attach_after(pointer _After) noexcept { // Attaches the elements in *this after _After, and resets *this to the default-initialized state const auto _Local_tail = _Tail; if (_Local_tail == pointer{}) { return _After; } _Construct_in_place(_Local_tail->_Next, _After->_Next); _After->_Next = _Head; _Tail = pointer{}; return _Local_tail; } ~_Flist_insert_after_op2() { if (_Tail == pointer{}) { return; } _Construct_in_place(_Tail->_Next, pointer{}); pointer _Subject = _Head; while (_Subject) { value_type::_Freenode(_Al, _STD exchange(_Subject, _Subject->_Next)); } } private: _Alnode& _Al; pointer _Tail; // Points to the most recently constructed node. If pointer{}, the value of _Head is indeterminate. // _Tail->_Next is not constructed. pointer _Head; // Points at the first constructed node. }; // CLASS TEMPLATE forward_list template > class forward_list { // singly linked list private: using _Alty = _Rebind_alloc_t<_Alloc, _Ty>; using _Alty_traits = allocator_traits<_Alty>; using _Node = _Flist_node<_Ty, typename _Alty_traits::void_pointer>; using _Alnode = _Rebind_alloc_t<_Alloc, _Node>; using _Alnode_traits = allocator_traits<_Alnode>; using _Nodeptr = typename _Alnode_traits::pointer; static_assert(!_ENFORCE_MATCHING_ALLOCATORS || is_same_v<_Ty, typename _Alloc::value_type>, _MISMATCHED_ALLOCATOR_MESSAGE("forward_list", "T")); using _Scary_val = _Flist_val, _Flist_simple_types<_Ty>, _Flist_iter_types<_Ty, typename _Alty_traits::size_type, typename _Alty_traits::difference_type, typename _Alty_traits::pointer, typename _Alty_traits::const_pointer, _Ty&, const _Ty&, _Nodeptr>>>; public: using value_type = _Ty; using allocator_type = _Alloc; using size_type = typename _Alty_traits::size_type; using difference_type = typename _Alty_traits::difference_type; using pointer = typename _Alty_traits::pointer; using const_pointer = typename _Alty_traits::const_pointer; using reference = value_type&; using const_reference = const value_type&; using iterator = _Flist_iterator<_Scary_val>; using const_iterator = _Flist_const_iterator<_Scary_val>; using _Unchecked_iterator = _Flist_unchecked_iterator<_Scary_val>; using _Unchecked_const_iterator = _Flist_unchecked_const_iterator<_Scary_val>; forward_list() noexcept(is_nothrow_default_constructible_v<_Alnode>) // strengthened : _Mypair(_Zero_then_variadic_args_t{}) { _Alloc_proxy(); } explicit forward_list(_CRT_GUARDOVERFLOW size_type _Count, const _Alloc& _Al = _Alloc()) : _Mypair(_One_then_variadic_args_t{}, _Al) { // construct list from _Count * _Ty(), optional allocator _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_n(_Count); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } forward_list(_CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val) : _Mypair(_Zero_then_variadic_args_t{}) { // construct list from _Count * _Val _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_n(_Count, _Val); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } forward_list(_CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { // construct list from _Count * _Val, allocator _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_n(_Count, _Val); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } explicit forward_list(const _Alloc& _Al) noexcept // strengthened : _Mypair(_One_then_variadic_args_t{}, _Al) { _Alloc_proxy(); } forward_list(const forward_list& _Right) : _Mypair(_One_then_variadic_args_t{}, _Alnode_traits::select_on_container_copy_construction(_Right._Getal())) { _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked(_Right._Unchecked_begin(), _Right._Unchecked_end()); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } forward_list(const forward_list& _Right, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked(_Right._Unchecked_begin(), _Right._Unchecked_end()); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } template , int> = 0> forward_list(_Iter _First, _Iter _Last) : _Mypair(_Zero_then_variadic_args_t{}) { _Adl_verify_range(_First, _Last); _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last)); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } template , int> = 0> forward_list(_Iter _First, _Iter _Last, const _Alloc& _Al) : _Mypair(_One_then_variadic_args_t{}, _Al) { _Adl_verify_range(_First, _Last); _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last)); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); } forward_list(forward_list&& _Right) noexcept // strengthened : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Alloc_proxy(); _Take_head(_Right); } forward_list(forward_list&& _Right, const _Alloc& _Al) noexcept( _Alnode_traits::is_always_equal::value) // strengthened : _Mypair(_One_then_variadic_args_t{}, _Al) { if _CONSTEXPR_IF (!_Alty_traits::is_always_equal::value) { if (_Getal() != _Right._Getal()) { _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked( _STD make_move_iterator(_Right._Unchecked_begin()), _Default_sentinel{}); _Alloc_proxy(); _Insert_op._Attach_after(_Mypair._Myval2._Before_head()); return; } } _Alloc_proxy(); _Take_head(_Right); } private: void _Move_assign(forward_list& _Right, _Equal_allocators) noexcept { clear(); _Pocma(_Getal(), _Right._Getal()); _Take_head(_Right); } void _Move_assign(forward_list& _Right, _Propagate_allocators) noexcept { if (_Getal() == _Right._Getal()) { _Move_assign(_Right, _Equal_allocators{}); } else { _Mypair._Myval2._Orphan_all(); clear(); _Mypair._Myval2._Reload_proxy( _GET_PROXY_ALLOCATOR(_Alty, _Getal()), _GET_PROXY_ALLOCATOR(_Alty, _Right._Getal())); _Pocma(_Getal(), _Right._Getal()); _Take_head(_Right); } } void _Move_assign(forward_list& _Right, _No_propagate_allocators) { if (_Getal() == _Right._Getal()) { _Move_assign(_Right, _Equal_allocators{}); } else { _Assign_unchecked(_STD make_move_iterator(_Right._Unchecked_begin()), _Right._Unchecked_end()); } } public: forward_list& operator=(forward_list&& _Right) noexcept( noexcept(_Move_assign(_Right, _Choose_pocma<_Alnode>{}))) /* strengthened */ { if (this != _STD addressof(_Right)) { _Move_assign(_Right, _Choose_pocma<_Alnode>{}); } return *this; } private: void _Take_head(forward_list& _Right) noexcept { // take contents from _Right, same allocator _Swap_proxy_and_iterators(_Right); _Mypair._Myval2._Myhead = _STD exchange(_Right._Mypair._Myval2._Myhead, nullptr); } public: void push_front(_Ty&& _Val) { // insert element at beginning _Insert_after(_Mypair._Myval2._Before_head(), _STD move(_Val)); } iterator insert_after(const_iterator _Where, _Ty&& _Val) { // insert _Val after _Where return emplace_after(_Where, _STD move(_Val)); } template decltype(auto) emplace_front(_Valty&&... _Val) { // insert element at beginning _Insert_after(_Mypair._Myval2._Before_head(), _STD forward<_Valty>(_Val)...); #if _HAS_CXX17 return front(); #endif // _HAS_CXX17 } template iterator emplace_after(const_iterator _Where, _Valty&&... _Val) { // insert element after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list insert_after iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Insert_after(_Where._Ptr, _STD forward<_Valty>(_Val)...); return _Make_iter(_Where._Ptr->_Next); } private: template void _Insert_after(_Nodeptr _Pnode, _Valty&&... _Val) { // insert element after _Where _Alloc_construct_ptr<_Alnode> _Newnode(_Getal()); _Newnode._Allocate(); // throws _Alnode_traits::construct( _Newnode._Al, _STD addressof(_Newnode._Ptr->_Myval), _STD forward<_Valty>(_Val)...); // throws _Construct_in_place(_Newnode._Ptr->_Next, _Pnode->_Next); _Pnode->_Next = _Newnode._Release(); } public: forward_list(initializer_list<_Ty> _Ilist, const _Alloc& _Al = allocator_type()) : _Mypair(_One_then_variadic_args_t{}, _Al) { auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alnode, _Getal()); _Container_proxy_ptr<_Alty> _Proxy(_Alproxy, _Mypair._Myval2); insert_after(before_begin(), _Ilist.begin(), _Ilist.end()); _Proxy._Release(); } forward_list& operator=(initializer_list<_Ty> _Ilist) { assign(_Ilist.begin(), _Ilist.end()); return *this; } void assign(initializer_list<_Ty> _Ilist) { assign(_Ilist.begin(), _Ilist.end()); } iterator insert_after(const_iterator _Where, initializer_list<_Ty> _Ilist) { // insert initializer_list return insert_after(_Where, _Ilist.begin(), _Ilist.end()); } ~forward_list() noexcept { clear(); #if _ITERATOR_DEBUG_LEVEL != 0 // TRANSITION, ABI auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alty, _Getal()); _Delete_plain_internal(_Alproxy, _Mypair._Myval2._Myproxy); #endif // _ITERATOR_DEBUG_LEVEL != 0 } private: void _Copy_assign(const forward_list& _Right, false_type) { _Pocca(_Getal(), _Right._Getal()); _Assign_unchecked(_Right._Unchecked_begin(), _Right._Unchecked_end()); } void _Copy_assign(const forward_list& _Right, true_type) { if (_Getal() != _Right._Getal()) { _Mypair._Myval2._Orphan_all(); clear(); _Mypair._Myval2._Reload_proxy( _GET_PROXY_ALLOCATOR(_Alnode, _Getal()), _GET_PROXY_ALLOCATOR(_Alnode, _Right._Getal())); } _Copy_assign(_Right, _No_propagate_allocators{}); } public: forward_list& operator=(const forward_list& _Right) { if (this != _STD addressof(_Right)) { _Copy_assign(_Right, _Choose_pocca<_Alnode>{}); } return *this; } _NODISCARD iterator before_begin() noexcept { return iterator(_Mypair._Myval2._Before_head(), _STD addressof(_Mypair._Myval2)); } _NODISCARD const_iterator before_begin() const noexcept { return const_iterator(_Mypair._Myval2._Before_head(), _STD addressof(_Mypair._Myval2)); } _NODISCARD const_iterator cbefore_begin() const noexcept { return before_begin(); } _NODISCARD iterator begin() noexcept { return iterator(_Mypair._Myval2._Myhead, _STD addressof(_Mypair._Myval2)); } _NODISCARD const_iterator begin() const noexcept { return const_iterator(_Mypair._Myval2._Myhead, _STD addressof(_Mypair._Myval2)); } _NODISCARD iterator end() noexcept { return iterator(nullptr, _STD addressof(_Mypair._Myval2)); } _NODISCARD const_iterator end() const noexcept { return const_iterator(nullptr, _STD addressof(_Mypair._Myval2)); } _Unchecked_iterator _Unchecked_before_begin() noexcept { return _Unchecked_iterator(_Mypair._Myval2._Before_head(), nullptr); } _Unchecked_iterator _Unchecked_begin() noexcept { return _Unchecked_iterator(_Mypair._Myval2._Myhead, nullptr); } _Unchecked_const_iterator _Unchecked_begin() const noexcept { return _Unchecked_const_iterator(_Mypair._Myval2._Myhead, nullptr); } _Default_sentinel _Unchecked_end() const noexcept { return {}; } iterator _Make_iter(_Nodeptr _Where) const noexcept { return iterator(_Where, _STD addressof(_Mypair._Myval2)); } _NODISCARD const_iterator cbegin() const noexcept { return begin(); } _NODISCARD const_iterator cend() const noexcept { return end(); } private: template void _Resize(_CRT_GUARDOVERFLOW size_type _Newsize, const _Args&... _Vals) { auto& _Al = _Getal(); auto _Ptr = _Mypair._Myval2._Before_head(); for (;;) { auto _Next = _Ptr->_Next; if (!_Next) { // list too short, insert remaining _Newsize objects initialized from _Vals... _Flist_insert_after_op2<_Alnode> _Insert_op(_Al); _Insert_op._Append_n(_Newsize, _Vals...); _Insert_op._Attach_after(_Ptr); return; } if (_Newsize == 0) { // list is too long, erase the _Next and after _Ptr->_Next = nullptr; do { const auto _Nextafter = _Next->_Next; #if _ITERATOR_DEBUG_LEVEL == 2 _Mypair._Myval2._Orphan_ptr(_Next); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Node::_Freenode(_Al, _Next); _Next = _Nextafter; } while (_Next); return; } _Ptr = _Next; --_Newsize; } } public: void resize(_CRT_GUARDOVERFLOW size_type _Newsize) { _Resize(_Newsize); } void resize(_CRT_GUARDOVERFLOW size_type _Newsize, const _Ty& _Val) { _Resize(_Newsize, _Val); } _NODISCARD size_type max_size() const noexcept { return (_STD min)( static_cast((numeric_limits::max)()), _Alnode_traits::max_size(_Getal())); } _NODISCARD bool empty() const noexcept { return _Mypair._Myval2._Myhead == nullptr; } _NODISCARD allocator_type get_allocator() const noexcept { return static_cast(_Getal()); } _NODISCARD reference front() noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Myhead != nullptr, "front() called on empty forward_list"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return _Mypair._Myval2._Myhead->_Myval; } _NODISCARD const_reference front() const noexcept /* strengthened */ { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Mypair._Myval2._Myhead != nullptr, "front() called on empty forward_list"); #endif // _CONTAINER_DEBUG_LEVEL > 0 return _Mypair._Myval2._Myhead->_Myval; } void push_front(const _Ty& _Val) { _Insert_after(_Mypair._Myval2._Before_head(), _Val); } void pop_front() noexcept /* strengthened */ { _Erase_after(_Mypair._Myval2._Before_head()); } private: template void _Assign_unchecked(_UIter _UFirst, _Sentinel _ULast) { auto _Myfirst = _Mypair._Myval2._Before_head(); for (; _UFirst != _ULast; ++_UFirst) { auto _Next = _Myfirst->_Next; if (!_Myfirst->_Next) { _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked(_UFirst, _ULast); _Insert_op._Attach_after(_Myfirst); return; } _Next->_Myval = *_UFirst; _Myfirst = _Next; } for (auto _To_delete = _STD exchange(_Myfirst->_Next, nullptr); _To_delete;) { auto _Next = _To_delete->_Next; #if _ITERATOR_DEBUG_LEVEL == 2 _Mypair._Myval2._Orphan_ptr(_To_delete); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Node::_Freenode(_Getal(), _To_delete); _To_delete = _Next; } } public: template , int> = 0> void assign(_Iter _First, _Iter _Last) { _Adl_verify_range(_First, _Last); _Assign_unchecked(_Get_unwrapped(_First), _Get_unwrapped(_Last)); } void assign(_CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val) { clear(); insert_after(before_begin(), _Count, _Val); } iterator insert_after(const_iterator _Where, const _Ty& _Val) { // insert _Val after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY(_Where._Getcont() == _STD addressof(_Mypair._Myval2), "insert_after location incompatible"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Insert_after(_Where._Ptr, _Val); return _Make_iter(_Where._Ptr->_Next); } iterator insert_after(const_iterator _Where, _CRT_GUARDOVERFLOW size_type _Count, const _Ty& _Val) { // insert _Count * _Val after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list insert_after location incompatible"); #endif // _ITERATOR_DEBUG_LEVEL == 2 if (_Count != 0) { _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_n(_Count, _Val); _Where._Ptr = _Insert_op._Attach_after(_Where._Ptr); } return _Make_iter(_Where._Ptr); } template , int> = 0> iterator insert_after(const_iterator _Where, _Iter _First, _Iter _Last) { // insert [_First, _Last) after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list insert_after location incompatible"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Adl_verify_range(_First, _Last); const auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); if (_UFirst == _ULast) { return _Make_iter(_Where._Ptr); } _Flist_insert_after_op2<_Alnode> _Insert_op(_Getal()); _Insert_op._Append_range_unchecked(_UFirst, _ULast); return _Make_iter(_Insert_op._Attach_after(_Where._Ptr)); } private: void _Erase_after(_Nodeptr _Pnode) noexcept { // erase element after _Pnode auto _Subject = _Pnode->_Next; #if _ITERATOR_DEBUG_LEVEL == 2 _Mypair._Myval2._Orphan_ptr(_Subject); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Pnode->_Next = _Subject->_Next; _Node::_Freenode(_Getal(), _Subject); } public: iterator erase_after(const_iterator _Where) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list erase_after iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Erase_after(_Where._Ptr); return _Make_iter(_Where._Ptr->_Next); } iterator erase_after(const_iterator _First, const_iterator _Last) noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL == 2 const auto _Mycont = _STD addressof(_Mypair._Myval2); _STL_VERIFY(_First._Getcont() == _Mycont && _Last._Getcont() == _Mycont, "forward_list erase_after iterator range from incorrect container"); #endif // _ITERATOR_DEBUG_LEVEL == 2 auto _Before = _First._Ptr; if (_Before != _Last._Ptr) { auto& _Al = _Getal(); for (;;) { const auto _Subject = _Before->_Next; if (_Subject == _Last._Ptr) { break; } #if _ITERATOR_DEBUG_LEVEL == 2 _Mypair._Myval2._Orphan_ptr(_Subject); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Before->_Next = _Subject->_Next; _Node::_Freenode(_Al, _Subject); } } return _Make_iter(_Last._Ptr); } void clear() noexcept { // erase all #if _ITERATOR_DEBUG_LEVEL == 2 _Mypair._Myval2._Orphan_ptr(nullptr); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Nodeptr _Pnext; _Nodeptr _Pnode = _STD exchange(_Mypair._Myval2._Myhead, nullptr); auto& _Al = _Getal(); for (; _Pnode; _Pnode = _Pnext) { // delete an element _Pnext = _Pnode->_Next; _Node::_Freenode(_Al, _Pnode); } } void swap(forward_list& _Right) noexcept /* strengthened */ { if (this != _STD addressof(_Right)) { _Pocs(_Getal(), _Right._Getal()); _Swap_proxy_and_iterators(_Right); _Swap_adl(_Mypair._Myval2._Myhead, _Right._Mypair._Myval2._Myhead); } } void splice_after(const_iterator _Where, forward_list& _Right) noexcept /* strengthened */ { // splice all of _Right after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list splice_after iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 if (this != _STD addressof(_Right) && !_Right.empty()) { // worth splicing, do it _Splice_after(_Where._Unwrapped(), _Right, _Right._Unchecked_before_begin(), _Default_sentinel{}); } } void splice_after(const_iterator _Where, forward_list&& _Right) noexcept /* strengthened */ { // splice all of _Right after _Where splice_after(_Where, _Right); } void splice_after(const_iterator _Where, forward_list& _Right, const_iterator _First) noexcept /* strengthened */ { // splice _Right (_First, _First + 2) after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list splice_after iterator outside range"); _STL_VERIFY(_First._Getcont() == _STD addressof(_Right._Mypair._Myval2), "forward_list splice_after iterator outside range"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Splice_after(_Where._Ptr, _Right, _First._Ptr); } void splice_after(const_iterator _Where, forward_list&& _Right, const_iterator _First) noexcept /* strengthened */ { // splice _Right (_First, _First + 2) after _Where splice_after(_Where, _Right, _First); } void splice_after(const_iterator _Where, forward_list& _Right, const_iterator _First, const_iterator _Last) noexcept /* strengthened */ { // splice _Right (_First, _Last) after _Where #if _ITERATOR_DEBUG_LEVEL == 2 _STL_VERIFY( _Where._Getcont() == _STD addressof(_Mypair._Myval2), "forward_list splice_after iterator outside range"); const auto _Rightcont = _STD addressof(_Right._Mypair._Myval2); _STL_VERIFY(_First._Getcont() == _Rightcont && _Last._Getcont() == _Rightcont, "forward_list splice_after range outside right"); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Splice_after(_Where._Unwrapped(), _Right, _First._Unwrapped(), _Last._Unwrapped()); } void splice_after(const_iterator _Where, forward_list&& _Right, const_iterator _First, const_iterator _Last) noexcept /* strengthened */ { // splice _Right [_First, _Last) after _Where splice_after(_Where, _Right, _First, _Last); } struct _Flist_node_remove_op { // tracks nodes pending removal in a remove operation, so that program-defined predicates may reference those // elements until the removal is complete. explicit _Flist_node_remove_op(forward_list& _List_) noexcept : _List(_List_), _Head(), _Tail(_STD addressof(_Head)) {} _Flist_node_remove_op(const _Flist_node_remove_op&) = delete; _Flist_node_remove_op& operator=(const _Flist_node_remove_op&) = delete; _Nodeptr _Transfer_back(const _Nodeptr _Predecessor) noexcept { // extract _Predecessor->_Next from the container, and add it to the singly-linked list of nodes to destroy // returns the successor of the removed node // snip the node out const auto _Removed = _Predecessor->_Next; const auto _Next = _Removed->_Next; _Removed->_Next = _Nodeptr(); _Predecessor->_Next = _Next; *_Tail = _Removed; _Tail = _STD addressof(_Removed->_Next); return _Next; } ~_Flist_node_remove_op() { auto& _Al = _List._Getal(); auto _Target = _Head; while (_Target) { auto _Next = _Target->_Next; #if _ITERATOR_DEBUG_LEVEL == 2 _List._Mypair._Myval2._Orphan_ptr(_Target); #endif // _ITERATOR_DEBUG_LEVEL == 2 _Alnode_traits::destroy(_Al, _STD addressof(_Target->_Next)); _Alnode_traits::destroy(_Al, _STD addressof(_Target->_Myval)); _Al.deallocate(_Target, 1); _Target = _Next; } } forward_list& _List; _Nodeptr _Head; _Nodeptr* _Tail; }; auto remove(const _Ty& _Val) { // erase each element matching _Val return remove_if([&](const _Ty& _Other) { return _Other == _Val; }); } template auto remove_if(_Pr1 _Pred) { // erase each element satisfying _Pr1 _Flist_node_remove_op _Op(*this); auto _Firstb = _Unchecked_before_begin(); size_type _Removed = 0; for (auto _First = _Unchecked_begin(); _First._Ptr;) { if (_Pred(*_First)) { _First._Ptr = _Op._Transfer_back(_Firstb._Ptr); ++_Removed; } else { // advance iterators _Firstb = _First; ++_First; } } #if _HAS_CXX20 return _Removed; #else // _HAS_CXX20 (void) _Removed; #endif // _HAS_CXX20 } auto unique() { // erase each element matching previous return unique(equal_to<>()); } template auto unique(_Pr2 _Pred) { // erase each element satisfying _Pred with previous _Flist_node_remove_op _Op(*this); auto _First = _Unchecked_begin(); size_type _Removed = 0; if (_First._Ptr) { // worth doing auto _After = _First; ++_After; while (_After._Ptr) { if (_Pred(*_First, *_After)) { _After._Ptr = _Op._Transfer_back(_First._Ptr); ++_Removed; } else { _First = _After; ++_After; } } } #if _HAS_CXX20 return _Removed; #else // _HAS_CXX20 (void) _Removed; #endif // _HAS_CXX20 } void merge(forward_list& _Right) { // merge in elements from _Right, both ordered by operator< _Merge1(_Right, less<>()); } void merge(forward_list&& _Right) { // merge in elements from _Right, both ordered by operator< _Merge1(_Right, less<>()); } template void merge(forward_list& _Right, _Pr2 _Pred) { // merge in elements from _Right, both ordered by _Pred _Merge1(_Right, _Pass_fn(_Pred)); } template void merge(forward_list&& _Right, _Pr2 _Pred) { // merge in elements from _Right, both ordered by _Pred _Merge1(_Right, _Pass_fn(_Pred)); } private: template void _Merge1(forward_list& _Right, _Pr2 _Pred) { // merge in elements from _Right, both ordered by _Pred #if _ITERATOR_DEBUG_LEVEL != 0 _DEBUG_ORDER_UNWRAPPED(_Unchecked_begin(), _Default_sentinel{}, _Pred); #endif // _ITERATOR_DEBUG_LEVEL != 0 if (this == _STD addressof(_Right)) { return; } auto& _My_data = _Mypair._Myval2; auto& _Right_data = _Right._Mypair._Myval2; #if _ITERATOR_DEBUG_LEVEL != 0 _DEBUG_ORDER_UNWRAPPED(_Right._Unchecked_begin(), _Default_sentinel{}, _Pred); if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "list allocators incompatible for merge"); } #endif // _ITERATOR_DEBUG_LEVEL != 0 if (!_My_data._Myhead) { // *this is empty; take all elements of _Right with no comparisons #if _ITERATOR_DEBUG_LEVEL == 2 { _Lockit _Lock(_LOCK_DEBUG); _Transfer_non_before_begin_ownership(_Right); } // unlock #endif // _ITERATOR_DEBUG_LEVEL == 2 _My_data._Myhead = _Right_data._Myhead; _Right_data._Myhead = nullptr; return; } #if _ITERATOR_DEBUG_LEVEL == 2 constexpr bool _Noexcept = noexcept(_DEBUG_LT_PRED(_Pred, _My_data._Myhead->_Myval, _Right_data._Myhead->_Myval)); if _CONSTEXPR_IF (_Noexcept) { // if the comparison is noexcept, we can take all the iterators in one go and avoid quadratic updates of // the iterator chain _Lockit _Lock(_LOCK_DEBUG); _Transfer_non_before_begin_ownership(_Right); } // unlock #endif // _ITERATOR_DEBUG_LEVEL == 2 if (!_Right_data._Myhead) { return; } auto _BFirst1 = _My_data._Before_head(); auto _First2 = _Right_data._Myhead; for (;;) { // process 1 splice _Nodeptr _First1; for (;;) { // advance _BFirst1 over elements already in position _First1 = _BFirst1->_Next; if (!_First1) { // all elements in _Right are greater than elements in *this, splice them all _BFirst1->_Next = _First2; _Right_data._Myhead = nullptr; return; } if (_DEBUG_LT_PRED(_Pred, _First2->_Myval, _First1->_Myval)) { // _First2->_Myval is out of order break; } // _First1->_Myval is already in position; advance _BFirst1 = _First1; } // find the end of the "run" of elements less than _First1->_Myval in _Right auto _BRun_end = _First2; _Nodeptr _Run_end; for (;;) { _Run_end = _BRun_end->_Next; if (!_Run_end) { break; } if (!_DEBUG_LT_PRED(_Pred, _Run_end->_Myval, _First1->_Myval)) { // _Run_end is the first element in _Right that shouldn't precede _First1->_Myval. // After the splice _First1->_Myval will be in position and must not be compared again. break; } _BRun_end = _Run_end; } #if _ITERATOR_DEBUG_LEVEL == 2 if _CONSTEXPR_IF (!_Noexcept) { _Lockit _Lock(_LOCK_DEBUG); for (auto _Next = _First2; _Next != _Run_end; _Next = _Next->_Next) { _Transfer_ownership(_Right, _Next); } } // unlock #endif // _ITERATOR_DEBUG_LEVEL == 2 _Right_data._Myhead = _Run_end; // snip out the run from its old position _BFirst1->_Next = _First2; // insert into new position _BRun_end->_Next = _First1; if (!_Run_end) { return; } _BFirst1 = _First1; _First2 = _Run_end; } } public: void sort() { // order sequence, using operator< _Scary_val::_Sort(_Mypair._Myval2._Before_head(), less<>{}); } template void sort(_Pr2 _Pred) { // order sequence, using _Pred _Scary_val::_Sort(_Mypair._Myval2._Before_head(), _Pass_fn(_Pred)); } void reverse() noexcept { // reverse sequence auto _Current = _Mypair._Myval2._Myhead; if (!_Current) { // empty forward_list return; } _Nodeptr _Prev{}; for (;;) { const auto _Next = _Current->_Next; _Current->_Next = _Prev; if (!_Next) { _Mypair._Myval2._Myhead = _Current; return; } _Prev = _Current; _Current = _Next; } } private: #if _ITERATOR_DEBUG_LEVEL == 2 void _Transfer_non_before_begin_ownership(forward_list& _Right) noexcept { // requires holding the debug lock const auto _Mycont = _STD addressof(_Mypair._Myval2); const auto _Myproxy = _Mycont->_Myproxy; const auto _Right_before_head = _Right._Mypair._Myval2._Before_head(); _Iterator_base12** _Pnext = &_Right._Mypair._Myval2._Myproxy->_Myfirstiter; while (*_Pnext) { const auto _Pnextptr = static_cast(**_Pnext)._Ptr; if (_Pnextptr == _Right_before_head) { _Pnext = &(*_Pnext)->_Mynextiter; } else { // take the iterator const auto _Extracted = *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter; _Extracted->_Myproxy = _Myproxy; _Extracted->_Mynextiter = _Myproxy->_Myfirstiter; _Myproxy->_Myfirstiter = _Extracted; } } } void _Transfer_ownership(forward_list& _Right, _Nodeptr _Target) noexcept { // requires holding the debug lock const auto _Mycont = _STD addressof(_Mypair._Myval2); const auto _Myproxy = _Mycont->_Myproxy; _Iterator_base12** _Pnext = &_Right._Mypair._Myval2._Myproxy->_Myfirstiter; while (*_Pnext) { const auto _Pnextptr = static_cast(**_Pnext)._Ptr; if (_Pnextptr != _Target) { _Pnext = &(*_Pnext)->_Mynextiter; } else { // take the iterator const auto _Extracted = *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter; _Extracted->_Myproxy = _Myproxy; _Extracted->_Mynextiter = _Myproxy->_Myfirstiter; _Myproxy->_Myfirstiter = _Extracted; } } } #endif // _ITERATOR_DEBUG_LEVEL == 2 void _Splice_after(_Nodeptr _Where, forward_list& _Right, _Nodeptr _Prev) noexcept { // splice _Right (_Prev, _Prev + 2) after _Where #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Right; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 // _ITERATOR_DEBUG_LEVEL != 0 vvv if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "forward_list containers incompatible for splice_after"); } #endif // _ITERATOR_DEBUG_LEVEL == 0 #if _ITERATOR_DEBUG_LEVEL == 2 if (this != _STD addressof(_Right)) { _Lockit _Lock(_LOCK_DEBUG); _Transfer_ownership(_Right, _Prev->_Next); } #endif // _ITERATOR_DEBUG_LEVEL == 2 if (_Where != _Prev) { const auto _First = _Prev->_Next; if (_Where != _First) { _Prev->_Next = _First->_Next; _First->_Next = _Where->_Next; _Where->_Next = _First; } } } template void _Splice_after(_Unchecked_const_iterator _Where, forward_list& _Right, _Unchecked_const_iterator _First, _Sentinel _Last) noexcept { // splice _Right (_First, _Last) just after _Where #if _ITERATOR_DEBUG_LEVEL == 0 (void) _Right; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 // _ITERATOR_DEBUG_LEVEL != 0 vvv if _CONSTEXPR_IF (!_Alnode_traits::is_always_equal::value) { _STL_VERIFY(_Getal() == _Right._Getal(), "forward_list containers incompatible for splice_after"); } #endif // _ITERATOR_DEBUG_LEVEL == 0 if (_First == _Last) { return; } #if _ITERATOR_DEBUG_LEVEL == 2 if (this != _STD addressof(_Right)) { // transfer ownership of (_First, _Last) _Lockit _Lock(_LOCK_DEBUG); _Unchecked_const_iterator _Next = _First; while (++_Next != _Last) { // transfer ownership _Transfer_ownership(_Right, _Next._Ptr); } } #endif // _ITERATOR_DEBUG_LEVEL == 2 // find prev(_Last) _Unchecked_const_iterator _After = _First; ++_After; if (_After == _Last) { return; } _Unchecked_const_iterator _Prev_last = _First; do { _Prev_last = _After; ++_After; } while (_After != _Last); const auto _Extracted_head = _First._Ptr->_Next; _First._Ptr->_Next = _After._Ptr; _Prev_last._Ptr->_Next = _Where._Ptr->_Next; _Where._Ptr->_Next = _Extracted_head; } void _Alloc_proxy() { _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alnode, _Getal())); } void _Swap_proxy_and_iterators(forward_list& _Right) noexcept { _Mypair._Myval2._Swap_proxy_and_iterators(_Right._Mypair._Myval2); } _Alnode& _Getal() noexcept { return _Mypair._Get_first(); } const _Alnode& _Getal() const noexcept { return _Mypair._Get_first(); } _Compressed_pair<_Alnode, _Scary_val> _Mypair; }; #if _HAS_CXX17 template >, enable_if_t, _Is_allocator<_Alloc>>, int> = 0> forward_list(_Iter, _Iter, _Alloc = _Alloc()) -> forward_list<_Iter_value_t<_Iter>, _Alloc>; #endif // _HAS_CXX17 template void swap(forward_list<_Ty, _Alloc>& _Left, forward_list<_Ty, _Alloc>& _Right) noexcept /* strengthened */ { _Left.swap(_Right); } template _NODISCARD bool operator==(const forward_list<_Ty, _Alloc>& _Left, const forward_list<_Ty, _Alloc>& _Right) { return _STD equal(_Left.begin(), _Left.end(), _Right.begin(), _Right.end()); } template _NODISCARD bool operator!=(const forward_list<_Ty, _Alloc>& _Left, const forward_list<_Ty, _Alloc>& _Right) { return !(_Left == _Right); } template _NODISCARD bool operator<(const forward_list<_Ty, _Alloc>& _Left, const forward_list<_Ty, _Alloc>& _Right) { return _STD lexicographical_compare(_Left.begin(), _Left.end(), _Right.begin(), _Right.end()); } template _NODISCARD bool operator>(const forward_list<_Ty, _Alloc>& _Left, const forward_list<_Ty, _Alloc>& _Right) { return _Right < _Left; } template _NODISCARD bool operator<=(const forward_list<_Ty, _Alloc>& _Left, const forward_list<_Ty, _Alloc>& _Right) { return !(_Right < _Left); } template _NODISCARD bool operator>=(const forward_list<_Ty, _Alloc>& _Left, const forward_list<_Ty, _Alloc>& _Right) { return !(_Left < _Right); } #if _HAS_CXX20 template typename forward_list<_Ty, _Alloc>::size_type erase(forward_list<_Ty, _Alloc>& _Cont, const _Uty& _Val) { return _Cont.remove_if([&](_Ty& _Elem) { return _Elem == _Val; }); } template typename forward_list<_Ty, _Alloc>::size_type erase_if(forward_list<_Ty, _Alloc>& _Cont, _Pr _Pred) { return _Cont.remove_if(_Pass_fn(_Pred)); } #endif // _HAS_CXX20 #if _HAS_CXX17 namespace pmr { template using forward_list = _STD forward_list<_Ty, polymorphic_allocator<_Ty>>; } // namespace pmr #endif // _HAS_CXX17 _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _FORWARD_LIST_