diff options
author | Paul Phillips <paulp@improving.org> | 2012-04-02 13:18:08 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-04-02 13:18:08 -0700 |
commit | 40334826eb573eed527cbd396ab406e7376edbcc (patch) | |
tree | 706a862b6e38f18ac9658ef79492d857d85d4b46 /src | |
parent | 03f32bd22f85bf3a6f8824dbe4a7a989e717c071 (diff) | |
parent | 9452d939331ee28313f0c9b2de260ee32d46af27 (diff) | |
download | scala-40334826eb573eed527cbd396ab406e7376edbcc.tar.gz scala-40334826eb573eed527cbd396ab406e7376edbcc.tar.bz2 scala-40334826eb573eed527cbd396ab406e7376edbcc.zip |
Merge branch 'develop'
Diffstat (limited to 'src')
17 files changed, 301 insertions, 78 deletions
diff --git a/src/build/maven/scala-library-pom.xml b/src/build/maven/scala-library-pom.xml index 673c3dfada..c3f8a4531c 100644 --- a/src/build/maven/scala-library-pom.xml +++ b/src/build/maven/scala-library-pom.xml @@ -30,17 +30,24 @@ <system>JIRA</system> <url>https://issues.scala-lang.org/</url> </issueManagement> - <distributionManagement> - <repository> - <id>scala-tools.org</id> - <url>@RELEASE_REPOSITORY@</url> - </repository> - <snapshotRepository> - <id>scala-tools.org</id> - <url>@SNAPSHOT_REPOSITORY@</url> - <uniqueVersion>false</uniqueVersion> - </snapshotRepository> - </distributionManagement> + <dependencies> + <dependency> + <groupId>org.skife.com.typesafe.config</groupId> + <artifactId>typesafe-config</artifactId> + <version>0.3.0</version> + </dependency> + </dependencies> + <distributionManagement> + <repository> + <id>scala-tools.org</id> + <url>@RELEASE_REPOSITORY@</url> + </repository> + <snapshotRepository> + <id>scala-tools.org</id> + <url>@SNAPSHOT_REPOSITORY@</url> + <uniqueVersion>false</uniqueVersion> + </snapshotRepository> + </distributionManagement> <developers> <developer> <id>lamp</id> 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/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/concurrent/ConcurrentPackageObject.scala b/src/library/scala/concurrent/ConcurrentPackageObject.scala index ba98757906..f4744a8757 100644 --- a/src/library/scala/concurrent/ConcurrentPackageObject.scala +++ b/src/library/scala/concurrent/ConcurrentPackageObject.scala @@ -10,8 +10,8 @@ package scala.concurrent -import java.util.concurrent.{ Executors, ExecutorService } -import scala.concurrent.forkjoin.ForkJoinPool +import java.util.concurrent.{ Executors, ExecutorService, ThreadFactory } +import scala.concurrent.forkjoin.{ ForkJoinPool, ForkJoinWorkerThread } import scala.util.{ Try, Success, Failure } import scala.concurrent.util.Duration import ConcurrentPackageObject._ @@ -24,14 +24,9 @@ abstract class ConcurrentPackageObject { /** A global execution environment for executing lightweight tasks. */ lazy val executionContext = - new impl.ExecutionContextImpl(getExecutorService) - - private[concurrent] def getExecutorService: AnyRef = - if (scala.util.Properties.isJavaAtLeast("1.6")) { - val vendor = scala.util.Properties.javaVmVendor - if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) new ForkJoinPool - else Executors.newCachedThreadPool() - } else Executors.newCachedThreadPool() + new impl.ExecutionContextImpl() + + private val currentExecutionContext = new ThreadLocal[ExecutionContext] val handledFutureException: PartialFunction[Throwable, Throwable] = { case t: Throwable if isFutureThrowable(t) => t @@ -58,10 +53,10 @@ abstract class ConcurrentPackageObject { /* concurrency constructs */ - def future[T](body: =>T)(implicit execCtx: ExecutionContext = executionContext): Future[T] = + def future[T](body: =>T)(implicit execctx: ExecutionContext = executionContext): Future[T] = Future[T](body) - def promise[T]()(implicit execCtx: ExecutionContext = executionContext): Promise[T] = + def promise[T]()(implicit execctx: ExecutionContext = executionContext): Promise[T] = Promise[T]() /** Wraps a block of code into an awaitable object. */ @@ -82,8 +77,8 @@ abstract class ConcurrentPackageObject { * - InterruptedException - in the case that a wait within the blockable object was interrupted * - TimeoutException - in the case that the blockable object timed out */ - def blocking[T](body: =>T)(implicit execCtx: ExecutionContext): T = - executionContext.blocking(body) + def blocking[T](body: =>T): T = + blocking(body2awaitable(body), Duration.fromNanos(0)) /** Blocks on an awaitable object. * @@ -94,8 +89,11 @@ abstract class ConcurrentPackageObject { * - InterruptedException - in the case that a wait within the blockable object was interrupted * - TimeoutException - in the case that the blockable object timed out */ - def blocking[T](awaitable: Awaitable[T], atMost: Duration)(implicit execCtx: ExecutionContext = executionContext): T = - executionContext.blocking(awaitable, atMost) + def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = + currentExecutionContext.get match { + case null => Await.result(awaitable, atMost) + case ec => ec.internalBlockingCall(awaitable, atMost) + } @inline implicit final def int2durationops(x: Int): DurationOps = new DurationOps(x) } diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index a206a2d4ea..f639f76dc9 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -26,10 +26,8 @@ trait ExecutionContext { def execute[U](body: () => U): Unit - def blocking[T](body: =>T): T - - def blocking[T](awaitable: Awaitable[T], atMost: Duration): T - + def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T + def reportFailure(t: Throwable): Unit /* implementations follow */ diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index d73801aa90..8cecadc605 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -274,6 +274,18 @@ self => p.future } + /** Used by for-comprehensions. + */ + final def withFilter(p: T => Boolean): Future[T] = filter(p) + // final def withFilter(p: T => Boolean) = new FutureWithFilter[T](this, p) + + // final class FutureWithFilter[+S](self: Future[S], p: S => Boolean) { + // def foreach(f: S => Unit): Unit = self filter p foreach f + // def map[R](f: S => R) = self filter p map f + // def flatMap[R](f: S => Future[R]) = self filter p flatMap f + // def withFilter(q: S => Boolean): FutureWithFilter[S] = new FutureWithFilter[S](self, x => p(x) && q(x)) + // } + /** Creates a new future by mapping the value of the current future if the given partial function is defined at that value. * * If the current future contains a value for which the partial function is defined, the new future will also hold that value. @@ -417,7 +429,26 @@ self => p.future } - + + /** Creates a new `Future[S]` which is completed with this `Future`'s result if + * that conforms to `S`'s erased type or a `ClassCastException` otherwise. + */ + def mapTo[S](implicit m: Manifest[S]): Future[S] = { + val p = newPromise[S] + + onComplete { + case l: Failure[_] => p complete l.asInstanceOf[Try[S]] + case Success(t) => + p complete (try { + Success(impl.Future.boxedType(m.erasure).cast(t).asInstanceOf[S]) + } catch { + case e: ClassCastException => Failure(e) + }) + } + + p.future + } + /** Applies the side-effecting function to the result of this future, and returns * a new future with the result of this future. * diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 5dc440f42b..2cfd6f22cd 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -10,7 +10,7 @@ package scala.concurrent.impl -import java.util.concurrent.{Callable, ExecutorService} +import java.util.concurrent.{Callable, ExecutorService, Executors, ThreadFactory} import scala.concurrent.forkjoin._ import scala.concurrent.{ExecutionContext, resolver, Awaitable, body2awaitable} import scala.util.{ Try, Success, Failure } @@ -18,8 +18,42 @@ import scala.concurrent.util.{ Duration } -private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends ExecutionContext { +private[scala] class ExecutionContextImpl() extends ExecutionContext { import ExecutionContextImpl._ + + val executorService: AnyRef = getExecutorService + + // to ensure that the current execution context thread local is properly set + private def executorsThreadFactory = new ThreadFactory { + def newThread(r: Runnable) = new Thread(new Runnable { + override def run() { + currentExecutionContext.set(ExecutionContextImpl.this) + r.run() + } + }) + } + + // to ensure that the current execution context thread local is properly set + private def forkJoinPoolThreadFactory = new ForkJoinPool.ForkJoinWorkerThreadFactory { + def newThread(fjp: ForkJoinPool) = new ForkJoinWorkerThread(fjp) { + override def onStart() { + currentExecutionContext.set(ExecutionContextImpl.this) + } + } + } + + private def getExecutorService: AnyRef = + if (scala.util.Properties.isJavaAtLeast("1.6")) { + val vendor = scala.util.Properties.javaVmVendor + if ((vendor contains "Oracle") || (vendor contains "Sun") || (vendor contains "Apple")) + new ForkJoinPool( + Runtime.getRuntime.availableProcessors(), + forkJoinPoolThreadFactory, + null, + false) + else + Executors.newCachedThreadPool(executorsThreadFactory) + } else Executors.newCachedThreadPool(executorsThreadFactory) def execute(runnable: Runnable): Unit = executorService match { case fj: ForkJoinPool => @@ -37,9 +71,7 @@ private[scala] class ExecutionContextImpl(val executorService: AnyRef) extends E def run() = body() }) - def blocking[T](body: =>T): T = blocking(body2awaitable(body), Duration.fromNanos(0)) - - def blocking[T](awaitable: Awaitable[T], atMost: Duration): T = { + def internalBlockingCall[T](awaitable: Awaitable[T], atMost: Duration): T = { Future.releaseStack(this) awaitable.result(atMost)(scala.concurrent.Await.canAwaitEvidence) diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala index 6833b2467f..1111aa4753 100644 --- a/src/library/scala/concurrent/impl/Future.scala +++ b/src/library/scala/concurrent/impl/Future.scala @@ -40,36 +40,6 @@ private[concurrent] trait Future[+T] extends scala.concurrent.Future[T] with Awa def onComplete[U](func: Try[T] => U): this.type - /** Creates a new Future[A] which is completed with this Future's result if - * that conforms to A's erased type or a ClassCastException otherwise. - */ - final def mapTo[T](implicit m: Manifest[T]) = { - val p = new Promise.DefaultPromise[T] - - onComplete { - case f @ Failure(t) => p complete f.asInstanceOf[Try[T]] - case Success(v) => - p complete (try { - Success(Future.boxedType(m.erasure).cast(v).asInstanceOf[T]) - } catch { - case e: ClassCastException => Failure(e) - }) - } - - p.future - } - - /** Used by for-comprehensions. - */ - final def withFilter(p: T => Boolean) = new FutureWithFilter[T](this, p) - - final class FutureWithFilter[+A](self: Future[A], p: A => Boolean) { - def foreach(f: A => Unit): Unit = self filter p foreach f - def map[B](f: A => B) = self filter p map f - def flatMap[B](f: A => Future[B]) = self filter p flatMap f - def withFilter(q: A => Boolean): FutureWithFilter[A] = new FutureWithFilter[A](self, x ⇒ p(x) && q(x)) - } - } object Future { diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index c79b0d02cc..f05e306088 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -127,7 +127,7 @@ object Promise { value.isDefined } - executor.blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), atMost) + blocking(concurrent.body2awaitable(awaitUnsafe(dur2long(atMost))), atMost) } def ready(atMost: Duration)(implicit permit: CanAwait): this.type = 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 |