@@ -127,7 +127,21 @@ transparent trait StrictMapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _]
127127 mapFactory.from(new View .Concat (thatIterable, this ))
128128 }
129129
130+ // The original keySet implementation, with a lazy iterator over the keys,
131+ // is only correct if we have a strict Map.
132+ // We restore it here.
133+ override def keySet : Set [K ] = new LazyKeySet
130134
135+ /** The implementation class of the set returned by `keySet`, for pure maps.
136+ */
137+ private class LazyKeySet extends AbstractSet [K ] with DefaultSerializable {
138+ def diff (that : Set [K ]): Set [K ] = LazyKeySet .this .fromSpecific(this .view.filterNot(that))
139+ def iterator : Iterator [K ] = StrictMapOps .this .keysIterator
140+ def contains (key : K ): Boolean = StrictMapOps .this .contains(key)
141+ override def size : Int = StrictMapOps .this .size
142+ override def knownSize : Int = StrictMapOps .this .knownSize
143+ override def isEmpty : Boolean = StrictMapOps .this .isEmpty
144+ }
131145}
132146
133147/** Base Map implementation type
@@ -239,19 +253,24 @@ transparent trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
239253 /** The implementation class of the set returned by `keySet`.
240254 */
241255 protected class KeySet extends AbstractSet [K ] with GenKeySet with DefaultSerializable {
242- def diff (that : Set [K ]): Set [K ] = fromSpecific(this .view.filterNot(that))
256+ // If you need a generic, capturing KeySet, create a View from keysIterator
257+ def diff (that : Set [K ]): Set [K ] = fromSpecific(allKeys.filterNot(that))
243258 }
244259
245- /** A generic trait that is reused by keyset implementations */
260+ /** A generic trait that is reused by keyset implementations.
261+ * Note that this version of KeySet copies all the keys into an interval val.
262+ * See [[StrictMapOps.LazyKeySet ]] for a version that lazily captures the map.
263+ */
246264 protected trait GenKeySet { this : Set [K ] =>
265+ // CC note: this is unavoidable to make the KeySet pure.
266+ private [MapOps ] val allKeys = MapOps .this .keysIterator.toSet
267+ // We restore the lazy behavior in StrictMapOps
247268 def iterator : Iterator [K ] =
248- // CC note: this is unavoidable to make the KeySet pure.
249- // If you need a generic, capturing KeySet, create a View from keysIterator
250- MapOps .this .keysIterator.toSet.iterator
251- def contains (key : K ): Boolean = MapOps .this .contains(key)
252- override def size : Int = MapOps .this .size
253- override def knownSize : Int = MapOps .this .knownSize
254- override def isEmpty : Boolean = MapOps .this .isEmpty
269+ allKeys.iterator
270+ def contains (key : K ): Boolean = allKeys.contains(key)
271+ override def size : Int = allKeys.size
272+ override def knownSize : Int = allKeys.knownSize
273+ override def isEmpty : Boolean = allKeys.isEmpty
255274 }
256275
257276 /** An [[Iterable ]] collection of the keys contained by this map.
0 commit comments