/**
   * @param key the key to be added to the receiver.
   * @return the index where the key would need to be inserted, if it is not already contained.
   *     Returns -index-1 if the key is already contained at slot index. Therefore, if the returned
   *     index < 0, then it is already contained at slot -index-1. If the returned index >= 0, then
   *     it is NOT already contained and should be inserted at slot index.
   */
  protected int indexOfInsertion(int key) {
    final int tab[] = table;
    final byte stat[] = state;
    final int length = tab.length;

    final int hash = HashFunctions.hash(key) & 0x7FFFFFFF;
    int i = hash % length;
    int decrement = hash % (length - 2); // double hashing, see
    // http://www.eece.unm.edu/faculty/heileman/hash/node4.html
    // int decrement = (hash / length) % length;
    if (decrement == 0) decrement = 1;

    // stop if we find a removed or free slot, or if we find the key itself
    // do NOT skip over removed slots (yes, open addressing is like that...)
    while (stat[i] == FULL && tab[i] != key) {
      i -= decrement;
      // hashCollisions++;
      if (i < 0) i += length;
    }

    if (stat[i] == REMOVED) {
      // stop if we find a free slot, or if we find the key itself.
      // do skip over removed slots (yes, open addressing is like that...)
      // assertion: there is at least one FREE slot.
      int j = i;
      while (stat[i] != FREE && (stat[i] == REMOVED || tab[i] != key)) {
        i -= decrement;
        // hashCollisions++;
        if (i < 0) i += length;
      }
      if (stat[i] == FREE) i = j;
    }

    if (stat[i] == FULL) {
      // key already contained at slot i.
      // return a negative number identifying the slot.
      return -i - 1;
    }
    // not already contained, should be inserted at slot i.
    // return a number >= 0 identifying the slot.
    return i;
  }
  /**
   * @param key the key to be searched in the receiver.
   * @return the index where the key is contained in the receiver, else returns -1.
   */
  protected int indexOfKey(int key) {
    final int tab[] = table;
    final byte stat[] = state;
    final int length = tab.length;

    final int hash = HashFunctions.hash(key) & 0x7FFFFFFF;
    int i = hash % length;
    int decrement = hash % (length - 2); // double hashing, see
    // http://www.eece.unm.edu/faculty/heileman/hash/node4.html
    // int decrement = (hash / length) % length;
    if (decrement == 0) decrement = 1;

    // stop if we find a free slot, or if we find the key itself.
    // do skip over removed slots (yes, open addressing is like that...)
    // assertion: there is at least one FREE slot.
    while (stat[i] != FREE && (stat[i] == REMOVED || tab[i] != key)) {
      i -= decrement;
      // hashCollisions++;
      if (i < 0) i += length;
    }

    if (stat[i] == FREE) return -1; // not found
    return i; // found, return index where key is contained
  }