Beispiel #1
0
  /**
   * Associate the specified value with the specified key in this {@code Hashtable}. If the key
   * already exists, the old value is replaced. The key and value cannot be null.
   *
   * @param key the key to add.
   * @param value the value to add.
   * @return the old value associated with the specified key, or {@code null} if the key did not
   *     exist.
   * @see #elements
   * @see #get
   * @see #keys
   * @see java.lang.Object#equals
   */
  public synchronized V put(K key, V value) {
    if (key == null) {
      throw new NullPointerException("key == null");
    } else if (value == null) {
      throw new NullPointerException("value == null");
    }
    int hash = secondaryHash(key.hashCode());
    HashtableEntry<K, V>[] tab = table;
    int index = hash & (tab.length - 1);
    HashtableEntry<K, V> first = tab[index];
    for (HashtableEntry<K, V> e = first; e != null; e = e.next) {
      if (e.hash == hash && key.equals(e.key)) {
        V oldValue = e.value;
        e.value = value;
        return oldValue;
      }
    }

    // No entry for key is present; create one
    modCount++;
    if (size++ > threshold) {
      rehash(); // Does nothing!!
      tab = doubleCapacity();
      index = hash & (tab.length - 1);
      first = tab[index];
    }
    tab[index] = new HashtableEntry<K, V>(key, value, hash, first);
    return null;
  }
Beispiel #2
0
  /**
   * Ensures that the hash table has sufficient capacity to store the specified number of mappings,
   * with room to grow. If not, it increases the capacity as appropriate. Like doubleCapacity, this
   * method moves existing entries to new buckets as appropriate. Unlike doubleCapacity, this method
   * can grow the table by factors of 2^n for n > 1. Hopefully, a single call to this method will be
   * faster than multiple calls to doubleCapacity.
   *
   * <p>This method is called only by putAll.
   */
  private void ensureCapacity(int numMappings) {
    int newCapacity = roundUpToPowerOfTwo(capacityForInitSize(numMappings));
    HashtableEntry<K, V>[] oldTable = table;
    int oldCapacity = oldTable.length;
    if (newCapacity <= oldCapacity) {
      return;
    }

    rehash(); // Does nothing!!

    if (newCapacity == oldCapacity * 2) {
      doubleCapacity();
      return;
    }

    // We're growing by at least 4x, rehash in the obvious way
    HashtableEntry<K, V>[] newTable = makeTable(newCapacity);
    if (size != 0) {
      int newMask = newCapacity - 1;
      for (int i = 0; i < oldCapacity; i++) {
        for (HashtableEntry<K, V> e = oldTable[i]; e != null; ) {
          HashtableEntry<K, V> oldNext = e.next;
          int newIndex = e.hash & newMask;
          HashtableEntry<K, V> newNext = newTable[newIndex];
          newTable[newIndex] = e;
          e.next = newNext;
          e = oldNext;
        }
      }
    }
  }
Beispiel #3
0
  /**
   * Maps the specified <code>key</code> to the specified <code>value</code> in this hashtable.
   * Neither the key nor the value can be <code>null</code>.
   *
   * <p>The value can be retrieved by calling the <code>get</code> method with a key that is equal
   * to the original key.
   *
   * @param key the hashtable key.
   * @param value the value.
   * @return the previous value of the specified key in this hashtable, or <code>null</code> if it
   *     did not have one.
   * @exception NullPointerException if the key or value is <code>null</code>.
   * @see java.lang.Object#equals(java.lang.Object)
   * @see java.util.Hashtable#get(java.lang.Object)
   * @since JDK1.0
   */
  public Object put(Object key, Object value) {
    // Make sure the value is not null
    if (value == null) {
      throw new NullPointerException();
    }

    // Makes sure the key is not already in the hashtable.
    HashtableEntry tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    for (HashtableEntry e = tab[index]; e != null; e = e.next) {
      if ((e.hash == hash) && e.key.equals(key)) {
        Object old = e.value;
        e.value = value;
        return old;
      }
    }

    if (count >= threshold) {
      // Rehash the table if the threshold is exceeded
      rehash();
      return put(key, value);
    }

    // Creates the new entry.
    HashtableEntry e = new HashtableEntry();
    e.hash = hash;
    e.key = key;
    e.value = value;
    e.next = tab[index];
    tab[index] = e;
    count++;
    return null;
  }
