Skip to content

Commit 6b1c71c

Browse files
Ghost element when applying multiples minus operations on a PersistentHashSet (#219)
Fixes #144
1 parent 57759ea commit 6b1c71c

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -621,17 +621,17 @@ internal class TrieNode<E>(
621621
val realSize = realBitMap.countOneBits()
622622
return when {
623623
realBitMap == 0 -> EMPTY
624+
// single values are kept only on root level
625+
realSize == 1 && shift != 0 -> when (val single = mutableNode.buffer[mutableNode.indexOfCellAt(realBitMap)]) {
626+
is TrieNode<*> -> TrieNode<E>(realBitMap, arrayOf(single), mutator.ownership)
627+
else -> single
628+
}
624629
realBitMap == bitmap -> {
625630
when {
626631
mutableNode.elementsIdentityEquals(this) -> this
627632
else -> mutableNode
628633
}
629634
}
630-
// single values are kept only on root level
631-
realSize == 1 && shift != 0 -> when (val single = mutableNode.buffer[mutableNode.indexOfCellAt(realBitMap)]) {
632-
is TrieNode<*> -> TrieNode<E>(realBitMap, arrayOf(single), mutator.ownership)
633-
else -> single
634-
}
635635
else -> {
636636
// clean up all the EMPTYs in the resulting buffer
637637
val realBuffer = arrayOfNulls<Any>(realSize)

core/commonTest/src/contract/set/PersistentHashSetTest.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
package tests.contract.set
77

8+
import kotlinx.collections.immutable.implementations.immutableSet.PersistentHashSet
89
import kotlinx.collections.immutable.persistentHashSetOf
10+
import kotlinx.collections.immutable.minus
11+
import kotlinx.collections.immutable.toPersistentHashSet
912
import kotlin.test.Test
1013
import kotlin.test.assertEquals
1114
import kotlin.test.assertTrue
@@ -27,4 +30,30 @@ class PersistentHashSetTest {
2730
assertEquals(set2, builder.build().toSet())
2831
assertEquals(set2, builder.build())
2932
}
33+
34+
/**
35+
* Test from issue: https://github.com/Kotlin/kotlinx.collections.immutable/issues/144
36+
*/
37+
@Test
38+
fun `removing multiple batches should leave only remaining elements`() {
39+
val firstBatch = listOf(4554, 9380, 4260, 6602)
40+
val secondBatch = listOf(1188, 14794)
41+
val extraElement = 7450
42+
43+
val set = firstBatch.plus(secondBatch).plus(extraElement).toPersistentHashSet()
44+
val result = set.minus(firstBatch.toPersistentHashSet()).minus(secondBatch)
45+
assertEquals(1, result.size)
46+
assertEquals(extraElement, result.first())
47+
}
48+
49+
@Test
50+
fun `after removing elements from one collision the remaining one element must be promoted to the root`() {
51+
val set1: PersistentHashSet<Int> = persistentHashSetOf(0, 32768, 65536) as PersistentHashSet<Int>
52+
val set2: PersistentHashSet<Int> = persistentHashSetOf(0, 32768) as PersistentHashSet<Int>
53+
54+
val expected = persistentHashSetOf(65536)
55+
val actual = set1 - set2
56+
57+
assertEquals(expected, actual)
58+
}
3059
}

0 commit comments

Comments
 (0)