[Wasm][Stdlib] Reuse K/N collections and StringBuilder

This commit is contained in:
Svyatoslav Kuzmich
2021-09-22 19:44:14 +03:00
parent 6ad6bca503
commit ab9a23cbfa
286 changed files with 1099 additions and 1409 deletions
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* Provides a skeletal implementation of the [MutableCollection] interface.
*
* @param E the type of elements contained in the collection. The collection is invariant in its element type.
*/
public actual abstract class AbstractMutableCollection<E> protected actual constructor(): MutableCollection<E>, AbstractCollection<E>() {
// Bulk Modification Operations
/**
* Adds all of the elements of the specified collection to this collection.
*
* @return `true` if any of the specified elements was added to the collection, `false` if the collection was not modified.
*/
actual override public fun addAll(elements: Collection<E>): Boolean {
var changed = false
for (v in elements) {
if (add(v)) changed = true
}
return changed
}
/**
* Removes a single instance of the specified element from this
* collection, if it is present.
*
* @return `true` if the element has been successfully removed; `false` if it was not present in the collection.
*/
actual override fun remove(element: E): Boolean {
val it = iterator()
while (it.hasNext()) {
if (it.next() == element) {
it.remove()
return true
}
}
return false
}
/**
* Removes all of this collection's elements that are also contained in the specified collection.
*
* @return `true` if any of the specified elements was removed from the collection, `false` if the collection was not modified.
*/
actual override public fun removeAll(elements: Collection<E>): Boolean = (this as MutableIterable<E>).removeAll { it in elements }
/**
* Retains only the elements in this collection that are contained in the specified collection.
*
* @return `true` if any element was removed from the collection, `false` if the collection was not modified.
*/
actual override public fun retainAll(elements: Collection<E>): Boolean = (this as MutableIterable<E>).retainAll { it in elements }
/**
* Removes all elements from this collection.
*/
actual override fun clear(): Unit {
val it = iterator()
while (it.hasNext()) {
it.next()
it.remove()
}
}
}
@@ -0,0 +1,204 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* AbstractMutableList implementation copied from JS backend
* (see <Kotlin JVM root>js/js.libraries/src/core/collections/AbstractMutableList.kt).
*
* Based on GWT AbstractList
* Copyright 2007 Google Inc.
*/
/**
* Provides a skeletal implementation of the [MutableList] interface.
*
* @param E the type of elements contained in the list. The list is invariant in its element type.
*/
public actual abstract class AbstractMutableList<E> protected actual constructor() : AbstractMutableCollection<E>(), MutableList<E> {
protected var modCount: Int = 0
abstract override fun add(index: Int, element: E): Unit
abstract override fun removeAt(index: Int): E
abstract override fun set(index: Int, element: E): E
/**
* Adds the specified element to the end of this list.
*
* @return `true` because the list is always modified as the result of this operation.
*/
override actual fun add(element: E): Boolean {
add(size, element)
return true
}
override actual fun addAll(index: Int, elements: Collection<E>): Boolean {
AbstractList.checkPositionIndex(index, size)
var i = index
var changed = false
for (e in elements) {
add(i++, e)
changed = true
}
return changed
}
override actual fun clear() {
removeRange(0, size)
}
override actual fun removeAll(elements: Collection<E>): Boolean = removeAll { it in elements }
override actual fun retainAll(elements: Collection<E>): Boolean = removeAll { it !in elements }
override actual fun iterator(): MutableIterator<E> = IteratorImpl()
override actual fun contains(element: E): Boolean = indexOf(element) >= 0
override actual fun indexOf(element: E): Int {
for (index in 0..lastIndex) {
if (get(index) == element) {
return index
}
}
return -1
}
override actual fun lastIndexOf(element: E): Int {
for (index in lastIndex downTo 0) {
if (get(index) == element) {
return index
}
}
return -1
}
override actual fun listIterator(): MutableListIterator<E> = listIterator(0)
override actual fun listIterator(index: Int): MutableListIterator<E> = ListIteratorImpl(index)
override actual fun subList(fromIndex: Int, toIndex: Int): MutableList<E> = SubList(this, fromIndex, toIndex)
/**
* Removes the range of elements from this list starting from [fromIndex] and ending with but not including [toIndex].
*/
protected open fun removeRange(fromIndex: Int, toIndex: Int) {
val iterator = listIterator(fromIndex)
repeat(toIndex - fromIndex) {
iterator.next()
iterator.remove()
}
}
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is List<*>) return false
return AbstractList.orderedEquals(this, other)
}
override fun hashCode(): Int = AbstractList.orderedHashCode(this)
private open inner class IteratorImpl : MutableIterator<E> {
/** the index of the item that will be returned on the next call to [next]`()` */
protected var index = 0
/** the index of the item that was returned on the previous call to [next]`()`
* or [ListIterator.previous]`()` (for `ListIterator`),
* -1 if no such item exists
*/
protected var last = -1
override fun hasNext(): Boolean = index < size
override fun next(): E {
if (!hasNext()) throw NoSuchElementException()
last = index++
return get(last)
}
override fun remove() {
check(last != -1) { "Call next() or previous() before removing element from the iterator."}
removeAt(last)
index = last
last = -1
}
}
/**
* Implementation of `MutableListIterator` for abstract lists.
*/
private inner class ListIteratorImpl(index: Int) : IteratorImpl(), MutableListIterator<E> {
init {
AbstractList.checkPositionIndex(index, this@AbstractMutableList.size)
this.index = index
}
override fun hasPrevious(): Boolean = index > 0
override fun nextIndex(): Int = index
override fun previous(): E {
if (!hasPrevious()) throw NoSuchElementException()
last = --index
return get(last)
}
override fun previousIndex(): Int = index - 1
override fun add(element: E) {
add(index, element)
index++
last = -1
}
override fun set(element: E) {
check(last != -1) { "Call next() or previous() before updating element value with the iterator."}
this@AbstractMutableList[last] = element
}
}
private class SubList<E>(private val list: AbstractMutableList<E>, private val fromIndex: Int, toIndex: Int) : AbstractMutableList<E>() {
private var _size: Int = 0
init {
AbstractList.checkRangeIndexes(fromIndex, toIndex, list.size)
this._size = toIndex - fromIndex
}
override fun add(index: Int, element: E) {
AbstractList.checkPositionIndex(index, _size)
list.add(fromIndex + index, element)
_size++
}
override fun get(index: Int): E {
AbstractList.checkElementIndex(index, _size)
return list[fromIndex + index]
}
override fun removeAt(index: Int): E {
AbstractList.checkElementIndex(index, _size)
val result = list.removeAt(fromIndex + index)
_size--
return result
}
override fun set(index: Int, element: E): E {
AbstractList.checkElementIndex(index, _size)
return list.set(fromIndex + index, element)
}
override val size: Int get() = _size
}
}
@@ -0,0 +1,135 @@
package kotlin.collections
/**
* Provides a skeletal implementation of the [MutableMap] interface.
*
* The implementor is required to implement [entries] property, which should return mutable set of map entries, and [put] function.
*
* @param K the type of map keys. The map is invariant in its key type.
* @param V the type of map values. The map is invariant in its value type.
*/
@SinceKotlin("1.1")
public actual abstract class AbstractMutableMap<K, V> protected actual constructor() : AbstractMap<K, V>(), MutableMap<K, V> {
/**
* Associates the specified [value] with the specified [key] in the map.
*
* @return the previous value associated with the key, or `null` if the key was not present in the map.
*/
actual abstract override fun put(key: K, value: V): V?
/**
* A mutable [Map.Entry] shared by several [Map] implementations.
*/
internal open class SimpleEntry<K, V>(override val key: K, value: V) : MutableMap.MutableEntry<K, V> {
constructor(entry: Map.Entry<K, V>) : this(entry.key, entry.value)
private var _value = value
override val value: V get() = _value
override fun setValue(newValue: V): V {
val oldValue = this._value
this._value = newValue
return oldValue
}
override fun hashCode(): Int = entryHashCode(this)
override fun toString(): String = entryToString(this)
override fun equals(other: Any?): Boolean = entryEquals(this, other)
}
actual override fun putAll(from: Map<out K, V>) {
for ((key, value) in from) {
put(key, value)
}
}
actual override fun remove(key: K): V? {
val iter = entries.iterator()
while (iter.hasNext()) {
val entry = iter.next()
val k = entry.key
if (key == k) {
val value = entry.value
iter.remove()
return value
}
}
return null
}
actual override fun clear() {
entries.clear()
}
private var _keys: MutableSet<K>? = null
actual override val keys: MutableSet<K>
get() {
if (_keys == null) {
_keys = object : AbstractMutableSet<K>() {
override fun add(element: K): Boolean = throw UnsupportedOperationException("Add is not supported on keys")
override fun clear() {
this@AbstractMutableMap.clear()
}
override operator fun contains(element: K): Boolean = containsKey(element)
override operator fun iterator(): MutableIterator<K> {
val entryIterator = entries.iterator()
return object : MutableIterator<K> {
override fun hasNext(): Boolean = entryIterator.hasNext()
override fun next(): K = entryIterator.next().key
override fun remove() = entryIterator.remove()
}
}
override fun remove(element: K): Boolean {
if (containsKey(element)) {
this@AbstractMutableMap.remove(element)
return true
}
return false
}
override val size: Int get() = this@AbstractMutableMap.size
}
}
return _keys!!
}
private var _values: MutableCollection<V>? = null
actual override val values: MutableCollection<V>
get() {
if (_values == null) {
_values = object : AbstractMutableCollection<V>() {
override fun add(element: V): Boolean = throw UnsupportedOperationException("Add is not supported on values")
override fun clear() = this@AbstractMutableMap.clear()
override operator fun contains(element: V): Boolean = containsValue(element)
override operator fun iterator(): MutableIterator<V> {
val entryIterator = entries.iterator()
return object : MutableIterator<V> {
override fun hasNext(): Boolean = entryIterator.hasNext()
override fun next(): V = entryIterator.next().value
override fun remove() = entryIterator.remove()
}
}
override val size: Int get() = this@AbstractMutableMap.size
// TODO: should we implement them this way? Currently it's unspecified in JVM
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Collection<*>) return false
return AbstractList.orderedEquals(this, other)
}
override fun hashCode(): Int = AbstractList.orderedHashCode(this)
}
}
return _values!!
}
}
@@ -0,0 +1,32 @@
package kotlin.collections
/**
* Provides a skeletal implementation of the [MutableSet] interface.
*
* @param E the type of elements contained in the set. The set is invariant in its element type.
*/
@SinceKotlin("1.1")
public actual abstract class AbstractMutableSet<E> protected actual constructor() : AbstractMutableCollection<E>(), MutableSet<E> {
/**
* Adds the specified element to the set.
*
* @return `true` if the element has been added, `false` if the element is already contained in the set.
*/
actual abstract override fun add(element: E): Boolean
/**
* Compares this set with another set instance with the unordered structural equality.
*
* @return `true`, if [other] instance is a [Set] of the same size, all elements of which are contained in this set.
*/
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is Set<*>) return false
return AbstractSet.setEquals(this, other)
}
/**
* Returns the hash code value for this set.
*/
override fun hashCode(): Int = AbstractSet.unorderedHashCode(this)
}
@@ -0,0 +1,370 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
actual class ArrayList<E> private constructor(
private var array: Array<E>,
private var offset: Int,
private var length: Int,
private var isReadOnly: Boolean,
private val backing: ArrayList<E>?,
private val root: ArrayList<E>?
) : MutableList<E>, RandomAccess, AbstractMutableList<E>() {
actual constructor() : this(10)
actual constructor(initialCapacity: Int) : this(
arrayOfUninitializedElements(initialCapacity), 0, 0, false, null, null)
actual constructor(elements: Collection<E>) : this(elements.size) {
addAll(elements)
}
@PublishedApi
internal fun build(): List<E> {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ArrayList
checkIsMutable()
isReadOnly = true
return this
}
override actual val size: Int
get() = length
override actual fun isEmpty(): Boolean = length == 0
override actual fun get(index: Int): E {
checkElementIndex(index)
return array[offset + index]
}
override actual operator fun set(index: Int, element: E): E {
checkIsMutable()
checkElementIndex(index)
val old = array[offset + index]
array[offset + index] = element
return old
}
override actual fun indexOf(element: E): Int {
var i = 0
while (i < length) {
if (array[offset + i] == element) return i
i++
}
return -1
}
override actual fun lastIndexOf(element: E): Int {
var i = length - 1
while (i >= 0) {
if (array[offset + i] == element) return i
i--
}
return -1
}
override actual fun iterator(): MutableIterator<E> = Itr(this, 0)
override actual fun listIterator(): MutableListIterator<E> = Itr(this, 0)
override actual fun listIterator(index: Int): MutableListIterator<E> {
checkPositionIndex(index)
return Itr(this, index)
}
override actual fun add(element: E): Boolean {
checkIsMutable()
addAtInternal(offset + length, element)
return true
}
override actual fun add(index: Int, element: E) {
checkIsMutable()
checkPositionIndex(index)
addAtInternal(offset + index, element)
}
override actual fun addAll(elements: Collection<E>): Boolean {
checkIsMutable()
val n = elements.size
addAllInternal(offset + length, elements, n)
return n > 0
}
override actual fun addAll(index: Int, elements: Collection<E>): Boolean {
checkIsMutable()
checkPositionIndex(index)
val n = elements.size
addAllInternal(offset + index, elements, n)
return n > 0
}
override actual fun clear() {
checkIsMutable()
removeRangeInternal(offset, length)
}
override actual fun removeAt(index: Int): E {
checkIsMutable()
checkElementIndex(index)
return removeAtInternal(offset + index)
}
override actual fun remove(element: E): Boolean {
checkIsMutable()
val i = indexOf(element)
if (i >= 0) removeAt(i)
return i >= 0
}
override actual fun removeAll(elements: Collection<E>): Boolean {
checkIsMutable()
return retainOrRemoveAllInternal(offset, length, elements, false) > 0
}
override actual fun retainAll(elements: Collection<E>): Boolean {
checkIsMutable()
return retainOrRemoveAllInternal(offset, length, elements, true) > 0
}
override actual fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
checkRangeIndexes(fromIndex, toIndex)
return ArrayList(array, offset + fromIndex, toIndex - fromIndex, isReadOnly, this, root ?: this)
}
actual fun trimToSize() {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ArrayList
if (length < array.size)
array = array.copyOfUninitializedElements(length)
}
final actual fun ensureCapacity(minCapacity: Int) {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ArrayList
if (minCapacity < 0) throw OutOfMemoryError() // overflow
if (minCapacity > array.size) {
val newSize = ArrayDeque.newCapacity(array.size, minCapacity)
array = array.copyOfUninitializedElements(newSize)
}
}
override fun equals(other: Any?): Boolean {
return other === this ||
(other is List<*>) && contentEquals(other)
}
override fun hashCode(): Int {
return array.subarrayContentHashCode(offset, length)
}
override fun toString(): String {
@Suppress("DEPRECATION_ERROR")
return array.subarrayContentToString(offset, length)
}
@Suppress("UNCHECKED_CAST")
override fun <T> toArray(destination: Array<T>): Array<T> {
if (destination.size < length) {
return array.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<T>
}
(array as Array<T>).copyInto(destination, 0, startIndex = offset, endIndex = offset + length)
if (destination.size > length) {
destination[length] = null as T // null-terminate
}
return destination
}
override fun toArray(): Array<Any?> {
@Suppress("UNCHECKED_CAST")
return array.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<Any?>
}
// ---------------------------- private ----------------------------
private fun checkElementIndex(index: Int) {
if (index < 0 || index >= length) {
throw IndexOutOfBoundsException("index: $index, size: $length")
}
}
private fun checkPositionIndex(index: Int) {
if (index < 0 || index > length) {
throw IndexOutOfBoundsException("index: $index, size: $length")
}
}
private fun checkRangeIndexes(fromIndex: Int, toIndex: Int) {
if (fromIndex < 0 || toIndex > length) {
throw IndexOutOfBoundsException("fromIndex: $fromIndex, toIndex: $toIndex, size: $length")
}
if (fromIndex > toIndex) {
throw IllegalArgumentException("fromIndex: $fromIndex > toIndex: $toIndex")
}
}
private fun checkIsMutable() {
if (isReadOnly || root != null && root.isReadOnly) throw UnsupportedOperationException()
}
private fun ensureExtraCapacity(n: Int) {
ensureCapacity(length + n)
}
private fun contentEquals(other: List<*>): Boolean {
return array.subarrayContentEquals(offset, length, other)
}
private fun insertAtInternal(i: Int, n: Int) {
ensureExtraCapacity(n)
array.copyInto(array, startIndex = i, endIndex = offset + length, destinationOffset = i + n)
length += n
}
private fun addAtInternal(i: Int, element: E) {
if (backing != null) {
backing.addAtInternal(i, element)
array = backing.array
length++
} else {
insertAtInternal(i, 1)
array[i] = element
}
}
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
if (backing != null) {
backing.addAllInternal(i, elements, n)
array = backing.array
length += n
} else {
insertAtInternal(i, n)
var j = 0
val it = elements.iterator()
while (j < n) {
array[i + j] = it.next()
j++
}
}
}
private fun removeAtInternal(i: Int): E {
if (backing != null) {
val old = backing.removeAtInternal(i)
length--
return old
} else {
val old = array[i]
array.copyInto(array, startIndex = i + 1, endIndex = offset + length, destinationOffset = i)
array.resetAt(offset + length - 1)
length--
return old
}
}
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
if (backing != null) {
backing.removeRangeInternal(rangeOffset, rangeLength)
} else {
array.copyInto(array, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset)
array.resetRange(fromIndex = length - rangeLength, toIndex = length)
}
length -= rangeLength
}
/** Retains elements if [retain] == true and removes them it [retain] == false. */
private fun retainOrRemoveAllInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>, retain: Boolean): Int {
if (backing != null) {
val removed = backing.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
length -= removed
return removed
} else {
var i = 0
var j = 0
while (i < rangeLength) {
if (elements.contains(array[rangeOffset + i]) == retain) {
array[rangeOffset + j++] = array[rangeOffset + i++]
} else {
i++
}
}
val removed = rangeLength - j
array.copyInto(array, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset + j)
array.resetRange(fromIndex = length - removed, toIndex = length)
length -= removed
return removed
}
}
private class Itr<E> : MutableListIterator<E> {
private val list: ArrayList<E>
private var index: Int
private var lastIndex: Int
constructor(list: ArrayList<E>, index: Int) {
this.list = list
this.index = index
this.lastIndex = -1
}
override fun hasPrevious(): Boolean = index > 0
override fun hasNext(): Boolean = index < list.length
override fun previousIndex(): Int = index - 1
override fun nextIndex(): Int = index
override fun previous(): E {
if (index <= 0) throw NoSuchElementException()
lastIndex = --index
return list.array[list.offset + lastIndex]
}
override fun next(): E {
if (index >= list.length) throw NoSuchElementException()
lastIndex = index++
return list.array[list.offset + lastIndex]
}
override fun set(element: E) {
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
list.set(lastIndex, element)
}
override fun add(element: E) {
list.add(index++, element)
lastIndex = -1
}
override fun remove() {
check(lastIndex != -1) { "Call next() or previous() before removing element from the iterator." }
list.removeAt(lastIndex)
index = lastIndex
lastIndex = -1
}
}
}
private fun <T> Array<T>.subarrayContentHashCode(offset: Int, length: Int): Int {
var result = 1
var i = 0
while (i < length) {
val nextElement = this[offset + i]
result = result * 31 + nextElement.hashCode()
i++
}
return result
}
private fun <T> Array<T>.subarrayContentEquals(offset: Int, length: Int, other: List<*>): Boolean {
if (length != other.size) return false
var i = 0
while (i < length) {
if (this[offset + i] != other[i]) return false
i++
}
return true
}
@@ -0,0 +1,395 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
private fun <T: Comparable<T>> mergeSort(array: Array<T>, start: Int, endInclusive: Int) {
@Suppress("UNCHECKED_CAST")
val buffer = arrayOfNulls<Any?>(array.size) as Array<T>
val result = mergeSort(array, buffer, start, endInclusive)
if (result !== array) {
for (i in start..endInclusive) array[i] = result[i]
}
}
// Both start and end are inclusive indices.
private fun <T: Comparable<T>> mergeSort(array: Array<T>, buffer: Array<T>, start: Int, end: Int): Array<T> {
if (start == end) {
return array
}
val median = (start + end) / 2
val left = mergeSort(array, buffer, start, median)
val right = mergeSort(array, buffer, median + 1, end)
val target = if (left === buffer) array else buffer
// Merge.
var leftIndex = start
var rightIndex = median + 1
for (i in start..end) {
when {
leftIndex <= median && rightIndex <= end -> {
val leftValue = left[leftIndex]
val rightValue = right[rightIndex]
if (leftValue <= rightValue) {
target[i] = leftValue
leftIndex++
} else {
target[i] = rightValue
rightIndex++
}
}
leftIndex <= median -> {
target[i] = left[leftIndex]
leftIndex++
}
else /* rightIndex <= end */ -> {
target[i] = right[rightIndex]
rightIndex++
}
}
}
return target
}
// Sort with comparator.
private fun <T> mergeSort(array: Array<T>, start: Int, endInclusive: Int, comparator: Comparator<T>) {
@Suppress("UNCHECKED_CAST")
val buffer = arrayOfNulls<Any?>(array.size) as Array<T>
val result = mergeSort(array, buffer, start, endInclusive, comparator)
if (result !== array) {
for (i in start..endInclusive) array[i] = result[i]
}
}
// Both start and end are inclusive indices.
private fun <T> mergeSort(array: Array<T>, buffer: Array<T>, start: Int, end: Int, comparator: Comparator<T>): Array<T> {
if (start == end) {
return array
}
val median = (start + end) / 2
val left = mergeSort(array, buffer, start, median, comparator)
val right = mergeSort(array, buffer, median + 1, end, comparator)
val target = if (left === buffer) array else buffer
// Merge.
var leftIndex = start
var rightIndex = median + 1
for (i in start..end) {
when {
leftIndex <= median && rightIndex <= end -> {
val leftValue = left[leftIndex]
val rightValue = right[rightIndex]
if (comparator.compare(leftValue, rightValue) <= 0) {
target[i] = leftValue
leftIndex++
} else {
target[i] = rightValue
rightIndex++
}
}
leftIndex <= median -> {
target[i] = left[leftIndex]
leftIndex++
}
else /* rightIndex <= end */ -> {
target[i] = right[rightIndex]
rightIndex++
}
}
}
return target
}
// ByteArray =============================================================================
private fun partition(
array: ByteArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i] < pivot)
i++
while (array[j] > pivot)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: ByteArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// ShortArray =============================================================================
private fun partition(
array: ShortArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i] < pivot)
i++
while (array[j] > pivot)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: ShortArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// IntArray =============================================================================
private fun partition(
array: IntArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i] < pivot)
i++
while (array[j] > pivot)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: IntArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// LongArray =============================================================================
private fun partition(
array: LongArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i] < pivot)
i++
while (array[j] > pivot)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: LongArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// CharArray =============================================================================
private fun partition(
array: CharArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i] < pivot)
i++
while (array[j] > pivot)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: CharArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// FloatArray =============================================================================
private fun partition(
array: FloatArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i].compareTo(pivot) < 0)
i++
while (array[j].compareTo(pivot) > 0)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: FloatArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// DoubleArray =============================================================================
private fun partition(
array: DoubleArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i].compareTo(pivot) < 0)
i++
while (array[j].compareTo(pivot) > 0)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: DoubleArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// BooleanArray =============================================================================
private fun partition(
array: BooleanArray, left: Int, right: Int): Int {
var i = left
var j = right
val pivot = array[(left + right) / 2]
while (i <= j) {
while (array[i] < pivot)
i++
while (array[j] > pivot)
j--
if (i <= j) {
val tmp = array[i]
array[i] = array[j]
array[j] = tmp
i++
j--
}
}
return i
}
private fun quickSort(
array: BooleanArray, left: Int, right: Int) {
val index = partition(array, left, right)
if (left < index - 1)
quickSort(array, left, index - 1)
if (index < right)
quickSort(array, index, right)
}
// Interfaces =============================================================================
/**
* Sorts the subarray specified by [fromIndex] (inclusive) and [toIndex] (exclusive) parameters
* using the merge sort algorithm with the given [comparator].
*/
internal fun <T> sortArrayWith(array: Array<out T>, fromIndex: Int, toIndex: Int, comparator: Comparator<T>) {
if (fromIndex < toIndex - 1) {
@Suppress("UNCHECKED_CAST")
mergeSort(array as Array<T>, fromIndex, toIndex - 1, comparator)
}
}
/**
* Sorts a subarray of [Comparable] elements specified by [fromIndex] (inclusive) and
* [toIndex] (exclusive) parameters using the merge sort algorithm.
*/
internal fun <T: Comparable<T>> sortArray(array: Array<out T>, fromIndex: Int, toIndex: Int) {
if (fromIndex < toIndex - 1) {
@Suppress("UNCHECKED_CAST")
mergeSort(array as Array<T>, fromIndex, toIndex - 1)
}
}
/**
* Sorts the given array using qsort algorithm.
*/
internal fun sortArray(array: ByteArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
internal fun sortArray(array: ShortArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
internal fun sortArray(array: IntArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
internal fun sortArray(array: LongArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
internal fun sortArray(array: CharArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
internal fun sortArray(array: FloatArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
internal fun sortArray(array: DoubleArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
internal fun sortArray(array: BooleanArray, fromIndex: Int, toIndex: Int) = quickSort(array, fromIndex, toIndex - 1)
@@ -0,0 +1,125 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
import kotlin.internal.PureReifiable
/**
* Returns the array if it's not `null`, or an empty array otherwise.
* @sample samples.collections.Arrays.Usage.arrayOrEmpty
*/
public actual inline fun <reified T> Array<out T>?.orEmpty(): Array<out T> = this ?: emptyArray<T>()
internal fun checkCopyOfRangeArguments(fromIndex: Int, toIndex: Int, size: Int) {
if (toIndex > size)
throw IndexOutOfBoundsException("toIndex ($toIndex) is greater than size ($size).")
if (fromIndex > toIndex)
throw IllegalArgumentException("fromIndex ($fromIndex) is greater than toIndex ($toIndex).")
}
// TODO: internal
/**
* Returns a string representation of the contents of the subarray of the specified array as if it is [List].
*/
@kotlin.internal.InlineOnly
@Deprecated("This function will become internal soon.")
@DeprecatedSinceKotlin(warningSince = "1.4", errorSince = "1.5")
public inline fun <T> Array<out T>.subarrayContentToString(offset: Int, length: Int): String {
val sb = StringBuilder(2 + length * 3)
sb.append("[")
var i = 0
while (i < length) {
if (i > 0) sb.append(", ")
sb.append(this[offset + i])
i++
}
sb.append("]")
return sb.toString()
}
/**
* Returns a hash code based on the contents of this array as if it is [List].
* Nested arrays are treated as lists too.
*
* If any of arrays contains itself on any nesting level the behavior is undefined.
*/
@SinceKotlin("1.1")
@OptIn(ExperimentalUnsignedTypes::class)
internal fun <T> Array<out T>?.contentDeepHashCodeImpl(): Int {
if (this == null) return 0
var result = 1
for (element in this) {
val elementHash = when (element) {
null -> 0
is Array<*> -> element.contentDeepHashCode()
is ByteArray -> element.contentHashCode()
is ShortArray -> element.contentHashCode()
is IntArray -> element.contentHashCode()
is LongArray -> element.contentHashCode()
is FloatArray -> element.contentHashCode()
is DoubleArray -> element.contentHashCode()
is CharArray -> element.contentHashCode()
is BooleanArray -> element.contentHashCode()
is UByteArray -> element.contentHashCode()
is UShortArray -> element.contentHashCode()
is UIntArray -> element.contentHashCode()
is ULongArray -> element.contentHashCode()
else -> element.hashCode()
}
result = 31 * result + elementHash
}
return result
}
@Suppress("UNCHECKED_CAST")
internal actual fun <T> arrayOfNulls(reference: Array<T>, size: Int): Array<T> = arrayOfNulls<Any>(size) as Array<T>
internal actual fun copyToArrayImpl(collection: Collection<*>): Array<Any?> {
val array = arrayOfUninitializedElements<Any?>(collection.size)
val iterator = collection.iterator()
var index = 0
while (iterator.hasNext())
array[index++] = iterator.next()
return array
}
@Suppress("UNCHECKED_CAST")
internal actual fun <T> copyToArrayImpl(collection: Collection<*>, array: Array<T>): Array<T> {
if (array.size < collection.size)
return copyToArrayImpl(collection) as Array<T>
val iterator = collection.iterator()
var index = 0
while (iterator.hasNext()) {
array[index++] = iterator.next() as T
}
if (index < array.size) {
return array.copyOf(index) as Array<T>
}
return array
}
/**
* Returns a *typed* array containing all of the elements of this collection.
*
* Allocates an array of runtime type `T` having its size equal to the size of this collection
* and populates the array with the elements of this collection.
* @sample samples.collections.Collections.Collections.collectionToTypedArray
*/
public actual inline fun <reified T> Collection<T>.toTypedArray(): Array<T> {
val result = arrayOfNulls<T>(size)
var index = 0
for (element in this) result[index++] = element
@Suppress("UNCHECKED_CAST")
return result as Array<T>
}
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* A generic collection of elements. Methods in this interface support only read-only access to the collection;
* read/write access is supported through the [MutableCollection] interface.
* @param E the type of elements contained in the collection. The collection is covariant in its element type.
*/
public interface Collection<out E> : Iterable<E> {
// Query Operations
/**
* Returns the size of the collection.
*/
public val size: Int
/**
* Returns `true` if the collection is empty (contains no elements), `false` otherwise.
*/
public fun isEmpty(): Boolean
/**
* Checks if the specified element is contained in this collection.
*/
public operator fun contains(element: @UnsafeVariance E): Boolean
override fun iterator(): Iterator<E>
// Bulk Operations
/**
* Checks if all elements in the specified collection are contained in this collection.
*/
public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
}
/**
* A generic collection of elements that supports adding and removing elements.
*
* @param E the type of elements contained in the collection. The mutable collection is invariant in its element type.
*/
public interface MutableCollection<E> : Collection<E>, MutableIterable<E> {
// Query Operations
override fun iterator(): MutableIterator<E>
// Modification Operations
/**
* Adds the specified element to the collection.
*
* @return `true` if the element has been added, `false` if the collection does not support duplicates
* and the element is already contained in the collection.
*/
public fun add(element: E): Boolean
/**
* Removes a single instance of the specified element from this
* collection, if it is present.
*
* @return `true` if the element has been successfully removed; `false` if it was not present in the collection.
*/
public fun remove(element: E): Boolean
// Bulk Modification Operations
/**
* Adds all of the elements of the specified collection to this collection.
*
* @return `true` if any of the specified elements was added to the collection, `false` if the collection was not modified.
*/
public fun addAll(elements: Collection<E>): Boolean
/**
* Removes all of this collection's elements that are also contained in the specified collection.
*
* @return `true` if any of the specified elements was removed from the collection, `false` if the collection was not modified.
*/
public fun removeAll(elements: Collection<E>): Boolean
/**
* Retains only the elements in this collection that are contained in the specified collection.
*
* @return `true` if any element was removed from the collection, `false` if the collection was not modified.
*/
public fun retainAll(elements: Collection<E>): Boolean
/**
* Removes all elements from this collection.
*/
public fun clear(): Unit
}
@@ -0,0 +1,137 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
import kotlin.comparisons.*
import kotlin.internal.InlineOnly
import kotlin.random.*
/** Copies typed varargs array to an array of objects */
internal actual fun <T> Array<out T>.copyToArrayOfAny(isVarargs: Boolean): Array<out Any?> =
// if the array came from varargs and already is array of Any, copying isn't required.
if (isVarargs) this
else this.copyOfUninitializedElements(this.size)
/**
* Classes that inherit from this interface can be represented as a sequence of elements that can
* be iterated over.
* @param T the type of element being iterated over. The iterator is covariant in its element type.
*/
public interface Iterable<out T> {
/**
* Returns an iterator over the elements of this object.
*/
public operator fun iterator(): Iterator<T>
}
/**
* Classes that inherit from this interface can be represented as a sequence of elements that can
* be iterated over and that supports removing elements during iteration.
* @param T the type of element being iterated over. The mutable iterator is invariant in its element type.
*/
public interface MutableIterable<out T> : Iterable<T> {
/**
* Returns an iterator over the elements of this sequence that supports removing elements during iteration.
*/
override fun iterator(): MutableIterator<T>
}
@PublishedApi
@SinceKotlin("1.3")
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildListInternal(builderAction: MutableList<E>.() -> Unit): List<E> {
return ArrayList<E>().apply(builderAction).build()
}
@PublishedApi
@SinceKotlin("1.3")
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildListInternal(capacity: Int, builderAction: MutableList<E>.() -> Unit): List<E> {
return ArrayList<E>(capacity).apply(builderAction).build()
}
/**
* Replaces each element in the list with a result of a transformation specified.
*/
public fun <T> MutableList<T>.replaceAll(transformation: (T) -> T) {
val it = listIterator()
while (it.hasNext()) {
val element = it.next()
it.set(transformation(element))
}
}
/**
* Groups elements from the [Grouping] source by key and counts elements in each group.
*
* @return a [Map] associating the key of each group with the count of elements in the group.
*
* @sample samples.collections.Grouping.groupingByEachCount
*/
@SinceKotlin("1.1")
public actual fun <T, K> Grouping<T, K>.eachCount(): Map<K, Int> = eachCountTo(mutableMapOf<K, Int>())
// Copied from JS.
/**
* Fills the list with the provided [value].
*
* Each element in the list gets replaced with the [value].
*/
@SinceKotlin("1.2")
public actual fun <T> MutableList<T>.fill(value: T): Unit {
for (index in 0..lastIndex) {
this[index] = value
}
}
/**
* Randomly shuffles elements in this list.
*
* See: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
*/
@SinceKotlin("1.2")
public actual fun <T> MutableList<T>.shuffle(): Unit {
for (i in lastIndex downTo 1) {
val j = Random.nextInt(i + 1)
val copy = this[i]
this[i] = this[j]
this[j] = copy
}
}
/**
* Returns a new list with the elements of this list randomly shuffled.
*/
@SinceKotlin("1.2")
public actual fun <T> Iterable<T>.shuffled(): List<T> = toMutableList().apply { shuffle() }
@PublishedApi
@SinceKotlin("1.3")
@InlineOnly
internal actual inline fun checkIndexOverflow(index: Int): Int {
if (index < 0) {
// TODO: api version check?
throwIndexOverflow()
}
return index
}
@PublishedApi
@SinceKotlin("1.3")
@InlineOnly
internal actual inline fun checkCountOverflow(count: Int): Int {
if (count < 0) {
// TODO: api version check?
throwCountOverflow()
}
return count
}
internal actual fun brittleContainsOptimizationEnabled(): Boolean = false
@@ -0,0 +1,682 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
import kotlin.native.concurrent.isFrozen
actual class HashMap<K, V> private constructor(
private var keysArray: Array<K>,
private var valuesArray: Array<V>?, // allocated only when actually used, always null in pure HashSet
private var presenceArray: IntArray,
private var hashArray: IntArray,
private var maxProbeDistance: Int,
private var length: Int
) : MutableMap<K, V> {
private var hashShift: Int = computeShift(hashSize)
private var _size: Int = 0
override actual val size: Int
get() = _size
private var keysView: HashMapKeys<K>? = null
private var valuesView: HashMapValues<V>? = null
private var entriesView: HashMapEntrySet<K, V>? = null
private var isReadOnly: Boolean = false
// ---------------------------- functions ----------------------------
actual constructor() : this(INITIAL_CAPACITY)
actual constructor(initialCapacity: Int) : this(
arrayOfUninitializedElements(initialCapacity),
null,
IntArray(initialCapacity),
IntArray(computeHashSize(initialCapacity)),
INITIAL_MAX_PROBE_DISTANCE,
0)
actual constructor(original: Map<out K, V>) : this(original.size) {
putAll(original)
}
// This implementation doesn't use a loadFactor, this constructor is used for compatibility with common stdlib
actual constructor(initialCapacity: Int, loadFactor: Float) : this(initialCapacity)
@PublishedApi
internal fun build(): Map<K, V> {
checkIsMutable()
isReadOnly = true
return this
}
override actual fun isEmpty(): Boolean = _size == 0
override actual fun containsKey(key: K): Boolean = findKey(key) >= 0
override actual fun containsValue(value: V): Boolean = findValue(value) >= 0
override actual operator fun get(key: K): V? {
val index = findKey(key)
if (index < 0) return null
return valuesArray!![index]
}
override actual fun put(key: K, value: V): V? {
checkIsMutable()
val index = addKey(key)
val valuesArray = allocateValuesArray()
if (index < 0) {
val oldValue = valuesArray[-index - 1]
valuesArray[-index - 1] = value
return oldValue
} else {
valuesArray[index] = value
return null
}
}
override actual fun putAll(from: Map<out K, V>) {
checkIsMutable()
putAllEntries(from.entries)
}
override actual fun remove(key: K): V? {
val index = removeKey(key) // mutability gets checked here
if (index < 0) return null
val valuesArray = valuesArray!!
val oldValue = valuesArray[index]
valuesArray.resetAt(index)
return oldValue
}
override actual fun clear() {
checkIsMutable()
// O(length) implementation for hashArray cleanup
for (i in 0..length - 1) {
val hash = presenceArray[i]
if (hash >= 0) {
hashArray[hash] = 0
presenceArray[i] = TOMBSTONE
}
}
keysArray.resetRange(0, length)
valuesArray?.resetRange(0, length)
_size = 0
length = 0
}
override actual val keys: MutableSet<K> get() {
val cur = keysView
return if (cur == null) {
val new = HashMapKeys(this)
if (!isFrozen)
keysView = new
new
} else cur
}
override actual val values: MutableCollection<V> get() {
val cur = valuesView
return if (cur == null) {
val new = HashMapValues(this)
if (!isFrozen)
valuesView = new
new
} else cur
}
override actual val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() {
val cur = entriesView
return if (cur == null) {
val new = HashMapEntrySet(this)
if (!isFrozen)
entriesView = new
return new
} else cur
}
override fun equals(other: Any?): Boolean {
return other === this ||
(other is Map<*, *>) &&
contentEquals(other)
}
override fun hashCode(): Int {
var result = 0
val it = entriesIterator()
while (it.hasNext()) {
result += it.nextHashCode()
}
return result
}
override fun toString(): String {
val sb = StringBuilder(2 + _size * 3)
sb.append("{")
var i = 0
val it = entriesIterator()
while (it.hasNext()) {
if (i > 0) sb.append(", ")
it.nextAppendString(sb)
i++
}
sb.append("}")
return sb.toString()
}
// ---------------------------- private ----------------------------
private val capacity: Int get() = keysArray.size
private val hashSize: Int get() = hashArray.size
internal fun checkIsMutable() {
if (isReadOnly) throw UnsupportedOperationException()
}
private fun ensureExtraCapacity(n: Int) {
ensureCapacity(length + n)
}
private fun ensureCapacity(capacity: Int) {
if (capacity < 0) throw OutOfMemoryError() // overflow
if (capacity > this.capacity) {
var newSize = this.capacity * 3 / 2
if (capacity > newSize) newSize = capacity
keysArray = keysArray.copyOfUninitializedElements(newSize)
valuesArray = valuesArray?.copyOfUninitializedElements(newSize)
presenceArray = presenceArray.copyOf(newSize)
val newHashSize = computeHashSize(newSize)
if (newHashSize > hashSize) rehash(newHashSize)
} else if (length + capacity - _size > this.capacity) {
rehash(hashSize)
}
}
private fun allocateValuesArray(): Array<V> {
val curValuesArray = valuesArray
if (curValuesArray != null) return curValuesArray
val newValuesArray = arrayOfUninitializedElements<V>(capacity)
valuesArray = newValuesArray
return newValuesArray
}
// Null-check for escaping extra boxing for non-nullable keys.
private fun hash(key: K) = if (key == null) 0 else (key.hashCode() * MAGIC) ushr hashShift
private fun compact() {
var i = 0
var j = 0
val valuesArray = valuesArray
while (i < length) {
if (presenceArray[i] >= 0) {
keysArray[j] = keysArray[i]
if (valuesArray != null) valuesArray[j] = valuesArray[i]
j++
}
i++
}
keysArray.resetRange(j, length)
valuesArray?.resetRange(j, length)
length = j
//check(length == size) { "Internal invariant violated during compact: length=$length != size=$size" }
}
private fun rehash(newHashSize: Int) {
if (length > _size) compact()
if (newHashSize != hashSize) {
hashArray = IntArray(newHashSize)
hashShift = computeShift(newHashSize)
} else {
hashArray.fill(0, 0, hashSize)
}
var i = 0
while (i < length) {
if (!putRehash(i++)) {
throw IllegalStateException("This cannot happen with fixed magic multiplier and grow-only hash array. " +
"Have object hashCodes changed?")
}
}
}
private fun putRehash(i: Int): Boolean {
var hash = hash(keysArray[i])
var probesLeft = maxProbeDistance
while (true) {
val index = hashArray[hash]
if (index == 0) {
hashArray[hash] = i + 1
presenceArray[i] = hash
return true
}
if (--probesLeft < 0) return false
if (hash-- == 0) hash = hashSize - 1
}
}
private fun findKey(key: K): Int {
var hash = hash(key)
var probesLeft = maxProbeDistance
while (true) {
val index = hashArray[hash]
if (index == 0) return TOMBSTONE
if (index > 0 && keysArray[index - 1] == key) return index - 1
if (--probesLeft < 0) return TOMBSTONE
if (hash-- == 0) hash = hashSize - 1
}
}
private fun findValue(value: V): Int {
var i = length
while (--i >= 0) {
if (presenceArray[i] >= 0 && valuesArray!![i] == value)
return i
}
return TOMBSTONE
}
internal fun addKey(key: K): Int {
checkIsMutable()
retry@ while (true) {
var hash = hash(key)
// put is allowed to grow maxProbeDistance with some limits (resize hash on reaching limits)
val tentativeMaxProbeDistance = (maxProbeDistance * 2).coerceAtMost(hashSize / 2)
var probeDistance = 0
while (true) {
val index = hashArray[hash]
if (index <= 0) { // claim or reuse hash slot
if (length >= capacity) {
ensureExtraCapacity(1)
continue@retry
}
val putIndex = length++
keysArray[putIndex] = key
presenceArray[putIndex] = hash
hashArray[hash] = putIndex + 1
_size++
if (probeDistance > maxProbeDistance) maxProbeDistance = probeDistance
return putIndex
}
if (keysArray[index - 1] == key) {
return -index
}
if (++probeDistance > tentativeMaxProbeDistance) {
rehash(hashSize * 2) // cannot find room even with extra "tentativeMaxProbeDistance" -- grow hash
continue@retry
}
if (hash-- == 0) hash = hashSize - 1
}
}
}
internal fun removeKey(key: K): Int {
checkIsMutable()
val index = findKey(key)
if (index < 0) return TOMBSTONE
removeKeyAt(index)
return index
}
private fun removeKeyAt(index: Int) {
keysArray.resetAt(index)
removeHashAt(presenceArray[index])
presenceArray[index] = TOMBSTONE
_size--
}
private fun removeHashAt(removedHash: Int) {
var hash = removedHash
var hole = removedHash // will try to patch the hole in hash array
var probeDistance = 0
var patchAttemptsLeft = (maxProbeDistance * 2).coerceAtMost(hashSize / 2) // don't spend too much effort
while (true) {
if (hash-- == 0) hash = hashSize - 1
if (++probeDistance > maxProbeDistance) {
// too far away -- can release the hole, bad case will not happen
hashArray[hole] = 0
return
}
val index = hashArray[hash]
if (index == 0) {
// end of chain -- can release the hole, bad case will not happen
hashArray[hole] = 0
return
}
if (index < 0) {
// TOMBSTONE FOUND
// - <--- [ TS ] ------ [hole] ---> +
// \------------/
// probeDistance
// move tombstone into the hole
hashArray[hole] = TOMBSTONE
hole = hash
probeDistance = 0
} else {
val otherHash = hash(keysArray[index - 1])
// Bad case:
// - <--- [hash] ------ [hole] ------ [otherHash] ---> +
// \------------/
// probeDistance
if ((otherHash - hash) and (hashSize - 1) >= probeDistance) {
// move otherHash into the hole, move the hole
hashArray[hole] = index
presenceArray[index - 1] = hole
hole = hash
probeDistance = 0
}
}
// check how long we're patching holes
if (--patchAttemptsLeft < 0) {
// just place tombstone into the hole
hashArray[hole] = TOMBSTONE
return
}
}
}
internal fun containsEntry(entry: Map.Entry<K, V>): Boolean {
val index = findKey(entry.key)
if (index < 0) return false
return valuesArray!![index] == entry.value
}
internal fun getEntry(entry: Map.Entry<K, V>): MutableMap.MutableEntry<K, V>? {
val index = findKey(entry.key)
return if (index < 0 || valuesArray!![index] != entry.value) {
null
} else {
EntryRef(this, index)
}
}
internal fun getKey(key: K): K? {
val index = findKey(key)
return if (index >= 0) {
keysArray[index]!!
} else {
null
}
}
private fun contentEquals(other: Map<*, *>): Boolean = _size == other.size && containsAllEntries(other.entries)
internal fun containsAllEntries(m: Collection<*>): Boolean {
val it = m.iterator()
while (it.hasNext()) {
val entry = it.next()
try {
@Suppress("UNCHECKED_CAST") // todo: get rid of unchecked cast here somehow
if (entry == null || !containsEntry(entry as Map.Entry<K, V>))
return false
} catch (e: ClassCastException) {
return false
}
}
return true
}
private fun putEntry(entry: Map.Entry<K, V>): Boolean {
val index = addKey(entry.key)
val valuesArray = allocateValuesArray()
if (index >= 0) {
valuesArray[index] = entry.value
return true
}
val oldValue = valuesArray[-index - 1]
if (entry.value != oldValue) {
valuesArray[-index - 1] = entry.value
return true
}
return false
}
private fun putAllEntries(from: Collection<Map.Entry<K, V>>): Boolean {
if (from.isEmpty()) return false
ensureExtraCapacity(from.size)
val it = from.iterator()
var updated = false
while (it.hasNext()) {
if (putEntry(it.next()))
updated = true
}
return updated
}
internal fun removeEntry(entry: Map.Entry<K, V>): Boolean {
checkIsMutable()
val index = findKey(entry.key)
if (index < 0) return false
if (valuesArray!![index] != entry.value) return false
removeKeyAt(index)
return true
}
internal fun removeValue(element: V): Boolean {
checkIsMutable()
val index = findValue(element)
if (index < 0) return false
removeKeyAt(index)
return true
}
internal fun keysIterator() = KeysItr(this)
internal fun valuesIterator() = ValuesItr(this)
internal fun entriesIterator() = EntriesItr(this)
@kotlin.native.internal.CanBePrecreated
private companion object {
private const val MAGIC = -1640531527 // 2654435769L.toInt(), golden ratio
private const val INITIAL_CAPACITY = 8
private const val INITIAL_MAX_PROBE_DISTANCE = 2
private const val TOMBSTONE = -1
private fun computeHashSize(capacity: Int): Int = (capacity.coerceAtLeast(1) * 3).takeHighestOneBit()
private fun computeShift(hashSize: Int): Int = hashSize.countLeadingZeroBits() + 1
}
internal open class Itr<K, V>(
internal val map: HashMap<K, V>
) {
internal var index = 0
internal var lastIndex: Int = -1
init {
initNext()
}
internal fun initNext() {
while (index < map.length && map.presenceArray[index] < 0)
index++
}
fun hasNext(): Boolean = index < map.length
fun remove() {
map.checkIsMutable()
map.removeKeyAt(lastIndex)
lastIndex = -1
}
}
internal class KeysItr<K, V>(map: HashMap<K, V>) : Itr<K, V>(map), MutableIterator<K> {
override fun next(): K {
if (index >= map.length) throw NoSuchElementException()
lastIndex = index++
val result = map.keysArray[lastIndex]
initNext()
return result
}
}
internal class ValuesItr<K, V>(map: HashMap<K, V>) : Itr<K, V>(map), MutableIterator<V> {
override fun next(): V {
if (index >= map.length) throw NoSuchElementException()
lastIndex = index++
val result = map.valuesArray!![lastIndex]
initNext()
return result
}
}
internal class EntriesItr<K, V>(map: HashMap<K, V>) : Itr<K, V>(map),
MutableIterator<MutableMap.MutableEntry<K, V>> {
override fun next(): EntryRef<K, V> {
if (index >= map.length) throw NoSuchElementException()
lastIndex = index++
val result = EntryRef(map, lastIndex)
initNext()
return result
}
internal fun nextHashCode(): Int {
if (index >= map.length) throw NoSuchElementException()
lastIndex = index++
val result = map.keysArray[lastIndex].hashCode() xor map.valuesArray!![lastIndex].hashCode()
initNext()
return result
}
fun nextAppendString(sb: StringBuilder) {
if (index >= map.length) throw NoSuchElementException()
lastIndex = index++
val key = map.keysArray[lastIndex]
if (key == map) sb.append("(this Map)") else sb.append(key)
sb.append('=')
val value = map.valuesArray!![lastIndex]
if (value == map) sb.append("(this Map)") else sb.append(value)
initNext()
}
}
internal class EntryRef<K, V>(
private val map: HashMap<K, V>,
private val index: Int
) : MutableMap.MutableEntry<K, V> {
override val key: K
get() = map.keysArray[index]
override val value: V
get() = map.valuesArray!![index]
override fun setValue(newValue: V): V {
map.checkIsMutable()
val valuesArray = map.allocateValuesArray()
val oldValue = valuesArray[index]
valuesArray[index] = newValue
return oldValue
}
override fun equals(other: Any?): Boolean =
other is Map.Entry<*, *> &&
other.key == key &&
other.value == value
override fun hashCode(): Int = key.hashCode() xor value.hashCode()
override fun toString(): String = "$key=$value"
}
}
internal class HashMapKeys<E> internal constructor(
private val backing: HashMap<E, *>
) : MutableSet<E>, kotlin.native.internal.KonanSet<E>, AbstractMutableSet<E>() {
override val size: Int get() = backing.size
override fun isEmpty(): Boolean = backing.isEmpty()
override fun contains(element: E): Boolean = backing.containsKey(element)
override fun getElement(element: E): E? = backing.getKey(element)
override fun clear() = backing.clear()
override fun add(element: E): Boolean = throw UnsupportedOperationException()
override fun addAll(elements: Collection<E>): Boolean = throw UnsupportedOperationException()
override fun remove(element: E): Boolean = backing.removeKey(element) >= 0
override fun iterator(): MutableIterator<E> = backing.keysIterator()
override fun removeAll(elements: Collection<E>): Boolean {
backing.checkIsMutable()
return super.removeAll(elements)
}
override fun retainAll(elements: Collection<E>): Boolean {
backing.checkIsMutable()
return super.retainAll(elements)
}
}
internal class HashMapValues<V> internal constructor(
val backing: HashMap<*, V>
) : MutableCollection<V>, AbstractMutableCollection<V>() {
override val size: Int get() = backing.size
override fun isEmpty(): Boolean = backing.isEmpty()
override fun contains(element: V): Boolean = backing.containsValue(element)
override fun add(element: V): Boolean = throw UnsupportedOperationException()
override fun addAll(elements: Collection<V>): Boolean = throw UnsupportedOperationException()
override fun clear() = backing.clear()
override fun iterator(): MutableIterator<V> = backing.valuesIterator()
override fun remove(element: V): Boolean = backing.removeValue(element)
override fun removeAll(elements: Collection<V>): Boolean {
backing.checkIsMutable()
return super.removeAll(elements)
}
override fun retainAll(elements: Collection<V>): Boolean {
backing.checkIsMutable()
return super.retainAll(elements)
}
}
/**
* Note: intermediate class with [E] `: Map.Entry<K, V>` is required to support
* [contains] for values that are [Map.Entry] but not [MutableMap.MutableEntry],
* and probably same for other functions.
* This is important because an instance of this class can be used as a result of [Map.entries],
* which should support [contains] for [Map.Entry].
* For example, this happens when upcasting [MutableMap] to [Map].
*
* The compiler enables special type-safe barriers to methods like [contains], which has [UnsafeVariance].
* Changing type from [MutableMap.MutableEntry] to [E] makes the compiler generate barriers checking that
* argument `is` [E] (so technically `is` [Map.Entry]) instead of `is` [MutableMap.MutableEntry].
*
* See also [KT-42248](https://youtrack.jetbrains.com/issue/KT-42428).
*/
internal abstract class HashMapEntrySetBase<K, V, E : Map.Entry<K, V>> internal constructor(
val backing: HashMap<K, V>
) : MutableSet<E>, kotlin.native.internal.KonanSet<E>, AbstractMutableSet<E>() {
override val size: Int get() = backing.size
override fun isEmpty(): Boolean = backing.isEmpty()
override fun contains(element: E): Boolean = backing.containsEntry(element)
override fun getElement(element: E): E? = getEntry(element)
protected abstract fun getEntry(element: Map.Entry<K, V>): E?
override fun clear() = backing.clear()
override fun add(element: E): Boolean = throw UnsupportedOperationException()
override fun addAll(elements: Collection<E>): Boolean = throw UnsupportedOperationException()
override fun remove(element: E): Boolean = backing.removeEntry(element)
override fun containsAll(elements: Collection<E>): Boolean = backing.containsAllEntries(elements)
override fun removeAll(elements: Collection<E>): Boolean {
backing.checkIsMutable()
return super.removeAll(elements)
}
override fun retainAll(elements: Collection<E>): Boolean {
backing.checkIsMutable()
return super.retainAll(elements)
}
}
internal class HashMapEntrySet<K, V> internal constructor(
backing: HashMap<K, V>
) : HashMapEntrySetBase<K, V, MutableMap.MutableEntry<K, V>>(backing) {
override fun getEntry(element: Map.Entry<K, V>): MutableMap.MutableEntry<K, V>? = backing.getEntry(element)
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = backing.entriesIterator()
}
// This hash map keeps insertion order.
actual typealias LinkedHashMap<K, V> = HashMap<K, V>
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
actual class HashSet<E> internal constructor(
private val backing: HashMap<E, *>
) : MutableSet<E>, kotlin.native.internal.KonanSet<E>, AbstractMutableSet<E>() {
actual constructor() : this(HashMap<E, Nothing>())
actual constructor(initialCapacity: Int) : this(HashMap<E, Nothing>(initialCapacity))
actual constructor(elements: Collection<E>) : this(elements.size) {
addAll(elements)
}
// This implementation doesn't use a loadFactor
actual constructor(initialCapacity: Int, loadFactor: Float) : this(initialCapacity)
@PublishedApi
internal fun build(): Set<E> {
backing.build()
return this
}
override actual val size: Int get() = backing.size
override actual fun isEmpty(): Boolean = backing.isEmpty()
override actual fun contains(element: E): Boolean = backing.containsKey(element)
override fun getElement(element: E): E? = backing.getKey(element)
override actual fun clear() = backing.clear()
override actual fun add(element: E): Boolean = backing.addKey(element) >= 0
override actual fun remove(element: E): Boolean = backing.removeKey(element) >= 0
override actual fun iterator(): MutableIterator<E> = backing.keysIterator()
override actual fun addAll(elements: Collection<E>): Boolean {
backing.checkIsMutable()
return super.addAll(elements)
}
override actual fun removeAll(elements: Collection<E>): Boolean {
backing.checkIsMutable()
return super.removeAll(elements)
}
override actual fun retainAll(elements: Collection<E>): Boolean {
backing.checkIsMutable()
return super.retainAll(elements)
}
}
// This hash set keeps insertion order.
actual typealias LinkedHashSet<V> = HashSet<V>
@@ -0,0 +1,91 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* An iterator over a collection or another entity that can be represented as a sequence of elements.
* Allows to sequentially access the elements.
*/
public interface Iterator<out T> {
/**
* Returns the next element in the iteration.
*/
public operator fun next(): T
/**
* Returns `true` if the iteration has more elements.
*/
public operator fun hasNext(): Boolean
}
/**
* An iterator over a mutable collection. Provides the ability to remove elements while iterating.
* @see MutableCollection.iterator
*/
public interface MutableIterator<out T> : Iterator<T> {
/**
* Removes from the underlying collection the last element returned by this iterator.
*/
public fun remove(): Unit
}
/**
* An iterator over a collection that supports indexed access.
* @see List.listIterator
*/
public interface ListIterator<out T> : Iterator<T> {
// Query Operations
override fun next(): T
override fun hasNext(): Boolean
/**
* Returns `true` if there are elements in the iteration before the current element.
*/
public fun hasPrevious(): Boolean
/**
* Returns the previous element in the iteration and moves the cursor position backwards.
*/
public fun previous(): T
/**
* Returns the index of the element that would be returned by a subsequent call to [next].
*/
public fun nextIndex(): Int
/**
* Returns the index of the element that would be returned by a subsequent call to [previous].
*/
public fun previousIndex(): Int
}
/**
* An iterator over a mutable collection that supports indexed access. Provides the ability
* to add, modify and remove elements while iterating.
*/
public interface MutableListIterator<T> : ListIterator<T>, MutableIterator<T> {
// Query Operations
override fun next(): T
override fun hasNext(): Boolean
// Modification Operations
override fun remove(): Unit
/**
* Replaces the last element returned by [next] or [previous] with the specified element [element].
*/
public fun set(element: T): Unit
/**
* Adds the specified element [element] into the underlying collection immediately before the element that would be
* returned by [next], if any, and after the element that would be returned by [previous], if any.
* (If the collection contains no elements, the new element becomes the sole element in the collection.)
* The new element is inserted before the implicit cursor: a subsequent call to [next] would be unaffected,
* and a subsequent call to [previous] would return the new element. (This call increases by one the value \
* that would be returned by a call to [nextIndex] or [previousIndex].)
*/
public fun add(element: T): Unit
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/** An iterator over a sequence of values of type `Byte`. */
public abstract class ByteIterator : Iterator<Byte> {
override final fun next() = nextByte()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextByte(): Byte
}
/** An iterator over a sequence of values of type `Char`. */
public abstract class CharIterator : Iterator<Char> {
override final fun next() = nextChar()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextChar(): Char
}
/** An iterator over a sequence of values of type `Short`. */
public abstract class ShortIterator : Iterator<Short> {
override final fun next() = nextShort()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextShort(): Short
}
/** An iterator over a sequence of values of type `Int`. */
public abstract class IntIterator : Iterator<Int> {
override final fun next() = nextInt()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextInt(): Int
}
/** An iterator over a sequence of values of type `Long`. */
public abstract class LongIterator : Iterator<Long> {
override final fun next() = nextLong()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextLong(): Long
}
/** An iterator over a sequence of values of type `Float`. */
public abstract class FloatIterator : Iterator<Float> {
override final fun next() = nextFloat()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextFloat(): Float
}
/** An iterator over a sequence of values of type `Double`. */
public abstract class DoubleIterator : Iterator<Double> {
override final fun next() = nextDouble()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextDouble(): Double
}
/** An iterator over a sequence of values of type `Boolean`. */
public abstract class BooleanIterator : Iterator<Boolean> {
override final fun next() = nextBoolean()
/** Returns the next value in the sequence without boxing. */
public abstract fun nextBoolean(): Boolean
}
@@ -0,0 +1,126 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* A generic ordered collection of elements. Methods in this interface support only read-only access to the list;
* read/write access is supported through the [MutableList] interface.
* @param E the type of elements contained in the list. The list is covariant in its element type.
*/
public interface List<out E> : Collection<E> {
// Query Operations
override val size: Int
override fun isEmpty(): Boolean
override fun contains(element: @UnsafeVariance E): Boolean
override fun iterator(): Iterator<E>
// Bulk Operations
override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
// Positional Access Operations
/**
* Returns the element at the specified index in the list.
*/
public operator fun get(index: Int): E
// Search Operations
/**
* Returns the index of the first occurrence of the specified element in the list, or -1 if the specified
* element is not contained in the list.
*/
public fun indexOf(element: @UnsafeVariance E): Int
/**
* Returns the index of the last occurrence of the specified element in the list, or -1 if the specified
* element is not contained in the list.
*/
public fun lastIndexOf(element: @UnsafeVariance E): Int
// List Iterators
/**
* Returns a list iterator over the elements in this list (in proper sequence).
*/
public fun listIterator(): ListIterator<E>
/**
* Returns a list iterator over the elements in this list (in proper sequence), starting at the specified [index].
*/
public fun listIterator(index: Int): ListIterator<E>
// View
/**
* Returns a view of the portion of this list between the specified [fromIndex] (inclusive) and [toIndex] (exclusive).
* The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
*
* Structural changes in the base list make the behavior of the view undefined.
*/
public fun subList(fromIndex: Int, toIndex: Int): List<E>
}
/**
* A generic ordered collection of elements that supports adding and removing elements.
* @param E the type of elements contained in the list. The mutable list is invariant in its element type.
*/
public interface MutableList<E> : List<E>, MutableCollection<E> {
// Modification Operations
/**
* Adds the specified element to the end of this list.
*
* @return `true` because the list is always modified as the result of this operation.
*/
override fun add(element: E): Boolean
override fun remove(element: E): Boolean
// Bulk Modification Operations
/**
* Adds all of the elements of the specified collection to the end of this list.
*
* The elements are appended in the order they appear in the [elements] collection.
*
* @return `true` if the list was changed as the result of the operation.
*/
override fun addAll(elements: Collection<E>): Boolean
/**
* Inserts all of the elements of the specified collection [elements] into this list at the specified [index].
*
* @return `true` if the list was changed as the result of the operation.
*/
public fun addAll(index: Int, elements: Collection<E>): Boolean
override fun removeAll(elements: Collection<E>): Boolean
override fun retainAll(elements: Collection<E>): Boolean
override fun clear(): Unit
// Positional Access Operations
/**
* Replaces the element at the specified position in this list with the specified element.
*
* @return the element previously at the specified position.
*/
public operator fun set(index: Int, element: E): E
/**
* Inserts an element into the list at the specified [index].
*/
public fun add(index: Int, element: E): Unit
/**
* Removes an element at the specified [index] from the list.
*
* @return the element that has been removed.
*/
public fun removeAt(index: Int): E
// List Iterators
override fun listIterator(): MutableListIterator<E>
override fun listIterator(index: Int): MutableListIterator<E>
// View
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E>
}
@@ -0,0 +1,136 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* A collection that holds pairs of objects (keys and values) and supports efficiently retrieving
* the value corresponding to each key. Map keys are unique; the map holds only one value for each key.
* Methods in this interface support only read-only access to the map; read-write access is supported through
* the [MutableMap] interface.
* @param K the type of map keys. The map is invariant in its key type, as it
* can accept key as a parameter (of [containsKey] for example) and return it in [keys] set.
* @param V the type of map values. The map is covariant in its value type.
*/
public interface Map<K, out V> {
// Query Operations
/**
* Returns the number of key/value pairs in the map.
*/
public val size: Int
/**
* Returns `true` if the map is empty (contains no elements), `false` otherwise.
*/
public fun isEmpty(): Boolean
/**
* Returns `true` if the map contains the specified [key].
*/
public fun containsKey(key: K): Boolean
/**
* Returns `true` if the map maps one or more keys to the specified [value].
*/
public fun containsValue(value: @UnsafeVariance V): Boolean
/**
* Returns the value corresponding to the given [key], or `null` if such a key is not present in the map.
*/
public operator fun get(key: K): V?
// Views
/**
* Returns a read-only [Set] of all keys in this map.
*/
public val keys: Set<K>
/**
* Returns a read-only [Collection] of all values in this map. Note that this collection may contain duplicate values.
*/
public val values: Collection<V>
/**
* Returns a read-only [Set] of all key/value pairs in this map.
*/
public val entries: Set<Map.Entry<K, V>>
/**
* Represents a key/value pair held by a [Map].
*/
public interface Entry<out K, out V> {
/**
* Returns the key of this key/value pair.
*/
public val key: K
/**
* Returns the value of this key/value pair.
*/
public val value: V
}
}
/**
* A modifiable collection that holds pairs of objects (keys and values) and supports efficiently retrieving
* the value corresponding to each key. Map keys are unique; the map holds only one value for each key.
* @param K the type of map keys. The map is invariant in its key type.
* @param V the type of map values. The mutable map is invariant in its value type.
*/
public interface MutableMap<K, V> : Map<K, V> {
// Modification Operations
/**
* Associates the specified [value] with the specified [key] in the map.
*
* @return the previous value associated with the key, or `null` if the key was not present in the map.
*/
public fun put(key: K, value: V): V?
/**
* Removes the specified key and its corresponding value from this map.
*
* @return the previous value associated with the key, or `null` if the key was not present in the map.
*/
public fun remove(key: K): V?
// Bulk Modification Operations
/**
* Updates this map with key/value pairs from the specified map [from].
*/
public fun putAll(from: Map<out K, V>): Unit
/**
* Removes all elements from this map.
*/
public fun clear(): Unit
// Views
/**
* Returns a [MutableSet] of all keys in this map.
*/
override val keys: MutableSet<K>
/**
* Returns a [MutableCollection] of all values in this map. Note that this collection may contain duplicate values.
*/
override val values: MutableCollection<V>
/**
* Returns a [MutableSet] of all key/value pairs in this map.
*/
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
/**
* Represents a key/value pair held by a [MutableMap].
*/
public interface MutableEntry<K, V> : Map.Entry<K, V> {
/**
* Changes the value associated with the key of this entry.
*
* @return the previous value corresponding to the key.
*/
public fun setValue(newValue: V): V
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
@PublishedApi
@SinceKotlin("1.3")
@kotlin.internal.InlineOnly
internal actual inline fun <K, V> buildMapInternal(builderAction: MutableMap<K, V>.() -> Unit): Map<K, V> {
return HashMap<K, V>().apply(builderAction).build()
}
@PublishedApi
@SinceKotlin("1.3")
@kotlin.internal.InlineOnly
internal actual inline fun <K, V> buildMapInternal(capacity: Int, builderAction: MutableMap<K, V>.() -> Unit): Map<K, V> {
return HashMap<K, V>(capacity).apply(builderAction).build()
}
// creates a singleton copy of map, if there is specialization available in target platform, otherwise returns itself
@Suppress("NOTHING_TO_INLINE")
internal inline actual fun <K, V> Map<K, V>.toSingletonMapOrSelf(): Map<K, V> = toSingletonMap()
// creates a singleton copy of map
internal actual fun <K, V> Map<out K, V>.toSingletonMap(): Map<K, V>
= with(entries.iterator().next()) { mutableMapOf(key to value) }
/**
* Native map and set implementations do not make use of capacities or load factors.
*/
@PublishedApi
internal actual fun mapCapacity(expectedSize: Int) = expectedSize
@@ -0,0 +1,33 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* Sorts elements in the list in-place according to their natural sort order.
*
* The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting.
*
* @sample samples.collections.Collections.Sorting.sortMutableList
*/
public actual fun <T : Comparable<T>> MutableList<T>.sort(): Unit = sortWith(naturalOrder())
/**
* Sorts elements in the list in-place according to the order specified with [comparator].
*
* The sort is _stable_. It means that equal elements preserve their order relative to each other after sorting.
*
* @sample samples.collections.Collections.Sorting.sortMutableListWith
*/
public actual fun <T> MutableList<T>.sortWith(comparator: Comparator<in T>): Unit {
if (size > 1) {
val it = listIterator()
val sortedArray = @Suppress("UNCHECKED_CAST") (toTypedArray<Any?>() as Array<T>).apply { sortWith(comparator) }
for (v in sortedArray) {
it.next()
it.set(v)
}
}
}
@@ -0,0 +1,11 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* Marker interface indicating that the [List] implementation supports fast indexed access.
*/
public actual interface RandomAccess
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
/**
* A generic unordered collection of elements that does not support duplicate elements.
* Methods in this interface support only read-only access to the set;
* read/write access is supported through the [MutableSet] interface.
* @param E the type of elements contained in the set. The set is covariant in its element type.
*/
public interface Set<out E> : Collection<E> {
// Query Operations
override val size: Int
override fun isEmpty(): Boolean
override fun contains(element: @UnsafeVariance E): Boolean
override fun iterator(): Iterator<E>
// Bulk Operations
override fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
}
/**
* A generic unordered collection of elements that does not support duplicate elements, and supports
* adding and removing elements.
* @param E the type of elements contained in the set. The mutable set is invariant in its element type.
*/
public interface MutableSet<E> : Set<E>, MutableCollection<E> {
// Query Operations
override fun iterator(): MutableIterator<E>
// Modification Operations
/**
* Adds the specified element to the set.
*
* @return `true` if the element has been added, `false` if the element is already contained in the set.
*/
override fun add(element: E): Boolean
override fun remove(element: E): Boolean
// Bulk Modification Operations
override fun addAll(elements: Collection<E>): Boolean
override fun removeAll(elements: Collection<E>): Boolean
override fun retainAll(elements: Collection<E>): Boolean
override fun clear(): Unit
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.collections
// TODO: Add SingletonSet class
/**
* Returns an immutable set containing only the specified object [element].
*/
public fun <T> setOf(element: T): Set<T> = hashSetOf(element)
@PublishedApi
@SinceKotlin("1.3")
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildSetInternal(builderAction: MutableSet<E>.() -> Unit): Set<E> {
return HashSet<E>().apply(builderAction).build()
}
@PublishedApi
@SinceKotlin("1.3")
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildSetInternal(capacity: Int, builderAction: MutableSet<E>.() -> Unit): Set<E> {
return HashSet<E>(capacity).apply(builderAction).build()
}
@@ -0,0 +1,939 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package kotlin.text
/**
* A mutable sequence of characters.
*
* String builder can be used to efficiently perform multiple string manipulation operations.
*/
actual class StringBuilder private constructor (
private var array: CharArray) : CharSequence, Appendable {
/** Constructs an empty string builder. */
actual constructor() : this(10)
/** Constructs an empty string builder with the specified initial [capacity]. */
actual constructor(capacity: Int) : this(CharArray(capacity))
/** Constructs a string builder that contains the same characters as the specified [content] string. */
actual constructor(content: String) : this(content.toCharArray()) {
_length = array.size
}
/** Constructs a string builder that contains the same characters as the specified [content] char sequence. */
actual constructor(content: CharSequence): this(content.length) {
append(content)
}
// Of CharSequence.
private var _length: Int = 0
set(capacity) {
ensureCapacity(capacity)
field = capacity
}
actual override val length: Int
get() = _length
actual override fun get(index: Int): Char {
checkIndex(index)
return array[index]
}
actual override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = substring(startIndex, endIndex)
// Of Appenable.
actual override fun append(value: Char) : StringBuilder {
ensureExtraCapacity(1)
array[_length++] = value
return this
}
actual override fun append(value: CharSequence?): StringBuilder {
// Kotlin/JVM processes null as if the argument was "null" char sequence.
val toAppend = value ?: "null"
return append(toAppend, 0, toAppend.length)
}
actual override fun append(value: CharSequence?, startIndex: Int, endIndex: Int): StringBuilder =
this.appendRange(value ?: "null", startIndex, endIndex)
/**
* Reverses the contents of this string builder and returns this instance.
*
* Surrogate pairs included in this string builder are treated as single characters.
* Therefore, the order of the high-low surrogates is never reversed.
*
* Note that the reverse operation may produce new surrogate pairs that were unpaired low-surrogates and high-surrogates before the operation.
* For example, reversing `"\uDC00\uD800"` produces `"\uD800\uDC00"` which is a valid surrogate pair.
*/
// Based on Apache Harmony implementation.
actual fun reverse(): StringBuilder {
if (this.length < 2) {
return this
}
var end = _length - 1
var front = 0
var frontLeadingChar = array[0]
var endTrailingChar = array[end]
var allowFrontSurrogate = true
var allowEndSurrogate = true
while (front < _length / 2) {
var frontTrailingChar = array[front + 1]
var endLeadingChar = array[end - 1]
var surrogateAtFront = allowFrontSurrogate && frontTrailingChar.isLowSurrogate() && frontLeadingChar.isHighSurrogate()
if (surrogateAtFront && _length < 3) {
return this
}
var surrogateAtEnd = allowEndSurrogate && endTrailingChar.isLowSurrogate() && endLeadingChar.isHighSurrogate()
allowFrontSurrogate = true
allowEndSurrogate = true
when {
surrogateAtFront && surrogateAtEnd -> {
// Both surrogates - just exchange them.
array[end] = frontTrailingChar
array[end - 1] = frontLeadingChar
array[front] = endLeadingChar
array[front + 1] = endTrailingChar
frontLeadingChar = array[front + 2]
endTrailingChar = array[end - 2]
front++
end--
}
!surrogateAtFront && !surrogateAtEnd -> {
// Neither surrogates - exchange only front/end.
array[end] = frontLeadingChar
array[front] = endTrailingChar
frontLeadingChar = frontTrailingChar
endTrailingChar = endLeadingChar
}
surrogateAtFront && !surrogateAtEnd -> {
// Surrogate only at the front -
// move the low part, the high part will be moved as a usual character on the next iteration.
array[end] = frontTrailingChar
array[front] = endTrailingChar
endTrailingChar = endLeadingChar
allowFrontSurrogate = false
}
!surrogateAtFront && surrogateAtEnd -> {
// Surrogate only at the end -
// move the high part, the low part will be moved as a usual character on the next iteration.
array[end] = frontLeadingChar
array[front] = endLeadingChar
frontLeadingChar = frontTrailingChar
allowEndSurrogate = false
}
}
front++
end--
}
if (_length % 2 == 1 && (!allowEndSurrogate || !allowFrontSurrogate)) {
array[end] = if (allowFrontSurrogate) endTrailingChar else frontLeadingChar
}
return this
}
/**
* Appends the string representation of the specified object [value] to this string builder and returns this instance.
*
* The overall effect is exactly as if the [value] were converted to a string by the `value.toString()` method,
* and then that string was appended to this string builder.
*/
actual fun append(value: Any?): StringBuilder = append(value.toString())
/**
* Appends the string representation of the specified boolean [value] to this string builder and returns this instance.
*
* The overall effect is exactly as if the [value] were converted to a string by the `value.toString()` method,
* and then that string was appended to this string builder.
*/
// TODO: optimize those!
actual fun append(value: Boolean): StringBuilder = append(value.toString())
fun append(value: Byte): StringBuilder = append(value.toString())
fun append(value: Short): StringBuilder = append(value.toString())
fun append(value: Int): StringBuilder {
ensureExtraCapacity(11)
_length += insertInt(array, _length, value)
return this
}
fun append(value: Long): StringBuilder = append(value.toString())
fun append(value: Float): StringBuilder = append(value.toString())
fun append(value: Double): StringBuilder = append(value.toString())
/**
* Appends characters in the specified character array [value] to this string builder and returns this instance.
*
* Characters are appended in order, starting at the index 0.
*/
actual fun append(value: CharArray): StringBuilder {
ensureExtraCapacity(value.size)
value.copyInto(array, _length)
_length += value.size
return this
}
@Deprecated("Provided for binary compatibility.", level = DeprecationLevel.HIDDEN)
fun append(value: String): StringBuilder = append(value)
/**
* Appends the specified string [value] to this string builder and returns this instance.
*
* If [value] is `null`, then the four characters `"null"` are appended.
*/
actual fun append(value: String?): StringBuilder {
val toAppend = value ?: "null"
ensureExtraCapacity(toAppend.length)
_length += insertString(array, _length, toAppend)
return this
}
/**
* Returns the current capacity of this string builder.
*
* The capacity is the maximum length this string builder can have before an allocation occurs.
*/
actual fun capacity(): Int = array.size
/**
* Ensures that the capacity of this string builder is at least equal to the specified [minimumCapacity].
*
* If the current capacity is less than the [minimumCapacity], a new backing storage is allocated with greater capacity.
* Otherwise, this method takes no action and simply returns.
*/
actual fun ensureCapacity(minimumCapacity: Int) {
if (minimumCapacity > array.size) {
var newSize = array.size * 2 + 2
if (minimumCapacity > newSize)
newSize = minimumCapacity
array = array.copyOf(newSize)
}
}
/**
* Returns the index within this string builder of the first occurrence of the specified [string].
*
* Returns `-1` if the specified [string] does not occur in this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
actual fun indexOf(string: String): Int {
return (this as CharSequence).indexOf(string, startIndex = 0, ignoreCase = false)
}
/**
* Returns the index within this string builder of the first occurrence of the specified [string],
* starting at the specified [startIndex].
*
* Returns `-1` if the specified [string] does not occur in this string builder starting at the specified [startIndex].
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
actual fun indexOf(string: String, startIndex: Int): Int {
if (string.isEmpty() && startIndex >= _length) return _length
return (this as CharSequence).indexOf(string, startIndex, ignoreCase = false)
}
/**
* Returns the index within this string builder of the last occurrence of the specified [string].
* The last occurrence of empty string `""` is considered to be at the index equal to `this.length`.
*
* Returns `-1` if the specified [string] does not occur in this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
actual fun lastIndexOf(string: String): Int {
if (string.isEmpty()) return _length
return (this as CharSequence).lastIndexOf(string, startIndex = lastIndex, ignoreCase = false)
}
/**
* Returns the index within this string builder of the last occurrence of the specified [string],
* starting from the specified [startIndex] toward the beginning.
*
* Returns `-1` if the specified [string] does not occur in this string builder starting at the specified [startIndex].
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
actual fun lastIndexOf(string: String, startIndex: Int): Int {
if (string.isEmpty() && startIndex >= _length) return _length
return (this as CharSequence).lastIndexOf(string, startIndex, ignoreCase = false)
}
/**
* Inserts the string representation of the specified boolean [value] into this string builder at the specified [index] and returns this instance.
*
* The overall effect is exactly as if the [value] were converted to a string by the `value.toString()` method,
* and then that string was inserted into this string builder at the specified [index].
*
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
// TODO: optimize those!
actual fun insert(index: Int, value: Boolean): StringBuilder = insert(index, value.toString())
fun insert(index: Int, value: Byte) = insert(index, value.toString())
fun insert(index: Int, value: Short) = insert(index, value.toString())
fun insert(index: Int, value: Int) = insert(index, value.toString())
fun insert(index: Int, value: Long) = insert(index, value.toString())
fun insert(index: Int, value: Float) = insert(index, value.toString())
fun insert(index: Int, value: Double) = insert(index, value.toString())
/**
* Inserts the specified character [value] into this string builder at the specified [index] and returns this instance.
*
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
actual fun insert(index: Int, value: Char): StringBuilder {
checkInsertIndex(index)
ensureExtraCapacity(1)
val newLastIndex = lastIndex + 1
for (i in newLastIndex downTo index + 1) {
array[i] = array[i - 1]
}
array[index] = value
_length++
return this
}
/**
* Inserts characters in the specified character array [value] into this string builder at the specified [index] and returns this instance.
*
* The inserted characters go in same order as in the [value] character array, starting at [index].
*
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
actual fun insert(index: Int, value: CharArray): StringBuilder {
checkInsertIndex(index)
ensureExtraCapacity(value.size)
array.copyInto(array, startIndex = index, endIndex = _length, destinationOffset = index + value.size)
value.copyInto(array, destinationOffset = index)
_length += value.size
return this
}
/**
* Inserts characters in the specified character sequence [value] into this string builder at the specified [index] and returns this instance.
*
* The inserted characters go in the same order as in the [value] character sequence, starting at [index].
*
* @param index the position in this string builder to insert at.
* @param value the character sequence from which characters are inserted. If [value] is `null`, then the four characters `"null"` are inserted.
*
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
actual fun insert(index: Int, value: CharSequence?): StringBuilder {
// Kotlin/JVM inserts the "null" string if the argument is null.
val toInsert = value ?: "null"
return insertRange(index, toInsert, 0, toInsert.length)
}
/**
* Inserts the string representation of the specified object [value] into this string builder at the specified [index] and returns this instance.
*
* The overall effect is exactly as if the [value] were converted to a string by the `value.toString()` method,
* and then that string was inserted into this string builder at the specified [index].
*
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
actual fun insert(index: Int, value: Any?): StringBuilder = insert(index, value.toString())
@Deprecated("Provided for binary compatibility.", level = DeprecationLevel.HIDDEN)
fun insert(index: Int, value: String): StringBuilder = insert(index, value)
/**
* Inserts the string [value] into this string builder at the specified [index] and returns this instance.
*
* If [value] is `null`, then the four characters `"null"` are inserted.
*
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
actual fun insert(index: Int, value: String?): StringBuilder {
val toInsert = value ?: "null"
checkInsertIndex(index)
ensureExtraCapacity(toInsert.length)
array.copyInto(array, startIndex = index, endIndex = _length, destinationOffset = index + toInsert.length)
_length += insertString(array, index, toInsert)
return this
}
/**
* Sets the length of this string builder to the specified [newLength].
*
* If the [newLength] is less than the current length, it is changed to the specified [newLength].
* Otherwise, null characters '\u0000' are appended to this string builder until its length is less than the [newLength].
*
* Note that in Kotlin/JS [set] operator function has non-constant execution time complexity.
* Therefore, increasing length of this string builder and then updating each character by index may slow down your program.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] if [newLength] is less than zero.
*/
actual fun setLength(newLength: Int) {
if (newLength < 0) {
throw IllegalArgumentException("Negative new length: $newLength.")
}
if (newLength > _length) {
array.fill('\u0000', _length, newLength.coerceAtMost(array.size))
}
_length = newLength
}
/**
* Returns a new [String] that contains characters in this string builder at [startIndex] (inclusive) and up to the [endIndex] (exclusive).
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this string builder indices or when `startIndex > endIndex`.
*/
actual fun substring(startIndex: Int, endIndex: Int): String {
checkBoundsIndexes(startIndex, endIndex, _length)
return unsafeStringFromCharArray(array, startIndex, endIndex - startIndex)
}
/**
* Returns a new [String] that contains characters in this string builder at [startIndex] (inclusive) and up to the [length] (exclusive).
*
* @throws IndexOutOfBoundsException if [startIndex] is less than zero or greater than the length of this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
actual fun substring(startIndex: Int): String {
return substring(startIndex, _length)
}
/**
* Attempts to reduce storage used for this string builder.
*
* If the backing storage of this string builder is larger than necessary to hold its current contents,
* then it may be resized to become more space efficient.
* Calling this method may, but is not required to, affect the value of the [capacity] property.
*/
actual fun trimToSize() {
if (_length < array.size)
array = array.copyOf(_length)
}
override fun toString(): String = unsafeStringFromCharArray(array, 0, _length)
/**
* Sets the character at the specified [index] to the specified [value].
*
* @throws IndexOutOfBoundsException if [index] is out of bounds of this string builder.
*/
operator fun set(index: Int, value: Char) {
checkIndex(index)
array[index] = value
}
/**
* Replaces characters in the specified range of this string builder with characters in the specified string [value] and returns this instance.
*
* @param startIndex the beginning (inclusive) of the range to replace.
* @param endIndex the end (exclusive) of the range to replace.
* @param value the string to replace with.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] if [startIndex] is less than zero, greater than the length of this string builder, or `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun setRange(startIndex: Int, endIndex: Int, value: String): StringBuilder {
checkReplaceRange(startIndex, endIndex, _length)
val coercedEndIndex = endIndex.coerceAtMost(_length)
val lengthDiff = value.length - (coercedEndIndex - startIndex)
ensureExtraCapacity(_length + lengthDiff)
array.copyInto(array, startIndex = coercedEndIndex, endIndex = _length, destinationOffset = startIndex + value.length)
var replaceIndex = startIndex
for (index in 0 until value.length) array[replaceIndex++] = value[index] // optimize
_length += lengthDiff
return this
}
/**
* Removes the character at the specified [index] from this string builder and returns this instance.
*
* If the `Char` at the specified [index] is part of a supplementary code point, this method does not remove the entire supplementary character.
*
* @param index the index of `Char` to remove.
*
* @throws IndexOutOfBoundsException if [index] is out of bounds of this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun deleteAt(index: Int): StringBuilder {
checkIndex(index)
array.copyInto(array, startIndex = index + 1, endIndex = _length, destinationOffset = index)
--_length
return this
}
/**
* Removes characters in the specified range from this string builder and returns this instance.
*
* @param startIndex the beginning (inclusive) of the range to remove.
* @param endIndex the end (exclusive) of the range to remove.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] is out of range of this string builder indices or when `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun deleteRange(startIndex: Int, endIndex: Int): StringBuilder {
checkReplaceRange(startIndex, endIndex, _length)
val coercedEndIndex = endIndex.coerceAtMost(_length)
array.copyInto(array, startIndex = coercedEndIndex, endIndex = _length, destinationOffset = startIndex)
_length -= coercedEndIndex - startIndex
return this
}
/**
* Copies characters from this string builder into the [destination] character array.
*
* @param destination the array to copy to.
* @param destinationOffset the position in the array to copy to, 0 by default.
* @param startIndex the beginning (inclusive) of the range to copy, 0 by default.
* @param endIndex the end (exclusive) of the range to copy, length of this string builder by default.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this string builder indices or when `startIndex > endIndex`.
* @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset],
* or when that index is out of the [destination] array indices range.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun toCharArray(destination: CharArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = this.length) {
checkBoundsIndexes(startIndex, endIndex, _length)
checkBoundsIndexes(destinationOffset, destinationOffset + endIndex - startIndex, destination.size)
array.copyInto(destination, destinationOffset, startIndex, endIndex)
}
/**
* Appends characters in a subarray of the specified character array [value] to this string builder and returns this instance.
*
* Characters are appended in order, starting at specified [startIndex].
*
* @param value the array from which characters are appended.
* @param startIndex the beginning (inclusive) of the subarray to append.
* @param endIndex the end (exclusive) of the subarray to append.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] array indices or when `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun appendRange(value: CharArray, startIndex: Int, endIndex: Int): StringBuilder {
checkBoundsIndexes(startIndex, endIndex, value.size)
val extraLength = endIndex - startIndex
ensureExtraCapacity(extraLength)
value.copyInto(array, _length, startIndex, endIndex)
_length += extraLength
return this
}
/**
* Appends a subsequence of the specified character sequence [value] to this string builder and returns this instance.
*
* @param value the character sequence from which a subsequence is appended.
* @param startIndex the beginning (inclusive) of the subsequence to append.
* @param endIndex the end (exclusive) of the subsequence to append.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] character sequence indices or when `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun appendRange(value: CharSequence, startIndex: Int, endIndex: Int): StringBuilder {
checkBoundsIndexes(startIndex, endIndex, value.length)
val extraLength = endIndex - startIndex
ensureExtraCapacity(extraLength)
(value as? String)?.let {
_length += insertString(array, _length, it, startIndex, extraLength)
return this
}
var index = startIndex
while (index < endIndex)
array[_length++] = value[index++]
return this
}
/**
* Inserts characters in a subsequence of the specified character sequence [value] into this string builder at the specified [index] and returns this instance.
*
* The inserted characters go in the same order as in the [value] character sequence, starting at [index].
*
* @param index the position in this string builder to insert at.
* @param value the character sequence from which a subsequence is inserted.
* @param startIndex the beginning (inclusive) of the subsequence to insert.
* @param endIndex the end (exclusive) of the subsequence to insert.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] character sequence indices or when `startIndex > endIndex`.
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun insertRange(index: Int, value: CharSequence, startIndex: Int, endIndex: Int): StringBuilder {
checkBoundsIndexes(startIndex, endIndex, value.length)
checkInsertIndex(index)
val extraLength = endIndex - startIndex
ensureExtraCapacity(extraLength)
array.copyInto(array, startIndex = index, endIndex = _length, destinationOffset = index + extraLength)
var from = startIndex
var to = index
while (from < endIndex) {
array[to++] = value[from++]
}
_length += extraLength
return this
}
/**
* Inserts characters in a subarray of the specified character array [value] into this string builder at the specified [index] and returns this instance.
*
* The inserted characters go in same order as in the [value] array, starting at [index].
*
* @param index the position in this string builder to insert at.
* @param value the array from which characters are inserted.
* @param startIndex the beginning (inclusive) of the subarray to insert.
* @param endIndex the end (exclusive) of the subarray to insert.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] array indices or when `startIndex > endIndex`.
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
fun insertRange(index: Int, value: CharArray, startIndex: Int, endIndex: Int): StringBuilder {
checkInsertIndex(index)
checkBoundsIndexes(startIndex, endIndex, value.size)
val extraLength = endIndex - startIndex
ensureExtraCapacity(extraLength)
array.copyInto(array, startIndex = index, endIndex = _length, destinationOffset = index + extraLength)
value.copyInto(array, startIndex = startIndex, endIndex = endIndex, destinationOffset = index)
_length += extraLength
return this
}
// ---------------------------- private ----------------------------
private fun ensureExtraCapacity(n: Int) {
ensureCapacity(_length + n)
}
private fun checkIndex(index: Int) {
if (index < 0 || index >= _length) throw IndexOutOfBoundsException()
}
private fun checkInsertIndex(index: Int) {
if (index < 0 || index > _length) throw IndexOutOfBoundsException()
}
private fun checkInsertIndexFrom(index: Int, fromIndex: Int) {
if (index < fromIndex || index > _length) throw IndexOutOfBoundsException()
}
private fun checkReplaceRange(startIndex: Int, endIndex: Int, length: Int) {
if (startIndex < 0 || startIndex > length) {
throw IndexOutOfBoundsException("startIndex: $startIndex, length: $length")
}
if (startIndex > endIndex) {
throw IllegalArgumentException("startIndex($startIndex) > endIndex($endIndex)")
}
}
}
/**
* Clears the content of this string builder making it empty and returns this instance.
*
* @sample samples.text.Strings.clearStringBuilder
*/
@SinceKotlin("1.3")
public actual fun StringBuilder.clear(): StringBuilder = apply { setLength(0) }
/**
* Sets the character at the specified [index] to the specified [value].
*
* @throws IndexOutOfBoundsException if [index] is out of bounds of this string builder.
*/
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline operator fun StringBuilder.set(index: Int, value: Char): Unit = this.set(index, value)
/**
* Replaces characters in the specified range of this string builder with characters in the specified string [value] and returns this instance.
*
* @param startIndex the beginning (inclusive) of the range to replace.
* @param endIndex the end (exclusive) of the range to replace.
* @param value the string to replace with.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] if [startIndex] is less than zero, greater than the length of this string builder, or `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.setRange(startIndex: Int, endIndex: Int, value: String): StringBuilder =
this.setRange(startIndex, endIndex, value)
/**
* Removes the character at the specified [index] from this string builder and returns this instance.
*
* If the `Char` at the specified [index] is part of a supplementary code point, this method does not remove the entire supplementary character.
*
* @param index the index of `Char` to remove.
*
* @throws IndexOutOfBoundsException if [index] is out of bounds of this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.deleteAt(index: Int): StringBuilder = this.deleteAt(index)
/**
* Removes characters in the specified range from this string builder and returns this instance.
*
* @param startIndex the beginning (inclusive) of the range to remove.
* @param endIndex the end (exclusive) of the range to remove.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] is out of range of this string builder indices or when `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.deleteRange(startIndex: Int, endIndex: Int): StringBuilder = this.deleteRange(startIndex, endIndex)
/**
* Copies characters from this string builder into the [destination] character array.
*
* @param destination the array to copy to.
* @param destinationOffset the position in the array to copy to, 0 by default.
* @param startIndex the beginning (inclusive) of the range to copy, 0 by default.
* @param endIndex the end (exclusive) of the range to copy, length of this string builder by default.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this string builder indices or when `startIndex > endIndex`.
* @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset],
* or when that index is out of the [destination] array indices range.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER", "ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.toCharArray(destination: CharArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = this.length) =
this.toCharArray(destination, destinationOffset, startIndex, endIndex)
/**
* Appends characters in a subarray of the specified character array [value] to this string builder and returns this instance.
*
* Characters are appended in order, starting at specified [startIndex].
*
* @param value the array from which characters are appended.
* @param startIndex the beginning (inclusive) of the subarray to append.
* @param endIndex the end (exclusive) of the subarray to append.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] array indices or when `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.appendRange(value: CharArray, startIndex: Int, endIndex: Int): StringBuilder =
this.appendRange(value, startIndex, endIndex)
/**
* Appends a subsequence of the specified character sequence [value] to this string builder and returns this instance.
*
* @param value the character sequence from which a subsequence is appended.
* @param startIndex the beginning (inclusive) of the subsequence to append.
* @param endIndex the end (exclusive) of the subsequence to append.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] character sequence indices or when `startIndex > endIndex`.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.appendRange(value: CharSequence, startIndex: Int, endIndex: Int): StringBuilder =
this.appendRange(value, startIndex, endIndex)
/**
* Inserts characters in a subarray of the specified character array [value] into this string builder at the specified [index] and returns this instance.
*
* The inserted characters go in same order as in the [value] array, starting at [index].
*
* @param index the position in this string builder to insert at.
* @param value the array from which characters are inserted.
* @param startIndex the beginning (inclusive) of the subarray to insert.
* @param endIndex the end (exclusive) of the subarray to insert.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] array indices or when `startIndex > endIndex`.
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.insertRange(index: Int, value: CharArray, startIndex: Int, endIndex: Int): StringBuilder =
this.insertRange(index, value, startIndex, endIndex)
/**
* Inserts characters in a subsequence of the specified character sequence [value] into this string builder at the specified [index] and returns this instance.
*
* The inserted characters go in the same order as in the [value] character sequence, starting at [index].
*
* @param index the position in this string builder to insert at.
* @param value the character sequence from which a subsequence is inserted.
* @param startIndex the beginning (inclusive) of the subsequence to insert.
* @param endIndex the end (exclusive) of the subsequence to insert.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of the [value] character sequence indices or when `startIndex > endIndex`.
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
@SinceKotlin("1.4")
@WasExperimental(ExperimentalStdlibApi::class)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@kotlin.internal.InlineOnly
public actual inline fun StringBuilder.insertRange(index: Int, value: CharSequence, startIndex: Int, endIndex: Int): StringBuilder =
this.insertRange(index, value, startIndex, endIndex)
internal fun insertString(array: CharArray, start: Int, value: String): Int =
insertString(array, start, value, 0, value.length)
// Method parameters renamings
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: Boolean) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: Boolean): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: Byte) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: Byte): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: Short) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: Short): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: Int) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: Int): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: Long) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: Long): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: Float) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: Float): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: Double) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: Double): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: String) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: String): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use append(value: CharArray) instead", ReplaceWith("append(value = it)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.append(it: CharArray): StringBuilder = this.append(value = it)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use ensureCapacity(minimumCapacity: Int) instead", ReplaceWith("ensureCapacity(minimumCapacity = capacity)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.ensureCapacity(capacity: Int): Unit = this.ensureCapacity(minimumCapacity = capacity)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use insert(index: Int, value: Char) instead", ReplaceWith("insert(index, value = c)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.insert(index: Int, c: Char): StringBuilder = this.insert(index, value = c)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use insert(index: Int, value: CharArray) instead", ReplaceWith("insert(index, value = chars)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.insert(index: Int, chars: CharArray): StringBuilder = this.insert(index, value = chars)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use insert(index: Int, value: CharSequence?) instead", ReplaceWith("insert(index, value = csq)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.insert(index: Int, csq: CharSequence?): StringBuilder = this.insert(index, value = csq)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use insert(index: Int, value: String) instead", ReplaceWith("insert(index, value = string)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.insert(index: Int, string: String): StringBuilder = this.insert(index, value = string)
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use setLength(newLength: Int) instead", ReplaceWith("setLength(newLength = l)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.setLength(l: Int) = this.setLength(newLength = l)
// Method renamings
/**
* Inserts characters in a subsequence of the specified character sequence [csq] into this string builder at the specified [index] and returns this instance.
*
* The inserted characters go in the same order as in the [csq] character sequence, starting at [index].
*
* @param index the position in this string builder to insert at.
* @param csq the character sequence from which a subsequence is inserted. If [csq] is `null`,
* then characters will be inserted as if [csq] contained the four characters `"null"`.
* @param start the beginning (inclusive) of the subsequence to insert.
* @param end the end (exclusive) of the subsequence to insert.
*
* @throws IndexOutOfBoundsException or [IllegalArgumentException] when [start] or [end] is out of range of the [csq] character sequence indices or when `start > end`.
* @throws IndexOutOfBoundsException if [index] is less than zero or greater than the length of this string builder.
*/
@DeprecatedSinceKotlin(warningSince = "1.4", errorSince = "1.6")
@Deprecated(
"Use insertRange(index: Int, csq: CharSequence, start: Int, end: Int) instead",
ReplaceWith("insertRange(index, csq ?: \"null\", start, end)")
)
@kotlin.internal.InlineOnly
public inline fun StringBuilder.insert(index: Int, csq: CharSequence?, start: Int, end: Int): StringBuilder =
this.insertRange(index, csq ?: "null", start, end)
@DeprecatedSinceKotlin(warningSince = "1.3", errorSince = "1.6")
@Deprecated("Use set(index: Int, value: Char) instead", ReplaceWith("set(index, value)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.setCharAt(index: Int, value: Char) = this.set(index, value)
/**
* Removes the character at the specified [index] from this string builder and returns this instance.
*
* If the `Char` at the specified [index] is part of a supplementary code point, this method does not remove the entire supplementary character.
*
* @param index the index of `Char` to remove.
*
* @throws IndexOutOfBoundsException if [index] is out of bounds of this string builder.
*/
@DeprecatedSinceKotlin(warningSince = "1.4", errorSince = "1.6")
@Deprecated("Use deleteAt(index: Int) instead", ReplaceWith("deleteAt(index)"))
@kotlin.internal.InlineOnly
public inline fun StringBuilder.deleteCharAt(index: Int) = this.deleteAt(index)