Beispiel #4
0
 /**
  * Removes the key (and its corresponding value) from this hashtable. This method does nothing if
  * the key is not in the hashtable.
  *
  * @param key the key that needs to be removed.
  * @return the value to which the key had been mapped in this hashtable, or <code>null</code> if
  *     the key did not have a mapping.
  * @since JDK1.0
  */
 public Object remove(Object key) {
   HashtableEntry tab[] = table;
   int hash = key.hashCode();
   int index = (hash & 0x7FFFFFFF) % tab.length;
   // this loop was reviewed - code is approved!
   for (HashtableEntry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
     if ((e.hash == hash) && e.key.equals(key)) {
       if (prev != null) {
         prev.next = e.next;
       } else {
         tab[index] = e.next;
       }
       count--;
       return e.value;
     }
   }
   return null;
 }
Beispiel #5
0
 /**
  * Removes the key/value pair with the specified key from this {@code Hashtable}.
  *
  * @param key the key to remove.
  * @return the value associated with the specified key, or {@code null} if the specified key did
  *     not exist.
  * @see #get
  * @see #put
  */
 public synchronized V remove(Object key) {
   int hash = secondaryHash(key.hashCode());
   HashtableEntry<K, V>[] tab = table;
   int index = hash & (tab.length - 1);
   for (HashtableEntry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) {
     if (e.hash == hash && key.equals(e.key)) {
       if (prev == null) {
         tab[index] = e.next;
       } else {
         prev.next = e.next;
       }
       modCount++;
       size--;
       return e.value;
     }
   }
   return null;
 }
Beispiel #6
0
  protected void rehash() {
    int oldCapacity = table.length;
    HashtableEntry oldTable[] = table;

    int newCapacity = oldCapacity * 2 + 1;
    HashtableEntry newTable[] = new HashtableEntry[newCapacity];

    threshold = (int) (newCapacity * loadFactor);
    table = newTable;

    for (int i = oldCapacity; i-- > 0; ) {
      for (HashtableEntry old = oldTable[i]; old != null; ) {
        HashtableEntry e = old;
        old = old.next;
        int index = (e.hash & 0x7FFFFFFF) % newCapacity;
        e.next = newTable[index];
        newTable[index] = e;
      }
    }
  }
Beispiel #7
0
 /**
  * Removes the mapping from key to value and returns true if this mapping exists; otherwise,
  * returns does nothing and returns false.
  */
 private synchronized boolean removeMapping(Object key, Object value) {
   int hash = secondaryHash(key.hashCode());
   HashtableEntry<K, V>[] tab = table;
   int index = hash & (tab.length - 1);
   for (HashtableEntry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) {
     if (e.hash == hash && e.key.equals(key)) {
       if (!e.value.equals(value)) {
         return false; // Map has wrong value for key
       }
       if (prev == null) {
         tab[index] = e.next;
       } else {
         prev.next = e.next;
       }
       modCount++;
       size--;
       return true;
     }
   }
   return false; // No entry for key
 }
Beispiel #8
0
  /**
   * This method is just like put, except that it doesn't do things that are inappropriate or
   * unnecessary for constructors and pseudo-constructors (i.e., clone, readObject). In particular,
   * this method does not check to ensure that capacity is sufficient, and does not increment
   * modCount.
   */
  private void constructorPut(K key, V value) {
    if (key == null) {
      throw new NullPointerException("key == null");
    } else if (value == null) {
      throw new NullPointerException("value == null");
    }
    int hash = secondaryHash(key.hashCode());
    HashtableEntry<K, V>[] tab = table;
    int index = hash & (tab.length - 1);
    HashtableEntry<K, V> first = tab[index];
    for (HashtableEntry<K, V> e = first; e != null; e = e.next) {
      if (e.hash == hash && key.equals(e.key)) {
        e.value = value;
        return;
      }
    }

    // No entry for key is present; create one
    tab[index] = new HashtableEntry<K, V>(key, value, hash, first);
    size++;
  }
