Skip to content

Commit 826cd4b

Browse files
som-snyttlrytz
andcommitted
Map#keys is alias of keySet and may be a view
Co-authored-by: Lukas Rytz <[email protected]>
1 parent df22335 commit 826cd4b

File tree

4 files changed

+51
-32
lines changed

4 files changed

+51
-32
lines changed

library/src/scala/collection/Map.scala

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,16 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
179179

180180
override /*PartialFunction*/ def applyOrElse[K1 <: K, V1 >: V](x: K1, default: K1 => V1): V1 = getOrElse(x, default(x))
181181

182-
/** Collects all keys of this map in a set.
183-
* @return a set containing all keys of this map.
184-
*/
182+
/** A set representing the keys contained by this map.
183+
*
184+
* For efficiency the resulting set may be a view (maintaining a reference to the map and reflecting modifications
185+
* to the map), but it may also be a strict collection without reference to the map.
186+
*
187+
* - To ensure an independent strict collection, use `m.keysIterator.toSet`
188+
* - To obtain a view on the keys, use `scala.collection.View.fromIteratorProvider(m.keysIterator)`
189+
*
190+
* @return a set representing the keys contained by this map
191+
*/
185192
def keySet: Set[K] = new KeySet
186193

187194
/** The implementation class of the set returned by `keySet`.
@@ -199,25 +206,32 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
199206
override def isEmpty: Boolean = MapOps.this.isEmpty
200207
}
201208

202-
/** Collects all keys of this map in an iterable collection.
203-
*
204-
* @return the keys of this map as an iterable.
205-
*/
209+
/** An [[Iterable]] collection of the keys contained by this map.
210+
*
211+
* For efficiency the resulting collection may be a view (maintaining a reference to the map and reflecting
212+
* modifications to the map), but it may also be a strict collection without reference to the map.
213+
*
214+
* - To ensure an independent strict collection, use `m.keysIterator.toSet`
215+
* - To obtain a view on the keys, use `scala.collection.View.fromIteratorProvider(m.keysIterator)`
216+
*
217+
* @return an [[Iterable]] collection of the keys contained by this map
218+
*/
219+
@deprecatedOverriding("This method should be an alias for keySet", since="2.13.13")
206220
def keys: Iterable[K] = keySet
207221

208222
/** Collects all values of this map in an iterable collection.
209-
*
210-
* @return the values of this map as an iterable.
211-
*/
223+
*
224+
* @return the values of this map as an iterable.
225+
*/
212226
def values: Iterable[V] = new AbstractIterable[V] with DefaultSerializable {
213227
override def knownSize: Int = MapOps.this.knownSize
214228
override def iterator: Iterator[V] = valuesIterator
215229
}
216230

217-
/** Creates an iterator for all keys.
218-
*
219-
* @return an iterator over all keys.
220-
*/
231+
/** An [[Iterator]] of the keys contained by this map.
232+
*
233+
* @return an [[Iterator]] of the keys contained by this map
234+
*/
221235
def keysIterator: Iterator[K] = new AbstractIterator[K] {
222236
val iter = MapOps.this.iterator
223237
def hasNext = iter.hasNext

library/src/scala/collection/MapView.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ trait MapView[K, +V]
2727
*
2828
* @return the keys of this map as a view.
2929
*/
30+
@nowarn("msg=overriding method keys")
3031
override def keys: Iterable[K] = new MapView.Keys(this)
3132

3233
// Ideally this returns a `View`, but bincompat

library/src/scala/collection/immutable/ListMap.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ package scala
1414
package collection
1515
package immutable
1616

17-
import scala.annotation.tailrec
17+
import scala.annotation.{nowarn, tailrec}
1818
import scala.collection.mutable.ReusableBuilder
1919
import scala.collection.generic.DefaultSerializable
2020
import scala.runtime.Statics.releaseFence
@@ -70,6 +70,7 @@ sealed class ListMap[K, +V]
7070
res.iterator
7171
}
7272

