Kotlin has ArrayDeque, which has simple methods for removing and adding elements to a list.
It doesn't have a limited capacity though.
Using a custom Delegated property is a fairly lightweight way to wrap an existing ArrayDeque so we can intercept calls and ensure the limit is maintained.
dequeLimiter
The method dequeLimiter is based on the NotNullVar delegate.
Whenever the internal deque field is read or written, it calls applyLimit() and this removes any excess items.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun <E> dequeLimiter(limit: Int): ReadWriteProperty<Any?, ArrayDeque<E>> =
object : ReadWriteProperty<Any?, ArrayDeque<E>> {
private var deque: ArrayDeque<E> = ArrayDeque(limit)
private fun applyLimit() {
while (deque.size > limit) {
val removed = deque.removeFirst()
println("dequeLimiter removed $removed")
}
}
override fun getValue(thisRef: Any?, property: KProperty<*>): ArrayDeque<E> {
applyLimit()
return deque
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: ArrayDeque<E>) {
this.deque = value
applyLimit()
}
}
Usage
The delegate is applied on any ArrayDeque with the by keyword (see the docs for more info).
After this, the deque can be used as normal and will be automatically limited.
fun main() {
// create a deque, and use our property delegate to intercept
// invocations and limit the size to 3
val limitedDeque: ArrayDeque<Int> by dequeLimiter(3)
// try adding 5 elements
(0..5).forEach {
limitedDeque.add(it)
println("limitedDeque: $limitedDeque")
}
/* output */
// limitedDeque: [0]
// limitedDeque: [0, 1]
// limitedDeque: [0, 1, 2]
// dequeLimiter removed 0
// limitedDeque: [1, 2, 3]
// dequeLimiter removed 1
// limitedDeque: [2, 3, 4]
// dequeLimiter removed 2
// limitedDeque: [3, 4, 5]
// try removing 5 elements
repeat(5) {
val removedLast = limitedDeque.removeLastOrNull()
println("removedLast: $removedLast")
println("limitedDeque: $limitedDeque")
}
/* output */
// removedLast: 5
// limitedDeque: [3, 4]
// removedLast: 4
// limitedDeque: [3]
// removedLast: 3
// limitedDeque: []
// removedLast: null
// limitedDeque: []
// removedLast: null
// limitedDeque: []
}