1 /* 2 * Copyright (C) 2020 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.util 18 19 import android.util.SparseArray 20 21 /** 22 * Transforms a sequence of Key/Value pairs into a SparseArray. 23 * 24 * See [kotlin.collections.toMap]. 25 */ 26 fun <T> Sequence<Pair<Int, T>>.toSparseArray(size: Int = -1): SparseArray<T> { 27 val sparseArray = when { 28 size < 0 -> SparseArray<T>() 29 else -> SparseArray<T>(size) 30 } 31 for ((i, v) in this) { 32 sparseArray.put(i, v) 33 } 34 return sparseArray 35 } 36 37 /** 38 * Transforms an [Array] into a [SparseArray], by applying each element to [keySelector] in order to 39 * generate the index at which it will be placed. If two elements produce the same index, the latter 40 * replaces the former in the final result. 41 * 42 * See [Array.associateBy]. 43 */ 44 inline fun <T> Array<T>.associateByToSparseArray( 45 crossinline keySelector: (T) -> Int 46 ): SparseArray<T> { 47 val sparseArray = SparseArray<T>(size) 48 for (value in this) { 49 sparseArray.put(keySelector(value), value) 50 } 51 return sparseArray 52 } 53 54 /** 55 * Folds a [Grouping] into a [SparseArray]. See [Grouping.fold]. 56 */ 57 inline fun <T, R> Grouping<T, Int>.foldToSparseArray( 58 initial: R, 59 size: Int = -1, 60 crossinline operation: (R, T) -> R 61 ): SparseArray<R> { 62 val sparseArray = when { 63 size < 0 -> SparseArray<R>() 64 else -> SparseArray<R>(size) 65 } 66 sourceIterator().forEach { elem -> 67 val key = keyOf(elem) 68 val acc = sparseArray.get(key) ?: initial 69 sparseArray.put(key, operation(acc, elem)) 70 } 71 return sparseArray 72 } 73 74 /** 75 * Wraps this [SparseArray] into an immutable [Map], the methods of which forward to this 76 * [SparseArray]. 77 */ 78 fun <T> SparseArray<T>.asMap(): Map<Int, T> = SparseArrayMapWrapper(this) 79 80 private class SparseArrayMapWrapper<T>( 81 private val sparseArray: SparseArray<T> 82 ) : Map<Int, T> { 83 84 private data class Entry<T>(override val key: Int, override val value: T) : Map.Entry<Int, T> 85 86 private val entrySequence = sequence { 87 val size = sparseArray.size() 88 for (i in 0 until size) { 89 val key = sparseArray.keyAt(i) 90 val value = sparseArray.get(key) 91 yield(Entry(key, value)) 92 } 93 } 94 95 override val entries: Set<Map.Entry<Int, T>> 96 get() = object : Set<Map.Entry<Int, T>> { 97 override val size: Int 98 get() = this@SparseArrayMapWrapper.size 99 100 override fun contains(element: Map.Entry<Int, T>): Boolean = 101 sparseArray[element.key]?.let { it == element.value } == true 102 103 override fun containsAll(elements: Collection<Map.Entry<Int, T>>): Boolean = 104 elements.all { contains(it) } 105 106 override fun isEmpty(): Boolean = size == 0 107 108 override fun iterator(): Iterator<Map.Entry<Int, T>> = entrySequence.iterator() 109 } 110 111 override val keys: Set<Int> = object : Set<Int> { 112 private val keySequence = entrySequence.map { it.key } 113 114 override val size: Int 115 get() = this@SparseArrayMapWrapper.size 116 117 override fun contains(element: Int): Boolean = containsKey(element) 118 119 override fun containsAll(elements: Collection<Int>): Boolean = 120 elements.all { contains(it) } 121 122 override fun isEmpty(): Boolean = size == 0 123 124 override fun iterator(): Iterator<Int> = keySequence.iterator() 125 } 126 override val size: Int 127 get() = sparseArray.size() 128 override val values: Collection<T> 129 get() = object : Collection<T> { 130 private val valueSequence = entrySequence.map { it.value } 131 132 override val size: Int 133 get() = this@SparseArrayMapWrapper.size 134 135 override fun contains(element: T): Boolean = containsValue(element) 136 137 override fun containsAll(elements: Collection<T>): Boolean = 138 elements.all { contains(it) } 139 140 override fun isEmpty(): Boolean = this@SparseArrayMapWrapper.isEmpty() 141 142 override fun iterator(): Iterator<T> = valueSequence.iterator() 143 } 144 145 override fun containsKey(key: Int): Boolean = sparseArray.contains(key) 146 147 override fun containsValue(value: T): Boolean = sparseArray.indexOfValue(value) >= 0 148 149 override fun get(key: Int): T? = sparseArray.get(key) 150 151 override fun isEmpty(): Boolean = sparseArray.size() == 0 152 }