blob: 1a25c84a796528793b0a9fe5aac8d7e1f80b8273 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.util
import android.util.SparseArray
/**
* Transforms a sequence of Key/Value pairs into a SparseArray.
*
* See [kotlin.collections.toMap].
*/
fun <T> Sequence<Pair<Int, T>>.toSparseArray(size: Int = -1): SparseArray<T> {
val sparseArray = when {
size < 0 -> SparseArray<T>()
else -> SparseArray<T>(size)
}
for ((i, v) in this) {
sparseArray.put(i, v)
}
return sparseArray
}
/**
* Transforms an [Array] into a [SparseArray], by applying each element to [keySelector] in order to
* generate the index at which it will be placed. If two elements produce the same index, the latter
* replaces the former in the final result.
*
* See [Array.associateBy].
*/
inline fun <T> Array<T>.associateByToSparseArray(
crossinline keySelector: (T) -> Int
): SparseArray<T> {
val sparseArray = SparseArray<T>(size)
for (value in this) {
sparseArray.put(keySelector(value), value)
}
return sparseArray
}
/**
* Folds a [Grouping] into a [SparseArray]. See [Grouping.fold].
*/
inline fun <T, R> Grouping<T, Int>.foldToSparseArray(
initial: R,
size: Int = -1,
crossinline operation: (R, T) -> R
): SparseArray<R> {
val sparseArray = when {
size < 0 -> SparseArray<R>()
else -> SparseArray<R>(size)
}
sourceIterator().forEach { elem ->
val key = keyOf(elem)
val acc = sparseArray.get(key) ?: initial
sparseArray.put(key, operation(acc, elem))
}
return sparseArray
}
/**
* Wraps this [SparseArray] into an immutable [Map], the methods of which forward to this
* [SparseArray].
*/
fun <T> SparseArray<T>.asMap(): Map<Int, T> = SparseArrayMapWrapper(this)
private class SparseArrayMapWrapper<T>(
private val sparseArray: SparseArray<T>
) : Map<Int, T> {
private data class Entry<T>(override val key: Int, override val value: T) : Map.Entry<Int, T>
private val entrySequence = sequence {
val size = sparseArray.size()
for (i in 0 until size) {
val key = sparseArray.keyAt(i)
val value = sparseArray.get(key)
yield(Entry(key, value))
}
}
override val entries: Set<Map.Entry<Int, T>>
get() = object : Set<Map.Entry<Int, T>> {
override val size: Int
get() = this@SparseArrayMapWrapper.size
override fun contains(element: Map.Entry<Int, T>): Boolean =
sparseArray[element.key]?.let { it == element.value } == true
override fun containsAll(elements: Collection<Map.Entry<Int, T>>): Boolean =
elements.all { contains(it) }
override fun isEmpty(): Boolean = size == 0
override fun iterator(): Iterator<Map.Entry<Int, T>> = entrySequence.iterator()
}
override val keys: Set<Int> = object : Set<Int> {
private val keySequence = entrySequence.map { it.key }
override val size: Int
get() = this@SparseArrayMapWrapper.size
override fun contains(element: Int): Boolean = containsKey(element)
override fun containsAll(elements: Collection<Int>): Boolean =
elements.all { contains(it) }
override fun isEmpty(): Boolean = size == 0
override fun iterator(): Iterator<Int> = keySequence.iterator()
}
override val size: Int
get() = sparseArray.size()
override val values: Collection<T>
get() = object : Collection<T> {
private val valueSequence = entrySequence.map { it.value }
override val size: Int
get() = this@SparseArrayMapWrapper.size
override fun contains(element: T): Boolean = containsValue(element)
override fun containsAll(elements: Collection<T>): Boolean =
elements.all { contains(it) }
override fun isEmpty(): Boolean = this@SparseArrayMapWrapper.isEmpty()
override fun iterator(): Iterator<T> = valueSequence.iterator()
}
override fun containsKey(key: Int): Boolean = sparseArray.contains(key)
override fun containsValue(value: T): Boolean = sparseArray.indexOfValue(value) >= 0
override fun get(key: Int): T? = sparseArray.get(key)
override fun isEmpty(): Boolean = sparseArray.size() == 0
}