Beispiel #9
0
 protected Object clone() {
   HashtableEntry entry = new HashtableEntry();
   entry.hash = hash;
   entry.key = key;
   entry.value = value;
   entry.next = (next != null) ? (HashtableEntry) next.clone() : null;
   return entry;
 }
Beispiel #10
0
  /**
   * Removes the key and its corresponding value. Key is searched case insensitively.
   *
   * @param key string key
   * @return object removed or null if none
   * @exception IllegalArgumentException if key is not s string
   */
  public synchronized Object remove(Object key) throws IllegalArgumentException {

    if (table == null) return null;
    try {
      HashtableEntry tab[] = table;
      int hash = hashCode((String) key);
      int index = (hash & 0x7FFFFFFF) % tab.length;
      for (HashtableEntry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
        if ((e.hash == hash) && e.key.equalsIgnoreCase((String) key)) {
          if (prev != null) {
            prev.next = e.next;
          } else {
            tab[index] = e.next;
          }
          count--;
          return e.value;
        }
      }
      return null;
    } catch (ClassCastException cce) {
      throw new IllegalArgumentException("Non string keys are not accepted!");
    }
  }
Beispiel #11
0
  /**
   * Doubles the capacity of the hash table. Existing entries are placed in the correct bucket on
   * the enlarged table. If the current capacity is, MAXIMUM_CAPACITY, this method is a no-op.
   * Returns the table, which will be new unless we were already at MAXIMUM_CAPACITY.
   */
  private HashtableEntry<K, V>[] doubleCapacity() {
    HashtableEntry<K, V>[] oldTable = table;
    int oldCapacity = oldTable.length;
    if (oldCapacity == MAXIMUM_CAPACITY) {
      return oldTable;
    }
    int newCapacity = oldCapacity * 2;
    HashtableEntry<K, V>[] newTable = makeTable(newCapacity);
    if (size == 0) {
      return newTable;
    }

    for (int j = 0; j < oldCapacity; j++) {
      /*
       * Rehash the bucket using the minimum number of field writes.
       * This is the most subtle and delicate code in the class.
       */
      HashtableEntry<K, V> e = oldTable[j];
      if (e == null) {
        continue;
      }
      int highBit = e.hash & oldCapacity;
      HashtableEntry<K, V> broken = null;
      newTable[j | highBit] = e;
      for (HashtableEntry<K, V> n = e.next; n != null; e = n, n = n.next) {
        int nextHighBit = n.hash & oldCapacity;
        if (nextHighBit != highBit) {
          if (broken == null) newTable[j | nextHighBit] = n;
          else broken.next = n;
          broken = e;
          highBit = nextHighBit;
        }
      }
      if (broken != null) broken.next = null;
    }
    return newTable;
  }
Beispiel #12
0
  /**
   * Puts the key and the value in the table. If there already is a key equal ignore case to the one
   * passed the new value exchhanes the old one.
   *
   * @param key String key
   * @param value object to put
   * @return old value if any, or null if none
   * @exception IllegalArgumentException if key is not a string
   */
  public synchronized Object put(Object key, Object value) throws IllegalArgumentException {

    if (value == null) {
      throw new NullPointerException();
    }
    if (table == null) initTable(MIN_CAPACITY);
    try {
      // Makes sure the key is not already in the hashtable.
      int hash = hashCode((String) key);
      int index;
      HashtableEntry[] tab = null;
      do {
        tab = table;
        index = (hash & 0x7FFFFFFF) % tab.length;
        for (HashtableEntry e = tab[index]; e != null; e = e.next) {
          if ((e.hash == hash) && e.key.equalsIgnoreCase((String) key)) {
            Object old = e.value;
            e.value = value;
            return old;
          }
        }
        if (count >= threshold) {
          // Rehash the table if the threshold is exceeded
          rehash();
          continue;
        }
        break;
      } while (true);

      // Creates the new entry.
      HashtableEntry e = new HashtableEntry();
      e.hash = hash;
      e.key = (String) key;
      e.value = value;
      e.next = tab[index];
      tab[index] = e;
      count++;
      return null;
    } catch (ClassCastException cce) {
      throw new IllegalArgumentException("Non string keys are not accepted!");
    }
  }