/**
  * Resizes the map.
  *
  * <p>This method implements the basic rehashing strategy, and may be overriden by subclasses
  * implementing different rehashing strategies (e.g., disk-based rehashing). However, you should
  * not override this method unless you understand the internal workings of this class.
  *
  * @param newN the new size
  */
 @SuppressWarnings("unchecked")
 protected void rehash(final int newN) {
   int i = 0, pos;
   final boolean used[] = this.used;
   K k;
   final K key[] = this.key;
   final char value[] = this.value;
   final int newMask = newN - 1;
   final K newKey[] = (K[]) new Object[newN];
   final char newValue[] = new char[newN];
   final boolean newUsed[] = new boolean[newN];
   for (int j = size; j-- != 0; ) {
     while (!used[i]) i++;
     k = key[i];
     pos = (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (k)))) & newMask;
     while (newUsed[pos]) pos = (pos + 1) & newMask;
     newUsed[pos] = true;
     newKey[pos] = k;
     newValue[pos] = value[i];
     i++;
   }
   n = newN;
   mask = newMask;
   maxFill = maxFill(n, f);
   this.key = newKey;
   this.value = newValue;
   this.used = newUsed;
 }
 /**
  * Returns a hash code for this map.
  *
  * <p>This method overrides the generic method provided by the superclass. Since <code>equals()
  * </code> is not overriden, it is important that the value returned by this method is the same
  * value as the one returned by the overriden method.
  *
  * @return a hash code for this map.
  */
 public int hashCode() {
   int h = 0;
   for (int j = size, i = 0, t = 0; j-- != 0; ) {
     while (!used[i]) i++;
     if (this != key[i]) t = (strategy.hashCode((K) (key[i])));
     t ^= (value[i]);
     h += t;
     i++;
   }
   return h;
 }
 @SuppressWarnings("unchecked")
 public boolean containsKey(final Object k) {
   // The starting point.
   int pos = (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (k)))) & mask;
   // There's always an unused entry.
   while (used[pos]) {
     if ((strategy.equals((key[pos]), (K) (k)))) return true;
     pos = (pos + 1) & mask;
   }
   return false;
 }
 @SuppressWarnings("unchecked")
 public char getChar(final Object k) {
   // The starting point.
   int pos = (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (k)))) & mask;
   // There's always an unused entry.
   while (used[pos]) {
     if ((strategy.equals((key[pos]), (K) (k)))) return value[pos];
     pos = (pos + 1) & mask;
   }
   return defRetValue;
 }
 @SuppressWarnings("unchecked")
 public Character remove(final Object ok) {
   final K k = (K) (ok);
   // The starting point.
   int pos = (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (k)))) & mask;
   // There's always an unused entry.
   while (used[pos]) {
     if ((strategy.equals((key[pos]), (K) (k)))) {
       size--;
       final char v = value[pos];
       shiftKeys(pos);
       return (Character.valueOf(v));
     }
     pos = (pos + 1) & mask;
   }
   return (null);
 }
 /*
  * The following methods implements some basic building blocks used by
  * all accessors. They are (and should be maintained) identical to those used in OpenHashSet.drv.
  */
 public char put(final K k, final char v) {
   // The starting point.
   int pos = (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (k)))) & mask;
   // There's always an unused entry.
   while (used[pos]) {
     if ((strategy.equals((key[pos]), (K) (k)))) {
       final char oldValue = value[pos];
       value[pos] = v;
       return oldValue;
     }
     pos = (pos + 1) & mask;
   }
   used[pos] = true;
   key[pos] = k;
   value[pos] = v;
   if (++size >= maxFill) rehash(arraySize(size + 1, f));
   if (ASSERTS) checkTable();
   return defRetValue;
 }
 /**
  * Shifts left entries with the specified hash code, starting at the specified position, and
  * empties the resulting free entry.
  *
  * @param pos a starting position.
  * @return the position cleared by the shifting process.
  */
 protected final int shiftKeys(int pos) {
   // Shift entries with the same hash.
   int last, slot;
   for (; ; ) {
     pos = ((last = pos) + 1) & mask;
     while (used[pos]) {
       slot =
           (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (key[pos]))))
               & mask;
       if (last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos) break;
       pos = (pos + 1) & mask;
     }
     if (!used[pos]) break;
     key[last] = key[pos];
     value[last] = value[pos];
   }
   used[last] = false;
   key[last] = null;
   return last;
 }
 public Character put(final K ok, final Character ov) {
   final char v = ((ov).charValue());
   final K k = (ok);
   // The starting point.
   int pos = (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (k)))) & mask;
   // There's always an unused entry.
   while (used[pos]) {
     if ((strategy.equals((key[pos]), (K) (k)))) {
       final Character oldValue = (Character.valueOf(value[pos]));
       value[pos] = v;
       return oldValue;
     }
     pos = (pos + 1) & mask;
   }
   used[pos] = true;
   key[pos] = k;
   value[pos] = v;
   if (++size >= maxFill) rehash(arraySize(size + 1, f));
   if (ASSERTS) checkTable();
   return (null);
 }
 @SuppressWarnings("unchecked")
 private void readObject(java.io.ObjectInputStream s)
     throws java.io.IOException, ClassNotFoundException {
   s.defaultReadObject();
   n = arraySize(size, f);
   maxFill = maxFill(n, f);
   mask = n - 1;
   final K key[] = this.key = (K[]) new Object[n];
   final char value[] = this.value = new char[n];
   final boolean used[] = this.used = new boolean[n];
   K k;
   char v;
   for (int i = size, pos = 0; i-- != 0; ) {
     k = (K) s.readObject();
     v = s.readChar();
     pos = (it.unimi.dsi.fastutil.HashCommon.murmurHash3(strategy.hashCode((K) (k)))) & mask;
     while (used[pos]) pos = (pos + 1) & mask;
     used[pos] = true;
     key[pos] = k;
     value[pos] = v;
   }
   if (ASSERTS) checkTable();
 }