public final Object put(Object key, Object value) {
    int h;
    for (h = firstIndex(key); table[h] != null; h = nextIndex(h)) {
      if (key.equals(table[h])) {
	h |= halfTableLength;
	Object tem = table[h];
	table[h] = value;
	return tem;
      }
    }
    if (used >= usedLimit) {
      // rehash
      halfTableLength = table.length;
      usedLimit = (int)(halfTableLength * LOAD_FACTOR);
      Object[] oldTable = table;
      table = new Object[halfTableLength << 1];
      for (int i = oldTable.length >> 1; i > 0;) {
	--i;
	if (oldTable[i] != null) {
	  int j;
	  for (j = firstIndex(oldTable[i]); table[j] != null; j = nextIndex(j))
	    ;
	  table[j] = oldTable[i];
	  // copy the value
	  table[j | halfTableLength] = oldTable[i + (oldTable.length >> 1)];
	}
      }
      for (h = firstIndex(key); table[h] != null; h = nextIndex(h))
	;
    }
    used++;
    table[h] = key;
    table[h | halfTableLength] = value;
    return null;
  }