Skip to content

Commit ced6899

Browse files
author
Abduqodiri Qurbonzoda
committed
Implement map TrieNode canonicalization
1 parent 71e95be commit ced6899

File tree

1 file changed

+50
-51
lines changed
  • core/commonMain/src/implementations/immutableMap

1 file changed

+50
-51
lines changed

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

Lines changed: 50 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,22 @@ private fun Array<Any?>.replaceEntryWithNode(keyIndex: Int, nodeIndex: Int, newN
4242
return newBuffer
4343
}
4444

45+
private fun <K, V> Array<Any?>.replaceNodeWithEntry(nodeIndex: Int, keyIndex: Int, key: K, value: V): Array<Any?> {
46+
val newBuffer = this.copyOf(this.size + 1)
47+
newBuffer.copyInto(newBuffer, nodeIndex + 2, nodeIndex + 1, this.size)
48+
newBuffer.copyInto(newBuffer, keyIndex + 2, keyIndex , nodeIndex)
49+
newBuffer[keyIndex] = key
50+
newBuffer[keyIndex + 1] = value
51+
return newBuffer
52+
}
53+
4554
private fun Array<Any?>.removeEntryAtIndex(keyIndex: Int): Array<Any?> {
4655
val newBuffer = arrayOfNulls<Any?>(this.size - ENTRY_SIZE)
4756
this.copyInto(newBuffer, endIndex = keyIndex)
4857
this.copyInto(newBuffer, keyIndex, startIndex = keyIndex + ENTRY_SIZE, endIndex = this.size)
4958
return newBuffer
5059
}
5160

52-
private fun Array<Any?>.removeNodeAtIndex(nodeIndex: Int): Array<Any?> {
53-
val newBuffer = arrayOfNulls<Any?>(this.size - 1)
54-
this.copyInto(newBuffer, endIndex = nodeIndex)
55-
this.copyInto(newBuffer, nodeIndex, startIndex = nodeIndex + 1, endIndex = this.size)
56-
return newBuffer
57-
}
58-
5961

6062

