• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.kairos.util
18 
19 import com.android.systemui.kairos.util.Either.First
20 import com.android.systemui.kairos.util.Either.Second
21 import com.android.systemui.kairos.util.Maybe.Present
22 
23 /** A "patch" that can be used to batch-update a [Map], via [applyPatch]. */
24 typealias MapPatch<K, V> = Map<K, Maybe<V>>
25 
26 /**
27  * Returns a new [Map] that has [patch] applied to the original map.
28  *
29  * For each entry in [patch]:
30  * * a [Present] value will be included in the new map, replacing the entry in the original map with
31  *   the same key, if present.
32  * * a [Maybe.Absent] value will be omitted from the new map, excluding the entry in the original
33  *   map with the same key, if present.
34  */
35 fun <K, V> Map<K, V>.applyPatch(patch: MapPatch<K, V>): Map<K, V> {
36     val (adds: List<Pair<K, V>>, removes: List<K>) =
37         patch
38             .asSequence()
39             .map { (k, v) -> if (v is Present) First(k to v.value) else Second(k) }
40             .partitionEithers()
41     val removed: Map<K, V> = this - removes.toSet()
42     val updated: Map<K, V> = removed + adds
43     return updated
44 }
45 
46 /**
47  * Returns a [MapPatch] that, when applied, includes all of the values from the original [Map].
48  *
49  * Shorthand for:
50  * ```
51  *   mapValues { (key, value) -> Maybe.present(value) }
52  * ```
53  */
<lambda>null54 fun <K, V> Map<K, V>.toMapPatch(): MapPatch<K, V> = mapValues { Maybe.present(it.value) }
55 
56 /**
57  * Returns a [MapPatch] that, when applied, includes all of the entries from [new] whose keys are
58  * not present in [old], and excludes all entries with keys present in [old] that are not also
59  * present in [new].
60  *
61  * Note that, unlike [mapPatchFromFullDiff], only keys are taken into account. If the same key is
62  * present in both [old] and [new], but the associated values are not equal, then the returned
63  * [MapPatch] will *not* include any update to that key.
64  */
mapPatchFromKeyDiffnull65 fun <K, V> mapPatchFromKeyDiff(old: Map<K, V>, new: Map<K, V>): MapPatch<K, V> {
66     val removes = old.keys - new.keys
67     val adds = new - old.keys
68     return buildMap {
69         for (removed in removes) {
70             put(removed, Maybe.absent)
71         }
72         for ((newKey, newValue) in adds) {
73             put(newKey, Maybe.present(newValue))
74         }
75     }
76 }
77 
78 /**
79  * Returns a [MapPatch] that, when applied, includes all of the entries from [new] that are not
80  * present in [old], and excludes all entries with keys present in [old] that are not also present
81  * in [new].
82  *
83  * Note that, unlike [mapPatchFromKeyDiff], both keys and values are taken into account. If the same
84  * key is present in both [old] and [new], but the associated values are not equal, then the
85  * returned [MapPatch] will include the entry from [new].
86  */
mapPatchFromFullDiffnull87 fun <K, V> mapPatchFromFullDiff(old: Map<K, V>, new: Map<K, V>): MapPatch<K, V> {
88     val removes = old.keys - new.keys
89     val adds =
90         new.mapMaybeValues { (k, v) ->
91             if (k in old && v == old[k]) Maybe.absent else Maybe.present(v)
92         }
93     return hashMapOf<K, Maybe<V>>().apply {
94         for (removed in removes) {
95             put(removed, Maybe.absent)
96         }
97         for ((newKey, newValue) in adds) {
98             put(newKey, Maybe.present(newValue))
99         }
100     }
101 }
102