xref: /aosp_15_r20/external/kotlinx.coroutines/kotlinx-coroutines-core/common/src/flow/operators/Distinct.kt (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)

<lambda>null1 @file:JvmMultifileClass
2 @file:JvmName("FlowKt")
3 
4 package kotlinx.coroutines.flow
5 
6 import kotlinx.coroutines.flow.internal.*
7 import kotlin.jvm.*
8 
9 /**
10  * Returns flow where all subsequent repetitions of the same value are filtered out.
11  *
12  * Note that any instance of [StateFlow] already behaves as if `distinctUntilChanged` operator is
13  * applied to it, so applying `distinctUntilChanged` to a `StateFlow` has no effect.
14  * See [StateFlow] documentation on Operator Fusion.
15  * Also, repeated application of `distinctUntilChanged` operator on any flow has no effect.
16  */
17 public fun <T> Flow<T>.distinctUntilChanged(): Flow<T> =
18     when (this) {
19         is StateFlow<*> -> this // state flows are always distinct
20         else -> distinctUntilChangedBy(keySelector = defaultKeySelector, areEquivalent = defaultAreEquivalent)
21     }
22 
23 /**
24  * Returns flow where all subsequent repetitions of the same value are filtered out, when compared
25  * with each other via the provided [areEquivalent] function.
26  *
27  * Note that repeated application of `distinctUntilChanged` operator with the same parameter has no effect.
28  */
29 @Suppress("UNCHECKED_CAST")
distinctUntilChangednull30 public fun <T> Flow<T>.distinctUntilChanged(areEquivalent: (old: T, new: T) -> Boolean): Flow<T> =
31     distinctUntilChangedBy(keySelector = defaultKeySelector, areEquivalent = areEquivalent as (Any?, Any?) -> Boolean)
32 
33 /**
34  * Returns flow where all subsequent repetitions of the same key are filtered out, where
35  * key is extracted with [keySelector] function.
36  *
37  * Note that repeated application of `distinctUntilChanged` operator with the same parameter has no effect.
38  */
39 public fun <T, K> Flow<T>.distinctUntilChangedBy(keySelector: (T) -> K): Flow<T> =
40     distinctUntilChangedBy(keySelector = keySelector, areEquivalent = defaultAreEquivalent)
41 
42 private val defaultKeySelector: (Any?) -> Any? = { it }
43 
newnull44 private val defaultAreEquivalent: (Any?, Any?) -> Boolean = { old, new -> old == new }
45 
46 /**
47  * Returns flow where all subsequent repetitions of the same key are filtered out, where
48  * keys are extracted with [keySelector] function and compared with each other via the
49  * provided [areEquivalent] function.
50  *
51  * NOTE: It is non-inline to share a single implementing class.
52  */
distinctUntilChangedBynull53 private fun <T> Flow<T>.distinctUntilChangedBy(
54     keySelector: (T) -> Any?,
55     areEquivalent: (old: Any?, new: Any?) -> Boolean
56 ): Flow<T> = when {
57     this is DistinctFlowImpl<*> && this.keySelector === keySelector && this.areEquivalent === areEquivalent -> this // same
58     else -> DistinctFlowImpl(this, keySelector, areEquivalent)
59 }
60 
61 private class DistinctFlowImpl<T>(
62     private val upstream: Flow<T>,
63     @JvmField val keySelector: (T) -> Any?,
64     @JvmField val areEquivalent: (old: Any?, new: Any?) -> Boolean
65 ): Flow<T> {
collectnull66     override suspend fun collect(collector: FlowCollector<T>) {
67         var previousKey: Any? = NULL
68         upstream.collect { value ->
69             val key = keySelector(value)
70             @Suppress("UNCHECKED_CAST")
71             if (previousKey === NULL || !areEquivalent(previousKey, key)) {
72                 previousKey = key
73                 collector.emit(value)
74             }
75         }
76     }
77 }
78