6163
internal class TrieNode<K, V>(
@@ -170,17 +172,38 @@ internal class TrieNode<K, V>(
170172
return TrieNode(dataMap, nodeMap, newBuffer, mutator.ownership)
171173
}
172174

173-
private fun updateNodeAtIndex(nodeIndex: Int, newNode: TrieNode<K, V>): TrieNode<K, V> {
175+
private fun updateNodeAtIndex(nodeIndex: Int, positionMask: Int, newNode: TrieNode<K, V>): TrieNode<K, V> {
174176
// assert(buffer[nodeIndex] !== newNode)
177+
val newNodeBuffer = newNode.buffer
178+
if (newNodeBuffer.size == 2 && newNode.nodeMap == 0) {
179+
val keyIndex = entryKeyIndex(positionMask)
180+
val newBuffer = buffer.replaceNodeWithEntry(nodeIndex, keyIndex, newNodeBuffer[0], newNodeBuffer[1])
181+
return TrieNode(dataMap xor positionMask, nodeMap xor positionMask, newBuffer)
182+
}
175183

176-
val newBuffer = buffer.copyOf()
184+
val newBuffer = buffer.copyOf(buffer.size)
177185
newBuffer[nodeIndex] = newNode
178186
return TrieNode(dataMap, nodeMap, newBuffer)
179187
}
180188

181-
private fun mutableUpdateNodeAtIndex(nodeIndex: Int, newNode: TrieNode<K, V>, owner: MutabilityOwnership): TrieNode<K, V> {
189+
private fun mutableUpdateNodeAtIndex(nodeIndex: Int, positionMask: Int, newNode: TrieNode<K, V>, owner: MutabilityOwnership): TrieNode<K, V> {
182190
// assert(buffer[nodeIndex] !== newNode)
183191

192+
val newNodeBuffer = newNode.buffer
193+
if (newNodeBuffer.size == 2 && newNode.nodeMap == 0) {
194+
val keyIndex = entryKeyIndex(positionMask)
195+
val newBuffer = buffer.replaceNodeWithEntry(nodeIndex, keyIndex, newNodeBuffer[0], newNodeBuffer[1])
196+
197+
if (ownedBy === owner) {
198+
buffer = newBuffer
199+
dataMap = dataMap xor positionMask
200+
nodeMap = nodeMap xor positionMask
201+
return this
202+
}
203+
204+
return TrieNode(dataMap xor positionMask, nodeMap xor positionMask, newBuffer)
205+
}
206+
184207
if (ownedBy === owner) {
185208
buffer[nodeIndex] = newNode
186209
return this
@@ -255,6 +278,7 @@ internal class TrieNode<K, V>(
255278

256279
private fun removeEntryAtIndex(keyIndex: Int, positionMask: Int): TrieNode<K, V>? {
257280
// assert(hasEntryAt(positionMask))
281+
// It is possible only when this node is the root node
258282
if (buffer.size == ENTRY_SIZE) return null
259283

260284
val newBuffer = buffer.removeEntryAtIndex(keyIndex)
@@ -296,27 +320,6 @@ internal class TrieNode<K, V>(
296320
return TrieNode(0, 0, newBuffer, mutator.ownership)
297321
}
298322

299-
private fun removeNodeAtIndex(nodeIndex: Int, positionMask: Int): TrieNode<K, V>? {
300-
// assert(hasNodeAt(positionMask))
301-
if (buffer.size == 1) return null
302-
303-
val newBuffer = buffer.removeNodeAtIndex(nodeIndex)
304-
return TrieNode(dataMap, nodeMap xor positionMask, newBuffer)
305-
}
306-
307-
private fun mutableRemoveNodeAtIndex(nodeIndex: Int, positionMask: Int, owner: MutabilityOwnership): TrieNode<K, V>? {
308-
// assert(hasNodeAt(positionMask))
309-
if (buffer.size == 1) return null
310-
311-
if (ownedBy === owner) {
312-
buffer = buffer.removeNodeAtIndex(nodeIndex)
313-
nodeMap = nodeMap xor positionMask
314-
return this
315-
}
316-
val newBuffer = buffer.removeNodeAtIndex(nodeIndex)
317-
return TrieNode(dataMap, nodeMap xor positionMask, newBuffer, owner)
318-
}
319-
320323
private fun collisionContainsKey(key: K): Boolean {
321324
for (i in 0 until buffer.size step ENTRY_SIZE) {
322325
if (key == buffer[i]) return true
@@ -473,7 +476,7 @@ internal class TrieNode<K, V>(
473476
} else {
474477
targetNode.put(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR) ?: return null
475478
}
476-
return putResult.replaceNode { node -> updateNodeAtIndex(nodeIndex, node) }
479+
return putResult.replaceNode { node -> updateNodeAtIndex(nodeIndex, keyPositionMask, node) }
477480
}
478481

479482
// no entry at this key hash segment
@@ -509,7 +512,7 @@ internal class TrieNode<K, V>(
509512
if (targetNode === newNode) {
510513
return this
511514
}
512-
return mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
515+
return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
513516
}
514517

515518
// key is absent
@@ -537,11 +540,9 @@ internal class TrieNode<K, V>(
537540
} else {
538541
targetNode.remove(keyHash, key, shift + LOG_MAX_BRANCHING_FACTOR)
539542
}
540-
return when {
541-
targetNode === newNode -> this
542-
newNode == null -> removeNodeAtIndex(nodeIndex, keyPositionMask)
543-
else -> updateNodeAtIndex(nodeIndex, newNode)
544-
}
543+
checkNotNull(newNode)
544+
if (targetNode === newNode) return this
545+
return updateNodeAtIndex(nodeIndex, keyPositionMask, newNode)
545546
}
546547

547548
// key is absent
@@ -568,11 +569,11 @@ internal class TrieNode<K, V>(
568569
} else {
569570
targetNode.mutableRemove(keyHash, key, shift + LOG_MAX_BRANCHING_FACTOR, mutator)
570571
}
571-
return when {
572-
targetNode === newNode -> this
573-
newNode == null -> mutableRemoveNodeAtIndex(nodeIndex, keyPositionMask, mutator.ownership)
574-
else -> mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
572+
checkNotNull(newNode)
573+
if (ownedBy === mutator.ownership || targetNode !== newNode) {
574+
return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
575575
}
576+
return this
576577
}
577578

578579
// key is absent
@@ -599,11 +600,9 @@ internal class TrieNode<K, V>(
599600
} else {
600601
targetNode.remove(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR)
601602
}
602-
return when {
603-
targetNode === newNode -> this
604-
newNode == null -> removeNodeAtIndex(nodeIndex, keyPositionMask)
605-
else -> updateNodeAtIndex(nodeIndex, newNode)
606-
}
603+
checkNotNull(newNode)
604+
if (targetNode === newNode) return this
605+
return updateNodeAtIndex(nodeIndex, keyPositionMask, newNode)
607606
}
608607

609608
// key is absent
@@ -630,11 +629,11 @@ internal class TrieNode<K, V>(
630629
} else {
631630
targetNode.mutableRemove(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR, mutator)
632631
}
633-
return when {
634-
targetNode === newNode -> this
635-
newNode == null -> mutableRemoveNodeAtIndex(nodeIndex, keyPositionMask, mutator.ownership)
636-
else -> mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
632+
checkNotNull(newNode)
633+
if (ownedBy === mutator.ownership || targetNode !== newNode) {
634+
return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
637635
}
636+
return this
638637
}
639638

640639
// key is absent

0 commit comments

Comments
 (0)