[go: nahoru, domu]

blob: cf44610e415567d0f688365fcbe53005c444c6b4 [file] [log] [blame]
/*
* Copyright 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.
*/
@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
package androidx.compose.collection
import androidx.compose.sortArrayWith
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.math.max
/**
* A [MutableList]-like structure with a simplified interface that offers faster access than
* [ArrayList].
*/
@OptIn(ExperimentalContracts::class, ExperimentalCollectionApi::class)
@ExperimentalCollectionApi
class MutableVector<T> @PublishedApi internal constructor(
@PublishedApi internal var content: Array<T?>,
size: Int
) {
/**
* Stores allocated [MutableList] representation of this vector.
*/
private var list: MutableList<T>? = null
/**
* The number of elements in the [MutableVector].
*/
var size: Int = size
private set
/**
* Returns the last valid index in the [MutableVector].
*/
inline val lastIndex: Int get() = size - 1
/**
* Returns an [IntRange] of the valid indices for this [MutableVector].
*/
inline val indices: IntRange get() = 0..size - 1
/**
* Adds [element] to the [MutableVector] and returns `true`.
*/
fun add(element: T): Boolean {
ensureCapacity(size + 1)
content[size] = element
size++
return true
}
/**
* Adds [element] to the [MutableVector] at the given [index], shifting over any elements
* that are in the way.
*/
fun add(index: Int, element: T) {
ensureCapacity(size + 1)
val content = content
if (index != size) {
content.copyInto(
destination = content,
destinationOffset = index + 1,
startIndex = index,
endIndex = size
)
}
content[index] = element
size++
}
/**
* Adds all [elements] to the [MutableVector] at the given [index], shifting over any
* elements that are in the way.
*/
fun addAll(index: Int, elements: List<T>): Boolean {
if (elements.isEmpty()) return false
ensureCapacity(size + elements.size)
val content = content
if (index != size) {
content.copyInto(
destination = content,
destinationOffset = index + elements.size,
startIndex = index,
endIndex = size
)
}
for (i in elements.indices) {
content[index + i] = elements[i]
}
size += elements.size
return true
}
/**
* Adds all [elements] to the [MutableVector] at the given [index], shifting over any
* elements that are in the way.
*/
fun addAll(index: Int, elements: MutableVector<T>): Boolean {
if (elements.isEmpty()) return false
ensureCapacity(size + elements.size)
val content = content
if (index != size) {
content.copyInto(
destination = content,
destinationOffset = index + elements.size,
startIndex = index,
endIndex = size
)
}
elements.content.copyInto(
destination = content,
destinationOffset = index,
startIndex = 0,
endIndex = elements.size
)
size += elements.size
return true
}
/**
* Adds all [elements] to the end of the [MutableVector] and returns `true` if the
* [MutableVector] was changed.
*/
inline fun addAll(elements: List<T>): Boolean {
return addAll(size, elements)
}
/**
* Adds all [elements] to the end of the [MutableVector] and returns `true` if the
* [MutableVector] was changed.
*/
inline fun addAll(elements: MutableVector<T>): Boolean {
return addAll(size, elements)
}
/**
* Adds all [elements] to the end of the [MutableVector] and returns `true` if the
* [MutableVector] was changed.
*/
fun addAll(
@Suppress("ArrayReturn")
elements: Array<T>
): Boolean {
if (elements.isEmpty()) {
return false
}
ensureCapacity(size + elements.size)
elements.copyInto(
destination = content,
destinationOffset = size
)
return true
}
/**
* Adds all [elements] to the [MutableVector] at the given [index], shifting over any
* elements that are in the way.
*/
fun addAll(index: Int, elements: Collection<T>): Boolean {
if (elements.isEmpty()) return false
ensureCapacity(size + elements.size)
val content = content
if (index != size) {
content.copyInto(
destination = content,
destinationOffset = index + elements.size,
startIndex = index,
endIndex = size
)
}
elements.forEachIndexed { i, item ->
content[index + i] = item
}
size += elements.size
return true
}
/**
* Adds all [elements] to the end of the [MutableVector] and returns `true` if the
* [MutableVector] was changed.
*/
fun addAll(elements: Collection<T>): Boolean {
return addAll(size, elements)
}
/**
* Returns `true` if any of the elements give a `true` return value for [predicate].
*/
inline fun any(predicate: (T) -> Boolean): Boolean {
contract { callsInPlace(predicate) }
for (i in 0..lastIndex) {
if (predicate(get(i))) return true
}
return false
}
/**
* Returns [MutableList] interface access to the [MutableVector].
*/
fun asMutableList(): MutableList<T> {
return list ?: MutableVectorList(this).also {
list = it
}
}
/**
* Removes all elements in the [MutableVector].
*/
fun clear() {
val content = content
for (i in lastIndex downTo 0) {
content[i] = null
}
size = 0
}
/**
* Returns `true` if the [MutableVector] contains [element] or `false` otherwise.
*/
operator fun contains(element: T): Boolean {
for (i in 0..lastIndex) {
if (get(i) == element) return true
}
return false
}
/**
* Returns `true` if the [MutableVector] contains all elements in [elements] or `false` if
* one or more are missing.
*/
fun containsAll(elements: List<T>): Boolean {
for (i in elements.indices) {
if (!contains(elements[i])) return false
}
return true
}
/**
* Returns `true` if the [MutableVector] contains all elements in [elements] or `false` if
* one or more are missing.
*/
fun containsAll(elements: Collection<T>): Boolean {
elements.forEach {
if (!contains(it)) return false
}
return true
}
/**
* Returns `true` if the [MutableVector] contains all elements in [elements] or `false` if
* one or more are missing.
*/
fun containsAll(elements: MutableVector<T>): Boolean {
for (i in elements.indices) {
if (!contains(elements[i])) return false
}
return true
}
/**
* Returns `true` if the contents of the [MutableVector] are the same or `false` if there
* is any difference. This uses equality comparisons on each element rather than reference
* equality.
*/
fun contentEquals(other: MutableVector<T>): Boolean {
if (other.size != size) {
return false
}
for (i in 0..lastIndex) {
if (other[i] != this[i]) {
return false
}
}
return true
}
/**
* Ensures that there is enough space to store [capacity] elements in the [MutableVector].
*/
fun ensureCapacity(capacity: Int) {
val oldContent = content
if (oldContent.size < capacity) {
val newSize = max(capacity, oldContent.size * 2)
content = oldContent.copyOf(newSize)
}
}
/**
* Returns the first element in the [MutableVector] or throws a [NoSuchElementException] if
* it [isEmpty].
*/
fun first(): T {
if (isEmpty()) {
throw NoSuchElementException("MutableVector is empty.")
}
return get(0)
}
/**
* Returns the first element in the [MutableVector] for which [predicate] returns `true` or
* throws [NoSuchElementException] if nothing matches.
*/
inline fun first(predicate: (T) -> Boolean): T {
contract { callsInPlace(predicate) }
for (i in 0..lastIndex) {
val item = get(i)
if (predicate(item)) {
return item
}
}
throwNoSuchElementException()
}
/**
* Returns the first element in the [MutableVector] or `null` if it [isEmpty].
*/
inline fun firstOrNull() = if (isEmpty()) null else get(0)
/**
* Returns the first element in the [MutableVector] for which [predicate] returns `true` or
* returns `null` if nothing matches.
*/
inline fun firstOrNull(predicate: (T) -> Boolean): T? {
contract { callsInPlace(predicate) }
for (i in 0..lastIndex) {
val item = get(i)
if (predicate(item)) {
return item
}
}
return null
}
/**
* Accumulates values, starting with [initial], and applying [operation] to each element
* in the [MutableVector] in order.
*/
inline fun <R> fold(initial: R, operation: (acc: R, T) -> R): R {
contract { callsInPlace(operation) }
var acc = initial
for (i in 0..lastIndex) {
acc = operation(acc, get(i))
}
return acc
}
/**
* Accumulates values, starting with [initial], and applying [operation] to each element
* in the [MutableVector] in order.
*/
inline fun <R> foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R {
contract { callsInPlace(operation) }
var acc = initial
for (i in 0..lastIndex) {
acc = operation(i, acc, get(i))
}
return acc
}
/**
* Accumulates values, starting with [initial], and applying [operation] to each element
* in the [MutableVector] in reverse order.
*/
inline fun <R> foldRight(initial: R, operation: (T, acc: R) -> R): R {
contract { callsInPlace(operation) }
var acc = initial
for (i in lastIndex downTo 0) {
acc = operation(get(i), acc)
}
return acc
}
/**
* Accumulates values, starting with [initial], and applying [operation] to each element
* in the [MutableVector] in reverse order.
*/
inline fun <R> foldRightIndexed(initial: R, operation: (index: Int, T, acc: R) -> R): R {
contract { callsInPlace(operation) }
var acc = initial
for (i in lastIndex downTo 0) {
acc = operation(i, get(i), acc)
}
return acc
}
/**
* Calls [block] for each element in the [MutableVector], in order.
*/
inline fun forEach(block: (T) -> Unit) {
contract { callsInPlace(block) }
for (i in 0..lastIndex) {
block(get(i))
}
}
/**
* Calls [block] for each element in the [MutableVector] along with its index, in order.
*/
inline fun forEachIndexed(block: (Int, T) -> Unit) {
contract { callsInPlace(block) }
for (i in 0 until size) {
block(i, get(i))
}
}
/**
* Calls [block] for each element in the [MutableVector] in reverse order.
*/
inline fun forEachReversed(block: (T) -> Unit) {
contract { callsInPlace(block) }
for (i in lastIndex downTo 0) {
block(get(i))
}
}
/**
* Calls [block] for each element in the [MutableVector] along with its index, in reverse
* order.
*/
inline fun forEachReversedIndexed(block: (Int, T) -> Unit) {
contract { callsInPlace(block) }
for (i in lastIndex downTo 0) {
block(i, get(i))
}
}
/**
* Returns the element at the given [index].
*/
inline operator fun get(index: Int): T = content[index] as T
/**
* Returns the index of [element] in the [MutableVector] or `-1` if [element] is not there.
*/
fun indexOf(element: T): Int {
for (i in 0..lastIndex) {
if (element == get(i)) return i
}
return -1
}
/**
* Returns the index if the first element in the [MutableVector] for which [predicate]
* returns `true`.
*/
inline fun indexOfFirst(predicate: (T) -> Boolean): Int {
contract { callsInPlace(predicate) }
for (i in 0..lastIndex) {
if (predicate(get(i))) {
return i
}
}
return -1
}
/**
* Returns the index if the last element in the [MutableVector] for which [predicate]
* returns `true`.
*/
inline fun indexOfLast(predicate: (T) -> Boolean): Int {
contract { callsInPlace(predicate) }
for (i in lastIndex downTo 0) {
if (predicate(get(i))) {
return i
}
}
return -1
}
/**
* Returns `true` if the [MutableVector] has no elements in it or `false` otherwise.
*/
fun isEmpty(): Boolean = size == 0
/**
* Returns `true` if there are elements in the [MutableVector] or `false` if it is empty.
*/
fun isNotEmpty(): Boolean = size != 0
/**
* Returns the last element in the [MutableVector] or throws a [NoSuchElementException] if
* it [isEmpty].
*/
fun last(): T {
if (isEmpty()) {
throw NoSuchElementException("MutableVector is empty.")
}
return get(lastIndex)
}
/**
* Returns the last element in the [MutableVector] for which [predicate] returns `true` or
* throws [NoSuchElementException] if nothing matches.
*/
inline fun last(predicate: (T) -> Boolean): T {
contract { callsInPlace(predicate) }
for (i in lastIndex downTo 0) {
val item = get(i)
if (predicate(item)) {
return item
}
}
throwNoSuchElementException()
}
/**
* Returns the index of the last element in the [MutableVector] that is the same as
* [element] or `-1` if no elements match.
*/
fun lastIndexOf(element: T): Int {
for (i in lastIndex downTo 0) {
if (element == get(i)) return i
}
return -1
}
/**
* Returns the last element in the [MutableVector] or `null` if it [isEmpty].
*/
inline fun lastOrNull() = if (isEmpty()) null else get(lastIndex)
/**
* Returns the last element in the [MutableVector] for which [predicate] returns `true` or
* returns `null` if nothing matches.
*/
inline fun lastOrNull(predicate: (T) -> Boolean): T? {
contract { callsInPlace(predicate) }
for (i in lastIndex downTo 0) {
val item = get(i)
if (predicate(item)) {
return item
}
}
return null
}
/**
* Returns an [Array] of results of transforming each element in the [MutableVector]. The
* Array will be the same size as this.
*/
@Suppress("ArrayReturn")
inline fun <reified R> map(transform: (T) -> R): Array<R> {
contract { callsInPlace(transform) }
return Array(size) { transform(get(it)) }
}
/**
* Returns an [Array] of results of transforming each element in the [MutableVector]. The
* Array will be the same size as this.
*/
@Suppress("ArrayReturn")
inline fun <reified R> mapIndexed(transform: (index: Int, T) -> R): Array<R> {
contract { callsInPlace(transform) }
return Array(size) { transform(it, get(it)) }
}
/**
* Returns an [MutableVector] of results of transforming each element in the [MutableVector],
* excluding those transformed values that are `null`.
*/
inline fun <reified R> mapIndexedNotNull(transform: (index: Int, T) -> R?): MutableVector<R> {
contract { callsInPlace(transform) }
val arr = arrayOfNulls<R>(size)
var targetSize = 0
for (i in 0..lastIndex) {
val target = transform(i, get(i))
if (target != null) {
arr[targetSize++] = target
}
}
return MutableVector(arr, targetSize)
}
/**
* Returns an [MutableVector] of results of transforming each element in the [MutableVector],
* excluding those transformed values that are `null`.
*/
inline fun <reified R> mapNotNull(transform: (T) -> R?): MutableVector<R> {
contract { callsInPlace(transform) }
val arr = arrayOfNulls<R>(size)
var targetSize = 0
for (i in 0..lastIndex) {
val target = transform(get(i))
if (target != null) {
arr[targetSize++] = target
}
}
return MutableVector(arr, targetSize)
}
/**
* [add] [element] to the [MutableVector].
*/
inline operator fun plusAssign(element: T) {
add(element)
}
/**
* Removes [element] from the [MutableVector]. If [element] was in the [MutableVector]
* and was removed, `true` will be returned, or `false` will be returned if the element
* was not found.
*/
fun remove(element: T): Boolean {
val index = indexOf(element)
if (index >= 0) {
removeAt(index)
return true
}
return false
}
/**
* Removes all [elements] from the [MutableVector] and returns `true` if anything was removed.
*/
fun removeAll(elements: List<T>): Boolean {
val initialSize = size
for (i in elements.indices) {
remove(elements[i])
}
return initialSize != size
}
/**
* Removes all [elements] from the [MutableVector] and returns `true` if anything was removed.
*/
fun removeAll(elements: MutableVector<T>): Boolean {
val initialSize = size
for (i in 0..elements.lastIndex) {
remove(elements.get(i))
}
return initialSize != size
}
/**
* Removes all [elements] from the [MutableVector] and returns `true` if anything was removed.
*/
fun removeAll(elements: Collection<T>): Boolean {
if (elements.isEmpty()) {
return false
}
val initialSize = size
elements.forEach {
remove(it)
}
return initialSize != size
}
/**
* Removes the element at the given [index] and returns it.
*/
fun removeAt(index: Int): T {
val content = content
val item = content[index] as T
if (index != lastIndex) {
content.copyInto(
destination = content,
destinationOffset = index,
startIndex = index + 1,
endIndex = size
)
}
size--
content[size] = null
return item
}
/**
* Removes items from index [start] (inclusive) to [end] (exclusive).
*/
fun removeRange(start: Int, end: Int) {
if (end > start) {
if (end < size) {
content.copyInto(
destination = content,
destinationOffset = start,
startIndex = end,
endIndex = size
)
}
val newSize = size - (end - start)
for (i in newSize..lastIndex) {
content[i] = null // clean up the removed items
}
size = newSize
}
}
/**
* Keeps only [elements] in the [MutableVector] and removes all other values.
*/
fun retainAll(elements: Collection<T>): Boolean {
val initialSize = size
for (i in lastIndex downTo 0) {
val item = get(i)
if (item !in elements) {
removeAt(i)
}
}
return initialSize != size
}
/**
* Sets the value at [index] to [element].
*/
operator fun set(index: Int, element: T): T {
val content = content
val old = content[index] as T
content[index] = element
return old
}
/**
* Sorts the [MutableVector] using [comparator] to order the items.
*/
fun sortWith(comparator: Comparator<T>) {
sortArrayWith(content as Array<T>, comparator = comparator, fromIndex = 0, toIndex = size)
}
/**
* Returns the sum of all values produced by [selector] for each element in the
* [MutableVector].
*/
inline fun sumBy(selector: (T) -> Int): Int {
contract { callsInPlace(selector) }
var sum = 0
for (i in 0..lastIndex) {
sum += selector(get(i))
}
return sum
}
@PublishedApi
internal fun throwNoSuchElementException(): Nothing {
throw NoSuchElementException("MutableVector contains no element matching the predicate.")
}
private class VectorListIterator<T>(
private val list: MutableList<T>,
private var index: Int
) : MutableListIterator<T> {
override fun hasNext(): Boolean {
return index < list.size
}
override fun next(): T {
return list[index++]
}
override fun remove() {
index--
list.removeAt(index)
}
override fun hasPrevious(): Boolean {
return index > 0
}
override fun nextIndex(): Int {
return index
}
override fun previous(): T {
index--
return list[index]
}
override fun previousIndex(): Int {
return index - 1
}
override fun add(element: T) {
list.add(index, element)
index++
}
override fun set(element: T) {
list[index] = element
}
}
/**
* [MutableList] implementation for a [MutableVector], used in [asMutableList].
*/
private class MutableVectorList<T>(private val vector: MutableVector<T>) : MutableList<T> {
override val size: Int
get() = vector.size
override fun contains(element: T): Boolean = vector.contains(element)
override fun containsAll(elements: Collection<T>): Boolean = vector.containsAll(elements)
override fun get(index: Int): T = vector[index]
override fun indexOf(element: T): Int = vector.indexOf(element)
override fun isEmpty(): Boolean = vector.isEmpty()
override fun iterator(): MutableIterator<T> = VectorListIterator(this, 0)
override fun lastIndexOf(element: T): Int = vector.lastIndexOf(element)
override fun add(element: T): Boolean = vector.add(element)
override fun add(index: Int, element: T) = vector.add(index, element)
override fun addAll(index: Int, elements: Collection<T>): Boolean =
vector.addAll(index, elements)
override fun addAll(elements: Collection<T>): Boolean = vector.addAll(elements)
override fun clear() = vector.clear()
override fun listIterator(): MutableListIterator<T> = VectorListIterator(this, 0)
override fun listIterator(index: Int): MutableListIterator<T> =
VectorListIterator(this, index)
override fun remove(element: T): Boolean = vector.remove(element)
override fun removeAll(elements: Collection<T>): Boolean = vector.removeAll(elements)
override fun removeAt(index: Int): T = vector.removeAt(index)
override fun retainAll(elements: Collection<T>): Boolean = vector.retainAll(elements)
override fun set(index: Int, element: T): T = vector.set(index, element)
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> =
SubList(this, fromIndex, toIndex)
}
/**
* A view into an underlying [MutableList] that directly accesses the underlying [MutableList].
* This is important for the implementation of [List.subList]. A change to the [SubList]
* also changes the referenced [MutableList].
*/
private class SubList<T>(
private val list: MutableList<T>,
private val start: Int,
private var end: Int
) : MutableList<T> {
override val size: Int
get() = end - start
override fun contains(element: T): Boolean {
for (i in start until end) {
if (list[i] == element) {
return true
}
}
return false
}
override fun containsAll(elements: Collection<T>): Boolean {
elements.forEach {
if (!contains(it)) {
return false
}
}
return true
}
override fun get(index: Int): T = list[index + start]
override fun indexOf(element: T): Int {
for (i in start until end) {
if (list[i] == element) {
return i - start
}
}
return -1
}
override fun isEmpty(): Boolean = end == start
override fun iterator(): MutableIterator<T> = VectorListIterator(this, 0)
override fun lastIndexOf(element: T): Int {
for (i in end - 1 downTo start) {
if (list[i] == element) {
return i - start
}
}
return -1
}
override fun add(element: T): Boolean {
list.add(end++, element)
return true
}
override fun add(index: Int, element: T) {
list.add(index + start, element)
end++
}
override fun addAll(index: Int, elements: Collection<T>): Boolean {
list.addAll(index + start, elements)
end += elements.size
return elements.size > 0
}
override fun addAll(elements: Collection<T>): Boolean {
list.addAll(end, elements)
end += elements.size
return elements.size > 0
}
override fun clear() {
for (i in end - 1 downTo start) {
list.removeAt(i)
}
end = start
}
override fun listIterator(): MutableListIterator<T> = VectorListIterator(this, 0)
override fun listIterator(index: Int): MutableListIterator<T> =
VectorListIterator(this, index)
override fun remove(element: T): Boolean {
for (i in start until end) {
if (list[i] == element) {
list.removeAt(i)
end--
return true
}
}
return false
}
override fun removeAll(elements: Collection<T>): Boolean {
val originalEnd = end
elements.forEach {
remove(it)
}
return originalEnd != end
}
override fun removeAt(index: Int): T {
val item = list.removeAt(index + start)
end--
return item
}
override fun retainAll(elements: Collection<T>): Boolean {
val originalEnd = end
for (i in end - 1 downTo start) {
val item = list[i]
if (item !in elements) {
list.removeAt(i)
end--
}
}
return originalEnd != end
}
override fun set(index: Int, element: T): T = list.set(index + start, element)
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> =
SubList(this, fromIndex, toIndex)
}
}
/**
* Create a [MutableVector] with a given initial [capacity].
*
* @see MutableVector.ensureCapacity
*/
@ExperimentalCollectionApi
inline fun <reified T> MutableVector(capacity: Int = 16) =
MutableVector<T>(arrayOfNulls<T>(capacity), 0)
/**
* Create a [MutableVector] with a given [size], initialiing each element using the [init]
* function.
*
* [init] is called for each element in the [MutableVector], starting from the first one and should
* return the value to be assigned to the element at its given index.
*/
@OptIn(ExperimentalContracts::class)
@ExperimentalCollectionApi
inline fun <reified T> MutableVector(size: Int, noinline init: (Int) -> T): MutableVector<T> {
contract { callsInPlace(init) }
val arr = Array(size, init)
return MutableVector(arr as Array<T?>, size)
}
/**
* Creates an empty [MutableVector] with a [capacity][MutableVector.ensureCapacity] of 16.
*/
@ExperimentalCollectionApi
inline fun <reified T> mutableVectorOf() =
MutableVector<T>()
/**
* Creates a [MutableVector] with the given values. This will use the passed vararg [elements]
* storage.
*/
@ExperimentalCollectionApi
inline fun <reified T> mutableVectorOf(vararg elements: T): MutableVector<T> {
return MutableVector(
elements as Array<T?>,
elements.size
)
}