private CharKeyOpenHashMap(
     CharHashFunction keyhash,
     int capacity,
     int growthPolicy,
     double growthFactor,
     int growthChunk,
     double loadFactor) {
   if (keyhash == null) Exceptions.nullArgument("hash function");
   if (capacity < 0) Exceptions.negativeArgument("capacity", String.valueOf(capacity));
   if (growthFactor <= 0.0)
     Exceptions.negativeOrZeroArgument("growthFactor", String.valueOf(growthFactor));
   if (growthChunk <= 0)
     Exceptions.negativeOrZeroArgument("growthChunk", String.valueOf(growthChunk));
   if (loadFactor <= 0.0)
     Exceptions.negativeOrZeroArgument("loadFactor", String.valueOf(loadFactor));
   this.keyhash = keyhash;
   capacity = Primes.nextPrime(capacity);
   keys = new char[capacity];
   values = (Object[]) new Object[capacity];
   this.states = new byte[capacity];
   size = 0;
   expandAt = (int) Math.round(loadFactor * capacity);
   this.used = 0;
   this.growthPolicy = growthPolicy;
   this.growthFactor = growthFactor;
   this.growthChunk = growthChunk;
   this.loadFactor = loadFactor;
 }
  private void ensureCapacity(int elements) {
    if (elements >= expandAt) {
      int newcapacity;
      if (growthPolicy == GROWTH_POLICY_RELATIVE)
        newcapacity = (int) (keys.length * (1.0 + growthFactor));
      else newcapacity = keys.length + growthChunk;
      if (newcapacity * loadFactor < elements)
        newcapacity = (int) Math.round(((double) elements / loadFactor));
      newcapacity = Primes.nextPrime(newcapacity);
      expandAt = (int) Math.round(loadFactor * newcapacity);

      char[] newkeys = new char[newcapacity];
      Object[] newvalues = (Object[]) new Object[newcapacity];
      byte[] newstates = new byte[newcapacity];

      used = 0;
      //  re-hash
      for (int i = 0; i < keys.length; i++) {
        if (states[i] == OCCUPIED) {
          used++;
          char k = keys[i];
          Object v = values[i];
          //  first hash
          int h = Math.abs(keyhash.hash(k));
          int n = h % newcapacity;
          if (newstates[n] == OCCUPIED) {
            //  second hash
            int c = 1 + (h % (newcapacity - 2));
            for (; ; ) {
              n -= c;
              if (n < 0) n += newcapacity;
              if (newstates[n] == EMPTY) break;
            }
          }
          newstates[n] = OCCUPIED;
          newvalues[n] = v;
          newkeys[n] = k;
        }
      }

      keys = newkeys;
      values = newvalues;
      states = newstates;
    }
  }