void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) { node_ptr* pos = &next_group(begin); if(*pos != begin) { // The node is at the beginning of a group. // Find the previous node pointer: pos = &b.next_; while(*pos != begin) pos = &next_group(*pos); // Remove from group if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end); } else { node_ptr group1 = split_group(begin); if(BOOST_UNORDERED_BORLAND_BOOL(end)) { node_ptr group2 = split_group(end); if(begin == group2) { node_ptr end1 = get(group1).group_prev_; node_ptr end2 = get(group2).group_prev_; get(group1).group_prev_ = end2; get(group2).group_prev_ = end1; } } } *pos = end; }
inline BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return hash_unique_table<H, P, A, K>::emplace_impl(key_type const& k, Args&&... args) { // No side effects in this initial code std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); node_ptr pos = this->find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Found an existing key, return it (no throw). return emplace_return(iterator_base(bucket, pos), false); } else { // Doesn't already exist, add to bucket. // Side effects only in this block. // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). node_constructor a(*this); a.construct(std::forward<Args>(args)...); // reserve has basic exception safety if the hash function // throws, strong otherwise. if(this->reserve_for_insert(this->size_ + 1)) bucket = this->bucket_ptr_from_hash(hash_value); // Nothing after this point can throw. return emplace_return( iterator_base(bucket, add_node(a, bucket)), true); } }
inline BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::emplace_return hash_unique_table<H, P, A, K>::emplace_impl_with_node(node_constructor& a) { // No side effects in this initial code key_type const& k = this->get_key(a.value()); std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); node_ptr pos = this->find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Found an existing key, return it (no throw). return emplace_return(iterator_base(bucket, pos), false); } else { // reserve has basic exception safety if the hash function // throws, strong otherwise. if(this->reserve_for_insert(this->size_ + 1)) bucket = this->bucket_ptr_from_hash(hash_value); // Nothing after this point can throw. return emplace_return( iterator_base(bucket, add_node(a, bucket)), true); } }
inline node_ptr add_node( node_constructor& a, std::size_t bucket_index, std::size_t hash, node_ptr pos) { node_ptr n = a.release(); node::set_hash(n, hash); if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { node::add_after_node(n, pos); if (n->next_) { std::size_t next_bucket = node::get_hash(n->next_) % this->bucket_count_; if (next_bucket != bucket_index) { this->buckets_[next_bucket].next_ = n; } } } else { bucket_ptr b = this->get_bucket(bucket_index); if (!b->next_) { bucket_ptr start_node = this->get_bucket(this->bucket_count_); if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) { this->buckets_[ node::get_hash(start_node->next_) % this->bucket_count_].next_ = n; } b->next_ = start_node; n->next_ = start_node->next_; start_node->next_ = n; } else { n->next_ = b->next_->next_; b->next_->next_ = n; } } ++this->size_; return n; }
void grouped_node_base<A>::unlink_node(bucket& b, node_ptr n) { node_ptr next = n->next_; node_ptr* pos = &next_group(n); if(*pos != n) { // The node is at the beginning of a group. // Find the previous node pointer: pos = &b.next_; while(*pos != n) pos = &next_group(*pos); // Remove from group if(BOOST_UNORDERED_BORLAND_BOOL(next) && get(next).group_prev_ == n) { get(next).group_prev_ = get(n).group_prev_; } } else if(BOOST_UNORDERED_BORLAND_BOOL(next) && get(next).group_prev_ == n) { // The deleted node is not at the end of the group, so // change the link from the next node. get(next).group_prev_ = get(n).group_prev_; } else { // The deleted node is at the end of the group, so the // first node in the group is pointing to it. // Find that to change its pointer. node_ptr x = get(n).group_prev_; while(get(x).group_prev_ != n) { x = get(x).group_prev_; } get(x).group_prev_ = get(n).group_prev_; } *pos = next; }
bool hash_unique_table<H, P, A, K> ::equals(hash_unique_table<H, P, A, K> const& other) const { if(this->size_ != other.size_) return false; if(!this->size_) return true; bucket_ptr end = this->get_bucket(this->bucket_count_); for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i) { node_ptr it1 = i->next_; while(BOOST_UNORDERED_BORLAND_BOOL(it1)) { node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1)); if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false; if(!extractor::compare_mapped( node::get_value(it1), node::get_value(it2))) return false; it1 = it1->next_; } } return true; }
inline void hash_unique_table<H, P, A, K>::insert_range_impl( key_type const&, InputIt i, InputIt j) { node_constructor a(*this); if(!this->size_) { a.construct(*i); this->emplace_empty_impl_with_node(a, 1); ++i; if(i == j) return; } do { // No side effects in this initial code // Note: can't use get_key as '*i' might not be value_type - it could // be a pair with first_types as key_type without const or a // different second_type. key_type const& k = extractor::extract(*i); std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); node_ptr pos = this->find_iterator(bucket, k); if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Doesn't already exist, add to bucket. // Side effects only in this block. // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). a.construct(*i); // reserve has basic exception safety if the hash function // throws, strong otherwise. if(this->size_ + 1 >= this->max_load_) { this->reserve_for_insert(this->size_ + insert_size(i, j)); bucket = this->bucket_ptr_from_hash(hash_value); } // Nothing after this point can throw. add_node(a, bucket); } } while(++i != j); }
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::value_type& hash_unique_table<H, P, A, K>::operator[](key_type const& k) { typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; std::size_t hash_value = this->hash_function()(k); bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); if(!this->buckets_) { node_constructor a(*this); a.construct_pair(k, (mapped_type*) 0); return *this->emplace_empty_impl_with_node(a, 1); } node_ptr pos = this->find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { return node::get_value(pos); } else { // Side effects only in this block. // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). node_constructor a(*this); a.construct_pair(k, (mapped_type*) 0); // reserve has basic exception safety if the hash function // throws, strong otherwise. if(this->reserve_for_insert(this->size_ + 1)) bucket = this->bucket_ptr_from_hash(hash_value); // Nothing after this point can throw. return node::get_value(add_node(a, bucket)); } }