diff options
Diffstat (limited to 'src/library')
24 files changed, 373 insertions, 90 deletions
diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala index 4a10b65735..9fa56a332f 100644 --- a/src/library/scala/Function.scala +++ b/src/library/scala/Function.scala @@ -29,6 +29,7 @@ object Function { /** Turns a function `A => Option[B]` into a `PartialFunction[A, B]`. * + * TODO: check if the paragraph below is still correct * '''Important note''': this transformation implies the original function * will be called 2 or more times on each logical invocation, because the * only way to supply an implementation of `isDefinedAt` is to call the @@ -39,11 +40,7 @@ object Function { * f returns `Some(_)` and undefined where `f` returns `None`. * @see [[scala.PartialFunction#lift]] */ - def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = new runtime.AbstractPartialFunction[T, R] { - def apply(x: T): R = f(x).get - def _isDefinedAt(x: T): Boolean = f(x).isDefined - override def lift: T => Option[R] = f - } + def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = PartialFunction.unlifted(f) /** Uncurrying for functions of arity 2. This transforms a unary function * returning another unary function into a function of arity 2. diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index 3c5d6d0d23..7154b8da34 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -8,6 +8,7 @@ package scala + /** A partial function of type `PartialFunction[A, B]` is a unary function * where the domain does not necessarily include all values of type `A`. * The function `isDefinedAt` allows to test dynamically if a value is in @@ -43,10 +44,11 @@ package scala * }}} * * - * @author Martin Odersky + * @author Martin Odersky, Pavel Pavlov, Adriaan Moors * @version 1.0, 16/07/2003 */ -trait PartialFunction[-A, +B] extends (A => B) { +trait PartialFunction[-A, +B] extends (A => B) { self => + import PartialFunction._ /** Checks if a value is contained in the function's domain. * @@ -55,10 +57,6 @@ trait PartialFunction[-A, +B] extends (A => B) { */ def isDefinedAt(x: A): Boolean - //protected def missingCase[A1 <: A, B1 >: B]: PartialFunction[A1, B1] = PartialFunction.empty - - protected def missingCase(x: A): B = throw new MatchError(x) - /** Composes this partial function with a fallback partial function which * gets applied where this partial function is not defined. * @@ -70,16 +68,8 @@ trait PartialFunction[-A, +B] extends (A => B) { * takes `x` to `this(x)` where `this` is defined, and to `that(x)` where it is not. */ def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = - new runtime.AbstractPartialFunction[A1, B1] { - def _isDefinedAt(x: A1): Boolean = - PartialFunction.this.isDefinedAt(x) || that.isDefinedAt(x) - def apply(x: A1): B1 = - if (PartialFunction.this.isDefinedAt(x)) PartialFunction.this.apply(x) - else that.apply(x) - } - - def orElseFast[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = - orElse(that) + new OrElse[A1, B1] (this, that) + //TODO: why not overload it with orElse(that: F1): F1? /** Composes this partial function with a transformation function that * gets applied to results of this partial function. @@ -88,9 +78,9 @@ trait PartialFunction[-A, +B] extends (A => B) { * @return a partial function with the same domain as this partial function, which maps * arguments `x` to `k(this(x))`. */ - override def andThen[C](k: B => C) : PartialFunction[A, C] = new runtime.AbstractPartialFunction[A, C] { - def _isDefinedAt(x: A): Boolean = PartialFunction.this.isDefinedAt(x) - def apply(x: A): C = k(PartialFunction.this.apply(x)) + override def andThen[C](k: B => C) : PartialFunction[A, C] = new PartialFunction[A, C] { + def isDefinedAt(x: A): Boolean = self isDefinedAt x + def apply(x: A): C = k(self(x)) } /** Turns this partial function into an plain function returning an `Option` result. @@ -98,9 +88,30 @@ trait PartialFunction[-A, +B] extends (A => B) { * @return a function that takes an argument `x` to `Some(this(x))` if `this` * is defined for `x`, and to `None` otherwise. */ - def lift: A => Option[B] = new (A => Option[B]) { - def apply(x: A): Option[B] = if (isDefinedAt(x)) Some(PartialFunction.this.apply(x)) else None - } + def lift: A => Option[B] = new Lifted(this) + + /** + * TODO: comment + * @since 2.10 + */ + def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + if (isDefinedAt(x)) apply(x) else default(x) + + /** + * TODO: comment + * @since 2.10 + */ + def run[U](x: A)(action: B => U): Boolean = + applyOrElse(x, fallbackToken) match { + case FallbackToken => false + case z => action(z); true + } + + /** + * TODO: comment + * @since 2.10 + */ + def runWith[U](action: B => U): A => Boolean = { x => run(x)(action) } } /** A few handy operations which leverage the extra bit of information @@ -119,14 +130,73 @@ trait PartialFunction[-A, +B] extends (A => B) { * @since 2.8 */ object PartialFunction { - private[this] final val empty_pf: PartialFunction[Any, Nothing] = new runtime.AbstractPartialFunction[Any, Nothing] { - def _isDefinedAt(x: Any) = false - override def isDefinedAt(x: Any) = false - def apply(x: Any): Nothing = throw new MatchError(x) - override def orElse[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that - override def orElseFast[A1, B1](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = that - override def lift = (x: Any) => None + /** Composite function produced by `PartialFunction#orElse` method + */ + private final class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) extends PartialFunction[A, B] { + def isDefinedAt(x: A) = f1.isDefinedAt(x) || f2.isDefinedAt(x) + + def apply(x: A): B = f1.applyOrElse(x, f2) + + override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + f1.applyOrElse(x, fallbackToken) match { + case FallbackToken => f2.applyOrElse(x, default) + case z => z + } + + override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]) = + new OrElse[A1, B1] (f1, f2 orElse that) + + override def andThen[C](k: B => C) = + new OrElse[A, C] (f1 andThen k, f2 andThen k) } + + private[scala] lazy val FallbackToken: PartialFunction[Any, PartialFunction[Any, Nothing]] = { case _ => FallbackToken.asInstanceOf[PartialFunction[Any, Nothing]] } + private[scala] final def fallbackToken[B] = FallbackToken.asInstanceOf[PartialFunction[Any, B]] + //TODO: check generated code for PF literal here + + private[scala] final class Lifted[-A, +B] (val pf: PartialFunction[A, B]) + extends runtime.AbstractFunction1[A, Option[B]] { + + def apply(x: A): Option[B] = pf.applyOrElse(x, fallbackToken) match { + case FallbackToken => None + case z => Some(z) + } + } + + private final class Unlifted[A, B] (f: A => Option[B]) extends runtime.AbstractPartialFunction[A, B] { + def isDefinedAt(x: A): Boolean = f(x).isDefined + override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = + f(x) getOrElse default(x) //TODO: check generated code and inline getOrElse if needed + override def lift = f + } + + private[scala] def unlifted[A, B](f: A => Option[B]): PartialFunction[A, B] = f match { + case lf: Lifted[A, B] => lf.pf + case ff => new Unlifted(ff) + } + + /** Converts ordinary function to partial one + * @since 2.10 + */ + //TODO: check generated code for PF literal here + def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) } + + private[this] final val constFalse: Any => Boolean = { _ => false} + + private[this] final val empty_pf: PartialFunction[Any, Nothing] = new PartialFunction[Any, Nothing] { + def isDefinedAt(x: Any) = false + def apply(x: Any) = throw new MatchError(x) + override def orElse[A1, B1](that: PartialFunction[A1, B1]) = that + override def andThen[C](k: Nothing => C) = this + override val lift = (x: Any) => None + override def run[U](x: Any)(action: Nothing => U) = false + override def runWith[U](action: Nothing => U) = constFalse + } + + /** + * TODO: comment + * @since 2.10 + */ def empty[A, B] : PartialFunction[A, B] = empty_pf /** Creates a Boolean test based on a value and a partial function. @@ -137,8 +207,7 @@ object PartialFunction { * @param pf the partial function * @return true, iff `x` is in the domain of `pf` and `pf(x) == true`. */ - def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean = - (pf isDefinedAt x) && pf(x) + def cond[T](x: T)(pf: PartialFunction[T, Boolean]): Boolean = pf.applyOrElse(x, constFalse) /** Transforms a PartialFunction[T, U] `pf` into Function1[T, Option[U]] `f` * whose result is `Some(x)` if the argument is in `pf`'s domain and `None` @@ -150,6 +219,5 @@ object PartialFunction { * @param pf the PartialFunction[T, U] * @return `Some(pf(x))` if `pf isDefinedAt x`, `None` otherwise. */ - def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] = - if (pf isDefinedAt x) Some(pf(x)) else None + def condOpt[T,U](x: T)(pf: PartialFunction[T, U]): Option[U] = pf.lift(x) } diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 75ab3f28f5..a978a9a783 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -127,3 +127,5 @@ object JavaConversions extends WrapAsScala with WrapAsJava { @deprecated("use propertiesAsScalaMap instead", "2.9.0") def asScalaMap(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) } + + diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 13f1f19f81..f8a9466caf 100755 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -100,4 +100,4 @@ object JavaConverters extends DecorateAsJava with DecorateAsScala { @deprecated("Use propertiesAsScalaMapConverter instead", "2.9.0") def asScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = propertiesAsScalaMapConverter(p) -}
\ No newline at end of file +} diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index 76837d937c..e05bfc41cd 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -291,6 +291,26 @@ trait DecorateAsJava { * @return An object with an `asJava` method that returns a Java * `ConcurrentMap` view of the argument. */ + @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") implicit def asJavaConcurrentMapConverter[A, B](m: mutable.ConcurrentMap[A, B]): AsJava[juc.ConcurrentMap[A, B]] = new AsJava(asJavaConcurrentMap(m)) + + /** + * Adds an `asJava` method that implicitly converts a Scala mutable + * `concurrent.Map` to a Java `ConcurrentMap`. + * + * The returned Java `ConcurrentMap` is backed by the provided Scala + * `concurrent.Map` and any side-effects of using it via the Java interface + * will be visible via the Scala interface and vice versa. + * + * If the Scala `concurrent.Map` was previously obtained from an implicit or + * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)` + * then the original Java `ConcurrentMap` will be returned. + * + * @param m The Scala `concurrent.Map` to be converted. + * @return An object with an `asJava` method that returns a Java + * `ConcurrentMap` view of the argument. + */ + implicit def asJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] = + new AsJava(asJavaConcurrentMap(m)) } diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala index bb14228e67..722f0b9af9 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -156,10 +156,29 @@ trait DecorateAsScala { * @return An object with an `asScala` method that returns a Scala mutable * `ConcurrentMap` view of the argument. */ - implicit def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] = + @deprecated("Use `mapAsScalaConcurrentMapConverter` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") + def asScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[mutable.ConcurrentMap[A, B]] = new AsScala(asScalaConcurrentMap(m)) /** + * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` + * to a Scala mutable `concurrent.Map`. The returned Scala `concurrent.Map` is + * backed by the provided Java `ConcurrentMap` and any side-effects of using + * it via the Scala interface will be visible via the Java interface and + * vice versa. + * + * If the Java `ConcurrentMap` was previously obtained from an implicit or + * explicit call of `mapAsScalaConcurrentMap(scala.collection.mutable.ConcurrentMap)` + * then the original Scala `concurrent.Map` will be returned. + * + * @param m The `ConcurrentMap` to be converted. + * @return An object with an `asScala` method that returns a Scala mutable + * `concurrent.Map` view of the argument. + */ + implicit def mapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] = + new AsScala(mapAsScalaConcurrentMap(m)) + + /** * Adds an `asScala` method that implicitly converts a Java `Dictionary` * to a Scala mutable `Map[String, String]`. The returned Scala * `Map[String, String]` is backed by the provided Java `Dictionary` and diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 6274518d1a..cdec72b9fe 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -241,16 +241,45 @@ trait WrapAsJava { * will be visible via the Scala interface and vice versa. * * If the Scala `ConcurrentMap` was previously obtained from an implicit or - * explicit call of `asConcurrentMap(java.util.concurrect.ConcurrentMap)` + * explicit call of `asScalaConcurrentMap(java.util.concurrect.ConcurrentMap)` * then the original Java ConcurrentMap will be returned. * * @param m The `ConcurrentMap` to be converted. * @return A Java `ConcurrentMap` view of the argument. */ + @deprecated("Use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") implicit def asJavaConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match { + case JConcurrentMapDeprecatedWrapper(wrapped) => wrapped + case _ => new ConcurrentMapDeprecatedWrapper(m) + } + + /** + * Implicitly converts a Scala mutable `concurrent.Map` to a Java + * `ConcurrentMap`. + * + * The returned Java `ConcurrentMap` is backed by the provided Scala + * `concurrent.Map` and any side-effects of using it via the Java interface + * will be visible via the Scala interface and vice versa. + * + * If the Scala `concurrent.Map` was previously obtained from an implicit or + * explicit call of `mapAsScalaConcurrentMap(java.util.concurrect.ConcurrentMap)` + * then the original Java ConcurrentMap will be returned. + * + * @param m The Scala `concurrent.Map` to be converted. + * @return A Java `ConcurrentMap` view of the argument. + */ + implicit def asJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { case JConcurrentMapWrapper(wrapped) => wrapped case _ => new ConcurrentMapWrapper(m) } } object WrapAsJava extends WrapAsJava { } + + + + + + + + diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index 02b58f55a4..56e13b2105 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -154,9 +154,28 @@ trait WrapAsScala { * @param m The ConcurrentMap to be converted. * @return A Scala mutable ConcurrentMap view of the argument. */ - implicit def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { - case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying - case _ => new JConcurrentMapWrapper(m) + @deprecated("Use `mapAsScalaConcurrentMap` instead, and use `concurrent.Map` instead of `ConcurrentMap`.", "2.10.0") + def asScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { + case cmw: ConcurrentMapDeprecatedWrapper[a, b] => cmw.underlying + case _ => new JConcurrentMapDeprecatedWrapper(m) + } + + /** + * Implicitly converts a Java ConcurrentMap to a Scala mutable ConcurrentMap. + * The returned Scala ConcurrentMap is backed by the provided Java + * ConcurrentMap and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * + * If the Java ConcurrentMap was previously obtained from an implicit or + * explicit call of `asConcurrentMap(scala.collection.mutable.ConcurrentMap)` + * then the original Scala ConcurrentMap will be returned. + * + * @param m The ConcurrentMap to be converted. + * @return A Scala mutable ConcurrentMap view of the argument. + */ + implicit def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match { + case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) } /** diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index 8136e462cb..b1b48b760f 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -268,7 +268,7 @@ private[collection] trait Wrappers { override def empty = JMapWrapper(new ju.HashMap[A, B]) } - class ConcurrentMapWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { + class ConcurrentMapDeprecatedWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { case Some(v) => v @@ -290,7 +290,54 @@ private[collection] trait Wrappers { def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) } - case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with mutable.ConcurrentMap[A, B] { + class ConcurrentMapWrapper[A, B](override val underlying: concurrent.Map[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { + + def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def remove(k: AnyRef, v: AnyRef) = try { + underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B]) + } catch { + case ex: ClassCastException => + false + } + + def replace(k: A, v: B): B = underlying.replace(k, v) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + + def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) + } + + case class JConcurrentMapDeprecatedWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapDeprecatedWrapper[A, B]] with mutable.ConcurrentMap[A, B] { + override def get(k: A) = { + val v = underlying get k + if (v != null) Some(v) + else None + } + + override def empty = new JConcurrentMapDeprecatedWrapper(new juc.ConcurrentHashMap[A, B]) + + def putIfAbsent(k: A, v: B): Option[B] = { + val r = underlying.putIfAbsent(k, v) + if (r != null) Some(r) else None + } + + def remove(k: A, v: B): Boolean = underlying.remove(k, v) + + def replace(k: A, v: B): Option[B] = { + val prev = underlying.replace(k, v) + if (prev != null) Some(prev) else None + } + + def replace(k: A, oldvalue: B, newvalue: B): Boolean = + underlying.replace(k, oldvalue, newvalue) + } + + case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[A, B] { override def get(k: A) = { val v = underlying get k if (v != null) Some(v) diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 870c179b2d..1b75c10113 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -58,7 +58,7 @@ import java.io._ * @author Martin Odersky and others * @version 2.8 * @since 1.0 - * @see [["http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#lists" "Scala's Collection Library overview"]] + * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#lists "Scala's Collection Library overview"]] * section on `Lists` for more information. * * @define coll list diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index cc0aed6963..06b7d40bfc 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -366,7 +366,7 @@ private[collection] object HashTable { private[collection] final def newThreshold(_loadFactor: Int, size: Int) = ((size.toLong * _loadFactor) / loadFactorDenum).toInt - private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = thr * loadFactorDenum / _loadFactor + private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = ((thr.toLong * loadFactorDenum) / _loadFactor).toInt private[collection] final def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) diff --git a/src/library/scala/collection/mutable/Stack.scala b/src/library/scala/collection/mutable/Stack.scala index 8fad131009..b70df05c55 100644 --- a/src/library/scala/collection/mutable/Stack.scala +++ b/src/library/scala/collection/mutable/Stack.scala @@ -44,7 +44,7 @@ object Stack extends SeqFactory[Stack] { * @author Martin Odersky * @version 2.8 * @since 1 - * @see [[http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html#stacks"Scala's Collection Library overview"]] + * @see [[http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html#stacks "Scala's Collection Library overview"]] * section on `Stacks` for more information. * @define Coll Stack * @define coll stack diff --git a/src/library/scala/collection/parallel/immutable/ParHashMap.scala b/src/library/scala/collection/parallel/immutable/ParHashMap.scala index 49b00bebdb..e630a9dbed 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashMap.scala @@ -36,7 +36,9 @@ import collection.parallel.Task * * @author Aleksandar Prokopec * @since 2.9 - * + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tries Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tries for more information. + * * @define Coll immutable.ParHashMap * @define coll immutable parallel hash map */ diff --git a/src/library/scala/collection/parallel/immutable/ParHashSet.scala b/src/library/scala/collection/parallel/immutable/ParHashSet.scala index 11d92a27c9..084637c5dc 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashSet.scala @@ -35,6 +35,8 @@ import collection.parallel.Task * * @author Aleksandar Prokopec * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tries Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tries for more information. * * @define Coll immutable.ParHashSet * @define coll immutable parallel hash set diff --git a/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala index 9cac433460..277fd5fdd3 100644 --- a/src/library/scala/collection/parallel/immutable/ParRange.scala +++ b/src/library/scala/collection/parallel/immutable/ParRange.scala @@ -25,6 +25,8 @@ import scala.collection.Iterator * * @author Aleksandar Prokopec * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_range Scala's Parallel Collections Library overview]] + * section on `ParRange` for more information. * * @define Coll immutable.ParRange * @define coll immutable parallel range diff --git a/src/library/scala/collection/parallel/immutable/ParVector.scala b/src/library/scala/collection/parallel/immutable/ParVector.scala index 5d9c431bc1..8baa84b77c 100644 --- a/src/library/scala/collection/parallel/immutable/ParVector.scala +++ b/src/library/scala/collection/parallel/immutable/ParVector.scala @@ -34,6 +34,8 @@ import immutable.VectorIterator * * @author Aleksandar Prokopec * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_vector Scala's Parallel Collections Library overview]] + * section on `ParVector` for more information. * * @define Coll immutable.ParVector * @define coll immutable parallel vector diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala index c33495bd39..8cc0b95997 100644 --- a/src/library/scala/collection/parallel/mutable/ParArray.scala +++ b/src/library/scala/collection/parallel/mutable/ParArray.scala @@ -44,10 +44,14 @@ import scala.collection.GenTraversableOnce * * @tparam T type of the elements in the array * + * @author Aleksandar Prokopec + * @since 2.9 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_array Scala's Parallel Collections Library overview]] + * section on `ParArray` for more information. + * * @define Coll ParArray * @define coll parallel array * - * @author Aleksandar Prokopec */ @SerialVersionUID(1L) class ParArray[T] private[mutable] (val arrayseq: ArraySeq[T]) diff --git a/src/library/scala/collection/parallel/mutable/ParHashMap.scala b/src/library/scala/collection/parallel/mutable/ParHashMap.scala index 6ce6c45460..23b23d55a1 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashMap.scala @@ -32,6 +32,8 @@ import collection.parallel.Task * @define coll parallel hash map * * @author Aleksandar Prokopec + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tables Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tables for more information. */ @SerialVersionUID(1L) class ParHashMap[K, V] private[collection] (contents: HashTable.Contents[K, DefaultEntry[K, V]]) diff --git a/src/library/scala/collection/parallel/mutable/ParHashSet.scala b/src/library/scala/collection/parallel/mutable/ParHashSet.scala index e0a2ab03df..4e9a38c13f 100644 --- a/src/library/scala/collection/parallel/mutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/mutable/ParHashSet.scala @@ -29,6 +29,8 @@ import collection.parallel.Task * @define coll parallel hash set * * @author Aleksandar Prokopec + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_hash_tables Scala's Parallel Collections Library overview]] + * section on Parallel Hash Tables for more information. */ @SerialVersionUID(1L) class ParHashSet[T] private[collection] (contents: FlatHashTable.Contents[T]) diff --git a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala index fa19990b91..359c35f1dd 100644 --- a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala @@ -33,6 +33,8 @@ import scala.collection.concurrent.TrieMapIterator * * @author Aleksandar Prokopec * @since 2.10 + * @see [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#parallel_concurrent_tries Scala's Parallel Collections Library overview]] + * section on `ParTrieMap` for more information. */ final class ParTrieMap[K, V] private[collection] (private val ctrie: TrieMap[K, V]) extends ParMap[K, V] diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index c1f45eccfb..cb42b76b51 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -183,7 +183,8 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { override def equals (that: Any): Boolean = that match { case that: BigDecimal => this equals that case that: BigInt => this.toBigIntExact exists (that equals _) - case _: Float | _: Double => unifiedPrimitiveEquals(that) + case that: Double => isValidDouble && toDouble == that + case that: Float => isValidFloat && toFloat == that case _ => isValidLong && unifiedPrimitiveEquals(that) } override def isValidByte = noArithmeticException(toByteExact) @@ -191,6 +192,18 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { override def isValidChar = isValidInt && toIntExact >= Char.MinValue && toIntExact <= Char.MaxValue override def isValidInt = noArithmeticException(toIntExact) def isValidLong = noArithmeticException(toLongExact) + /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`. + */ + def isValidFloat = { + val f = toFloat + !f.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(f)) == 0 + } + /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`. + */ + def isValidDouble = { + val d = toDouble + !d.isInfinity && bigDecimal.compareTo(new java.math.BigDecimal(d)) == 0 + } private def noArithmeticException(body: => Unit): Boolean = { try { body ; true } diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 8a53afaa62..dbec30b2fe 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -20,6 +20,7 @@ object BigInt { private val minCached = -1024 private val maxCached = 1024 private val cache = new Array[BigInt](maxCached - minCached + 1) + private val minusOne = BigInteger.valueOf(-1) @deprecated("Use Long.MinValue", "2.9.0") val MinLong = BigInt(Long.MinValue) @@ -122,6 +123,8 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo override def equals(that: Any): Boolean = that match { case that: BigInt => this equals that case that: BigDecimal => that.toBigIntExact exists (this equals _) + case that: Double => isValidDouble && toDouble == that + case that: Float => isValidFloat && toFloat == that case x => isValidLong && unifiedPrimitiveEquals(x) } override def isValidByte = this >= Byte.MinValue && this <= Byte.MaxValue @@ -129,6 +132,41 @@ class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericCo override def isValidChar = this >= Char.MinValue && this <= Char.MaxValue override def isValidInt = this >= Int.MinValue && this <= Int.MaxValue def isValidLong = this >= Long.MinValue && this <= Long.MaxValue + /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`. + */ + def isValidFloat = { + val bitLen = bitLength + (bitLen <= 24 || + { + val lowest = lowestSetBit + bitLen <= java.lang.Float.MAX_EXPONENT + 1 && // exclude this < -2^128 && this >= 2^128 + lowest >= bitLen - 24 && + lowest < java.lang.Float.MAX_EXPONENT + 1 // exclude this == -2^128 + } + ) && !bitLengthOverflow + } + /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`. + */ + def isValidDouble = { + val bitLen = bitLength + (bitLen <= 53 || + { + val lowest = lowestSetBit + bitLen <= java.lang.Double.MAX_EXPONENT + 1 && // exclude this < -2^1024 && this >= 2^1024 + lowest >= bitLen - 53 && + lowest < java.lang.Double.MAX_EXPONENT + 1 // exclude this == -2^1024 + } + ) && !bitLengthOverflow + } + /** Some implementations of java.math.BigInteger allow huge values with bit length greater than Int.MaxValue . + * The BigInteger.bitLength method returns truncated bit length in this case . + * This method tests if result of bitLength is valid. + * This method will become unnecessary if BigInt constructors reject huge BigIntegers. + */ + private def bitLengthOverflow = { + val shifted = bigInteger.shiftRight(Int.MaxValue) + (shifted.signum != 0) && !(shifted equals BigInt.minusOne) + } protected[math] def isWhole = true def underlying = bigInteger diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala index cbe778f09b..2e435d8a7e 100644 --- a/src/library/scala/runtime/AbstractPartialFunction.scala +++ b/src/library/scala/runtime/AbstractPartialFunction.scala @@ -8,45 +8,61 @@ package scala.runtime -import scala.annotation.unchecked.uncheckedVariance - -/** This class provides a default implementation of partial functions - * that is used for all partial function literals. - * It contains an optimized `orElse` method which supports - * chained `orElse` in linear time, and with no slow-down - * if the `orElse` part is not needed. - * The implementation of `orElse` works by cloning the abstract function object - * and modifying a private `fallBack` variable that encodes the `getorElse` part. +/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` in terms of `isDefinedAt` and `applyOrElse`. + * + * This allows more efficient implementations in many cases: + * - optimized `orElse` method supports chained `orElse` in linear time, + * and with no slow-down if the `orElse` part is not needed. + * - optimized `lift` method helps to avoid double evaluation of pattern matchers & guards + * of partial function literals. + * + * This trait is used as a basis for implementation of all partial function literals + * with non-exhaustive matchers. + * + * Use of `AbstractPartialFunction` instead of `PartialFunction` as a base trait for + * user-defined partial functions may result in better performance + * and more predictable behavior w.r.t. side effects. + * + * @author Pavel Pavlov + * @since 2.10 */ -abstract class AbstractPartialFunction[-T1, +R] - extends AbstractFunction1[T1, R] - with PartialFunction[T1, R] - with Cloneable { - - private var fallBackField: PartialFunction[T1 @uncheckedVariance, R @uncheckedVariance] = _ +abstract class AbstractPartialFunction[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends Function1[T1, R] with PartialFunction[T1, R] { self => + // this method must be overridden for better performance, + // for backwards compatibility, fall back to the one inherited from PartialFunction + // this assumes the old-school partial functions override the apply method, though + // override def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = ??? - def fallBack: PartialFunction[T1, R] = synchronized { - if (fallBackField eq null) fallBackField = PartialFunction.empty - fallBackField - } + // probably okay to make final since classes compiled before have overridden against the old version of AbstractPartialFunction + // let's not make it final so as not to confuse anyone + /*final*/ def apply(x: T1): R = applyOrElse(x, PartialFunction.empty) - override protected def missingCase(x: T1): R = fallBack(x) - - // Question: Need to ensure that fallBack is overwritten before any access - // Is the `synchronized` here the right thing to achieve this? - // Is there a cheaper way? - override def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]) : PartialFunction[A1, B1] = { - val result = this.clone.asInstanceOf[AbstractPartialFunction[A1, B1]] - result.synchronized { - result.fallBackField = if (this.fallBackField eq null) that else this.fallBackField orElse that - result + override final def andThen[C](k: R => C) : PartialFunction[T1, C] = + new AbstractPartialFunction[T1, C] { + def isDefinedAt(x: T1): Boolean = self.isDefinedAt(x) + override def applyOrElse[A1 <: T1, C1 >: C](x: A1, default: A1 => C1): C1 = + self.applyOrElse(x, PartialFunction.fallbackToken) match { + case PartialFunction.FallbackToken => default(x) + case z => k(z) + } } - } - - def isDefinedAt(x: T1): scala.Boolean = _isDefinedAt(x) || fallBack.isDefinedAt(x) - def _isDefinedAt(x: T1): scala.Boolean + // TODO: remove + protected def missingCase(x: T1): R = throw new MatchError(x) } - +/** `AbstractTotalFunction` is a partial function whose `isDefinedAt` method always returns `true`. + * + * This class is used as base class for partial function literals with + * certainly exhaustive pattern matchers. + * + * @author Pavel Pavlov + * @since 2.10 + */ +abstract class AbstractTotalFunction[@specialized(scala.Int, scala.Long, scala.Float, scala.Double, scala.AnyRef) -T1, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long, scala.Double, scala.AnyRef) +R] extends Function1[T1, R] with PartialFunction[T1, R] { + final def isDefinedAt(x: T1): Boolean = true + override final def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = apply(x) + override final def orElse[A1 <: T1, B1 >: R](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] = this + //TODO: check generated code for PF literal here + override final def andThen[C](k: R => C): PartialFunction[T1, C] = { case x => k(apply(x)) } +} diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala index 5e3f8b6451..20a179a884 100644 --- a/src/library/scala/util/control/Exception.scala +++ b/src/library/scala/util/control/Exception.scala @@ -230,8 +230,5 @@ object Exception { classes exists (_ isAssignableFrom x.getClass) private def pfFromExceptions(exceptions: Class[_]*): PartialFunction[Throwable, Nothing] = - new scala.runtime.AbstractPartialFunction[Throwable, Nothing] { - def apply(x: Throwable) = throw x - def _isDefinedAt(x: Throwable) = wouldMatch(x, exceptions) - } + { case x if wouldMatch(x, exceptions) => throw x } } |