final void splitSegmentAndPut(SmoothieMap<K, V> map, long hash, K key, V value) { int mc = map.modCount; cancelAllocBeyondCapacity(map); int segments = map.segments(); int tierDiff = map.segmentsTier - this.tier; // Double segments array, if needed if (tierDiff == 0) { map.doubleSegments(); segments *= 2; tierDiff = 1; } // Create a new Segment and replace half indexes pointing to the old segment with // refs to the new int segmentOccursEach = segments >>> tierDiff; int lowestSegmentIndex = (int) (hash & (segmentOccursEach - 1)); int newTier = this.tier += 1; Segment<K, V> higherSegment = map.makeSegment(newTier); for (int segmentIndex = lowestSegmentIndex + segmentOccursEach; segmentIndex < segments; segmentIndex += segmentOccursEach * 2) { map.segments[segmentIndex] = higherSegment; } // Rebalance entries between two segments int balance = 0; for (long slotIndex = 0, slot; slotIndex < HASH_TABLE_SIZE; slotIndex++) { if ((slot = readSlot(slotIndex)) != 0) { long allocIndex; K k; long kHash = map.keyHashCode(k = readKey(allocIndex = allocIndex(slot))); if ((kHash & segmentOccursEach) != 0) { V v = readValue(allocIndex); eraseAlloc(allocIndex); if (shiftRemove(slotIndex) != slotIndex) slotIndex--; // don't skip shifted slot higherSegment.putOnSplit(map, kHash, k, v); balance++; } } } // Check rebalanced something, otherwise we are going to split segments infinitely // ending up with OutOfMemoryError if (balance == 0) checkHashCodesAreNotAllSame(map); if (balance >= map.allocCapacity) higherSegment.checkHashCodesAreNotAllSame(map); // Finally, put the entry Segment<K, V> segmentForPut; segmentForPut = (hash & segmentOccursEach) != 0 ? higherSegment : this; segmentForPut.put(map, hash, key, value, false); mc++; if (mc != map.modCount) throw new ConcurrentModificationException(); }