forked from boostorg/unordered
		
	
		
			
				
	
	
		
			305 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| // 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 <boost/unordered/detail/table.hpp>
 | |
| #include <boost/unordered/detail/extract_key.hpp>
 | |
| 
 | |
| namespace boost { namespace unordered_detail {
 | |
| 
 | |
|     template <class T>
 | |
|     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 <class... Args>
 | |
|         iterator_base emplace(Args&&... args);
 | |
| 
 | |
| #else
 | |
| 
 | |
| #define BOOST_UNORDERED_INSERT_IMPL(z, n, _)                                   \
 | |
|         template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)>                         \
 | |
|         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 <class I>
 | |
|         void insert_for_range(I i, I j, forward_traversal_tag);
 | |
|         template <class I>
 | |
|         void insert_for_range(I i, I j, boost::incrementable_traversal_tag);
 | |
|         template <class I>
 | |
|         void insert_range(I i, I j);
 | |
|     };
 | |
| 
 | |
|     template <class H, class P, class A>
 | |
|     struct multiset : public types<
 | |
|         BOOST_DEDUCED_TYPENAME A::value_type,
 | |
|         BOOST_DEDUCED_TYPENAME A::value_type,
 | |
|         H, P, A,
 | |
|         set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
 | |
|         grouped>
 | |
|     {
 | |
|         typedef hash_equivalent_table<multiset<H, P, A> > impl;
 | |
|         typedef hash_table<multiset<H, P, A> > table;
 | |
|     };
 | |
| 
 | |
|     template <class K, class H, class P, class A>
 | |
|     struct multimap : public types<
 | |
|         K, BOOST_DEDUCED_TYPENAME A::value_type,
 | |
|         H, P, A,
 | |
|         map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
 | |
|         grouped>
 | |
|     {
 | |
|         typedef hash_equivalent_table<multimap<K, H, P, A> > impl;
 | |
|         typedef hash_table<multimap<K, H, P, A> > table;
 | |
|     };
 | |
| 
 | |
|     ////////////////////////////////////////////////////////////////////////////
 | |
|     // Equality
 | |
| 
 | |
|     template <class T>
 | |
|     bool hash_equivalent_table<T>
 | |
|         ::equals(hash_equivalent_table<T> 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 <class T>
 | |
|     inline BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::node_ptr
 | |
|         hash_equivalent_table<T>
 | |
|             ::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 <class T>
 | |
|     inline BOOST_DEDUCED_TYPENAME
 | |
|         hash_equivalent_table<T>::iterator_base
 | |
|         hash_equivalent_table<T>::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 <class T>
 | |
|     inline void hash_equivalent_table<T>
 | |
|             ::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 <class T>
 | |
|     template <class... Args>
 | |
|     BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base
 | |
|         hash_equivalent_table<T>
 | |
|             ::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>(args)...);
 | |
| 
 | |
|         return emplace_impl(a);
 | |
|     }
 | |
| 
 | |
| #else
 | |
| 
 | |
| #define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _)                       \
 | |
|     template <class T>                                                      \
 | |
|     template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)>                 \
 | |
|     BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base          \
 | |
|         hash_equivalent_table<T>                                            \
 | |
|             ::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 <class T>
 | |
|     template <class I>
 | |
|     inline void hash_equivalent_table<T>
 | |
|         ::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 <class T>
 | |
|     template <class I>
 | |
|     inline void hash_equivalent_table<T>
 | |
|         ::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 <class T>
 | |
|     template <class I>
 | |
|     void hash_equivalent_table<T>::insert_range(I i, I j)
 | |
|     {
 | |
|         BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
 | |
|             iterator_traversal_tag;
 | |
|         insert_for_range(i, j, iterator_traversal_tag);
 | |
|     }
 | |
| }}
 | |
| 
 | |
| #endif
 |