1 /* <lambda>null2 * Copyright 2022 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 androidx.compose.foundation.lazy.layout 18 19 import androidx.collection.MutableObjectIntMap 20 import androidx.collection.ObjectIntMap 21 import androidx.collection.emptyObjectIntMap 22 import androidx.compose.foundation.internal.checkPrecondition 23 24 /** 25 * A key-index mapping used inside the [LazyLayoutItemProvider]. It might not contain all items in 26 * the lazy layout as optimization, but it must cover items the provider is requesting during layout 27 * pass. See [NearestRangeKeyIndexMap] as sample implementation that samples items near current 28 * viewport. 29 */ 30 internal interface LazyLayoutKeyIndexMap { 31 /** @return current index for given [key] or `-1` if not found. */ 32 fun getIndex(key: Any): Int 33 34 /** @return key for a given [index] if it is known, or null otherwise. */ 35 fun getKey(index: Int): Any? 36 37 /** Empty map implementation, always returning `-1` for any key. */ 38 companion object Empty : LazyLayoutKeyIndexMap { 39 @Suppress("AutoBoxing") override fun getIndex(key: Any): Int = -1 40 41 override fun getKey(index: Int) = null 42 } 43 } 44 45 /** 46 * Implementation of [LazyLayoutKeyIndexMap] indexing over given [IntRange] of items. Items outside 47 * of given range are considered unknown, with null returned as the index. 48 */ 49 internal class NearestRangeKeyIndexMap( 50 nearestRange: IntRange, 51 intervalContent: LazyLayoutIntervalContent<*> 52 ) : LazyLayoutKeyIndexMap { 53 private val map: ObjectIntMap<Any> 54 private val keys: Array<Any?> 55 private val keysStartIndex: Int 56 57 init { 58 // Traverses the interval [list] in order to create a mapping from the key to the index for 59 // all the indexes in the passed [range]. 60 val list = intervalContent.intervals 61 val first = nearestRange.first <lambda>null62 checkPrecondition(first >= 0) { "negative nearestRange.first" } 63 val last = minOf(nearestRange.last, list.size - 1) 64 if (last < first) { 65 map = emptyObjectIntMap() 66 keys = emptyArray() 67 keysStartIndex = 0 68 } else { 69 val size = last - first + 1 70 keys = arrayOfNulls<Any?>(size) 71 keysStartIndex = first 72 map = mapnull73 MutableObjectIntMap<Any>(size).also { map -> 74 list.forEach( 75 fromIndex = first, 76 toIndex = last, 77 ) { 78 val keyFactory = it.value.key 79 val start = maxOf(first, it.startIndex) 80 val end = minOf(last, it.startIndex + it.size - 1) 81 for (i in start..end) { 82 val key = 83 keyFactory?.invoke(i - it.startIndex) ?: getDefaultLazyLayoutKey(i) 84 map[key] = i 85 keys[i - keysStartIndex] = key 86 } 87 } 88 } 89 } 90 } 91 <lambda>null92 override fun getIndex(key: Any): Int = map.getOrElse(key) { -1 } 93 <lambda>null94 override fun getKey(index: Int) = keys.getOrElse(index - keysStartIndex) { null } 95 } 96