Adding the missing ParMap and GenMap methods.
No review. git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25382 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
parent
6e8c8703a7
commit
467840cb80
|
@ -23,6 +23,8 @@ extends GenMapLike[A, B, GenMap[A, B]]
|
|||
with GenIterable[(A, B)]
|
||||
{
|
||||
def seq: Map[A, B]
|
||||
|
||||
def updated [B1 >: B](key: A, value: B1): GenMap[A, B1]
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,10 +29,78 @@ trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals
|
|||
def +[B1 >: B](kv: (A, B1)): GenMap[A, B1]
|
||||
def - (key: A): Repr
|
||||
|
||||
|
||||
// This hash code must be symmetric in the contents but ought not
|
||||
// collide trivially.
|
||||
override def hashCode() = util.MurmurHash.symmetricHash(seq, Map.hashSeed)
|
||||
|
||||
/** Returns the value associated with a key, or a default value if the key is not contained in the map.
|
||||
* @param key the key.
|
||||
* @param default a computation that yields a default value in case no binding for `key` is
|
||||
* found in the map.
|
||||
* @tparam B1 the result type of the default computation.
|
||||
* @return the value associated with `key` if it exists,
|
||||
* otherwise the result of the `default` computation.
|
||||
* @usecase def getOrElse(key: A, default: => B): B
|
||||
*/
|
||||
def getOrElse[B1 >: B](key: A, default: => B1): B1
|
||||
|
||||
/** Tests whether this map contains a binding for a key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return `true` if there is a binding for `key` in this map, `false` otherwise.
|
||||
*/
|
||||
def contains(key: A): Boolean
|
||||
|
||||
/** Tests whether this map contains a binding for a key. This method,
|
||||
* which implements an abstract method of trait `PartialFunction`,
|
||||
* is equivalent to `contains`.
|
||||
*
|
||||
* @param key the key
|
||||
* @return `true` if there is a binding for `key` in this map, `false` otherwise.
|
||||
*/
|
||||
def isDefinedAt(key: A): Boolean
|
||||
|
||||
def keySet: GenSet[A]
|
||||
|
||||
/** Collects all keys of this map in an iterable collection.
|
||||
*
|
||||
* @return the keys of this map as an iterable.
|
||||
*/
|
||||
def keys: GenIterable[A]
|
||||
|
||||
/** Collects all values of this map in an iterable collection.
|
||||
*
|
||||
* @return the values of this map as an iterable.
|
||||
*/
|
||||
def values: GenIterable[B]
|
||||
|
||||
/** Creates an iterator for all keys.
|
||||
*
|
||||
* @return an iterator over all keys.
|
||||
*/
|
||||
def keysIterator: Iterator[A]
|
||||
|
||||
/** Creates an iterator for all values in this map.
|
||||
*
|
||||
* @return an iterator over all values that are associated with some key in this map.
|
||||
*/
|
||||
def valuesIterator: Iterator[B]
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
def filterKeys(p: A => Boolean): GenMap[A, B]
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
def mapValues[C](f: B => C): GenMap[A, C]
|
||||
|
||||
/** Compares two maps structurally; i.e. checks if all mappings
|
||||
* contained in this map are also contained in the other map,
|
||||
* and vice versa.
|
||||
|
|
|
@ -50,6 +50,10 @@ self =>
|
|||
def empty: ParMap[K, V] = new mutable.ParHashMap[K, V]
|
||||
|
||||
override def stringPrefix = "ParMap"
|
||||
|
||||
override def updated [U >: V](key: K, value: U): ParMap[K, U] = this + ((key, value))
|
||||
|
||||
def + [U >: V](kv: (K, U)): ParMap[K, U]
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,6 +65,15 @@ object ParMap extends ParMapFactory[ParMap] {
|
|||
|
||||
implicit def canBuildFrom[K, V]: CanCombineFrom[Coll, (K, V), ParMap[K, V]] = new CanCombineFromMap[K, V]
|
||||
|
||||
/** An abstract shell used by { mutable, immutable }.Map but not by collection.Map
|
||||
* because of variance issues.
|
||||
*/
|
||||
abstract class WithDefault[A, +B](underlying: ParMap[A, B], d: A => B) extends ParMap[A, B] {
|
||||
override def size = underlying.size
|
||||
def get(key: A) = underlying.get(key)
|
||||
def splitter = underlying.splitter
|
||||
override def default(key: A): B = d(key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@ import scala.collection.MapLike
|
|||
import scala.collection.GenMapLike
|
||||
import scala.collection.Map
|
||||
import scala.collection.mutable.Builder
|
||||
|
||||
|
||||
|
||||
import annotation.unchecked.uncheckedVariance
|
||||
import scala.collection.generic.IdleSignalling
|
||||
import scala.collection.generic.Signalling
|
||||
|
||||
|
||||
|
||||
|
@ -53,6 +53,99 @@ self =>
|
|||
case None => default(key)
|
||||
}
|
||||
|
||||
def getOrElse[U >: V](key: K, default: => U): U = get(key) match {
|
||||
case Some(v) => v
|
||||
case None => default
|
||||
}
|
||||
|
||||
def contains(key: K): Boolean = get(key).isDefined
|
||||
|
||||
def isDefinedAt(key: K): Boolean = contains(key)
|
||||
|
||||
private[this] def keysIterator(s: IterableSplitter[(K, V)] @uncheckedVariance): IterableSplitter[K] =
|
||||
new IterableSplitter[K] {
|
||||
i =>
|
||||
val iter = s
|
||||
var signalDelegate: Signalling = IdleSignalling
|
||||
def hasNext = iter.hasNext
|
||||
def next() = iter.next._1
|
||||
def split = {
|
||||
val ss = iter.split.map(keysIterator(_))
|
||||
ss.foreach { _.signalDelegate = i.signalDelegate }
|
||||
ss
|
||||
}
|
||||
def remaining = iter.remaining
|
||||
def dup = keysIterator(iter.dup)
|
||||
}
|
||||
|
||||
def keysIterator: IterableSplitter[K] = keysIterator(splitter)
|
||||
|
||||
private[this] def valuesIterator(s: IterableSplitter[(K, V)] @uncheckedVariance): IterableSplitter[V] =
|
||||
new IterableSplitter[V] {
|
||||
i =>
|
||||
val iter = s
|
||||
var signalDelegate: Signalling = IdleSignalling
|
||||
def hasNext = iter.hasNext
|
||||
def next() = iter.next._2
|
||||
def split = {
|
||||
val ss = iter.split.map(valuesIterator(_))
|
||||
ss.foreach { _.signalDelegate = i.signalDelegate }
|
||||
ss
|
||||
}
|
||||
def remaining = iter.remaining
|
||||
def dup = valuesIterator(iter.dup)
|
||||
}
|
||||
|
||||
def valuesIterator: IterableSplitter[V] = valuesIterator(splitter)
|
||||
|
||||
protected class DefaultKeySet extends ParSet[K] {
|
||||
def contains(key : K) = self.contains(key)
|
||||
def splitter = keysIterator(self.splitter)
|
||||
def + (elem: K): ParSet[K] =
|
||||
(ParSet[K]() ++ this + elem).asInstanceOf[ParSet[K]] // !!! concrete overrides abstract problem
|
||||
def - (elem: K): ParSet[K] =
|
||||
(ParSet[K]() ++ this - elem).asInstanceOf[ParSet[K]] // !!! concrete overrides abstract problem
|
||||
override def size = self.size
|
||||
override def foreach[S](f: K => S) = for ((k, v) <- self) f(k)
|
||||
override def seq = self.seq.keySet
|
||||
}
|
||||
|
||||
protected class DefaultValuesIterable extends ParIterable[V] {
|
||||
def splitter = valuesIterator(self.splitter)
|
||||
override def size = self.size
|
||||
override def foreach[S](f: V => S) = for ((k, v) <- self) f(v)
|
||||
def seq = self.seq.values
|
||||
}
|
||||
|
||||
def keySet: ParSet[K] = new DefaultKeySet
|
||||
|
||||
def keys: ParIterable[K] = keySet
|
||||
|
||||
def values: ParIterable[V] = new DefaultValuesIterable
|
||||
|
||||
def filterKeys(p: K => Boolean): ParMap[K, V] = new ParMap[K, V] {
|
||||
lazy val filtered = self.filter(kv => p(kv._1))
|
||||
override def foreach[S](f: ((K, V)) => S): Unit = for (kv <- self) if (p(kv._1)) f(kv)
|
||||
def splitter = filtered.splitter
|
||||
override def contains(key: K) = self.contains(key) && p(key)
|
||||
def get(key: K) = if (!p(key)) None else self.get(key)
|
||||
def seq = self.seq.filterKeys(p)
|
||||
def size = filtered.size
|
||||
def + [U >: V](kv: (K, U)): ParMap[K, U] = ParMap[K, U]() ++ this + kv
|
||||
def - (key: K): ParMap[K, V] = ParMap[K, V]() ++ this - key
|
||||
}
|
||||
|
||||
def mapValues[S](f: V => S): ParMap[K, S] = new ParMap[K, S] {
|
||||
override def foreach[Q](g: ((K, S)) => Q): Unit = for ((k, v) <- self) g((k, f(v)))
|
||||
def splitter = self.splitter.map(kv => (kv._1, f(kv._2)))
|
||||
override def size = self.size
|
||||
override def contains(key: K) = self.contains(key)
|
||||
def get(key: K) = self.get(key).map(f)
|
||||
def seq = self.seq.mapValues(f)
|
||||
def + [U >: S](kv: (K, U)): ParMap[K, U] = ParMap[K, U]() ++ this + kv
|
||||
def - (key: K): ParMap[K, S] = ParMap[K, S]() ++ this - key
|
||||
}
|
||||
|
||||
// note - should not override toMap (could be mutable)
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,30 @@ self =>
|
|||
override def stringPrefix = "ParMap"
|
||||
|
||||
override def toMap[P, Q](implicit ev: (K, V) <:< (P, Q)): ParMap[P, Q] = this.asInstanceOf[ParMap[P, Q]]
|
||||
|
||||
override def updated [U >: V](key: K, value: U): ParMap[K, U] = this + ((key, value))
|
||||
|
||||
def + [U >: V](kv: (K, U)): ParMap[K, U]
|
||||
|
||||
/** The same map with a given default function.
|
||||
* Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefault`.
|
||||
*
|
||||
* Invoking transformer methods (e.g. `map`) will not preserve the default value.
|
||||
*
|
||||
* @param d the function mapping keys to values, used for non-present keys
|
||||
* @return a wrapper of the map with a default value
|
||||
*/
|
||||
def withDefault[U >: V](d: K => U): collection.parallel.immutable.ParMap[K, U] = new ParMap.WithDefault[K, U](this, d)
|
||||
|
||||
/** The same map with a given default value.
|
||||
*
|
||||
* Invoking transformer methods (e.g. `map`) will not preserve the default value.
|
||||
*
|
||||
* @param d the function mapping keys to values, used for non-present keys
|
||||
* @return a wrapper of the map with a default value
|
||||
*/
|
||||
def withDefaultValue[U >: V](d: U): collection.parallel.immutable.ParMap[K, U] = new ParMap.WithDefault[K, U](this, x => d)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,4 +78,15 @@ object ParMap extends ParMapFactory[ParMap] {
|
|||
|
||||
implicit def canBuildFrom[K, V]: CanCombineFrom[Coll, (K, V), ParMap[K, V]] = new CanCombineFromMap[K, V]
|
||||
|
||||
class WithDefault[K, +V](underlying: ParMap[K, V], d: K => V)
|
||||
extends collection.parallel.ParMap.WithDefault[K, V](underlying, d) with ParMap[K, V] {
|
||||
override def empty = new WithDefault(underlying.empty, d)
|
||||
override def updated[U >: V](key: K, value: U): WithDefault[K, U] = new WithDefault[K, U](underlying.updated[U](key, value), d)
|
||||
override def + [U >: V](kv: (K, U)): WithDefault[K, U] = updated(kv._1, kv._2)
|
||||
override def - (key: K): WithDefault[K, V] = new WithDefault(underlying - key, d)
|
||||
override def withDefault[U >: V](d: K => U): ParMap[K, U] = new WithDefault[K, U](underlying, d)
|
||||
override def withDefaultValue[U >: V](d: U): ParMap[K, U] = new WithDefault[K, U](underlying, x => d)
|
||||
override def seq = underlying.seq.withDefault(d)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,27 @@ extends collection/*.mutable*/.GenMap[K, V]
|
|||
|
||||
def seq: collection.mutable.Map[K, V]
|
||||
|
||||
override def updated [U >: V](key: K, value: U): ParMap[K, U] = this + ((key, value))
|
||||
|
||||
/** The same map with a given default function.
|
||||
* Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefault`.
|
||||
*
|
||||
* Invoking transformer methods (e.g. `map`) will not preserve the default value.
|
||||
*
|
||||
* @param d the function mapping keys to values, used for non-present keys
|
||||
* @return a wrapper of the map with a default value
|
||||
*/
|
||||
def withDefault(d: K => V): collection.parallel.mutable.ParMap[K, V] = new ParMap.WithDefault[K, V](this, d)
|
||||
|
||||
/** The same map with a given default value.
|
||||
*
|
||||
* Invoking transformer methods (e.g. `map`) will not preserve the default value.
|
||||
*
|
||||
* @param d the function mapping keys to values, used for non-present keys
|
||||
* @return a wrapper of the map with a default value
|
||||
*/
|
||||
def withDefaultValue(d: V): collection.parallel.mutable.ParMap[K, V] = new ParMap.WithDefault[K, V](this, x => d)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,6 +75,24 @@ object ParMap extends ParMapFactory[ParMap] {
|
|||
|
||||
implicit def canBuildFrom[K, V]: CanCombineFrom[Coll, (K, V), ParMap[K, V]] = new CanCombineFromMap[K, V]
|
||||
|
||||
class WithDefault[K, V](underlying: ParMap[K, V], d: K => V)
|
||||
extends collection.parallel.ParMap.WithDefault(underlying, d) with ParMap[K, V] {
|
||||
override def += (kv: (K, V)) = {underlying += kv; this}
|
||||
def -= (key: K) = {underlying -= key; this}
|
||||
override def empty = new WithDefault(underlying.empty, d)
|
||||
override def updated[U >: V](key: K, value: U): WithDefault[K, U] = new WithDefault[K, U](underlying.updated[U](key, value), d)
|
||||
override def + [U >: V](kv: (K, U)): WithDefault[K, U] = updated(kv._1, kv._2)
|
||||
override def - (key: K): WithDefault[K, V] = new WithDefault(underlying - key, d)
|
||||
override def seq = underlying.seq.withDefault(d)
|
||||
def clear() = underlying.clear()
|
||||
def put(key: K, value: V): Option[V] = underlying.put(key, value)
|
||||
|
||||
/** If these methods aren't overridden to thread through the underlying map,
|
||||
* successive calls to withDefault* have no effect.
|
||||
*/
|
||||
override def withDefault(d: K => V): ParMap[K, V] = new WithDefault[K, V](underlying, d)
|
||||
override def withDefaultValue(d: V): ParMap[K, V] = new WithDefault[K, V](underlying, x => d)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
|
||||
import collection._
|
||||
|
||||
|
||||
|
||||
object Test {
|
||||
|
||||
def main(args: Array[String]) {
|
||||
val gm: GenMap[Int, Int] = GenMap(0 -> 0, 1 -> 1).par
|
||||
|
||||
// ops
|
||||
assert(gm.isDefinedAt(1))
|
||||
assert(gm.contains(1))
|
||||
assert(gm.getOrElse(1, 2) == 1)
|
||||
assert(gm.getOrElse(2, 3) == 3)
|
||||
assert(gm.keysIterator.toSet == Set(0, 1))
|
||||
assert(gm.valuesIterator.toSet == Set(0, 1))
|
||||
assert(gm.keySet == Set(0, 1))
|
||||
assert(gm.keys.toSet == Set(0, 1))
|
||||
assert(gm.values.toSet == Set(0, 1))
|
||||
try {
|
||||
gm.default(-1)
|
||||
assert(false)
|
||||
} catch {
|
||||
case e: NoSuchElementException => // ok
|
||||
}
|
||||
|
||||
assert(gm.filterKeys(_ % 2 == 0)(0) == 0)
|
||||
assert(gm.filterKeys(_ % 2 == 0).get(1) == None)
|
||||
assert(gm.mapValues(_ + 1)(0) == 1)
|
||||
|
||||
// with defaults
|
||||
val pm = parallel.mutable.ParMap(0 -> 0, 1 -> 1)
|
||||
val dm = pm.withDefault(x => -x)
|
||||
assert(dm(0) == 0)
|
||||
assert(dm(1) == 1)
|
||||
assert(dm(2) == -2)
|
||||
assert(dm.updated(2, 2) == parallel.ParMap(0 -> 0, 1 -> 1, 2 -> 2))
|
||||
dm.put(3, 3)
|
||||
assert(dm(3) == 3)
|
||||
assert(pm(3) == 3)
|
||||
assert(dm(4) == -4)
|
||||
|
||||
val imdm = parallel.immutable.ParMap(0 -> 0, 1 -> 1).withDefault(x => -x)
|
||||
assert(imdm(0) == 0)
|
||||
assert(imdm(1) == 1)
|
||||
assert(imdm(2) == -2)
|
||||
assert(imdm.updated(2, 2) == parallel.ParMap(0 -> 0, 1 -> 1, 2 -> 2))
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue