Skip to content

Instantly share code, notes, and snippets.

@mrenouf
Created April 8, 2025 02:47
Show Gist options
  • Save mrenouf/3bd802e06e7b5fb10594c5e96018669e to your computer and use it in GitHub Desktop.
Save mrenouf/3bd802e06e7b5fb10594c5e96018669e to your computer and use it in GitHub Desktop.
Flow window function for log event flows -> lazy list UI
package com.android.atool.ui
import kotlinx.coroutines.channels.BufferOverflow.DROP_LATEST
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.Flow
/**
* Creates a [Flow] that emits sliding windows of the elements from the original [Flow].
* Each emitted list represents a window of the specified [length]. The window starts with
* the first emitted value, emitting a list of size 1, and grows until it reaches [length].
*
* The window slides by one element at a time. For example, if the original flow
* emits `[1, 2, 3, 4, 5]` and `length` is 3, the resulting flow will emit:
* `[1]`, `[1, 2]`, `[1, 2, 3]`, `[2, 3, 4]`, `[3, 4, 5]`.
*
* The latest result is buffered and replaced as needed to avoid overwhelming
* downstream collectors when the source flow produces rapidly.
*
* @param length The size of each window. Must be greater than 0.
* @return A [Flow] emitting lists of size [length], representing the sliding windows.
* @throws IllegalArgumentException if [length] is not greater than 0.
*/
fun <T> Flow<T>.window(length: Int): Flow<List<T>> {
require(length > 0) { "length must be greater than 0, but was $length" }
return channelFlow {
val buffer = ArrayDeque<T>(maxOf(length + 1, 16))
this@window.collect { value ->
buffer.addLast(value)
if (buffer.size > length) {
buffer.removeFirst()
}
send(buffer.toList())
}
}
.buffer(capacity = 1, onBufferOverflow = DROP_LATEST)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment