void clear() { // Call the destructor for all objects and reinitialize the memory. _Destroy( begin(), end() ); initialize_memory(); m_num_elements = 0; }
value_type& find_or_insert( const key_type& key ) { size_t buck = m_hasher( key ) & m_mask; key_type& table_key = m_key_extract( m_table[ buck ] ); if ( ! m_key_equal( key, table_key ) ) { // The bucket is either empty or it contains another item. In // this case we have to mark it as discarded, because we cannot // know how the reference will be used ( probably to overwrite // the item with a new one that has a different key ). if ( ! m_key_equal( table_key, m_empty_key ) ) { // The bucket already contained an item. This item is // discarded and replaced with an empty one. The destructor // is called on it. // The m_num_elements does not change because m_discard( m_table[ buck ], m_empty_value ); _Destroy( m_table + buck ); reset_value( m_table + buck ); } else { // The bucket was empty, so we have to increment the items // counter ++m_num_elements; } // Set the key in the empty item _Construct( &table_key, key ); } // Returns the reference to the found or recently added item return m_table[ buck ]; }
pair<iterator,bool> insert( const value_type& obj ) { const key_type& obj_key = m_key_extract( obj ); const size_t buck = m_hasher( obj_key ) & m_mask; const key_type& table_key = m_key_extract( m_table[ buck ] ); if ( ! m_key_equal( table_key, m_empty_key ) ) { // There's already an item in the bucket and its key it different // from the key of the inserted item. Element is discarded. ++m_num_collisions; // Notify that the item will be discarded, to allow a policy to // do something useful with it. m_discard( m_table[ buck ], obj ); _Destroy( m_table + buck ); reset_value( m_table + buck ); } else ++m_num_elements; // Copy the object into the hash table. _Construct( m_table + buck, obj ); return pair<iterator,bool>( iterator( this, m_table + buck ), true ); }
void erase( const iterator& it ) { if ( it != m_end_it && ! m_key_equal( m_key_extract( *it ), m_empty_key ) ) { _Destroy( &* it ); reset_value( it.m_pos ); --m_num_elements; } }
void resize( size_type size ) { size_t new_size = round_to_power2( size ); size_t old_size = m_buckets; if ( new_size == old_size ) { // Do nothing return; } else if ( new_size < old_size ) { // The new table will be smaller, so there's no need to rehash // all the items. value_type* new_table; new_table = m_allocator.allocate( new_size * ItemSize ); // Copy the elements that fit into the new table and destroy // those that doesn't fit. Plain old memcpy seems to have much // less problems with types than std::copy.. std::memcpy( new_table, m_table, new_size * ItemSize ); _Destroy( iterator( this, m_table + new_size, true ), m_end_it ); m_allocator.deallocate( m_table, old_size ); m_table = new_table; m_end_marker = m_table + new_size; m_end_it = iterator( this, m_end_marker ); m_buckets = new_size; m_mask = m_buckets - 1; // Re-count the number of elements. m_num_elements = 0; for ( const_iterator it = begin(); it != m_end_it; ++it ) ++m_num_elements; } else // new_size > old_size { // Creates a new table and re-insert all the items, with // new buckets. cache_table other( new_size, m_hasher, m_key_equal ); other.set_empty_value( m_empty_value ); swap( other ); insert( other.begin(), other.end() ); } }
void erase( iterator first, iterator last ) { m_num_elements -= mm::distance( first, last ); _Destroy( first, last ); std::uninitialized_fill( first, last, m_empty_value ); }