@@ -56,14 +56,18 @@ internal suspend fun <R, T> FlowCollector<R>.combineInternal(
56
56
val isClosed = Array (size) { false }
57
57
var nonClosed = size
58
58
var remainingNulls = size
59
- // See flow.combine(other) for explanation.
60
- while (nonClosed != 0 ) {
61
- select<Unit > {
62
- for (i in 0 until size) {
63
- onReceive(isClosed[i], channels[i], { isClosed[i] = true ; -- nonClosed }) { value ->
64
- if (latestValues[i] == null ) -- remainingNulls
65
- latestValues[i] = value
66
- if (remainingNulls != 0 ) return @onReceive
59
+ // See flow.combine(other) for explanation of the logic
60
+ // Reuse receive blocks to avoid allocations on each iteration
61
+ val onReceiveBlocks = Array < suspend (Any? ) -> Unit > (size) { i ->
62
+ { value ->
63
+ if (value == = null ) {
64
+ isClosed[i] = true ;
65
+ -- nonClosed
66
+ }
67
+ else {
68
+ if (latestValues[i] == null ) -- remainingNulls
69
+ latestValues[i] = value
70
+ if (remainingNulls == 0 ) {
67
71
val arguments = arrayFactory()
68
72
for (index in 0 until size) {
69
73
arguments[index] = NULL .unbox(latestValues[index])
@@ -73,6 +77,15 @@ internal suspend fun <R, T> FlowCollector<R>.combineInternal(
73
77
}
74
78
}
75
79
}
80
+
81
+ while (nonClosed != 0 ) {
82
+ select<Unit > {
83
+ for (i in 0 until size) {
84
+ if (isClosed[i]) continue
85
+ channels[i].onReceiveOrNull(onReceiveBlocks[i])
86
+ }
87
+ }
88
+ }
76
89
}
77
90
78
91
private inline fun SelectBuilder<Unit>.onReceive (
0 commit comments