@@ -100,11 +100,6 @@ public class SyncMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,
100100 */
101101 /* package */ static final int MINIMUM_TRANSFER_STRIDE = 16 ;
102102
103- /**
104- * Represents the number of usable bits for node hash keys.
105- */
106- /* package */ static final int HASH_BITS = 0x7FFFFFFF ;
107-
108103 /**
109104 * Represents the hash for a node that has been transferred.
110105 */
@@ -122,17 +117,6 @@ public class SyncMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,
122117
123118 /* ------------------------------ < Utilities > ------------------------------ */
124119
125- /**
126- * Spreads the given hash value to a positive value and forces the top bit to
127- * 0.
128- *
129- * @param value the value to spread
130- * @return the spread value
131- */
132- /* package */ static int spread (final int value ) {
133- return (value ^ (value >>> 16 )) & SyncMap .HASH_BITS ;
134- }
135-
136120 /**
137121 * Returns the optimal table size depending on the given capacity.
138122 *
@@ -225,6 +209,11 @@ public class SyncMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,
225209
226210 /* ------------------------------ < Fields > ------------------------------ */
227211
212+ /**
213+ * Represents the mix function for distributing hashes in the map.
214+ */
215+ /* package */ final transient Hashing .MixFunction mixFunction ;
216+
228217 /**
229218 * Represents the load factor for resizing the map.
230219 */
@@ -297,40 +286,77 @@ public class SyncMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K,
297286 /* ------------------------- < Public Operations > ------------------------- */
298287
299288 /**
300- * Initializes a new {@link SyncMap} with {@link SyncMap#DEFAULT_CAPACITY} and
301- * {@link SyncMap#DEFAULT_LOAD_FACTOR}.
289+ * Initializes a new {@link SyncMap} with {@link Hashing#FAST_MIX},
290+ * {@link SyncMap#DEFAULT_CAPACITY} and {@link SyncMap# DEFAULT_LOAD_FACTOR}.
302291 *
303292 * @since 1.0.0
304293 */
305294 public SyncMap () {
306- this (SyncMap . DEFAULT_CAPACITY );
295+ this (Hashing . FAST_MIX );
307296 }
308297
309298 /**
310- * Initializes a new {@link SyncMap} with the given initial capacity and
311- * {@link SyncMap#DEFAULT_LOAD_FACTOR}.
299+ * Initializes a new {@link SyncMap} with the given mix function,
300+ * {@link SyncMap#DEFAULT_CAPACITY} and {@link SyncMap#DEFAULT_LOAD_FACTOR}.
301+ *
302+ * @param mixFunction the mix function
303+ * @since 1.0.0
304+ */
305+ public SyncMap (final Hashing .MixFunction mixFunction ) {
306+ this (mixFunction , SyncMap .DEFAULT_CAPACITY );
307+ }
308+
309+ /**
310+ * Initializes a new {@link SyncMap} with {@link Hashing#FAST_MIX}, the
311+ * given initial capacity and {@link SyncMap#DEFAULT_LOAD_FACTOR}.
312312 *
313313 * @param initialCapacity the initial capacity
314314 * @since 1.0.0
315315 */
316316 public SyncMap (final int initialCapacity ) {
317- this (initialCapacity , SyncMap . DEFAULT_LOAD_FACTOR );
317+ this (Hashing . FAST_MIX , initialCapacity );
318318 }
319319
320320 /**
321- * Initializes a new {@link SyncMap} with the given initial capacity and load
322- * factor.
321+ * Initializes a new {@link SyncMap} with the given mix function, the given
322+ * initial capacity and {@link SyncMap#DEFAULT_LOAD_FACTOR}.
323+ *
324+ * @param mixFunction the mix function
325+ * @param initialCapacity the initial capacity
326+ * @since 1.0.0
327+ */
328+ public SyncMap (final Hashing .MixFunction mixFunction , final int initialCapacity ) {
329+ this (mixFunction , initialCapacity , SyncMap .DEFAULT_LOAD_FACTOR );
330+ }
331+
332+ /**
333+ * Initializes a new {@link SyncMap} with {@link Hashing#FAST_MIX}, the
334+ * given initial capacity and the given load factor.
323335 *
324336 * @param initialCapacity the initial capacity
325337 * @param loadFactor the load factor
326338 * @since 1.0.0
327339 */
328- @ SuppressWarnings ({"rawtypes" , "unchecked" })
329340 public SyncMap (final int initialCapacity , final float loadFactor ) {
341+ this (Hashing .FAST_MIX , initialCapacity , loadFactor );
342+ }
343+
344+ /**
345+ * Initializes a new {@link SyncMap} with the given mix function, the given
346+ * initial capacity and the given load factor.
347+ *
348+ * @param mixFunction the mix function
349+ * @param initialCapacity the initial capacity
350+ * @param loadFactor the load factor
351+ * @since 1.0.0
352+ */
353+ @ SuppressWarnings ({"rawtypes" , "unchecked" })
354+ public SyncMap (final Hashing .MixFunction mixFunction , final int initialCapacity , final float loadFactor ) {
330355 final int capacity = initialCapacity >= SyncMap .MAXIMUM_CAPACITY
331356 ? SyncMap .MAXIMUM_CAPACITY
332357 : SyncMap .tableSizeFor (initialCapacity );
333358
359+ this .mixFunction = mixFunction ;
334360 this .loadFactor = loadFactor ;
335361 this .capacity = capacity ;
336362
@@ -358,7 +384,7 @@ public boolean containsKey(final Object key) {
358384 Node <K , V > node , nextNode ;
359385 int nodeHash ; K nodeKey ;
360386
361- final int hash = SyncMap . spread (key .hashCode ());
387+ final int hash = this . mixFunction . mix (key .hashCode ());
362388
363389 if (length > 0 && (node = SyncMap .getNode (table , (length - 1 ) & hash )) != null ) {
364390 if ((nodeHash = node .hash ) == hash ) {
@@ -416,7 +442,7 @@ public boolean containsKey(final Object key) {
416442 Node <K , V > node , nextNode ;
417443 int nodeHash ; K nodeKey ;
418444
419- final int hash = SyncMap . spread (key .hashCode ());
445+ final int hash = this . mixFunction . mix (key .hashCode ());
420446
421447 if (length > 0 && (node = SyncMap .getNode (table , (length - 1 ) & hash )) != null ) {
422448 if ((nodeHash = node .hash ) == hash ) {
@@ -475,7 +501,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
475501 Node <K , V > node , nextNode ;
476502 int nodeHash ; K nodeKey ;
477503
478- final int hash = SyncMap . spread (key .hashCode ());
504+ final int hash = this . mixFunction . mix (key .hashCode ());
479505
480506 if (length > 0 && (node = SyncMap .getNode (table , (length - 1 ) & hash )) != null ) {
481507 if ((nodeHash = node .hash ) == hash ) {
@@ -534,7 +560,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
534560 Node <K , V >[] immutable , mutable = null ; int length ;
535561 Node <K , V > node ; K nodeKey ;
536562
537- final int hash = SyncMap . spread (key .hashCode ());
563+ final int hash = this . mixFunction . mix (key .hashCode ());
538564
539565 V next ;
540566 retry : for (; ; ) {
@@ -642,7 +668,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
642668 Node <K , V >[] immutable , mutable ; int length ;
643669 Node <K , V > node ; K nodeKey ;
644670
645- final int hash = SyncMap . spread (key .hashCode ());
671+ final int hash = this . mixFunction . mix (key .hashCode ());
646672
647673 V next ; long count = 0L ;
648674 retry : for (; ; ) {
@@ -738,7 +764,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
738764 Node <K , V >[] immutable , mutable = null ; int length ;
739765 Node <K , V > node ; K nodeKey ;
740766
741- final int hash = SyncMap . spread (key .hashCode ());
767+ final int hash = this . mixFunction . mix (key .hashCode ());
742768
743769 V next ; long count = 0L ;
744770 retry : for (; ; ) {
@@ -866,7 +892,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
866892 Node <K , V >[] immutable , mutable = null ; int length ;
867893 Node <K , V > node ; K nodeKey ;
868894
869- final int hash = SyncMap . spread (key .hashCode ());
895+ final int hash = this . mixFunction . mix (key .hashCode ());
870896
871897 retry : for (; ; ) {
872898 immutable = this .immutableTable ; length = immutable .length ;
@@ -961,7 +987,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
961987 Node <K , V >[] immutable , mutable = null ; int length ;
962988 Node <K , V > node ; K nodeKey ;
963989
964- final int hash = SyncMap . spread (key .hashCode ());
990+ final int hash = this . mixFunction . mix (key .hashCode ());
965991
966992 retry : for (; ; ) {
967993 immutable = this .immutableTable ; length = immutable .length ;
@@ -1094,7 +1120,7 @@ public V getOrDefault(final Object key, final V defaultValue) {
10941120 Node <K , V >[] immutable , mutable ; int length ;
10951121 Node <K , V > node ; K nodeKey ;
10961122
1097- final int hash = SyncMap . spread (key .hashCode ());
1123+ final int hash = this . mixFunction . mix (key .hashCode ());
10981124
10991125 Object previous ;
11001126 retry : for (; ; ) {
@@ -1179,7 +1205,7 @@ public boolean remove(final Object key, final Object value) {
11791205 Node <K , V >[] immutable , mutable ; int length ;
11801206 Node <K , V > node ; K nodeKey ;
11811207
1182- final int hash = SyncMap . spread (key .hashCode ());
1208+ final int hash = this . mixFunction . mix (key .hashCode ());
11831209
11841210 retry : for (; ; ) {
11851211 immutable = this .immutableTable ; length = immutable .length ;
@@ -1266,7 +1292,7 @@ public boolean remove(final Object key, final Object value) {
12661292 Node <K , V >[] immutable , mutable ; int length ;
12671293 Node <K , V > node ; K nodeKey ;
12681294
1269- final int hash = SyncMap . spread (key .hashCode ());
1295+ final int hash = this . mixFunction . mix (key .hashCode ());
12701296
12711297 Object previous ;
12721298 retry : for (; ; ) {
@@ -1343,7 +1369,7 @@ public boolean replace(final @NonNull K key, final @NonNull V oldValue, final @N
13431369 Node <K , V >[] immutable , mutable ; int length ;
13441370 Node <K , V > node ; K nodeKey ;
13451371
1346- final int hash = SyncMap . spread (key .hashCode ());
1372+ final int hash = this . mixFunction . mix (key .hashCode ());
13471373
13481374 Object previous ;
13491375 retry : for (; ; ) {
@@ -1472,11 +1498,14 @@ public void clear() {
14721498 /**
14731499 * {@inheritDoc}
14741500 *
1475- * <p>Creating an {@link Iterator} from this view, takes an immutable
1476- * snapshot of the entries, meaning, modifications after calling
1477- * {@link Set#iterator()} will not be visible. Calling
1478- * {@link Iterator#remove()} will work provided the key-value pair is
1479- * identical to the pair currently in the map.</p>
1501+ * <p>The {@link Iterator} produced by this view is weakly consistent: it
1502+ * iterates over an immutable snapshot captured at iterator creation time.
1503+ * New insertions after calling {@link Set#iterator()} are not reflected in
1504+ * the traversal.</p>
1505+ *
1506+ * <p>{@link Iterator#remove()} attempts to remove the last returned entry
1507+ * from the backing map, and succeeds only if the key still maps to the same
1508+ * value at the time of removal.</p>
14801509 */
14811510 @ Override
14821511 public Set <Map .Entry <K , V >> entrySet () {
0 commit comments