@@ -52,20 +52,22 @@ private fun Array<Any?>.replaceEntryWithNode(keyIndex: Int, nodeIndex: Int, newN
52
52
return newBuffer
53
53
}
54
54
55
+ private fun <K , V > Array<Any?>.replaceNodeWithEntry (nodeIndex : Int , keyIndex : Int , key : K , value : V ): Array <Any ?> {
56
+ val newBuffer = this .copyOf(this .size + 1 )
57
+ newBuffer.copyInto(newBuffer, nodeIndex + 2 , nodeIndex + 1 , this .size)
58
+ newBuffer.copyInto(newBuffer, keyIndex + 2 , keyIndex , nodeIndex)
59
+ newBuffer[keyIndex] = key
60
+ newBuffer[keyIndex + 1 ] = value
61
+ return newBuffer
62
+ }
63
+
55
64
private fun Array<Any?>.removeEntryAtIndex (keyIndex : Int ): Array <Any ?> {
56
65
val newBuffer = arrayOfNulls<Any ?>(this .size - ENTRY_SIZE )
57
66
this .copyInto(newBuffer, endIndex = keyIndex)
58
67
this .copyInto(newBuffer, keyIndex, startIndex = keyIndex + ENTRY_SIZE , endIndex = this .size)
59
68
return newBuffer
60
69
}
61
70
62
- private fun Array<Any?>.removeNodeAtIndex (nodeIndex : Int ): Array <Any ?> {
63
- val newBuffer = arrayOfNulls<Any ?>(this .size - 1 )
64
- this .copyInto(newBuffer, endIndex = nodeIndex)
65
- this .copyInto(newBuffer, nodeIndex, startIndex = nodeIndex + 1 , endIndex = this .size)
66
- return newBuffer
67
- }
68
-
69
71
70
72
71
73
internal class TrieNode <K , V >(
@@ -181,17 +183,40 @@ internal class TrieNode<K, V>(
181
183
return TrieNode (dataMap, nodeMap, newBuffer, mutator.ownership)
182
184
}
183
185
184
- private fun updateNodeAtIndex (nodeIndex : Int , newNode : TrieNode <K , V >): TrieNode <K , V > {
186
+ private fun updateNodeAtIndex (nodeIndex : Int , positionMask : Int , newNode : TrieNode <K , V >): TrieNode <K , V > {
185
187
// assert(buffer[nodeIndex] !== newNode)
188
+ // TODO: check how this changes affect `put` and non-collision `remove` operations performance.
186
189
187
- val newBuffer = buffer.copyOf()
190
+ val newNodeBuffer = newNode.buffer
191
+ if (newNodeBuffer.size == 2 && newNode.nodeMap == 0 ) {
192
+ val keyIndex = entryKeyIndex(positionMask)
193
+ val newBuffer = buffer.replaceNodeWithEntry(nodeIndex, keyIndex, newNodeBuffer[0 ], newNodeBuffer[1 ])
194
+ return TrieNode (dataMap xor positionMask, nodeMap xor positionMask, newBuffer)
195
+ }
196
+
197
+ val newBuffer = buffer.copyOf(buffer.size)
188
198
newBuffer[nodeIndex] = newNode
189
199
return TrieNode (dataMap, nodeMap, newBuffer)
190
200
}
191
201
192
- private fun mutableUpdateNodeAtIndex (nodeIndex : Int , newNode : TrieNode <K , V >, owner : MutabilityOwnership ): TrieNode <K , V > {
202
+ private fun mutableUpdateNodeAtIndex (nodeIndex : Int , positionMask : Int , newNode : TrieNode <K , V >, owner : MutabilityOwnership ): TrieNode <K , V > {
193
203
// assert(buffer[nodeIndex] !== newNode)
194
204
205
+ val newNodeBuffer = newNode.buffer
206
+ if (newNodeBuffer.size == 2 && newNode.nodeMap == 0 ) {
207
+ val keyIndex = entryKeyIndex(positionMask)
208
+ val newBuffer = buffer.replaceNodeWithEntry(nodeIndex, keyIndex, newNodeBuffer[0 ], newNodeBuffer[1 ])
209
+
210
+ if (ownedBy == = owner) {
211
+ buffer = newBuffer
212
+ dataMap = dataMap xor positionMask
213
+ nodeMap = nodeMap xor positionMask
214
+ return this
215
+ }
216
+
217
+ return TrieNode (dataMap xor positionMask, nodeMap xor positionMask, newBuffer)
218
+ }
219
+
195
220
if (ownedBy == = owner) {
196
221
buffer[nodeIndex] = newNode
197
222
return this
@@ -282,6 +307,7 @@ internal class TrieNode<K, V>(
282
307
283
308
private fun removeEntryAtIndex (keyIndex : Int , positionMask : Int ): TrieNode <K , V >? {
284
309
// assert(hasEntryAt(positionMask))
310
+ // It is possible only when this node is the root node
285
311
if (buffer.size == ENTRY_SIZE ) return null
286
312
287
313
val newBuffer = buffer.removeEntryAtIndex(keyIndex)
@@ -323,27 +349,6 @@ internal class TrieNode<K, V>(
323
349
return makeCollisionNode(newBuffer, mutator.ownership)
324
350
}
325
351
326
- private fun removeNodeAtIndex (nodeIndex : Int , positionMask : Int ): TrieNode <K , V >? {
327
- // assert(hasNodeAt(positionMask))
328
- if (buffer.size == 1 ) return null
329
-
330
- val newBuffer = buffer.removeNodeAtIndex(nodeIndex)
331
- return TrieNode (dataMap, nodeMap xor positionMask, newBuffer)
332
- }
333
-
334
- private fun mutableRemoveNodeAtIndex (nodeIndex : Int , positionMask : Int , owner : MutabilityOwnership ): TrieNode <K , V >? {
335
- // assert(hasNodeAt(positionMask))
336
- if (buffer.size == 1 ) return null
337
-
338
- if (ownedBy == = owner) {
339
- buffer = buffer.removeNodeAtIndex(nodeIndex)
340
- nodeMap = nodeMap xor positionMask
341
- return this
342
- }
343
- val newBuffer = buffer.removeNodeAtIndex(nodeIndex)
344
- return TrieNode (dataMap, nodeMap xor positionMask, newBuffer, owner)
345
- }
346
-
347
352
private fun collisionContainsKey (key : K ): Boolean {
348
353
val collisionHash = keyAtIndex(0 ).hashCode()
349
354
val keyHash = key.hashCode()
@@ -559,7 +564,7 @@ internal class TrieNode<K, V>(
559
564
560
565
val targetNode = nodeAtIndex(nodeIndex)
561
566
val putResult = targetNode.put(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR ) ? : return null
562
- return putResult.replaceNode { node -> updateNodeAtIndex(nodeIndex, node) }
567
+ return putResult.replaceNode { node -> updateNodeAtIndex(nodeIndex, keyPositionMask, node) }
563
568
}
564
569
565
570
// no entry at this key hash segment
@@ -595,7 +600,7 @@ internal class TrieNode<K, V>(
595
600
if (targetNode == = newNode) {
596
601
return this
597
602
}
598
- return mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
603
+ return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
599
604
}
600
605
601
606
// key is absent
@@ -623,11 +628,9 @@ internal class TrieNode<K, V>(
623
628
624
629
val targetNode = nodeAtIndex(nodeIndex)
625
630
val newNode = targetNode.remove(keyHash, key, shift + LOG_MAX_BRANCHING_FACTOR )
626
- return when {
627
- targetNode == = newNode -> this
628
- newNode == null -> removeNodeAtIndex(nodeIndex, keyPositionMask)
629
- else -> updateNodeAtIndex(nodeIndex, newNode)
630
- }
631
+ checkNotNull(newNode)
632
+ if (targetNode == = newNode) return this
633
+ return updateNodeAtIndex(nodeIndex, keyPositionMask, newNode)
631
634
}
632
635
633
636
// key is absent
@@ -654,11 +657,11 @@ internal class TrieNode<K, V>(
654
657
655
658
val targetNode = nodeAtIndex(nodeIndex)
656
659
val newNode = targetNode.mutableRemove(keyHash, key, shift + LOG_MAX_BRANCHING_FACTOR , mutator)
657
- return when {
658
- targetNode == = newNode -> this
659
- newNode == null -> mutableRemoveNodeAtIndex(nodeIndex, keyPositionMask, mutator.ownership)
660
- else -> mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
660
+ checkNotNull(newNode)
661
+ if (ownedBy == = mutator.ownership || targetNode != = newNode) {
662
+ return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
661
663
}
664
+ return this
662
665
}
663
666
664
667
// key is absent
@@ -685,11 +688,9 @@ internal class TrieNode<K, V>(
685
688
686
689
val targetNode = nodeAtIndex(nodeIndex)
687
690
val newNode = targetNode.remove(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR )
688
- return when {
689
- targetNode == = newNode -> this
690
- newNode == null -> removeNodeAtIndex(nodeIndex, keyPositionMask)
691
- else -> updateNodeAtIndex(nodeIndex, newNode)
692
- }
691
+ checkNotNull(newNode)
692
+ if (targetNode == = newNode) return this
693
+ return updateNodeAtIndex(nodeIndex, keyPositionMask, newNode)
693
694
}
694
695
695
696
// key is absent
@@ -716,11 +717,11 @@ internal class TrieNode<K, V>(
716
717
717
718
val targetNode = nodeAtIndex(nodeIndex)
718
719
val newNode = targetNode.mutableRemove(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR , mutator)
719
- return when {
720
- targetNode == = newNode -> this
721
- newNode == null -> mutableRemoveNodeAtIndex(nodeIndex, keyPositionMask, mutator.ownership)
722
- else -> mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
720
+ checkNotNull(newNode)
721
+ if (ownedBy == = mutator.ownership || targetNode != = newNode) {
722
+ return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
723
723
}
724
+ return this
724
725
}
725
726
726
727
// key is absent
0 commit comments