int nextFree() {
   int ret = (int) freeList.setNFrom(nextSet, 1);
   if (ret == DirectBitSet.NOT_FOUND) {
     ret = (int) freeList.setNFrom(0, 1);
     if (ret == DirectBitSet.NOT_FOUND)
       throw new IllegalStateException("Segment is full, no free entries found");
   }
   nextSet = ret + 1;
   return ret;
 }
    void directRemove(final Bytes keyBytes, int hash2) {
      lock();
      try {
        hash2 = hashLookup.startSearch(hash2);
        while (true) {

          final int pos = hashLookup.nextPos();
          if (pos < 0) {
            return;

          } else {
            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            final long keyLength =
                align(keyBytes.remaining() + tmpBytes.position()); // includes the stop bit length.
            tmpBytes.position(keyLength);

            hashLookup.remove(hash2, pos);
            decrementSize();

            freeList.clear(pos);
            if (pos < nextSet) nextSet = pos;

            return;
          }
        }
      } finally {
        unlock();
      }
    }
    public V remove(DirectBytes keyBytes, V value, int hash2) {
      if (hash2 == hashLookup.unsetKey()) hash2 = ~hash2;
      lock();
      try {
        hashLookup.startSearch(hash2);
        while (true) {
          int pos = hashLookup.nextInt();
          if (pos == hashLookup.unsetValue()) {
            return null;

          } else {
            long offset = entriesOffset + pos * builder.entrySize();
            tmpBytes.storePositionAndSize(bytes, offset, builder.entrySize());
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            long keyLength = align(keyBytes.remaining());
            tmpBytes.skip(keyLength);
            V v =
                value == null && builder.removeReturnsNull()
                    ? null
                    : readObjectUsing(value, offset + keyLength);
            hashLookup.remove(hash2, pos);
            freeList.clear(pos);
            if (pos < nextSet) nextSet = pos;
            return v;
          }
        }
      } finally {
        unlock();
      }
    }
    /**
     * implementation for map.remove(Key,Value)
     *
     * @param keyBytes the key of the entry to remove
     * @param expectedValue the entry will only be removed if the {@param existingValue} equals null
     *     or the {@param existingValue} equals that of the entry.value
     * @param hash2 a hash code relating to the {@keyBytes} ( not the natural hash of {@keyBytes} )
     * @return
     */
    V remove(final DirectBytes keyBytes, final V expectedValue, int hash2) {
      lock();
      try {
        hash2 = hashLookup.startSearch(hash2);
        while (true) {

          final int pos = hashLookup.nextPos();
          if (pos < 0) {
            return null;

          } else {
            final long offset = entriesOffset + pos * entrySize;
            tmpBytes.storePositionAndSize(bytes, offset, entrySize);
            if (!keyEquals(keyBytes, tmpBytes)) continue;
            final long keyLength =
                align(keyBytes.remaining() + tmpBytes.position()); // includes the stop bit length.
            tmpBytes.position(keyLength);
            V valueRemoved =
                expectedValue == null && removeReturnsNull
                    ? null
                    : readObjectUsing(null, offset + keyLength);

            if (expectedValue != null && !expectedValue.equals(valueRemoved)) return null;

            hashLookup.remove(hash2, pos);
            decrementSize();

            freeList.clear(pos);
            if (pos < nextSet) nextSet = pos;

            return valueRemoved;
          }
        }
      } finally {
        unlock();
      }
    }