[K/N] Catch concurrent modifications of HashMap
As a part of efforts to stabilize Native stdlib.
This commit is contained in:
committed by
Space Team
parent
9d8d9d000f
commit
af1630e270
@@ -25,6 +25,18 @@ internal class MapBuilder<K, V> private constructor(
|
||||
) : MutableMap<K, V>, Serializable {
|
||||
private var hashShift: Int = computeShift(hashSize)
|
||||
|
||||
/**
|
||||
* The number of times this map is structurally modified.
|
||||
*
|
||||
* A modification is considered to be structural if it changes the map size,
|
||||
* or otherwise changes it in a way that iterations in progress may return incorrect results.
|
||||
*
|
||||
* This value can be used by iterators of the [keys], [values] and [entries] views
|
||||
* to provide fail-fast behavoir when a concurrent modification is detected during iteration.
|
||||
* [ConcurrentModificationException] will be thrown in this case.
|
||||
*/
|
||||
private var modCount: Int = 0
|
||||
|
||||
override var size: Int = 0
|
||||
private set
|
||||
|
||||
@@ -112,6 +124,7 @@ internal class MapBuilder<K, V> private constructor(
|
||||
valuesArray?.resetRange(0, length)
|
||||
size = 0
|
||||
length = 0
|
||||
registerModification()
|
||||
}
|
||||
|
||||
override val keys: MutableSet<K> get() {
|
||||
@@ -176,6 +189,10 @@ internal class MapBuilder<K, V> private constructor(
|
||||
internal val capacity: Int get() = keysArray.size
|
||||
private val hashSize: Int get() = hashArray.size
|
||||
|
||||
private fun registerModification() {
|
||||
modCount += 1
|
||||
}
|
||||
|
||||
internal fun checkIsMutable() {
|
||||
if (isReadOnly) throw UnsupportedOperationException()
|
||||
}
|
||||
@@ -237,6 +254,7 @@ internal class MapBuilder<K, V> private constructor(
|
||||
}
|
||||
|
||||
private fun rehash(newHashSize: Int) {
|
||||
registerModification()
|
||||
if (length > size) compact()
|
||||
if (newHashSize != hashSize) {
|
||||
hashArray = IntArray(newHashSize)
|
||||
@@ -308,6 +326,7 @@ internal class MapBuilder<K, V> private constructor(
|
||||
presenceArray[putIndex] = hash
|
||||
hashArray[hash] = putIndex + 1
|
||||
size++
|
||||
registerModification()
|
||||
if (probeDistance > maxProbeDistance) maxProbeDistance = probeDistance
|
||||
return putIndex
|
||||
}
|
||||
@@ -336,6 +355,7 @@ internal class MapBuilder<K, V> private constructor(
|
||||
removeHashAt(presenceArray[index])
|
||||
presenceArray[index] = TOMBSTONE
|
||||
size--
|
||||
registerModification()
|
||||
}
|
||||
|
||||
private fun removeHashAt(removedHash: Int) {
|
||||
@@ -477,6 +497,7 @@ internal class MapBuilder<K, V> private constructor(
|
||||
) {
|
||||
internal var index = 0
|
||||
internal var lastIndex: Int = -1
|
||||
private var expectedModCount: Int = map.modCount
|
||||
|
||||
init {
|
||||
initNext()
|
||||
@@ -490,15 +511,23 @@ internal class MapBuilder<K, V> private constructor(
|
||||
fun hasNext(): Boolean = index < map.length
|
||||
|
||||
fun remove() {
|
||||
checkForComodification()
|
||||
check(lastIndex != -1) { "Call next() before removing element from the iterator." }
|
||||
map.checkIsMutable()
|
||||
map.removeKeyAt(lastIndex)
|
||||
lastIndex = -1
|
||||
expectedModCount = map.modCount
|
||||
}
|
||||
|
||||
internal fun checkForComodification() {
|
||||
if (map.modCount != expectedModCount)
|
||||
throw ConcurrentModificationException()
|
||||
}
|
||||
}
|
||||
|
||||
internal class KeysItr<K, V>(map: MapBuilder<K, V>) : Itr<K, V>(map), MutableIterator<K> {
|
||||
override fun next(): K {
|
||||
checkForComodification()
|
||||
if (index >= map.length) throw NoSuchElementException()
|
||||
lastIndex = index++
|
||||
val result = map.keysArray[lastIndex]
|
||||
@@ -510,6 +539,7 @@ internal class MapBuilder<K, V> private constructor(
|
||||
|
||||
internal class ValuesItr<K, V>(map: MapBuilder<K, V>) : Itr<K, V>(map), MutableIterator<V> {
|
||||
override fun next(): V {
|
||||
checkForComodification()
|
||||
if (index >= map.length) throw NoSuchElementException()
|
||||
lastIndex = index++
|
||||
val result = map.valuesArray!![lastIndex]
|
||||
@@ -521,6 +551,7 @@ internal class MapBuilder<K, V> private constructor(
|
||||
internal class EntriesItr<K, V>(map: MapBuilder<K, V>) : Itr<K, V>(map),
|
||||
MutableIterator<MutableMap.MutableEntry<K, V>> {
|
||||
override fun next(): EntryRef<K, V> {
|
||||
checkForComodification()
|
||||
if (index >= map.length) throw NoSuchElementException()
|
||||
lastIndex = index++
|
||||
val result = EntryRef(map, lastIndex)
|
||||
|
||||
Reference in New Issue
Block a user