Skip to content

Commit 9a8b081

Browse files
committed
Replace ModificationWrapper with ModificationResult
It's created only when some change to the map is made.
1 parent 36ffd1d commit 9a8b081

File tree

2 files changed

+23
-30
lines changed

2 files changed

+23
-30
lines changed

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/immutableMap/PersistentHashMap.kt

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ package kotlinx.collections.immutable.implementations.immutableMap
1818

1919
import kotlinx.collections.immutable.*
2020

21-
internal const val NO_MODIFICATION = 0
22-
internal const val UPDATE_VALUE = 1
23-
internal const val PUT_KEY_VALUE = 2
24-
internal class ModificationWrapper(var value: Int = NO_MODIFICATION)
25-
26-
2721
internal class PersistentHashMap<K, V>(internal val node: TrieNode<K, V>,
2822
override val size: Int): AbstractMap<K, V>(), PersistentMap<K, V> {
2923

@@ -61,11 +55,8 @@ internal class PersistentHashMap<K, V>(internal val node: TrieNode<K, V>,
6155
}
6256

6357
override fun put(key: K, value: @UnsafeVariance V): PersistentHashMap<K, V> {
64-
val modification = ModificationWrapper()
65-
val newNode = node.put(key.hashCode(), key, value, 0, modification)
66-
if (node === newNode) { return this }
67-
val sizeDelta = if (modification.value == PUT_KEY_VALUE) 1 else 0
68-
return PersistentHashMap(newNode, size + sizeDelta)
58+
val newNodeResult = node.put(key.hashCode(), key, value, 0) ?: return this
59+
return PersistentHashMap(newNodeResult.node, size + newNodeResult.sizeDelta)
6960
}
7061

7162
override fun remove(key: K): PersistentHashMap<K, V> {

kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/immutableMap/TrieNode.kt

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ internal class TrieNode<K, V>(
7575
) {
7676
constructor(dataMap: Int, nodeMap: Int, buffer: Array<Any?>) : this(dataMap, nodeMap, buffer, null)
7777

78+
internal class ModificationResult<K, V>(var node: TrieNode<K, V>, val sizeDelta: Int) {
79+
inline fun replaceNode(operation: (TrieNode<K, V>) -> TrieNode<K, V>): ModificationResult<K, V> =
80+
apply { node = operation(node) }
81+
}
82+
83+
private fun asInsertResult() = ModificationResult(this, 1)
84+
private fun asUpdateResult() = ModificationResult(this, 0)
85+
7886
internal var buffer: Array<Any?> = buffer
7987
private set
8088

@@ -333,21 +341,19 @@ internal class TrieNode<K, V>(
333341
return null
334342
}
335343

336-
private fun collisionPut(key: K, value: V, modification: ModificationWrapper): TrieNode<K, V> {
344+
private fun collisionPut(key: K, value: V): ModificationResult<K, V>? {
337345
for (i in 0 until buffer.size step ENTRY_SIZE) {
338346
if (key == buffer[i]) {
339347
if (value === buffer[i + 1]) {
340-
return this
348+
return null
341349
}
342-
modification.value = UPDATE_VALUE
343350
val newBuffer = buffer.copyOf()
344351
newBuffer[i + 1] = value
345-
return TrieNode(0, 0, newBuffer)
352+
return TrieNode<K, V>(0, 0, newBuffer).asUpdateResult()
346353
}
347354
}
348-
modification.value = PUT_KEY_VALUE
349355
val newBuffer = buffer.insertEntryAtIndex(0, key, value)
350-
return TrieNode(0, 0, newBuffer)
356+
return TrieNode<K, V>(0, 0, newBuffer).asInsertResult()
351357
}
352358

353359
private fun mutableCollisionPut(key: K, value: V, mutator: PersistentHashMapBuilder<K, V>): TrieNode<K, V> {
@@ -454,37 +460,33 @@ internal class TrieNode<K, V>(
454460
return null
455461
}
456462

457-
fun put(keyHash: Int, key: K, value: @UnsafeVariance V, shift: Int, modification: ModificationWrapper): TrieNode<K, V> {
463+
fun put(keyHash: Int, key: K, value: @UnsafeVariance V, shift: Int): ModificationResult<K, V>? {
458464
val keyPositionMask = 1 shl indexSegment(keyHash, shift)
459465

460466
if (hasEntryAt(keyPositionMask)) { // key is directly in buffer
461467
val keyIndex = entryKeyIndex(keyPositionMask)
462468

463469
if (key == keyAtIndex(keyIndex)) {
464-
modification.value = UPDATE_VALUE
465-
if (valueAtKeyIndex(keyIndex) === value) return this
470+
if (valueAtKeyIndex(keyIndex) === value) return null
466471

467-
return updateValueAtIndex(keyIndex, value)
472+
return updateValueAtIndex(keyIndex, value).asUpdateResult()
468473
}
469-
modification.value = PUT_KEY_VALUE
470-
return moveEntryToNode(keyIndex, keyPositionMask, keyHash, key, value, shift)
474+
return moveEntryToNode(keyIndex, keyPositionMask, keyHash, key, value, shift).asInsertResult()
471475
}
472476
if (hasNodeAt(keyPositionMask)) { // key is in node
473477
val nodeIndex = nodeIndex(keyPositionMask)
474478

475479
val targetNode = nodeAtIndex(nodeIndex)
476-
val newNode = if (shift == MAX_SHIFT) {
477-
targetNode.collisionPut(key, value, modification)
480+
val putResult = if (shift == MAX_SHIFT) {
481+
targetNode.collisionPut(key, value) ?: return null
478482
} else {
479-
targetNode.put(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR, modification)
483+
targetNode.put(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR) ?: return null
480484
}
481-
if (targetNode === newNode) return this
482-
return updateNodeAtIndex(nodeIndex, newNode)
485+
return putResult.replaceNode { node -> updateNodeAtIndex(nodeIndex, node) }
483486
}
484487

485488
// no entry at this key hash segment
486-
modification.value = PUT_KEY_VALUE
487-
return insertEntryAt(keyPositionMask, key, value)
489+
return insertEntryAt(keyPositionMask, key, value).asInsertResult()
488490
}
489491

490492
fun mutablePut(keyHash: Int, key: K, value: @UnsafeVariance V, shift: Int, mutator: PersistentHashMapBuilder<K, V>): TrieNode<K, V> {

0 commit comments

Comments
 (0)