Skip to content

Commit ec5c519

Browse files
NthPortallrytz
authored andcommitted
Fix concurrent.Map#{filterInPlace,mapValuesInPlace}
Fix the behaviour of `concurrent.Map#filterInPlace` and `concurrent.Map#mapValuesInPlace` to respect atomic entry changes.
1 parent 9a8a375 commit ec5c519

File tree

3 files changed

+33
-12
lines changed

3 files changed

+33
-12
lines changed

library/src/scala/collection/concurrent/Map.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,22 @@ trait Map[K, V] extends scala.collection.mutable.Map[K, V] {
131131
case _ => this.updateWithAux(key)(remappingFunction)
132132
}
133133
}
134+
135+
private[collection] def filterInPlaceImpl(p: (K, V) => Boolean): this.type = {
136+
val it = iterator
137+
while (it.hasNext) {
138+
val (k, v) = it.next()
139+
if (p(k, v)) remove(k, v)
140+
}
141+
this
142+
}
143+
144+
private[collection] def mapValuesInPlaceImpl(f: (K, V) => V): this.type = {
145+
val it = iterator
146+
while (it.hasNext) {
147+
val (k, v) = it.next()
148+
replace(k, v, f(k, v))
149+
}
150+
this
151+
}
134152
}

library/src/scala/collection/concurrent/TrieMap.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen, equiv: E
153153
* KEY_ABSENT - key wasn't there, insert only, do not overwrite
154154
* KEY_PRESENT - key was there, overwrite only, do not insert
155155
* other value `v` - only overwrite if the current value is this
156-
* @param hc the hashcode of `k``
156+
* @param hc the hashcode of `k`
157157
*
158158
* @return null if unsuccessful, Option[V] otherwise (indicating previous value bound to the key)
159159
*/

library/src/scala/collection/mutable/Map.scala

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,17 +171,19 @@ trait MapOps[K, V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]]
171171
* @param p The test predicate
172172
*/
173173
def filterInPlace(p: (K, V) => Boolean): this.type = {
174-
if (nonEmpty) {
175-
val array = this.toArray[Any] // scala/bug#7269 toArray avoids ConcurrentModificationException
176-
val arrayLength = array.length
177-
var i = 0
178-
while (i < arrayLength) {
179-
val (k, v) = array(i).asInstanceOf[(K, V)]
180-
if (!p(k, v)) {
181-
this -= k
174+
if (!isEmpty) this match {
175+
case tm: concurrent.Map[_, _] => tm.asInstanceOf[concurrent.Map[K, V]].filterInPlaceImpl(p)
176+
case _ =>
177+
val array = this.toArray[Any] // scala/bug#7269 toArray avoids ConcurrentModificationException
178+
val arrayLength = array.length
179+
var i = 0
180+
while (i < arrayLength) {
181+
val (k, v) = array(i).asInstanceOf[(K, V)]
182+
if (!p(k, v)) {
183+
this -= k
184+
}
185+
i += 1
182186
}
183-
i += 1
184-
}
185187
}
186188
this
187189
}
@@ -197,8 +199,9 @@ trait MapOps[K, V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]]
197199
* @return the map itself.
198200
*/
199201
def mapValuesInPlace(f: (K, V) => V): this.type = {
200-
if (nonEmpty) this match {
202+
if (!isEmpty) this match {
201203
case hm: mutable.HashMap[_, _] => hm.asInstanceOf[mutable.HashMap[K, V]].mapValuesInPlaceImpl(f)
204+
case tm: concurrent.Map[_, _] => tm.asInstanceOf[concurrent.Map[K, V]].mapValuesInPlaceImpl(f)
202205
case _ =>
203206
val array = this.toArray[Any]
204207
val arrayLength = array.length

0 commit comments

Comments
 (0)