/* * 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 Sequence>.toSparseArray(size: Int = -1): SparseArray { val sparseArray = when { size < 0 -> SparseArray() else -> SparseArray(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 Array.associateByToSparseArray( crossinline keySelector: (T) -> Int ): SparseArray { val sparseArray = SparseArray(size) for (value in this) { sparseArray.put(keySelector(value), value) } return sparseArray } /** * Folds a [Grouping] into a [SparseArray]. See [Grouping.fold]. */ inline fun Grouping.foldToSparseArray( initial: R, size: Int = -1, crossinline operation: (R, T) -> R ): SparseArray { val sparseArray = when { size < 0 -> SparseArray() else -> SparseArray(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 SparseArray.asMap(): Map = SparseArrayMapWrapper(this) private class SparseArrayMapWrapper( private val sparseArray: SparseArray ) : Map { private data class Entry(override val key: Int, override val value: T) : Map.Entry 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> get() = object : Set> { override val size: Int get() = this@SparseArrayMapWrapper.size override fun contains(element: Map.Entry): Boolean = sparseArray[element.key]?.let { it == element.value } == true override fun containsAll(elements: Collection>): Boolean = elements.all { contains(it) } override fun isEmpty(): Boolean = size == 0 override fun iterator(): Iterator> = entrySequence.iterator() } override val keys: Set = object : Set { 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): Boolean = elements.all { contains(it) } override fun isEmpty(): Boolean = size == 0 override fun iterator(): Iterator = keySequence.iterator() } override val size: Int get() = sparseArray.size() override val values: Collection get() = object : Collection { 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): Boolean = elements.all { contains(it) } override fun isEmpty(): Boolean = this@SparseArrayMapWrapper.isEmpty() override fun iterator(): Iterator = 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 }