// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2005-2009 Daniel James // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED #include #include namespace boost { namespace unordered_detail { template class hash_equivalent_table : public T::table { public: typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; typedef BOOST_DEDUCED_TYPENAME T::table table; typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; typedef BOOST_DEDUCED_TYPENAME T::node node; typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base; typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; // Constructors hash_equivalent_table(std::size_t n, hasher const& hf, key_equal const& eq, value_allocator const& a) : table(n, hf, eq, a) {} hash_equivalent_table(hash_equivalent_table const& x) : table(x, x.node_alloc()) {} hash_equivalent_table(hash_equivalent_table const& x, value_allocator const& a) : table(x, a) {} hash_equivalent_table(hash_equivalent_table& x, move_tag m) : table(x, m) {} hash_equivalent_table(hash_equivalent_table& x, value_allocator const& a, move_tag m) : table(x, a, m) {} ~hash_equivalent_table() {} // Insert methods iterator_base emplace_impl(node_constructor& a); void emplace_impl_no_rehash(node_constructor& a); // equals bool equals(hash_equivalent_table const&) const; inline node_ptr add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos); #if defined(BOOST_UNORDERED_STD_FORWARD) template iterator_base emplace(Args&&... args); #else #define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ template \ iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_INSERT_IMPL, _) #undef BOOST_UNORDERED_INSERT_IMPL #endif template void insert_for_range(I i, I j, forward_traversal_tag); template void insert_for_range(I i, I j, boost::incrementable_traversal_tag); template void insert_range(I i, I j); }; template struct multiset : public types< BOOST_DEDUCED_TYPENAME A::value_type, BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, set_extractor, grouped> { typedef hash_equivalent_table > impl; typedef hash_table > table; }; template struct multimap : public types< K, BOOST_DEDUCED_TYPENAME A::value_type, H, P, A, map_extractor, grouped> { typedef hash_equivalent_table > impl; typedef hash_table > table; }; //////////////////////////////////////////////////////////////////////////// // Equality template bool hash_equivalent_table ::equals(hash_equivalent_table 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; node_ptr end1 = node::next_group(it1); node_ptr end2 = node::next_group(it2); do { if(!extractor::compare_mapped( node::get_value(it1), node::get_value(it2))) return false; it1 = it1->next_; it2 = it2->next_; } while(it1 != end1 && it2 != end2); if(it1 != end1 || it2 != end2) return false; } } return true; } //////////////////////////////////////////////////////////////////////////// // A convenience method for adding nodes. template inline BOOST_DEDUCED_TYPENAME hash_equivalent_table::node_ptr hash_equivalent_table ::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos) { node_ptr n = a.release(); if(BOOST_UNORDERED_BORLAND_BOOL(pos)) { node::add_after_node(n, pos); } else { node::add_to_bucket(n, *bucket); if(bucket < this->cached_begin_bucket_) this->cached_begin_bucket_ = bucket; } ++this->size_; return n; } //////////////////////////////////////////////////////////////////////////// // Insert methods template inline BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base hash_equivalent_table::emplace_impl(node_constructor& a) { key_type const& k = this->get_key(a.value()); std::size_t hash_value = this->hash_function()(k); if(!this->size_) { return this->emplace_empty_impl_with_node(a, 1); } else { bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value); node_ptr position = this->find_iterator(bucket, k); // 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); return iterator_base(bucket, add_node(a, bucket, position)); } } template inline void hash_equivalent_table ::emplace_impl_no_rehash(node_constructor& a) { key_type const& k = this->get_key(a.value()); bucket_ptr bucket = this->get_bucket(this->bucket_index(k)); add_node(a, bucket, this->find_iterator(bucket, k)); } #if defined(BOOST_UNORDERED_STD_FORWARD) // Emplace (equivalent key containers) // (I'm using an overloaded emplace for both 'insert' and 'emplace') // if hash function throws, basic exception safety // strong otherwise template template BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base hash_equivalent_table ::emplace(Args&&... args) { // 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)...); return emplace_impl(a); } #else #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \ template \ template \ BOOST_DEDUCED_TYPENAME hash_equivalent_table::iterator_base \ hash_equivalent_table \ ::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ node_constructor a(*this); \ a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ return emplace_impl(a); \ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_INSERT_IMPL, _) #undef BOOST_UNORDERED_INSERT_IMPL #endif //////////////////////////////////////////////////////////////////////////// // Insert range methods // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise template template inline void hash_equivalent_table ::insert_for_range(I i, I j, forward_traversal_tag) { if(i == j) return; std::size_t distance = unordered_detail::distance(i, j); if(distance == 1) { emplace(*i); } else { node_constructor a(*this); // Only require basic exception safety here if(this->size_) { this->reserve_for_insert(this->size_ + distance); } else { a.construct(*i++); this->emplace_empty_impl_with_node(a, distance); } for (; i != j; ++i) { a.construct(*i); emplace_impl_no_rehash(a); } } } // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise template template inline void hash_equivalent_table ::insert_for_range(I i, I j, boost::incrementable_traversal_tag) { node_constructor a(*this); for (; i != j; ++i) { a.construct(*i); emplace_impl(a); } } // if hash function throws, or inserting > 1 element, basic exception safety // strong otherwise template template void hash_equivalent_table::insert_range(I i, I j) { BOOST_DEDUCED_TYPENAME boost::iterator_traversal::type iterator_traversal_tag; insert_for_range(i, j, iterator_traversal_tag); } }} #endif