package kotlinx.coroutines.internal /** * Analogue of java.util.concurrent.CopyOnWriteArrayList for JS. * Even though JS has no real concurrency, [CopyOnWriteList] is essential to manage any kinds * of callbacks or continuations. * * Implementation note: most of the methods fallbacks to [AbstractMutableList] (thus inefficient for CoW pattern) * and some methods are unsupported, because currently they are not required for this class consumers. */ internal class CopyOnWriteList(private var array: Array = emptyArray()) : AbstractMutableList() { override val size: Int get() = array.size override fun add(element: E): Boolean { val copy = array.asDynamic().slice() copy.push(element) array = copy as Array return true } override fun add(index: Int, element: E) { val copy = array.asDynamic().slice() copy.splice(insertionRangeCheck(index), 0, element) array = copy as Array } override fun remove(element: E): Boolean { for (index in array.indices) { if (array[index] == element) { val copy = array.asDynamic().slice() copy.splice(index, 1) array = copy as Array return true } } return false } override fun removeAt(index: Int): E { rangeCheck(index) val copy = array.asDynamic().slice() val result = if (index == lastIndex) { copy.pop() } else { copy.splice(index, 1)[0] } array = copy as Array return result as E } override fun iterator(): MutableIterator = IteratorImpl(array) override fun listIterator(): MutableListIterator = throw UnsupportedOperationException("Operation is not supported") override fun listIterator(index: Int): MutableListIterator = throw UnsupportedOperationException("Operation is not supported") override fun isEmpty(): Boolean = size == 0 override fun set(index: Int, element: E): E = throw UnsupportedOperationException("Operation is not supported") override fun get(index: Int): E = array[rangeCheck(index)] private class IteratorImpl(private var array: Array) : MutableIterator { private var current = 0 override fun hasNext(): Boolean = current != array.size override fun next(): E { if (!hasNext()) { throw NoSuchElementException() } return array[current++] } override fun remove() = throw UnsupportedOperationException("Operation is not supported") } private fun insertionRangeCheck(index: Int) { if (index < 0 || index > size) { throw IndexOutOfBoundsException("index: $index, size: $size") } } private fun rangeCheck(index: Int) = index.apply { if (index < 0 || index >= size) { throw IndexOutOfBoundsException("index: $index, size: $size") } } }