@@ -4,18 +4,28 @@ import kotlinx.coroutines.flow.Flow
4
4
import kotlinx.coroutines.flow.collect
5
5
import kotlinx.coroutines.flow.flow
6
6
7
+ fun <T > Flow<T>.chunked (size : Int ): Flow <List <T >> = chunked(size) { it.toList() }
7
8
8
- fun <T , R > Flow<T>.chunked (size : Int , transform : suspend (List <T >) -> R ): Flow <R > = nonOverlappingWindowed(size, size, true , transform)
9
+ fun <T , R > Flow<T>.chunked (size : Int , transform : suspend (List <T >) -> R ): Flow <R > =
10
+ nonOverlappingWindowed(size, size, true , transform)
11
+
12
+ fun <T > Flow<T>.windowed (size : Int , step : Int , partialWindows : Boolean ): Flow <List <T >> =
13
+ windowed(size, step, partialWindows) { it.toList() }
9
14
10
15
fun <T , R > Flow<T>.windowed (size : Int , step : Int , partialWindows : Boolean , transform : suspend (List <T >) -> R ): Flow <R > =
11
16
if (size <= step) nonOverlappingWindowed(size, step, partialWindows, transform)
12
17
else overlappingWindowed(size, step, partialWindows, transform)
13
18
14
19
15
- private fun <T , R > Flow<T>.nonOverlappingWindowed (size : Int , step : Int , partialWindows : Boolean , transform : suspend (List <T >) -> R ): Flow <R > {
20
+ private fun <T , R > Flow<T>.nonOverlappingWindowed (
21
+ size : Int ,
22
+ step : Int ,
23
+ partialWindows : Boolean ,
24
+ transform : suspend (List <T >) -> R
25
+ ): Flow <R > {
26
+ require(size in 1 .. step) { " Size should be non-negative, and equal to or lesser than step, but was size: $size , step: $step " }
16
27
17
28
return flow {
18
- require(size in 1 .. step)
19
29
val window = ArrayList <T >(size)
20
30
val toSkip = step - size
21
31
var skipped = toSkip
@@ -26,39 +36,41 @@ private fun <T, R> Flow<T>.nonOverlappingWindowed(size: Int, step: Int, partialW
26
36
} else skipped++
27
37
28
38
if (window.size == size) {
29
- emit(transform(window.toList() ))
39
+ emit(transform(window))
30
40
window.clear()
31
41
skipped = 0
32
42
}
33
43
}
34
44
35
45
if (partialWindows && window.isNotEmpty()) {
36
- emit(transform(window.toList() ))
46
+ emit(transform(window))
37
47
}
38
48
}
39
49
}
40
50
41
- private fun <T , R > Flow<T>.overlappingWindowed (size : Int , step : Int , partialWindows : Boolean , transform : suspend (List <T >) -> R ) = flow {
42
- require(step in 1 until size)
43
- val buffer = ArrayList <T >(size)
51
+ private inline fun <T , R > Flow<T>.overlappingWindowed (
52
+ size : Int ,
53
+ step : Int ,
54
+ partialWindows : Boolean ,
55
+ crossinline transform : suspend (List <T >) -> R
56
+ ): Flow <R > {
57
+ require(step in 1 until size) { " Size should be non-negative, and greater than step, but was size: $size , step: $step " }
58
+
59
+ return flow {
60
+ val buffer = ArrayList <T >(size)
44
61
45
- collect { value ->
46
- buffer.add(value)
62
+ collect { value ->
63
+ buffer.add(value)
47
64
48
- if (buffer.size == size) {
49
- val window = makeWindow(step, buffer)
50
- emit(transform(window))
65
+ if (buffer.size == size) {
66
+ emit(transform(buffer))
67
+ repeat(step) { buffer.removeAt(0 ) }
68
+ }
51
69
}
52
- }
53
70
54
- while (partialWindows && buffer.isNotEmpty()) {
55
- val window = makeWindow(step, buffer)
56
- emit(transform(window))
71
+ while (partialWindows && buffer.isNotEmpty()) {
72
+ emit(transform(buffer))
73
+ repeat(step) { buffer.removeAt(0 ) }
74
+ }
57
75
}
58
- }
59
-
60
- private fun <T > makeWindow (step : Int , buffer : MutableList <T >): List <T > {
61
- val window = ArrayList (buffer)
62
- repeat(step) { buffer.removeAt(0 ) }
63
- return window
64
76
}
0 commit comments