blob: c52ce7f7ad0df982a93e9eac4a0afee51a712c6a [file] [log] [blame]
Vsevolod Tolstopyatov167ca632018-06-29 11:49:00 +03001/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03002 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Vsevolod Tolstopyatov167ca632018-06-29 11:49:00 +03003 */
4
5package kotlinx.coroutines.experimental.internal
6
7/**
8 * Analogue of java.util.concurrent.CopyOnWriteArrayList for JS.
9 * Even though JS has no real concurrency, [CopyOnWriteList] is essential to manage any kinds
10 * of callbacks or continuations.
11 *
12 * Implementation note: most of the methods fallbacks to [AbstractMutableList] (thus inefficient for CoW pattern)
13 * and some methods are unsupported, because currently they are not required for this class consumers.
14 */
15internal class CopyOnWriteList<E>(private var array: Array<E> = emptyArray()) : AbstractMutableList<E>() {
16
17 override val size: Int get() = array.size
18
19 override fun add(element: E): Boolean {
20 val copy = array.asDynamic().slice()
21 copy.push(element)
22 array = copy as Array<E>
23 return true
24 }
25
26 override fun add(index: Int, element: E) {
27 val copy = array.asDynamic().slice()
28 copy.splice(insertionRangeCheck(index), 0, element)
29 array = copy as Array<E>
30 }
31
32 override fun remove(element: E): Boolean {
33 for (index in array.indices) {
34 if (array[index] == element) {
35 val copy = array.asDynamic().slice()
36 copy.splice(index, 1)
37 array = copy as Array<E>
38 return true
39 }
40 }
41
42 return false
43 }
44
45 override fun removeAt(index: Int): E {
46 modCount++
47 val copy = array.asDynamic().slice()
48 val result = if (index == lastIndex) {
49 copy.pop()
50 } else {
51 copy.splice(index, 1)[0]
52 }
53
54 array = copy as Array<E>
55 return result as E
56 }
57
58 override fun iterator(): MutableIterator<E> = IteratorImpl(array)
59
60 override fun listIterator(): MutableListIterator<E> = throw UnsupportedOperationException("Operation is not supported")
61
62 override fun listIterator(index: Int): MutableListIterator<E> = throw UnsupportedOperationException("Operation is not supported")
63
64 override fun isEmpty(): Boolean = size == 0
65
66 override fun set(index: Int, element: E): E = throw UnsupportedOperationException("Operation is not supported")
67
68 override fun get(index: Int): E = array[rangeCheck(index)]
69
70 private class IteratorImpl<E>(private var array: Array<E>) : MutableIterator<E> {
71
72 private var current = 0
73
74 override fun hasNext(): Boolean = current != array.size
75
76 override fun next(): E {
77 if (!hasNext()) {
78 throw NoSuchElementException()
79 }
80
81 return array[current++]
82 }
83
84 override fun remove() = throw UnsupportedOperationException("Operation is not supported")
85 }
86
87 private fun insertionRangeCheck(index: Int) {
88 if (index < 0 || index > size) {
89 throw IndexOutOfBoundsException("index: $index, size: $size")
90 }
91 }
92
93 private fun rangeCheck(index: Int) = index.apply {
94 if (index < 0 || index >= size) {
95 throw IndexOutOfBoundsException("index: $index, size: $size")
96 }
97 }
98}