-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
203 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
/* | ||
* Scala (https://www.scala-lang.org) | ||
* | ||
* Copyright EPFL and Lightbend, Inc. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (http://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package scala.collection | ||
|
||
import scala.annotation.nowarn | ||
import scala.collection.MapView.SomeMapOps | ||
import scala.collection.mutable.Builder | ||
import language.experimental.captureChecking | ||
import caps.unsafe.unsafeAssumePure | ||
|
||
trait MapView[K, +V] | ||
extends MapOps[K, V, ({ type l[X, Y] = View[(X, Y)] })#l, View[(K, V)]] | ||
with View[(K, V)] { | ||
this: MapView[K, V]^ => | ||
|
||
override def view: MapView[K, V]^{this} = this | ||
|
||
// Ideally this returns a `View`, but bincompat | ||
/** Creates a view over all keys of this map. | ||
* | ||
* @return the keys of this map as a view. | ||
*/ | ||
override def keys: Iterable[K]^{this} = new MapView.Keys(this) | ||
|
||
// Ideally this returns a `View`, but bincompat | ||
/** Creates a view over all values of this map. | ||
* | ||
* @return the values of this map as a view. | ||
*/ | ||
override def values: Iterable[V]^{this} = new MapView.Values(this) | ||
|
||
/** Filters this map by retaining only keys satisfying a predicate. | ||
* @param p the predicate used to test keys | ||
* @return an immutable map consisting only of those key value pairs of this map where the key satisfies | ||
* the predicate `p`. The resulting map wraps the original map without copying any elements. | ||
*/ | ||
override def filterKeys(p: K => Boolean): MapView[K, V]^{this, p} = new MapView.FilterKeys(this, p) | ||
|
||
/** Transforms this map by applying a function to every retrieved value. | ||
* @param f the function used to transform values of this map. | ||
* @return a map view which maps every key of this map | ||
* to `f(this(key))`. The resulting map wraps the original map without copying any elements. | ||
*/ | ||
override def mapValues[W](f: V => W): MapView[K, W]^{this, f} = new MapView.MapValues(this, f) | ||
|
||
override def filter(pred: ((K, V)) => Boolean): MapView[K, V]^{this, pred} = new MapView.Filter(this, false, pred) | ||
|
||
override def filterNot(pred: ((K, V)) => Boolean): MapView[K, V]^{this, pred} = new MapView.Filter(this, true, pred) | ||
|
||
override def partition(p: ((K, V)) => Boolean): (MapView[K, V]^{this, p}, MapView[K, V]^{this, p}) = (filter(p), filterNot(p)) | ||
|
||
override def tapEach[U](f: ((K, V)) => U): MapView[K, V]^{this, f} = new MapView.TapEach(this, f) | ||
|
||
def mapFactory: MapViewFactory = MapView | ||
|
||
override def empty: MapView[K, V] = mapFactory.empty | ||
|
||
override def withFilter(p: ((K, V)) => Boolean): MapOps.WithFilter[K, V, View, ({ type l[X, Y] = View[(X, Y)] })#l]^{this, p} = new MapOps.WithFilter(this, p) | ||
|
||
override def toString: String = super[View].toString | ||
|
||
@nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") | ||
override protected[this] def stringPrefix: String = "MapView" | ||
} | ||
|
||
object MapView extends MapViewFactory { | ||
|
||
/** An `IterableOps` whose collection type and collection type constructor are unknown */ | ||
type SomeIterableConstr[X, Y] = IterableOps[_, AnyConstr, _] | ||
/** A `MapOps` whose collection type and collection type constructor are (mostly) unknown */ | ||
type SomeMapOps[K, +V] = MapOps[K, V, SomeIterableConstr, _] | ||
|
||
@SerialVersionUID(3L) | ||
object EmptyMapView extends AbstractMapView[Any, Nothing] { | ||
// !!! cc problem: crash when we replace the line with | ||
// private val EmptyMapView: MapView[Any, Nothing] = new AbstractMapView[Any, Nothing] { | ||
override def get(key: Any): Option[Nothing] = None | ||
override def iterator: Iterator[Nothing] = Iterator.empty[Nothing] | ||
override def knownSize: Int = 0 | ||
override def isEmpty: Boolean = true | ||
override def filterKeys(p: Any => Boolean): MapView[Any, Nothing] = this | ||
override def mapValues[W](f: Nothing => W): MapView[Any, Nothing] = this | ||
override def filter(pred: ((Any, Nothing)) => Boolean): MapView[Any, Nothing] = this | ||
override def filterNot(pred: ((Any, Nothing)) => Boolean): MapView[Any, Nothing] = this | ||
override def partition(p: ((Any, Nothing)) => Boolean): (MapView[Any, Nothing], MapView[Any, Nothing]) = (this, this) | ||
} | ||
|
||
@SerialVersionUID(3L) | ||
class Id[K, +V](underlying: SomeMapOps[K, V]^) extends AbstractMapView[K, V] { | ||
def get(key: K): Option[V] = underlying.get(key) | ||
def iterator: Iterator[(K, V)]^{this} = underlying.iterator | ||
override def knownSize: Int = underlying.knownSize | ||
override def isEmpty: Boolean = underlying.isEmpty | ||
} | ||
|
||
// Ideally this is public, but bincompat | ||
@SerialVersionUID(3L) | ||
private class Keys[K](underlying: SomeMapOps[K, _]^) extends AbstractView[K] { | ||
def iterator: Iterator[K]^{this} = underlying.keysIterator | ||
override def knownSize: Int = underlying.knownSize | ||
override def isEmpty: Boolean = underlying.isEmpty | ||
} | ||
|
||
// Ideally this is public, but bincompat | ||
@SerialVersionUID(3L) | ||
private class Values[+V](underlying: SomeMapOps[_, V]^) extends AbstractView[V] { | ||
def iterator: Iterator[V]^{this} = underlying.valuesIterator | ||
override def knownSize: Int = underlying.knownSize | ||
override def isEmpty: Boolean = underlying.isEmpty | ||
} | ||
|
||
@SerialVersionUID(3L) | ||
class MapValues[K, +V, +W](underlying: SomeMapOps[K, V]^, f: V => W) extends AbstractMapView[K, W] { | ||
def iterator: Iterator[(K, W)]^{this} = underlying.iterator.map(kv => (kv._1, f(kv._2))) | ||
def get(key: K): Option[W] = underlying.get(key).map(f) | ||
override def knownSize: Int = underlying.knownSize | ||
override def isEmpty: Boolean = underlying.isEmpty | ||
} | ||
|
||
@SerialVersionUID(3L) | ||
class FilterKeys[K, +V](underlying: SomeMapOps[K, V]^, p: K => Boolean) extends AbstractMapView[K, V] { | ||
def iterator: Iterator[(K, V)]^{this} = underlying.iterator.filter { case (k, _) => p(k) } | ||
def get(key: K): Option[V] = if (p(key)) underlying.get(key) else None | ||
override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize | ||
override def isEmpty: Boolean = iterator.isEmpty | ||
} | ||
|
||
@SerialVersionUID(3L) | ||
class Filter[K, +V](underlying: SomeMapOps[K, V]^, isFlipped: Boolean, p: ((K, V)) => Boolean) extends AbstractMapView[K, V] { | ||
def iterator: Iterator[(K, V)]^{this} = underlying.iterator.filterImpl(p, isFlipped) | ||
def get(key: K): Option[V] = underlying.get(key) match { | ||
case s @ Some(v) if p((key, v)) != isFlipped => s | ||
case _ => None | ||
} | ||
override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize | ||
override def isEmpty: Boolean = iterator.isEmpty | ||
} | ||
|
||
@SerialVersionUID(3L) | ||
class TapEach[K, +V, +U](underlying: SomeMapOps[K, V]^, f: ((K, V)) => U) extends AbstractMapView[K, V] { | ||
override def get(key: K): Option[V] = { | ||
underlying.get(key) match { | ||
case s @ Some(v) => | ||
f((key, v)) | ||
s | ||
case None => None | ||
} | ||
} | ||
override def iterator: Iterator[(K, V)]^{this} = underlying.iterator.tapEach(f) | ||
override def knownSize: Int = underlying.knownSize | ||
override def isEmpty: Boolean = underlying.isEmpty | ||
} | ||
|
||
override def newBuilder[sealed X, sealed Y]: Builder[(X, Y), MapView[X, Y]] = mutable.HashMap.newBuilder[X, Y].mapResult(_.view) | ||
|
||
override def empty[K, V]: MapView[K, V] = EmptyMapView.asInstanceOf[MapView[K, V]] | ||
|
||
override def from[K, V](it: IterableOnce[(K, V)]^): View[(K, V)] = | ||
View.from(it).unsafeAssumePure | ||
// unsafeAssumePure needed here since MapViewFactory inherits from MapFactory, | ||
// and the latter assumes maps are strict, so from's result captures nothing. | ||
|
||
override def from[K, V](it: SomeMapOps[K, V]^): MapView[K, V]^{it} = it match { | ||
case mv: MapView[K, V] => mv | ||
case other => new MapView.Id(other) | ||
} | ||
|
||
override def apply[K, V](elems: (K, V)*): MapView[K, V] = from(elems.toMap) | ||
} | ||
|
||
trait MapViewFactory extends collection.MapFactory[({ type l[X, Y] = View[(X, Y)]})#l] { | ||
|
||
def newBuilder[X, Y]: Builder[(X, Y), MapView[X, Y]] | ||
|
||
def empty[X, Y]: MapView[X, Y] | ||
|
||
def from[K, V](it: SomeMapOps[K, V]^): MapView[K, V]^{it} | ||
|
||
override def apply[K, V](elems: (K, V)*): MapView[K, V] = from(elems.toMap) | ||
} | ||
|
||
/** Explicit instantiation of the `MapView` trait to reduce class file size in subclasses. */ | ||
@SerialVersionUID(3L) | ||
abstract class AbstractMapView[K, +V] extends AbstractView[(K, V)] with MapView[K, V]: | ||
this: AbstractMapView[K, V]^ => | ||
|