@@ -350,82 +350,64 @@ public UnmodifiableArrayBackedMap copyAndRemove(String key) {
350350 }
351351
352352 /**
353- * Creates a new instance that contains the same entries as this map, minus all
354- * of the keys passed in the arguments.
355- *
356- * @param key
357- * @param value
358- * @return
353+ * Creates a new instance where the entries of provided keys are removed.
359354 */
360355 public UnmodifiableArrayBackedMap copyAndRemoveAll (Iterable <String > keysToRemoveIterable ) {
356+
357+ // Short-circuit if the map is empty
361358 if (isEmpty ()) {
362- // shortcut: if this map is empty, the result will continue to be empty
363359 return EMPTY_MAP ;
364360 }
365361
366- // now we build a Set of keys to remove
367- Set <String > keysToRemoveSet ;
362+ // Collect distinct keys to remove
363+ final Set <String > keysToRemove ;
368364 if (keysToRemoveIterable instanceof Set ) {
369- // we already have a set, let's cast it and reuse it
370- keysToRemoveSet = (Set <String >) keysToRemoveIterable ;
365+ keysToRemove = (Set <String >) keysToRemoveIterable ;
371366 } else {
372- // iterate through the keys and build a set
373- keysToRemoveSet = new HashSet <>();
374- for (String key : keysToRemoveIterable ) {
375- keysToRemoveSet .add (key );
367+ keysToRemove = new HashSet <>();
368+ for (final String key : keysToRemoveIterable ) {
369+ keysToRemove .add (key );
376370 }
377371 }
378372
379- int firstIndexToKeep = -1 ;
380- int lastIndexToKeep = -1 ;
381- int destinationIndex = 0 ;
382- int numEntriesKept = 0 ;
383- // build the new map
384- UnmodifiableArrayBackedMap newMap = new UnmodifiableArrayBackedMap (numEntries );
385- for (int indexInCurrentMap = 0 ; indexInCurrentMap < numEntries ; indexInCurrentMap ++) {
386- // for each key in this map, check whether it's in the set we built above
387- Object key = backingArray [getArrayIndexForKey (indexInCurrentMap )];
388- if (!keysToRemoveSet .contains (key )) {
389- // this key should be kept
390- if (firstIndexToKeep == -1 ) {
391- firstIndexToKeep = indexInCurrentMap ;
392- }
393- lastIndexToKeep = indexInCurrentMap ;
394- } else if (lastIndexToKeep > 0 ) {
395- // we hit a remove, copy any keys that are known ready
396- int numEntriesToCopy = lastIndexToKeep - firstIndexToKeep + 1 ;
397- System .arraycopy (
398- backingArray ,
399- getArrayIndexForKey (firstIndexToKeep ),
400- newMap .backingArray ,
401- getArrayIndexForKey (destinationIndex ),
402- numEntriesToCopy * 2 );
403- firstIndexToKeep = -1 ;
404- lastIndexToKeep = -1 ;
405- destinationIndex += numEntriesToCopy ;
406- numEntriesKept += numEntriesToCopy ;
407- }
408- }
373+ // Create the new map
374+ final UnmodifiableArrayBackedMap oldMap = this ;
375+ final int oldMapEntryCount = oldMap .numEntries ;
376+ final UnmodifiableArrayBackedMap newMap = new UnmodifiableArrayBackedMap (oldMapEntryCount );
409377
410- if (lastIndexToKeep > -1 ) {
411- // at least one key still requires copying
412- int numEntriesToCopy = lastIndexToKeep - firstIndexToKeep + 1 ;
413- System .arraycopy (
414- backingArray ,
415- getArrayIndexForKey (firstIndexToKeep ),
416- newMap .backingArray ,
417- getArrayIndexForKey (destinationIndex ),
418- numEntriesToCopy * 2 );
419- numEntriesKept += numEntriesToCopy ;
378+ // Short-circuit if there is nothing to remove
379+ if (keysToRemove .isEmpty ()) {
380+ System .arraycopy (oldMap .backingArray , 0 , newMap .backingArray , 0 , oldMapEntryCount * 2 );
381+ newMap .numEntries = oldMapEntryCount ;
382+ return this ;
420383 }
421384
422- if (numEntriesKept == 0 ) {
423- return EMPTY_MAP ;
385+ // Iterate over old map entries
386+ int newMapEntryIndex = 0 ;
387+ for (int oldMapEntryIndex = 0 ; oldMapEntryIndex < oldMapEntryCount ; oldMapEntryIndex ++) {
388+ final int oldMapKeyIndex = getArrayIndexForKey (oldMapEntryIndex );
389+ final Object key = oldMap .backingArray [oldMapKeyIndex ];
390+
391+ // Skip entries of removed keys
392+ @ SuppressWarnings ("SuspiciousMethodCalls" )
393+ final boolean removed = keysToRemove .contains (key );
394+ if (removed ) {
395+ continue ;
396+ }
397+
398+ // Copy the entry
399+ final int oldMapValueIndex = getArrayIndexForValue (oldMapEntryIndex );
400+ final Object value = oldMap .backingArray [oldMapValueIndex ];
401+ final int newMapKeyIndex = getArrayIndexForKey (newMapEntryIndex );
402+ final int newMapValueIndex = getArrayIndexForValue (newMapEntryIndex );
403+ newMap .backingArray [newMapKeyIndex ] = key ;
404+ newMap .backingArray [newMapValueIndex ] = value ;
405+ newMapEntryIndex ++;
424406 }
425407
426- newMap .numEntries = numEntriesKept ;
408+ // Cap and return the new map
409+ newMap .numEntries = newMapEntryIndex ;
427410 newMap .updateNumEntriesInArray ();
428-
429411 return newMap ;
430412 }
431413
0 commit comments