/**
   * Modify is whether to make room for the new key if it doesn't exist. If a new entry is created,
   * the value at that position will be Double.NaN. Here's where all the magic happens.
   */
  private int find(T key, boolean modify) {
    // System.out.println("find " + key + " " + modify + " " + mapType + " " + capacity());

    if (mapType == MapType.SORTED_LIST) {
      // Binary search
      int i = binarySearch(key);
      if (i < num && keys[i] != null && key.equals(keys[i])) return i;
      if (modify) {
        if (locked)
          throw new RuntimeException(
              "Cannot make new entry for " + key + ", because map is locked");

        if (num == capacity()) changeSortedListCapacity(getCapacity(num + 1, false));

        // Shift everything forward
        for (int j = num; j > i; j--) {
          keys[j] = keys[j - 1];
          values[j] = values[j - 1];
        }
        num++;
        values[i] = Double.NaN;
        return i;
      } else return -1;
    } else if (mapType == MapType.HASH_TABLE) {
      int capacity = capacity();
      int keyHash = hash(key);
      int i = keyHash % capacity;
      if (i < 0) i = -i; // Arbitrary transformation

      // Make sure big enough
      if (!locked && modify && (num > loadFactor * capacity || capacity <= num + 1)) {
        /*if(locked)
        throw new RuntimeException("Cannot make new entry for " + key + ", because map is locked");*/

        switchMapType(MapType.HASH_TABLE);
        return find(key, modify);
      }

      // System.out.println("!!! " + keyHash + " " + capacity);
      if (num == capacity) throw new RuntimeException("Hash table is full: " + capacity);
      while (keys[i] != null && !keys[i].equals(key)) { // Collision
        // Warning: infinite loop if the hash table is full
        // (but this shouldn't happen based on the check above)
        i++;
        numCollisions++;
        if (i == capacity) i = 0;
      }
      if (keys[i] != null) { // Found
        assert key.equals(keys[i]);
        return i;
      }
      if (modify) { // Not found
        num++;
        values[i] = Double.NaN;
        return i;
      } else return -1;
    } else throw new RuntimeException("Internal bug: " + mapType);
  }
 public void switchToHashTable() {
   switchMapType(MapType.HASH_TABLE);
 }
 public void switchToSortedList() {
   switchMapType(MapType.SORTED_LIST);
 }