/**
   * Removes the given key with its associated element from the receiver, if present.
   *
   * @param key the key to be removed from the receiver.
   * @return <tt>true</tt> if the receiver contained the specified key, <tt>false</tt> otherwise.
   */
  public boolean removeKey(int key) {
    int i = indexOfKey(key);
    if (i < 0) return false; // key not contained

    // if (debug) if (this.state[i] == FREE) throw new InternalError();
    // if (debug) if (this.state[i] == REMOVED) throw new InternalError();
    this.state[i] = REMOVED;
    // this.values[i]=0; // delta

    // if (debug) this.table[i]=Integer.MAX_VALUE; // delta
    // if (debug) this.values[i]=Double.NaN; // delta
    this.distinct--;

    if (this.distinct < this.lowWaterMark) {
      int newCapacity = chooseShrinkCapacity(this.distinct, this.minLoadFactor, this.maxLoadFactor);
      /*
       * if (table.length != newCapacity) { System.out.print("shrink rehashing ");
       * System.out.println
       * ("at distinct="+distinct+", capacity="+table.length+" to newCapacity="+newCapacity+" ...");
       * }
       */
      rehash(newCapacity);
    }

    return true;
  }
 /**
  * Trims the capacity of the receiver to be the receiver's current size. Releases any superfluous
  * internal memory. An application can use this operation to minimize the storage of the receiver.
  */
 public void trimToSize() {
   // * 1.2 because open addressing's performance exponentially degrades beyond that point
   // so that even rehashing the table can take very long
   int newCapacity = nextPrime((int) (1 + 1.2 * size()));
   if (table.length > newCapacity) {
     rehash(newCapacity);
   }
 }
  /**
   * Associates the given key with the given value. Replaces any old <tt>(key,someOtherValue)</tt>
   * association, if existing.
   *
   * @param key the key the value shall be associated with.
   * @param value the value to be associated.
   * @return <tt>true</tt> if the receiver did not already contain such a key; <tt>false</tt> if the
   *     receiver did already contain such a key - the new value has now replaced the formerly
   *     associated value.
   */
  public boolean put(int key, double value) {
    int i = indexOfInsertion(key);
    if (i < 0) { // already contained
      i = -i - 1;
      // if (debug) if (this.state[i] != FULL) throw new InternalError();
      // if (debug) if (this.table[i] != key) throw new InternalError();
      this.values[i] = value;
      return false;
    }

    if (this.distinct > this.highWaterMark) {
      int newCapacity =
          chooseGrowCapacity(this.distinct + 1, this.minLoadFactor, this.maxLoadFactor);
      /*
       * System.out.print("grow rehashing ");
       * System.out.println("at distinct="+distinct+", capacity="
       * +table.length+" to newCapacity="+newCapacity+" ...");
       */
      rehash(newCapacity);
      return put(key, value);
    }

    this.table[i] = key;
    this.values[i] = value;
    if (this.state[i] == FREE) this.freeEntries--;
    this.state[i] = FULL;
    this.distinct++;

    if (this.freeEntries < 1) { // delta
      int newCapacity =
          chooseGrowCapacity(this.distinct + 1, this.minLoadFactor, this.maxLoadFactor);
      rehash(newCapacity);
    }

    return true;
  }
 /**
  * Ensures that the receiver can hold at least the specified number of associations without
  * needing to allocate new internal memory. If necessary, allocates new internal memory and
  * increases the capacity of the receiver.
  *
  * <p>This method never need be called; it is for performance tuning only. Calling this method
  * before <tt>put()</tt>ing a large number of associations boosts performance, because the
  * receiver will grow only once instead of potentially many times and hash collisions get less
  * probable.
  *
  * @param minCapacity the desired minimum capacity.
  */
 public void ensureCapacity(int minCapacity) {
   if (table.length < minCapacity) {
     int newCapacity = nextPrime(minCapacity);
     rehash(newCapacity);
   }
 }