From e9c4696544f11376d7dfe23dcc171d2852b4437c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 27 Apr 2017 18:22:43 +0100 Subject: [PATCH] Get rid of node_algo --- .../boost/unordered/detail/implementation.hpp | 257 ++++++++---------- include/boost/unordered/detail/map.hpp | 2 - include/boost/unordered/detail/set.hpp | 2 - include/boost/unordered/unordered_map.hpp | 24 +- include/boost/unordered/unordered_set.hpp | 14 +- 5 files changed, 124 insertions(+), 175 deletions(-) diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index f92f3ec5..13c549e1 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -175,7 +175,6 @@ struct ptr_bucket; template struct node; template struct ptr_node; -template struct node_algo; static const float minimum_max_load_factor = 1e-3f; static const std::size_t default_bucket_count = 11; @@ -2660,7 +2659,6 @@ struct table : boost::unordered::detail::functions @@ -2701,6 +2699,42 @@ struct table : boost::unordered::detail::functions(n->next_); + } + + static node_pointer next_for_find(link_pointer n) + { + return static_cast(n->next_); + } + + static link_pointer next_for_erase(link_pointer prev) + { + return prev->next_; + } + + node_pointer next_group(node_pointer n) const + { + node_pointer n1 = n; + do { + n1 = next_node(n1); + } while (n1 && this->key_eq()(get_key(n), get_key(n1))); + return n1; + } + + std::size_t group_count(node_pointer n) const + { + std::size_t x = 0; + node_pointer it = n; + do { + ++x; + it = next_node(it); + } while (it && this->key_eq()(get_key(n), get_key(it))); + + return x; + } + bucket_allocator const& bucket_alloc() const { return allocators_.first(); } node_allocator const& node_alloc() const { return allocators_.second(); } @@ -2734,8 +2768,7 @@ struct table : boost::unordered::detail::functionshash_) == index) { ++count; - n = node_algo::next_node(n); + n = next_node(n); } return count; @@ -3235,7 +3268,7 @@ struct table : boost::unordered::detail::functionsnext_) { return link_pointer(); } - std::size_t node_hash = node_algo::next_node(prev)->hash_; + std::size_t node_hash = next_node(prev)->hash_; if (this->hash_to_bucket(node_hash) != bucket_index) { return link_pointer(); } if (node_hash == key_hash && - this->key_eq()(k, this->get_key(node_algo::next_node(prev)))) { + this->key_eq()(k, this->get_key(next_node(prev)))) { return prev; } - prev = node_algo::next_for_erase(prev); + prev = next_for_erase(prev); } } @@ -3277,7 +3310,8 @@ struct table : boost::unordered::detail::functionsnext_ = n->next_; --this->size_; this->fix_bucket(bucket_index, prev); n->next_ = link_pointer(); @@ -3302,8 +3336,7 @@ struct table : boost::unordered::detail::functionssize_ != other.size_) return false; - for (node_pointer n1 = this->begin(); n1; - n1 = node_algo::next_node(n1)) { + for (node_pointer n1 = this->begin(); n1; n1 = next_node(n1)) { node_pointer n2 = other.find_node(other.get_key(n1)); if (!n2 || n1->value() != n2->value()) @@ -3325,8 +3358,8 @@ struct table : boost::unordered::detail::functionsget_previous_start(); if (start_node->next_) { - this->get_bucket(this->hash_to_bucket( - node_algo::next_node(start_node)->hash_)) + this->get_bucket( + this->hash_to_bucket(next_node(start_node)->hash_)) ->next_ = n; } @@ -3551,7 +3584,7 @@ struct table : boost::unordered::detail::functionsnext_) { - node_pointer n = other_table::node_algo::next_node(prev); + node_pointer n = other_table::next_node(prev); const_key_type& k = this->get_key(n); std::size_t key_hash = this->hash(k); node_pointer pos = this->find_node(key_hash, k); @@ -3560,8 +3593,7 @@ struct table : boost::unordered::detail::functionsreserve_for_insert(this->size_ + 1); - other_table::node_algo::split_groups( - n, other_table::node_algo::next_node(n)); + // other_table::split_groups(n, other_table::next_node(n)); prev->next_ = n->next_; --other.size_; other.fix_bucket(other.hash_to_bucket(n->hash_), prev); @@ -3670,7 +3702,7 @@ struct table : boost::unordered::detail::functionsfind_previous_node(k, key_hash, bucket_index); if (!prev) return 0; - link_pointer end = node_algo::next_node(prev)->next_; + link_pointer end = next_node(prev)->next_; this->delete_nodes(prev, end); this->fix_bucket(bucket_index, prev); return 1; @@ -3699,7 +3731,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), @@ -3712,7 +3744,7 @@ struct table : boost::unordered::detail::functionscreate_buckets(this->bucket_count_); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), @@ -3723,7 +3755,7 @@ struct table : boost::unordered::detail::functions holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique(holder.copy_of(n->value()), n->hash_); } } @@ -3731,7 +3763,7 @@ struct table : boost::unordered::detail::functions holder(*this); - for (node_pointer n = src.begin(); n; n = node_algo::next_node(n)) { + for (node_pointer n = src.begin(); n; n = next_node(n)) { this->add_node_unique(holder.move_copy_of(n->value()), n->hash_); } } @@ -3750,8 +3782,8 @@ struct table : boost::unordered::detail::functionsvalue() != n2->value()) break; - n1 = node_algo::next_node(n1); - n2 = node_algo::next_node(n2); + n1 = next_node(n1); + n2 = next_node(n2); if (n1 == end1) return n2 == end2; @@ -3777,8 +3809,8 @@ struct table : boost::unordered::detail::functionsvalue(); if (!find_equiv(start, n1, v)) { std::size_t matches = count_equal_equiv(n2, end2, v); if (!matches) return false; - if (matches != - 1 + count_equal_equiv(node_algo::next_node(n1), end1, v)) + if (matches != 1 + count_equal_equiv(next_node(n1), end1, v)) return false; } } @@ -3810,7 +3841,7 @@ struct table : boost::unordered::detail::functionsvalue() == v) return true; return false; @@ -3820,7 +3851,7 @@ struct table : boost::unordered::detail::functionsvalue() == v) ++count; return count; @@ -3833,10 +3864,11 @@ struct table : boost::unordered::detail::functionshash_ = key_hash; if (pos) { - node_algo::add_to_node(n, pos); + n->next_ = pos->next_; + pos->next_ = n; if (n->next_) { std::size_t next_bucket = - this->hash_to_bucket(node_algo::next_node(n)->hash_); + this->hash_to_bucket(next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(key_hash)) { this->get_bucket(next_bucket)->next_ = n; } @@ -3849,8 +3881,7 @@ struct table : boost::unordered::detail::functionsnext_) { this->get_bucket( - this->hash_to_bucket( - node_algo::next_node(start_node)->hash_)) + this->hash_to_bucket(next_node(start_node)->hash_)) ->next_ = n; } @@ -3869,10 +3900,10 @@ struct table : boost::unordered::detail::functionshash_ = hint->hash_; - node_algo::add_to_node(n, hint); + n->next_ = hint->next_; + hint->next_ = n; if (n->next_ != hint && n->next_) { - std::size_t next_bucket = - this->hash_to_bucket(node_algo::next_node(n)->hash_); + std::size_t next_bucket = this->hash_to_bucket(next_node(n)->hash_); if (next_bucket != this->hash_to_bucket(n->hash_)) { this->get_bucket(next_bucket)->next_ = n; } @@ -4006,21 +4037,19 @@ struct table : boost::unordered::detail::functionshash_to_bucket(i->hash_); // Split the groups containing 'i' and 'j'. // And get the pointer to the node before i while // we're at it. - link_pointer prev = node_algo::split_groups(i, j); + // link_pointer prev = split_groups(i, j); // If we don't have a 'prev' it means that i is at the // beginning of a block, so search through the blocks in the // same bucket. - if (!prev) { - prev = this->get_previous_start(bucket_index); - while (prev->next_ != i) { - prev = node_algo::next_for_erase(prev); - } + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = next_for_erase(prev); } prev->next_ = i->next_; @@ -4047,8 +4076,8 @@ struct table : boost::unordered::detail::functionsdelete_nodes(prev, end); this->fix_bucket(bucket_index, prev); @@ -4062,16 +4091,14 @@ struct table : boost::unordered::detail::functionsget_previous_start(bucket_index); - while (prev->next_ != i) { - prev = node_algo::next_for_erase(prev); - } + link_pointer prev = this->get_previous_start(bucket_index); + while (prev->next_ != i) { + prev = next_for_erase(prev); } // Delete the nodes. @@ -4093,13 +4120,12 @@ struct table : boost::unordered::detail::functionshash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), n->value()), @@ -4114,13 +4140,12 @@ struct table : boost::unordered::detail::functionshash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( boost::unordered::detail::func::construct_node( this->node_alloc(), boost::move(n->value())), @@ -4134,11 +4159,10 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.copy_of(n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv(holder.copy_of(n->value()), key_hash, pos); } } @@ -4149,11 +4173,10 @@ struct table : boost::unordered::detail::functions holder(*this); for (node_pointer n = src.begin(); n;) { std::size_t key_hash = n->hash_; - node_pointer group_end(node_algo::next_group(n, this)); + node_pointer group_end(next_group(n)); node_pointer pos = this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, node_pointer()); - for (n = node_algo::next_node(n); n != group_end; - n = node_algo::next_node(n)) { + for (n = next_node(n); n != group_end; n = next_node(n)) { this->add_node_equiv( holder.move_copy_of(n->value()), key_hash, pos); } @@ -4209,7 +4232,21 @@ inline void table::rehash_impl(std::size_t num_buckets) this->create_buckets(num_buckets); link_pointer prev = this->get_previous_start(); while (prev->next_) { - node_pointer group_last = node_algo::last_for_rehash(prev); + // Group together all nodes with equal hash value, this may + // include nodes with different keys, but that's okay because + // they will end up in the same bucket. + // + // TODO: Don't do this for unique keys? + node_pointer group_last = next_node(prev); + std::size_t hash = group_last->hash_; + for (;;) { + node_pointer next = next_node(group_last); + if (!next || next->hash_ != hash) { + break; + } + group_last = next; + } + bucket_pointer b = this->get_bucket(this->hash_to_bucket(group_last->hash_)); if (!b->next_) { @@ -4419,87 +4456,6 @@ template struct ptr_node : boost::unordered::detail::ptr_bucket ptr_node& operator=(ptr_node const&); }; -template struct node_algo -{ - typedef typename N::node_pointer node_pointer; - typedef typename N::link_pointer link_pointer; - typedef typename N::bucket_pointer bucket_pointer; - - static node_pointer next_node(link_pointer n) - { - return static_cast(n->next_); - } - - static node_pointer next_for_find(node_pointer n) - { - return static_cast(n->next_); - } - - static link_pointer next_for_erase(link_pointer prev) - { - return prev->next_; - } - - // Group together all nodes with equal hash value, this may - // include nodes with different keys, but that's okay because - // they will end up in the same bucket. - static node_pointer last_for_rehash(link_pointer prev) - { - node_pointer n = next_node(prev); - std::size_t hash = n->hash_; - for (;;) { - node_pointer next = next_node(n); - if (!next || next->hash_ != hash) { - return n; - } - n = next; - } - } - - template - static node_pointer next_group(node_pointer n, Table const* t) - { - node_pointer n1 = n; - do { - n1 = next_node(n1); - } while (n1 && t->key_eq()(t->get_key(n), t->get_key(n1))); - return n1; - } - - template - static std::size_t count(node_pointer n, Table const* t) - { - std::size_t x = 0; - node_pointer it = n; - do { - ++x; - it = next_node(it); - } while (it && t->key_eq()(t->get_key(n), t->get_key(it))); - - return x; - } - - // Add node 'n' after 'pos'. - // This results in a different order to the grouped implementation. - static inline void add_to_node(node_pointer n, node_pointer pos) - { - n->next_ = pos->next_; - pos->next_ = n; - } - - static inline node_pointer extract_first_node(link_pointer prev) - { - node_pointer n = next_node(prev); - prev->next_ = n->next_; - return n; - } - - static link_pointer split_groups(node_pointer, node_pointer) - { - return link_pointer(); - } -}; - // If the allocator uses raw pointers use ptr_node // Otherwise use node. @@ -4546,7 +4502,6 @@ template struct pick_node typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef boost::unordered::detail::node_algo node_algo; }; } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 13e223f3..30d8151c 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -27,7 +27,6 @@ template struct map typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; @@ -69,7 +68,6 @@ struct multimap typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::map_extractor extractor; diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index edb98ece..edeeaa86 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -27,7 +27,6 @@ template struct set typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; @@ -68,7 +67,6 @@ template struct multiset typedef typename pick::node node; typedef typename pick::bucket bucket; typedef typename pick::link_pointer link_pointer; - typedef typename pick::node_algo node_algo; typedef boost::unordered::detail::table table; typedef boost::unordered::detail::set_extractor extractor; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index ab20642c..b268cb19 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -1569,7 +1569,7 @@ unordered_map::erase(iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1580,7 +1580,7 @@ unordered_map::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1723,8 +1723,7 @@ std::pair::iterator, unordered_map::equal_range(const key_type& k) { node_pointer n = table_.find_node(k); - return std::make_pair( - iterator(n), iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair(iterator(n), iterator(n ? table::next_node(n) : n)); } template @@ -1733,8 +1732,8 @@ std::pair::const_iterator, unordered_map::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table::next_node(n) : n)); } template @@ -2054,7 +2053,7 @@ unordered_multimap::erase(iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2065,7 +2064,7 @@ unordered_multimap::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -2209,7 +2208,7 @@ typename unordered_multimap::size_type unordered_multimap::count(const key_type& k) const { node_pointer n = table_.find_node(k); - return n ? table::node_algo::count(n, &table_) : 0; + return n ? table_.group_count(n) : 0; } template @@ -2218,8 +2217,7 @@ std::pair::iterator, unordered_multimap::equal_range(const key_type& k) { node_pointer n = table_.find_node(k); - return std::make_pair(iterator(n), - iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair(iterator(n), iterator(n ? table_.next_group(n) : n)); } template @@ -2228,8 +2226,8 @@ std::pair::const_iterator, unordered_multimap::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table_.next_group(n) : n)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 674d4e67..b5775a77 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1242,7 +1242,7 @@ typename unordered_set::iterator unordered_set::erase( { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_unique(node, next); return iterator(next); } @@ -1368,8 +1368,8 @@ std::pair::const_iterator, unordered_set::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_node(n) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table::next_node(n) : n)); } template @@ -1646,7 +1646,7 @@ unordered_multiset::erase(const_iterator position) { node_pointer node = table::get_node(position); BOOST_ASSERT(node); - node_pointer next = table::node_algo::next_node(node); + node_pointer next = table::next_node(node); table_.erase_nodes_equiv(node, next); return iterator(next); } @@ -1772,7 +1772,7 @@ typename unordered_multiset::size_type unordered_multiset::count(const key_type& k) const { node_pointer n = table_.find_node(k); - return n ? table::node_algo::count(n, &table_) : 0; + return n ? table_.group_count(n) : 0; } template @@ -1781,8 +1781,8 @@ std::pair::const_iterator, unordered_multiset::equal_range(const key_type& k) const { node_pointer n = table_.find_node(k); - return std::make_pair(const_iterator(n), - const_iterator(n ? table::node_algo::next_group(n, &table_) : n)); + return std::make_pair( + const_iterator(n), const_iterator(n ? table_.next_group(n) : n)); } template