Skip to content

Commit 046b650

Browse files
authored
Merge pull request scala/scala#8983 from mkeskells/2.12.x_Map_Iterator
allocation hotspot in small Map iterators
2 parents 645776b + ac0dda8 commit 046b650

File tree

1 file changed

+57
-5
lines changed
  • library/src/scala/collection/immutable

1 file changed

+57
-5
lines changed

library/src/scala/collection/immutable/Map.scala

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ object Map extends ImmutableMapFactory[Map] {
108108
override def contains(key: Any) = false
109109
def get(key: Any): Option[Nothing] = None
110110
override def getOrElse [V1](key: Any, default: => V1): V1 = default
111-
def iterator: Iterator[(Any, Nothing)] = Iterator.empty
111+
override def iterator: Iterator[(Any, Nothing)] = Iterator.empty
112+
override def keysIterator: Iterator[Any] = Iterator.empty
113+
override def valuesIterator: Iterator[Nothing] = Iterator.empty
112114
override def updated [V1] (key: Any, value: V1): Map[Any, V1] = new Map1(key, value)
113115
def + [V1](kv: (Any, V1)): Map[Any, V1] = updated(kv._1, kv._2)
114116
override def ++[V1 >: Nothing](xs: GenTraversableOnce[(Any, V1)]): Map[Any, V1] = ++[(Any, V1), Map[Any, V1]](xs)(Map.canBuildFrom[Any, V1])
@@ -136,6 +138,24 @@ object Map extends ImmutableMapFactory[Map] {
136138
override def hashCode: Int = MurmurHash3.emptyMapHash
137139
override private[immutable] def foreachEntry[U](f: (Any, Nothing) => U): Unit = ()
138140
}
141+
@SerialVersionUID(3L)
142+
private abstract class MapNIterator[T]() extends AbstractIterator[T] with Serializable {
143+
private[this] var current = 0
144+
def hasNext = current < size
145+
def apply(i: Int): T
146+
def size: Int
147+
def next(): T =
148+
if (hasNext) {
149+
val r = apply(current)
150+
current += 1
151+
r
152+
} else Iterator.empty.next()
153+
154+
override def drop(n: Int): Iterator[T] = {
155+
if (n > 0) current = Math.min(current + n, size)
156+
this
157+
}
158+
}
139159

140160
@SerialVersionUID(-9131943191104946031L)
141161
class Map1[K, +V](key1: K, value1: V) extends AbstractMap[K, V] with Map[K, V] with Serializable with HasForeachEntry[K, V] {
@@ -146,7 +166,9 @@ object Map extends ImmutableMapFactory[Map] {
146166
if (key == key1) Some(value1) else None
147167
override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
148168
if (key == key1) value1 else default
149-
def iterator = Iterator((key1, value1))
169+
override def iterator = Iterator.single((key1, value1))
170+
override def keysIterator: Iterator[K] = Iterator.single(key1)
171+
override def valuesIterator: Iterator[V] = Iterator.single(value1)
150172
override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] =
151173
if (key == key1) new Map1(key1, value)
152174
else new Map2(key1, value1, key, value)
@@ -198,7 +220,17 @@ object Map extends ImmutableMapFactory[Map] {
198220
if (key == key1) value1
199221
else if (key == key2) value2
200222
else default
201-
def iterator = Iterator((key1, value1), (key2, value2))
223+
//we have to insert these additional methods to avoid the compiler rewriting the field names and changing binary format
224+
private def _getKey(i: Int) = i match { case 0 => key1 case 1 => key2}
225+
private def _getValue(i: Int) = i match { case 0 => value1 case 1 => value2}
226+
private abstract class Map2Iterator[T] extends MapNIterator[T]{
227+
final def getKey(i: Int) = _getKey(i)
228+
final def getValue(i: Int) = _getValue(i)
229+
override final def size = 2
230+
}
231+
override def iterator: Iterator[(K,V)] = new Map2Iterator[(K,V)] {def apply(i: Int) = (getKey(i), getValue(i))}
232+
override def keysIterator: Iterator[K] = new Map2Iterator[K] {def apply(i: Int) = getKey(i)}
233+
override def valuesIterator: Iterator[V] = new Map2Iterator[V] {def apply(i: Int) = getValue(i)}
202234
override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] =
203235
if (key == key1) new Map2(key1, value, key2, value2)
204236
else if (key == key2) new Map2(key1, value1, key2, value)
@@ -273,7 +305,17 @@ object Map extends ImmutableMapFactory[Map] {
273305
else if (key == key2) value2
274306
else if (key == key3) value3
275307
else default
276-
def iterator = Iterator((key1, value1), (key2, value2), (key3, value3))
308+
//we have to insert these additional methods to avoid the compiler rewriting the field names and changing binary format
309+
private def _getKey(i: Int) = i match { case 0 => key1 case 1 => key2 case 2 => key3}
310+
private def _getValue(i: Int) = i match { case 0 => value1 case 1 => value2 case 2 => value3}
311+
private abstract class Map3Iterator[T] extends MapNIterator[T]{
312+
final def getKey(i: Int) = _getKey(i)
313+
final def getValue(i: Int) = _getValue(i)
314+
override final def size = 3
315+
}
316+
override def iterator: Iterator[(K,V)] = new Map3Iterator[(K,V)] {def apply(i: Int) = (getKey(i), getValue(i))}
317+
override def keysIterator: Iterator[K] = new Map3Iterator[K] {def apply(i: Int) = getKey(i)}
318+
override def valuesIterator: Iterator[V] = new Map3Iterator[V] {def apply(i: Int) = getValue(i)}
277319
override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] =
278320
if (key == key1) new Map3(key1, value, key2, value2, key3, value3)
279321
else if (key == key2) new Map3(key1, value1, key2, value, key3, value3)
@@ -361,7 +403,17 @@ object Map extends ImmutableMapFactory[Map] {
361403
else if (key == key3) value3
362404
else if (key == key4) value4
363405
else default
364-
def iterator = Iterator((key1, value1), (key2, value2), (key3, value3), (key4, value4))
406+
//we have to insert these additional methods to avoid the compiler rewriting the field names and changing binary format
407+
private def _getKey(i: Int) = i match { case 0 => key1 case 1 => key2 case 2 => key3 case 3 => key4 }
408+
private def _getValue(i: Int) = i match { case 0 => value1 case 1 => value2 case 2 => value3 case 3 => value4}
409+
private abstract class Map4Iterator[T] extends MapNIterator[T]{
410+
final def getKey(i: Int) = _getKey(i)
411+
final def getValue(i: Int) = _getValue(i)
412+
override final def size = 4
413+
}
414+
override def iterator: Iterator[(K,V)] = new Map4Iterator[(K,V)] {def apply(i: Int) = (getKey(i), getValue(i))}
415+
override def keysIterator: Iterator[K] = new Map4Iterator[K] {def apply(i: Int) = getKey(i)}
416+
override def valuesIterator: Iterator[V] = new Map4Iterator[V] {def apply(i: Int) = getValue(i)}
365417
override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] =
366418
if (key == key1) new Map4(key1, value, key2, value2, key3, value3, key4, value4)
367419
else if (key == key2) new Map4(key1, value1, key2, value, key3, value3, key4, value4)

0 commit comments

Comments
 (0)