On Wed, 4 Dec 2024 at 21:50, Jonathan Wakely <jwak...@redhat.com> wrote: > > On 04/12/24 19:27 +0100, François Dumont wrote: > >Hi > > > >I've completed the synchronization with your equivalent PR for > >std::list so here is the updated patch. > > > >PR updated a couple of days ago. > > > >Note that I've started to rework the patch for the same in _Hashtable. > > Great, thanks.
Ugh, gmail completely mangles this mail for me. You can see my comments and questions about changing _Link_type to _Base_ptr here: https://gcc.gnu.org/pipermail/gcc-patches/2024-December/670872.html > >François > > > > > >On 30/11/2024 18:21, Jonathan Wakely wrote: > >> > >> > >>On Sat, 30 Nov 2024, 13:52 François Dumont, <frs.dum...@gmail.com> wrote: > >> > >> Hi > >> > >> I've applied all your comments below and the ones you did on the > >> PR directly. > >> > >> When all new types totally seperated from the legacy types > >> _Rb_tree_node_traits is indeed useless. > >> > >> Regarding _Rb_tree_helpers I got rid of it but move the > >> insert-and-rebalance and rebalance-for-erase function to > >> _Node_traits<>. > >> > >> PR updated: > >> > >> https://forge.sourceware.org/gcc/gcc-TEST/pulls/27 > >> > >> libstdc++: Add fancy pointer support in map and set Support fancy > >> allocator pointer type in std::_Rb_tree<>. In case of fancy > >> pointer type the container is now storing the pointer to > >> __rb_tree::_Node<_ValPtr> as a pointer to > >> __rb_tree::_Node_base<_VoidPtr>. Many methods are adapted to take > >> and return _Base_ptr in place of _Link_type which has been renamed > >> into _Node_ptr. As all node are stored as _Base_ptr have all > >> methods working with this type and remove _Const_Base_ptr and > >> _Const_Node_ptr and all methods associated with it. > >> > >> > >>Sounds good! I'll take another look on Monday. > >> > >> > >> libstdc++-v3/ChangeLog: * include/bits/stl_tree.h > >> [_GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE]: New macro to control usage > >> of the code required to support fancy allocator pointer type. > >> (_Rb_tree_node_base::_Const_Base_ptr): Remove. > >> (_Rb_tree_node_base::_S_minimum, _Rb_tree_node_base::_S_maximum): > >> Remove overloads for _Const_Base_ptr. > >> (_Rb_tree_node_base::_M_base_ptr()): New. > >> (_Rb_tree_node_base::_M_node_ptr<_NodePtr>()): New. > >> (_Rb_tree_node::_Link_type): Rename into... > >> (_Rb_tree_node::_Node_ptr): ...this. (__rb_tree::_Node_base<>): > >> New. (__rb_tree::_Header<>): New. (__rb_tree::_Node<>): New. > >> (_Rb_tree_increment(const _Rb_tree_node_base*)): Remove > >> declaration. (_Rb_tree_decrement(const _Rb_tree_node_base*)): > >> Remove declaration. (_Rb_tree_iterator<>::_Link_type): Rename > >> into... (_Rb_tree_iterator<>::_Node_ptr): ...this. > >> (_Rb_tree_const_iterator<>::_Link_type): Rename into... > >> (_Rb_tree_const_iterator<>::_Node_ptr): ...this. > >> (_Rb_tree_const_iterator<>::_M_const_cast): Remove. > >> (_Rb_tree_const_iterator<>::_M_node): Change type into _Base_ptr. > >> (__rb_tree::_Iterator<>): New. (__rb_tree::_Node_traits<>): New. > >> (_Rb_tree<>::_Node_base, _Rb_tree::_Node_type): New. > >> (_Rb_tree<>::_Link_type): Rename into... (_Rb_tree<>::_Node_ptr): > >> ...this. (_Rb_tree<>::_Const_Base_ptr, > >> _Rb_tree<>::_Const_Node_ptr): Remove. (_Rb_tree<>): Adapt to > >> generalize usage of _Base_ptr in place of former _Link_type now > >> _Node_ptr. (_Rb_tree<>::_M_mbegin): Remove. > >> (_Rb_tree<>::_S_left(_Const_Base_ptr)): Remove. > >> (_Rb_tree<>::_S_right(_Const_Base_ptr)): Remove. > >> (_Rb_tree<>::_S_maximum(_Const_Base_ptr)): Remove. > >> (_Rb_tree<>::_S_minimum(_Const_Base_ptr)): Remove. * > >> testsuite/23_containers/map/allocator/ext_ptr.cc: New test case. * > >> testsuite/23_containers/multimap/allocator/ext_ptr.cc: New test > >> case. * testsuite/23_containers/multiset/allocator/ext_ptr.cc: New > >> test case. * testsuite/23_containers/set/allocator/ext_ptr.cc: New > >> test case. > >> > >> I've tested it in C++98/C++17/C++20 with default > >> _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE and with it 9001. > >> > >> François > >> > >> On 18/11/2024 17:39, Jonathan Wakely wrote: > >>> On 18/11/24 06:57 +0100, François Dumont wrote: > >>>> Hi > >>>> > >>>> Here is a new proposal with all the cleanup regarding _Const_Base_ptr > >>>> that makes support of allocator's fancy pointer type simpler. > >>>> > >>>> Also submitted as PR: > >>>> > >>>> https://forge.sourceware.org/gcc/gcc-TEST/pulls/27 > >>>> > >>>> libstdc++: Add fancy pointer support in map and set > >>>> > >>>> Support fancy allocator pointer type instd::_Rb_tree<>. > >>>> > >>>> In case of fancy pointer type the container is now storing the > >>>> pointer to > >>>> _Rb_tree_pnode<> as a pointer to _Rb_tree_pnode_base<>. > >>>> > >>>> Many methods are adapted to take and return _Base_ptr in place of > >>>> _Link_type > >>>> which has been renamed into _Node_ptr. > >>>> > >>>> As all node are stored as _Base_ptr have all methods working with > >>>> this type > >>>> and remove _Const_Base_ptr and all methods associated to it. > >>>> > >>>> libstdc++-v3/ChangeLog: > >>>> > >>>> * include/bits/stl_set.h (std::set<>::upper_bound<>(const > >>>> _Kt&) const): Fix > >>>> decltype typo to use const_iterator. > >>>> * include/bits/stl_tree.h > >>>> (_Rb_tree_ptr_traits<>): New. > >>>> (_Rb_tree_pnode_base<>): New. > >>>> (_Rb_tree_node_base): Inherit from latter. > >>>> (_Rb_tree_node_base::_Const_Base_ptr): Remove. > >>>> (_Rb_tree_node_base::_S_minimum(_Const_Base_ptr)): Remove. > >>>> (_Rb_tree_node_base::_S_maximum(_Const_Base_ptr)): Remove. > >>>> (_Rb_tree_pheader): New. > >>>> (_Rb_tree_header): Inherit from latter. > >>>> (_Rb_tree_node_val): New. > >>>> (_Rb_tree_node): Inherit from latter. > >>>> (_Rb_tree_pnode): New. > >>>> (_Rb_tree_iterator<>::_Link_type): Rename into... > >>>> (_Rb_tree_iterator<>::_Node_ptr): ...this. > >>>> (_Rb_tree_const_iterator<>::_Link_type): Rename into... > >>>> (_Rb_tree_const_iterator<>::_Node_ptr): ...this. > >>>> (_Rb_tree_const_iterator<>::_M_node): Change type into > >>>> _Base_ptr. > >>>> (_Rb_tree_const_iterator<>::_M_const_cast): Remove. > >>>> (_Rb_tree_helpers<>): New. > >>>> (_Rb_tree_piterator): New. > >>>> (_Rb_tree_const_piterator): New. > >>>> (_Rb_tree_node_traits<>): New. > >>>> (_Rb_tree::_Node_base, _Rb_tree::_Node_type): New. > >>>> (_Rb_tree<>::_Const_Base_ptr): Remove. > >>>> (_Rb_tree): Adapt to generalize usage of _Base_ptr in > >>>> place of _Link_type. > >>>> (_Rb_tree<>::_M_mbegin): Remove. > >>>> (_Rb_tree<>::_S_left(_Const_Base_ptr)): Remove. > >>>> (_Rb_tree<>::_S_right(_Const_Base_ptr)): Remove. > >>>> (_Rb_tree<>::_S_maximum(_Const_Base_ptr)): Remove. > >>>> (_Rb_tree<>::_S_minimum(_Const_Base_ptr)): Remove. > >>>> * testsuite/23_containers/map/allocator/ext_ptr.cc: New > >>>> test case. > >>>> * testsuite/23_containers/multimap/allocator/ext_ptr.cc: > >>>> New test case. > >>>> * testsuite/23_containers/multiset/allocator/ext_ptr.cc: > >>>> New test case. > >>>> * testsuite/23_containers/set/allocator/ext_ptr.cc: New > >>>> test case. > >>>> > >>>> Tested under Linux x64. > >>>> > >>>> > >>>> Note that I've also run the 23_containers tests on map, multimap, > >>>> multiset and set tweaking implementation > >>>> so that new types are being used when C++11 or later even if allocator > >>>> pointer type is a C pointer. > >>> Please take a look at the _GLIBCXX_USE_ALLOC_PTR_xxx macros in > >>> https://gcc.gnu.org/pipermail/gcc-patches/2024-November/669128.html > >>> andhttps://gcc.gnu.org/pipermail/gcc-patches/2024-November/669127.html > >>> Those macros allow the fancy pointer support to be disabled, in case > >>> it will break anything for current users. Maybe more importantly, it > >>> allows the new node types to be used always, even for T*. That means > >>> we can run the entire testsuite using the new nodes without tweaking > >>> the implementation. > >>> > >>> Please consider a _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE macro (or some > >>> other name). > >>> > >>>> Ok to commit ? > >>>> > >>>> François > >>>> > >>>> On 12/11/2024 15:56, Jonathan Wakely wrote: > >>>>> On Mon, 4 Nov 2024 at 21:34, François Dumont<frs.dum...@gmail.com> > >>>>> <mailto:frs.dum...@gmail.com> wrote: > >>>>>> On 04/11/2024 19:45, Jonathan Wakely wrote: > >>>>>>> On Mon, 4 Nov 2024 at 18:30, François Dumont<frs.dum...@gmail.com> > >>>>>>> <mailto:frs.dum...@gmail.com> wrote: > >>>>>>>> On 21/10/2024 06:56, François Dumont wrote: > >>>>>>>> > >>>>>>>> > >>>>>>>> On 17/10/2024 23:11, Jonathan Wakely wrote: > >>>>>>>> > >>>>>>>> > >>>>>>>> > >>>>>>>> On Thu, 17 Oct 2024 at 21:39, Jonathan > >>>>>>>> Wakely<jwakely....@gmail.com> <mailto:jwakely....@gmail.com> wrote: > >>>>>>>>> On Thu, 17 Oct 2024 at 20:52, François > >>>>>>>>> Dumont<frs.dum...@gmail.com> <mailto:frs.dum...@gmail.com> wrote: > >>>>>>>>>> Here is an updated version that compiles, I think, all your > >>>>>>>>>> feedbacks. It's much cleaner indeed. > >>>>>>>>> Thanks, I'll take a look tomorrow. > >>>>>>>>> > >>>>>>>>>> It's also tested in C++98/17/23. > >>>>>>>>>> > >>>>>>>>>> I'm surprised that we do not need to consider > >>>>>>>>>> potentialallocator::const_pointer. > >>>>>>>>> Do you mean consider the case whereAlloc::const_pointer is not > >>>>>>>>> the same type as rebinding 'pointer' to a const element type? > >>>>>>>> Yes, exactly. > >>>>>>>> > >>>>>>>> > >>>>>>>>> We don't need to consider that because we never get a > >>>>>>>>> 'const_pointer' from the allocator, and we never need to pass a > >>>>>>>>> 'const_pointer' to the allocator. The allocator's 'allocate' and > >>>>>>>>> 'deallocate' members both work with the 'pointer' type, so we only > >>>>>>>>> need to use that type when interacting with the allocator. For all > >>>>>>>>> the other uses, such as _Const_Node_ptr, what we need is a > >>>>>>>>> pointer-to-const that's compatible with the allocator's pointer > >>>>>>>>> type. It doesn't actually matter if it's the same type as > >>>>>>>>> allocator_traits<Alloc>::const_pointer, because we don't need > >>>>>>>> Sorry, I sent the email before finishing that thought! > >>>>>>>> > >>>>>>>> ... we don't need to pass a const_pointer to anything, we only > >>>>>>>> need it for the container's own purposes. > >>>>>>>> > >>>>>>>> But thinking about it some more, do we even need a const-pointer > >>>>>>>> for the container? Currently the const_iterator stores a > >>>>>>>> const-pointer, and some members like _M_root() and _M_leftmost() > >>>>>>>> return a const-pointer. But they don't need to. The nodes are all > >>>>>>>> pointed to by a non-const _Base_ptr, none of the storage managed by > >>>>>>>> the container is const. > >>>>>>>> > >>>>>>>> Except _M_impl._M_header in a const context. > >>>>>>>> > >>>>>>>> Using const_cast would result in a similar UB that you fixed on > >>>>>>>> _GLIBCXX_DEBUG containers, no ? > >>>>>>> We only use a pointer to _M_header for the past-the-end iterator, > >>>>>>> which is not dereferenceable. It's OK to do the const_cast, it's > >>>>>>> not > >>>>>>> OK to write something through that pointer/reference if the object > >>>>>>> is > >>>>>>> really const. But you can't write through a past-the-end pointer > >>>>>>> anyway. > >>>>>>> > >>>>>> One last question then to complete this work, is it fine to change > >>>>>> _Rb_tree_const_iterator::_M_node to _Base_ptr ? No abi issue in > >>>>>> doing so ? > >>>>> I thought I'd sent a reply to this question, but I don't see it in > >>>>> the > >>>>> archives, sorry. > >>>>> > >>>>> So changing from _Const_Base_ptr to _Base_ptr? Yes, I think that's > >>>>> OK. > >>>>> > >>>> diff --git a/libstdc++-v3/include/bits/stl_set.h > >>>> b/libstdc++-v3/include/bits/stl_set.h > >>>> index c0eb4dbf65f..3d17626f330 100644 > >>>> --- a/libstdc++-v3/include/bits/stl_set.h > >>>> +++ b/libstdc++-v3/include/bits/stl_set.h > >>>> @@ -875,7 +875,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER > >>>> template<typename _Kt> > >>>> auto > >>>> upper_bound(const _Kt& __x) const > >>>> - -> decltype(iterator(_M_t._M_upper_bound_tr(__x))) > >>>> + -> decltype(const_iterator(_M_t._M_upper_bound_tr(__x))) > >>>> { return const_iterator(_M_t._M_upper_bound_tr(__x)); } > >>>> #endif > >>>> ///@} > >>>> diff --git a/libstdc++-v3/include/bits/stl_tree.h > >>>> b/libstdc++-v3/include/bits/stl_tree.h > >>>> index bc27e191e8b..c6cba99726d 100644 > >>>> --- a/libstdc++-v3/include/bits/stl_tree.h > >>>> +++ b/libstdc++-v3/include/bits/stl_tree.h > >>>> @@ -96,44 +96,100 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> > >>>> enum _Rb_tree_color { _S_red = false, _S_black = true }; > >>>> > >>>> - struct _Rb_tree_node_base > >>>> - { > >>>> - typedef _Rb_tree_node_base* _Base_ptr; > >>>> - typedef const _Rb_tree_node_base* _Const_Base_ptr; > >>>> - > >>>> - _Rb_tree_color _M_color; > >>>> - _Base_ptr _M_parent; > >>>> - _Base_ptr _M_left; > >>>> - _Base_ptr _M_right; > >>>> - > >>>> - static _Base_ptr > >>>> - _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> +#if __cplusplus >= 201103L > >>>> + template<typename _Ptr> > >>>> + struct _Rb_tree_ptr_traits > >>>> { > >>>> - while (__x->_M_left != 0) __x = __x->_M_left; > >>>> - return __x; > >>>> - } > >>>> + template<typename _Tp> > >>>> + struct __rebind > >>>> + { using __type = __ptr_rebind<_Ptr, _Tp>; }; > >>> This only seems to be used in one place, can you just use __ptr_rebind > >>> directly in that one place? > >>> > >>>> + > >>>> + template<typename _BasePtr> > >>>> + static _Ptr > >>>> + _S_ptr_to(_BasePtr __this) noexcept > >>>> + { return pointer_traits<_Ptr>::pointer_to(*__this); } > >>> This is also only needed in exactly one place. I avoided needing this > >>> function by adding _M_base_ptr() to the node base classes. > >>> > >>> The whole of this _Rb_tree_ptr_traits class template seems unnecessary > >>> to me. Just inline the code directly into the places it's needed. > >>> You're not optimizing anything by replacing > >>> pointer_traits<T*>::pointer_to with > >>> _Rb_tree_ptr_traits<T*>::_S_ptr_to, it's still a class template > >>> specialization and a function call. > >>> > >>>> + > >>>> + template<typename _BasePtr, typename _UpPtr> > >>>> + static _UpPtr > >>>> + _S_up_ptr_to(_BasePtr __this) noexcept > >>> pointer_to is not guaranteed to be noexcept. > >>> > >>> This appears to be a downcast, i.e. a base-to-derived cast, having > >>> "up" in the name is a bit confusing. > >>> > >>>> + { > >>>> + using __ptr_traits = pointer_traits<_UpPtr>; > >>>> + using __up_type = typename __ptr_traits::element_type; > >>>> + auto __up_this = static_cast<__up_type*>(__this); > >>>> + return __ptr_traits::pointer_to(*__up_this); > >>>> + } > >>>> + }; > >>>> +#else > >>>> + template<typename _Ptr> > >>>> + struct _Rb_tree_ptr_traits; > >>>> +#endif > >>>> > >>>> - static _Const_Base_ptr > >>>> - _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> + template<typename _Tp> > >>>> + struct _Rb_tree_ptr_traits<_Tp*> > >>>> { > >>>> - while (__x->_M_left != 0) __x = __x->_M_left; > >>>> - return __x; > >>>> - } > >>>> + template<typename> > >>>> + struct __rebind > >>>> + { typedef _Tp* __type; }; > >>>> + > >>>> + template<typename _BasePtr> > >>>> + static _Tp* > >>>> + _S_ptr_to(_BasePtr __this) _GLIBCXX_NOEXCEPT > >>>> + { return static_cast<_Tp*>(__this); } > >>>> + > >>>> + template<typename _BasePtr, typename _UpPtr> > >>>> + static _UpPtr > >>>> + _S_up_ptr_to(_BasePtr __this) _GLIBCXX_NOEXCEPT > >>>> + { return static_cast<_UpPtr>(__this); } > >>>> + }; > >>>> > >>>> - static _Base_ptr > >>>> - _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> + template<typename _BasePtr> > >>>> + struct _Rb_tree_pnode_base > >>>> { > >>>> - while (__x->_M_right != 0) __x = __x->_M_right; > >>>> - return __x; > >>>> - } > >>>> + typedef typename _Rb_tree_ptr_traits<_BasePtr>::template > >>>> + __rebind<_Rb_tree_pnode_base>::__type _Base_ptr; > >>> The names _BasePtr and _Base_ptr are very similar, and confusing. > >>> It looks like sometimes the template argument that is substituted for > >>> _BasePtr is sometimes a derived class (_Rb_tree_node_base) and > >>> sometimes is _ValPtr. It's never a "base" pointer. Please rename it. > >>> > >>>> - static _Const_Base_ptr > >>>> - _S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> - { > >>>> - while (__x->_M_right != 0) __x = __x->_M_right; > >>>> - return __x; > >>>> - } > >>>> - }; > >>>> + _Base_ptr > >>>> + _M_self_ptr() _GLIBCXX_NOEXCEPT > >>> Why do we need a non-const overload? The const one will work for all > >>> cases, right? > >>> > >>> I added a comment to my list patches pointing out that it's not > >>> const-correct, but is safe as long as only used carefully. > >>> > >>> > >>>> + { return _Rb_tree_ptr_traits<_Base_ptr>::_S_ptr_to(this); } > >>>> + > >>>> + _Base_ptr > >>>> + _M_self_ptr() const _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _Rb_tree_pnode_base* __self = > >>>> const_cast<_Rb_tree_pnode_base*>(this); > >>>> + return __self->_M_self_ptr(); > >>>> + } > >>>> + > >>>> + template<typename _NodePtr> > >>>> + _NodePtr > >>>> + _M_node_ptr() _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + return _Rb_tree_ptr_traits<_Base_ptr>::template > >>>> + _S_up_ptr_to<_Rb_tree_pnode_base*, _NodePtr>(this); > >>>> + } > >>>> + > >>>> + _Rb_tree_color _M_color; > >>>> + _Base_ptr _M_parent; > >>>> + _Base_ptr _M_left; > >>>> + _Base_ptr _M_right; > >>>> + > >>>> + static _Base_ptr > >>>> + _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + while (__x->_M_left) __x = __x->_M_left; > >>>> + return __x; > >>>> + } > >>>> + > >>>> + static _Base_ptr > >>>> + _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + while (__x->_M_right) __x = __x->_M_right; > >>>> + return __x; > >>>> + } > >>>> + }; > >>>> + > >>>> + struct _Rb_tree_node_base > >>>> + : _Rb_tree_pnode_base<_Rb_tree_node_base*> > >>>> + { }; > >>> This approaches means that the existing specializations of RB trees > >>> all get twice as many base classes. I don't see an ABI problem, and it > >>> should generate the same code for optimized builds, but increasing the > >>> inheritance depth and the number of class template instantiations > >>> gives the compiler more work to do, compiling slower, and generating > >>> additional debug info (and maybe RTTI?) > >>> > >>> Please take a look at how I did it for the linked lists, where > >>> specializations for non-fancy pointers, e.g. _List_node<T>, are mostly > >>> unchanged. They don't get any new base classes, just some new typedefs > >>> and new accessors like: > >>> > >>> _Base_ptr _M_base() { return this; } > >>> const _List_node* _M_base() const { return this; } > >>> > >>> The _List_node_traits class template is used bystd::list etc. to > >>> select whether to use _List_node<Alloc::value_type> or > >>> __list::_Node<Alloc::pointer>. All the fancy pointer support is in the > >>> new type hierarchy, __list::_Node_base, __list::_Node, and > >>> __list::_Iterator. The old types like _List_node don't really change. > >>> > >>> I found that using the __list namespace with new types reduced a lot > >>> of confusion I had between the very similar names _List_node and > >>> _List_pnode (or _List_ptr_node, or other names like that). > >>> > >>> Maybe we could call it _List::_Node instead of __list::_Node, so it's > >>> a bit closer to _List_node but still distinguishable (and would > >>> produce very slightly shorter mangled names). I didn't do that, > >>> because our convention is to name impl namespaces as __foo not _Foo. > >>> > >>> That pattern could naturally be extended to __tree::_Node (or > >>> _Tree::_Node) as well. > >>> > >>>> // Helper type offering value initialization guarantee on the > >>>> compare functor. > >>>> template<typename _Key_compare> > >>>> @@ -163,81 +219,108 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> }; > >>>> > >>>> // Helper type to manage default initialization of node count and > >>>> header. > >>>> - struct _Rb_tree_header > >>>> - { > >>>> - _Rb_tree_node_base _M_header; > >>>> - size_t _M_node_count; // Keeps track of size of tree. > >>>> - > >>>> - _Rb_tree_header() _GLIBCXX_NOEXCEPT > >>>> + template<typename _NodeBase> > >>>> + struct _Rb_tree_pheader > >>>> { > >>>> - _M_header._M_color = _S_red; > >>>> - _M_reset(); > >>>> - } > >>>> + private: > >>>> + typedef typename _NodeBase::_Base_ptr _Base_ptr; > >>>> + > >>>> + public: > >>>> + _NodeBase _M_header; > >>>> + size_t _M_node_count; // Keeps track of size of tree. > >>>> + > >>>> + _Rb_tree_pheader() _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _M_header._M_color = _S_red; > >>>> + _M_reset(); > >>>> + } > >>>> > >>>> #if __cplusplus >= 201103L > >>>> - _Rb_tree_header(_Rb_tree_header&& __x) noexcept > >>>> - { > >>>> - if (__x._M_header._M_parent != nullptr) > >>>> - _M_move_data(__x); > >>>> - else > >>>> - { > >>>> - _M_header._M_color = _S_red; > >>>> - _M_reset(); > >>>> - } > >>>> - } > >>>> + _Rb_tree_pheader(_Rb_tree_pheader&& __x) noexcept > >>>> + { > >>>> + if (__x._M_header._M_parent) > >>>> + _M_move_data(__x); > >>>> + else > >>>> + { > >>>> + _M_header._M_color = _S_red; > >>>> + _M_reset(); > >>>> + } > >>>> + } > >>>> #endif > >>>> > >>>> - void > >>>> - _M_move_data(_Rb_tree_header& __from) > >>>> - { > >>>> - _M_header._M_color = __from._M_header._M_color; > >>>> - _M_header._M_parent = __from._M_header._M_parent; > >>>> - _M_header._M_left = __from._M_header._M_left; > >>>> - _M_header._M_right = __from._M_header._M_right; > >>>> - _M_header._M_parent->_M_parent = &_M_header; > >>>> - _M_node_count = __from._M_node_count; > >>>> - > >>>> - __from._M_reset(); > >>>> - } > >>>> + void > >>>> + _M_move_data(_Rb_tree_pheader& __from) > >>>> + { > >>>> + _M_header._M_color = __from._M_header._M_color; > >>>> + _M_header._M_parent = __from._M_header._M_parent; > >>>> + _M_header._M_left = __from._M_header._M_left; > >>>> + _M_header._M_right = __from._M_header._M_right; > >>>> + _M_header._M_parent->_M_parent = _M_header._M_self_ptr(); > >>>> + _M_node_count = __from._M_node_count; > >>>> + > >>>> + __from._M_reset(); > >>>> + } > >>>> > >>>> - void > >>>> - _M_reset() > >>>> - { > >>>> - _M_header._M_parent = 0; > >>>> - _M_header._M_left = &_M_header; > >>>> - _M_header._M_right = &_M_header; > >>>> - _M_node_count = 0; > >>>> - } > >>>> - }; > >>>> + void > >>>> + _M_reset() > >>>> + { > >>>> + _M_header._M_parent = _Base_ptr(); > >>>> + _M_header._M_left = _M_header._M_right = _M_header._M_self_ptr(); > >>>> + _M_node_count = 0; > >>>> + } > >>>> + }; > >>>> + > >>>> + struct _Rb_tree_header : _Rb_tree_pheader<_Rb_tree_node_base> > >>>> + { }; > >>>> > >>>> template<typename _Val> > >>>> - struct _Rb_tree_node : public _Rb_tree_node_base > >>>> + struct _Rb_tree_node_val > >>>> { > >>>> - typedef _Rb_tree_node<_Val>* _Link_type; > >>>> - > >>>> #if __cplusplus < 201103L > >>>> _Val _M_value_field; > >>>> > >>>> + __attribute__((__always_inline__)) > >>>> _Val* > >>>> _M_valptr() > >>>> { returnstd::__addressof(_M_value_field); } > >>>> > >>>> + __attribute__((__always_inline__)) > >>>> const _Val* > >>>> _M_valptr() const > >>>> { returnstd::__addressof(_M_value_field); } > >>>> #else > >>>> __gnu_cxx::__aligned_membuf<_Val> _M_storage; > >>> For the new __list::_Node type I took the opportunity to replace > >>> __aligned_membuf with a union { _Val _M_data; }; which is simpler and > >>> produces the same code. We could probably make that change for the > >>> existing node types, I think it's safe, but making it only for the new > >>> _Node type means the old node type isn't affected. > >>> > >>> > >>>> + [[__gnu__::__always_inline__]] > >>>> _Val* > >>>> _M_valptr() > >>>> { return _M_storage._M_ptr(); } > >>>> > >>>> + [[__gnu__::__always_inline__]] > >>>> const _Val* > >>>> _M_valptr() const > >>>> { return _M_storage._M_ptr(); } > >>>> #endif > >>>> }; > >>>> > >>>> + template<typename _Val> > >>>> + struct _Rb_tree_node > >>>> + : _Rb_tree_node_base > >>>> + , _Rb_tree_node_val<_Val> > >>>> + { > >>>> + typedef _Rb_tree_node<_Val>* _Node_ptr; > >>>> + }; > >>>> + > >>>> +#if __cplusplus >= 201103L > >>>> + template<typename _ValPtr> > >>>> + struct _Rb_tree_pnode > >>>> + : _Rb_tree_pnode_base<_ValPtr> > >>> This makes _Rb_tree_pnode_base depend on the value_type, which means > >>> you instantiate a different specialization of _Rb_tree_pnode_base for > >>> every _Rb_tree. There's no point even having a common base class if > >>> every specialization is different. You might as well just put the > >>> _M_parent/_M_left/_M_right pointers in _Rb_tree_pnode directly. > >>> > >>> The point of the node_base class is to have a common base that is not > >>> dependent on the value type, so thatstd::set<int> andstd::set<long> > >>> andstd::set<int, Cmp> all use the same node base. The way this patch > >>> works,std::set<int> will use _Rb_tree_pnode_base<int*> and > >>> std::set<long> will use _Rb_tree_pnode_base<long*>. > >>> > >>> This is why my patch for lists uses __ptr_rebind<_ValPtr, void> as the > >>> template argument to _Node_base, so that they all use > >>> _Node_base<void*>. > >>> > >>> Obviously for a fancy pointer, it will be a different specialization, > >>> sostd::list<int, A<int>> uses _Node_base<A::void_pointer>, but > >>> std::list<long, A<long>> uses the same _Node_base<A::void_pointer>. > >>> > >>>> + , > >>>> _Rb_tree_node_val<typenamestd::pointer_traits<_ValPtr>::element_type> > >>>> + { > >>>> + using _Node_ptr = __ptr_rebind<_ValPtr, _Rb_tree_pnode>; > >>>> + }; > >>>> +#endif > >>>> + > >>>> _GLIBCXX_PURE _Rb_tree_node_base* > >>>> _Rb_tree_increment(_Rb_tree_node_base* __x) throw (); > >>>> > >>> [...] > >>> > >>>> +#if __cplusplus >= 201103L > >>>> + template<typename _ValPtr> > >>>> + struct _Rb_tree_piterator > >>>> + { > >>>> + using __ptr_traits = pointer_traits<_ValPtr>; > >>>> + using value_type = typename __ptr_traits::element_type; > >>>> + using reference = value_type&; > >>>> + using pointer = value_type*; > >>>> + > >>>> + typedef bidirectional_iterator_tag iterator_category; > >>>> + typedef ptrdiff_t difference_type; > >>>> + > >>>> + typedef _Rb_tree_piterator _Self; > >>>> + typedef _Rb_tree_pnode_base<_ValPtr> _Node_base; > >>>> + typedef _Rb_tree_pnode<_ValPtr> _Node_type; > >>>> + typedef typename _Node_type::_Base_ptr _Base_ptr; > >>>> + typedef typename _Node_type::_Node_ptr _Node_ptr; > >>>> + typedef _Rb_tree_helpers<_Node_base> _Tree_helpers; > >>>> + > >>>> + _Rb_tree_piterator() _GLIBCXX_NOEXCEPT > >>>> + : _M_node() { } > >>>> + > >>>> + explicit > >>>> + _Rb_tree_piterator(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> + : _M_node(__x) { } > >>>> + > >>>> + reference > >>>> + operator*() const _GLIBCXX_NOEXCEPT > >>>> + { return *static_cast<_Node_type&>(*_M_node)._M_valptr(); } > >>>> + > >>>> + pointer > >>>> + operator->() const _GLIBCXX_NOEXCEPT > >>>> + { return static_cast<_Node_type&>(*_M_node)._M_valptr(); } > >>>> + > >>>> + _Self& > >>>> + operator++() _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _M_node = _Tree_helpers::_Increment(_M_node); > >>>> + return *this; > >>>> + } > >>>> + > >>>> + _Self > >>>> + operator++(int) _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _Self __tmp = *this; > >>>> + _M_node = _Tree_helpers::_Increment(_M_node); > >>>> + return __tmp; > >>>> + } > >>>> + > >>>> + _Self& > >>>> + operator--() _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _M_node = _Tree_helpers::_Decrement(_M_node); > >>>> + return *this; > >>>> + } > >>>> + > >>>> + _Self > >>>> + operator--(int) _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _Self __tmp = *this; > >>>> + _M_node = _Tree_helpers::_Decrement(_M_node); > >>>> + return __tmp; > >>>> + } > >>>> + > >>>> + friend bool > >>>> + operator==(const _Self& __x, const _Self& __y) > >>>> _GLIBCXX_NOEXCEPT > >>>> + { return __x._M_node == __y._M_node; } > >>>> + > >>>> +#if ! __cpp_lib_three_way_comparison > >>>> + friend bool > >>>> + operator!=(const _Self& __x, const _Self& __y) > >>>> _GLIBCXX_NOEXCEPT > >>>> + { return __x._M_node != __y._M_node; } > >>>> +#endif > >>>> + > >>>> + _Base_ptr _M_node; > >>>> + }; > >>>> + > >>>> + template<typename _ValPtr> > >>>> + struct _Rb_tree_const_piterator > >>> For the linked lists, I didn't add two new iterator types, just > >>> _Iterator<_Const, _ValPtr> which is used for iterator and > >>> const_iterator. > >>> > >>> It seemed nice not to duplicate the iterator type, since the iterator > >>> and const_iterator are 95% the same. If we don't need to support > >>> C++98, we can write a single iterator implementation. > >>> > >>> If you have a single iterator implementation, you probably don't need > >>> the _Rb_tree_helpers. > >>> > >>> There would still be uses of insert-and-rebalance and > >>> rebalance-for-erase, but those could just be new overloads for fancy > >>> pointers. I don't think we need the _Rb_tree_helpers class template. > >>> > >>> > >>>> + { > >>>> + using __ptr_traits = pointer_traits<_ValPtr>; > >>>> + using value_type = typename __ptr_traits::element_type; > >>>> + using reference = const value_type&; > >>>> + using pointer = const value_type*; > >>>> + > >>>> + typedef _Rb_tree_piterator<_ValPtr> iterator; > >>>> + typedef typenameiterator::_Base_ptr _Base_ptr; > >>>> + > >>>> + typedef bidirectional_iterator_tag iterator_category; > >>>> + typedef ptrdiff_t difference_type; > >>>> + > >>>> + typedef _Rb_tree_const_piterator _Self; > >>>> + typedef _Rb_tree_pnode_base<_ValPtr> _Node_base; > >>>> + typedef _Rb_tree_pnode<_ValPtr> _Node_type; > >>>> + typedef _Rb_tree_helpers<_Node_base> _Tree_helpers; > >>>> + > >>>> + _Rb_tree_const_piterator() _GLIBCXX_NOEXCEPT > >>>> + : _M_node() { } > >>>> + > >>>> + explicit > >>>> + _Rb_tree_const_piterator(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >>>> + : _M_node(__x) { } > >>>> + > >>>> + _Rb_tree_const_piterator(const iterator& __it) > >>>> _GLIBCXX_NOEXCEPT > >>>> + : _M_node(__it._M_node) { } > >>>> + > >>>> + reference > >>>> + operator*() const _GLIBCXX_NOEXCEPT > >>>> + { return *static_cast<_Node_type&>(*_M_node)._M_valptr(); } > >>>> + > >>>> + pointer > >>>> + operator->() const _GLIBCXX_NOEXCEPT > >>>> + { return static_cast<_Node_type&>(*_M_node)._M_valptr(); } > >>>> + > >>>> + _Self& > >>>> + operator++() _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _M_node = _Tree_helpers::_Increment(_M_node); > >>> You need the iterator increment code here, but you can define it > >>> inline without the _Increment helper. > >>> > >>>> + return *this; > >>>> + } > >>>> + > >>>> + _Self > >>>> + operator++(int) _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _Self __tmp = *this; > >>>> + _M_node = _Tree_helpers::_Increment(_M_node); > >>> This could just use ++*this. So if there's no separate const iterator > >>> implementation, there's no more use of _Increment. > >>> > >>>> + return __tmp; > >>>> + } > >>>> + > >>>> + _Self& > >>>> + operator--() _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _M_node = _Tree_helpers::_Decrement(_M_node); > >>>> + return *this; > >>>> + } > >>>> + > >>>> + _Self > >>>> + operator--(int) _GLIBCXX_NOEXCEPT > >>>> + { > >>>> + _Self __tmp = *this; > >>>> + _M_node = _Tree_helpers::_Decrement(_M_node); > >>>> + return __tmp; > >>>> + } > >>>> + > >>>> + friend bool > >>>> + operator==(const _Self& __x, const _Self& __y) > >>>> _GLIBCXX_NOEXCEPT > >>>> + { return __x._M_node == __y._M_node; } > >>>> + > >>>> +#if ! __cpp_lib_three_way_comparison > >>>> + friend bool > >>>> + operator!=(const _Self& __x, const _Self& __y) > >>>> _GLIBCXX_NOEXCEPT > >>>> + { return __x._M_node != __y._M_node; } > >>>> +#endif > >>>> + > >>>> + _Base_ptr _M_node; > >>>> + }; > >>>> +#endif // C++11 > >>>> + > >>>> +#if __cplusplus >= 201103L > >>>> + template<typename _ValPtr> > >>>> + struct _Rb_tree_node_traits > >>>> + { > >>>> + using _Node_base = _Rb_tree_pnode_base<_ValPtr>; > >>>> + using _Node_type = _Rb_tree_pnode<_ValPtr>; > >>>> + using _Header_t = _Rb_tree_pheader<_Node_base>; > >>>> + using _Iterator_t = _Rb_tree_piterator<_ValPtr>; > >>>> + using _Const_iterator_t = _Rb_tree_const_piterator<_ValPtr>; > >>>> + }; > >>>> +#else > >>>> + template<typename _ValPtr> > >>>> + struct _Rb_tree_node_traits; > >>>> +#endif > >>>> + > >>>> + template<typename _Val> > >>>> + struct _Rb_tree_node_traits<_Val*> > >>>> + { > >>>> + typedef _Rb_tree_node_base _Node_base; > >>>> + typedef _Rb_tree_node<_Val> _Node_type; > >>>> + typedef _Rb_tree_header _Header_t; > >>>> + typedef _Rb_tree_iterator<_Val> _Iterator_t; > >>>> + typedef _Rb_tree_const_iterator<_Val> _Const_iterator_t; > >>>> + }; > >>>> > >>>> #if __cplusplus > 201402L > >>>> template<typename _Tree1, typename _Cmp2> > >>>> @@ -424,16 +1068,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> typename _Compare, typename _Alloc = allocator<_Val> > > >>>> class _Rb_tree > >>>> { > >>>> + typedef typename __gnu_cxx::__alloc_traits<_Alloc>::pointer > >>>> _ValPtr; > >>>> + typedef _Rb_tree_node_traits<_ValPtr> _Node_traits; > >>>> + > >>>> + typedef typename _Node_traits::_Node_base _Node_base; > >>>> + typedef typename _Node_traits::_Node_type _Node_type; > >>>> + > >>>> typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template > >>>> - rebind<_Rb_tree_node<_Val> >::other _Node_allocator; > >>>> + rebind<_Node_type>::other _Node_allocator; > >>>> > >>>> typedef __gnu_cxx::__alloc_traits<_Node_allocator> > >>>> _Alloc_traits; > >>>> > >>>> protected: > >>>> - typedef _Rb_tree_node_base* _Base_ptr; > >>>> - typedef const _Rb_tree_node_base* _Const_Base_ptr; > >>>> - typedef _Rb_tree_node<_Val>* _Link_type; > >>>> - typedef const _Rb_tree_node<_Val>* _Const_Link_type; > >>>> + typedef typename _Node_base::_Base_ptr _Base_ptr; > >>>> + typedef typename _Node_type::_Node_ptr _Node_ptr; > >>> Accessing a member of _Node_type here requires _Node_type to be > >>> complete, which requires _Tp to be complete. That's allowed by the > >>> standard, becausestd::map andstd::set don't support incomplete types > >>> (unlike vector and the linked lists). > >>> > >>> But we don't really ned to instantiate _Node_type here, we could use > >>> _Alloc_traits::pointer instead. > >>> > >>> > >>> [...] > >>> > >>>> @@ -1826,10 +2427,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> || _M_impl._M_key_compare(_KeyOfValue()(__v), > >>>> _S_key(__p))); > >>>> > >>>> - _Link_type __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v)); > >>>> + _Base_ptr __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v)); > >>> I think this relies on implicit conversion from _Node_ptr to > >>> _Base_ptr, which is not necessarily possible. It works for the > >>> _Pointer_adapter type in <ext/pointer.h> because it has a > >>> template<typename U> _Pointer_adapter(_Pointer_adapter<U>) constructor > >>> that supports implicit conversions. > >>> > >>> There seems to be a few other places with this problem. Please take a > >>> look at the Pointer type in the new test for my list and forward_list > >>> fancy ptr patches (that Pointer should probably be added to the > >>> testsuite/util/testsuite_allocator.h header for reuse). > >>> > >>> I solved these problems by adding a _M_base_ptr() function to the > >>> node_base type, which means that instead of relying on an implicit > >>> conversion from node_ptr to _Base_ptr you call node_ptr->_M_base_ptr() > >>> to get a _Base_ptr. > >>> > >>>> @@ -2255,7 +2821,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> } > >>>> else > >>>> // Equivalent keys. > >>>> - return _Res(__pos._M_node, 0); > >>>> + return _Res(__position._M_node, 0); > >>>> } > >>>> > >>>> template<typename _Key, typename _Val, typename _KeyOfValue, > >>>> @@ -2294,11 +2860,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >>>> _M_get_insert_hint_equal_pos(const_iterator __position, const > >>>> key_type& __k) > >>>> { > >>>> - iterator __pos = __position._M_const_cast(); > >>> This removes __pos ... > >>> > >>>> typedef pair<_Base_ptr, _Base_ptr> _Res; > >>>> > >>>> // end() > >>>> - if (__pos._M_node == _M_end()) > >>>> + if (__position._M_node == _M_end()) > >>>> { > >>>> if (size() > 0 > >>>> && !_M_impl._M_key_compare(__k, _S_key(_M_rightmost()))) > >>>> @@ -2306,18 +2871,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> else > >>>> return _M_get_insert_equal_pos(__k); > >>>> } > >>>> - else if (!_M_impl._M_key_compare(_S_key(__pos._M_node), __k)) > >>>> + else if (!_M_impl._M_key_compare(_S_key(__position._M_node), > >>>> __k)) > >>>> { > >>>> // First, try before... > >>>> iterator __before = __pos; > >>> But it's still used here. > >>> > >>>> - if (__pos._M_node == _M_leftmost()) // begin() > >>>> + if (__position._M_node == _M_leftmost()) // begin() > >>>> return _Res(_M_leftmost(), _M_leftmost()); > >>>> else if (!_M_impl._M_key_compare(__k, > >>>> _S_key((--__before)._M_node))) > >>>> { > >>>> if (_S_right(__before._M_node) == 0) > >>>> return _Res(0, __before._M_node); > >>>> else > >>>> - return _Res(__pos._M_node, __pos._M_node); > >>>> + return _Res(__position._M_node, __position._M_node); > >>>> } > >>>> else > >>>> return _M_get_insert_equal_pos(__k); > >>>> @@ -2326,12 +2891,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >>>> { > >>>> // ... then try after. > >>>> iterator __after = __pos; > >>> And here. > >>> > >>> I think they should both be __position._M_const_cast(). > >>> > >>> > >>>> diff --git > >>>> a/libstdc++-v3/testsuite/23_containers/map/allocator/ext_ptr.cc > >>>> b/libstdc++-v3/testsuite/23_containers/map/allocator/ext_ptr.cc > >>>> new file mode 100644 > >>>> index 00000000000..758beedccfd > >>>> --- /dev/null > >>>> +++ b/libstdc++-v3/testsuite/23_containers/map/allocator/ext_ptr.cc > >>>> @@ -0,0 +1,44 @@ > >>>> +// { dg-do run { target c++11 } } > >>>> + > >>>> +#include <map> > >>>> +#include <memory> > >>>> +#include <testsuite_hooks.h> > >>>> +#include <testsuite_allocator.h> > >>>> + > >>>> +struct T { int i; }; > >>>> + > >>>> +bool operator<(const T& l, const T& r) > >>>> +{ return l.i < r.i; } > >>>> + > >>>> +struct H > >>> This struct H occurs in several tests but seems to be unused. > >>> > >>>> +{ > >>>> +std::size_t > >>>> + operator()(const T& t) const noexcept > >>>> + { return t.i; } > >>>> +}; > >>>> + > >>>> +struct L :std::less<T> > >>>> +{ }; > >>>> + > >>>> +using __gnu_test::CustomPointerAlloc; > >>>> + > >>>> +template classstd::map<T, int, L, > >>>> + CustomPointerAlloc<std::pair<const T, int>>>; > >>>> + > >>>> +void test01() > >>>> +{ > >>>> + typedef CustomPointerAlloc<std::pair<const T, int>> alloc_type; > >>>> + typedefstd::map<T, int, L, alloc_type> test_type; > >>>> + test_type v; > >>>> + v.insert({ T(), 0 }); > >>>> + VERIFY( v.begin()->second == 0 ); > >>>> + VERIFY( ++v.begin() == v.end() ); > >>>> + v.insert({ T { 1 }, 1 }); > >>>> + VERIFY( v.size() == 2 ); > >>>> + VERIFY( v.find(T()) != v.end() ); > >>>> +} > >>>> + > >>>> +int main() > >>>> +{ > >>>> + test01(); > >>>> +} > >>> I'd be interested on your opinion on my patches for fancy pointer > >>> support in the linked lists. I think it's cleaner and requires fewer > >>> changes to the existing specializations. > >>> > >>> My changes can also be disabled by a macro (to avoid breaking any > >>> users who are somehow managing to use allocators-with-fancy-pointers > >>> with RB trees today, which could be useful unless that's completely > >>> broken today), and to be enabled for non-fancy pointers (for test > >>> coverage). > >>> > > >diff --git a/libstdc++-v3/include/bits/stl_tree.h > >b/libstdc++-v3/include/bits/stl_tree.h > >index bc27e191e8b..bed7266c688 100644 > >--- a/libstdc++-v3/include/bits/stl_tree.h > >+++ b/libstdc++-v3/include/bits/stl_tree.h > >@@ -66,6 +66,7 @@ > > #include <bits/allocator.h> > > #include <bits/stl_function.h> > > #include <bits/cpp_type_traits.h> > >+#include <bits/ptr_traits.h> > > #include <ext/alloc_traits.h> > > #if __cplusplus >= 201103L > > # include <ext/aligned_buffer.h> > >@@ -74,6 +75,13 @@ > > # include <bits/node_handle.h> > > #endif > > > >+#if __cplusplus < 201103L > >+# undef _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE > >+# define _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE 0 > >+#elif ! defined _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE > >+# define _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE 1 > >+#endif > >+ > > namespace std _GLIBCXX_VISIBILITY(default) > > { > > _GLIBCXX_BEGIN_NAMESPACE_VERSION > >@@ -99,7 +107,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > struct _Rb_tree_node_base > > { > > typedef _Rb_tree_node_base* _Base_ptr; > >- typedef const _Rb_tree_node_base* _Const_Base_ptr; > > > > _Rb_tree_color _M_color; > > _Base_ptr _M_parent; > >@@ -113,13 +120,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > return __x; > > } > > > >- static _Const_Base_ptr > >- _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { > >- while (__x->_M_left != 0) __x = __x->_M_left; > >- return __x; > >- } > >- > > static _Base_ptr > > _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > > { > >@@ -127,12 +127,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > return __x; > > } > > > >- static _Const_Base_ptr > >- _S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { > >- while (__x->_M_right != 0) __x = __x->_M_right; > >- return __x; > >- } > >+ // This is not const-correct, but it's only used in a const access path > >+ // by std::_Rb_tree::_M_end() where the pointer is used to initialize a > >+ // const_iterator and so constness is restored. > >+ _Base_ptr > >+ _M_base_ptr() const _GLIBCXX_NOEXCEPT > >+ { return const_cast<_Rb_tree_node_base*>(this); } > >+ > >+ template<typename _NodePtr> > >+ _NodePtr > >+ _M_node_ptr() _GLIBCXX_NOEXCEPT > >+ { return static_cast<_NodePtr>(this); } > > }; > > > > // Helper type offering value initialization guarantee on the compare > > functor. > >@@ -213,7 +218,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > template<typename _Val> > > struct _Rb_tree_node : public _Rb_tree_node_base > > { > >- typedef _Rb_tree_node<_Val>* _Link_type; > >+ typedef _Rb_tree_node<_Val>* _Node_ptr; > > > > #if __cplusplus < 201103L > > _Val _M_value_field; > >@@ -238,18 +243,136 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > #endif > > }; > > > >+#if _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE > >+namespace __rb_tree > >+{ > >+ template<typename _VoidPtr> > >+ struct _Node_base > >+ { > >+ using _Base_ptr = __ptr_rebind<_VoidPtr, _Node_base>; > >+ > >+ _Rb_tree_color _M_color; > >+ _Base_ptr _M_parent; > >+ _Base_ptr _M_left; > >+ _Base_ptr _M_right; > >+ > >+ static _Base_ptr > >+ _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >+ { > >+ while (__x->_M_left) __x = __x->_M_left; > >+ return __x; > >+ } > >+ > >+ static _Base_ptr > >+ _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >+ { > >+ while (__x->_M_right) __x = __x->_M_right; > >+ return __x; > >+ } > >+ > >+ // This is not const-correct, but it's only used in a const access > >path > >+ // by std::_Rb_tree::_M_end() where the pointer is used to initialize > >a > >+ // const_iterator and so constness is restored. > >+ _Base_ptr > >+ _M_base_ptr() const > >+ { > >+ return pointer_traits<_Base_ptr>::pointer_to > >+ (*const_cast<_Node_base*>(this)); > >+ } > >+ > >+ template<typename _NodePtr> > >+ _NodePtr > >+ _M_node_ptr() _GLIBCXX_NOEXCEPT > >+ { > >+ using __ptr_traits = pointer_traits<_NodePtr>; > >+ using __node_type = typename __ptr_traits::element_type; > >+ auto __this = static_cast<__node_type*>(this); > >+ return __ptr_traits::pointer_to(*__this); > >+ } > >+ }; > >+ > >+ // Helper type to manage default initialization of node count and header. > >+ template<typename _NodeBase> > >+ struct _Header > >+ { > >+ private: > >+ using _Base_ptr = typename _NodeBase::_Base_ptr; > >+ > >+ public: > >+ _NodeBase _M_header; > >+ size_t _M_node_count; // Keeps track of size of tree. > >+ > >+ _Header() noexcept > >+ { > >+ _M_header._M_color = _S_red; > >+ _M_reset(); > >+ } > >+ > >+ _Header(_Header&& __x) noexcept > >+ { > >+ if (__x._M_header._M_parent) > >+ _M_move_data(__x); > >+ else > >+ { > >+ _M_header._M_color = _S_red; > >+ _M_reset(); > >+ } > >+ } > >+ > >+ void > >+ _M_move_data(_Header& __from) > >+ { > >+ _M_header._M_color = __from._M_header._M_color; > >+ _M_header._M_parent = __from._M_header._M_parent; > >+ _M_header._M_left = __from._M_header._M_left; > >+ _M_header._M_right = __from._M_header._M_right; > >+ _M_header._M_parent->_M_parent = _M_header._M_base_ptr(); > >+ _M_node_count = __from._M_node_count; > >+ > >+ __from._M_reset(); > >+ } > >+ > >+ void > >+ _M_reset() > >+ { > >+ _M_header._M_parent = _Base_ptr{}; > >+ _M_header._M_left = _M_header._M_right = _M_header._M_base_ptr(); > >+ _M_node_count = 0; > >+ } > >+ }; > >+ > >+ template<typename _ValPtr> > >+ struct _Node : public __rb_tree::_Node_base<__ptr_rebind<_ValPtr, void>> > >+ { > >+ using value_type = typename pointer_traits<_ValPtr>::element_type; > >+ using _Node_ptr = __ptr_rebind<_ValPtr, _Node>; > >+ > >+ union > >+ { > >+ value_type _M_storage; > >+ }; > >+ > >+ _Node() { } > >+ ~_Node() { } > >+ _Node(_Node&&) = delete; > >+ > >+ value_type* > >+ _M_valptr() > >+ { return std::__addressof(_M_storage); } > >+ > >+ value_type const* > >+ _M_valptr() const > >+ { return std::__addressof(_M_storage); } > >+ }; > >+} // namespace __rb_tree > >+#endif > >+ > > _GLIBCXX_PURE _Rb_tree_node_base* > > _Rb_tree_increment(_Rb_tree_node_base* __x) throw (); > > > >- _GLIBCXX_PURE const _Rb_tree_node_base* > >- _Rb_tree_increment(const _Rb_tree_node_base* __x) throw (); > >- > > _GLIBCXX_PURE _Rb_tree_node_base* > > _Rb_tree_decrement(_Rb_tree_node_base* __x) throw (); > > > >- _GLIBCXX_PURE const _Rb_tree_node_base* > >- _Rb_tree_decrement(const _Rb_tree_node_base* __x) throw (); > >- > > template<typename _Tp> > > struct _Rb_tree_iterator > > { > >@@ -260,9 +383,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typedef bidirectional_iterator_tag iterator_category; > > typedef ptrdiff_t difference_type; > > > >- typedef _Rb_tree_iterator<_Tp> _Self; > > typedef _Rb_tree_node_base::_Base_ptr _Base_ptr; > >- typedef _Rb_tree_node<_Tp>* _Link_type; > >+ typedef _Rb_tree_node<_Tp>* _Node_ptr; > > > > _Rb_tree_iterator() _GLIBCXX_NOEXCEPT > > : _M_node() { } > >@@ -273,49 +395,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > reference > > operator*() const _GLIBCXX_NOEXCEPT > >- { return *static_cast<_Link_type>(_M_node)->_M_valptr(); } > >+ { return *static_cast<_Node_ptr>(_M_node)->_M_valptr(); } > > > > pointer > > operator->() const _GLIBCXX_NOEXCEPT > >- { return static_cast<_Link_type> (_M_node)->_M_valptr(); } > >+ { return static_cast<_Node_ptr>(_M_node)->_M_valptr(); } > > > >- _Self& > >+ _Rb_tree_iterator& > > operator++() _GLIBCXX_NOEXCEPT > > { > > _M_node = _Rb_tree_increment(_M_node); > > return *this; > > } > > > >- _Self > >+ _Rb_tree_iterator > > operator++(int) _GLIBCXX_NOEXCEPT > > { > >- _Self __tmp = *this; > >+ _Rb_tree_iterator __tmp = *this; > > _M_node = _Rb_tree_increment(_M_node); > > return __tmp; > > } > > > >- _Self& > >+ _Rb_tree_iterator& > > operator--() _GLIBCXX_NOEXCEPT > > { > > _M_node = _Rb_tree_decrement(_M_node); > > return *this; > > } > > > >- _Self > >+ _Rb_tree_iterator > > operator--(int) _GLIBCXX_NOEXCEPT > > { > >- _Self __tmp = *this; > >+ _Rb_tree_iterator __tmp = *this; > > _M_node = _Rb_tree_decrement(_M_node); > > return __tmp; > > } > > > > friend bool > >- operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT > >+ operator==(const _Rb_tree_iterator& __x, > >+ const _Rb_tree_iterator& __y) _GLIBCXX_NOEXCEPT > > { return __x._M_node == __y._M_node; } > > > > #if ! __cpp_lib_three_way_comparison > > friend bool > >- operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT > >+ operator!=(const _Rb_tree_iterator& __x, > >+ const _Rb_tree_iterator& __y) _GLIBCXX_NOEXCEPT > > { return __x._M_node != __y._M_node; } > > #endif > > > >@@ -334,9 +458,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typedef bidirectional_iterator_tag iterator_category; > > typedef ptrdiff_t difference_type; > > > >- typedef _Rb_tree_const_iterator<_Tp> _Self; > >- typedef _Rb_tree_node_base::_Const_Base_ptr _Base_ptr; > >- typedef const _Rb_tree_node<_Tp>* _Link_type; > >+ typedef _Rb_tree_node_base::_Base_ptr _Base_ptr; > >+ typedef const _Rb_tree_node<_Tp>* _Node_ptr; > > > > _Rb_tree_const_iterator() _GLIBCXX_NOEXCEPT > > : _M_node() { } > >@@ -348,55 +471,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree_const_iterator(const iterator& __it) _GLIBCXX_NOEXCEPT > > : _M_node(__it._M_node) { } > > > >- iterator > >- _M_const_cast() const _GLIBCXX_NOEXCEPT > >- { return iterator(const_cast<typename iterator::_Base_ptr>(_M_node)); > >} > >- > > reference > > operator*() const _GLIBCXX_NOEXCEPT > >- { return *static_cast<_Link_type>(_M_node)->_M_valptr(); } > >+ { return *static_cast<_Node_ptr>(_M_node)->_M_valptr(); } > > > > pointer > > operator->() const _GLIBCXX_NOEXCEPT > >- { return static_cast<_Link_type>(_M_node)->_M_valptr(); } > >+ { return static_cast<_Node_ptr>(_M_node)->_M_valptr(); } > > > >- _Self& > >+ _Rb_tree_const_iterator& > > operator++() _GLIBCXX_NOEXCEPT > > { > > _M_node = _Rb_tree_increment(_M_node); > > return *this; > > } > > > >- _Self > >+ _Rb_tree_const_iterator > > operator++(int) _GLIBCXX_NOEXCEPT > > { > >- _Self __tmp = *this; > >+ _Rb_tree_const_iterator __tmp = *this; > > _M_node = _Rb_tree_increment(_M_node); > > return __tmp; > > } > > > >- _Self& > >+ _Rb_tree_const_iterator& > > operator--() _GLIBCXX_NOEXCEPT > > { > > _M_node = _Rb_tree_decrement(_M_node); > > return *this; > > } > > > >- _Self > >+ _Rb_tree_const_iterator > > operator--(int) _GLIBCXX_NOEXCEPT > > { > >- _Self __tmp = *this; > >+ _Rb_tree_const_iterator __tmp = *this; > > _M_node = _Rb_tree_decrement(_M_node); > > return __tmp; > > } > > > > friend bool > >- operator==(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT > >+ operator==(const _Rb_tree_const_iterator& __x, > >+ const _Rb_tree_const_iterator& __y) _GLIBCXX_NOEXCEPT > > { return __x._M_node == __y._M_node; } > > > > #if ! __cpp_lib_three_way_comparison > > friend bool > >- operator!=(const _Self& __x, const _Self& __y) _GLIBCXX_NOEXCEPT > >+ operator!=(const _Rb_tree_const_iterator& __x, > >+ const _Rb_tree_const_iterator& __y) _GLIBCXX_NOEXCEPT > > { return __x._M_node != __y._M_node; } > > #endif > > > >@@ -415,6 +536,485 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree_rebalance_for_erase(_Rb_tree_node_base* const __z, > > _Rb_tree_node_base& __header) throw (); > > > >+namespace __rb_tree > >+{ > >+#if _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE > >+ template<bool _Const, typename _ValPtr> > >+ struct _Iterator > >+ { > >+ template<typename _Tp> > >+ using __maybe_const = __conditional_t<_Const, const _Tp, _Tp>; > >+ > >+ using __ptr_traits = pointer_traits<_ValPtr>; > >+ using value_type = typename __ptr_traits::element_type; > >+ using reference = __maybe_const<value_type>&; > >+ using pointer = __maybe_const<value_type>*; > >+ > >+ using iterator_category = bidirectional_iterator_tag; > >+ using difference_type = ptrdiff_t; > >+ > >+ using _Node = __rb_tree::_Node<_ValPtr>; > >+ using _Node_base = __rb_tree::_Node_base<__ptr_rebind<_ValPtr, void>>; > >+ using _Base_ptr = typename _Node_base::_Base_ptr; > >+ > >+ _Iterator() _GLIBCXX_NOEXCEPT > >+ : _M_node() { } > >+ > >+ constexpr explicit > >+ _Iterator(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >+ : _M_node(__x) { } > >+ > >+#if __cplusplus >= 201103L > >+ _Iterator(const _Iterator&) = default; > >+ _Iterator& operator=(const _Iterator&) = default; > >+#endif > >+ > >+#ifdef __glibcxx_concepts > >+ constexpr > >+ _Iterator(const _Iterator<false, _ValPtr>& __it) requires _Const > >+#else > >+ template<bool _OtherConst, > >+ typename = __enable_if_t<_Const && !_OtherConst>> > >+ constexpr > >+ _Iterator(const _Iterator<_OtherConst, _ValPtr>& __it) > >+#endif > >+ : _M_node(__it._M_node) { } > >+ > >+ [[__nodiscard__]] > >+ reference > >+ operator*() const _GLIBCXX_NOEXCEPT > >+ { return *static_cast<_Node&>(*_M_node)._M_valptr(); } > >+ > >+ [[__nodiscard__]] > >+ pointer > >+ operator->() const _GLIBCXX_NOEXCEPT > >+ { return static_cast<_Node&>(*_M_node)._M_valptr(); } > >+ > >+ _GLIBCXX14_CONSTEXPR _Iterator& > >+ operator++() _GLIBCXX_NOEXCEPT > >+ { > >+ if (_M_node->_M_right) > >+ { > >+ _M_node = _M_node->_M_right; > >+ while (_M_node->_M_left) > >+ _M_node = _M_node->_M_left; > >+ } > >+ else > >+ { > >+ _Base_ptr __y = _M_node->_M_parent; > >+ while (_M_node == __y->_M_right) > >+ { > >+ _M_node = __y; > >+ __y = __y->_M_parent; > >+ } > >+ if (_M_node->_M_right != __y) > >+ _M_node = __y; > >+ } > >+ > >+ return *this; > >+ } > >+ > >+ _GLIBCXX14_CONSTEXPR _Iterator > >+ operator++(int) _GLIBCXX_NOEXCEPT > >+ { > >+ _Iterator __tmp(this->_M_node); > >+ ++*this; > >+ return __tmp; > >+ } > >+ > >+ _GLIBCXX14_CONSTEXPR _Iterator& > >+ operator--() _GLIBCXX_NOEXCEPT > >+ { > >+ if (_M_node->_M_color == _S_red > >+ && _M_node->_M_parent->_M_parent == _M_node) > >+ _M_node = _M_node->_M_right; > >+ else if (_M_node->_M_left) > >+ { > >+ _Base_ptr __y = _M_node->_M_left; > >+ while (__y->_M_right) > >+ __y = __y->_M_right; > >+ _M_node = __y; > >+ } > >+ else > >+ { > >+ _Base_ptr __y = _M_node->_M_parent; > >+ while (_M_node == __y->_M_left) > >+ { > >+ _M_node = __y; > >+ __y = __y->_M_parent; > >+ } > >+ _M_node = __y; > >+ } > >+ return *this; > >+ } > >+ > >+ _GLIBCXX14_CONSTEXPR _Iterator > >+ operator--(int) _GLIBCXX_NOEXCEPT > >+ { > >+ _Iterator __tmp(this->_M_node); > >+ --*this; > >+ return __tmp; > >+ } > >+ > >+ [[__nodiscard__]] > >+ friend bool > >+ operator==(const _Iterator& __x, const _Iterator& __y) > >_GLIBCXX_NOEXCEPT > >+ { return __x._M_node == __y._M_node; } > >+ > >+#if ! __cpp_lib_three_way_comparison > >+ [[__nodiscard__]] > >+ friend bool > >+ operator!=(const _Iterator& __x, const _Iterator& __y) > >_GLIBCXX_NOEXCEPT > >+ { return __x._M_node != __y._M_node; } > >+#endif > >+ > >+ _Base_ptr _M_node; > >+ }; > >+#endif // USE_ALLOC_PTR_FOR_RB_TREE > >+ > >+ // Determine the node and iterator types used by std::_Rb_tree. > >+ template<typename _Val, typename _Ptr> > >+ struct _Node_traits; > >+ > >+#if _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE <= 9000 > >+ // Specialization for the simple case where the allocator's pointer type > >+ // is the same type as value_type*. > >+ // For ABI compatibility we can't change the types used for this case. > >+ template<typename _Val> > >+ struct _Node_traits<_Val, _Val*> > >+ { > >+ typedef _Rb_tree_node<_Val> _Node; > >+ typedef _Rb_tree_node_base _Node_base; > >+ typedef _Rb_tree_header _Header_t; > >+ typedef _Rb_tree_iterator<_Val> _Iterator; > >+ typedef _Rb_tree_const_iterator<_Val> _Const_iterator; > >+ > >+ __attribute__((__nonnull__)) > >+ static void > >+ _S_insert_and_rebalance(const bool __insert_left, > >+ _Node_base* __x, _Node_base* __p, > >+ _Node_base& __header) _GLIBCXX_USE_NOEXCEPT > >+ { > >+ return _Rb_tree_insert_and_rebalance(__insert_left, __x, __p, > >__header); > >+ } > >+ > >+ __attribute__((__nonnull__,__returns_nonnull__)) > >+ static _Node_base* > >+ _S_rebalance_for_erase(_Node_base* const __z, > >+ _Node_base& __header) _GLIBCXX_USE_NOEXCEPT > >+ { return _Rb_tree_rebalance_for_erase(__z, __header); } > >+ }; > >+#endif > >+ > >+#if ! _GLIBCXX_USE_ALLOC_PTR_FOR_RB_TREE > >+ // Always use the T* specialization. > >+ template<typename _Val, typename _Ptr> > >+ struct _Node_traits > >+ : _Node_traits<_Val, _Val*> > >+ { }; > >+#else > >+ // Primary template used when the allocator uses fancy pointers. > >+ template<typename _Val, typename _ValPtr> > >+ struct _Node_traits > >+ { > >+ using _Node = __rb_tree::_Node<_ValPtr>; > >+ using _Node_base = __rb_tree::_Node_base<__ptr_rebind<_ValPtr, void>>; > >+ using _Header_t = __rb_tree::_Header<_Node_base>; > >+ using _Iterator = __rb_tree::_Iterator<false, _ValPtr>; > >+ using _Const_iterator = __rb_tree::_Iterator<true, _ValPtr>; > >+ > >+ using _Base_ptr = typename _Node_base::_Base_ptr; > >+ > >+ static void > >+ _Rotate_left(_Base_ptr __x, _Base_ptr& __root) > >+ { > >+ const _Base_ptr __y = __x->_M_right; > >+ > >+ __x->_M_right = __y->_M_left; > >+ if (__y->_M_left) > >+ __y->_M_left->_M_parent = __x; > >+ __y->_M_parent = __x->_M_parent; > >+ > >+ if (__x == __root) > >+ __root = __y; > >+ else if (__x == __x->_M_parent->_M_left) > >+ __x->_M_parent->_M_left = __y; > >+ else > >+ __x->_M_parent->_M_right = __y; > >+ __y->_M_left = __x; > >+ __x->_M_parent = __y; > >+ } > >+ > >+ static void > >+ _Rotate_right(_Base_ptr __x, _Base_ptr& __root) > >+ { > >+ const _Base_ptr __y = __x->_M_left; > >+ > >+ __x->_M_left = __y->_M_right; > >+ if (__y->_M_right) > >+ __y->_M_right->_M_parent = __x; > >+ __y->_M_parent = __x->_M_parent; > >+ > >+ if (__x == __root) > >+ __root = __y; > >+ else if (__x == __x->_M_parent->_M_right) > >+ __x->_M_parent->_M_right = __y; > >+ else > >+ __x->_M_parent->_M_left = __y; > >+ __y->_M_right = __x; > >+ __x->_M_parent = __y; > >+ } > >+ > >+ static void > >+ _S_insert_and_rebalance(const bool __insert_left, > >+ _Base_ptr __x, _Base_ptr __p, > >+ _Node_base& __header) > >+ { > >+ _Base_ptr& __root = __header._M_parent; > >+ > >+ // Initialize fields in new node to insert. > >+ __x->_M_parent = __p; > >+ __x->_M_left = __x->_M_right = nullptr; > >+ __x->_M_color = _S_red; > >+ > >+ // Insert. > >+ // Make new node child of parent and maintain root, leftmost and > >+ // rightmost nodes. > >+ // N.B. First node is always inserted left. > >+ if (__insert_left) > >+ { > >+ __p->_M_left = __x; // also makes leftmost = __x when __p == > >&__header > >+ > >+ if (std::__to_address(__p) == std::addressof(__header)) > >+ { > >+ __header._M_parent = __x; > >+ __header._M_right = __x; > >+ } > >+ else if (__p == __header._M_left) > >+ __header._M_left = __x; // maintain leftmost pointing to min > >node > >+ } > >+ else > >+ { > >+ __p->_M_right = __x; > >+ > >+ if (__p == __header._M_right) > >+ __header._M_right = __x; // maintain rightmost pointing to max > >node > >+ } > >+ // Rebalance. > >+ while (__x != __root > >+ && __x->_M_parent->_M_color == _S_red) > >+ { > >+ const _Base_ptr __xpp = __x->_M_parent->_M_parent; > >+ > >+ if (__x->_M_parent == __xpp->_M_left) > >+ { > >+ const _Base_ptr __y = __xpp->_M_right; > >+ if (__y && __y->_M_color == _S_red) > >+ { > >+ __x->_M_parent->_M_color = _S_black; > >+ __y->_M_color = _S_black; > >+ __xpp->_M_color = _S_red; > >+ __x = __xpp; > >+ } > >+ else > >+ { > >+ if (__x == __x->_M_parent->_M_right) > >+ { > >+ __x = __x->_M_parent; > >+ _Rotate_left(__x, __root); > >+ } > >+ __x->_M_parent->_M_color = _S_black; > >+ __xpp->_M_color = _S_red; > >+ _Rotate_right(__xpp, __root); > >+ } > >+ } > >+ else > >+ { > >+ const _Base_ptr __y = __xpp->_M_left; > >+ if (__y && __y->_M_color == _S_red) > >+ { > >+ __x->_M_parent->_M_color = _S_black; > >+ __y->_M_color = _S_black; > >+ __xpp->_M_color = _S_red; > >+ __x = __xpp; > >+ } > >+ else > >+ { > >+ if (__x == __x->_M_parent->_M_left) > >+ { > >+ __x = __x->_M_parent; > >+ _Rotate_right(__x, __root); > >+ } > >+ __x->_M_parent->_M_color = _S_black; > >+ __xpp->_M_color = _S_red; > >+ _Rotate_left(__xpp, __root); > >+ } > >+ } > >+ } > >+ __root->_M_color = _S_black; > >+ } > >+ > >+ static _Base_ptr > >+ _S_rebalance_for_erase(_Base_ptr __z, _Node_base& __header) > >+ { > >+ _Base_ptr& __root = __header._M_parent; > >+ _Base_ptr& __leftmost = __header._M_left; > >+ _Base_ptr& __rightmost = __header._M_right; > >+ _Base_ptr __y = __z; > >+ _Base_ptr __x{}; > >+ _Base_ptr __x_parent{}; > >+ > >+ if (!__y->_M_left) // __z has at most one non-null child. y == z. > >+ __x = __y->_M_right; // __x might be null. > >+ else > >+ if (!__y->_M_right) // __z has exactly one non-null child. y == z. > >+ __x = __y->_M_left; // __x is not null. > >+ else > >+ { > >+ // __z has two non-null children. Set __y to > >+ __y = __y->_M_right; // __z's successor. __x might be null. > >+ while (__y->_M_left) > >+ __y = __y->_M_left; > >+ __x = __y->_M_right; > >+ } > >+ if (__y != __z) > >+ { > >+ // relink y in place of z. y is z's successor > >+ __z->_M_left->_M_parent = __y; > >+ __y->_M_left = __z->_M_left; > >+ if (__y != __z->_M_right) > >+ { > >+ __x_parent = __y->_M_parent; > >+ if (__x) > >+ __x->_M_parent = __y->_M_parent; > >+ __y->_M_parent->_M_left = __x; // __y must be a child of > >_M_left > >+ __y->_M_right = __z->_M_right; > >+ __z->_M_right->_M_parent = __y; > >+ } > >+ else > >+ __x_parent = __y; > >+ if (__root == __z) > >+ __root = __y; > >+ else if (__z->_M_parent->_M_left == __z) > >+ __z->_M_parent->_M_left = __y; > >+ else > >+ __z->_M_parent->_M_right = __y; > >+ __y->_M_parent = __z->_M_parent; > >+ std::swap(__y->_M_color, __z->_M_color); > >+ __y = __z; > >+ // __y now points to node to be actually deleted > >+ } > >+ else > >+ { // __y == __z > >+ __x_parent = __y->_M_parent; > >+ if (__x) > >+ __x->_M_parent = __y->_M_parent; > >+ if (__root == __z) > >+ __root = __x; > >+ else > >+ if (__z->_M_parent->_M_left == __z) > >+ __z->_M_parent->_M_left = __x; > >+ else > >+ __z->_M_parent->_M_right = __x; > >+ if (__leftmost == __z) > >+ { > >+ if (!__z->_M_right) // __z->_M_left must be null also > >+ __leftmost = __z->_M_parent; > >+ // makes __leftmost == _M_header if __z == __root > >+ else > >+ __leftmost = _Node_base::_S_minimum(__x); > >+ } > >+ if (__rightmost == __z) > >+ { > >+ if (__z->_M_left == 0) // __z->_M_right must be null > >also > >+ __rightmost = __z->_M_parent; > >+ // makes __rightmost == _M_header if __z == __root > >+ else // __x == __z->_M_left > >+ __rightmost = _Node_base::_S_maximum(__x); > >+ } > >+ } > >+ if (__y->_M_color != _S_red) > >+ { > >+ while (__x != __root && (__x == 0 || __x->_M_color == _S_black)) > >+ if (__x == __x_parent->_M_left) > >+ { > >+ _Base_ptr __w = __x_parent->_M_right; > >+ if (__w->_M_color == _S_red) > >+ { > >+ __w->_M_color = _S_black; > >+ __x_parent->_M_color = _S_red; > >+ _Rotate_left(__x_parent, __root); > >+ __w = __x_parent->_M_right; > >+ } > >+ if ((!__w->_M_left || __w->_M_left->_M_color == _S_black) && > >+ (!__w->_M_right || __w->_M_right->_M_color == _S_black)) > >+ { > >+ __w->_M_color = _S_red; > >+ __x = __x_parent; > >+ __x_parent = __x_parent->_M_parent; > >+ } > >+ else > >+ { > >+ if (!__w->_M_right || __w->_M_right->_M_color == > >_S_black) > >+ { > >+ __w->_M_left->_M_color = _S_black; > >+ __w->_M_color = _S_red; > >+ _Rotate_right(__w, __root); > >+ __w = __x_parent->_M_right; > >+ } > >+ __w->_M_color = __x_parent->_M_color; > >+ __x_parent->_M_color = _S_black; > >+ if (__w->_M_right) > >+ __w->_M_right->_M_color = _S_black; > >+ _Rotate_left(__x_parent, __root); > >+ break; > >+ } > >+ } > >+ else > >+ { > >+ // same as above, with _M_right <-> _M_left. > >+ _Base_ptr __w = __x_parent->_M_left; > >+ if (__w->_M_color == _S_red) > >+ { > >+ __w->_M_color = _S_black; > >+ __x_parent->_M_color = _S_red; > >+ _Rotate_right(__x_parent, __root); > >+ __w = __x_parent->_M_left; > >+ } > >+ if ((!__w->_M_right || __w->_M_right->_M_color == _S_black) > >&& > >+ (!__w->_M_left || __w->_M_left->_M_color == _S_black)) > >+ { > >+ __w->_M_color = _S_red; > >+ __x = __x_parent; > >+ __x_parent = __x_parent->_M_parent; > >+ } > >+ else > >+ { > >+ if (!__w->_M_left || __w->_M_left->_M_color == _S_black) > >+ { > >+ __w->_M_right->_M_color = _S_black; > >+ __w->_M_color = _S_red; > >+ _Rotate_left(__w, __root); > >+ __w = __x_parent->_M_left; > >+ } > >+ __w->_M_color = __x_parent->_M_color; > >+ __x_parent->_M_color = _S_black; > >+ if (__w->_M_left) > >+ __w->_M_left->_M_color = _S_black; > >+ _Rotate_right(__x_parent, __root); > >+ break; > >+ } > >+ } > >+ if (__x) > >+ __x->_M_color = _S_black; > >+ } > >+ > >+ return __y; > >+ } > >+ }; > >+#endif > >+} // namespace __rb_tree > >+ > > #if __cplusplus > 201402L > > template<typename _Tree1, typename _Cmp2> > > struct _Rb_tree_merge_helper { }; > >@@ -425,15 +1025,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > class _Rb_tree > > { > > typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template > >- rebind<_Rb_tree_node<_Val> >::other _Node_allocator; > >+ rebind<_Val>::other _Val_alloc_type; > >+ > >+ typedef __gnu_cxx::__alloc_traits<_Val_alloc_type> _Val_alloc_traits; > >+ typedef typename _Val_alloc_traits::pointer _ValPtr; > >+ typedef __rb_tree::_Node_traits<_Val, _ValPtr> _Node_traits; > >+ > >+ typedef typename _Node_traits::_Node_base _Node_base; > >+ typedef typename _Node_traits::_Node _Node; > >+ > >+ typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template > >+ rebind<_Node>::other _Node_allocator; > > > >- typedef __gnu_cxx::__alloc_traits<_Node_allocator> _Alloc_traits; > >+ typedef __gnu_cxx::__alloc_traits<_Node_allocator> _Node_alloc_traits; > > > > protected: > >- typedef _Rb_tree_node_base* _Base_ptr; > >- typedef const _Rb_tree_node_base* _Const_Base_ptr; > >- typedef _Rb_tree_node<_Val>* _Link_type; > >- typedef const _Rb_tree_node<_Val>* _Const_Link_type; > >+ typedef typename _Node_base::_Base_ptr _Base_ptr; > >+ typedef typename _Node_alloc_traits::pointer _Node_ptr; > > > > private: > > // Functor recycling a pool of nodes and using allocation once the > > pool > >@@ -445,13 +1053,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > { > > if (_M_root) > > { > >- _M_root->_M_parent = 0; > >+ _M_root->_M_parent = _Base_ptr(); > > > > if (_M_nodes->_M_left) > > _M_nodes = _M_nodes->_M_left; > > } > > else > >- _M_nodes = 0; > >+ _M_nodes = _Base_ptr(); > > } > > > > #if __cplusplus >= 201103L > >@@ -459,13 +1067,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > #endif > > > > ~_Reuse_or_alloc_node() > >- { _M_t._M_erase(static_cast<_Link_type>(_M_root)); } > >+ { _M_t._M_erase(_M_root); } > > > > template<typename _Arg> > >- _Link_type > >+ _Base_ptr > > Changing this from a node pointer to a base pointer seems to weaken > the API. We know it returns a pointer to a node, so can it return the > correct type? > > > operator()(_GLIBCXX_FWDREF(_Arg) __arg) > > { > >- _Link_type __node = static_cast<_Link_type>(_M_extract()); > >+ _Base_ptr __node = _M_extract(); > > if (__node) > > { > > _M_t._M_destroy_node(__node); > >@@ -489,7 +1097,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > { > > if (_M_nodes->_M_right == __node) > > { > >- _M_nodes->_M_right = 0; > >+ _M_nodes->_M_right = _Base_ptr(); > > > > if (_M_nodes->_M_left) > > { > >@@ -503,10 +1111,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > } > > else // __node is on the left. > >- _M_nodes->_M_left = 0; > >+ _M_nodes->_M_left = _Base_ptr(); > > } > > else > >- _M_root = 0; > >+ _M_root = _Base_ptr(); > > > > return __node; > > } > >@@ -524,9 +1132,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > : _M_t(__t) { } > > > > template<typename _Arg> > >- _Link_type > >+ _Base_ptr > > Same comment here. > > > operator()(_GLIBCXX_FWDREF(_Arg) __arg) const > >- { return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg)); } > >+ { > >+ return _M_t._M_create_node(_GLIBCXX_FORWARD(_Arg, __arg)); > >+ } > > > > private: > > _Rb_tree& _M_t; > >@@ -556,18 +1166,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > { return allocator_type(_M_get_Node_allocator()); } > > > > protected: > >- _Link_type > >+ _Node_ptr > > _M_get_node() > >- { return _Alloc_traits::allocate(_M_get_Node_allocator(), 1); } > >+ { return _Node_alloc_traits::allocate(_M_get_Node_allocator(), 1); } > > > > void > >- _M_put_node(_Link_type __p) _GLIBCXX_NOEXCEPT > >- { _Alloc_traits::deallocate(_M_get_Node_allocator(), __p, 1); } > >+ _M_put_node(_Base_ptr __p) _GLIBCXX_NOEXCEPT > >+ { > >+ _Node_alloc_traits::deallocate > >+ (_M_get_Node_allocator(), __p->template _M_node_ptr<_Node_ptr>(), > >1); > >+ } > > > > #if __cplusplus < 201103L > > void > >- _M_construct_node(_Link_type __node, const value_type& __x) > >+ _M_construct_node(_Base_ptr __p, const value_type& __x) > > And can this be left as _Node_ptr instead of changed to _Base_ptr? > Then it wouldn't need the static_cast, and the callers wouldn't need > to use _M_base_ptr(). > > Logically, it has to be a _Node_ptr or the cast isn't valid anyway. > > There seem to be several places like this where we're giving up > valuable type information by using _base_ptr instead of _Node_ptr. > > Is that really necessary? If we have a _Node_ptr we can always get a > _Base_ptr easily by calling _M_base_ptr(). > > Is it a constness thing, because _M_begin() const was changed to > return _Base_ptr instead of _Const_link_ptr? > > > > { > >+ _Node_ptr __node = static_cast<_Node_ptr>(__p); > > __try > > { get_allocator().construct(__node->_M_valptr(), __x); } > > __catch(...) > >@@ -577,79 +1191,83 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > } > > > >- _Link_type > >+ _Base_ptr > > _M_create_node(const value_type& __x) > > { > >- _Link_type __tmp = _M_get_node(); > >+ _Base_ptr __tmp = _M_get_node()->_M_base_ptr(); > > _M_construct_node(__tmp, __x); > > return __tmp; > > } > > #else > > template<typename... _Args> > > void > >- _M_construct_node(_Link_type __node, _Args&&... __args) > >+ _M_construct_node(_Base_ptr __p, _Args&&... __args) > > { > >+ _Node& __node = static_cast<_Node&>(*__p); > > __try > > { > >- ::new(__node) _Rb_tree_node<_Val>; > >- _Alloc_traits::construct(_M_get_Node_allocator(), > >- __node->_M_valptr(), > >- std::forward<_Args>(__args)...); > >+ ::new(std::__addressof(__node)) _Node; > >+ _Node_alloc_traits::construct(_M_get_Node_allocator(), > >+ __node._M_valptr(), > >+ std::forward<_Args>(__args)...); > > } > > __catch(...) > > { > >- __node->~_Rb_tree_node<_Val>(); > >- _M_put_node(__node); > >+ __node.~_Node(); > >+ _M_put_node(__p); > > __throw_exception_again; > > } > > } > > > > template<typename... _Args> > >- _Link_type > >+ _Base_ptr > > _M_create_node(_Args&&... __args) > > { > >- _Link_type __tmp = _M_get_node(); > >+ _Base_ptr __tmp = _M_get_node()->_M_base_ptr(); > > _M_construct_node(__tmp, std::forward<_Args>(__args)...); > > return __tmp; > > } > > #endif > > > > void > >- _M_destroy_node(_Link_type __p) _GLIBCXX_NOEXCEPT > >+ _M_destroy_node(_Base_ptr __p) _GLIBCXX_NOEXCEPT > > { > > #if __cplusplus < 201103L > >- get_allocator().destroy(__p->_M_valptr()); > >+ get_allocator().destroy(static_cast<_Node_ptr>(__p)->_M_valptr()); > > #else > >- _Alloc_traits::destroy(_M_get_Node_allocator(), __p->_M_valptr()); > >- __p->~_Rb_tree_node<_Val>(); > >+ _Node& __node = static_cast<_Node&>(*__p); > >+ _Node_alloc_traits::destroy(_M_get_Node_allocator(), > >+ __node._M_valptr()); > >+ __node.~_Node(); > > #endif > > } > > > > void > >- _M_drop_node(_Link_type __p) _GLIBCXX_NOEXCEPT > >+ _M_drop_node(_Base_ptr __p) _GLIBCXX_NOEXCEPT > > { > > _M_destroy_node(__p); > > _M_put_node(__p); > > } > > > > template<bool _MoveValue, typename _NodeGen> > >- _Link_type > >- _M_clone_node(_Link_type __x, _NodeGen& __node_gen) > >+ _Base_ptr > >+ _M_clone_node(_Base_ptr __x, _NodeGen& __node_gen) > > { > > #if __cplusplus >= 201103L > > using _Vp = __conditional_t<_MoveValue, > > value_type&&, > > const value_type&>; > > #endif > >- _Link_type __tmp > >- = __node_gen(_GLIBCXX_FORWARD(_Vp, *__x->_M_valptr())); > >+ _Base_ptr __tmp = __node_gen > >+ (_GLIBCXX_FORWARD(_Vp, *static_cast<_Node&>(*__x)._M_valptr())); > > __tmp->_M_color = __x->_M_color; > >- __tmp->_M_left = 0; > >- __tmp->_M_right = 0; > >+ __tmp->_M_left = __tmp->_M_right = _Base_ptr(); > > return __tmp; > > } > > > > protected: > >+ typedef typename _Node_traits::_Header_t _Header_t; > >+ > > #if _GLIBCXX_INLINE_VERSION > > template<typename _Key_compare> > > #else > >@@ -660,7 +1278,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > struct _Rb_tree_impl > > : public _Node_allocator > > , public _Rb_tree_key_compare<_Key_compare> > >- , public _Rb_tree_header > >+ , public _Header_t > > { > > typedef _Rb_tree_key_compare<_Key_compare> _Base_key_compare; > > > >@@ -672,9 +1290,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > { } > > > > _Rb_tree_impl(const _Rb_tree_impl& __x) > >- : _Node_allocator(_Alloc_traits::_S_select_on_copy(__x)) > >+ : _Node_allocator(_Node_alloc_traits::_S_select_on_copy(__x)) > > , _Base_key_compare(__x._M_key_compare) > >- , _Rb_tree_header() > >+ , _Header_t() > > { } > > > > #if __cplusplus < 201103L > >@@ -694,7 +1312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree_impl(_Rb_tree_impl&& __x, _Node_allocator&& __a) > > : _Node_allocator(std::move(__a)), > > _Base_key_compare(std::move(__x)), > >- _Rb_tree_header(std::move(__x)) > >+ _Header_t(std::move(__x)) > > { } > > > > _Rb_tree_impl(const _Key_compare& __comp, _Node_allocator&& __a) > >@@ -710,7 +1328,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_root() _GLIBCXX_NOEXCEPT > > { return this->_M_impl._M_header._M_parent; } > > > >- _Const_Base_ptr > >+ _Base_ptr > > _M_root() const _GLIBCXX_NOEXCEPT > > { return this->_M_impl._M_header._M_parent; } > > > >@@ -718,7 +1336,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_leftmost() _GLIBCXX_NOEXCEPT > > { return this->_M_impl._M_header._M_left; } > > > >- _Const_Base_ptr > >+ _Base_ptr > > _M_leftmost() const _GLIBCXX_NOEXCEPT > > { return this->_M_impl._M_header._M_left; } > > > >@@ -726,35 +1344,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_rightmost() _GLIBCXX_NOEXCEPT > > { return this->_M_impl._M_header._M_right; } > > > >- _Const_Base_ptr > >+ _Base_ptr > > _M_rightmost() const _GLIBCXX_NOEXCEPT > > { return this->_M_impl._M_header._M_right; } > > > >- _Link_type > >- _M_mbegin() const _GLIBCXX_NOEXCEPT > >- { return static_cast<_Link_type>(this->_M_impl._M_header._M_parent); } > >- > >- _Link_type > >- _M_begin() _GLIBCXX_NOEXCEPT > >- { return _M_mbegin(); } > >- > >- _Const_Link_type > >+ _Base_ptr > > _M_begin() const _GLIBCXX_NOEXCEPT > >- { > >- return static_cast<_Const_Link_type> > >- (this->_M_impl._M_header._M_parent); > >- } > >+ { return this->_M_impl._M_header._M_parent; } > > > > _Base_ptr > >- _M_end() _GLIBCXX_NOEXCEPT > >- { return &this->_M_impl._M_header; } > >- > >- _Const_Base_ptr > > _M_end() const _GLIBCXX_NOEXCEPT > >- { return &this->_M_impl._M_header; } > >+ { return this->_M_impl._M_header._M_base_ptr(); } > > > > static const _Key& > >- _S_key(_Const_Link_type __x) > >+ _S_key(_Base_ptr __x) > > { > > #if __cplusplus >= 201103L > > // If we're asking for the key we're presumably using the comparison > >@@ -772,48 +1375,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > # endif // C++17 > > #endif // C++11 > > > >- return _KeyOfValue()(*__x->_M_valptr()); > >+ return _KeyOfValue()(*static_cast<const _Node&>(*__x)._M_valptr()); > > } > > > >- static _Link_type > >- _S_left(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return static_cast<_Link_type>(__x->_M_left); } > >- > >- static _Const_Link_type > >- _S_left(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return static_cast<_Const_Link_type>(__x->_M_left); } > >- > >- static _Link_type > >- _S_right(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return static_cast<_Link_type>(__x->_M_right); } > >- > >- static _Const_Link_type > >- _S_right(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return static_cast<_Const_Link_type>(__x->_M_right); } > >- > >- static const _Key& > >- _S_key(_Const_Base_ptr __x) > >- { return _S_key(static_cast<_Const_Link_type>(__x)); } > >- > > static _Base_ptr > >- _S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return _Rb_tree_node_base::_S_minimum(__x); } > >- > >- static _Const_Base_ptr > >- _S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return _Rb_tree_node_base::_S_minimum(__x); } > >+ _S_left(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >+ { return __x->_M_left; } > > > > static _Base_ptr > >- _S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return _Rb_tree_node_base::_S_maximum(__x); } > >- > >- static _Const_Base_ptr > >- _S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT > >- { return _Rb_tree_node_base::_S_maximum(__x); } > >+ _S_right(_Base_ptr __x) _GLIBCXX_NOEXCEPT > >+ { return __x->_M_right; } > > > > public: > >- typedef _Rb_tree_iterator<value_type> iterator; > >- typedef _Rb_tree_const_iterator<value_type> const_iterator; > >+ typedef typename _Node_traits::_Iterator iterator; > >+ typedef typename _Node_traits::_Const_iterator const_iterator; > > > > typedef std::reverse_iterator<iterator> reverse_iterator; > > typedef std::reverse_iterator<const_iterator> const_reverse_iterator; > >@@ -846,7 +1421,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_insert_(_Base_ptr __x, _Base_ptr __y, _Arg&& __v, _NodeGen&); > > > > iterator > >- _M_insert_node(_Base_ptr __x, _Base_ptr __y, _Link_type __z); > >+ _M_insert_node(_Base_ptr __x, _Base_ptr __y, _Base_ptr __z); > > > > template<typename _Arg> > > iterator > >@@ -857,10 +1432,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_insert_equal_lower(_Arg&& __x); > > > > iterator > >- _M_insert_lower_node(_Base_ptr __p, _Link_type __z); > >+ _M_insert_lower_node(_Base_ptr __p, _Base_ptr __z); > > > > iterator > >- _M_insert_equal_lower_node(_Link_type __z); > >+ _M_insert_equal_lower_node(_Base_ptr __z); > > #else > > template<typename _NodeGen> > > iterator > >@@ -879,22 +1454,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > enum { __as_lvalue, __as_rvalue }; > > > > template<bool _MoveValues, typename _NodeGen> > >- _Link_type > >- _M_copy(_Link_type, _Base_ptr, _NodeGen&); > >+ _Base_ptr > >+ _M_copy(_Base_ptr, _Base_ptr, _NodeGen&); > > > > template<bool _MoveValues, typename _NodeGen> > >- _Link_type > >+ _Base_ptr > > _M_copy(const _Rb_tree& __x, _NodeGen& __gen) > > { > >- _Link_type __root = > >- _M_copy<_MoveValues>(__x._M_mbegin(), _M_end(), __gen); > >- _M_leftmost() = _S_minimum(__root); > >- _M_rightmost() = _S_maximum(__root); > >+ _Base_ptr __root = > >+ _M_copy<_MoveValues>(__x._M_begin(), _M_end(), __gen); > >+ _M_leftmost() = _Node_base::_S_minimum(__root); > >+ _M_rightmost() = _Node_base::_S_maximum(__root); > > _M_impl._M_node_count = __x._M_impl._M_node_count; > > return __root; > > } > > > >- _Link_type > >+ _Base_ptr > > _M_copy(const _Rb_tree& __x) > > { > > _Alloc_node __an(*this); > >@@ -902,22 +1477,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > > > void > >- _M_erase(_Link_type __x); > >+ _M_erase(_Base_ptr __x); > > > >- iterator > >- _M_lower_bound(_Link_type __x, _Base_ptr __y, > >- const _Key& __k); > >- > >- const_iterator > >- _M_lower_bound(_Const_Link_type __x, _Const_Base_ptr __y, > >+ _Base_ptr > >+ _M_lower_bound(_Base_ptr __x, _Base_ptr __y, > > const _Key& __k) const; > > > >- iterator > >- _M_upper_bound(_Link_type __x, _Base_ptr __y, > >- const _Key& __k); > >- > >- const_iterator > >- _M_upper_bound(_Const_Link_type __x, _Const_Base_ptr __y, > >+ _Base_ptr > >+ _M_upper_bound(_Base_ptr __x, _Base_ptr __y, > > const _Key& __k) const; > > > > public: > >@@ -935,7 +1502,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree(const _Rb_tree& __x) > > : _M_impl(__x._M_impl) > > { > >- if (__x._M_root() != 0) > >+ if (__x._M_root()) > > _M_root() = _M_copy(__x); > > } > > > >@@ -947,7 +1514,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree(const _Rb_tree& __x, const allocator_type& __a) > > : _M_impl(__x._M_impl._M_key_compare, _Node_allocator(__a)) > > { > >- if (__x._M_root() != nullptr) > >+ if (__x._M_root()) > > _M_root() = _M_copy(__x); > > } > > > >@@ -966,7 +1533,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a, false_type) > > : _M_impl(__x._M_impl._M_key_compare, std::move(__a)) > > { > >- if (__x._M_root() != nullptr) > >+ if (__x._M_root()) > > _M_move_data(__x, false_type{}); > > } > > > >@@ -974,9 +1541,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree(_Rb_tree&& __x, _Node_allocator&& __a) > > noexcept( noexcept( > > _Rb_tree(std::declval<_Rb_tree&&>(), > > std::declval<_Node_allocator&&>(), > >- std::declval<typename _Alloc_traits::is_always_equal>())) ) > >+ std::declval<typename > >_Node_alloc_traits::is_always_equal>())) ) > > : _Rb_tree(std::move(__x), std::move(__a), > >- typename _Alloc_traits::is_always_equal{}) > >+ typename _Node_alloc_traits::is_always_equal{}) > > { } > > #endif > > > >@@ -1001,11 +1568,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > iterator > > end() _GLIBCXX_NOEXCEPT > >- { return iterator(&this->_M_impl._M_header); } > >+ { return iterator(_M_end()); } > > > > const_iterator > > end() const _GLIBCXX_NOEXCEPT > >- { return const_iterator(&this->_M_impl._M_header); } > >+ { return const_iterator(_M_end()); } > > > > reverse_iterator > > rbegin() _GLIBCXX_NOEXCEPT > >@@ -1033,7 +1600,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > size_type > > max_size() const _GLIBCXX_NOEXCEPT > >- { return _Alloc_traits::max_size(_M_get_Node_allocator()); } > >+ { return _Node_alloc_traits::max_size(_M_get_Node_allocator()); } > > > > void > > swap(_Rb_tree& __t) > >@@ -1194,7 +1761,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > const_iterator __result = __position; > > ++__result; > > _M_erase_aux(__position); > >- return __result._M_const_cast(); > >+ return iterator(__result._M_node); > > } > > > > // LWG 2059. > >@@ -1235,7 +1802,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > erase(const_iterator __first, const_iterator __last) > > { > > _M_erase_aux(__first, __last); > >- return __last._M_const_cast(); > >+ return iterator(__last._M_node); > > } > > #else > > void > >@@ -1266,19 +1833,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > iterator > > lower_bound(const key_type& __k) > >- { return _M_lower_bound(_M_begin(), _M_end(), __k); } > >+ { return iterator(_M_lower_bound(_M_begin(), _M_end(), __k)); } > > > > const_iterator > > lower_bound(const key_type& __k) const > >- { return _M_lower_bound(_M_begin(), _M_end(), __k); } > >+ { > >+ return const_iterator > >+ (_M_lower_bound(_M_begin(), _M_end(), __k)); > >+ } > > > > iterator > > upper_bound(const key_type& __k) > >- { return _M_upper_bound(_M_begin(), _M_end(), __k); } > >+ { return iterator(_M_upper_bound(_M_begin(), _M_end(), __k)); } > > > > const_iterator > > upper_bound(const key_type& __k) const > >- { return _M_upper_bound(_M_begin(), _M_end(), __k); } > >+ { > >+ return const_iterator > >+ (_M_upper_bound(_M_begin(), _M_end(), __k)); > >+ } > > > > pair<iterator, iterator> > > equal_range(const key_type& __k); > >@@ -1293,7 +1866,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_find_tr(const _Kt& __k) > > { > > const _Rb_tree* __const_this = this; > >- return __const_this->_M_find_tr(__k)._M_const_cast(); > >+ return iterator(__const_this->_M_find_tr(__k)._M_node); > > } > > > > template<typename _Kt, > >@@ -1301,7 +1874,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > const_iterator > > _M_find_tr(const _Kt& __k) const > > { > >- auto __j = _M_lower_bound_tr(__k); > >+ const_iterator __j(_M_lower_bound_tr(__k)); > > if (__j != end() && _M_impl._M_key_compare(__k, > > _S_key(__j._M_node))) > > __j = end(); > > return __j; > >@@ -1318,21 +1891,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > > template<typename _Kt, > > typename _Req = __has_is_transparent_t<_Compare, _Kt>> > >- iterator > >- _M_lower_bound_tr(const _Kt& __k) > >- { > >- const _Rb_tree* __const_this = this; > >- return __const_this->_M_lower_bound_tr(__k)._M_const_cast(); > >- } > >- > >- template<typename _Kt, > >- typename _Req = __has_is_transparent_t<_Compare, _Kt>> > >- const_iterator > >+ _Base_ptr > > _M_lower_bound_tr(const _Kt& __k) const > > { > > auto __x = _M_begin(); > > auto __y = _M_end(); > >- while (__x != 0) > >+ while (__x) > > if (!_M_impl._M_key_compare(_S_key(__x), __k)) > > { > > __y = __x; > >@@ -1340,26 +1904,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > else > > __x = _S_right(__x); > >- return const_iterator(__y); > >+ return __y; > > } > > > > template<typename _Kt, > > typename _Req = __has_is_transparent_t<_Compare, _Kt>> > >- iterator > >- _M_upper_bound_tr(const _Kt& __k) > >- { > >- const _Rb_tree* __const_this = this; > >- return __const_this->_M_upper_bound_tr(__k)._M_const_cast(); > >- } > >- > >- template<typename _Kt, > >- typename _Req = __has_is_transparent_t<_Compare, _Kt>> > >- const_iterator > >+ _Base_ptr > > _M_upper_bound_tr(const _Kt& __k) const > > { > > auto __x = _M_begin(); > > auto __y = _M_end(); > >- while (__x != 0) > >+ while (__x) > > if (_M_impl._M_key_compare(__k, _S_key(__x))) > > { > > __y = __x; > >@@ -1367,7 +1922,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > else > > __x = _S_right(__x); > >- return const_iterator(__y); > >+ return __y; > > } > > > > template<typename _Kt, > >@@ -1377,7 +1932,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > { > > const _Rb_tree* __const_this = this; > > auto __ret = __const_this->_M_equal_range_tr(__k); > >- return { __ret.first._M_const_cast(), __ret.second._M_const_cast() > >}; > >+ return > >+ { iterator(__ret.first._M_node), iterator(__ret.second._M_node) }; > > } > > > > template<typename _Kt, > >@@ -1385,7 +1941,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > pair<const_iterator, const_iterator> > > _M_equal_range_tr(const _Kt& __k) const > > { > >- auto __low = _M_lower_bound_tr(__k); > >+ const_iterator __low(_M_lower_bound_tr(__k)); > > auto __high = __low; > > auto& __cmp = _M_impl._M_key_compare; > > while (__high != end() && !__cmp(__k, _S_key(__high._M_node))) > >@@ -1401,7 +1957,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > #if __cplusplus >= 201103L > > _Rb_tree& > > operator=(_Rb_tree&&) > >- noexcept(_Alloc_traits::_S_nothrow_move() > >+ noexcept(_Node_alloc_traits::_S_nothrow_move() > > && is_nothrow_move_assignable<_Compare>::value); > > > > template<typename _Iterator> > >@@ -1449,8 +2005,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > auto __res = _M_get_insert_unique_pos(__nh._M_key()); > > if (__res.second) > > { > >- __ret.position > >- = _M_insert_node(__res.first, __res.second, __nh._M_ptr); > >+ __ret.position = _M_insert_node(__res.first, __res.second, > >+ __nh._M_ptr->_M_base_ptr()); > > __nh.release(); > > __ret.inserted = true; > > } > >@@ -1476,9 +2032,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc); > > auto __res = _M_get_insert_equal_pos(__nh._M_key()); > > if (__res.second) > >- __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr); > >+ __ret = _M_insert_node(__res.first, __res.second, > >+ __nh._M_ptr->_M_base_ptr()); > > else > >- __ret = _M_insert_equal_lower_node(__nh._M_ptr); > >+ __ret = _M_insert_equal_lower_node(__nh._M_ptr->_M_base_ptr()); > > __nh.release(); > > } > > return __ret; > >@@ -1497,7 +2054,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > auto __res = _M_get_insert_hint_unique_pos(__hint, __nh._M_key()); > > if (__res.second) > > { > >- __ret = _M_insert_node(__res.first, __res.second, > >__nh._M_ptr); > >+ __ret = _M_insert_node(__res.first, __res.second, > >+ __nh._M_ptr->_M_base_ptr()); > > __nh.release(); > > } > > else > >@@ -1518,9 +2076,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > __glibcxx_assert(_M_get_Node_allocator() == *__nh._M_alloc); > > auto __res = _M_get_insert_hint_equal_pos(__hint, __nh._M_key()); > > if (__res.second) > >- __ret = _M_insert_node(__res.first, __res.second, __nh._M_ptr); > >+ __ret = _M_insert_node(__res.first, __res.second, > >+ __nh._M_ptr->_M_base_ptr()); > > else > >- __ret = _M_insert_equal_lower_node(__nh._M_ptr); > >+ __ret = _M_insert_equal_lower_node(__nh._M_ptr->_M_base_ptr()); > > __nh.release(); > > } > > return __ret; > >@@ -1530,10 +2089,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > node_type > > extract(const_iterator __pos) > > { > >- auto __ptr = _Rb_tree_rebalance_for_erase( > >- __pos._M_const_cast()._M_node, _M_impl._M_header); > >+ auto __ptr = _Node_traits::_S_rebalance_for_erase > >+ (__pos._M_node, _M_impl._M_header); > > --_M_impl._M_node_count; > >- return { static_cast<_Link_type>(__ptr), _M_get_Node_allocator() }; > >+ return > >+ { __ptr->template _M_node_ptr<_Node_ptr>(), _M_get_Node_allocator() > >}; > > } > > > > /// Extract a node. > >@@ -1567,11 +2127,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > if (__res.second) > > { > > auto& __src_impl = _Merge_helper::_S_get_impl(__src); > >- auto __ptr = _Rb_tree_rebalance_for_erase( > >- __pos._M_node, __src_impl._M_header); > >+ auto __ptr = _Node_traits::_S_rebalance_for_erase > >+ (__pos._M_node, __src_impl._M_header); > > --__src_impl._M_node_count; > >- _M_insert_node(__res.first, __res.second, > >- static_cast<_Link_type>(__ptr)); > >+ _M_insert_node(__res.first, __res.second, __ptr); > > } > > } > > } > >@@ -1589,11 +2148,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > if (__res.second) > > { > > auto& __src_impl = _Merge_helper::_S_get_impl(__src); > >- auto __ptr = _Rb_tree_rebalance_for_erase( > >- __pos._M_node, __src_impl._M_header); > >+ auto __ptr = _Node_traits::_S_rebalance_for_erase > >+ (__pos._M_node, __src_impl._M_header); > > --__src_impl._M_node_count; > >- _M_insert_node(__res.first, __res.second, > >- static_cast<_Link_type>(__ptr)); > >+ _M_insert_node(__res.first, __res.second, __ptr); > > } > > } > > } > >@@ -1666,7 +2224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > > > _Rb_tree& _M_t; > >- _Link_type _M_node; > >+ _Base_ptr _M_node; > > }; > > #endif // C++11 > > }; > >@@ -1704,7 +2262,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_move_assign(_Rb_tree& __x, true_type) > > { > > clear(); > >- if (__x._M_root() != nullptr) > >+ if (__x._M_root()) > > _M_move_data(__x, true_type()); > > std::__alloc_on_move(_M_get_Node_allocator(), > > __x._M_get_Node_allocator()); > >@@ -1723,7 +2281,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > // structure. > > _Reuse_or_alloc_node __roan(*this); > > _M_impl._M_reset(); > >- if (__x._M_root() != nullptr) > >+ if (__x._M_root()) > > { > > _M_root() = _M_copy<__as_rvalue>(__x, __roan); > > __x.clear(); > >@@ -1735,11 +2293,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > inline _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>& > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > > operator=(_Rb_tree&& __x) > >- noexcept(_Alloc_traits::_S_nothrow_move() > >+ noexcept(_Node_alloc_traits::_S_nothrow_move() > > && is_nothrow_move_assignable<_Compare>::value) > > { > > _M_impl._M_key_compare = std::move(__x._M_impl._M_key_compare); > >- _M_move_assign(__x, > >__bool_constant<_Alloc_traits::_S_nothrow_move()>()); > >+ _M_move_assign(__x, > >+ > >__bool_constant<_Node_alloc_traits::_S_nothrow_move()>()); > > return *this; > > } > > > >@@ -1780,11 +2339,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > { > > // Note that _Key may be a constant type. > > #if __cplusplus >= 201103L > >- if (_Alloc_traits::_S_propagate_on_copy_assign()) > >+ if (_Node_alloc_traits::_S_propagate_on_copy_assign()) > > { > > auto& __this_alloc = this->_M_get_Node_allocator(); > > auto& __that_alloc = __x._M_get_Node_allocator(); > >- if (!_Alloc_traits::_S_always_equal() > >+ if (!_Node_alloc_traits::_S_always_equal() > > && __this_alloc != __that_alloc) > > { > > // Replacement allocator cannot free existing storage, we > > need > >@@ -1798,7 +2357,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Reuse_or_alloc_node __roan(*this); > > _M_impl._M_reset(); > > _M_impl._M_key_compare = __x._M_impl._M_key_compare; > >- if (__x._M_root() != 0) > >+ if (__x._M_root()) > > _M_root() = _M_copy<__as_lvalue>(__x, __roan); > > } > > > >@@ -1822,14 +2381,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > #endif > > _NodeGen& __node_gen) > > { > >- bool __insert_left = (__x != 0 || __p == _M_end() > >+ bool __insert_left = (__x || __p == _M_end() > > || _M_impl._M_key_compare(_KeyOfValue()(__v), > > _S_key(__p))); > > > >- _Link_type __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v)); > >+ _Base_ptr __z = __node_gen(_GLIBCXX_FORWARD(_Arg, __v)); > > > >- _Rb_tree_insert_and_rebalance(__insert_left, __z, __p, > >- this->_M_impl._M_header); > >+ _Node_traits::_S_insert_and_rebalance > >+ (__insert_left, __z, __p, this->_M_impl._M_header); > > ++_M_impl._M_node_count; > > return iterator(__z); > > } > >@@ -1851,10 +2410,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > || !_M_impl._M_key_compare(_S_key(__p), > > _KeyOfValue()(__v))); > > > >- _Link_type __z = _M_create_node(_GLIBCXX_FORWARD(_Arg, __v)); > >- > >- _Rb_tree_insert_and_rebalance(__insert_left, __z, __p, > >- this->_M_impl._M_header); > >+ _Base_ptr __z = _M_create_node(_GLIBCXX_FORWARD(_Arg, __v)); > >+ _Node_traits::_S_insert_and_rebalance > >+ (__insert_left, __z, __p, this->_M_impl._M_header); > > ++_M_impl._M_node_count; > > return iterator(__z); > > } > >@@ -1872,9 +2430,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_insert_equal_lower(const _Val& __v) > > #endif > > { > >- _Link_type __x = _M_begin(); > >+ _Base_ptr __x = _M_begin(); > > _Base_ptr __y = _M_end(); > >- while (__x != 0) > >+ while (__x) > > { > > __y = __x; > > __x = !_M_impl._M_key_compare(_S_key(__x), _KeyOfValue()(__v)) ? > >@@ -1886,12 +2444,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > template<typename _Key, typename _Val, typename _KoV, > > typename _Compare, typename _Alloc> > > template<bool _MoveValues, typename _NodeGen> > >- typename _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::_Link_type > >+ typename _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>::_Base_ptr > > _Rb_tree<_Key, _Val, _KoV, _Compare, _Alloc>:: > >- _M_copy(_Link_type __x, _Base_ptr __p, _NodeGen& __node_gen) > >+ _M_copy(_Base_ptr __x, _Base_ptr __p, _NodeGen& __node_gen) > > { > > // Structural copy. __x and __p must be non-null. > >- _Link_type __top = _M_clone_node<_MoveValues>(__x, __node_gen); > >+ _Base_ptr __top = _M_clone_node<_MoveValues>(__x, __node_gen); > > __top->_M_parent = __p; > > > > __try > >@@ -1902,9 +2460,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > __p = __top; > > __x = _S_left(__x); > > > >- while (__x != 0) > >+ while (__x) > > { > >- _Link_type __y = _M_clone_node<_MoveValues>(__x, __node_gen); > >+ _Base_ptr __y = _M_clone_node<_MoveValues>(__x, __node_gen); > > __p->_M_left = __y; > > __y->_M_parent = __p; > > if (__x->_M_right) > >@@ -1926,13 +2484,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typename _Compare, typename _Alloc> > > void > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_erase(_Link_type __x) > >+ _M_erase(_Base_ptr __x) > > { > > // Erase without rebalancing. > >- while (__x != 0) > >+ while (__x) > > { > > _M_erase(_S_right(__x)); > >- _Link_type __y = _S_left(__x); > >+ _Base_ptr __y = _S_left(__x); > > _M_drop_node(__x); > > __x = __y; > > } > >@@ -1941,65 +2499,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > template<typename _Key, typename _Val, typename _KeyOfValue, > > typename _Compare, typename _Alloc> > > typename _Rb_tree<_Key, _Val, _KeyOfValue, > >- _Compare, _Alloc>::iterator > >+ _Compare, _Alloc>::_Base_ptr > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_lower_bound(_Link_type __x, _Base_ptr __y, > >- const _Key& __k) > >- { > >- while (__x != 0) > >- if (!_M_impl._M_key_compare(_S_key(__x), __k)) > >- __y = __x, __x = _S_left(__x); > >- else > >- __x = _S_right(__x); > >- return iterator(__y); > >- } > >- > >- template<typename _Key, typename _Val, typename _KeyOfValue, > >- typename _Compare, typename _Alloc> > >- typename _Rb_tree<_Key, _Val, _KeyOfValue, > >- _Compare, _Alloc>::const_iterator > >- _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_lower_bound(_Const_Link_type __x, _Const_Base_ptr __y, > >+ _M_lower_bound(_Base_ptr __x, _Base_ptr __y, > > const _Key& __k) const > > { > >- while (__x != 0) > >+ while (__x) > > if (!_M_impl._M_key_compare(_S_key(__x), __k)) > > __y = __x, __x = _S_left(__x); > > else > > __x = _S_right(__x); > >- return const_iterator(__y); > >- } > >- > >- template<typename _Key, typename _Val, typename _KeyOfValue, > >- typename _Compare, typename _Alloc> > >- typename _Rb_tree<_Key, _Val, _KeyOfValue, > >- _Compare, _Alloc>::iterator > >- _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_upper_bound(_Link_type __x, _Base_ptr __y, > >- const _Key& __k) > >- { > >- while (__x != 0) > >- if (_M_impl._M_key_compare(__k, _S_key(__x))) > >- __y = __x, __x = _S_left(__x); > >- else > >- __x = _S_right(__x); > >- return iterator(__y); > >+ return __y; > > } > > > > template<typename _Key, typename _Val, typename _KeyOfValue, > > typename _Compare, typename _Alloc> > > typename _Rb_tree<_Key, _Val, _KeyOfValue, > >- _Compare, _Alloc>::const_iterator > >+ _Compare, _Alloc>::_Base_ptr > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_upper_bound(_Const_Link_type __x, _Const_Base_ptr __y, > >+ _M_upper_bound(_Base_ptr __x, _Base_ptr __y, > > const _Key& __k) const > > { > >- while (__x != 0) > >+ while (__x) > > if (_M_impl._M_key_compare(__k, _S_key(__x))) > > __y = __x, __x = _S_left(__x); > > else > > __x = _S_right(__x); > >- return const_iterator(__y); > >+ return __y; > > } > > > > template<typename _Key, typename _Val, typename _KeyOfValue, > >@@ -2011,9 +2537,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > > equal_range(const _Key& __k) > > { > >- _Link_type __x = _M_begin(); > >+ _Base_ptr __x = _M_begin(); > > _Base_ptr __y = _M_end(); > >- while (__x != 0) > >+ while (__x) > > { > > if (_M_impl._M_key_compare(_S_key(__x), __k)) > > __x = _S_right(__x); > >@@ -2021,13 +2547,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > __y = __x, __x = _S_left(__x); > > else > > { > >- _Link_type __xu(__x); > >+ _Base_ptr __xu(__x); > > _Base_ptr __yu(__y); > > __y = __x, __x = _S_left(__x); > > __xu = _S_right(__xu); > >- return pair<iterator, > >- iterator>(_M_lower_bound(__x, __y, __k), > >- _M_upper_bound(__xu, __yu, __k)); > >+ return make_pair(iterator(_M_lower_bound(__x, __y, __k)), > >+ iterator(_M_upper_bound(__xu, __yu, __k))); > > } > > } > > return pair<iterator, iterator>(iterator(__y), > >@@ -2043,9 +2568,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > > equal_range(const _Key& __k) const > > { > >- _Const_Link_type __x = _M_begin(); > >- _Const_Base_ptr __y = _M_end(); > >- while (__x != 0) > >+ _Base_ptr __x = _M_begin(); > >+ _Base_ptr __y = _M_end(); > >+ while (__x) > > { > > if (_M_impl._M_key_compare(_S_key(__x), __k)) > > __x = _S_right(__x); > >@@ -2053,13 +2578,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > __y = __x, __x = _S_left(__x); > > else > > { > >- _Const_Link_type __xu(__x); > >- _Const_Base_ptr __yu(__y); > >+ _Base_ptr __xu(__x); > >+ _Base_ptr __yu(__y); > > __y = __x, __x = _S_left(__x); > > __xu = _S_right(__xu); > >- return pair<const_iterator, > >- const_iterator>(_M_lower_bound(__x, __y, __k), > >- _M_upper_bound(__xu, __yu, __k)); > >+ return make_pair(const_iterator(_M_lower_bound(__x, __y, __k)), > >+ const_iterator(_M_upper_bound(__xu, __yu, > >__k))); > > } > > } > > return pair<const_iterator, const_iterator>(const_iterator(__y), > >@@ -2073,12 +2597,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > swap(_Rb_tree& __t) > > _GLIBCXX_NOEXCEPT_IF(__is_nothrow_swappable<_Compare>::value) > > { > >- if (_M_root() == 0) > >+ if (!_M_root()) > > { > >- if (__t._M_root() != 0) > >+ if (__t._M_root()) > > _M_impl._M_move_data(__t._M_impl); > > } > >- else if (__t._M_root() == 0) > >+ else if (!__t._M_root()) > > __t._M_impl._M_move_data(_M_impl); > > else > > { > >@@ -2093,8 +2617,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > // No need to swap header's color as it does not change. > > std::swap(this->_M_impl._M_key_compare, __t._M_impl._M_key_compare); > > > >- _Alloc_traits::_S_on_swap(_M_get_Node_allocator(), > >- __t._M_get_Node_allocator()); > >+ _Node_alloc_traits::_S_on_swap(_M_get_Node_allocator(), > >+ __t._M_get_Node_allocator()); > > } > > > > template<typename _Key, typename _Val, typename _KeyOfValue, > >@@ -2107,10 +2631,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_get_insert_unique_pos(const key_type& __k) > > { > > typedef pair<_Base_ptr, _Base_ptr> _Res; > >- _Link_type __x = _M_begin(); > >+ _Base_ptr __x = _M_begin(); > > _Base_ptr __y = _M_end(); > > bool __comp = true; > >- while (__x != 0) > >+ while (__x) > > { > > __y = __x; > > __comp = _M_impl._M_key_compare(__k, _S_key(__x)); > >@@ -2126,7 +2650,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > if (_M_impl._M_key_compare(_S_key(__j._M_node), __k)) > > return _Res(__x, __y); > >- return _Res(__j._M_node, 0); > >+ return _Res(__j._M_node, _Base_ptr()); > > } > > > > template<typename _Key, typename _Val, typename _KeyOfValue, > >@@ -2139,9 +2663,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_get_insert_equal_pos(const key_type& __k) > > { > > typedef pair<_Base_ptr, _Base_ptr> _Res; > >- _Link_type __x = _M_begin(); > >+ _Base_ptr __x = _M_begin(); > > _Base_ptr __y = _M_end(); > >- while (__x != 0) > >+ while (__x) > > { > > __y = __x; > > __x = _M_impl._M_key_compare(__k, _S_key(__x)) ? > >@@ -2209,44 +2733,43 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _M_get_insert_hint_unique_pos(const_iterator __position, > > const key_type& __k) > > { > >- iterator __pos = __position._M_const_cast(); > > typedef pair<_Base_ptr, _Base_ptr> _Res; > > > > // end() > >- if (__pos._M_node == _M_end()) > >+ if (__position._M_node == _M_end()) > > { > > if (size() > 0 > > && _M_impl._M_key_compare(_S_key(_M_rightmost()), __k)) > >- return _Res(0, _M_rightmost()); > >+ return _Res(_Base_ptr(), _M_rightmost()); > > else > > return _M_get_insert_unique_pos(__k); > > } > >- else if (_M_impl._M_key_compare(__k, _S_key(__pos._M_node))) > >+ else if (_M_impl._M_key_compare(__k, _S_key(__position._M_node))) > > { > > // First, try before... > >- iterator __before = __pos; > >- if (__pos._M_node == _M_leftmost()) // begin() > >+ iterator __before(__position._M_node); > >+ if (__position._M_node == _M_leftmost()) // begin() > > return _Res(_M_leftmost(), _M_leftmost()); > > else if (_M_impl._M_key_compare(_S_key((--__before)._M_node), __k)) > > { > >- if (_S_right(__before._M_node) == 0) > >- return _Res(0, __before._M_node); > >+ if (!_S_right(__before._M_node)) > >+ return _Res(_Base_ptr(), __before._M_node); > > else > >- return _Res(__pos._M_node, __pos._M_node); > >+ return _Res(__position._M_node, __position._M_node); > > } > > else > > return _M_get_insert_unique_pos(__k); > > } > >- else if (_M_impl._M_key_compare(_S_key(__pos._M_node), __k)) > >+ else if (_M_impl._M_key_compare(_S_key(__position._M_node), __k)) > > { > > // ... then try after. > >- iterator __after = __pos; > >- if (__pos._M_node == _M_rightmost()) > >- return _Res(0, _M_rightmost()); > >+ iterator __after(__position._M_node); > >+ if (__position._M_node == _M_rightmost()) > >+ return _Res(_Base_ptr(), _M_rightmost()); > > else if (_M_impl._M_key_compare(__k, _S_key((++__after)._M_node))) > > { > >- if (_S_right(__pos._M_node) == 0) > >- return _Res(0, __pos._M_node); > >+ if (!_S_right(__position._M_node)) > >+ return _Res(_Base_ptr(), __position._M_node); > > else > > return _Res(__after._M_node, __after._M_node); > > } > >@@ -2255,7 +2778,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > } > > else > > // Equivalent keys. > >- return _Res(__pos._M_node, 0); > >+ return _Res(__position._M_node, _Base_ptr()); > > } > > > > template<typename _Key, typename _Val, typename _KeyOfValue, > >@@ -2294,30 +2817,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > > _M_get_insert_hint_equal_pos(const_iterator __position, const key_type& > > __k) > > { > >- iterator __pos = __position._M_const_cast(); > > typedef pair<_Base_ptr, _Base_ptr> _Res; > > > > // end() > >- if (__pos._M_node == _M_end()) > >+ if (__position._M_node == _M_end()) > > { > > if (size() > 0 > > && !_M_impl._M_key_compare(__k, _S_key(_M_rightmost()))) > >- return _Res(0, _M_rightmost()); > >+ return _Res(_Base_ptr(), _M_rightmost()); > > else > > return _M_get_insert_equal_pos(__k); > > } > >- else if (!_M_impl._M_key_compare(_S_key(__pos._M_node), __k)) > >+ else if (!_M_impl._M_key_compare(_S_key(__position._M_node), __k)) > > { > > // First, try before... > >- iterator __before = __pos; > >- if (__pos._M_node == _M_leftmost()) // begin() > >+ iterator __before(__position._M_node); > >+ if (__position._M_node == _M_leftmost()) // begin() > > return _Res(_M_leftmost(), _M_leftmost()); > > else if (!_M_impl._M_key_compare(__k, _S_key((--__before)._M_node))) > > { > >- if (_S_right(__before._M_node) == 0) > >- return _Res(0, __before._M_node); > >+ if (!_S_right(__before._M_node)) > >+ return _Res(_Base_ptr(), __before._M_node); > > else > >- return _Res(__pos._M_node, __pos._M_node); > >+ return _Res(__position._M_node, __position._M_node); > > } > > else > > return _M_get_insert_equal_pos(__k); > >@@ -2325,18 +2847,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > else > > { > > // ... then try after. > >- iterator __after = __pos; > >- if (__pos._M_node == _M_rightmost()) > >- return _Res(0, _M_rightmost()); > >+ iterator __after(__position._M_node); > >+ if (__position._M_node == _M_rightmost()) > >+ return _Res(_Base_ptr(), _M_rightmost()); > > else if (!_M_impl._M_key_compare(_S_key((++__after)._M_node), __k)) > > { > >- if (_S_right(__pos._M_node) == 0) > >- return _Res(0, __pos._M_node); > >+ if (!_S_right(__position._M_node)) > >+ return _Res(_Base_ptr(), __position._M_node); > > else > > return _Res(__after._M_node, __after._M_node); > > } > > else > >- return _Res(0, 0); > >+ return _Res(_Base_ptr(), _Base_ptr()); > > } > > } > > > >@@ -2373,15 +2895,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typename _Compare, typename _Alloc> > > auto > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_insert_node(_Base_ptr __x, _Base_ptr __p, _Link_type __z) > >+ _M_insert_node(_Base_ptr __x, _Base_ptr __p, _Base_ptr __z) > > -> iterator > > { > >- bool __insert_left = (__x != 0 || __p == _M_end() > >+ bool __insert_left = (__x || __p == _M_end() > > || _M_impl._M_key_compare(_S_key(__z), > > _S_key(__p))); > > > >- _Rb_tree_insert_and_rebalance(__insert_left, __z, __p, > >- this->_M_impl._M_header); > >+ _Node_traits::_S_insert_and_rebalance > >+ (__insert_left, __z, __p, this->_M_impl._M_header); > > ++_M_impl._M_node_count; > > return iterator(__z); > > } > >@@ -2390,15 +2912,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typename _Compare, typename _Alloc> > > auto > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_insert_lower_node(_Base_ptr __p, _Link_type __z) > >+ _M_insert_lower_node(_Base_ptr __p, _Base_ptr __z) > > -> iterator > > { > > bool __insert_left = (__p == _M_end() > > || !_M_impl._M_key_compare(_S_key(__p), > > _S_key(__z))); > > > >- _Rb_tree_insert_and_rebalance(__insert_left, __z, __p, > >- this->_M_impl._M_header); > >+ _Node_traits::_S_insert_and_rebalance > >+ (__insert_left, __z, __p, this->_M_impl._M_header); > > ++_M_impl._M_node_count; > > return iterator(__z); > > } > >@@ -2407,12 +2929,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > typename _Compare, typename _Alloc> > > auto > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > >- _M_insert_equal_lower_node(_Link_type __z) > >+ _M_insert_equal_lower_node(_Base_ptr __z) > > -> iterator > > { > >- _Link_type __x = _M_begin(); > >+ _Base_ptr __x = _M_begin(); > > _Base_ptr __y = _M_end(); > >- while (__x != 0) > >+ while (__x) > > { > > __y = __x; > > __x = !_M_impl._M_key_compare(_S_key(__x), _S_key(__z)) ? > >@@ -2487,10 +3009,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > > _M_erase_aux(const_iterator __position) > > { > >- _Link_type __y = > >- static_cast<_Link_type>(_Rb_tree_rebalance_for_erase > >- (const_cast<_Base_ptr>(__position._M_node), > >- this->_M_impl._M_header)); > >+ _Base_ptr __y = _Node_traits::_S_rebalance_for_erase > >+ (__position._M_node, this->_M_impl._M_header); > > _M_drop_node(__y); > > --_M_impl._M_node_count; > > } > >@@ -2527,7 +3047,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > > find(const _Key& __k) > > { > >- iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k); > >+ iterator __j(_M_lower_bound(_M_begin(), _M_end(), __k)); > > return (__j == end() > > || _M_impl._M_key_compare(__k, > > _S_key(__j._M_node))) ? end() : __j; > >@@ -2540,7 +3060,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>:: > > find(const _Key& __k) const > > { > >- const_iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k); > >+ const_iterator __j(_M_lower_bound(_M_begin(), _M_end(), __k)); > > return (__j == end() > > || _M_impl._M_key_compare(__k, > > _S_key(__j._M_node))) ? end() : __j; > >@@ -2574,9 +3094,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > unsigned int __len = _Rb_tree_black_count(_M_leftmost(), _M_root()); > > for (const_iterator __it = begin(); __it != end(); ++__it) > > { > >- _Const_Link_type __x = static_cast<_Const_Link_type>(__it._M_node); > >- _Const_Link_type __L = _S_left(__x); > >- _Const_Link_type __R = _S_right(__x); > >+ _Base_ptr __x = __it._M_node; > >+ _Base_ptr __L = _S_left(__x); > >+ _Base_ptr __R = _S_right(__x); > > > > if (__x->_M_color == _S_red) > > if ((__L && __L->_M_color == _S_red) > >@@ -2592,9 +3112,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > return false; > > } > > > >- if (_M_leftmost() != _Rb_tree_node_base::_S_minimum(_M_root())) > >+ if (_M_leftmost() != _Node_base::_S_minimum(_M_root())) > > return false; > >- if (_M_rightmost() != _Rb_tree_node_base::_S_maximum(_M_root())) > >+ if (_M_rightmost() != _Node_base::_S_maximum(_M_root())) > > return false; > > return true; > > } > >diff --git a/libstdc++-v3/testsuite/23_containers/map/allocator/ext_ptr.cc > >b/libstdc++-v3/testsuite/23_containers/map/allocator/ext_ptr.cc > >new file mode 100644 > >index 00000000000..3d83738f86b > >--- /dev/null > >+++ b/libstdc++-v3/testsuite/23_containers/map/allocator/ext_ptr.cc > >@@ -0,0 +1,37 @@ > >+// { dg-do run { target c++11 } } > >+ > >+#include <map> > >+#include <memory> > >+#include <testsuite_hooks.h> > >+#include <testsuite_allocator.h> > >+ > >+struct T { int i; }; > >+ > >+bool operator<(const T& l, const T& r) > >+{ return l.i < r.i; } > >+ > >+struct L : std::less<T> > >+{ }; > >+ > >+using __gnu_test::CustomPointerAlloc; > >+ > >+template class std::map<T, int, L, > >+ CustomPointerAlloc<std::pair<const T, int>>>; > >+ > >+void test01() > >+{ > >+ typedef CustomPointerAlloc<std::pair<const T, int>> alloc_type; > >+ typedef std::map<T, int, L, alloc_type> test_type; > >+ test_type v; > >+ v.insert({ T(), 0 }); > >+ VERIFY( v.begin()->second == 0 ); > >+ VERIFY( ++v.begin() == v.end() ); > >+ v.insert({ T { 1 }, 1 }); > >+ VERIFY( v.size() == 2 ); > >+ VERIFY( v.find(T()) != v.end() ); > >+} > >+ > >+int main() > >+{ > >+ test01(); > >+} > >diff --git > >a/libstdc++-v3/testsuite/23_containers/multimap/allocator/ext_ptr.cc > >b/libstdc++-v3/testsuite/23_containers/multimap/allocator/ext_ptr.cc > >new file mode 100644 > >index 00000000000..41689ef43b7 > >--- /dev/null > >+++ b/libstdc++-v3/testsuite/23_containers/multimap/allocator/ext_ptr.cc > >@@ -0,0 +1,33 @@ > >+// { dg-do run { target c++11 } } > >+ > >+#include <map> > >+#include <memory> > >+#include <testsuite_hooks.h> > >+#include <testsuite_allocator.h> > >+ > >+struct T { int i; }; > >+ > >+bool operator<(const T& l, const T& r) > >+{ return l.i < r.i; } > >+ > >+struct L : std::less<T> > >+{ }; > >+ > >+using __gnu_test::CustomPointerAlloc; > >+ > >+template class std::multimap<T, int, L, > >+ CustomPointerAlloc<std::pair<const T, int>>>; > >+ > >+void test01() > >+{ > >+ typedef CustomPointerAlloc<std::pair<const T, int>> alloc_type; > >+ typedef std::multimap<T, int, L, alloc_type> test_type; > >+ test_type v; > >+ v.insert({ T(), 0 }); > >+ VERIFY( ++v.begin() == v.end() ); > >+} > >+ > >+int main() > >+{ > >+ test01(); > >+} > >diff --git > >a/libstdc++-v3/testsuite/23_containers/multiset/allocator/ext_ptr.cc > >b/libstdc++-v3/testsuite/23_containers/multiset/allocator/ext_ptr.cc > >new file mode 100644 > >index 00000000000..589e6b0a617 > >--- /dev/null > >+++ b/libstdc++-v3/testsuite/23_containers/multiset/allocator/ext_ptr.cc > >@@ -0,0 +1,32 @@ > >+// { dg-do run { target c++11 } } > >+ > >+#include <set> > >+#include <memory> > >+#include <testsuite_hooks.h> > >+#include <testsuite_allocator.h> > >+ > >+struct T { int i; }; > >+ > >+bool operator<(const T& l, const T& r) > >+{ return l.i < r.i; } > >+ > >+struct L : std::less<T> > >+{ }; > >+ > >+using __gnu_test::CustomPointerAlloc; > >+ > >+template class std::multiset<T, L, CustomPointerAlloc<T>>; > >+ > >+void test01() > >+{ > >+ typedef CustomPointerAlloc<T> alloc_type; > >+ typedef std::multiset<T, L, alloc_type> test_type; > >+ test_type v; > >+ v.insert(T()); > >+ VERIFY( ++v.begin() == v.end() ); > >+} > >+ > >+int main() > >+{ > >+ test01(); > >+} > >diff --git a/libstdc++-v3/testsuite/23_containers/set/allocator/ext_ptr.cc > >b/libstdc++-v3/testsuite/23_containers/set/allocator/ext_ptr.cc > >new file mode 100644 > >index 00000000000..bbcf32b20be > >--- /dev/null > >+++ b/libstdc++-v3/testsuite/23_containers/set/allocator/ext_ptr.cc > >@@ -0,0 +1,32 @@ > >+// { dg-do run { target c++11 } } > >+ > >+#include <set> > >+#include <memory> > >+#include <testsuite_hooks.h> > >+#include <testsuite_allocator.h> > >+ > >+struct T { int i; }; > >+ > >+bool operator<(const T& l, const T& r) > >+{ return l.i < r.i; } > >+ > >+struct L : std::less<T> > >+{ }; > >+ > >+using __gnu_test::CustomPointerAlloc; > >+ > >+template class std::set<T, L, CustomPointerAlloc<T>>; > >+ > >+void test01() > >+{ > >+ typedef CustomPointerAlloc<T> alloc_type; > >+ typedef std::set<T, L, alloc_type> test_type; > >+ test_type v; > >+ v.insert(T()); > >+ VERIFY( ++v.begin() == v.end() ); > >+} > >+ > >+int main() > >+{ > >+ test01(); > >+} >