synchronized boolean remove(long hash, K key) {
   int h = smallMap.startSearch(hash);
   boolean found = false;
   while (true) {
     int pos = smallMap.nextPos();
     if (pos < 0) {
       break;
     }
     bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
     K key2 = getKey();
     if (equals(key, key2)) {
       usedSet.clear(pos);
       smallMap.remove(h, pos);
       found = true;
       this.size--;
       break;
     }
   }
   K key2 = key instanceof CharSequence ? (K) key.toString() : key;
   DirectStore remove = map.remove(key2);
   if (remove == null) return found;
   offHeapUsed -= remove.size();
   remove.free();
   this.size--;
   return true;
 }
 public Entry<K, V> getNextEntry(K prevKey) {
   try {
     int pos;
     if (prevKey == null) {
       pos = smallMap.firstPos();
     } else {
       long hash = hasher.hash(prevKey);
       pos = smallMap.nextDifferentHashNonEmptyPosition(hash);
     }
     while (true) {
       if (pos < 0) {
         return null;
       } else {
         bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
         K key = getKey();
         if (prevKey == null || !equals(key, prevKey)) {
           if (bytesMarshallable) {
             V value = (V) NativeBytes.UNSAFE.allocateInstance(vClass);
             ((BytesMarshallable) value).readMarshallable(bytes);
             return new SimpleEntry<K, V>(key, value);
           } else {
             V value = (V) bytes.readObject();
             return new SimpleEntry<K, V>(key, value);
           }
         }
       }
       pos = smallMap.nextPos();
     }
   } catch (InstantiationException e) {
     throw new AssertionError(e);
   }
 }
 synchronized V get(long hash, K key, V value) {
   smallMap.startSearch(hash);
   while (true) {
     int pos = smallMap.nextPos();
     if (pos < 0) {
       K key2 = key instanceof CharSequence ? (K) key.toString() : key;
       final DirectStore store = map.get(key2);
       if (store == null) return null;
       bytes.storePositionAndSize(store, 0, store.size());
       break;
     } else {
       bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
       K key2 = getKey();
       if (equals(key, key2)) break;
     }
   }
   if (bytesMarshallable) {
     try {
       V v = value == null ? (V) NativeBytes.UNSAFE.allocateInstance(vClass) : value;
       ((BytesMarshallable) v).readMarshallable(bytes);
       return v;
     } catch (InstantiationException e) {
       throw new AssertionError(e);
     }
   }
   return (V) bytes.readObject();
 }
 synchronized boolean containsKey(long hash, K key) {
   smallMap.startSearch(hash);
   while (true) {
     int pos = smallMap.nextPos();
     if (pos < 0) {
       K key2 = key instanceof CharSequence ? (K) key.toString() : key;
       return map.containsKey(key2);
     }
     bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
     K key2 = getKey();
     if (equals(key, key2)) {
       return true;
     }
   }
 }
 void clear() {
   usedSet.clear();
   smallMap.clear();
   for (DirectStore directStore : map.values()) {
     directStore.free();
   }
   map.clear();
   size = 0;
 }
 public K getNextKey(K prevKey) {
   int pos;
   if (prevKey == null) {
     pos = smallMap.firstPos();
   } else {
     long hash = hasher.hash(prevKey);
     pos = smallMap.nextDifferentHashNonEmptyPosition(hash);
   }
   while (true) {
     if (pos < 0) {
       return null;
     } else {
       bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
       K key = getKey();
       if (prevKey == null || !equals(key, prevKey)) {
         return key;
       }
     }
     pos = smallMap.nextPos();
   }
 }
    synchronized void put(long hash, K key, V value, boolean ifPresent, boolean ifAbsent) {
      // search for the previous entry
      int h = smallMap.startSearch(hash);
      boolean foundSmall = false, foundLarge = false;
      while (true) {
        int pos = smallMap.nextPos();
        if (pos < 0) {
          K key2 = key instanceof CharSequence ? (K) key.toString() : key;
          final DirectStore store = map.get(key2);
          if (store == null) {
            if (ifPresent && !ifAbsent) return;
            break;
          }
          if (ifAbsent) return;
          bytes.storePositionAndSize(store, 0, store.size());
          foundLarge = true;
          break;
        } else {
          bytes.storePositionAndSize(store, pos * smallEntrySize, smallEntrySize);
          K key2 = getKey();
          if (equals(key, key2)) {
            if (ifAbsent && !ifPresent) return;
            foundSmall = true;
            break;
          }
        }
      }

      tmpBytes.clear();
      if (csKey)
        //noinspection ConstantConditions
        tmpBytes.writeUTFΔ((CharSequence) key);
      else tmpBytes.writeObject(key);
      long startOfValuePos = tmpBytes.position();
      if (bytesMarshallable) ((BytesMarshallable) value).writeMarshallable(tmpBytes);
      else tmpBytes.writeObject(value);
      long size = tmpBytes.position();
      if (size <= smallEntrySize) {
        if (foundSmall) {
          bytes.position(0);
          bytes.write(tmpBytes, 0, size);
          return;
        } else if (foundLarge) {
          remove(hash, key);
        }
        // look for a free spot.
        int position = h & (entriesPerSegment - 1);
        int free = usedSet.nextClearBit(position);
        if (free >= entriesPerSegment) free = usedSet.nextClearBit(0);
        if (free < entriesPerSegment) {
          bytes.storePositionAndSize(store, free * smallEntrySize, smallEntrySize);
          bytes.write(tmpBytes, 0, size);
          smallMap.put(h, free);
          usedSet.set(free);
          this.size++;
          return;
        }
      }
      if (foundSmall) {
        remove(hash, key);
      } else if (foundLarge) {
        // can it be reused.
        if (bytes.capacity() <= size || bytes.capacity() - size < (size >> 3)) {
          bytes.write(tmpBytes, startOfValuePos, size);
          return;
        }
        remove(hash, key);
      }
      size = size - startOfValuePos;
      DirectStore store = new DirectStore(bmf, size);
      bytes.storePositionAndSize(store, 0, size);
      bytes.write(tmpBytes, startOfValuePos, size);
      K key2 = key instanceof CharSequence ? (K) key.toString() : key;
      map.put(key2, store);
      offHeapUsed += size;
      this.size++;
    }