Align ListBuilder with native ArrayList
Furthermore, add test for ListBuilder.subList detection of concurrent modification, and fix error in ListBuilder and ArrayList. Fix KT-62346
This commit is contained in:
committed by
Space Cloud
parent
d62dbbb1bd
commit
5a8faa8775
@@ -9,81 +9,58 @@ import java.io.Externalizable
|
|||||||
import java.io.InvalidObjectException
|
import java.io.InvalidObjectException
|
||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
|
|
||||||
internal class ListBuilder<E> private constructor(
|
internal class ListBuilder<E>(initialCapacity: Int = 10) : MutableList<E>, RandomAccess, AbstractMutableList<E>(), Serializable {
|
||||||
private var array: Array<E>,
|
private var backing = arrayOfUninitializedElements<E>(initialCapacity)
|
||||||
private var offset: Int,
|
private var length = 0
|
||||||
private var length: Int,
|
private var isReadOnly = false
|
||||||
private var isReadOnly: Boolean,
|
|
||||||
private val backing: ListBuilder<E>?,
|
|
||||||
private val root: ListBuilder<E>?
|
|
||||||
) : MutableList<E>, RandomAccess, AbstractMutableList<E>(), Serializable {
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private val Empty = ListBuilder<Nothing>(0).also { it.isReadOnly = true }
|
private val Empty = ListBuilder<Nothing>(0).also { it.isReadOnly = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
if (backing != null) this.modCount = backing.modCount
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() : this(10)
|
|
||||||
|
|
||||||
constructor(initialCapacity: Int) : this(
|
|
||||||
arrayOfUninitializedElements(initialCapacity), 0, 0, false, null, null)
|
|
||||||
|
|
||||||
fun build(): List<E> {
|
fun build(): List<E> {
|
||||||
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ListBuilder
|
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
isReadOnly = true
|
isReadOnly = true
|
||||||
return if (length > 0) this else Empty
|
return if (length > 0) this else Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun writeReplace(): Any =
|
private fun writeReplace(): Any =
|
||||||
if (isEffectivelyReadOnly)
|
if (isReadOnly)
|
||||||
SerializedCollection(this, SerializedCollection.tagList)
|
SerializedCollection(this, SerializedCollection.tagList)
|
||||||
else
|
else
|
||||||
throw NotSerializableException("The list cannot be serialized while it is being built.")
|
throw NotSerializableException("The list cannot be serialized while it is being built.")
|
||||||
|
|
||||||
override val size: Int
|
override val size: Int
|
||||||
get() {
|
get() = length
|
||||||
checkForComodification()
|
|
||||||
return length
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
override fun isEmpty() = length == 0
|
||||||
checkForComodification()
|
|
||||||
return length == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun get(index: Int): E {
|
override fun get(index: Int): E {
|
||||||
checkForComodification()
|
|
||||||
AbstractList.checkElementIndex(index, length)
|
AbstractList.checkElementIndex(index, length)
|
||||||
return array[offset + index]
|
return backing[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
override operator fun set(index: Int, element: E): E {
|
override operator fun set(index: Int, element: E): E {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
|
||||||
AbstractList.checkElementIndex(index, length)
|
AbstractList.checkElementIndex(index, length)
|
||||||
val old = array[offset + index]
|
val old = backing[index]
|
||||||
array[offset + index] = element
|
backing[index] = element
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun indexOf(element: E): Int {
|
override fun indexOf(element: E): Int {
|
||||||
checkForComodification()
|
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
if (array[offset + i] == element) return i
|
if (backing[i] == element) return i
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lastIndexOf(element: E): Int {
|
override fun lastIndexOf(element: E): Int {
|
||||||
checkForComodification()
|
|
||||||
var i = length - 1
|
var i = length - 1
|
||||||
while (i >= 0) {
|
while (i >= 0) {
|
||||||
if (array[offset + i] == element) return i
|
if (backing[i] == element) return i
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
@@ -93,58 +70,50 @@ internal class ListBuilder<E> private constructor(
|
|||||||
override fun listIterator(): MutableListIterator<E> = listIterator(0)
|
override fun listIterator(): MutableListIterator<E> = listIterator(0)
|
||||||
|
|
||||||
override fun listIterator(index: Int): MutableListIterator<E> {
|
override fun listIterator(index: Int): MutableListIterator<E> {
|
||||||
checkForComodification()
|
|
||||||
AbstractList.checkPositionIndex(index, length)
|
AbstractList.checkPositionIndex(index, length)
|
||||||
return Itr(this, index)
|
return Itr(this, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: E): Boolean {
|
override fun add(element: E): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
addAtInternal(length, element)
|
||||||
addAtInternal(offset + length, element)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(index: Int, element: E) {
|
override fun add(index: Int, element: E) {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
|
||||||
AbstractList.checkPositionIndex(index, length)
|
AbstractList.checkPositionIndex(index, length)
|
||||||
addAtInternal(offset + index, element)
|
addAtInternal(index, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addAll(elements: Collection<E>): Boolean {
|
override fun addAll(elements: Collection<E>): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
|
||||||
val n = elements.size
|
val n = elements.size
|
||||||
addAllInternal(offset + length, elements, n)
|
addAllInternal(length, elements, n)
|
||||||
return n > 0
|
return n > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addAll(index: Int, elements: Collection<E>): Boolean {
|
override fun addAll(index: Int, elements: Collection<E>): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
|
||||||
AbstractList.checkPositionIndex(index, length)
|
AbstractList.checkPositionIndex(index, length)
|
||||||
val n = elements.size
|
val n = elements.size
|
||||||
addAllInternal(offset + index, elements, n)
|
addAllInternal(index, elements, n)
|
||||||
return n > 0
|
return n > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
removeRangeInternal(0, length)
|
||||||
removeRangeInternal(offset, length)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeAt(index: Int): E {
|
override fun removeAt(index: Int): E {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
|
||||||
AbstractList.checkElementIndex(index, length)
|
AbstractList.checkElementIndex(index, length)
|
||||||
return removeAtInternal(offset + index)
|
return removeAtInternal(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(element: E): Boolean {
|
override fun remove(element: E): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
|
||||||
val i = indexOf(element)
|
val i = indexOf(element)
|
||||||
if (i >= 0) removeAt(i)
|
if (i >= 0) removeAt(i)
|
||||||
return i >= 0
|
return i >= 0
|
||||||
@@ -152,53 +121,46 @@ internal class ListBuilder<E> private constructor(
|
|||||||
|
|
||||||
override fun removeAll(elements: Collection<E>): Boolean {
|
override fun removeAll(elements: Collection<E>): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
return retainOrRemoveAllInternal(0, length, elements, false) > 0
|
||||||
return retainOrRemoveAllInternal(offset, length, elements, false) > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<E>): Boolean {
|
override fun retainAll(elements: Collection<E>): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
return retainOrRemoveAllInternal(0, length, elements, true) > 0
|
||||||
return retainOrRemoveAllInternal(offset, length, elements, true) > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
||||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, length)
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, length)
|
||||||
return ListBuilder(array, offset + fromIndex, toIndex - fromIndex, isReadOnly, this, root ?: this)
|
return BuilderSubList(backing, fromIndex, toIndex - fromIndex, null, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> toArray(destination: Array<T>): Array<T> {
|
@Suppress("UNCHECKED_CAST")
|
||||||
checkForComodification()
|
override fun <T> toArray(array: Array<T>): Array<T> {
|
||||||
if (destination.size < length) {
|
if (array.size < length) {
|
||||||
return java.util.Arrays.copyOfRange(array, offset, offset + length, destination.javaClass)
|
return java.util.Arrays.copyOfRange(backing, 0, length, array.javaClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
(backing as Array<T>).copyInto(array, 0, startIndex = 0, endIndex = length)
|
||||||
(array as Array<T>).copyInto(destination, 0, startIndex = offset, endIndex = offset + length)
|
|
||||||
|
|
||||||
return terminateCollectionToArray(length, destination)
|
return terminateCollectionToArray(length, array)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toArray(): Array<Any?> {
|
override fun toArray(): Array<Any?> {
|
||||||
checkForComodification()
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return array.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<Any?>
|
return backing.copyOfRange(fromIndex = 0, toIndex = length) as Array<Any?>
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
checkForComodification()
|
|
||||||
return other === this ||
|
return other === this ||
|
||||||
(other is List<*>) && contentEquals(other)
|
(other is List<*>) && contentEquals(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
checkForComodification()
|
return backing.subarrayContentHashCode(0, length)
|
||||||
return array.subarrayContentHashCode(offset, length)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
checkForComodification()
|
return backing.subarrayContentToString(0, length, this)
|
||||||
return array.subarrayContentToString(offset, length, this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------- private ----------------------------
|
// ---------------------------- private ----------------------------
|
||||||
@@ -207,131 +169,90 @@ internal class ListBuilder<E> private constructor(
|
|||||||
modCount += 1
|
modCount += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkForComodification() {
|
|
||||||
if (root != null && root.modCount != modCount)
|
|
||||||
throw ConcurrentModificationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkIsMutable() {
|
private fun checkIsMutable() {
|
||||||
if (isEffectivelyReadOnly) throw UnsupportedOperationException()
|
if (isReadOnly) throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val isEffectivelyReadOnly: Boolean
|
|
||||||
get() = isReadOnly || root != null && root.isReadOnly
|
|
||||||
|
|
||||||
private fun ensureExtraCapacity(n: Int) {
|
private fun ensureExtraCapacity(n: Int) {
|
||||||
ensureCapacityInternal(length + n)
|
ensureCapacityInternal(length + n)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureCapacityInternal(minCapacity: Int) {
|
private fun ensureCapacityInternal(minCapacity: Int) {
|
||||||
if (minCapacity < 0) throw OutOfMemoryError() // overflow
|
if (minCapacity < 0) throw OutOfMemoryError() // overflow
|
||||||
if (minCapacity > array.size) {
|
if (minCapacity > backing.size) {
|
||||||
val newSize = AbstractList.newCapacity(array.size, minCapacity)
|
val newSize = AbstractList.newCapacity(backing.size, minCapacity)
|
||||||
array = array.copyOfUninitializedElements(newSize)
|
backing = backing.copyOfUninitializedElements(newSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun contentEquals(other: List<*>): Boolean {
|
private fun contentEquals(other: List<*>): Boolean {
|
||||||
return array.subarrayContentEquals(offset, length, other)
|
return backing.subarrayContentEquals(0, length, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insertAtInternal(i: Int, n: Int) {
|
private fun insertAtInternal(i: Int, n: Int) {
|
||||||
ensureExtraCapacity(n)
|
ensureExtraCapacity(n)
|
||||||
array.copyInto(array, startIndex = i, endIndex = offset + length, destinationOffset = i + n)
|
backing.copyInto(backing, startIndex = i, endIndex = length, destinationOffset = i + n)
|
||||||
length += n
|
length += n
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addAtInternal(i: Int, element: E) {
|
private fun addAtInternal(i: Int, element: E) {
|
||||||
registerModification()
|
registerModification()
|
||||||
if (backing != null) {
|
insertAtInternal(i, 1)
|
||||||
backing.addAtInternal(i, element)
|
backing[i] = element
|
||||||
array = backing.array
|
|
||||||
length++
|
|
||||||
} else {
|
|
||||||
insertAtInternal(i, 1)
|
|
||||||
array[i] = element
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
|
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
|
||||||
registerModification()
|
registerModification()
|
||||||
if (backing != null) {
|
insertAtInternal(i, n)
|
||||||
backing.addAllInternal(i, elements, n)
|
var j = 0
|
||||||
array = backing.array
|
val it = elements.iterator()
|
||||||
length += n
|
while (j < n) {
|
||||||
} else {
|
backing[i + j] = it.next()
|
||||||
insertAtInternal(i, n)
|
j++
|
||||||
var j = 0
|
|
||||||
val it = elements.iterator()
|
|
||||||
while (j < n) {
|
|
||||||
array[i + j] = it.next()
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAtInternal(i: Int): E {
|
private fun removeAtInternal(i: Int): E {
|
||||||
registerModification()
|
registerModification()
|
||||||
if (backing != null) {
|
val old = backing[i]
|
||||||
val old = backing.removeAtInternal(i)
|
backing.copyInto(backing, startIndex = i + 1, endIndex = length, destinationOffset = i)
|
||||||
length--
|
backing.resetAt(length - 1)
|
||||||
return old
|
length--
|
||||||
} else {
|
return old
|
||||||
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) {
|
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
|
||||||
if (rangeLength > 0) registerModification()
|
if (rangeLength > 0) registerModification()
|
||||||
if (backing != null) {
|
backing.copyInto(backing, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset)
|
||||||
backing.removeRangeInternal(rangeOffset, rangeLength)
|
backing.resetRange(fromIndex = length - rangeLength, toIndex = length)
|
||||||
} else {
|
|
||||||
array.copyInto(array, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset)
|
|
||||||
array.resetRange(fromIndex = length - rangeLength, toIndex = length)
|
|
||||||
}
|
|
||||||
length -= rangeLength
|
length -= rangeLength
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Retains elements if [retain] == true and removes them it [retain] == false. */
|
/** Retains elements if [retain] == true and removes them it [retain] == false. */
|
||||||
private fun retainOrRemoveAllInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>, retain: Boolean): Int {
|
private fun retainOrRemoveAllInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>, retain: Boolean): Int {
|
||||||
val removed = if (backing != null) {
|
var i = 0
|
||||||
backing.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
var j = 0
|
||||||
} else {
|
while (i < rangeLength) {
|
||||||
var i = 0
|
if (elements.contains(backing[rangeOffset + i]) == retain) {
|
||||||
var j = 0
|
backing[rangeOffset + j++] = backing[rangeOffset + i++]
|
||||||
while (i < rangeLength) {
|
} else {
|
||||||
if (elements.contains(array[rangeOffset + i]) == retain) {
|
i++
|
||||||
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)
|
|
||||||
removed
|
|
||||||
}
|
}
|
||||||
|
val removed = rangeLength - j
|
||||||
|
backing.copyInto(backing, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset + j)
|
||||||
|
backing.resetRange(fromIndex = length - removed, toIndex = length)
|
||||||
if (removed > 0) registerModification()
|
if (removed > 0) registerModification()
|
||||||
length -= removed
|
length -= removed
|
||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Itr<E> : MutableListIterator<E> {
|
private class Itr<E>(
|
||||||
private val list: ListBuilder<E>
|
private val list: ListBuilder<E>,
|
||||||
private var index: Int
|
private var index: Int
|
||||||
private var lastIndex: Int
|
) : MutableListIterator<E> {
|
||||||
private var expectedModCount: Int
|
private var lastIndex = -1
|
||||||
|
private var expectedModCount = list.modCount
|
||||||
constructor(list: ListBuilder<E>, index: Int) {
|
|
||||||
this.list = list
|
|
||||||
this.index = index
|
|
||||||
this.lastIndex = -1
|
|
||||||
this.expectedModCount = list.modCount
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasPrevious(): Boolean = index > 0
|
override fun hasPrevious(): Boolean = index > 0
|
||||||
override fun hasNext(): Boolean = index < list.length
|
override fun hasNext(): Boolean = index < list.length
|
||||||
@@ -343,20 +264,20 @@ internal class ListBuilder<E> private constructor(
|
|||||||
checkForComodification()
|
checkForComodification()
|
||||||
if (index <= 0) throw NoSuchElementException()
|
if (index <= 0) throw NoSuchElementException()
|
||||||
lastIndex = --index
|
lastIndex = --index
|
||||||
return list.array[list.offset + lastIndex]
|
return list.backing[lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun next(): E {
|
override fun next(): E {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
if (index >= list.length) throw NoSuchElementException()
|
if (index >= list.length) throw NoSuchElementException()
|
||||||
lastIndex = index++
|
lastIndex = index++
|
||||||
return list.array[list.offset + lastIndex]
|
return list.backing[lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun set(element: E) {
|
override fun set(element: E) {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
|
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
|
||||||
list.set(lastIndex, element)
|
list[lastIndex] = element
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: E) {
|
override fun add(element: E) {
|
||||||
@@ -380,6 +301,315 @@ internal class ListBuilder<E> private constructor(
|
|||||||
throw ConcurrentModificationException()
|
throw ConcurrentModificationException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BuilderSubList<E>(
|
||||||
|
private var backing: Array<E>,
|
||||||
|
private val offset: Int,
|
||||||
|
private var length: Int,
|
||||||
|
private val parent: BuilderSubList<E>?,
|
||||||
|
private val root: ListBuilder<E>
|
||||||
|
) : MutableList<E>, RandomAccess, AbstractMutableList<E>(), Serializable {
|
||||||
|
init {
|
||||||
|
this.modCount = root.modCount
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeReplace(): Any =
|
||||||
|
if (isReadOnly)
|
||||||
|
SerializedCollection(this, SerializedCollection.tagList)
|
||||||
|
else
|
||||||
|
throw NotSerializableException("The list cannot be serialized while it is being built.")
|
||||||
|
|
||||||
|
override val size: Int
|
||||||
|
get() {
|
||||||
|
checkForComodification()
|
||||||
|
return length
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean {
|
||||||
|
checkForComodification()
|
||||||
|
return length == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(index: Int): E {
|
||||||
|
checkForComodification()
|
||||||
|
AbstractList.checkElementIndex(index, length)
|
||||||
|
return backing[offset + index]
|
||||||
|
}
|
||||||
|
|
||||||
|
override operator fun set(index: Int, element: E): E {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
AbstractList.checkElementIndex(index, length)
|
||||||
|
val old = backing[offset + index]
|
||||||
|
backing[offset + index] = element
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun indexOf(element: E): Int {
|
||||||
|
checkForComodification()
|
||||||
|
var i = 0
|
||||||
|
while (i < length) {
|
||||||
|
if (backing[offset + i] == element) return i
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun lastIndexOf(element: E): Int {
|
||||||
|
checkForComodification()
|
||||||
|
var i = length - 1
|
||||||
|
while (i >= 0) {
|
||||||
|
if (backing[offset + i] == element) return i
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): MutableIterator<E> = listIterator(0)
|
||||||
|
override fun listIterator(): MutableListIterator<E> = listIterator(0)
|
||||||
|
|
||||||
|
override fun listIterator(index: Int): MutableListIterator<E> {
|
||||||
|
checkForComodification()
|
||||||
|
AbstractList.checkPositionIndex(index, length)
|
||||||
|
return Itr(this, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(element: E): Boolean {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
addAtInternal(offset + length, element)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(index: Int, element: E) {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
AbstractList.checkPositionIndex(index, length)
|
||||||
|
addAtInternal(offset + index, element)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addAll(elements: Collection<E>): Boolean {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
val n = elements.size
|
||||||
|
addAllInternal(offset + length, elements, n)
|
||||||
|
return n > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addAll(index: Int, elements: Collection<E>): Boolean {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
AbstractList.checkPositionIndex(index, length)
|
||||||
|
val n = elements.size
|
||||||
|
addAllInternal(offset + index, elements, n)
|
||||||
|
return n > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
removeRangeInternal(offset, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeAt(index: Int): E {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
AbstractList.checkElementIndex(index, length)
|
||||||
|
return removeAtInternal(offset + index)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(element: E): Boolean {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
val i = indexOf(element)
|
||||||
|
if (i >= 0) removeAt(i)
|
||||||
|
return i >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeAll(elements: Collection<E>): Boolean {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
return retainOrRemoveAllInternal(offset, length, elements, false) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun retainAll(elements: Collection<E>): Boolean {
|
||||||
|
checkIsMutable()
|
||||||
|
checkForComodification()
|
||||||
|
return retainOrRemoveAllInternal(offset, length, elements, true) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
||||||
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, length)
|
||||||
|
return BuilderSubList(backing, offset + fromIndex, toIndex - fromIndex, this, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T> toArray(array: Array<T>): Array<T> {
|
||||||
|
checkForComodification()
|
||||||
|
if (array.size < length) {
|
||||||
|
return java.util.Arrays.copyOfRange(backing, offset, offset + length, array.javaClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
(backing as Array<T>).copyInto(array, 0, startIndex = offset, endIndex = offset + length)
|
||||||
|
|
||||||
|
return terminateCollectionToArray(length, array)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toArray(): Array<Any?> {
|
||||||
|
checkForComodification()
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return backing.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<Any?>
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
checkForComodification()
|
||||||
|
return other === this ||
|
||||||
|
(other is List<*>) && contentEquals(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
checkForComodification()
|
||||||
|
return backing.subarrayContentHashCode(offset, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
checkForComodification()
|
||||||
|
return backing.subarrayContentToString(offset, length, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------- private ----------------------------
|
||||||
|
|
||||||
|
private fun registerModification() {
|
||||||
|
modCount += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkForComodification() {
|
||||||
|
if (root.modCount != modCount)
|
||||||
|
throw ConcurrentModificationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkIsMutable() {
|
||||||
|
if (isReadOnly) throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val isReadOnly: Boolean
|
||||||
|
get() = root.isReadOnly
|
||||||
|
|
||||||
|
private fun contentEquals(other: List<*>): Boolean {
|
||||||
|
return backing.subarrayContentEquals(offset, length, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAtInternal(i: Int, element: E) {
|
||||||
|
registerModification()
|
||||||
|
if (parent != null) {
|
||||||
|
parent.addAtInternal(i, element)
|
||||||
|
} else {
|
||||||
|
root.addAtInternal(i, element)
|
||||||
|
}
|
||||||
|
backing = root.backing
|
||||||
|
length++
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
|
||||||
|
registerModification()
|
||||||
|
if (parent != null) {
|
||||||
|
parent.addAllInternal(i, elements, n)
|
||||||
|
} else {
|
||||||
|
root.addAllInternal(i, elements, n)
|
||||||
|
}
|
||||||
|
backing = root.backing
|
||||||
|
length += n
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeAtInternal(i: Int): E {
|
||||||
|
registerModification()
|
||||||
|
val old = if (parent != null) {
|
||||||
|
parent.removeAtInternal(i)
|
||||||
|
} else {
|
||||||
|
root.removeAtInternal(i)
|
||||||
|
}
|
||||||
|
length--
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
|
||||||
|
if (rangeLength > 0) registerModification()
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeRangeInternal(rangeOffset, rangeLength)
|
||||||
|
} else {
|
||||||
|
root.removeRangeInternal(rangeOffset, rangeLength)
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
val removed =
|
||||||
|
if (parent != null) {
|
||||||
|
parent.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
||||||
|
} else {
|
||||||
|
root.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
||||||
|
}
|
||||||
|
if (removed > 0) registerModification()
|
||||||
|
length -= removed
|
||||||
|
return removed
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Itr<E>(
|
||||||
|
private val list: BuilderSubList<E>,
|
||||||
|
private var index: Int
|
||||||
|
) : MutableListIterator<E> {
|
||||||
|
private var lastIndex = -1
|
||||||
|
private var expectedModCount = list.modCount
|
||||||
|
|
||||||
|
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 {
|
||||||
|
checkForComodification()
|
||||||
|
if (index <= 0) throw NoSuchElementException()
|
||||||
|
lastIndex = --index
|
||||||
|
return list.backing[list.offset + lastIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun next(): E {
|
||||||
|
checkForComodification()
|
||||||
|
if (index >= list.length) throw NoSuchElementException()
|
||||||
|
lastIndex = index++
|
||||||
|
return list.backing[list.offset + lastIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(element: E) {
|
||||||
|
checkForComodification()
|
||||||
|
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
|
||||||
|
list[lastIndex] = element
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(element: E) {
|
||||||
|
checkForComodification()
|
||||||
|
list.add(index++, element)
|
||||||
|
lastIndex = -1
|
||||||
|
expectedModCount = list.modCount
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove() {
|
||||||
|
checkForComodification()
|
||||||
|
check(lastIndex != -1) { "Call next() or previous() before removing element from the iterator." }
|
||||||
|
list.removeAt(lastIndex)
|
||||||
|
index = lastIndex
|
||||||
|
lastIndex = -1
|
||||||
|
expectedModCount = list.modCount
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkForComodification() {
|
||||||
|
if (list.root.modCount != expectedModCount)
|
||||||
|
throw ConcurrentModificationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <E> arrayOfUninitializedElements(size: Int): Array<E> {
|
internal fun <E> arrayOfUninitializedElements(size: Int): Array<E> {
|
||||||
@@ -484,4 +714,4 @@ internal class SerializedCollection(
|
|||||||
const val tagList: Int = 0
|
const val tagList: Int = 0
|
||||||
const val tagSet: Int = 1
|
const val tagSet: Int = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,7 +252,6 @@ class CollectionJVMTest {
|
|||||||
private fun testCollectionBuilderSerialization(value: Any) {
|
private fun testCollectionBuilderSerialization(value: Any) {
|
||||||
val result = serializeAndDeserialize(value)
|
val result = serializeAndDeserialize(value)
|
||||||
assertEquals(value, result)
|
assertEquals(value, result)
|
||||||
assertEquals(value.javaClass, result.javaClass)
|
|
||||||
assertReadOnly(result)
|
assertReadOnly(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,22 @@
|
|||||||
|
|
||||||
package kotlin.collections
|
package kotlin.collections
|
||||||
|
|
||||||
actual class ArrayList<E> private constructor(
|
/**
|
||||||
private var backingArray: Array<E>,
|
* Creates a new empty [ArrayList] with the specified initial capacity.
|
||||||
private var length: Int,
|
*
|
||||||
private var isReadOnly: Boolean
|
* Capacity is the maximum number of elements the list is able to store in current backing storage.
|
||||||
) : MutableList<E>, RandomAccess, AbstractMutableList<E>() {
|
* When the list gets full and a new element can't be added, its capacity is expanded,
|
||||||
|
* which usually leads to creation of a bigger backing storage.
|
||||||
|
*
|
||||||
|
* @param initialCapacity the initial capacity of the created list.
|
||||||
|
* Note that the argument is just a hint for the implementation and can be ignored.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if [initialCapacity] is negative.
|
||||||
|
*/
|
||||||
|
actual class ArrayList<E> actual constructor(initialCapacity: Int) : MutableList<E>, RandomAccess, AbstractMutableList<E>() {
|
||||||
|
private var backing = arrayOfUninitializedElements<E>(initialCapacity)
|
||||||
|
private var length = 0
|
||||||
|
private var isReadOnly = false
|
||||||
private companion object {
|
private companion object {
|
||||||
private val Empty = ArrayList<Nothing>(0).also { it.isReadOnly = true }
|
private val Empty = ArrayList<Nothing>(0).also { it.isReadOnly = true }
|
||||||
}
|
}
|
||||||
@@ -19,21 +30,6 @@ actual class ArrayList<E> private constructor(
|
|||||||
*/
|
*/
|
||||||
actual constructor() : this(10)
|
actual constructor() : this(10)
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new empty [ArrayList] with the specified initial capacity.
|
|
||||||
*
|
|
||||||
* Capacity is the maximum number of elements the list is able to store in current backing storage.
|
|
||||||
* When the list gets full and a new element can't be added, its capacity is expanded,
|
|
||||||
* which usually leads to creation of a bigger backing storage.
|
|
||||||
*
|
|
||||||
* @param initialCapacity the initial capacity of the created list.
|
|
||||||
* Note that the argument is just a hint for the implementation and can be ignored.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if [initialCapacity] is negative.
|
|
||||||
*/
|
|
||||||
actual constructor(initialCapacity: Int) : this(
|
|
||||||
arrayOfUninitializedElements(initialCapacity), 0, false)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new [ArrayList] filled with the elements of the specified collection.
|
* Creates a new [ArrayList] filled with the elements of the specified collection.
|
||||||
*
|
*
|
||||||
@@ -51,31 +47,27 @@ actual class ArrayList<E> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override actual val size: Int
|
override actual val size: Int
|
||||||
get() {
|
get() = length
|
||||||
return length
|
|
||||||
}
|
|
||||||
|
|
||||||
override actual fun isEmpty(): Boolean {
|
override actual fun isEmpty() = length == 0
|
||||||
return length == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override actual fun get(index: Int): E {
|
override actual fun get(index: Int): E {
|
||||||
AbstractList.checkElementIndex(index, length)
|
AbstractList.checkElementIndex(index, length)
|
||||||
return backingArray[index]
|
return backing[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
override actual operator fun set(index: Int, element: E): E {
|
override actual operator fun set(index: Int, element: E): E {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
AbstractList.checkElementIndex(index, length)
|
AbstractList.checkElementIndex(index, length)
|
||||||
val old = backingArray[index]
|
val old = backing[index]
|
||||||
backingArray[index] = element
|
backing[index] = element
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
override actual fun indexOf(element: E): Int {
|
override actual fun indexOf(element: E): Int {
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
if (backingArray[i] == element) return i
|
if (backing[i] == element) return i
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
@@ -84,7 +76,7 @@ actual class ArrayList<E> private constructor(
|
|||||||
override actual fun lastIndexOf(element: E): Int {
|
override actual fun lastIndexOf(element: E): Int {
|
||||||
var i = length - 1
|
var i = length - 1
|
||||||
while (i >= 0) {
|
while (i >= 0) {
|
||||||
if (backingArray[i] == element) return i
|
if (backing[i] == element) return i
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
@@ -155,17 +147,33 @@ actual class ArrayList<E> private constructor(
|
|||||||
|
|
||||||
override actual fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
override actual fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
||||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, length)
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, length)
|
||||||
return ArraySubList(backingArray, fromIndex, toIndex - fromIndex, null, this)
|
return ArraySubList(backing, fromIndex, toIndex - fromIndex, null, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T> toArray(array: Array<T>): Array<T> {
|
||||||
|
if (array.size < length) {
|
||||||
|
return backing.copyOfRange(fromIndex = 0, toIndex = length) as Array<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
(backing as Array<T>).copyInto(array, 0, startIndex = 0, endIndex = length)
|
||||||
|
|
||||||
|
return terminateCollectionToArray(length, array)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toArray(): Array<Any?> {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return backing.copyOfRange(fromIndex = 0, toIndex = length) as Array<Any?>
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun trimToSize() {
|
actual fun trimToSize() {
|
||||||
registerModification()
|
registerModification()
|
||||||
if (length < backingArray.size)
|
if (length < backing.size)
|
||||||
backingArray = backingArray.copyOfUninitializedElements(length)
|
backing = backing.copyOfUninitializedElements(length)
|
||||||
}
|
}
|
||||||
|
|
||||||
final actual fun ensureCapacity(minCapacity: Int) {
|
final actual fun ensureCapacity(minCapacity: Int) {
|
||||||
if (minCapacity <= backingArray.size) return
|
if (minCapacity <= backing.size) return
|
||||||
registerModification()
|
registerModification()
|
||||||
ensureCapacityInternal(minCapacity)
|
ensureCapacityInternal(minCapacity)
|
||||||
}
|
}
|
||||||
@@ -176,27 +184,11 @@ actual class ArrayList<E> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return backingArray.subarrayContentHashCode(0, length)
|
return backing.subarrayContentHashCode(0, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return backingArray.subarrayContentToString(0, length, this)
|
return backing.subarrayContentToString(0, length, this)
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T> toArray(array: Array<T>): Array<T> {
|
|
||||||
if (array.size < length) {
|
|
||||||
return backingArray.copyOfRange(fromIndex = 0, toIndex = length) as Array<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
(backingArray as Array<T>).copyInto(array, 0, startIndex = 0, endIndex = length)
|
|
||||||
|
|
||||||
return terminateCollectionToArray(length, array)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toArray(): Array<Any?> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return backingArray.copyOfRange(fromIndex = 0, toIndex = length) as Array<Any?>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------- private ----------------------------
|
// ---------------------------- private ----------------------------
|
||||||
@@ -215,26 +207,26 @@ actual class ArrayList<E> private constructor(
|
|||||||
|
|
||||||
private fun ensureCapacityInternal(minCapacity: Int) {
|
private fun ensureCapacityInternal(minCapacity: Int) {
|
||||||
if (minCapacity < 0) throw OutOfMemoryError() // overflow
|
if (minCapacity < 0) throw OutOfMemoryError() // overflow
|
||||||
if (minCapacity > backingArray.size) {
|
if (minCapacity > backing.size) {
|
||||||
val newSize = AbstractList.newCapacity(backingArray.size, minCapacity)
|
val newSize = AbstractList.newCapacity(backing.size, minCapacity)
|
||||||
backingArray = backingArray.copyOfUninitializedElements(newSize)
|
backing = backing.copyOfUninitializedElements(newSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun contentEquals(other: List<*>): Boolean {
|
private fun contentEquals(other: List<*>): Boolean {
|
||||||
return backingArray.subarrayContentEquals(0, length, other)
|
return backing.subarrayContentEquals(0, length, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun insertAtInternal(i: Int, n: Int) {
|
private fun insertAtInternal(i: Int, n: Int) {
|
||||||
ensureExtraCapacity(n)
|
ensureExtraCapacity(n)
|
||||||
backingArray.copyInto(backingArray, startIndex = i, endIndex = length, destinationOffset = i + n)
|
backing.copyInto(backing, startIndex = i, endIndex = length, destinationOffset = i + n)
|
||||||
length += n
|
length += n
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addAtInternal(i: Int, element: E) {
|
private fun addAtInternal(i: Int, element: E) {
|
||||||
registerModification()
|
registerModification()
|
||||||
insertAtInternal(i, 1)
|
insertAtInternal(i, 1)
|
||||||
backingArray[i] = element
|
backing[i] = element
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
|
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
|
||||||
@@ -243,24 +235,24 @@ actual class ArrayList<E> private constructor(
|
|||||||
var j = 0
|
var j = 0
|
||||||
val it = elements.iterator()
|
val it = elements.iterator()
|
||||||
while (j < n) {
|
while (j < n) {
|
||||||
backingArray[i + j] = it.next()
|
backing[i + j] = it.next()
|
||||||
j++
|
j++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAtInternal(i: Int): E {
|
private fun removeAtInternal(i: Int): E {
|
||||||
registerModification()
|
registerModification()
|
||||||
val old = backingArray[i]
|
val old = backing[i]
|
||||||
backingArray.copyInto(backingArray, startIndex = i + 1, endIndex = length, destinationOffset = i)
|
backing.copyInto(backing, startIndex = i + 1, endIndex = length, destinationOffset = i)
|
||||||
backingArray.resetAt(length - 1)
|
backing.resetAt(length - 1)
|
||||||
length--
|
length--
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
|
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
|
||||||
if (rangeLength > 0) registerModification()
|
if (rangeLength > 0) registerModification()
|
||||||
backingArray.copyInto(backingArray, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset)
|
backing.copyInto(backing, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset)
|
||||||
backingArray.resetRange(fromIndex = length - rangeLength, toIndex = length)
|
backing.resetRange(fromIndex = length - rangeLength, toIndex = length)
|
||||||
length -= rangeLength
|
length -= rangeLength
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,32 +261,26 @@ actual class ArrayList<E> private constructor(
|
|||||||
var i = 0
|
var i = 0
|
||||||
var j = 0
|
var j = 0
|
||||||
while (i < rangeLength) {
|
while (i < rangeLength) {
|
||||||
if (elements.contains(backingArray[rangeOffset + i]) == retain) {
|
if (elements.contains(backing[rangeOffset + i]) == retain) {
|
||||||
backingArray[rangeOffset + j++] = backingArray[rangeOffset + i++]
|
backing[rangeOffset + j++] = backing[rangeOffset + i++]
|
||||||
} else {
|
} else {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val removed = rangeLength - j
|
val removed = rangeLength - j
|
||||||
backingArray.copyInto(backingArray, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset + j)
|
backing.copyInto(backing, startIndex = rangeOffset + rangeLength, endIndex = length, destinationOffset = rangeOffset + j)
|
||||||
backingArray.resetRange(fromIndex = length - removed, toIndex = length)
|
backing.resetRange(fromIndex = length - removed, toIndex = length)
|
||||||
if (removed > 0) registerModification()
|
if (removed > 0) registerModification()
|
||||||
length -= removed
|
length -= removed
|
||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Itr<E> : MutableListIterator<E> {
|
private class Itr<E>(
|
||||||
private val list: ArrayList<E>
|
private val list: ArrayList<E>,
|
||||||
private var index: Int
|
private var index: Int
|
||||||
private var lastIndex: Int
|
) : MutableListIterator<E> {
|
||||||
private var expectedModCount: Int
|
private var lastIndex = -1
|
||||||
|
private var expectedModCount = list.modCount
|
||||||
constructor(list: ArrayList<E>, index: Int) {
|
|
||||||
this.list = list
|
|
||||||
this.index = index
|
|
||||||
this.lastIndex = -1
|
|
||||||
this.expectedModCount = list.modCount
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasPrevious(): Boolean = index > 0
|
override fun hasPrevious(): Boolean = index > 0
|
||||||
override fun hasNext(): Boolean = index < list.length
|
override fun hasNext(): Boolean = index < list.length
|
||||||
@@ -306,20 +292,20 @@ actual class ArrayList<E> private constructor(
|
|||||||
checkForComodification()
|
checkForComodification()
|
||||||
if (index <= 0) throw NoSuchElementException()
|
if (index <= 0) throw NoSuchElementException()
|
||||||
lastIndex = --index
|
lastIndex = --index
|
||||||
return list.backingArray[lastIndex]
|
return list.backing[lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun next(): E {
|
override fun next(): E {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
if (index >= list.length) throw NoSuchElementException()
|
if (index >= list.length) throw NoSuchElementException()
|
||||||
lastIndex = index++
|
lastIndex = index++
|
||||||
return list.backingArray[lastIndex]
|
return list.backing[lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun set(element: E) {
|
override fun set(element: E) {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
|
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
|
||||||
list.set(lastIndex, element)
|
list[lastIndex] = element
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: E) {
|
override fun add(element: E) {
|
||||||
@@ -347,10 +333,10 @@ actual class ArrayList<E> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class ArraySubList<E>(
|
private class ArraySubList<E>(
|
||||||
private var backingArray: Array<E>,
|
private var backing: Array<E>,
|
||||||
private val offset: Int,
|
private val offset: Int,
|
||||||
private var length: Int,
|
private var length: Int,
|
||||||
private val backingList: ArraySubList<E>?,
|
private val parent: ArraySubList<E>?,
|
||||||
private val root: ArrayList<E>
|
private val root: ArrayList<E>
|
||||||
) : MutableList<E>, RandomAccess, AbstractMutableList<E>() {
|
) : MutableList<E>, RandomAccess, AbstractMutableList<E>() {
|
||||||
|
|
||||||
@@ -372,15 +358,15 @@ actual class ArrayList<E> private constructor(
|
|||||||
override fun get(index: Int): E {
|
override fun get(index: Int): E {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
AbstractList.checkElementIndex(index, length)
|
AbstractList.checkElementIndex(index, length)
|
||||||
return backingArray[offset + index]
|
return backing[offset + index]
|
||||||
}
|
}
|
||||||
|
|
||||||
override operator fun set(index: Int, element: E): E {
|
override operator fun set(index: Int, element: E): E {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
AbstractList.checkElementIndex(index, length)
|
AbstractList.checkElementIndex(index, length)
|
||||||
val old = backingArray[offset + index]
|
val old = backing[offset + index]
|
||||||
backingArray[offset + index] = element
|
backing[offset + index] = element
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +374,7 @@ actual class ArrayList<E> private constructor(
|
|||||||
checkForComodification()
|
checkForComodification()
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
if (backingArray[offset + i] == element) return i
|
if (backing[offset + i] == element) return i
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
@@ -398,7 +384,7 @@ actual class ArrayList<E> private constructor(
|
|||||||
checkForComodification()
|
checkForComodification()
|
||||||
var i = length - 1
|
var i = length - 1
|
||||||
while (i >= 0) {
|
while (i >= 0) {
|
||||||
if (backingArray[offset + i] == element) return i
|
if (backing[offset + i] == element) return i
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
@@ -479,7 +465,25 @@ actual class ArrayList<E> private constructor(
|
|||||||
|
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
|
||||||
AbstractList.checkRangeIndexes(fromIndex, toIndex, length)
|
AbstractList.checkRangeIndexes(fromIndex, toIndex, length)
|
||||||
return ArraySubList(backingArray, offset + fromIndex, toIndex - fromIndex, this, root)
|
return ArraySubList(backing, offset + fromIndex, toIndex - fromIndex, this, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T> toArray(array: Array<T>): Array<T> {
|
||||||
|
checkForComodification()
|
||||||
|
if (array.size < length) {
|
||||||
|
return backing.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
(backing as Array<T>).copyInto(array, 0, startIndex = offset, endIndex = offset + length)
|
||||||
|
|
||||||
|
return terminateCollectionToArray(length, array)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toArray(): Array<Any?> {
|
||||||
|
checkForComodification()
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return backing.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<Any?>
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@@ -490,30 +494,12 @@ actual class ArrayList<E> private constructor(
|
|||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
return backingArray.subarrayContentHashCode(offset, length)
|
return backing.subarrayContentHashCode(offset, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
return backingArray.subarrayContentToString(offset, length, this)
|
return backing.subarrayContentToString(offset, length, this)
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T> toArray(array: Array<T>): Array<T> {
|
|
||||||
checkForComodification()
|
|
||||||
if (array.size < length) {
|
|
||||||
return backingArray.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
(backingArray as Array<T>).copyInto(array, 0, startIndex = offset, endIndex = offset + length)
|
|
||||||
|
|
||||||
return terminateCollectionToArray(length, array)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toArray(): Array<Any?> {
|
|
||||||
checkForComodification()
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return backingArray.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<Any?>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------- private ----------------------------
|
// ---------------------------- private ----------------------------
|
||||||
@@ -528,54 +514,42 @@ actual class ArrayList<E> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIsMutable() {
|
private fun checkIsMutable() {
|
||||||
if (root.isReadOnly) throw UnsupportedOperationException()
|
if (isReadOnly) throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureExtraCapacity(n: Int) {
|
private val isReadOnly: Boolean
|
||||||
ensureCapacityInternal(length + n)
|
get() = root.isReadOnly
|
||||||
}
|
|
||||||
|
|
||||||
private fun ensureCapacityInternal(minCapacity: Int) {
|
|
||||||
if (minCapacity < 0) throw OutOfMemoryError() // overflow
|
|
||||||
if (minCapacity > backingArray.size) {
|
|
||||||
val newSize = AbstractList.newCapacity(backingArray.size, minCapacity)
|
|
||||||
backingArray = backingArray.copyOfUninitializedElements(newSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun contentEquals(other: List<*>): Boolean {
|
private fun contentEquals(other: List<*>): Boolean {
|
||||||
return backingArray.subarrayContentEquals(offset, length, other)
|
return backing.subarrayContentEquals(offset, length, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addAtInternal(i: Int, element: E) {
|
private fun addAtInternal(i: Int, element: E) {
|
||||||
registerModification()
|
registerModification()
|
||||||
val backingList = backingList
|
if (parent != null) {
|
||||||
if (backingList != null) {
|
parent.addAtInternal(i, element)
|
||||||
backingList.addAtInternal(i, element)
|
|
||||||
} else {
|
} else {
|
||||||
root.addAtInternal(i, element)
|
root.addAtInternal(i, element)
|
||||||
}
|
}
|
||||||
backingArray = root.backingArray
|
backing = root.backing
|
||||||
length++
|
length++
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
|
private fun addAllInternal(i: Int, elements: Collection<E>, n: Int) {
|
||||||
registerModification()
|
registerModification()
|
||||||
val backingList = backingList
|
if (parent != null) {
|
||||||
if (backingList != null) {
|
parent.addAllInternal(i, elements, n)
|
||||||
backingList.addAllInternal(i, elements, n)
|
|
||||||
} else {
|
} else {
|
||||||
root.addAllInternal(i, elements, n)
|
root.addAllInternal(i, elements, n)
|
||||||
}
|
}
|
||||||
backingArray = root.backingArray
|
backing = root.backing
|
||||||
length += n
|
length += n
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAtInternal(i: Int): E {
|
private fun removeAtInternal(i: Int): E {
|
||||||
registerModification()
|
registerModification()
|
||||||
val backingList = backingList
|
val old = if (parent != null) {
|
||||||
val old = if (backingList != null) {
|
parent.removeAtInternal(i)
|
||||||
backingList.removeAtInternal(i)
|
|
||||||
} else {
|
} else {
|
||||||
root.removeAtInternal(i)
|
root.removeAtInternal(i)
|
||||||
}
|
}
|
||||||
@@ -585,9 +559,8 @@ actual class ArrayList<E> private constructor(
|
|||||||
|
|
||||||
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
|
private fun removeRangeInternal(rangeOffset: Int, rangeLength: Int) {
|
||||||
if (rangeLength > 0) registerModification()
|
if (rangeLength > 0) registerModification()
|
||||||
val backingList = backingList
|
if (parent != null) {
|
||||||
if (backingList != null) {
|
parent.removeRangeInternal(rangeOffset, rangeLength)
|
||||||
backingList.removeRangeInternal(rangeOffset, rangeLength)
|
|
||||||
} else {
|
} else {
|
||||||
root.removeRangeInternal(rangeOffset, rangeLength)
|
root.removeRangeInternal(rangeOffset, rangeLength)
|
||||||
}
|
}
|
||||||
@@ -596,10 +569,9 @@ actual class ArrayList<E> private constructor(
|
|||||||
|
|
||||||
/** Retains elements if [retain] == true and removes them it [retain] == false. */
|
/** Retains elements if [retain] == true and removes them it [retain] == false. */
|
||||||
private fun retainOrRemoveAllInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>, retain: Boolean): Int {
|
private fun retainOrRemoveAllInternal(rangeOffset: Int, rangeLength: Int, elements: Collection<E>, retain: Boolean): Int {
|
||||||
val backingList = backingList
|
|
||||||
val removed =
|
val removed =
|
||||||
if (backingList != null) {
|
if (parent != null) {
|
||||||
backingList.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
parent.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
||||||
} else {
|
} else {
|
||||||
root.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
root.retainOrRemoveAllInternal(rangeOffset, rangeLength, elements, retain)
|
||||||
}
|
}
|
||||||
@@ -608,18 +580,12 @@ actual class ArrayList<E> private constructor(
|
|||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Itr<E> : MutableListIterator<E> {
|
private class Itr<E>(
|
||||||
private val list: ArraySubList<E>
|
private val list: ArraySubList<E>,
|
||||||
private var index: Int
|
private var index: Int
|
||||||
private var lastIndex: Int
|
) : MutableListIterator<E> {
|
||||||
private var expectedModCount: Int
|
private var lastIndex = -1
|
||||||
|
private var expectedModCount = list.modCount
|
||||||
constructor(list: ArraySubList<E>, index: Int) {
|
|
||||||
this.list = list
|
|
||||||
this.index = index
|
|
||||||
this.lastIndex = -1
|
|
||||||
this.expectedModCount = list.modCount
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasPrevious(): Boolean = index > 0
|
override fun hasPrevious(): Boolean = index > 0
|
||||||
override fun hasNext(): Boolean = index < list.length
|
override fun hasNext(): Boolean = index < list.length
|
||||||
@@ -631,20 +597,20 @@ actual class ArrayList<E> private constructor(
|
|||||||
checkForComodification()
|
checkForComodification()
|
||||||
if (index <= 0) throw NoSuchElementException()
|
if (index <= 0) throw NoSuchElementException()
|
||||||
lastIndex = --index
|
lastIndex = --index
|
||||||
return list.backingArray[list.offset + lastIndex]
|
return list.backing[list.offset + lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun next(): E {
|
override fun next(): E {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
if (index >= list.length) throw NoSuchElementException()
|
if (index >= list.length) throw NoSuchElementException()
|
||||||
lastIndex = index++
|
lastIndex = index++
|
||||||
return list.backingArray[list.offset + lastIndex]
|
return list.backing[list.offset + lastIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun set(element: E) {
|
override fun set(element: E) {
|
||||||
checkForComodification()
|
checkForComodification()
|
||||||
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
|
check(lastIndex != -1) { "Call next() or previous() before replacing element from the iterator." }
|
||||||
list.set(lastIndex, element)
|
list[lastIndex] = element
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(element: E) {
|
override fun add(element: E) {
|
||||||
@@ -666,7 +632,7 @@ actual class ArrayList<E> private constructor(
|
|||||||
// Must inline for native, suppress warning for WASM
|
// Must inline for native, suppress warning for WASM
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
private inline fun checkForComodification() {
|
private inline fun checkForComodification() {
|
||||||
if (list.modCount != expectedModCount)
|
if (list.root.modCount != expectedModCount)
|
||||||
throw ConcurrentModificationException()
|
throw ConcurrentModificationException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,6 +252,12 @@ class ConcurrentModificationTest {
|
|||||||
action(subList)
|
action(subList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assertFailsWith<ConcurrentModificationException> {
|
||||||
|
buildList<String> {
|
||||||
|
addAll(listOf("a", "b", "c"))
|
||||||
|
for (e in subList(1, 3)) remove(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user