@@ -41,20 +41,22 @@ private fun Array<Any?>.replaceEntryWithNode(keyIndex: Int, nodeIndex: Int, newN
41
41
return newBuffer
42
42
}
43
43
44
+ private fun <K , V > Array<Any?>.replaceNodeWithEntry (nodeIndex : Int , keyIndex : Int , key : K , value : V ): Array <Any ?> {
45
+ val newBuffer = this .copyOf(this .size + 1 )
46
+ newBuffer.copyInto(newBuffer, nodeIndex + 2 , nodeIndex + 1 , this .size)
47
+ newBuffer.copyInto(newBuffer, keyIndex + 2 , keyIndex , nodeIndex)
48
+ newBuffer[keyIndex] = key
49
+ newBuffer[keyIndex + 1 ] = value
50
+ return newBuffer
51
+ }
52
+
44
53
private fun Array<Any?>.removeEntryAtIndex (keyIndex : Int ): Array <Any ?> {
45
54
val newBuffer = arrayOfNulls<Any ?>(this .size - ENTRY_SIZE )
46
55
this .copyInto(newBuffer, endIndex = keyIndex)
47
56
this .copyInto(newBuffer, keyIndex, startIndex = keyIndex + ENTRY_SIZE , endIndex = this .size)
48
57
return newBuffer
49
58
}
50
59
51
- private fun Array<Any?>.removeNodeAtIndex (nodeIndex : Int ): Array <Any ?> {
52
- val newBuffer = arrayOfNulls<Any ?>(this .size - 1 )
53
- this .copyInto(newBuffer, endIndex = nodeIndex)
54
- this .copyInto(newBuffer, nodeIndex, startIndex = nodeIndex + 1 , endIndex = this .size)
55
- return newBuffer
56
- }
57
-
58
60
59
61
60
62
internal class TrieNode <K , V >(
@@ -173,17 +175,40 @@ internal class TrieNode<K, V>(
173
175
return TrieNode (dataMap, nodeMap, newBuffer, mutator.ownership)
174
176
}
175
177
176
- private fun updateNodeAtIndex (nodeIndex : Int , newNode : TrieNode <K , V >): TrieNode <K , V > {
178
+ private fun updateNodeAtIndex (nodeIndex : Int , positionMask : Int , newNode : TrieNode <K , V >): TrieNode <K , V > {
177
179
// assert(buffer[nodeIndex] !== newNode)
180
+ // TODO: check how this changes affect `put` and non-collision `remove` operations performance.
178
181
179
- val newBuffer = buffer.copyOf()
182
+ val newNodeBuffer = newNode.buffer
183
+ if (newNodeBuffer.size == 2 && newNode.nodeMap == 0 ) {
184
+ val keyIndex = entryKeyIndex(positionMask)
185
+ val newBuffer = buffer.replaceNodeWithEntry(nodeIndex, keyIndex, newNodeBuffer[0 ], newNodeBuffer[1 ])
186
+ return TrieNode (dataMap xor positionMask, nodeMap xor positionMask, newBuffer)
187
+ }
188
+
189
+ val newBuffer = buffer.copyOf(buffer.size)
180
190
newBuffer[nodeIndex] = newNode
181
191
return TrieNode (dataMap, nodeMap, newBuffer)
182
192
}
183
193
184
- private fun mutableUpdateNodeAtIndex (nodeIndex : Int , newNode : TrieNode <K , V >, owner : MutabilityOwnership ): TrieNode <K , V > {
194
+ private fun mutableUpdateNodeAtIndex (nodeIndex : Int , positionMask : Int , newNode : TrieNode <K , V >, owner : MutabilityOwnership ): TrieNode <K , V > {
185
195
// assert(buffer[nodeIndex] !== newNode)
186
196
197
+ val newNodeBuffer = newNode.buffer
198
+ if (newNodeBuffer.size == 2 && newNode.nodeMap == 0 ) {
199
+ val keyIndex = entryKeyIndex(positionMask)
200
+ val newBuffer = buffer.replaceNodeWithEntry(nodeIndex, keyIndex, newNodeBuffer[0 ], newNodeBuffer[1 ])
201
+
202
+ if (ownedBy == = owner) {
203
+ buffer = newBuffer
204
+ dataMap = dataMap xor positionMask
205
+ nodeMap = nodeMap xor positionMask
206
+ return this
207
+ }
208
+
209
+ return TrieNode (dataMap xor positionMask, nodeMap xor positionMask, newBuffer)
210
+ }
211
+
187
212
if (ownedBy == = owner) {
188
213
buffer[nodeIndex] = newNode
189
214
return this
@@ -274,6 +299,7 @@ internal class TrieNode<K, V>(
274
299
275
300
private fun removeEntryAtIndex (keyIndex : Int , positionMask : Int ): TrieNode <K , V >? {
276
301
// assert(hasEntryAt(positionMask))
302
+ // It is possible only when this node is the root node
277
303
if (buffer.size == ENTRY_SIZE ) return null
278
304
279
305
val newBuffer = buffer.removeEntryAtIndex(keyIndex)
@@ -315,27 +341,6 @@ internal class TrieNode<K, V>(
315
341
return makeCollisionNode(newBuffer, mutator.ownership)
316
342
}
317
343
318
- private fun removeNodeAtIndex (nodeIndex : Int , positionMask : Int ): TrieNode <K , V >? {
319
- // assert(hasNodeAt(positionMask))
320
- if (buffer.size == 1 ) return null
321
-
322
- val newBuffer = buffer.removeNodeAtIndex(nodeIndex)
323
- return TrieNode (dataMap, nodeMap xor positionMask, newBuffer)
324
- }
325
-
326
- private fun mutableRemoveNodeAtIndex (nodeIndex : Int , positionMask : Int , owner : MutabilityOwnership ): TrieNode <K , V >? {
327
- // assert(hasNodeAt(positionMask))
328
- if (buffer.size == 1 ) return null
329
-
330
- if (ownedBy == = owner) {
331
- buffer = buffer.removeNodeAtIndex(nodeIndex)
332
- nodeMap = nodeMap xor positionMask
333
- return this
334
- }
335
- val newBuffer = buffer.removeNodeAtIndex(nodeIndex)
336
- return TrieNode (dataMap, nodeMap xor positionMask, newBuffer, owner)
337
- }
338
-
339
344
private fun collisionContainsKey (key : K ): Boolean {
340
345
val collisionHash = keyAtIndex(0 ).hashCode()
341
346
val keyHash = key.hashCode()
@@ -551,7 +556,7 @@ internal class TrieNode<K, V>(
551
556
552
557
val targetNode = nodeAtIndex(nodeIndex)
553
558
val putResult = targetNode.put(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR ) ? : return null
554
- return putResult.replaceNode { node -> updateNodeAtIndex(nodeIndex, node) }
559
+ return putResult.replaceNode { node -> updateNodeAtIndex(nodeIndex, keyPositionMask, node) }
555
560
}
556
561
557
562
// no entry at this key hash segment
@@ -587,7 +592,7 @@ internal class TrieNode<K, V>(
587
592
if (targetNode == = newNode) {
588
593
return this
589
594
}
590
- return mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
595
+ return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
591
596
}
592
597
593
598
// key is absent
@@ -615,11 +620,9 @@ internal class TrieNode<K, V>(
615
620
616
621
val targetNode = nodeAtIndex(nodeIndex)
617
622
val newNode = targetNode.remove(keyHash, key, shift + LOG_MAX_BRANCHING_FACTOR )
618
- return when {
619
- targetNode == = newNode -> this
620
- newNode == null -> removeNodeAtIndex(nodeIndex, keyPositionMask)
621
- else -> updateNodeAtIndex(nodeIndex, newNode)
622
- }
623
+ checkNotNull(newNode)
624
+ if (targetNode == = newNode) return this
625
+ return updateNodeAtIndex(nodeIndex, keyPositionMask, newNode)
623
626
}
624
627
625
628
// key is absent
@@ -646,11 +649,11 @@ internal class TrieNode<K, V>(
646
649
647
650
val targetNode = nodeAtIndex(nodeIndex)
648
651
val newNode = targetNode.mutableRemove(keyHash, key, shift + LOG_MAX_BRANCHING_FACTOR , mutator)
649
- return when {
650
- targetNode == = newNode -> this
651
- newNode == null -> mutableRemoveNodeAtIndex(nodeIndex, keyPositionMask, mutator.ownership)
652
- else -> mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
652
+ checkNotNull(newNode)
653
+ if (ownedBy == = mutator.ownership || targetNode != = newNode) {
654
+ return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
653
655
}
656
+ return this
654
657
}
655
658
656
659
// key is absent
@@ -677,11 +680,9 @@ internal class TrieNode<K, V>(
677
680
678
681
val targetNode = nodeAtIndex(nodeIndex)
679
682
val newNode = targetNode.remove(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR )
680
- return when {
681
- targetNode == = newNode -> this
682
- newNode == null -> removeNodeAtIndex(nodeIndex, keyPositionMask)
683
- else -> updateNodeAtIndex(nodeIndex, newNode)
684
- }
683
+ checkNotNull(newNode)
684
+ if (targetNode == = newNode) return this
685
+ return updateNodeAtIndex(nodeIndex, keyPositionMask, newNode)
685
686
}
686
687
687
688
// key is absent
@@ -708,11 +709,11 @@ internal class TrieNode<K, V>(
708
709
709
710
val targetNode = nodeAtIndex(nodeIndex)
710
711
val newNode = targetNode.mutableRemove(keyHash, key, value, shift + LOG_MAX_BRANCHING_FACTOR , mutator)
711
- return when {
712
- targetNode == = newNode -> this
713
- newNode == null -> mutableRemoveNodeAtIndex(nodeIndex, keyPositionMask, mutator.ownership)
714
- else -> mutableUpdateNodeAtIndex(nodeIndex, newNode, mutator.ownership)
712
+ checkNotNull(newNode)
713
+ if (ownedBy == = mutator.ownership || targetNode != = newNode) {
714
+ return mutableUpdateNodeAtIndex(nodeIndex, keyPositionMask, newNode, mutator.ownership)
715
715
}
716
+ return this
716
717
}
717
718
718
719
// key is absent
0 commit comments