Re: [PATCH] Implement C++17 node extraction and insertion (P0083R5)
On 21/09/16 14:48 +0100, Jonathan Wakely wrote: This implements container node extraction/insertion, and merging. The patch includes Debug Mode support and pretty printers for the node handles. Most of the changes are fairly straightforward, with two things worth pointing out. There's a FIXME in bits/hashtable.h due to an exception-safety issue. If the hash function or equality predicate throws then the node is destroyed and deallocated. It would be better to leave it unchanged in the node_handle argument. I didn't want to make all map and multimap specializations friends of each other (and similarly for all sets and multisets, and again for the unordered ones). That would make it too easy to accidentally access the internals of a map from a map. So I defined the _Rb_tree_merge_helper and _Hash_merge_helper class templates to mediate access, so that any access to a "foreign" container type must be done through that type, and only certain internals can be obtained. I forgot to mention another thing worth calling out. I spoke to Richi and Michael Matz at the Cauldron and they assured me that the middle end won't do any optimizations that would cause the "magic happens here" part to do the wrong thing. Specifically, the node handle for maps does this to get a non-const pointer to the key_type in the pair: auto& __key = const_cast<_Key&>(__ptr->_M_valptr()->first); _M_pkey = _S_pointer_to(__key); _M_pmapped = _S_pointer_to(__ptr->_M_valptr()->second); Where _S_pointer_to() is: template using __pointer = __ptr_rebind; template __pointer<_Tp> _S_pointer_to(_Tp& __obj) { return pointer_traits<__pointer<_Tp>>::pointer_to(__obj); } The potentially worrying part of this is the const_cast, but as we know that the pair is inside a non-const node allocated on the heap, it will never be in read-only memory or actually non-modifiable. Once we have std::launder we could consider using that, i.e. _M_pkey = _S_pointer_to(std::launder(__key));
Re: [PATCH] Implement C++17 node extraction and insertion (P0083R5)
On 21/09/16 14:48 +0100, Jonathan Wakely wrote: This implements container node extraction/insertion, and merging. The patch includes Debug Mode support and pretty printers for the node handles. This adds some assertions to check for the mistake of trying to extract the end iterator. Tested powerpc64le-linux, comitted to trunk. commit 1073944c341d022d501c07b7881e7c6ead0b1fca Author: Jonathan Wakely Date: Mon Sep 26 10:35:52 2016 +0100 Add assertions to extract(const_iterator) functions * include/bits/stl_map.h (map::extract(const_iterator)): Assert that iterator is not past-the-end. * include/bits/stl_multimap.h (multimap::extract(const_iterator)): Likewise. * include/bits/stl_multiset.h (multiset::extract(const_iterator)): Likewise. * include/bits/stl_set.h (set::extract(const_iterator)): Likewise. * include/bits/unordered_map.h (unordered_map::extract(const_iterator)) (unordered_multimap::extract(const_iterator)): Likewise. * include/bits/unordered_set.h (unordered_set::extract(const_iterator)) (unordered_multiset::extract(const_iterator)): Likewise. diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h index f9482e2..9a0454a 100644 --- a/libstdc++-v3/include/bits/stl_map.h +++ b/libstdc++-v3/include/bits/stl_map.h @@ -605,7 +605,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_t.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_t.extract(__pos); + } /// Extract a node. node_type diff --git a/libstdc++-v3/include/bits/stl_multimap.h b/libstdc++-v3/include/bits/stl_multimap.h index 2b56824..c794b9b 100644 --- a/libstdc++-v3/include/bits/stl_multimap.h +++ b/libstdc++-v3/include/bits/stl_multimap.h @@ -606,7 +606,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_t.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_t.extract(__pos); + } /// Extract a node. node_type diff --git a/libstdc++-v3/include/bits/stl_multiset.h b/libstdc++-v3/include/bits/stl_multiset.h index d7312df..d3219eb 100644 --- a/libstdc++-v3/include/bits/stl_multiset.h +++ b/libstdc++-v3/include/bits/stl_multiset.h @@ -549,7 +549,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_t.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_t.extract(__pos); + } /// Extract a node. node_type diff --git a/libstdc++-v3/include/bits/stl_set.h b/libstdc++-v3/include/bits/stl_set.h index fd96dd4..140db39 100644 --- a/libstdc++-v3/include/bits/stl_set.h +++ b/libstdc++-v3/include/bits/stl_set.h @@ -565,7 +565,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_t.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_t.extract(__pos); + } /// Extract a node. node_type diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h index ab8a762..6776090 100644 --- a/libstdc++-v3/include/bits/unordered_map.h +++ b/libstdc++-v3/include/bits/unordered_map.h @@ -421,7 +421,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_h.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_h.extract(__pos); + } /// Extract a node. node_type @@ -1534,7 +1537,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_h.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_h.extract(__pos); + } /// Extract a node. node_type diff --git a/libstdc++-v3/include/bits/unordered_set.h b/libstdc++-v3/include/bits/unordered_set.h index e5bb2be..9905257 100644 --- a/libstdc++-v3/include/bits/unordered_set.h +++ b/libstdc++-v3/include/bits/unordered_set.h @@ -482,7 +482,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_h.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_h.extract(__pos); + } /// Extract a node. node_type @@ -1190,7 +1193,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// Extract a node. node_type extract(const_iterator __pos) - { return _M_h.extract(__pos); } + { + __glibcxx_assert(__pos != end()); + return _M_h.extract(__pos); + } /// Extract a node. node_type
Re: [PATCH] Implement C++17 node extraction and insertion (P0083R5)
This mail got rejected from gcc-patches as spam. The attachment can be found at https://gcc.gnu.org/ml/libstdc++/2016-09/msg00115.html On 21/09/16 14:48 +0100, Jonathan Wakely wrote: This implements container node extraction/insertion, and merging. The patch includes Debug Mode support and pretty printers for the node handles. Most of the changes are fairly straightforward, with two things worth pointing out. There's a FIXME in bits/hashtable.h due to an exception-safety issue. If the hash function or equality predicate throws then the node is destroyed and deallocated. It would be better to leave it unchanged in the node_handle argument. I didn't want to make all map and multimap specializations friends of each other (and similarly for all sets and multisets, and again for the unordered ones). That would make it too easy to accidentally access the internals of a map from a map. So I defined the _Rb_tree_merge_helper and _Hash_merge_helper class templates to mediate access, so that any access to a "foreign" container type must be done through that type, and only certain internals can be obtained. I'll probably commit this tomorrow. * doc/xml/manual/status_cxx2017.xml: Document status. * doc/html/*: Regenerate. * include/Makefile.am: Add bits/node_handle.h and reorder. * include/Makefile.in: Regenerate. * include/bits/hashtable.h (_Hashtable::node_type) (_Hashtable::insert_return_type, _Hashtable::_M_reinsert_node) (_Hashtable::_M_reinsert_node_multi, _Hashtable::extract) (_Hashtable::_M_merge_unique, _Hashtable::_M_merge_multi): Define. (_Hash_merge_helper): Define primary template. * include/bits/node_handle.h: New header. * include/bits/stl_map.h (map): Declare _Rb_tree_merge_helper as friend. (map::node_type, map::insert_return_type, map::extract, map::merge) (map::insert(node_type&&), map::insert(const_iterator, node_type&&)): Define new members. (_Rb_tree_merge_helper): Specialize for map. * include/bits/stl_multimap.h (multimap): Declare _Rb_tree_merge_helper as friend. (multimap::node_type, multimap::extract, multimap::merge) (multimap::insert(node_type&&)) (multimap::insert(const_iterator, node_type&&)): Define. (_Rb_tree_merge_helper): Specialize for multimap. * include/bits/stl_multiset.h (multiset): Declare _Rb_tree_merge_helper as friend. (multiset::node_type, multiset::extract, multiset::merge) (multiset::insert(node_type&&)) (multiset::insert(const_iterator, node_type&&)): Define. * include/bits/stl_set.h (set): Declare _Rb_tree_merge_helper as friend. (set::node_type, set::insert_return_type, set::extract, set::merge) (set::insert(node_type&&), set::insert(const_iterator, node_type&&)): Define. (_Rb_tree_merge_helper): Specialize for set. * include/bits/stl_tree.h (_Rb_tree): Declare _Rb_tree<> as friend. (_Rb_tree::node_type, _Rb_tree::insert_return_type) (_Rb_tree::_M_reinsert_node_unique, _Rb_tree::_M_reinsert_node_equal) (_Rb_tree::_M_reinsert_node_hint_unique) (_Rb_tree::_M_reinsert_node_hint_equal, _Rb_tree::extract) (_Rb_tree::_M_merge_unique, _Rb_tree::_M_merge_equal): Define. (_Rb_tree_merge_helper): Specialize for multiset. * include/bits/unordered_map.h (unordered_map): Declare unordered_map<> and unordered_multimap<> as friends. (unordered_map::node_type, unordered_map::insert_return_type) (unordered_map::extract, unordered_map::merge) (unordered_map::insert(node_type&&)) (unordered_map::insert(const_iterator, node_type&&)) (unordered_multimap): Declare _Hash_merge_helper as friend. (unordered_multimap::node_type, unordered_multimap::extract) (unordered_multimap::merge, unordered_multimap::insert(node_type&&)) (unordered_multimap::insert(const_iterator, node_type&&)): Define. (_Hash_merge_helper): Specialize for unordered maps and multimaps. * include/bits/unordered_set.h (unordered_set, unordered_multiset): Declare _Hash_merge_helper as friend. (unordered_set::node_type, unordered_set::insert_return_type) (unordered_set::extract, unordered_set::merge) (unordered_set::insert(node_type&&)) (unordered_set::insert(const_iterator, node_type&&)): Define. (unordered_multiset::node_type, unordered_multiset::extract) (unordered_multiset::merge, unordered_multiset::insert(node_type&&)) (unordered_multiset::insert(const_iterator, node_type&&)): Define. (_Hash_merge_helper): Specialize for unordered sets and multisets. * include/debug/map.h (map): Add using declarations or forwarding functions for new members. * include/debug/map.h (multimap): Likewise. * include/debug/ma