Skip to content

Commit 68fc9cd

Browse files
committed
[K/N] Internal implementation of PriorityQueue ^KT-79037
To be used internaly e.g. by workers
1 parent 0f1c76f commit 68fc9cd

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package kotlin.native.internal.collections
7+
8+
internal class PriorityQueue<T>(initialCapacity: Int, private val comparator: Comparator<T>) {
9+
10+
constructor(comparator: Comparator<T>) : this(DEFAULT_INITIAL_CAPACITY, comparator)
11+
12+
companion object {
13+
private const val DEFAULT_INITIAL_CAPACITY = 11
14+
15+
fun <T : Comparable<T>> minimal(initialCapacity: Int = DEFAULT_INITIAL_CAPACITY): PriorityQueue<T> =
16+
PriorityQueue(initialCapacity) { a, b -> a.compareTo(b) }
17+
18+
fun <T : Comparable<T>> maximal(initialCapacity: Int = DEFAULT_INITIAL_CAPACITY): PriorityQueue<T> =
19+
PriorityQueue(initialCapacity) { a, b -> b.compareTo(a) }
20+
}
21+
22+
private val elements = ArrayList<T>(initialCapacity)
23+
24+
val unorderedElements: List<T>
25+
get() = elements.toList()
26+
27+
val size: Int
28+
get() = elements.size
29+
30+
fun isEmpty(): Boolean = elements.isEmpty()
31+
32+
fun contains(element: T): Boolean = elements.contains(element)
33+
34+
fun containsAll(elements: Collection<T>): Boolean = this.elements.containsAll(elements)
35+
36+
fun add(element: T): Boolean {
37+
elements.add(element)
38+
siftUp(elements.size - 1)
39+
return true
40+
}
41+
42+
fun firstOrNull(): T? {
43+
return if (isEmpty()) null else elements[0]
44+
}
45+
46+
fun first(): T {
47+
return firstOrNull() ?: throw NoSuchElementException("PriorityQueue is empty")
48+
}
49+
50+
fun removeFirstOrNull(): T? {
51+
if (isEmpty()) return null
52+
return removeAt(0)
53+
}
54+
55+
fun removeFirst(): T = removeFirstOrNull() ?: throw NoSuchElementException("PriorityQueue is empty")
56+
57+
fun clear() {
58+
elements.clear()
59+
}
60+
61+
fun remove(element: T): Boolean {
62+
val index = elements.indexOf(element)
63+
if (index == -1) return false
64+
removeAt(index)
65+
return true
66+
}
67+
68+
private fun removeAt(index: Int): T {
69+
val removedElement = elements[index]
70+
if (index == elements.size - 1) {
71+
elements.removeAt(index)
72+
} else {
73+
elements[index] = elements.removeAt(elements.size - 1)
74+
siftDown(index)
75+
}
76+
return removedElement
77+
}
78+
79+
private fun leftChild(index: Int): Int = 2 * index + 1
80+
private fun rightChild(index: Int): Int = leftChild(index) + 1
81+
private fun parent(index: Int): Int = (index - 1) / 2
82+
83+
private operator fun T.compareTo(other: T): Int = comparator.compare(this, other)
84+
85+
private fun siftUp(start: Int) {
86+
val startElement = elements[start]
87+
var child = start
88+
while (child > 0) {
89+
val parent = parent(child)
90+
if (startElement >= elements[parent]) break
91+
elements[child] = elements[parent]
92+
child = parent
93+
}
94+
elements[child] = startElement
95+
}
96+
97+
private fun siftDown(start: Int) {
98+
val startElement = elements[start]
99+
var parent = start
100+
val firstLeaf = elements.size / 2
101+
while (parent < firstLeaf) {
102+
val left = leftChild(parent)
103+
val right = rightChild(parent)
104+
105+
val leastChild = if (right < elements.size && elements[right] < elements[left]) {
106+
right
107+
} else {
108+
left
109+
}
110+
111+
if (startElement <= elements[leastChild]) break
112+
elements[parent] = elements[leastChild]
113+
parent = leastChild
114+
}
115+
elements[parent] = startElement
116+
}
117+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2010-2025 JetBrains s.r.o. and Kotlin Programming Language contributors.
3+
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4+
*/
5+
6+
package test.native.internal.collections
7+
8+
import kotlin.native.internal.collections.PriorityQueue
9+
import kotlin.test.Test
10+
import kotlin.test.assertEquals
11+
import kotlin.test.assertFalse
12+
13+
class PriorityQueueTest {
14+
val testData = listOf(108, 42, 37, 4, 8, 15, 16, 23, 42)
15+
16+
@Test
17+
fun addAndFirstElement() {
18+
val queue = PriorityQueue.minimal<Int>()
19+
queue.add(testData.first())
20+
assertFalse(queue.isEmpty())
21+
assertEquals(1, queue.size)
22+
assertEquals(testData.first(), queue.first())
23+
}
24+
25+
@Test
26+
fun minHeap() {
27+
val queue = PriorityQueue.minimal<Int>()
28+
testData.forEach { queue.add(it) }
29+
30+
assertEquals(
31+
testData.sorted(),
32+
generateSequence { queue.removeFirstOrNull() }.toList()
33+
)
34+
}
35+
36+
@Test
37+
fun maxHeap() {
38+
val queue = PriorityQueue.maximal<Int>()
39+
testData.forEach { queue.add(it) }
40+
41+
assertEquals(
42+
testData.sortedDescending(),
43+
generateSequence { queue.removeFirstOrNull() }.toList()
44+
)
45+
}
46+
}

0 commit comments

Comments
 (0)