4848 * Implementation of a map with a memory-efficient structure that always preserves insertion order
4949 * when iterating over keys. Particularly efficient when number of entries is 0 or smaller equal
5050 * {@link #INITIAL_CAPACITY} or smaller 256.
51- *
51+ * <p>
5252 * The key/value pairs are kept in an expanding flat object array with keys at even indices and
5353 * values at odd indices. If the map has smaller or equal to {@link #HASH_THRESHOLD} entries, there
5454 * is no additional hash data structure and comparisons are done via linear checking of the
5555 * key/value pairs. For the case where the equality check is particularly cheap (e.g., just an
5656 * object identity comparison), this limit below which the map is without an actual hash table is
5757 * higher and configured at {@link #HASH_THRESHOLD_IDENTITY_COMPARE}.
58- *
58+ * <p>
5959 * When the hash table needs to be constructed, the field {@link #hashArray} becomes a new hash
6060 * array where an entry of 0 means no hit and otherwise denotes the entry number in the
6161 * {@link #entries} array. The hash array is interpreted as an actual byte array if the indices fit
6262 * within 8 bit, or as an array of short values if the indices fit within 16 bit, or as an array of
6363 * integer values in other cases.
64- *
64+ * <p>
6565 * Hash collisions are handled by chaining a linked list of {@link CollisionLink} objects that take
6666 * the place of the values in the {@link #entries} array.
67- *
67+ * <p>
6868 * Removing entries will put {@code null} into the {@link #entries} array. If the occupation of the
6969 * map falls below a specific threshold, the map will be compressed via the
7070 * {@link #maybeCompress(int)} method.
@@ -355,8 +355,7 @@ private int findAndRemoveHash(Object key) {
355355 if (compareKeys (key , entryKey )) {
356356 Object value = getRawValue (index );
357357 int nextIndex = -1 ;
358- if (value instanceof CollisionLink ) {
359- CollisionLink collisionLink = (CollisionLink ) value ;
358+ if (value instanceof CollisionLink collisionLink ) {
360359 nextIndex = collisionLink .next ;
361360 }
362361 setHashArray (hashIndex , nextIndex + 1 );
@@ -383,8 +382,7 @@ private int findAndRemoveWithCollision(Object key, CollisionLink initialEntryVal
383382 entryKey = getKey (index );
384383 if (compareKeys (key , entryKey )) {
385384 Object value = getRawValue (index );
386- if (value instanceof CollisionLink ) {
387- CollisionLink thisCollisionLink = (CollisionLink ) value ;
385+ if (value instanceof CollisionLink thisCollisionLink ) {
388386 setRawValue (lastIndex , new CollisionLink (collisionLink .value , thisCollisionLink .next ));
389387 } else {
390388 setRawValue (lastIndex , collisionLink .value );
@@ -581,16 +579,16 @@ private void putHashEntry(Object key, int entryIndex, boolean rehashOnCollision)
581579 setHashArray (hashIndex , entryIndex + 1 );
582580 Object value = getRawValue (entryIndex );
583581 if (oldIndex != -1 ) {
584- assert entryIndex != oldIndex : "this cannot happen and would create an endless collision link cycle" ;
585- if (value instanceof CollisionLink ) {
586- CollisionLink collisionLink = (CollisionLink ) value ;
582+ if (entryIndex == oldIndex ) {
583+ throw new InternalError ("endless collision link cycle, most likely due to unsynchronized concurrent access" );
584+ }
585+ if (value instanceof CollisionLink collisionLink ) {
587586 setRawValue (entryIndex , new CollisionLink (collisionLink .value , oldIndex ));
588587 } else {
589588 setRawValue (entryIndex , new CollisionLink (getRawValue (entryIndex ), oldIndex ));
590589 }
591590 } else {
592- if (value instanceof CollisionLink ) {
593- CollisionLink collisionLink = (CollisionLink ) value ;
591+ if (value instanceof CollisionLink collisionLink ) {
594592 setRawValue (entryIndex , collisionLink .value );
595593 }
596594 }
@@ -700,6 +698,7 @@ public void remove() {
700698 }
701699 }
702700
701+ @ SuppressWarnings ({"rawtypes" , "unchecked" })
703702 @ Override
704703 public Iterable <V > getValues () {
705704 return new Iterable <>() {
@@ -811,8 +810,7 @@ private void setKey(int index, Object newValue) {
811810
812811 private void setValue (int index , Object newValue ) {
813812 Object oldValue = getRawValue (index );
814- if (oldValue instanceof CollisionLink ) {
815- CollisionLink collisionLink = (CollisionLink ) oldValue ;
813+ if (oldValue instanceof CollisionLink collisionLink ) {
816814 setRawValue (index , new CollisionLink (newValue , collisionLink .next ));
817815 } else {
818816 setRawValue (index , newValue );
@@ -859,6 +857,7 @@ static <K, V> String toString(boolean isSet, int size, MapCursor<K, V> cursor) {
859857 return builder .toString ();
860858 }
861859
860+ @ SuppressWarnings ({"rawtypes" , "unchecked" })
862861 @ Override
863862 public Iterator <K > iterator () {
864863 return new SparseMapIterator <>() {
0 commit comments