@@ -14,12 +14,10 @@ package scala
14
14
package collection
15
15
package immutable
16
16
17
- import java .io .{ObjectInputStream , ObjectOutputStream }
18
-
19
- import collection .{Iterator , MapFactory }
20
17
import scala .annotation .tailrec
21
18
22
- import scala .collection .mutable .{Builder , ImmutableBuilder }
19
+ import scala .collection .mutable .Builder
20
+ import scala .runtime .Statics .releaseFence
23
21
24
22
/**
25
23
* This class implements immutable maps using a list-based data structure. List map iterators and
@@ -60,7 +58,7 @@ sealed class ListMap[K, +V]
60
58
override def knownSize : Int = 0
61
59
def get (key : K ): Option [V ] = None
62
60
63
- def updated [B1 >: V ](key : K , value : B1 ): ListMap [K , B1 ] = new Node [B1 ](key, value)
61
+ def updated [V1 >: V ](key : K , value : V1 ): ListMap [K , V1 ] = new ListMap . Node [K , V1 ](key, value, this )
64
62
65
63
def removed (key : K ): ListMap [K , V ] = this
66
64
@@ -84,82 +82,90 @@ sealed class ListMap[K, +V]
84
82
res
85
83
}
86
84
87
- protected def key : K = throw new NoSuchElementException (" key of empty map" )
88
- protected def value : V = throw new NoSuchElementException (" value of empty map" )
89
- protected def next : ListMap [K , V ] = throw new NoSuchElementException (" next of empty map" )
85
+ private [immutable] def key : K = throw new NoSuchElementException (" key of empty map" )
86
+ private [immutable] def value : V = throw new NoSuchElementException (" value of empty map" )
87
+ private [immutable] def next : ListMap [K , V ] = throw new NoSuchElementException (" next of empty map" )
90
88
91
89
override protected [this ] def className = " ListMap"
92
90
91
+ }
92
+
93
+ /**
94
+ * $factoryInfo
95
+ *
96
+ * Note that each element insertion takes O(n) time, which means that creating a list map with
97
+ * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of
98
+ * elements.
99
+ *
100
+ * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list-maps "Scala's Collection Library overview" ]]
101
+ * section on `List Maps` for more information.
102
+ * @since 1
103
+ * @define Coll ListMap
104
+ * @define coll list map
105
+ */
106
+ @ SerialVersionUID (3L )
107
+ object ListMap extends MapFactory [ListMap ] {
93
108
/**
94
109
* Represents an entry in the `ListMap`.
95
110
*/
96
- protected class Node [V1 >: V ](override protected val key : K ,
97
- override protected val value : V1 ) extends ListMap [K , V1 ] {
111
+ private [immutable] class Node [K , V ](
112
+ override private [immutable] val key : K ,
113
+ override private [immutable] val value : V ,
114
+ private [immutable] var _init : ListMap [K , V ]
115
+ ) extends ListMap [K , V ] {
116
+
117
+ releaseFence()
98
118
99
119
override def size : Int = sizeInternal(this , 0 )
100
120
101
- @ tailrec private [this ] def sizeInternal (cur : ListMap [K , V1 ], acc : Int ): Int =
121
+ @ tailrec private [this ] def sizeInternal (cur : ListMap [K , V ], acc : Int ): Int =
102
122
if (cur.isEmpty) acc
103
123
else sizeInternal(cur.next, acc + 1 )
104
124
105
125
override def isEmpty : Boolean = false
126
+
106
127
override def knownSize : Int = - 1
128
+
107
129
@ throws[NoSuchElementException ]
108
- override def apply (k : K ): V1 = applyInternal(this , k)
130
+ override def apply (k : K ): V = applyInternal(this , k)
109
131
110
- @ tailrec private [this ] def applyInternal (cur : ListMap [K , V1 ], k : K ): V1 =
132
+ @ tailrec private [this ] def applyInternal (cur : ListMap [K , V ], k : K ): V =
111
133
if (cur.isEmpty) throw new NoSuchElementException (" key not found: " + k)
112
134
else if (k == cur.key) cur.value
113
135
else applyInternal(cur.next, k)
114
136
115
- override def get (k : K ): Option [V1 ] = getInternal(this , k)
137
+ override def get (k : K ): Option [V ] = getInternal(this , k)
116
138
117
- @ tailrec private [this ] def getInternal (cur : ListMap [K , V1 ], k : K ): Option [V1 ] =
139
+ @ tailrec private [this ] def getInternal (cur : ListMap [K , V ], k : K ): Option [V ] =
118
140
if (cur.isEmpty) None
119
141
else if (k == cur.key) Some (cur.value)
120
142
else getInternal(cur.next, k)
121
143
122
144
override def contains (k : K ): Boolean = containsInternal(this , k)
123
145
124
- @ tailrec private [this ] def containsInternal (cur : ListMap [K , V1 ], k : K ): Boolean =
125
- if (cur.isEmpty) false
146
+ @ tailrec private [this ] def containsInternal (cur : ListMap [K , V ], k : K ): Boolean =
147
+ if (cur.isEmpty) false
126
148
else if (k == cur.key) true
127
149
else containsInternal(cur.next, k)
128
150
129
- override def updated [V2 >: V1 ](k : K , v : V2 ): ListMap [K , V2 ] = {
151
+ override def updated [V1 >: V ](k : K , v : V1 ): ListMap [K , V1 ] = {
130
152
val (m, k0) = removeInternal(k, this , Nil )
131
- new m. Node [ V2 ] (k0, v)
153
+ new Node (k0, v, m )
132
154
}
133
155
134
- override def removed (k : K ): ListMap [K , V1 ] = removeInternal(k, this , Nil )._1
135
-
136
- @ tailrec private [this ] def removeInternal (k : K , cur : ListMap [K , V1 ], acc : List [ListMap [K , V1 ]]): (ListMap [K , V1 ], K ) =
156
+ @ tailrec private [this ] def removeInternal (k : K , cur : ListMap [K , V ], acc : List [ListMap [K , V ]]): (ListMap [K , V ], K ) =
137
157
if (cur.isEmpty) (acc.last, k)
138
- else if (k == cur.key) (acc.foldLeft(cur.next) { (t, h) => new t. Node (h.key, h.value) }, cur.key)
158
+ else if (k == cur.key) (acc.foldLeft(cur.next) { (t, h) => new Node (h.key, h.value, t ) }, cur.key)
139
159
else removeInternal(k, cur.next, cur :: acc)
140
160
141
- override protected def next : ListMap [K , V1 ] = ListMap . this
161
+ override def removed ( k : K ) : ListMap [K , V ] = removeInternal(k, this , Nil )._1
142
162
143
- override def last : (K , V1 ) = (key, value)
144
- override def init : ListMap [K , V1 ] = next
145
- }
146
- }
163
+ override private [immutable] def next : ListMap [K , V ] = _init
147
164
148
- /**
149
- * $factoryInfo
150
- *
151
- * Note that each element insertion takes O(n) time, which means that creating a list map with
152
- * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of
153
- * elements.
154
- *
155
- * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list-maps "Scala's Collection Library overview" ]]
156
- * section on `List Maps` for more information.
157
- * @since 1
158
- * @define Coll ListMap
159
- * @define coll list map
160
- */
161
- @ SerialVersionUID (3L )
162
- object ListMap extends MapFactory [ListMap ] {
165
+ override def last : (K , V ) = (key, value)
166
+ override def init : ListMap [K , V ] = next
167
+
168
+ }
163
169
164
170
def empty [K , V ]: ListMap [K , V ] = EmptyListMap .asInstanceOf [ListMap [K , V ]]
165
171
@@ -171,8 +177,54 @@ object ListMap extends MapFactory[ListMap] {
171
177
case _ => (newBuilder[K , V ] ++= it).result()
172
178
}
173
179
174
- def newBuilder [K , V ]: Builder [(K , V ), ListMap [K , V ]] =
175
- new ImmutableBuilder [(K , V ), ListMap [K , V ]](empty) {
176
- def addOne (elem : (K , V )): this .type = { elems = elems + elem; this }
180
+ /** Returns a new ListMap builder
181
+ *
182
+ * The implementation safely handles additions after `result()` without calling `clear()`
183
+ *
184
+ * @tparam K the map key type
185
+ * @tparam V the map value type
186
+ */
187
+ def newBuilder [K , V ]: Builder [(K , V ), ListMap [K , V ]] = new ListMapBuilder [K , V ]
188
+ }
189
+
190
+ private [immutable] final class ListMapBuilder [K , V ] extends mutable.Builder [(K , V ), ListMap [K , V ]] {
191
+ private [this ] var isAliased : Boolean = false
192
+ private [this ] var underlying : ListMap [K , V ] = ListMap .empty
193
+
194
+ override def clear (): Unit = {
195
+ underlying = ListMap .empty
196
+ isAliased = false
197
+ }
198
+
199
+ override def result (): ListMap [K , V ] = {
200
+ isAliased = true
201
+ releaseFence()
202
+ underlying
203
+ }
204
+
205
+ override def addOne (elem : (K , V )): this .type = addOne(elem._1, elem._2)
206
+
207
+ def addOne (key : K , value : V ): this .type = {
208
+ if (isAliased) {
209
+ underlying = underlying.updated(key, value)
210
+ } else {
211
+ var prev : ListMap .Node [K , V ] = null
212
+ var curr = underlying
213
+ while (curr.nonEmpty) {
214
+ if (key == curr.key) {
215
+ if (prev eq null ) {
216
+ underlying = underlying.next
217
+ } else {
218
+ prev._init = curr.init
219
+ }
220
+ underlying = new ListMap .Node (curr.key, value, underlying)
221
+ return this
222
+ }
223
+ prev = curr.asInstanceOf [ListMap .Node [K , V ]]
224
+ curr = curr.next
225
+ }
226
+ underlying = new ListMap .Node (key, value, underlying)
177
227
}
228
+ this
229
+ }
178
230
}
0 commit comments