Skip to content

Commit dca8d17

Browse files
author
Abduqodiri Qurbonzoda
committed
Implement set TrieNode canonicalization
1 parent 42146e2 commit dca8d17

File tree

1 file changed

+28
-12
lines changed
  • kotlinx-collections-immutable/src/main/kotlin/kotlinx/collections/immutable/implementations/immutableSet

1 file changed

+28
-12
lines changed

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

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,36 @@ internal class TrieNode<E>(
102102
// assert(buffer[nodeIndex] !== newNode)
103103

104104
val newBuffer = buffer.copyOf()
105-
newBuffer[nodeIndex] = newNode
105+
106+
// TODO: check how this changes affect `add` operation performance.
107+
// Try to not create this newNode, but pass here the remained element.
108+
val newNodeBuffer = newNode.buffer
109+
if (newNodeBuffer.size == 1 && newNodeBuffer[0] !is TrieNode<*>) {
110+
newBuffer[nodeIndex] = newNodeBuffer[0]
111+
} else {
112+
newBuffer[nodeIndex] = newNode
113+
}
114+
106115
return TrieNode(bitmap, newBuffer)
107116
}
108117

109118
private fun mutableUpdateNodeAtIndex(nodeIndex: Int, newNode: TrieNode<E>, owner: MutabilityOwnership): TrieNode<E> {
110119
// assert(buffer[nodeIndex] !== newNode)
111120

121+
val cell: Any?
122+
val newNodeBuffer = newNode.buffer
123+
if (newNodeBuffer.size == 1 && newNodeBuffer[0] !is TrieNode<*>) {
124+
cell = newNodeBuffer[0]
125+
} else {
126+
cell = newNode
127+
}
128+
112129
if (ownedBy === owner) {
113-
buffer[nodeIndex] = newNode
130+
buffer[nodeIndex] = cell
114131
return this
115132
}
116133
val newBuffer = buffer.copyOf()
117-
newBuffer[nodeIndex] = newNode
134+
newBuffer[nodeIndex] = cell
118135
return TrieNode(bitmap, newBuffer, owner)
119136
}
120137

@@ -194,6 +211,7 @@ internal class TrieNode<E>(
194211

195212
private fun removeCellAtIndex(cellIndex: Int, positionMask: Int): TrieNode<E>? {
196213
// assert(!hasNoCellAt(positionMask))
214+
// It is possible only when this node is the root node
197215
if (buffer.size == 1) return null
198216

199217
val newBuffer = buffer.removeCellAtIndex(cellIndex)
@@ -365,11 +383,9 @@ internal class TrieNode<E>(
365383
if (buffer[cellIndex] is TrieNode<*>) { // element may be in node
366384
val targetNode = nodeAtIndex(cellIndex)
367385
val newNode = targetNode.remove(elementHash, element, shift + LOG_MAX_BRANCHING_FACTOR)
368-
return when {
369-
targetNode === newNode -> this
370-
newNode == null -> removeCellAtIndex(cellIndex, cellPositionMask)
371-
else -> updateNodeAtIndex(cellIndex, newNode)
372-
}
386+
checkNotNull(newNode)
387+
if (targetNode === newNode) return this
388+
return updateNodeAtIndex(cellIndex, newNode)
373389
}
374390
// element is directly in buffer
375391
if (element == buffer[cellIndex]) {
@@ -393,11 +409,11 @@ internal class TrieNode<E>(
393409
if (buffer[cellIndex] is TrieNode<*>) { // element may be in node
394410
val targetNode = nodeAtIndex(cellIndex)
395411
val newNode = targetNode.mutableRemove(elementHash, element, shift + LOG_MAX_BRANCHING_FACTOR, mutator)
396-
return when {
397-
targetNode === newNode -> this
398-
newNode == null -> mutableRemoveCellAtIndex(cellIndex, cellPositionMask, mutator.ownership)
399-
else -> mutableUpdateNodeAtIndex(cellIndex, newNode, mutator.ownership)
412+
checkNotNull(newNode)
413+
if (ownedBy === mutator.ownership || targetNode !== newNode) {
414+
return mutableUpdateNodeAtIndex(cellIndex, newNode, mutator.ownership)
400415
}
416+
return this
401417
}
402418
// element is directly in buffer
403419
if (element == buffer[cellIndex]) {

0 commit comments

Comments
 (0)