Skip to content

Commit 34652b1

Browse files
Abduqodiri Qurbonzodaqurbonzoda
authored andcommitted
Fix setValue method of MutableMapEntry
1 parent 9ea68d0 commit 34652b1

File tree

2 files changed

+59
-23
lines changed

2 files changed

+59
-23
lines changed

core/commonMain/src/implementations/immutableMap/PersistentHashMapBuilderContentIterators.kt

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,37 @@ package kotlinx.collections.immutable.implementations.immutableMap
88
import kotlinx.collections.immutable.internal.assert
99

1010

11-
internal class TrieNodeMutableEntriesIterator<K, V>(private val builder: PersistentHashMapBuilder<K, V>)
12-
: TrieNodeBaseIterator<K, V, MutableMap.MutableEntry<K, V>>() {
11+
internal class TrieNodeMutableEntriesIterator<K, V>(
12+
private val parentIterator: PersistentHashMapBuilderEntriesIterator<K, V>
13+
) : TrieNodeBaseIterator<K, V, MutableMap.MutableEntry<K, V>>() {
1314

1415
override fun next(): MutableMap.MutableEntry<K, V> {
1516
assert(hasNextKey())
1617
index += 2
1718
@Suppress("UNCHECKED_CAST")
18-
return MutableMapEntry(builder, buffer[index - 2] as K, buffer[index - 1] as V)
19+
return MutableMapEntry(parentIterator, buffer[index - 2] as K, buffer[index - 1] as V)
1920
}
2021
}
2122

22-
private class MutableMapEntry<K, V>(private val builder: PersistentHashMapBuilder<K, V>,
23-
key: K,
24-
override var value: V) : MapEntry<K, V>(key, value), MutableMap.MutableEntry<K, V> {
23+
private class MutableMapEntry<K, V>(
24+
private val parentIterator: PersistentHashMapBuilderEntriesIterator<K, V>,
25+
key: K,
26+
override var value: V
27+
) : MapEntry<K, V>(key, value), MutableMap.MutableEntry<K, V> {
28+
2529
override fun setValue(newValue: V): V {
2630
val result = value
2731
value = newValue
28-
builder[key] = newValue
32+
parentIterator.setValue(key, newValue)
2933
return result
3034
}
3135
}
3236

3337

34-
internal abstract class PersistentHashMapBuilderBaseIterator<K, V, T>(private val builder: PersistentHashMapBuilder<K, V>,
35-
path: Array<TrieNodeBaseIterator<K, V, T>>)
36-
: MutableIterator<T>, PersistentHashMapBaseIterator<K, V, T>(builder.node, path) {
38+
internal open class PersistentHashMapBuilderBaseIterator<K, V, T>(
39+
private val builder: PersistentHashMapBuilder<K, V>,
40+
path: Array<TrieNodeBaseIterator<K, V, T>>
41+
) : MutableIterator<T>, PersistentHashMapBaseIterator<K, V, T>(builder.node, path) {
3742

3843
private var lastIteratedKey: K? = null
3944
private var nextWasInvoked = false
@@ -62,8 +67,33 @@ internal abstract class PersistentHashMapBuilderBaseIterator<K, V, T>(private va
6267
expectedModCount = builder.modCount
6368
}
6469

70+
fun setValue(key: K, newValue: V) {
71+
if (!builder.containsKey(key)) return
72+
73+
if (hasNext()) {
74+
val currentKey = currentKey()
75+
76+
builder[key] = newValue
77+
resetPath(currentKey.hashCode(), builder.node, currentKey, 0)
78+
} else {
79+
builder[key] = newValue
80+
}
81+
82+
expectedModCount = builder.modCount
83+
}
84+
6585
private fun resetPath(keyHash: Int, node: TrieNode<*, *>, key: K, pathIndex: Int) {
6686
val shift = pathIndex * LOG_MAX_BRANCHING_FACTOR
87+
88+
if (shift > MAX_SHIFT) { // collision
89+
path[pathIndex].reset(node.buffer, node.buffer.size, 0)
90+
while (path[pathIndex].currentKey() != key) {
91+
path[pathIndex].moveToNextKey()
92+
}
93+
pathLastIndex = pathIndex
94+
return
95+
}
96+
6797
val keyPositionMask = 1 shl indexSegment(keyHash, shift)
6898

6999
if (node.hasEntryAt(keyPositionMask)) { // key is directly in buffer
@@ -72,22 +102,16 @@ internal abstract class PersistentHashMapBuilderBaseIterator<K, V, T>(private va
72102
// assert(node.keyAtIndex(keyIndex) == key)
73103

74104
path[pathIndex].reset(node.buffer, ENTRY_SIZE * node.entryCount(), keyIndex)
105+
pathLastIndex = pathIndex
75106
return
76107
}
77108

78-
// assert(node.hasNodeAt(keyPosition)) // key is in node
109+
// assert(node.hasNodeAt(keyPositionMask)) // key is in node
79110

80111
val nodeIndex = node.nodeIndex(keyPositionMask)
81112
val targetNode = node.nodeAtIndex(nodeIndex)
82-
if (shift == MAX_SHIFT) { // collision
83-
path[pathIndex].reset(node.buffer, node.buffer.size, 0)
84-
while (path[pathIndex].currentKey() != key) {
85-
path[pathIndex].moveToNextKey()
86-
}
87-
} else {
88-
path[pathIndex].reset(node.buffer, ENTRY_SIZE * node.entryCount(), nodeIndex)
89-
resetPath(keyHash, targetNode, key, pathIndex + 1)
90-
}
113+
path[pathIndex].reset(node.buffer, ENTRY_SIZE * node.entryCount(), nodeIndex)
114+
resetPath(keyHash, targetNode, key, pathIndex + 1)
91115
}
92116

93117
private fun checkNextWasInvoked() {
@@ -101,8 +125,20 @@ internal abstract class PersistentHashMapBuilderBaseIterator<K, V, T>(private va
101125
}
102126
}
103127

104-
internal class PersistentHashMapBuilderEntriesIterator<K, V>(builder: PersistentHashMapBuilder<K, V>)
105-
: PersistentHashMapBuilderBaseIterator<K, V, MutableMap.MutableEntry<K, V>>(builder, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeMutableEntriesIterator<K, V>(builder) })
128+
internal class PersistentHashMapBuilderEntriesIterator<K, V>(
129+
builder: PersistentHashMapBuilder<K, V>
130+
) : MutableIterator<MutableMap.MutableEntry<K, V>> {
131+
private val base = PersistentHashMapBuilderBaseIterator<K, V, MutableMap.MutableEntry<K, V>>(
132+
builder,
133+
Array(TRIE_MAX_HEIGHT + 1) { TrieNodeMutableEntriesIterator(this) }
134+
)
135+
136+
override fun hasNext(): Boolean = base.hasNext()
137+
override fun next(): MutableMap.MutableEntry<K, V> = base.next()
138+
override fun remove(): Unit = base.remove()
139+
140+
fun setValue(key: K, newValue: V): Unit = base.setValue(key, newValue)
141+
}
106142

107143
internal class PersistentHashMapBuilderKeysIterator<K, V>(builder: PersistentHashMapBuilder<K, V>)
108144
: PersistentHashMapBuilderBaseIterator<K, V, K>(builder, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeKeysIterator<K, V>() })

core/commonMain/src/implementations/immutableMap/PersistentHashMapContentIterators.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ internal abstract class PersistentHashMapBaseIterator<K, V, T>(
103103
protected val path: Array<TrieNodeBaseIterator<K, V, T>>
104104
) : Iterator<T> {
105105

106-
private var pathLastIndex = 0
106+
protected var pathLastIndex = 0
107107
@JsName("_hasNext")
108108
private var hasNext = true
109109

0 commit comments

Comments
 (0)