I need a collection that:
I think Guava's EvictingQueue
and Apache Commons CircularFifoQueue
is what I need.
However, I am on Android, and was hoping Kotlin already has something similar. But I did not find yet ;)
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()
}
}
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: []
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With