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 );
 }