@Override
 public V remove(Object key) {
   long h = hasher.hash(key);
   int segment = hasher.getSegment();
   segments[segment].remove(h, (K) key);
   return null;
 }
 @Override
 public V put(K key, V value) {
   long h = hasher.hash(key);
   int segment = hasher.getSegment();
   segments[segment].put(h, key, value, true, true);
   return null;
 }
 @Override
 public V replace(@NotNull K key, @NotNull V value) {
   long h = hasher.hash(key);
   int segment = hasher.getSegment();
   segments[segment].put(h, key, value, true, false);
   return null;
 }
 @Override
 public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) {
   long h = hasher.hash(key);
   int segment = hasher.getSegment();
   Segment<K, V> segment2 = segments[segment];
   //noinspection SynchronizationOnLocalVariableOrMethodParameter
   synchronized (segment2) {
     V value2 = get(key);
     if (value2 != null && oldValue.equals(value2)) {
       segment2.put(h, key, newValue, true, true);
       return true;
     }
     return false;
   }
 }
 @Override
 public boolean remove(@NotNull Object key, Object value) {
   long h = hasher.hash(key);
   int segment = hasher.getSegment();
   Segment<K, V> segment2 = segments[segment];
   //noinspection SynchronizationOnLocalVariableOrMethodParameter
   synchronized (segment2) {
     V value2 = get(key);
     if (value2 != null && value.equals(value2)) {
       segment2.remove(h, (K) key);
       return true;
     }
     return false;
   }
 }
 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);
   }
 }
 public FileCollectionSnapshot snapshot(FileCollection sourceFiles) {
   Map<String, FileSnapshot> snapshots = new HashMap<String, FileSnapshot>();
   for (File file : sourceFiles) {
     if (file.isFile()) {
       snapshots.put(file.getAbsolutePath(), new FileHashSnapshot(hasher.hash(file)));
     } else if (file.isDirectory()) {
       snapshots.put(file.getAbsolutePath(), new DirSnapshot());
     } else {
       snapshots.put(file.getAbsolutePath(), new MissingFileSnapshot());
     }
   }
   return new FileCollectionSnapshotImpl(snapshots);
 }
 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();
   }
 }
 @Override
 public boolean containsKey(Object key) {
   long h = hasher.hash(key);
   int segment = hasher.getSegment();
   return segments[segment].containsKey(h, (K) key);
 }
 @Override
 public V get(K key, V value) {
   long h = hasher.hash(key);
   int segment = hasher.getSegment();
   return segments[segment].get(h, key, value);
 }