73+
@nowarn("msg=overriding method keys")
7374
override def keys: Iterable[K] = {
7475
var curr: ListMap[K, V] = this
7576
var res: List[K] = Nil

library/src/scala/collection/immutable/VectorMap.scala

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ package scala
1414
package collection
1515
package immutable
1616

17-
import scala.annotation.tailrec
17+
import scala.annotation.{nowarn, tailrec}
1818

1919
/** This class implements immutable maps using a vector/map-based data structure, which preserves insertion order.
2020
*
@@ -28,8 +28,9 @@ import scala.annotation.tailrec
2828
* @define Coll `immutable.VectorMap`
2929
*/
3030
final class VectorMap[K, +V] private (
31-
private[immutable] val fields: Vector[Any],
32-
private[immutable] val underlying: Map[K, (Int, V)], dropped: Int)
31+
private[immutable] val fields: Vector[Any], // K | Tombstone | Null
32+
private[immutable] val underlying: Map[K, (Int, V)],
33+
dropped: Int)
3334
extends AbstractMap[K, V]
3435
with SeqMap[K, V]
3536
with StrictOptimizedMapOps[K, V, VectorMap, VectorMap[K, V]]
@@ -39,9 +40,7 @@ final class VectorMap[K, +V] private (
3940

4041
override protected[this] def className: String = "VectorMap"
4142

42-
private[immutable] def this(fields: Vector[K], underlying: Map[K, (Int, V)]) = {
43-
this(fields, underlying, 0)
44-
}
43+
private[immutable] def this(fields: Vector[K], underlying: Map[K, (Int, V)]) = this(fields, underlying, 0)
4544

4645
override val size = underlying.size
4746

@@ -73,10 +72,8 @@ final class VectorMap[K, +V] private (
7372
private def nextValidField(slot: Int): (Int, K) = {
7473
if (slot >= fields.size) (-1, null.asInstanceOf[K])
7574
else fields(slot) match {
76-
case Tombstone(distance) =>
77-
nextValidField(slot + distance)
78-
case k =>
79-
(slot, k.asInstanceOf[K])
75+
case Tombstone(distance) => nextValidField(slot + distance)
76+
case k /*: K | Null */ => (slot, k.asInstanceOf[K])
8077
}
8178
}
8279

@@ -106,12 +103,13 @@ final class VectorMap[K, +V] private (
106103

107104
override def hasNext: Boolean = slot < fieldsLength
108105

109-
override def next(): (K, V) = {
110-
if (!hasNext) throw new NoSuchElementException("next called on depleted iterator")
111-
val result = (key, underlying(key)._2)
112-
advance()
113-
result
114-
}
106+
override def next(): (K, V) =
107+
if (!hasNext) Iterator.empty.next()
108+
else {
109+
val result = (key, underlying(key)._2)
110+
advance()
111+
result
112+
}
115113
}
116114

117115
// No-Op overrides to allow for more efficient steppers in a minor release.
@@ -208,6 +206,11 @@ final class VectorMap[K, +V] private (
208206
new VectorMap(fields.dropRight(fields.size - slot), underlying - key, dropped)
209207
}
210208

209+
/** A [[Vector]] of the keys contained by this map.
210+
*
211+
* @return a [[Vector]] of the keys contained by this map.
212+
*/
213+
@nowarn("msg=overriding method keys")
211214
override def keys: Vector[K] = keysIterator.toVector
212215

213216
override def values: Iterable[V] = new Iterable[V] with IterableFactoryDefaults[V, Iterable] {
@@ -251,7 +254,7 @@ private[immutable] final class VectorMapBuilder[K, V] extends mutable.Builder[(K
251254

252255
override def result(): VectorMap[K, V] = {
253256
if (aliased eq null) {
254-
aliased = new VectorMap(vectorBuilder.result(), mapBuilder.result())
257+
aliased = new VectorMap(vectorBuilder.result(), mapBuilder.result())
255258
}
256259
aliased
257260
}

0 commit comments

Comments
 (0)