@@ -14,75 +14,159 @@ package java.util
14
14
15
15
import java .lang .Cloneable
16
16
import java .lang .Utils ._
17
+ import java .util .ScalaOps ._
17
18
18
19
import scala .scalajs ._
20
+ import scala .scalajs .LinkingInfo .isWebAssembly
19
21
20
- class ArrayList [E ] private (private [ ArrayList ] val inner : js. Array [ E ] )
22
+ class ArrayList [E ] private (innerInit : AnyRef , private var _size : Int )
21
23
extends AbstractList [E ] with RandomAccess with Cloneable with Serializable {
22
24
self =>
23
25
26
+ /* This class has two different implementations for handling the
27
+ * internal data storage, depending on whether we are on Wasm or JS.
28
+ * On JS, we utilize `js.Array`. On Wasm, for performance reasons,
29
+ * we avoid JS interop and use a scala.Array.
30
+ * The `_size` field (unused in JS) keeps track of the effective size
31
+ * of the underlying Array for the Wasm implementation.
32
+ */
33
+
34
+ private val innerJS : js.Array [E ] =
35
+ if (isWebAssembly) null
36
+ else innerInit.asInstanceOf [js.Array [E ]]
37
+
38
+ private var innerWasm : Array [AnyRef ] =
39
+ if (! isWebAssembly) null
40
+ else innerInit.asInstanceOf [Array [AnyRef ]]
41
+
24
42
def this (initialCapacity : Int ) = {
25
- this (new js.Array [E ])
26
- if (initialCapacity < 0 )
27
- throw new IllegalArgumentException
43
+ this (
44
+ {
45
+ if (initialCapacity < 0 )
46
+ throw new IllegalArgumentException
47
+ if (isWebAssembly) new Array [Any ](initialCapacity)
48
+ else new js.Array [E ]
49
+ },
50
+ 0
51
+ )
28
52
}
29
53
30
- def this () =
31
- this (new js.Array [E ])
54
+ def this () = this (16 )
32
55
33
56
def this (c : Collection [_ <: E ]) = {
34
- this ()
57
+ this (c.size() )
35
58
addAll(c)
36
59
}
37
60
38
61
def trimToSize (): Unit = {
39
- // We ignore this as js.Array doesn't support explicit pre-allocation
62
+ if (isWebAssembly)
63
+ resizeTo(size())
64
+ // We ignore this in JS as js.Array doesn't support explicit pre-allocation
40
65
}
41
66
42
67
def ensureCapacity (minCapacity : Int ): Unit = {
43
- // We ignore this as js.Array doesn't support explicit pre-allocation
68
+ if (isWebAssembly) {
69
+ if (innerWasm.length < minCapacity) {
70
+ if (minCapacity > 1073741824 ) { // 2^30
71
+ resizeTo(minCapacity)
72
+ } else {
73
+ var powerOf2 : Int = 1
74
+ while (powerOf2 < minCapacity)
75
+ powerOf2 *= 2
76
+ resizeTo(powerOf2)
77
+ }
78
+ }
79
+ }
80
+ // We ignore this in JS as js.Array doesn't support explicit pre-allocation
44
81
}
45
82
46
83
def size (): Int =
47
- inner.length
48
-
49
- override def clone (): AnyRef =
50
- new ArrayList (inner.jsSlice(0 ))
84
+ if (isWebAssembly) _size
85
+ else innerJS.length
86
+
87
+ override def clone (): AnyRef = {
88
+ if (isWebAssembly)
89
+ new ArrayList (innerWasm.clone(), size())
90
+ else
91
+ new ArrayList (innerJS.jsSlice(0 ), 0 )
92
+ }
51
93
52
94
def get (index : Int ): E = {
53
95
checkIndexInBounds(index)
54
- inner(index)
96
+ if (isWebAssembly)
97
+ innerWasm(index).asInstanceOf [E ]
98
+ else
99
+ innerJS(index)
55
100
}
56
101
57
102
override def set (index : Int , element : E ): E = {
58
103
val e = get(index)
59
- inner(index) = element
104
+ if (isWebAssembly)
105
+ innerWasm(index) = element.asInstanceOf [AnyRef ]
106
+ else
107
+ innerJS(index) = element
60
108
e
61
109
}
62
110
63
111
override def add (e : E ): Boolean = {
64
- inner.push(e)
112
+ if (isWebAssembly) {
113
+ if (size() >= innerWasm.length)
114
+ expand()
115
+ innerWasm(size()) = e.asInstanceOf [AnyRef ]
116
+ _size += 1
117
+ } else {
118
+ innerJS.push(e)
119
+ }
65
120
true
66
121
}
67
122
68
123
override def add (index : Int , element : E ): Unit = {
69
124
checkIndexOnBounds(index)
70
- inner.splice(index, 0 , element)
125
+ if (isWebAssembly) {
126
+ if (size() >= innerWasm.length)
127
+ expand()
128
+ System .arraycopy(innerWasm, index, innerWasm, index + 1 , size() - index)
129
+ innerWasm(index) = element.asInstanceOf [AnyRef ]
130
+ _size += 1
131
+ } else {
132
+ innerJS.splice(index, 0 , element)
133
+ }
71
134
}
72
135
73
136
override def remove (index : Int ): E = {
74
137
checkIndexInBounds(index)
75
- arrayRemoveAndGet(inner, index)
138
+ if (isWebAssembly) {
139
+ val removed = innerWasm(index).asInstanceOf [E ]
140
+ System .arraycopy(innerWasm, index + 1 , innerWasm, index, size() - index - 1 )
141
+ innerWasm(size - 1 ) = null
142
+ _size -= 1
143
+ removed
144
+ } else {
145
+ arrayRemoveAndGet(innerJS, index)
146
+ }
76
147
}
77
148
78
149
override def clear (): Unit =
79
- inner.length = 0
150
+ if (isWebAssembly) {
151
+ Arrays .fill(innerWasm, null ) // free references for GC
152
+ _size = 0
153
+ } else {
154
+ innerJS.length = 0
155
+ }
80
156
81
157
override def addAll (index : Int , c : Collection [_ <: E ]): Boolean = {
82
158
c match {
83
159
case other : ArrayList [_] =>
84
160
checkIndexOnBounds(index)
85
- inner.splice(index, 0 , other.inner.toSeq: _* )
161
+ if (isWebAssembly) {
162
+ if (size() + other.size() >= innerWasm.length)
163
+ resizeTo(size() + other.size())
164
+ System .arraycopy(innerWasm, index, innerWasm, index + other.size(), size() - index)
165
+ System .arraycopy(other.innerWasm, 0 , innerWasm, index, other.size())
166
+ _size += c.size()
167
+ } else {
168
+ innerJS.splice(index, 0 , other.innerJS.toSeq: _* )
169
+ }
86
170
other.size() > 0
87
171
case _ => super .addAll(index, c)
88
172
}
@@ -91,6 +175,25 @@ class ArrayList[E] private (private[ArrayList] val inner: js.Array[E])
91
175
override protected def removeRange (fromIndex : Int , toIndex : Int ): Unit = {
92
176
if (fromIndex < 0 || toIndex > size() || toIndex < fromIndex)
93
177
throw new IndexOutOfBoundsException ()
94
- inner.splice(fromIndex, toIndex - fromIndex)
178
+ if (isWebAssembly) {
179
+ if (fromIndex != toIndex) {
180
+ System .arraycopy(innerWasm, toIndex, innerWasm, fromIndex, size() - toIndex)
181
+ val newSize = size() - toIndex + fromIndex
182
+ Arrays .fill(innerWasm, newSize, size(), null ) // free references for GC
183
+ _size = newSize
184
+ }
185
+ } else {
186
+ innerJS.splice(fromIndex, toIndex - fromIndex)
187
+ }
188
+ }
189
+
190
+ // Wasm only
191
+ private def expand (): Unit = {
192
+ resizeTo(Math .max(innerWasm.length * 2 , 16 ))
193
+ }
194
+
195
+ // Wasm only
196
+ private def resizeTo (newCapacity : Int ): Unit = {
197
+ innerWasm = Arrays .copyOf(innerWasm, newCapacity)
95
198
}
96
199
}
0 commit comments