diff options
Diffstat (limited to 'src/library')
412 files changed, 9302 insertions, 5119 deletions
diff --git a/src/library/rootdoc.txt b/src/library/rootdoc.txt index e84942b8c4..0aef41c4da 100644 --- a/src/library/rootdoc.txt +++ b/src/library/rootdoc.txt @@ -37,19 +37,14 @@ Notable packages include: - [[scala.sys `scala.sys`]] - Interaction with other processes and the operating system - [[scala.util.matching `scala.util.matching`]] - [[scala.util.matching.Regex Regular expressions]] -Other packages exist. See the complete list on the left. +Other packages exist. See the complete list on the right. Additional parts of the standard library are shipped as separate libraries. These include: - [[scala.reflect `scala.reflect`]] - Scala's reflection API (scala-reflect.jar) - [[scala.xml `scala.xml`]] - XML parsing, manipulation, and serialization (scala-xml.jar) - [[scala.swing `scala.swing`]] - A convenient wrapper around Java's GUI framework called Swing (scala-swing.jar) - - [[scala.util.continuations `scala.util.continuations`]] - Delimited continuations using continuation-passing-style - (scala-continuations-library.jar, scala-continuations-plugin.jar) - - [[scala.util.parsing `scala.util.parsing`]] - [[scala.util.parsing.combinator Parser combinators]], including an - example implementation of a [[scala.util.parsing.json JSON parser]] (scala-parser-combinators.jar) - - [[scala.actors `scala.actors`]] - Actor-based concurrency (deprecated and replaced by Akka actors, - scala-actors.jar) + - [[scala.util.parsing `scala.util.parsing`]] - Parser combinators (scala-parser-combinators.jar) == Automatic imports == diff --git a/src/library/scala/App.scala b/src/library/scala/App.scala index 62245322da..52ef9ca60f 100644 --- a/src/library/scala/App.scala +++ b/src/library/scala/App.scala @@ -59,7 +59,7 @@ trait App extends DelayedInit { * themselves define a `delayedInit` method. * @param body the initialization code to be stored for later execution */ - @deprecated("The delayedInit mechanism will disappear.", "2.11.0") + @deprecated("the delayedInit mechanism will disappear", "2.11.0") override def delayedInit(body: => Unit) { initCode += (() => body) } diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index d89e9d291d..5d1c25732c 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -11,7 +11,6 @@ package scala import scala.collection.generic._ import scala.collection.{ mutable, immutable } import mutable.{ ArrayBuilder, ArraySeq } -import scala.compat.Platform.arraycopy import scala.reflect.ClassTag import scala.runtime.ScalaRunTime.{ array_apply, array_update } @@ -102,7 +101,7 @@ object Array extends FallbackArrayBuilding { def copy(src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int) { val srcClass = src.getClass if (srcClass.isArray && dest.getClass.isAssignableFrom(srcClass)) - arraycopy(src, srcPos, dest, destPos, length) + java.lang.System.arraycopy(src, srcPos, dest, destPos, length) else slowcopy(src, srcPos, dest, destPos, length) } @@ -486,6 +485,27 @@ object Array extends FallbackArrayBuilding { * @see [[http://www.scala-lang.org/files/archive/spec/2.11/ Scala Language Specification]], for in-depth information on the transformations the Scala compiler makes on Arrays (Sections 6.6 and 6.15 respectively.) * @see [[http://docs.scala-lang.org/sips/completed/scala-2-8-arrays.html "Scala 2.8 Arrays"]] the Scala Improvement Document detailing arrays since Scala 2.8. * @see [[http://docs.scala-lang.org/overviews/collections/arrays.html "The Scala 2.8 Collections' API"]] section on `Array` by Martin Odersky for more information. + * @hideImplicitConversion scala.Predef.booleanArrayOps + * @hideImplicitConversion scala.Predef.byteArrayOps + * @hideImplicitConversion scala.Predef.charArrayOps + * @hideImplicitConversion scala.Predef.doubleArrayOps + * @hideImplicitConversion scala.Predef.floatArrayOps + * @hideImplicitConversion scala.Predef.intArrayOps + * @hideImplicitConversion scala.Predef.longArrayOps + * @hideImplicitConversion scala.Predef.refArrayOps + * @hideImplicitConversion scala.Predef.shortArrayOps + * @hideImplicitConversion scala.Predef.unitArrayOps + * @hideImplicitConversion scala.LowPriorityImplicits.wrapRefArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapIntArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapDoubleArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapLongArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapFloatArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapCharArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapByteArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapShortArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapBooleanArray + * @hideImplicitConversion scala.LowPriorityImplicits.wrapUnitArray + * @hideImplicitConversion scala.LowPriorityImplicits.genericWrapArray * @define coll array * @define Coll `Array` * @define orderDependent diff --git a/src/library/scala/Boolean.scala b/src/library/scala/Boolean.scala index 53b4fb2af2..017f10a283 100644 --- a/src/library/scala/Boolean.scala +++ b/src/library/scala/Boolean.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -102,7 +102,8 @@ final abstract class Boolean private extends AnyVal { */ def ^(x: Boolean): Boolean - override def getClass(): Class[Boolean] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Boolean] = ??? } object Boolean extends AnyValCompanion { @@ -114,7 +115,7 @@ object Boolean extends AnyValCompanion { * @param x the Boolean to be boxed * @return a java.lang.Boolean offering `x` as its underlying value. */ - def box(x: Boolean): java.lang.Boolean = java.lang.Boolean.valueOf(x) + def box(x: Boolean): java.lang.Boolean = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -126,7 +127,7 @@ object Boolean extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Boolean * @return the Boolean resulting from calling booleanValue() on `x` */ - def unbox(x: java.lang.Object): Boolean = x.asInstanceOf[java.lang.Boolean].booleanValue() + def unbox(x: java.lang.Object): Boolean = ??? /** The String representation of the scala.Boolean companion object. */ override def toString = "object scala.Boolean" diff --git a/src/library/scala/Byte.scala b/src/library/scala/Byte.scala index fb662911b3..3709586f2e 100644 --- a/src/library/scala/Byte.scala +++ b/src/library/scala/Byte.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -434,7 +434,8 @@ final abstract class Byte private extends AnyVal { /** Returns the remainder of the division of this value by `x`. */ def %(x: Double): Double - override def getClass(): Class[Byte] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Byte] = ??? } object Byte extends AnyValCompanion { @@ -451,7 +452,7 @@ object Byte extends AnyValCompanion { * @param x the Byte to be boxed * @return a java.lang.Byte offering `x` as its underlying value. */ - def box(x: Byte): java.lang.Byte = java.lang.Byte.valueOf(x) + def box(x: Byte): java.lang.Byte = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -463,7 +464,7 @@ object Byte extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Byte * @return the Byte resulting from calling byteValue() on `x` */ - def unbox(x: java.lang.Object): Byte = x.asInstanceOf[java.lang.Byte].byteValue() + def unbox(x: java.lang.Object): Byte = ??? /** The String representation of the scala.Byte companion object. */ override def toString = "object scala.Byte" diff --git a/src/library/scala/Char.scala b/src/library/scala/Char.scala index 9f06503569..7dbb0209c3 100644 --- a/src/library/scala/Char.scala +++ b/src/library/scala/Char.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -434,7 +434,8 @@ final abstract class Char private extends AnyVal { /** Returns the remainder of the division of this value by `x`. */ def %(x: Double): Double - override def getClass(): Class[Char] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Char] = ??? } object Char extends AnyValCompanion { @@ -451,7 +452,7 @@ object Char extends AnyValCompanion { * @param x the Char to be boxed * @return a java.lang.Character offering `x` as its underlying value. */ - def box(x: Char): java.lang.Character = java.lang.Character.valueOf(x) + def box(x: Char): java.lang.Character = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -463,7 +464,7 @@ object Char extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Character * @return the Char resulting from calling charValue() on `x` */ - def unbox(x: java.lang.Object): Char = x.asInstanceOf[java.lang.Character].charValue() + def unbox(x: java.lang.Object): Char = ??? /** The String representation of the scala.Char companion object. */ override def toString = "object scala.Char" diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala index 37127a93d5..bc702cfaad 100644 --- a/src/library/scala/Console.scala +++ b/src/library/scala/Console.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2003-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -12,12 +12,115 @@ import java.io.{ BufferedReader, InputStream, InputStreamReader, OutputStream, P import scala.io.{ AnsiColor, StdIn } import scala.util.DynamicVariable -/** Implements functionality for - * printing Scala values on the terminal as well as reading specific values. +/** Implements functionality for printing Scala values on the terminal. For reading values + * use [[scala.io.StdIn$ StdIn]]. * Also defines constants for marking up text on ANSI terminals. * + * == Console Output == + * + * Use the print methods to output text. + * {{{ + * scala> Console.printf( + * "Today the outside temperature is a balmy %.1f°C. %<.1f°C beats the previous record of %.1f°C.\n", + * -137.0, + * -135.05) + * Today the outside temperature is a balmy -137.0°C. -137.0°C beats the previous record of -135.1°C. + * }}} + * + * == ANSI escape codes == + * Use the ANSI escape codes for colorizing console output either to STDOUT or STDERR. + * {{{ + * import Console.{GREEN, RED, RESET, YELLOW_B, UNDERLINED} + * + * object PrimeTest { + * + * def isPrime(): Unit = { + * + * val candidate = io.StdIn.readInt().ensuring(_ > 1) + * + * val prime = (2 to candidate - 1).forall(candidate % _ != 0) + * + * if (prime) + * Console.println(s"${RESET}${GREEN}yes${RESET}") + * else + * Console.err.println(s"${RESET}${YELLOW_B}${RED}${UNDERLINED}NO!${RESET}") + * } + * + * def main(args: Array[String]): Unit = isPrime() + * + * } + * }}} + * + * <table style="border: 10px solid #000;width:100%"> + * <tr><td style="background-color:#000;color:#fff">$ scala PrimeTest</td></tr> + * <tr><td style="background-color:#000;color:#fff">1234567891</td></tr> + * <tr><td style="background-color:#000;color:#0f0">yes</td></tr> + * <tr><td style="background-color:#000;color:#fff">$ scala PrimeTest</td></tr> + * <tr><td style="background-color:#000;color:#fff">56474</td></tr> + * <tr><td style="background-color:#000;color:#fff"><span style="background-color:#ff0;color:#f00;text-decoration:underline">NO!</span></td></tr> + * </table> + * + * == IO redefinition == + * + * Use IO redefinition to temporarily swap in a different set of input and/or output streams. In this example the stream based + * method above is wrapped into a function. + * + * {{{ + * import java.io.{ByteArrayOutputStream, StringReader} + * + * object FunctionalPrimeTest { + * + * def isPrime(candidate: Int): Boolean = { + * + * val input = new StringReader(s"$candidate\n") + * val outCapture = new ByteArrayOutputStream + * val errCapture = new ByteArrayOutputStream + * + * Console.withIn(input) { + * Console.withOut(outCapture) { + * Console.withErr(errCapture) { + * PrimeTest.isPrime() + * } + * } + * } + * + * if (outCapture.toByteArray.nonEmpty) // "yes" + * true + * else if (errCapture.toByteArray.nonEmpty) // "NO!" + * false + * else throw new IllegalArgumentException(candidate.toString) + * } + * + * def main(args: Array[String]): Unit = { + * val primes = (2 to 50) filter (isPrime) + * println(s"First primes: $primes") + * } + * + * } + * }}} + * + * + * <table style="border: 10px solid #000;width:100%"> + * <tr><td style="background-color:#000;color:#fff">$ scala FunctionalPrimeTest</td></tr> + * <tr><td style="background-color:#000;color:#fff">First primes: Vector(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47)</td></tr> + * </table> + * * @author Matthias Zenger * @version 1.0, 03/09/2003 + * + * @groupname console-output Console Output + * @groupprio console-output 30 + * @groupdesc console-output These methods provide output via the console. + * + * @groupname io-default IO Defaults + * @groupprio io-default 50 + * @groupdesc io-default These values provide direct access to the standard IO channels + * + * @groupname io-redefinition IO Redefinition + * @groupprio io-redefinition 60 + * @groupdesc io-redefinition These methods allow substituting alternative streams for the duration of + * a body of code. Threadsafe by virtue of [[scala.util.DynamicVariable]]. + * */ object Console extends DeprecatedConsole with AnsiColor { private val outVar = new DynamicVariable[PrintStream](java.lang.System.out) @@ -29,11 +132,17 @@ object Console extends DeprecatedConsole with AnsiColor { protected def setErrDirect(err: PrintStream): Unit = errVar.value = err protected def setInDirect(in: BufferedReader): Unit = inVar.value = in - /** The default output, can be overridden by `setOut` */ + /** The default output, can be overridden by `withOut` + * @group io-default + */ def out = outVar.value - /** The default error, can be overridden by `setErr` */ + /** The default error, can be overridden by `withErr` + * @group io-default + */ def err = errVar.value - /** The default input, can be overridden by `setIn` */ + /** The default input, can be overridden by `withIn` + * @group io-default + */ def in = inVar.value /** Sets the default output stream for the duration @@ -48,6 +157,7 @@ object Console extends DeprecatedConsole with AnsiColor { * the new output stream active * @return the results of `thunk` * @see `withOut[T](out:OutputStream)(thunk: => T)` + * @group io-redefinition */ def withOut[T](out: PrintStream)(thunk: =>T): T = outVar.withValue(out)(thunk) @@ -60,6 +170,7 @@ object Console extends DeprecatedConsole with AnsiColor { * the new output stream active * @return the results of `thunk` * @see `withOut[T](out:PrintStream)(thunk: => T)` + * @group io-redefinition */ def withOut[T](out: OutputStream)(thunk: =>T): T = withOut(new PrintStream(out))(thunk) @@ -67,7 +178,7 @@ object Console extends DeprecatedConsole with AnsiColor { /** Set the default error stream for the duration * of execution of one thunk. * @example {{{ - * withErr(Console.out) { println("This goes to default _out_") } + * withErr(Console.out) { err.println("This goes to default _out_") } * }}} * * @param err the new error stream. @@ -75,6 +186,7 @@ object Console extends DeprecatedConsole with AnsiColor { * the new error stream active * @return the results of `thunk` * @see `withErr[T](err:OutputStream)(thunk: =>T)` + * @group io-redefinition */ def withErr[T](err: PrintStream)(thunk: =>T): T = errVar.withValue(err)(thunk) @@ -87,6 +199,7 @@ object Console extends DeprecatedConsole with AnsiColor { * the new error stream active * @return the results of `thunk` * @see `withErr[T](err:PrintStream)(thunk: =>T)` + * @group io-redefinition */ def withErr[T](err: OutputStream)(thunk: =>T): T = withErr(new PrintStream(err))(thunk) @@ -105,8 +218,9 @@ object Console extends DeprecatedConsole with AnsiColor { * @param thunk the code to execute with * the new input stream active * - * @return the results of `thunk` - * @see `withIn[T](in:InputStream)(thunk: =>T)` + * @return the results of `thunk` + * @see `withIn[T](in:InputStream)(thunk: =>T)` + * @group io-redefinition */ def withIn[T](reader: Reader)(thunk: =>T): T = inVar.withValue(new BufferedReader(reader))(thunk) @@ -117,8 +231,9 @@ object Console extends DeprecatedConsole with AnsiColor { * @param in the new input stream. * @param thunk the code to execute with * the new input stream active - * @return the results of `thunk` - * @see `withIn[T](reader:Reader)(thunk: =>T)` + * @return the results of `thunk` + * @see `withIn[T](reader:Reader)(thunk: =>T)` + * @group io-redefinition */ def withIn[T](in: InputStream)(thunk: =>T): T = withIn(new InputStreamReader(in))(thunk) @@ -126,6 +241,7 @@ object Console extends DeprecatedConsole with AnsiColor { /** Prints an object to `out` using its `toString` method. * * @param obj the object to print; may be null. + * @group console-output */ def print(obj: Any) { out.print(if (null == obj) "null" else obj.toString()) @@ -134,29 +250,31 @@ object Console extends DeprecatedConsole with AnsiColor { /** Flushes the output stream. This function is required when partial * output (i.e. output not terminated by a newline character) has * to be made visible on the terminal. + * @group console-output */ def flush() { out.flush() } /** Prints a newline character on the default output. + * @group console-output */ def println() { out.println() } /** Prints out an object to the default output, followed by a newline character. * * @param x the object to print. + * @group console-output */ def println(x: Any) { out.println(x) } /** Prints its arguments as a formatted string to the default output, * based on a string pattern (in a fashion similar to printf in C). * - * The interpretation of the formatting patterns is described in - * <a href="" target="contentFrame" class="java/util/Formatter"> - * `java.util.Formatter`</a>. + * The interpretation of the formatting patterns is described in [[java.util.Formatter]]. * * @param text the pattern for formatting the arguments. * @param args the arguments used to instantiating the pattern. * @throws java.lang.IllegalArgumentException if there was a problem with the format string or arguments + * @group console-output */ def printf(text: String, args: Any*) { out.print(text format (args : _*)) } } @@ -169,54 +287,54 @@ private[scala] abstract class DeprecatedConsole { protected def setErrDirect(err: PrintStream): Unit protected def setInDirect(in: BufferedReader): Unit - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readBoolean(): Boolean = StdIn.readBoolean() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readByte(): Byte = StdIn.readByte() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readChar(): Char = StdIn.readChar() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readDouble(): Double = StdIn.readDouble() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readFloat(): Float = StdIn.readFloat() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readInt(): Int = StdIn.readInt() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readLine(): String = StdIn.readLine() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readLine(text: String, args: Any*): String = StdIn.readLine(text, args: _*) - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readLong(): Long = StdIn.readLong() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readShort(): Short = StdIn.readShort() - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf(format: String): List[Any] = StdIn.readf(format) - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf1(format: String): Any = StdIn.readf1(format) - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf2(format: String): (Any, Any) = StdIn.readf2(format) - @deprecated("Use the method in scala.io.StdIn", "2.11.0") def readf3(format: String): (Any, Any, Any) = StdIn.readf3(format) + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readBoolean(): Boolean = StdIn.readBoolean() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readByte(): Byte = StdIn.readByte() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readChar(): Char = StdIn.readChar() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readDouble(): Double = StdIn.readDouble() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readFloat(): Float = StdIn.readFloat() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readInt(): Int = StdIn.readInt() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readLine(): String = StdIn.readLine() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readLine(text: String, args: Any*): String = StdIn.readLine(text, args: _*) + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readLong(): Long = StdIn.readLong() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readShort(): Short = StdIn.readShort() + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readf(format: String): List[Any] = StdIn.readf(format) + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readf1(format: String): Any = StdIn.readf1(format) + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readf2(format: String): (Any, Any) = StdIn.readf2(format) + @deprecated("use the method in scala.io.StdIn", "2.11.0") def readf3(format: String): (Any, Any, Any) = StdIn.readf3(format) /** Sets the default output stream. * * @param out the new output stream. */ - @deprecated("Use withOut", "2.11.0") def setOut(out: PrintStream): Unit = setOutDirect(out) + @deprecated("use withOut", "2.11.0") def setOut(out: PrintStream): Unit = setOutDirect(out) /** Sets the default output stream. * * @param out the new output stream. */ - @deprecated("Use withOut", "2.11.0") def setOut(out: OutputStream): Unit = setOutDirect(new PrintStream(out)) + @deprecated("use withOut", "2.11.0") def setOut(out: OutputStream): Unit = setOutDirect(new PrintStream(out)) /** Sets the default error stream. * * @param err the new error stream. */ - @deprecated("Use withErr", "2.11.0") def setErr(err: PrintStream): Unit = setErrDirect(err) + @deprecated("use withErr", "2.11.0") def setErr(err: PrintStream): Unit = setErrDirect(err) /** Sets the default error stream. * * @param err the new error stream. */ - @deprecated("Use withErr", "2.11.0") def setErr(err: OutputStream): Unit = setErrDirect(new PrintStream(err)) + @deprecated("use withErr", "2.11.0") def setErr(err: OutputStream): Unit = setErrDirect(new PrintStream(err)) /** Sets the default input stream. * * @param reader specifies the new input stream. */ - @deprecated("Use withIn", "2.11.0") def setIn(reader: Reader): Unit = setInDirect(new BufferedReader(reader)) + @deprecated("use withIn", "2.11.0") def setIn(reader: Reader): Unit = setInDirect(new BufferedReader(reader)) /** Sets the default input stream. * * @param in the new input stream. */ - @deprecated("Use withIn", "2.11.0") def setIn(in: InputStream): Unit = setInDirect(new BufferedReader(new InputStreamReader(in))) + @deprecated("use withIn", "2.11.0") def setIn(in: InputStream): Unit = setInDirect(new BufferedReader(new InputStreamReader(in))) } diff --git a/src/library/scala/DelayedInit.scala b/src/library/scala/DelayedInit.scala index 7f976b073f..8dc841a7e3 100644 --- a/src/library/scala/DelayedInit.scala +++ b/src/library/scala/DelayedInit.scala @@ -43,7 +43,7 @@ package scala * * @author Martin Odersky */ -@deprecated("DelayedInit semantics can be surprising. Support for `App` will continue.\nSee the release notes for more details: https://github.com/scala/scala/releases/tag/v2.11.0-RC1", "2.11.0") +@deprecated("DelayedInit semantics can be surprising. Support for `App` will continue. See the release notes for more details: https://github.com/scala/scala/releases/tag/v2.11.0-RC1", "2.11.0") trait DelayedInit { def delayedInit(x: => Unit): Unit -}
\ No newline at end of file +} diff --git a/src/library/scala/Double.scala b/src/library/scala/Double.scala index a58fa3ed25..08bcb9fefc 100644 --- a/src/library/scala/Double.scala +++ b/src/library/scala/Double.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -200,7 +200,8 @@ final abstract class Double private extends AnyVal { /** Returns the remainder of the division of this value by `x`. */ def %(x: Double): Double - override def getClass(): Class[Double] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Double] = ??? } object Double extends AnyValCompanion { @@ -229,7 +230,7 @@ object Double extends AnyValCompanion { * @param x the Double to be boxed * @return a java.lang.Double offering `x` as its underlying value. */ - def box(x: Double): java.lang.Double = java.lang.Double.valueOf(x) + def box(x: Double): java.lang.Double = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -241,7 +242,7 @@ object Double extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Double * @return the Double resulting from calling doubleValue() on `x` */ - def unbox(x: java.lang.Object): Double = x.asInstanceOf[java.lang.Double].doubleValue() + def unbox(x: java.lang.Object): Double = ??? /** The String representation of the scala.Double companion object. */ override def toString = "object scala.Double" diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala index c4aa511cd7..9d9a3f849b 100644 --- a/src/library/scala/Enumeration.scala +++ b/src/library/scala/Enumeration.scala @@ -9,7 +9,7 @@ package scala import scala.collection.{ mutable, immutable, generic, SortedSetLike, AbstractSet } -import java.lang.reflect.{ Modifier, Method => JMethod, Field => JField } +import java.lang.reflect.{ Method => JMethod, Field => JField } import scala.reflect.NameTransformer._ import scala.util.matching.Regex @@ -154,14 +154,14 @@ abstract class Enumeration (initial: Int) extends Serializable { protected final def Value(i: Int, name: String): Value = new Val(i, name) private def populateNameMap() { - val fields = getClass.getDeclaredFields - def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType) + val fields: Array[JField] = getClass.getDeclaredFields + def isValDef(m: JMethod): Boolean = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType) // The list of possible Value methods: 0-args which return a conforming type - val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty && - classOf[Value].isAssignableFrom(m.getReturnType) && - m.getDeclaringClass != classOf[Enumeration] && - isValDef(m)) + val methods: Array[JMethod] = getClass.getMethods filter (m => m.getParameterTypes.isEmpty && + classOf[Value].isAssignableFrom(m.getReturnType) && + m.getDeclaringClass != classOf[Enumeration] && + isValDef(m)) methods foreach { m => val name = m.getName // invoke method to obtain actual `Value` instance diff --git a/src/library/scala/Float.scala b/src/library/scala/Float.scala index 3c59057a8d..01fdbc00e4 100644 --- a/src/library/scala/Float.scala +++ b/src/library/scala/Float.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -200,7 +200,8 @@ final abstract class Float private extends AnyVal { /** Returns the remainder of the division of this value by `x`. */ def %(x: Double): Double - override def getClass(): Class[Float] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Float] = ??? } object Float extends AnyValCompanion { @@ -229,7 +230,7 @@ object Float extends AnyValCompanion { * @param x the Float to be boxed * @return a java.lang.Float offering `x` as its underlying value. */ - def box(x: Float): java.lang.Float = java.lang.Float.valueOf(x) + def box(x: Float): java.lang.Float = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -241,7 +242,7 @@ object Float extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Float * @return the Float resulting from calling floatValue() on `x` */ - def unbox(x: java.lang.Object): Float = x.asInstanceOf[java.lang.Float].floatValue() + def unbox(x: java.lang.Object): Float = ??? /** The String representation of the scala.Float companion object. */ override def toString = "object scala.Float" diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala index 7bd12a2719..f28897c20b 100644 --- a/src/library/scala/Function.scala +++ b/src/library/scala/Function.scala @@ -72,7 +72,7 @@ object Function { * @note These functions are slotted for deprecation, but it is on * hold pending superior type inference for tupling anonymous functions. */ - // @deprecated("Use `f.tupled` instead") + // @deprecated("use `f.tupled` instead") def tupled[a1, a2, b](f: (a1, a2) => b): Tuple2[a1, a2] => b = { case Tuple2(x1, x2) => f(x1, x2) } @@ -80,7 +80,7 @@ object Function { /** Tupling for functions of arity 3. This transforms a function * of arity 3 into a unary function that takes a triple of arguments. */ - // @deprecated("Use `f.tupled` instead") + // @deprecated("use `f.tupled` instead") def tupled[a1, a2, a3, b](f: (a1, a2, a3) => b): Tuple3[a1, a2, a3] => b = { case Tuple3(x1, x2, x3) => f(x1, x2, x3) } @@ -88,7 +88,7 @@ object Function { /** Tupling for functions of arity 4. This transforms a function * of arity 4 into a unary function that takes a 4-tuple of arguments. */ - // @deprecated("Use `f.tupled` instead") + // @deprecated("use `f.tupled` instead") def tupled[a1, a2, a3, a4, b](f: (a1, a2, a3, a4) => b): Tuple4[a1, a2, a3, a4] => b = { case Tuple4(x1, x2, x3, x4) => f(x1, x2, x3, x4) } @@ -96,7 +96,7 @@ object Function { /** Tupling for functions of arity 5. This transforms a function * of arity 5 into a unary function that takes a 5-tuple of arguments. */ - // @deprecated("Use `f.tupled` instead") + // @deprecated("use `f.tupled` instead") def tupled[a1, a2, a3, a4, a5, b](f: (a1, a2, a3, a4, a5) => b): Tuple5[a1, a2, a3, a4, a5] => b = { case Tuple5(x1, x2, x3, x4, x5) => f(x1, x2, x3, x4, x5) } diff --git a/src/library/scala/Immutable.scala b/src/library/scala/Immutable.scala index fead590ef6..c7e96a46a0 100644 --- a/src/library/scala/Immutable.scala +++ b/src/library/scala/Immutable.scala @@ -10,7 +10,7 @@ package scala -/** A marker trait for all immutable datastructures such as immutable +/** A marker trait for all immutable data structures such as immutable * collections. * * @since 2.8 diff --git a/src/library/scala/Int.scala b/src/library/scala/Int.scala index 3bd3775eba..491094cfde 100644 --- a/src/library/scala/Int.scala +++ b/src/library/scala/Int.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -434,14 +434,15 @@ final abstract class Int private extends AnyVal { /** Returns the remainder of the division of this value by `x`. */ def %(x: Double): Double - override def getClass(): Class[Int] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Int] = ??? } object Int extends AnyValCompanion { - /** The smallest value representable as a Int. */ + /** The smallest value representable as an Int. */ final val MinValue = java.lang.Integer.MIN_VALUE - /** The largest value representable as a Int. */ + /** The largest value representable as an Int. */ final val MaxValue = java.lang.Integer.MAX_VALUE /** Transform a value type into a boxed reference type. @@ -451,7 +452,7 @@ object Int extends AnyValCompanion { * @param x the Int to be boxed * @return a java.lang.Integer offering `x` as its underlying value. */ - def box(x: Int): java.lang.Integer = java.lang.Integer.valueOf(x) + def box(x: Int): java.lang.Integer = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -463,7 +464,7 @@ object Int extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Integer * @return the Int resulting from calling intValue() on `x` */ - def unbox(x: java.lang.Object): Int = x.asInstanceOf[java.lang.Integer].intValue() + def unbox(x: java.lang.Object): Int = ??? /** The String representation of the scala.Int companion object. */ override def toString = "object scala.Int" diff --git a/src/library/scala/Long.scala b/src/library/scala/Long.scala index b27a66647f..84e6f09da3 100644 --- a/src/library/scala/Long.scala +++ b/src/library/scala/Long.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -434,7 +434,8 @@ final abstract class Long private extends AnyVal { /** Returns the remainder of the division of this value by `x`. */ def %(x: Double): Double - override def getClass(): Class[Long] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Long] = ??? } object Long extends AnyValCompanion { @@ -451,7 +452,7 @@ object Long extends AnyValCompanion { * @param x the Long to be boxed * @return a java.lang.Long offering `x` as its underlying value. */ - def box(x: Long): java.lang.Long = java.lang.Long.valueOf(x) + def box(x: Long): java.lang.Long = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -463,7 +464,7 @@ object Long extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Long * @return the Long resulting from calling longValue() on `x` */ - def unbox(x: java.lang.Object): Long = x.asInstanceOf[java.lang.Long].longValue() + def unbox(x: java.lang.Object): Long = ??? /** The String representation of the scala.Long companion object. */ override def toString = "object scala.Long" diff --git a/src/library/scala/NotNull.scala b/src/library/scala/NotNull.scala index 3cbe9ed4ac..6a9be79281 100644 --- a/src/library/scala/NotNull.scala +++ b/src/library/scala/NotNull.scala @@ -13,5 +13,5 @@ package scala * @since 2.5 */ -@deprecated("This trait will be removed", "2.11.0") +@deprecated("this trait will be removed", "2.11.0") trait NotNull extends Any {} diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index 7282feebb6..c7894a45b8 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -107,7 +107,7 @@ sealed abstract class Option[+A] extends Product with Serializable { def isDefined: Boolean = !isEmpty /** Returns the option's value. - * @note The option must be nonEmpty. + * @note The option must be nonempty. * @throws java.util.NoSuchElementException if the option is empty. */ def get: A @@ -330,9 +330,11 @@ sealed abstract class Option[+A] extends Product with Serializable { * @version 1.0, 16/07/2003 */ @SerialVersionUID(1234815782226070388L) // value computed by serialver for 2.11.2, annotation added in 2.11.4 -final case class Some[+A](x: A) extends Option[A] { +final case class Some[+A](@deprecatedName('x, "2.12.0") value: A) extends Option[A] { def isEmpty = false - def get = x + def get = value + + @deprecated("Use .value instead.", "2.12.0") def x: A = value } diff --git a/src/library/scala/PartialFunction.scala b/src/library/scala/PartialFunction.scala index fba759eb32..c1a413d516 100644 --- a/src/library/scala/PartialFunction.scala +++ b/src/library/scala/PartialFunction.scala @@ -20,7 +20,7 @@ package scala * {{{ * val f: PartialFunction[Int, Any] = { case _ => 1/0 } * }}} - * + * * It is the responsibility of the caller to call `isDefinedAt` before * calling `apply`, because if `isDefinedAt` is false, it is not guaranteed * `apply` will throw an exception to indicate an error condition. If an @@ -161,10 +161,11 @@ trait PartialFunction[-A, +B] extends (A => B) { self => object PartialFunction { /** Composite function produced by `PartialFunction#orElse` method */ - private class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) extends PartialFunction[A, B] { + private class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B]) + extends scala.runtime.AbstractPartialFunction[A, B] with Serializable { def isDefinedAt(x: A) = f1.isDefinedAt(x) || f2.isDefinedAt(x) - def apply(x: A): B = f1.applyOrElse(x, f2) + override def apply(x: A): B = f1.applyOrElse(x, f2) override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = { val z = f1.applyOrElse(x, checkFallback[B]) @@ -180,7 +181,7 @@ object PartialFunction { /** Composite function produced by `PartialFunction#andThen` method */ - private class AndThen[-A, B, +C] (pf: PartialFunction[A, B], k: B => C) extends PartialFunction[A, C] { + private class AndThen[-A, B, +C] (pf: PartialFunction[A, B], k: B => C) extends PartialFunction[A, C] with Serializable { def isDefinedAt(x: A) = pf.isDefinedAt(x) def apply(x: A): C = k(pf(x)) @@ -217,7 +218,7 @@ object PartialFunction { private def fallbackOccurred[B](x: B) = (fallback_pf eq x.asInstanceOf[AnyRef]) private class Lifted[-A, +B] (val pf: PartialFunction[A, B]) - extends scala.runtime.AbstractFunction1[A, Option[B]] { + extends scala.runtime.AbstractFunction1[A, Option[B]] with Serializable { def apply(x: A): Option[B] = { val z = pf.applyOrElse(x, checkFallback[B]) @@ -225,7 +226,7 @@ object PartialFunction { } } - private class Unlifted[A, B] (f: A => Option[B]) extends scala.runtime.AbstractPartialFunction[A, B] { + private class Unlifted[A, B] (f: A => Option[B]) extends scala.runtime.AbstractPartialFunction[A, B] with Serializable { def isDefinedAt(x: A): Boolean = f(x).isDefined override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = { @@ -248,7 +249,7 @@ object PartialFunction { private[this] val constFalse: Any => Boolean = { _ => false} - private[this] val empty_pf: PartialFunction[Any, Nothing] = new PartialFunction[Any, Nothing] { + private[this] val empty_pf: PartialFunction[Any, Nothing] = new PartialFunction[Any, Nothing] with Serializable { def isDefinedAt(x: Any) = false def apply(x: Any) = throw new MatchError(x) override def orElse[A1, B1](that: PartialFunction[A1, B1]) = that diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 94cb331ce1..b79fa9d732 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -8,13 +8,14 @@ package scala +import scala.language.implicitConversions + import scala.collection.{ mutable, immutable, generic } import immutable.StringOps import mutable.ArrayOps import generic.CanBuildFrom import scala.annotation.{ elidable, implicitNotFound } import scala.annotation.elidable.ASSERTION -import scala.language.{implicitConversions, existentials} import scala.io.StdIn /** The `Predef` object provides definitions that are accessible in all Scala @@ -27,13 +28,11 @@ import scala.io.StdIn * constructors ([[scala.collection.immutable.::]] and * [[scala.collection.immutable.Nil]]). * - * === Console I/O === - * Predef provides a number of simple functions for console I/O, such as - * `print`, `println`, `readLine`, `readInt`, etc. These functions are all - * aliases of the functions provided by [[scala.Console]]. + * === Console Output === + * For basic console output, `Predef` provides convenience methods [[print(x:Any* print]] and [[println(x:Any* println]], + * which are aliases of the methods in the object [[scala.Console]]. * * === Assertions === - * * A set of `assert` functions are provided for use as a way to document * and dynamically check invariants in code. Invocations of `assert` can be elided * at compile time by providing the command line option `-Xdisable-assertions`, @@ -66,6 +65,49 @@ import scala.io.StdIn * are provided for the "widening" of numeric values, for instance, converting a * Short value to a Long value as required, and to add additional higher-order * functions to Array values. These are described in more detail in the documentation of [[scala.Array]]. + * + * @groupname utilities Utility Methods + * @groupprio utilities 10 + * + * @groupname assertions Assertions + * @groupprio assertions 20 + * @groupdesc assertions These methods support program verification and runtime correctness. + * + * @groupname console-output Console Output + * @groupprio console-output 30 + * @groupdesc console-output These methods provide output via the console. + * + * @groupname type-constraints Type Constraints + * @groupprio type-constraints 40 + * @groupdesc type-constraints These entities allows constraints between types to be stipulated. + * + * @groupname aliases Aliases + * @groupprio aliases 50 + * @groupdesc aliases These aliases bring selected immutable types into scope without any imports. + * + * @groupname conversions-string String Conversions + * @groupprio conversions-string 60 + * @groupdesc conversions-string Conversions to and from String and StringOps. + * + * @groupname implicit-classes-any Implicit Classes + * @groupprio implicit-classes-any 70 + * @groupdesc implicit-classes-any These implicit classes add useful extension methods to every type. + * + * @groupname implicit-classes-char CharSequence Conversions + * @groupprio implicit-classes-char 80 + * @groupdesc implicit-classes-char These implicit classes add CharSequence methods to Array[Char] and IndexedSeq[Char] instances. + * + * @groupname conversions-java-to-anyval Java to Scala + * @groupprio conversions-java-to-anyval 90 + * @groupdesc conversions-java-to-anyval Implicit conversion from Java primitive wrapper types to Scala equivalents. + * + * @groupname conversions-anyval-to-java Scala to Java + * @groupprio conversions-anyval-to-java 100 + * @groupdesc conversions-anyval-to-java Implicit conversion from Scala AnyVals to Java primitive wrapper types equivalents. + * + * @groupname conversions-array-to-wrapped-array Array to WrappedArray + * @groupprio conversions-array-to-wrapped-array 110 + * @groupdesc conversions-array-to-wrapped-array Conversions from Arrays to WrappedArrays. */ object Predef extends LowPriorityImplicits with DeprecatedPredef { /** @@ -79,6 +121,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * val mapIntString = classOf[Map[Int,String]] * // mapIntString is java.lang.Class[Map[Int,String]] = interface scala.collection.immutable.Map * }}} + * @group utilities */ def classOf[T]: Class[T] = null // This is a stub method. The actual implementation is filled in by the compiler. @@ -86,69 +129,74 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * Java String (see the documentation corresponding to your Java version, for * example [[http://docs.oracle.com/javase/8/docs/api/java/lang/String.html]]) or * are added implicitly through [[scala.collection.immutable.StringOps]]. + * @group aliases */ type String = java.lang.String + /** @group aliases */ type Class[T] = java.lang.Class[T] // miscellaneous ----------------------------------------------------- scala.`package` // to force scala package object to be seen. scala.collection.immutable.List // to force Nil, :: to be seen. + /** @group aliases */ type Function[-A, +B] = Function1[A, B] + /** @group aliases */ type Map[A, +B] = immutable.Map[A, B] + /** @group aliases */ type Set[A] = immutable.Set[A] + /** @group aliases */ val Map = immutable.Map + /** @group aliases */ val Set = immutable.Set // Manifest types, companions, and incantations for summoning @annotation.implicitNotFound(msg = "No ClassManifest available for ${T}.") - @deprecated("Use `scala.reflect.ClassTag` instead", "2.10.0") + @deprecated("use `scala.reflect.ClassTag` instead", "2.10.0") type ClassManifest[T] = scala.reflect.ClassManifest[T] // TODO undeprecated until Scala reflection becomes non-experimental - // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") + // @deprecated("this notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") type OptManifest[T] = scala.reflect.OptManifest[T] @annotation.implicitNotFound(msg = "No Manifest available for ${T}.") // TODO undeprecated until Scala reflection becomes non-experimental - // @deprecated("Use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") + // @deprecated("use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") type Manifest[T] = scala.reflect.Manifest[T] - @deprecated("Use `scala.reflect.ClassTag` instead", "2.10.0") + @deprecated("use `scala.reflect.ClassTag` instead", "2.10.0") val ClassManifest = scala.reflect.ClassManifest // TODO undeprecated until Scala reflection becomes non-experimental - // @deprecated("Use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") + // @deprecated("use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") val Manifest = scala.reflect.Manifest // TODO undeprecated until Scala reflection becomes non-experimental - // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") + // @deprecated("this notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") val NoManifest = scala.reflect.NoManifest // TODO undeprecated until Scala reflection becomes non-experimental - // @deprecated("Use scala.reflect.classTag[T] and scala.reflect.runtime.universe.typeTag[T] instead", "2.10.0") + // @deprecated("use scala.reflect.classTag[T] and scala.reflect.runtime.universe.typeTag[T] instead", "2.10.0") def manifest[T](implicit m: Manifest[T]) = m - @deprecated("Use scala.reflect.classTag[T] instead", "2.10.0") + @deprecated("use scala.reflect.classTag[T] instead", "2.10.0") def classManifest[T](implicit m: ClassManifest[T]) = m // TODO undeprecated until Scala reflection becomes non-experimental - // @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") + // @deprecated("this notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0") def optManifest[T](implicit m: OptManifest[T]) = m // Minor variations on identity functions - def identity[A](x: A): A = x // @see `conforms` for the implicit version + /** @group utilities */ + @inline def identity[A](x: A): A = x // @see `conforms` for the implicit version + /** @group utilities */ @inline def implicitly[T](implicit e: T) = e // for summoning implicit values from the nether world -- TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero` + /** @group utilities */ @inline def locally[T](x: T): T = x // to communicate intent and avoid unmoored statements - // errors and asserts ------------------------------------------------- - - // !!! Remove this when possible - ideally for 2.11. - // We are stuck with it a while longer because sbt's compiler interface - // still calls it as of 0.12.2. - @deprecated("Use `sys.error(message)` instead", "2.9.0") - def error(message: String): Nothing = sys.error(message) + // assertions --------------------------------------------------------- /** Tests an expression, throwing an `AssertionError` if false. * Calls to this method will not be generated if `-Xelide-below` - * is at least `ASSERTION`. + * is greater than `ASSERTION`. * - * @see elidable + * @see [[scala.annotation.elidable elidable]] * @param assertion the expression to test + * @group assertions */ @elidable(ASSERTION) def assert(assertion: Boolean) { @@ -158,11 +206,12 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { /** Tests an expression, throwing an `AssertionError` if false. * Calls to this method will not be generated if `-Xelide-below` - * is at least `ASSERTION`. + * is greater than `ASSERTION`. * - * @see elidable + * @see [[scala.annotation.elidable elidable]] * @param assertion the expression to test * @param message a String to include in the failure message + * @group assertions */ @elidable(ASSERTION) @inline final def assert(assertion: Boolean, message: => Any) { @@ -174,10 +223,11 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * This method differs from assert only in the intent expressed: * assert contains a predicate which needs to be proven, while * assume contains an axiom for a static checker. Calls to this method - * will not be generated if `-Xelide-below` is at least `ASSERTION`. + * will not be generated if `-Xelide-below` is greater than `ASSERTION`. * - * @see elidable + * @see [[scala.annotation.elidable elidable]] * @param assumption the expression to test + * @group assertions */ @elidable(ASSERTION) def assume(assumption: Boolean) { @@ -189,11 +239,12 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * This method differs from assert only in the intent expressed: * assert contains a predicate which needs to be proven, while * assume contains an axiom for a static checker. Calls to this method - * will not be generated if `-Xelide-below` is at least `ASSERTION`. + * will not be generated if `-Xelide-below` is greater than `ASSERTION`. * - * @see elidable + * @see [[scala.annotation.elidable elidable]] * @param assumption the expression to test * @param message a String to include in the failure message + * @group assertions */ @elidable(ASSERTION) @inline final def assume(assumption: Boolean, message: => Any) { @@ -206,6 +257,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * for violating the condition. * * @param requirement the expression to test + * @group assertions */ def require(requirement: Boolean) { if (!requirement) @@ -218,6 +270,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * * @param requirement the expression to test * @param message a String to include in the failure message + * @group assertions */ @inline final def require(requirement: Boolean, message: => Any) { if (!requirement) @@ -226,22 +279,23 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { /** `???` can be used for marking methods that remain to be implemented. * @throws NotImplementedError + * @group utilities */ def ??? : Nothing = throw new NotImplementedError // tupling ------------------------------------------------------------ - @deprecated("Use built-in tuple syntax or Tuple2 instead", "2.11.0") + @deprecated("use built-in tuple syntax or Tuple2 instead", "2.11.0") type Pair[+A, +B] = Tuple2[A, B] - @deprecated("Use built-in tuple syntax or Tuple2 instead", "2.11.0") + @deprecated("use built-in tuple syntax or Tuple2 instead", "2.11.0") object Pair { def apply[A, B](x: A, y: B) = Tuple2(x, y) def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x) } - @deprecated("Use built-in tuple syntax or Tuple3 instead", "2.11.0") + @deprecated("use built-in tuple syntax or Tuple3 instead", "2.11.0") type Triple[+A, +B, +C] = Tuple3[A, B, C] - @deprecated("Use built-in tuple syntax or Tuple3 instead", "2.11.0") + @deprecated("use built-in tuple syntax or Tuple3 instead", "2.11.0") object Triple { def apply[A, B, C](x: A, y: B, z: C) = Tuple3(x, y, z) def unapply[A, B, C](x: Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x) @@ -249,11 +303,13 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { // implicit classes ----------------------------------------------------- + /** @group implicit-classes-any */ implicit final class ArrowAssoc[A](private val self: A) extends AnyVal { @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y) def →[B](y: B): Tuple2[A, B] = ->(y) } + /** @group implicit-classes-any */ implicit final class Ensuring[A](private val self: A) extends AnyVal { def ensuring(cond: Boolean): A = { assert(cond); self } def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); self } @@ -261,6 +317,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(self), msg); self } } + /** @group implicit-classes-any */ implicit final class StringFormat[A](private val self: A) extends AnyVal { /** Returns string formatted according to given `format` string. * Format strings are as for `String.format` @@ -269,31 +326,35 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { @inline def formatted(fmtstr: String): String = fmtstr format self } - // TODO: remove, only needed for binary compatibility of 2.11.0-RC1 with 2.11.0-M8 - // note that `private[scala]` becomes `public` in bytecode - private[scala] final class StringAdd[A](private val self: A) extends AnyVal { - def +(other: String): String = String.valueOf(self) + other - } - private[scala] def StringAdd(x: Any): Any = new StringAdd(x) - // SI-8229 retaining the pre 2.11 name for source compatibility in shadowing this implicit + /** @group implicit-classes-any */ implicit final class any2stringadd[A](private val self: A) extends AnyVal { def +(other: String): String = String.valueOf(self) + other } implicit final class RichException(private val self: Throwable) extends AnyVal { import scala.compat.Platform.EOL - @deprecated("Use Throwable#getStackTrace", "2.11.0") def getStackTraceString = self.getStackTrace().mkString("", EOL, EOL) + @deprecated("use Throwable#getStackTrace", "2.11.0") def getStackTraceString = self.getStackTrace().mkString("", EOL, EOL) } - implicit final class SeqCharSequence(val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence { + // Sadly we have to do `@deprecatedName(null, "2.12.0")` because + // `@deprecatedName(since="2.12.0")` incurs a warning about + // Usage of named or default arguments transformed this annotation constructor call into a block. + // The corresponding AnnotationInfo will contain references to local values and default getters + // instead of the actual argument trees + // and `@deprecatedName(Symbol("<none>"), "2.12.0")` crashes scalac with + // scala.reflect.internal.Symbols$CyclicReference: illegal cyclic reference involving object Symbol + // in run/repl-no-imports-no-predef-power.scala. + /** @group implicit-classes-char */ + implicit final class SeqCharSequence(@deprecated("will be made private", "2.12.0") @deprecatedName(null, "2.12.0") val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence { def length: Int = __sequenceOfChars.length def charAt(index: Int): Char = __sequenceOfChars(index) def subSequence(start: Int, end: Int): CharSequence = new SeqCharSequence(__sequenceOfChars.slice(start, end)) override def toString = __sequenceOfChars mkString "" } - implicit final class ArrayCharSequence(val __arrayOfChars: Array[Char]) extends CharSequence { + /** @group implicit-classes-char */ + implicit final class ArrayCharSequence(@deprecated("will be made private", "2.12.0") @deprecatedName(null, "2.12.0") val __arrayOfChars: Array[Char]) extends CharSequence { def length: Int = __arrayOfChars.length def charAt(index: Int): Char = __arrayOfChars(index) def subSequence(start: Int, end: Int): CharSequence = new runtime.ArrayCharSequence(__arrayOfChars, start, end) @@ -305,14 +366,47 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { def apply() = mutable.StringBuilder.newBuilder } + /** @group conversions-string */ @inline implicit def augmentString(x: String): StringOps = new StringOps(x) + /** @group conversions-string */ @inline implicit def unaugmentString(x: StringOps): String = x.repr // printing ----------------------------------------------------------- + /** Prints an object to `out` using its `toString` method. + * + * @param x the object to print; may be null. + * @group console-output + */ def print(x: Any) = Console.print(x) + + /** Prints a newline character on the default output. + * @group console-output + */ def println() = Console.println() + + /** Prints out an object to the default output, followed by a newline character. + * + * @param x the object to print. + * @group console-output + */ def println(x: Any) = Console.println(x) + + /** Prints its arguments as a formatted string to the default output, + * based on a string pattern (in a fashion similar to printf in C). + * + * The interpretation of the formatting patterns is described in + * [[java.util.Formatter]]. + * + * Consider using the [[scala.StringContext.f f interpolator]] as more type safe and idiomatic. + * + * @param text the pattern for formatting the arguments. + * @param args the arguments used to instantiating the pattern. + * @throws java.lang.IllegalArgumentException if there was a problem with the format string or arguments + * + * @see [[scala.StringContext.f StringContext.f]] + * @group console-output + */ def printf(text: String, xs: Any*) = Console.print(text.format(xs: _*)) // views -------------------------------------------------------------- @@ -334,36 +428,52 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { case null => null }).asInstanceOf[ArrayOps[T]] - implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs) - implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps.ofByte(xs) - implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps.ofChar(xs) - implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps.ofDouble(xs) - implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps.ofFloat(xs) - implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps.ofInt(xs) - implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps.ofLong(xs) - implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps.ofRef[T](xs) - implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps.ofShort(xs) - implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps.ofUnit(xs) + implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps.ofBoolean = new ArrayOps.ofBoolean(xs) + implicit def byteArrayOps(xs: Array[Byte]): ArrayOps.ofByte = new ArrayOps.ofByte(xs) + implicit def charArrayOps(xs: Array[Char]): ArrayOps.ofChar = new ArrayOps.ofChar(xs) + implicit def doubleArrayOps(xs: Array[Double]): ArrayOps.ofDouble = new ArrayOps.ofDouble(xs) + implicit def floatArrayOps(xs: Array[Float]): ArrayOps.ofFloat = new ArrayOps.ofFloat(xs) + implicit def intArrayOps(xs: Array[Int]): ArrayOps.ofInt = new ArrayOps.ofInt(xs) + implicit def longArrayOps(xs: Array[Long]): ArrayOps.ofLong = new ArrayOps.ofLong(xs) + implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps.ofRef[T] = new ArrayOps.ofRef[T](xs) + implicit def shortArrayOps(xs: Array[Short]): ArrayOps.ofShort = new ArrayOps.ofShort(xs) + implicit def unitArrayOps(xs: Array[Unit]): ArrayOps.ofUnit = new ArrayOps.ofUnit(xs) // "Autoboxing" and "Autounboxing" --------------------------------------------------- - implicit def byte2Byte(x: Byte) = java.lang.Byte.valueOf(x) - implicit def short2Short(x: Short) = java.lang.Short.valueOf(x) - implicit def char2Character(x: Char) = java.lang.Character.valueOf(x) - implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x) - implicit def long2Long(x: Long) = java.lang.Long.valueOf(x) - implicit def float2Float(x: Float) = java.lang.Float.valueOf(x) - implicit def double2Double(x: Double) = java.lang.Double.valueOf(x) - implicit def boolean2Boolean(x: Boolean) = java.lang.Boolean.valueOf(x) - - implicit def Byte2byte(x: java.lang.Byte): Byte = x.byteValue - implicit def Short2short(x: java.lang.Short): Short = x.shortValue - implicit def Character2char(x: java.lang.Character): Char = x.charValue - implicit def Integer2int(x: java.lang.Integer): Int = x.intValue - implicit def Long2long(x: java.lang.Long): Long = x.longValue - implicit def Float2float(x: java.lang.Float): Float = x.floatValue - implicit def Double2double(x: java.lang.Double): Double = x.doubleValue - implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue + /** @group conversions-anyval-to-java */ + implicit def byte2Byte(x: Byte): java.lang.Byte = x.asInstanceOf[java.lang.Byte] + /** @group conversions-anyval-to-java */ + implicit def short2Short(x: Short): java.lang.Short = x.asInstanceOf[java.lang.Short] + /** @group conversions-anyval-to-java */ + implicit def char2Character(x: Char): java.lang.Character = x.asInstanceOf[java.lang.Character] + /** @group conversions-anyval-to-java */ + implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer] + /** @group conversions-anyval-to-java */ + implicit def long2Long(x: Long): java.lang.Long = x.asInstanceOf[java.lang.Long] + /** @group conversions-anyval-to-java */ + implicit def float2Float(x: Float): java.lang.Float = x.asInstanceOf[java.lang.Float] + /** @group conversions-anyval-to-java */ + implicit def double2Double(x: Double): java.lang.Double = x.asInstanceOf[java.lang.Double] + /** @group conversions-anyval-to-java */ + implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = x.asInstanceOf[java.lang.Boolean] + + /** @group conversions-java-to-anyval */ + implicit def Byte2byte(x: java.lang.Byte): Byte = x.asInstanceOf[Byte] + /** @group conversions-java-to-anyval */ + implicit def Short2short(x: java.lang.Short): Short = x.asInstanceOf[Short] + /** @group conversions-java-to-anyval */ + implicit def Character2char(x: java.lang.Character): Char = x.asInstanceOf[Char] + /** @group conversions-java-to-anyval */ + implicit def Integer2int(x: java.lang.Integer): Int = x.asInstanceOf[Int] + /** @group conversions-java-to-anyval */ + implicit def Long2long(x: java.lang.Long): Long = x.asInstanceOf[Long] + /** @group conversions-java-to-anyval */ + implicit def Float2float(x: java.lang.Float): Float = x.asInstanceOf[Float] + /** @group conversions-java-to-anyval */ + implicit def Double2double(x: java.lang.Double): Double = x.asInstanceOf[Double] + /** @group conversions-java-to-anyval */ + implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.asInstanceOf[Boolean] // Type Constraints -------------------------------------------------------------- @@ -383,6 +493,7 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { * required lower bound. * * In part contributed by Jason Zaugg. + * @group type-constraints */ @implicitNotFound(msg = "Cannot prove that ${From} <:< ${To}.") sealed abstract class <:<[-From, +To] extends (From => To) with Serializable @@ -390,18 +501,21 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef { // The dollar prefix is to dodge accidental shadowing of this method // by a user-defined method of the same name (SI-7788). // The collections rely on this method. + /** @group type-constraints */ implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A] - @deprecated("Use `implicitly[T <:< U]` or `identity` instead.", "2.11.0") + @deprecated("use `implicitly[T <:< U]` or `identity` instead.", "2.11.0") def conforms[A]: A <:< A = $conforms[A] /** An instance of `A =:= B` witnesses that the types `A` and `B` are equal. * * @see `<:<` for expressing subtyping constraints + * @group type-constraints */ @implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.") sealed abstract class =:=[From, To] extends (From => To) with Serializable private[this] final val singleton_=:= = new =:=[Any,Any] { def apply(x: Any): Any = x } + /** @group type-constraints */ object =:= { implicit def tpEquals[A]: A =:= A = singleton_=:=.asInstanceOf[A =:= A] } @@ -424,27 +538,27 @@ private[scala] trait DeprecatedPredef { self: Predef.type => // Deprecated stubs for any who may have been calling these methods directly. - @deprecated("Use `ArrowAssoc`", "2.11.0") def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x) - @deprecated("Use `Ensuring`", "2.11.0") def any2Ensuring[A](x: A): Ensuring[A] = new Ensuring(x) - @deprecated("Use `StringFormat`", "2.11.0") def any2stringfmt(x: Any): StringFormat[Any] = new StringFormat(x) - @deprecated("Use `Throwable` directly", "2.11.0") def exceptionWrapper(exc: Throwable) = new RichException(exc) - @deprecated("Use `SeqCharSequence`", "2.11.0") def seqToCharSequence(xs: scala.collection.IndexedSeq[Char]): CharSequence = new SeqCharSequence(xs) - @deprecated("Use `ArrayCharSequence`", "2.11.0") def arrayToCharSequence(xs: Array[Char]): CharSequence = new ArrayCharSequence(xs) - - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(): String = StdIn.readLine() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLine(text: String, args: Any*) = StdIn.readLine(text, args: _*) - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readBoolean() = StdIn.readBoolean() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readByte() = StdIn.readByte() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readShort() = StdIn.readShort() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readChar() = StdIn.readChar() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readInt() = StdIn.readInt() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readLong() = StdIn.readLong() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readFloat() = StdIn.readFloat() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readDouble() = StdIn.readDouble() - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf(format: String) = StdIn.readf(format) - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf1(format: String) = StdIn.readf1(format) - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf2(format: String) = StdIn.readf2(format) - @deprecated("Use the method in `scala.io.StdIn`", "2.11.0") def readf3(format: String) = StdIn.readf3(format) + @deprecated("use `ArrowAssoc`", "2.11.0") def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x) + @deprecated("use `Ensuring`", "2.11.0") def any2Ensuring[A](x: A): Ensuring[A] = new Ensuring(x) + @deprecated("use `StringFormat`", "2.11.0") def any2stringfmt(x: Any): StringFormat[Any] = new StringFormat(x) + @deprecated("use `Throwable` directly", "2.11.0") def exceptionWrapper(exc: Throwable) = new RichException(exc) + @deprecated("use `SeqCharSequence`", "2.11.0") def seqToCharSequence(xs: scala.collection.IndexedSeq[Char]): CharSequence = new SeqCharSequence(xs) + @deprecated("use `ArrayCharSequence`", "2.11.0") def arrayToCharSequence(xs: Array[Char]): CharSequence = new ArrayCharSequence(xs) + + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readLine(): String = StdIn.readLine() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readLine(text: String, args: Any*) = StdIn.readLine(text, args: _*) + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readBoolean() = StdIn.readBoolean() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readByte() = StdIn.readByte() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readShort() = StdIn.readShort() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readChar() = StdIn.readChar() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readInt() = StdIn.readInt() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readLong() = StdIn.readLong() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readFloat() = StdIn.readFloat() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readDouble() = StdIn.readDouble() + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readf(format: String) = StdIn.readf(format) + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readf1(format: String) = StdIn.readf1(format) + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readf2(format: String) = StdIn.readf2(format) + @deprecated("use the method in `scala.io.StdIn`", "2.11.0") def readf3(format: String) = StdIn.readf3(format) } /** The `LowPriorityImplicits` class provides implicit values that @@ -481,6 +595,7 @@ private[scala] abstract class LowPriorityImplicits { @inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x) @inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x) + /** @group conversions-array-to-wrapped-array */ implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] = if (xs eq null) null else WrappedArray.make(xs) @@ -488,23 +603,35 @@ private[scala] abstract class LowPriorityImplicits { // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef] // is as good as another for all T <: AnyRef. Instead of creating 100,000,000 // unique ones by way of this implicit, let's share one. + /** @group conversions-array-to-wrapped-array */ implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = { if (xs eq null) null else if (xs.length == 0) WrappedArray.empty[T] else new WrappedArray.ofRef[T](xs) } + /** @group conversions-array-to-wrapped-array */ implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = if (xs ne null) new WrappedArray.ofInt(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = if (xs ne null) new WrappedArray.ofDouble(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = if (xs ne null) new WrappedArray.ofLong(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = if (xs ne null) new WrappedArray.ofFloat(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = if (xs ne null) new WrappedArray.ofChar(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = if (xs ne null) new WrappedArray.ofByte(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = if (xs ne null) new WrappedArray.ofShort(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = if (xs ne null) new WrappedArray.ofBoolean(xs) else null + /** @group conversions-array-to-wrapped-array */ implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = if (xs ne null) new WrappedArray.ofUnit(xs) else null + /** @group conversions-string */ implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null + /** @group conversions-string */ implicit def unwrapString(ws: WrappedString): String = if (ws ne null) ws.self else null implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, immutable.IndexedSeq[T]] = diff --git a/src/library/scala/Product.scala b/src/library/scala/Product.scala index 9cd38ed148..f3a96fb333 100644 --- a/src/library/scala/Product.scala +++ b/src/library/scala/Product.scala @@ -19,7 +19,7 @@ package scala */ trait Product extends Any with Equals { /** The n^th^ element of this product, 0-based. In other words, for a - * product `A(x,,1,,, ..., x,,k,,)`, returns `x,,(n+1),,` where `0 < n < k`. + * product `A(x,,1,,, ..., x,,k,,)`, returns `x,,(n+1),,` where `0 <= n < k`. * * @param n the index of the element to return * @throws IndexOutOfBoundsException diff --git a/src/library/scala/Product1.scala b/src/library/scala/Product1.scala index e82300adf6..3b0194e41f 100644 --- a/src/library/scala/Product1.scala +++ b/src/library/scala/Product1.scala @@ -14,7 +14,7 @@ object Product1 { Some(x) } -/** Product1 is a cartesian product of 1 component. +/** Product1 is a Cartesian product of 1 component. * @since 2.3 */ trait Product1[@specialized(Int, Long, Double) +T1] extends Any with Product { diff --git a/src/library/scala/Product10.scala b/src/library/scala/Product10.scala index 5fc4874048..8826d95007 100644 --- a/src/library/scala/Product10.scala +++ b/src/library/scala/Product10.scala @@ -14,7 +14,7 @@ object Product10 { Some(x) } -/** Product10 is a cartesian product of 10 components. +/** Product10 is a Cartesian product of 10 components. * @since 2.3 */ trait Product10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10] extends Any with Product { diff --git a/src/library/scala/Product11.scala b/src/library/scala/Product11.scala index dcebc90e3e..2a846fff4e 100644 --- a/src/library/scala/Product11.scala +++ b/src/library/scala/Product11.scala @@ -14,7 +14,7 @@ object Product11 { Some(x) } -/** Product11 is a cartesian product of 11 components. +/** Product11 is a Cartesian product of 11 components. * @since 2.3 */ trait Product11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11] extends Any with Product { diff --git a/src/library/scala/Product12.scala b/src/library/scala/Product12.scala index 2221170452..87419048d6 100644 --- a/src/library/scala/Product12.scala +++ b/src/library/scala/Product12.scala @@ -14,7 +14,7 @@ object Product12 { Some(x) } -/** Product12 is a cartesian product of 12 components. +/** Product12 is a Cartesian product of 12 components. * @since 2.3 */ trait Product12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12] extends Any with Product { diff --git a/src/library/scala/Product13.scala b/src/library/scala/Product13.scala index e76f326766..a944279a2e 100644 --- a/src/library/scala/Product13.scala +++ b/src/library/scala/Product13.scala @@ -14,7 +14,7 @@ object Product13 { Some(x) } -/** Product13 is a cartesian product of 13 components. +/** Product13 is a Cartesian product of 13 components. * @since 2.3 */ trait Product13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13] extends Any with Product { diff --git a/src/library/scala/Product14.scala b/src/library/scala/Product14.scala index a076e2cc7a..098721f216 100644 --- a/src/library/scala/Product14.scala +++ b/src/library/scala/Product14.scala @@ -14,7 +14,7 @@ object Product14 { Some(x) } -/** Product14 is a cartesian product of 14 components. +/** Product14 is a Cartesian product of 14 components. * @since 2.3 */ trait Product14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14] extends Any with Product { diff --git a/src/library/scala/Product15.scala b/src/library/scala/Product15.scala index 4568aff1fe..ef550c80d2 100644 --- a/src/library/scala/Product15.scala +++ b/src/library/scala/Product15.scala @@ -14,7 +14,7 @@ object Product15 { Some(x) } -/** Product15 is a cartesian product of 15 components. +/** Product15 is a Cartesian product of 15 components. * @since 2.3 */ trait Product15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15] extends Any with Product { diff --git a/src/library/scala/Product16.scala b/src/library/scala/Product16.scala index 84dccb0ac8..dd32e2f637 100644 --- a/src/library/scala/Product16.scala +++ b/src/library/scala/Product16.scala @@ -14,7 +14,7 @@ object Product16 { Some(x) } -/** Product16 is a cartesian product of 16 components. +/** Product16 is a Cartesian product of 16 components. * @since 2.3 */ trait Product16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16] extends Any with Product { diff --git a/src/library/scala/Product17.scala b/src/library/scala/Product17.scala index 0d50898bf4..e97cc5189e 100644 --- a/src/library/scala/Product17.scala +++ b/src/library/scala/Product17.scala @@ -14,7 +14,7 @@ object Product17 { Some(x) } -/** Product17 is a cartesian product of 17 components. +/** Product17 is a Cartesian product of 17 components. * @since 2.3 */ trait Product17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17] extends Any with Product { diff --git a/src/library/scala/Product18.scala b/src/library/scala/Product18.scala index 9b32265d71..1266b77a9f 100644 --- a/src/library/scala/Product18.scala +++ b/src/library/scala/Product18.scala @@ -14,7 +14,7 @@ object Product18 { Some(x) } -/** Product18 is a cartesian product of 18 components. +/** Product18 is a Cartesian product of 18 components. * @since 2.3 */ trait Product18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18] extends Any with Product { diff --git a/src/library/scala/Product19.scala b/src/library/scala/Product19.scala index fe6b95669b..4bf5dcf23e 100644 --- a/src/library/scala/Product19.scala +++ b/src/library/scala/Product19.scala @@ -14,7 +14,7 @@ object Product19 { Some(x) } -/** Product19 is a cartesian product of 19 components. +/** Product19 is a Cartesian product of 19 components. * @since 2.3 */ trait Product19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19] extends Any with Product { diff --git a/src/library/scala/Product2.scala b/src/library/scala/Product2.scala index 091bcc89de..93144abeb3 100644 --- a/src/library/scala/Product2.scala +++ b/src/library/scala/Product2.scala @@ -14,7 +14,7 @@ object Product2 { Some(x) } -/** Product2 is a cartesian product of 2 components. +/** Product2 is a Cartesian product of 2 components. * @since 2.3 */ trait Product2[@specialized(Int, Long, Double) +T1, @specialized(Int, Long, Double) +T2] extends Any with Product { diff --git a/src/library/scala/Product20.scala b/src/library/scala/Product20.scala index 81315e3558..a1dfd469ad 100644 --- a/src/library/scala/Product20.scala +++ b/src/library/scala/Product20.scala @@ -14,7 +14,7 @@ object Product20 { Some(x) } -/** Product20 is a cartesian product of 20 components. +/** Product20 is a Cartesian product of 20 components. * @since 2.3 */ trait Product20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20] extends Any with Product { diff --git a/src/library/scala/Product21.scala b/src/library/scala/Product21.scala index b5967c06e1..4f01277ad3 100644 --- a/src/library/scala/Product21.scala +++ b/src/library/scala/Product21.scala @@ -14,7 +14,7 @@ object Product21 { Some(x) } -/** Product21 is a cartesian product of 21 components. +/** Product21 is a Cartesian product of 21 components. * @since 2.3 */ trait Product21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21] extends Any with Product { diff --git a/src/library/scala/Product22.scala b/src/library/scala/Product22.scala index c7b9da5ce8..cef8d30402 100644 --- a/src/library/scala/Product22.scala +++ b/src/library/scala/Product22.scala @@ -14,7 +14,7 @@ object Product22 { Some(x) } -/** Product22 is a cartesian product of 22 components. +/** Product22 is a Cartesian product of 22 components. * @since 2.3 */ trait Product22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21, +T22] extends Any with Product { diff --git a/src/library/scala/Product3.scala b/src/library/scala/Product3.scala index 7154bf5bdf..7da324106d 100644 --- a/src/library/scala/Product3.scala +++ b/src/library/scala/Product3.scala @@ -14,7 +14,7 @@ object Product3 { Some(x) } -/** Product3 is a cartesian product of 3 components. +/** Product3 is a Cartesian product of 3 components. * @since 2.3 */ trait Product3[+T1, +T2, +T3] extends Any with Product { diff --git a/src/library/scala/Product4.scala b/src/library/scala/Product4.scala index 046f8c7a7c..88e5dea9d3 100644 --- a/src/library/scala/Product4.scala +++ b/src/library/scala/Product4.scala @@ -14,7 +14,7 @@ object Product4 { Some(x) } -/** Product4 is a cartesian product of 4 components. +/** Product4 is a Cartesian product of 4 components. * @since 2.3 */ trait Product4[+T1, +T2, +T3, +T4] extends Any with Product { diff --git a/src/library/scala/Product5.scala b/src/library/scala/Product5.scala index 3e952c8c55..d8c3ffc190 100644 --- a/src/library/scala/Product5.scala +++ b/src/library/scala/Product5.scala @@ -14,7 +14,7 @@ object Product5 { Some(x) } -/** Product5 is a cartesian product of 5 components. +/** Product5 is a Cartesian product of 5 components. * @since 2.3 */ trait Product5[+T1, +T2, +T3, +T4, +T5] extends Any with Product { diff --git a/src/library/scala/Product6.scala b/src/library/scala/Product6.scala index 010c68711a..ab50d678fc 100644 --- a/src/library/scala/Product6.scala +++ b/src/library/scala/Product6.scala @@ -14,7 +14,7 @@ object Product6 { Some(x) } -/** Product6 is a cartesian product of 6 components. +/** Product6 is a Cartesian product of 6 components. * @since 2.3 */ trait Product6[+T1, +T2, +T3, +T4, +T5, +T6] extends Any with Product { diff --git a/src/library/scala/Product7.scala b/src/library/scala/Product7.scala index 24e5a5c05a..efdeb142d1 100644 --- a/src/library/scala/Product7.scala +++ b/src/library/scala/Product7.scala @@ -14,7 +14,7 @@ object Product7 { Some(x) } -/** Product7 is a cartesian product of 7 components. +/** Product7 is a Cartesian product of 7 components. * @since 2.3 */ trait Product7[+T1, +T2, +T3, +T4, +T5, +T6, +T7] extends Any with Product { diff --git a/src/library/scala/Product8.scala b/src/library/scala/Product8.scala index 4a9f65b00e..743c0ac485 100644 --- a/src/library/scala/Product8.scala +++ b/src/library/scala/Product8.scala @@ -14,7 +14,7 @@ object Product8 { Some(x) } -/** Product8 is a cartesian product of 8 components. +/** Product8 is a Cartesian product of 8 components. * @since 2.3 */ trait Product8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8] extends Any with Product { diff --git a/src/library/scala/Product9.scala b/src/library/scala/Product9.scala index 9af11f709a..8d04213cd9 100644 --- a/src/library/scala/Product9.scala +++ b/src/library/scala/Product9.scala @@ -14,7 +14,7 @@ object Product9 { Some(x) } -/** Product9 is a cartesian product of 9 components. +/** Product9 is a Cartesian product of 9 components. * @since 2.3 */ trait Product9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9] extends Any with Product { diff --git a/src/library/scala/Responder.scala b/src/library/scala/Responder.scala index 8a658e252a..eb8260dc9a 100644 --- a/src/library/scala/Responder.scala +++ b/src/library/scala/Responder.scala @@ -18,7 +18,7 @@ package scala * @see class Responder * @since 2.1 */ -@deprecated("This object will be removed", "2.11.0") +@deprecated("this object will be removed", "2.11.0") object Responder { /** Creates a responder that answer continuations with the constant `a`. @@ -59,7 +59,7 @@ object Responder { * @version 1.0 * @since 2.1 */ -@deprecated("This class will be removed", "2.11.0") +@deprecated("this class will be removed", "2.11.0") abstract class Responder[+A] extends Serializable { def respond(k: A => Unit): Unit diff --git a/src/library/scala/Short.scala b/src/library/scala/Short.scala index 2cbbf3cc59..136d745f16 100644 --- a/src/library/scala/Short.scala +++ b/src/library/scala/Short.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -434,7 +434,8 @@ final abstract class Short private extends AnyVal { /** Returns the remainder of the division of this value by `x`. */ def %(x: Double): Double - override def getClass(): Class[Short] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Short] = ??? } object Short extends AnyValCompanion { @@ -451,7 +452,7 @@ object Short extends AnyValCompanion { * @param x the Short to be boxed * @return a java.lang.Short offering `x` as its underlying value. */ - def box(x: Short): java.lang.Short = java.lang.Short.valueOf(x) + def box(x: Short): java.lang.Short = ??? /** Transform a boxed type into a value type. Note that this * method is not typesafe: it accepts any Object, but will throw @@ -463,7 +464,7 @@ object Short extends AnyValCompanion { * @throws ClassCastException if the argument is not a java.lang.Short * @return the Short resulting from calling shortValue() on `x` */ - def unbox(x: java.lang.Object): Short = x.asInstanceOf[java.lang.Short].shortValue() + def unbox(x: java.lang.Object): Short = ??? /** The String representation of the scala.Short companion object. */ override def toString = "object scala.Short" diff --git a/src/library/scala/Symbol.scala b/src/library/scala/Symbol.scala index 4fead7a50c..4dcfdd4cba 100644 --- a/src/library/scala/Symbol.scala +++ b/src/library/scala/Symbol.scala @@ -71,8 +71,8 @@ private[scala] abstract class UniquenessCache[K, V >: Null] else { // If we don't remove the old String key from the map, we can // wind up with one String as the key and a different String as - // as the name field in the Symbol, which can lead to surprising - // GC behavior and duplicate Symbols. See SI-6706. + // the name field in the Symbol, which can lead to surprising GC + // behavior and duplicate Symbols. See SI-6706. map remove name val sym = valueFromKey(name) map.put(name, new WeakReference(sym)) diff --git a/src/library/scala/Tuple1.scala b/src/library/scala/Tuple1.scala index 5898b63e21..5544a5f63d 100644 --- a/src/library/scala/Tuple1.scala +++ b/src/library/scala/Tuple1.scala @@ -15,8 +15,7 @@ package scala * @constructor Create a new tuple with 1 elements. * @param _1 Element 1 of this Tuple1 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple1[@specialized(Int, Long, Double) +T1](_1: T1) +final case class Tuple1[@specialized(Int, Long, Double) +T1](_1: T1) extends Product1[T1] { override def toString() = "(" + _1 + ")" diff --git a/src/library/scala/Tuple10.scala b/src/library/scala/Tuple10.scala index 2b0239561d..c57acb7c6e 100644 --- a/src/library/scala/Tuple10.scala +++ b/src/library/scala/Tuple10.scala @@ -24,8 +24,7 @@ package scala * @param _9 Element 9 of this Tuple10 * @param _10 Element 10 of this Tuple10 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10) +final case class Tuple10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10) extends Product10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + ")" diff --git a/src/library/scala/Tuple11.scala b/src/library/scala/Tuple11.scala index 0d5294d547..06360e6679 100644 --- a/src/library/scala/Tuple11.scala +++ b/src/library/scala/Tuple11.scala @@ -25,8 +25,7 @@ package scala * @param _10 Element 10 of this Tuple11 * @param _11 Element 11 of this Tuple11 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11) +final case class Tuple11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11) extends Product11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + ")" diff --git a/src/library/scala/Tuple12.scala b/src/library/scala/Tuple12.scala index d36c8275c1..e223de104d 100644 --- a/src/library/scala/Tuple12.scala +++ b/src/library/scala/Tuple12.scala @@ -26,8 +26,7 @@ package scala * @param _11 Element 11 of this Tuple12 * @param _12 Element 12 of this Tuple12 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12) +final case class Tuple12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12) extends Product12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + diff --git a/src/library/scala/Tuple13.scala b/src/library/scala/Tuple13.scala index edc37456fe..56e12b96b6 100644 --- a/src/library/scala/Tuple13.scala +++ b/src/library/scala/Tuple13.scala @@ -27,8 +27,7 @@ package scala * @param _12 Element 12 of this Tuple13 * @param _13 Element 13 of this Tuple13 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13) +final case class Tuple13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13) extends Product13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + diff --git a/src/library/scala/Tuple14.scala b/src/library/scala/Tuple14.scala index 9896e736c9..53dd4d79bb 100644 --- a/src/library/scala/Tuple14.scala +++ b/src/library/scala/Tuple14.scala @@ -28,8 +28,7 @@ package scala * @param _13 Element 13 of this Tuple14 * @param _14 Element 14 of this Tuple14 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14) +final case class Tuple14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14) extends Product14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + diff --git a/src/library/scala/Tuple15.scala b/src/library/scala/Tuple15.scala index 45cd4f751f..0aca96d00d 100644 --- a/src/library/scala/Tuple15.scala +++ b/src/library/scala/Tuple15.scala @@ -29,8 +29,7 @@ package scala * @param _14 Element 14 of this Tuple15 * @param _15 Element 15 of this Tuple15 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15) +final case class Tuple15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15) extends Product15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + diff --git a/src/library/scala/Tuple16.scala b/src/library/scala/Tuple16.scala index 2e370a5b31..d4c0c31807 100644 --- a/src/library/scala/Tuple16.scala +++ b/src/library/scala/Tuple16.scala @@ -30,8 +30,7 @@ package scala * @param _15 Element 15 of this Tuple16 * @param _16 Element 16 of this Tuple16 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16) +final case class Tuple16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16) extends Product16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + diff --git a/src/library/scala/Tuple17.scala b/src/library/scala/Tuple17.scala index 2242a15fda..47df6cb59f 100644 --- a/src/library/scala/Tuple17.scala +++ b/src/library/scala/Tuple17.scala @@ -31,8 +31,7 @@ package scala * @param _16 Element 16 of this Tuple17 * @param _17 Element 17 of this Tuple17 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17) +final case class Tuple17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17) extends Product17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + diff --git a/src/library/scala/Tuple18.scala b/src/library/scala/Tuple18.scala index 68f245c6ce..464b08fb28 100644 --- a/src/library/scala/Tuple18.scala +++ b/src/library/scala/Tuple18.scala @@ -32,8 +32,7 @@ package scala * @param _17 Element 17 of this Tuple18 * @param _18 Element 18 of this Tuple18 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18) +final case class Tuple18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18) extends Product18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + diff --git a/src/library/scala/Tuple19.scala b/src/library/scala/Tuple19.scala index a8a49549fb..d64b3920b4 100644 --- a/src/library/scala/Tuple19.scala +++ b/src/library/scala/Tuple19.scala @@ -33,8 +33,7 @@ package scala * @param _18 Element 18 of this Tuple19 * @param _19 Element 19 of this Tuple19 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19) +final case class Tuple19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19) extends Product19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + diff --git a/src/library/scala/Tuple2.scala b/src/library/scala/Tuple2.scala index 9ea1469c5c..5faa4e9821 100644 --- a/src/library/scala/Tuple2.scala +++ b/src/library/scala/Tuple2.scala @@ -16,8 +16,7 @@ package scala * @param _1 Element 1 of this Tuple2 * @param _2 Element 2 of this Tuple2 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple2[@specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T1, @specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T2](_1: T1, _2: T2) +final case class Tuple2[@specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T1, @specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T2](_1: T1, _2: T2) extends Product2[T1, T2] { override def toString() = "(" + _1 + "," + _2 + ")" diff --git a/src/library/scala/Tuple20.scala b/src/library/scala/Tuple20.scala index 0118d382ab..a96c41baa5 100644 --- a/src/library/scala/Tuple20.scala +++ b/src/library/scala/Tuple20.scala @@ -34,8 +34,7 @@ package scala * @param _19 Element 19 of this Tuple20 * @param _20 Element 20 of this Tuple20 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20) +final case class Tuple20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20) extends Product20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + diff --git a/src/library/scala/Tuple21.scala b/src/library/scala/Tuple21.scala index ceae94af41..6f240d1fba 100644 --- a/src/library/scala/Tuple21.scala +++ b/src/library/scala/Tuple21.scala @@ -35,8 +35,7 @@ package scala * @param _20 Element 20 of this Tuple21 * @param _21 Element 21 of this Tuple21 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21) +final case class Tuple21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21) extends Product21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + diff --git a/src/library/scala/Tuple22.scala b/src/library/scala/Tuple22.scala index ecd567a710..681b709f65 100644 --- a/src/library/scala/Tuple22.scala +++ b/src/library/scala/Tuple22.scala @@ -36,8 +36,7 @@ package scala * @param _21 Element 21 of this Tuple22 * @param _22 Element 22 of this Tuple22 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21, +T22](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21, _22: T22) +final case class Tuple22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21, +T22](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21, _22: T22) extends Product22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + diff --git a/src/library/scala/Tuple3.scala b/src/library/scala/Tuple3.scala index 6e71d3ae8c..86f8f7e1a4 100644 --- a/src/library/scala/Tuple3.scala +++ b/src/library/scala/Tuple3.scala @@ -17,8 +17,7 @@ package scala * @param _2 Element 2 of this Tuple3 * @param _3 Element 3 of this Tuple3 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple3[+T1, +T2, +T3](_1: T1, _2: T2, _3: T3) +final case class Tuple3[+T1, +T2, +T3](_1: T1, _2: T2, _3: T3) extends Product3[T1, T2, T3] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + ")" diff --git a/src/library/scala/Tuple4.scala b/src/library/scala/Tuple4.scala index 4c84cfc674..f3266c262c 100644 --- a/src/library/scala/Tuple4.scala +++ b/src/library/scala/Tuple4.scala @@ -18,8 +18,7 @@ package scala * @param _3 Element 3 of this Tuple4 * @param _4 Element 4 of this Tuple4 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple4[+T1, +T2, +T3, +T4](_1: T1, _2: T2, _3: T3, _4: T4) +final case class Tuple4[+T1, +T2, +T3, +T4](_1: T1, _2: T2, _3: T3, _4: T4) extends Product4[T1, T2, T3, T4] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + ")" diff --git a/src/library/scala/Tuple5.scala b/src/library/scala/Tuple5.scala index fe8e853f12..e6ac0a6245 100644 --- a/src/library/scala/Tuple5.scala +++ b/src/library/scala/Tuple5.scala @@ -19,8 +19,7 @@ package scala * @param _4 Element 4 of this Tuple5 * @param _5 Element 5 of this Tuple5 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple5[+T1, +T2, +T3, +T4, +T5](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5) +final case class Tuple5[+T1, +T2, +T3, +T4, +T5](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5) extends Product5[T1, T2, T3, T4, T5] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + ")" diff --git a/src/library/scala/Tuple6.scala b/src/library/scala/Tuple6.scala index 6bf1c73d4b..cf69b9c10a 100644 --- a/src/library/scala/Tuple6.scala +++ b/src/library/scala/Tuple6.scala @@ -20,8 +20,7 @@ package scala * @param _5 Element 5 of this Tuple6 * @param _6 Element 6 of this Tuple6 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple6[+T1, +T2, +T3, +T4, +T5, +T6](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6) +final case class Tuple6[+T1, +T2, +T3, +T4, +T5, +T6](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6) extends Product6[T1, T2, T3, T4, T5, T6] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + ")" diff --git a/src/library/scala/Tuple7.scala b/src/library/scala/Tuple7.scala index ea42709cb7..4f0200fe23 100644 --- a/src/library/scala/Tuple7.scala +++ b/src/library/scala/Tuple7.scala @@ -21,8 +21,7 @@ package scala * @param _6 Element 6 of this Tuple7 * @param _7 Element 7 of this Tuple7 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple7[+T1, +T2, +T3, +T4, +T5, +T6, +T7](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7) +final case class Tuple7[+T1, +T2, +T3, +T4, +T5, +T6, +T7](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7) extends Product7[T1, T2, T3, T4, T5, T6, T7] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + ")" diff --git a/src/library/scala/Tuple8.scala b/src/library/scala/Tuple8.scala index c24f9454e0..ebd9f70252 100644 --- a/src/library/scala/Tuple8.scala +++ b/src/library/scala/Tuple8.scala @@ -22,8 +22,7 @@ package scala * @param _7 Element 7 of this Tuple8 * @param _8 Element 8 of this Tuple8 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8) +final case class Tuple8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8) extends Product8[T1, T2, T3, T4, T5, T6, T7, T8] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + ")" diff --git a/src/library/scala/Tuple9.scala b/src/library/scala/Tuple9.scala index ed02b30df2..854fe97b44 100644 --- a/src/library/scala/Tuple9.scala +++ b/src/library/scala/Tuple9.scala @@ -23,8 +23,7 @@ package scala * @param _8 Element 8 of this Tuple9 * @param _9 Element 9 of this Tuple9 */ -@deprecatedInheritance("Tuples will be made final in a future version.", "2.11.0") -case class Tuple9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9) +final case class Tuple9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9) extends Product9[T1, T2, T3, T4, T5, T6, T7, T8, T9] { override def toString() = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + ")" diff --git a/src/library/scala/Unit.scala b/src/library/scala/Unit.scala index 018ad24a99..eb6d1d0ddf 100644 --- a/src/library/scala/Unit.scala +++ b/src/library/scala/Unit.scala @@ -7,8 +7,8 @@ \* */ // DO NOT EDIT, CHANGES WILL BE LOST -// This auto-generated code can be modified in scala.tools.cmd.gen. -// Afterwards, running tools/codegen-anyvals regenerates this source file. +// This auto-generated code can be modified in "project/GenerateAnyVals.scala". +// Afterwards, running "sbt generateSources" regenerates this source file. package scala @@ -19,7 +19,8 @@ package scala * method which is declared `void`. */ final abstract class Unit private extends AnyVal { - override def getClass(): Class[Unit] = null + // Provide a more specific return type for Scaladoc + override def getClass(): Class[Unit] = ??? } object Unit extends AnyValCompanion { @@ -39,7 +40,7 @@ object Unit extends AnyValCompanion { * @throws ClassCastException if the argument is not a scala.runtime.BoxedUnit * @return the Unit value () */ - def unbox(x: java.lang.Object): Unit = () + def unbox(x: java.lang.Object): Unit = x.asInstanceOf[scala.runtime.BoxedUnit] /** The String representation of the scala.Unit companion object. */ override def toString = "object scala.Unit" diff --git a/src/library/scala/annotation/bridge.scala b/src/library/scala/annotation/bridge.scala index 9f25e2beb3..c0c6dba424 100644 --- a/src/library/scala/annotation/bridge.scala +++ b/src/library/scala/annotation/bridge.scala @@ -10,5 +10,5 @@ package scala.annotation /** If this annotation is present on a method, it will be treated as a bridge method. */ -@deprecated("Reconsider whether using this annotation will accomplish anything", "2.10.0") +@deprecated("reconsider whether using this annotation will accomplish anything", "2.10.0") private[scala] class bridge extends scala.annotation.StaticAnnotation diff --git a/src/library/scala/annotation/elidable.scala b/src/library/scala/annotation/elidable.scala index f9c5e8a744..dd0d9b511c 100644 --- a/src/library/scala/annotation/elidable.scala +++ b/src/library/scala/annotation/elidable.scala @@ -8,8 +8,6 @@ package scala.annotation -import java.util.logging.Level - /** An annotation for methods whose bodies may be excluded * from compiler-generated bytecode. * @@ -62,7 +60,7 @@ import java.util.logging.Level * @author Paul Phillips * @since 2.8 */ -final class elidable(final val level: Int) extends scala.annotation.StaticAnnotation {} +final class elidable(final val level: Int) extends scala.annotation.StaticAnnotation /** This useless appearing code was necessary to allow people to use * named constants for the elidable annotation. This is what it takes diff --git a/src/library/scala/annotation/implicitAmbiguous.scala b/src/library/scala/annotation/implicitAmbiguous.scala new file mode 100644 index 0000000000..44e8d23085 --- /dev/null +++ b/src/library/scala/annotation/implicitAmbiguous.scala @@ -0,0 +1,32 @@ +package scala.annotation + +/** + * To customize the error message that's emitted when an implicit search finds + * multiple ambiguous values, annotate at least one of the implicit values + * `@implicitAmbiguous`. Assuming the implicit value is a method with type + * parameters `X1,..., XN`, the error message will be the result of replacing + * all occurrences of `${Xi}` in the string `msg` with the string representation + * of the corresponding type argument `Ti`. + * + * If more than one `@implicitAmbiguous` annotation is collected, the compiler is + * free to pick any of them to display. + * + * Nice errors can direct users to fix imports or even tell them why code + * intentionally doesn't compile. + * + * {{{ + * trait =!=[C, D] + * + * implicit def neq[E, F] : E =!= F = null + * + * @annotation.implicitAmbiguous("Could not prove ${J} =!= ${J}") + * implicit def neqAmbig1[G, H, J] : J =!= J = null + * implicit def neqAmbig2[I] : I =!= I = null + * + * implicitly[Int =!= Int] + * }}} + * + * @author Brian McKenna + * @since 2.12.0 + */ +final class implicitAmbiguous(msg: String) extends scala.annotation.StaticAnnotation diff --git a/src/library/scala/annotation/showAsInfix.scala b/src/library/scala/annotation/showAsInfix.scala new file mode 100644 index 0000000000..6c25e08efa --- /dev/null +++ b/src/library/scala/annotation/showAsInfix.scala @@ -0,0 +1,27 @@ +package scala.annotation + +/** + * This annotation configures how Scala prints two-parameter generic types. + * + * By default, types with symbolic names are printed infix; while types without + * them are printed using the regular generic type syntax. + * + * Example of usage: + {{{ + scala> class Map[T, U] + defined class Map + + scala> def foo: Int Map Int = ??? + foo: Map[Int,Int] + + scala> @showAsInfix class Map[T, U] + defined class Map + + scala> def foo: Int Map Int = ??? + foo: Int Map Int + }}} + * + * @param enabled whether to show this type as an infix type operator. + * @since 2.12.2 + */ +class showAsInfix(enabled: Boolean = true) extends annotation.StaticAnnotation
\ No newline at end of file diff --git a/src/library/scala/beans/BeanInfo.scala b/src/library/scala/beans/BeanInfo.scala index 799e93e71a..d7f0a1618b 100644 --- a/src/library/scala/beans/BeanInfo.scala +++ b/src/library/scala/beans/BeanInfo.scala @@ -17,4 +17,5 @@ package scala.beans * * @author Ross Judson (rjudson@managedobjects.com) */ +@deprecated(message = "the generation of BeanInfo classes is no longer supported", since = "2.12.0") class BeanInfo extends scala.annotation.Annotation diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala index 29369447d1..f0a70170c2 100644 --- a/src/library/scala/collection/BitSetLike.scala +++ b/src/library/scala/collection/BitSetLike.scala @@ -77,26 +77,26 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe def rangeImpl(from: Option[Int], until: Option[Int]): This = { val a = toBitMask val len = a.length - if(from.isDefined) { + if (from.isDefined) { var f = from.get var pos = 0 - while(f >= 64 && pos < len) { + while (f >= 64 && pos < len) { f -= 64 a(pos) = 0 pos += 1 } - if(f > 0 && pos < len) a(pos) &= ~((1L << f)-1) + if (f > 0 && pos < len) a(pos) &= ~((1L << f)-1) } - if(until.isDefined) { + if (until.isDefined) { val u = until.get val w = u / 64 val b = u % 64 var clearw = w+1 - while(clearw < len) { + while (clearw < len) { a(clearw) = 0 clearw += 1 } - if(w < len) a(w) &= (1L << b)-1 + if (w < len) a(w) &= (1L << b)-1 } fromBitMaskNoCopy(a) } @@ -204,12 +204,33 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe def subsetOf(other: BitSet): Boolean = (0 until nwords) forall (idx => (this.word(idx) & ~ other.word(idx)) == 0L) + override def head: Int = { + val n = nwords + var i = 0 + while (i < n) { + val wi = word(i) + if (wi != 0L) return WordLength*i + java.lang.Long.numberOfTrailingZeros(wi) + i += 1 + } + throw new NoSuchElementException("Empty BitSet") + } + + override def last: Int = { + var i = nwords - 1 + while (i >= 0) { + val wi = word(i) + if (wi != 0L) return WordLength*i + 63 - java.lang.Long.numberOfLeadingZeros(wi) + i -= 1 + } + throw new NoSuchElementException("Empty BitSet") + } + override def addString(sb: StringBuilder, start: String, sep: String, end: String) = { sb append start var pre = "" val max = nwords * WordLength var i = 0 - while(i != max) { + while (i != max) { if (contains(i)) { sb append pre append i pre = sep diff --git a/src/library/scala/collection/BufferedIterator.scala b/src/library/scala/collection/BufferedIterator.scala index e6e97d584c..1424ef2fd0 100644 --- a/src/library/scala/collection/BufferedIterator.scala +++ b/src/library/scala/collection/BufferedIterator.scala @@ -24,5 +24,11 @@ trait BufferedIterator[+A] extends Iterator[A] { */ def head: A + /** Returns an option of the next element of an iterator without advancing beyond it. + * @return the next element of this iterator if it has a next element + * `None` if it does not + */ + def headOption : Option[A] = if (hasNext) Some(head) else None + override def buffered: this.type = this } diff --git a/src/library/scala/collection/GenMap.scala b/src/library/scala/collection/GenMap.scala index d17a2de179..6bc507ae93 100644 --- a/src/library/scala/collection/GenMap.scala +++ b/src/library/scala/collection/GenMap.scala @@ -18,18 +18,18 @@ import generic._ * @author Aleksandar Prokopec * @since 2.9 */ -trait GenMap[A, +B] -extends GenMapLike[A, B, GenMap[A, B]] - with GenIterable[(A, B)] +trait GenMap[K, +V] +extends GenMapLike[K, V, GenMap[K, V]] + with GenIterable[(K, V)] { - def seq: Map[A, B] + def seq: Map[K, V] - def updated [B1 >: B](key: A, value: B1): GenMap[A, B1] + def updated [V1 >: V](key: K, value: V1): GenMap[K, V1] } object GenMap extends GenMapFactory[GenMap] { - def empty[A, B]: immutable.Map[A, B] = immutable.Map.empty + def empty[K, V]: immutable.Map[K, V] = immutable.Map.empty /** $mapCanBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), GenMap[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), GenMap[K, V]] = new MapCanBuildFrom[K, V] } diff --git a/src/library/scala/collection/GenMapLike.scala b/src/library/scala/collection/GenMapLike.scala index 2b39fa2289..f6c2d071b5 100644 --- a/src/library/scala/collection/GenMapLike.scala +++ b/src/library/scala/collection/GenMapLike.scala @@ -22,13 +22,13 @@ package collection * A map is a collection of bindings from keys to values, where there are * no duplicate keys. */ -trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals with Parallelizable[(A, B), parallel.ParMap[A, B]] { - def default(key: A): B - def get(key: A): Option[B] - def apply(key: A): B - def seq: Map[A, B] - def +[B1 >: B](kv: (A, B1)): GenMap[A, B1] - def - (key: A): Repr +trait GenMapLike[K, +V, +Repr] extends GenIterableLike[(K, V), Repr] with Equals with Parallelizable[(K, V), parallel.ParMap[K, V]] { + def default(key: K): V + def get(key: K): Option[V] + def apply(key: K): V + def seq: Map[K, V] + def +[V1 >: V](kv: (K, V1)): GenMap[K, V1] + def - (key: K): Repr // This hash code must be symmetric in the contents but ought not // collide trivially. @@ -41,17 +41,17 @@ trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals * @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 + * @usecase def getOrElse(key: K, default: => V): V * @inheritdoc */ - def getOrElse[B1 >: B](key: A, default: => B1): B1 + def getOrElse[V1 >: V](key: K, default: => V1): V1 /** 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 + def contains(key: K): Boolean /** Tests whether this map contains a binding for a key. This method, * which implements an abstract method of trait `PartialFunction`, @@ -60,47 +60,47 @@ trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals * @param key the key * @return `true` if there is a binding for `key` in this map, `false` otherwise. */ - def isDefinedAt(key: A): Boolean + def isDefinedAt(key: K): Boolean - def keySet: GenSet[A] + def keySet: GenSet[K] /** Collects all keys of this map in an iterable collection. * * @return the keys of this map as an iterable. */ - def keys: GenIterable[A] + def keys: GenIterable[K] /** Collects all values of this map in an iterable collection. * * @return the values of this map as an iterable. */ - def values: GenIterable[B] + def values: GenIterable[V] /** Creates an iterator for all keys. * * @return an iterator over all keys. */ - def keysIterator: Iterator[A] + def keysIterator: Iterator[K] /** 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] + def valuesIterator: Iterator[V] /** 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] + def filterKeys(p: K => Boolean): GenMap[K, V] /** 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] + def mapValues[W](f: V => W): GenMap[K, W] /** Compares two maps structurally; i.e., checks if all mappings * contained in this map are also contained in the other map, diff --git a/src/library/scala/collection/GenSeqLike.scala b/src/library/scala/collection/GenSeqLike.scala index be1da1660a..405d8d7e57 100644 --- a/src/library/scala/collection/GenSeqLike.scala +++ b/src/library/scala/collection/GenSeqLike.scala @@ -58,6 +58,7 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal * Note: `xs.length` and `xs.size` yield the same result. * * @return the number of elements in this $coll. + * @throws IllegalArgumentException if the length of the sequence cannot be represented in an `Int`, for example, `(-1 to Int.MaxValue).length`. */ def length: Int diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala index d730996be2..0ee5542e30 100644 --- a/src/library/scala/collection/GenTraversableLike.scala +++ b/src/library/scala/collection/GenTraversableLike.scala @@ -24,7 +24,7 @@ import scala.annotation.migration * is found. * @define bfinfo an implicit value of class `CanBuildFrom` which determines * the result class `That` from the current representation type `Repr` and - * and the new element type `B`. + * the new element type `B`. * @define orderDependent * * Note: might return different results for different runs, unless the @@ -249,30 +249,6 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with * @param bf $bfinfo * @return a new collection of type `That` which contains all elements * of this $coll followed by all elements of `that`. - * - * @usecase def ++[B](that: GenTraversableOnce[B]): $Coll[B] - * @inheritdoc - * - * Example: - * {{{ - * scala> val a = List(1) - * a: List[Int] = List(1) - * - * scala> val b = List(2) - * b: List[Int] = List(2) - * - * scala> val c = a ++ b - * c: List[Int] = List(1, 2) - * - * scala> val d = List('a') - * d: List[Char] = List(a) - * - * scala> val e = c ++ d - * e: List[AnyVal] = List(1, 2, a) - * }}} - * - * @return a new $coll which contains all elements of this $coll - * followed by all elements of `that`. */ def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 4af2ca23be..f87f7654bc 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -96,6 +96,12 @@ trait GenTraversableOnce[+A] extends Any { */ def size: Int + /** The size of this $coll, if it can be cheaply computed + * + * @return the number of elements in this $coll, or -1 if the size cannot be determined cheaply + */ + protected[collection] def sizeHintIfCheap: Int = -1 + /** Tests whether the $coll is empty. * * Note: Implementations in subclasses that are not repeatedly traversable must take diff --git a/src/library/scala/collection/IndexedSeqLike.scala b/src/library/scala/collection/IndexedSeqLike.scala index 18c9175ee1..f0cede224d 100644 --- a/src/library/scala/collection/IndexedSeqLike.scala +++ b/src/library/scala/collection/IndexedSeqLike.scala @@ -9,9 +9,6 @@ package scala package collection -import mutable.ArrayBuffer -import scala.annotation.tailrec - /** A template trait for indexed sequences of type `IndexedSeq[A]`. * * $indexedSeqInfo @@ -95,4 +92,6 @@ trait IndexedSeqLike[+A, +Repr] extends Any with SeqLike[A, Repr] { copyToBuffer(result) result } + + override protected[collection] def sizeHintIfCheap: Int = size } diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala index a7e06b4d1a..320725c30e 100644 --- a/src/library/scala/collection/IndexedSeqOptimized.scala +++ b/src/library/scala/collection/IndexedSeqOptimized.scala @@ -10,7 +10,6 @@ package scala package collection import generic._ -import mutable.ArrayBuffer import scala.annotation.tailrec /** A template trait for indexed sequences of type `IndexedSeq[A]` which optimizes @@ -200,7 +199,7 @@ trait IndexedSeqOptimized[+A, +Repr] extends Any with IndexedSeqLike[A, Repr] { override /*SeqLike*/ def indexWhere(p: A => Boolean, from: Int): Int = { - val start = from max 0 + val start = math.max(from, 0) negLength(start + segmentLength(!p(_), start)) } diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala index ecf64624e8..419206c226 100644 --- a/src/library/scala/collection/IterableLike.scala +++ b/src/library/scala/collection/IterableLike.scala @@ -10,8 +10,7 @@ package scala package collection import generic._ -import immutable.{ List, Stream } -import scala.annotation.unchecked.uncheckedVariance +import immutable.Stream /** A template trait for iterable collections of type `Iterable[A]`. * $iterableInfo @@ -83,8 +82,8 @@ self => iterator.foldRight(z)(op) override /*TraversableLike*/ def reduceRight[B >: A](op: (A, B) => B): B = iterator.reduceRight(op) - - + + /** Returns this $coll as an iterable collection. * * A new collection will not be built; lazy collections will stay lazy. @@ -94,7 +93,7 @@ self => */ override /*TraversableLike*/ def toIterable: Iterable[A] = thisCollection - + /** Returns an Iterator over the elements in this $coll. Produces the same * result as `iterator`. * $willNotTerminateInf @@ -102,7 +101,7 @@ self => */ @deprecatedOverriding("toIterator should stay consistent with iterator for all Iterables: override iterator instead.", "2.11.0") override def toIterator: Iterator[A] = iterator - + override /*TraversableLike*/ def head: A = iterator.next() @@ -178,14 +177,14 @@ self => } /** Groups elements in fixed size blocks by passing a "sliding window" - * over them (as opposed to partitioning them, as is done in grouped.) - * "Sliding window" step is 1 by default. + * over them (as opposed to partitioning them, as is done in `grouped`.) + * The "sliding window" step is set to one. * @see [[scala.collection.Iterator]], method `sliding` * * @param size the number of elements per group * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int): Iterator[Repr] = sliding(size, 1) @@ -197,8 +196,8 @@ self => * @param step the distance between the first elements of successive * groups * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int, step: Int): Iterator[Repr] = for (xs <- iterator.sliding(size, step)) yield { diff --git a/src/library/scala/collection/IterableProxy.scala b/src/library/scala/collection/IterableProxy.scala index 97aa830c5a..5f4d69c411 100644 --- a/src/library/scala/collection/IterableProxy.scala +++ b/src/library/scala/collection/IterableProxy.scala @@ -16,5 +16,5 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait IterableProxy[+A] extends Iterable[A] with IterableProxyLike[A, Iterable[A]] diff --git a/src/library/scala/collection/IterableProxyLike.scala b/src/library/scala/collection/IterableProxyLike.scala index 90e630ee28..f87089cba8 100644 --- a/src/library/scala/collection/IterableProxyLike.scala +++ b/src/library/scala/collection/IterableProxyLike.scala @@ -12,7 +12,6 @@ package scala package collection import generic._ -import mutable.Buffer // Methods could be printed by cat IterableLike.scala | egrep '^ (override )?def' @@ -23,7 +22,7 @@ import mutable.Buffer * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait IterableProxyLike[+A, +Repr <: IterableLike[A, Repr] with Iterable[A]] extends IterableLike[A, Repr] with TraversableProxyLike[A, Repr] { diff --git a/src/library/scala/collection/IterableViewLike.scala b/src/library/scala/collection/IterableViewLike.scala index b84d90c51b..c254ed7480 100644 --- a/src/library/scala/collection/IterableViewLike.scala +++ b/src/library/scala/collection/IterableViewLike.scala @@ -69,6 +69,10 @@ trait IterableViewLike[+A, trait Appended[B >: A] extends super.Appended[B] with Transformed[B] { def iterator = self.iterator ++ rest } + + trait Prepended[B >: A] extends super.Prepended[B] with Transformed[B] { + def iterator = fst.toIterator ++ self + } trait Filtered extends super.Filtered with Transformed[A] { def iterator = self.iterator filter pred @@ -110,6 +114,7 @@ trait IterableViewLike[+A, } with AbstractTransformed[(A1, B)] with ZippedAll[A1, B] protected override def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 03b9fbff26..809e851494 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -11,9 +11,8 @@ package collection import mutable.ArrayBuffer import scala.annotation.{tailrec, migration} +import scala.annotation.unchecked.{uncheckedVariance => uV} import immutable.Stream -import scala.collection.generic.CanBuildFrom -import scala.annotation.unchecked.{ uncheckedVariance => uV } /** The `Iterator` object provides various functions for creating specialized iterators. * @@ -162,30 +161,49 @@ object Iterator { def next = elem } - /** Avoid stack overflows when applying ++ to lots of iterators by - * flattening the unevaluated iterators out into a vector of closures. + /** Creates an iterator to which other iterators can be appended efficiently. + * Nested ConcatIterators are merged to avoid blowing the stack. */ - private[scala] final class ConcatIterator[+A](private[this] var current: Iterator[A], initial: Vector[() => Iterator[A]]) extends Iterator[A] { - @deprecated def this(initial: Vector[() => Iterator[A]]) = this(Iterator.empty, initial) // for binary compatibility - private[this] var queue: Vector[() => Iterator[A]] = initial - private[this] var currentHasNextChecked = false + private final class ConcatIterator[+A](private var current: Iterator[A @uV]) extends Iterator[A] { + private var tail: ConcatIteratorCell[A @uV] = null + private var last: ConcatIteratorCell[A @uV] = null + private var currentHasNextChecked = false + // Advance current to the next non-empty iterator // current is set to null when all iterators are exhausted @tailrec private[this] def advance(): Boolean = { - if (queue.isEmpty) { + if (tail eq null) { current = null + last = null false } else { - current = queue.head() - queue = queue.tail - if (current.hasNext) { + current = tail.headIterator + tail = tail.tail + merge() + if (currentHasNextChecked) true + else if (current.hasNext) { currentHasNextChecked = true true } else advance() } } + + // If the current iterator is a ConcatIterator, merge it into this one + @tailrec + private[this] def merge(): Unit = + if (current.isInstanceOf[ConcatIterator[_]]) { + val c = current.asInstanceOf[ConcatIterator[A]] + current = c.current + currentHasNextChecked = c.currentHasNextChecked + if (c.tail ne null) { + c.last.tail = tail + tail = c.tail + } + merge() + } + def hasNext = if (currentHasNextChecked) true else if (current eq null) false @@ -193,48 +211,73 @@ object Iterator { currentHasNextChecked = true true } else advance() + def next() = if (hasNext) { currentHasNextChecked = false current.next() } else Iterator.empty.next() - override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = - if(current eq null) new JoinIterator(Iterator.empty, that) - else new ConcatIterator(current, queue :+ (() => that.toIterator)) + override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = { + val c = new ConcatIteratorCell[B](that, null).asInstanceOf[ConcatIteratorCell[A]] + if(tail eq null) { + tail = c + last = c + } else { + last.tail = c + last = c + } + if(current eq null) current = Iterator.empty + this + } } - private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] { - private[this] var state = 0 // 0: lhs not checked, 1: lhs has next, 2: switched to rhs - private[this] lazy val rhs: Iterator[A] = that.toIterator - def hasNext = state match { - case 0 => - if (lhs.hasNext) { - state = 1 - true - } else { - state = 2 - rhs.hasNext - } - case 1 => true - case _ => rhs.hasNext + private[this] final class ConcatIteratorCell[A](head: => GenTraversableOnce[A], var tail: ConcatIteratorCell[A]) { + def headIterator: Iterator[A] = head.toIterator + } + + /** Creates a delegating iterator capped by a limit count. Negative limit means unbounded. + * Lazily skip to start on first evaluation. Avoids daisy-chained iterators due to slicing. + */ + private[scala] final class SliceIterator[A](val underlying: Iterator[A], start: Int, limit: Int) extends AbstractIterator[A] { + private var remaining = limit + private var dropping = start + @inline private def unbounded = remaining < 0 + private def skip(): Unit = + while (dropping > 0) { + if (underlying.hasNext) { + underlying.next() + dropping -= 1 + } else + dropping = 0 + } + def hasNext = { skip(); remaining != 0 && underlying.hasNext } + def next() = { + skip() + if (remaining > 0) { + remaining -= 1 + underlying.next() + } + else if (unbounded) underlying.next() + else empty.next() } - def next() = state match { - case 0 => - if (lhs.hasNext) lhs.next() - else { - state = 2 - rhs.next() - } - case 1 => - state = 0 - lhs.next() - case _ => - rhs.next() + override protected def sliceIterator(from: Int, until: Int): Iterator[A] = { + val lo = from max 0 + def adjustedBound = + if (unbounded) -1 + else 0 max (remaining - lo) + val rest = + if (until < 0) adjustedBound // respect current bound, if any + else if (until <= lo) 0 // empty + else if (unbounded) until - lo // now finite + else adjustedBound min (until - lo) // keep lesser bound + if (rest == 0) empty + else { + dropping += lo + remaining = rest + this + } } - - override def ++[B >: A](that: => GenTraversableOnce[B]) = - new ConcatIterator(this, Vector(() => that.toIterator)) } } @@ -347,11 +390,11 @@ trait Iterator[+A] extends TraversableOnce[A] { /** Selects first ''n'' values of this iterator. * * @param n the number of values to take - * @return an iterator producing only of the first `n` values of this iterator, or else the + * @return an iterator producing only the first `n` values of this iterator, or else the * whole iterator, if it produces fewer than `n` values. * @note Reuse: $consumesAndProducesIterator */ - def take(n: Int): Iterator[A] = slice(0, n) + def take(n: Int): Iterator[A] = sliceIterator(0, n max 0) /** Advances this iterator past the first ''n'' elements, or the length of the iterator, whichever is smaller. * @@ -372,29 +415,24 @@ trait Iterator[+A] extends TraversableOnce[A] { /** Creates an iterator returning an interval of the values produced by this iterator. * * @param from the index of the first element in this iterator which forms part of the slice. - * @param until the index of the first element following the slice. + * If negative, the slice starts at zero. + * @param until the index of the first element following the slice. If negative, the slice is empty. * @return an iterator which advances this iterator past the first `from` elements using `drop`, * and then takes `until - from` elements, using `take`. * @note Reuse: $consumesAndProducesIterator */ - def slice(from: Int, until: Int): Iterator[A] = { + def slice(from: Int, until: Int): Iterator[A] = sliceIterator(from, until max 0) + + /** Creates an optionally bounded slice, unbounded if `until` is negative. */ + protected def sliceIterator(from: Int, until: Int): Iterator[A] = { val lo = from max 0 - var toDrop = lo - while (toDrop > 0 && self.hasNext) { - self.next() - toDrop -= 1 - } + val rest = + if (until < 0) -1 // unbounded + else if (until <= lo) 0 // empty + else until - lo // finite - new AbstractIterator[A] { - private var remaining = until - lo - def hasNext = remaining > 0 && self.hasNext - def next(): A = - if (remaining > 0) { - remaining -= 1 - self.next() - } - else empty.next() - } + if (rest == 0) empty + else new Iterator.SliceIterator(this, lo, rest) } /** Creates a new iterator that maps all produced values of this iterator @@ -420,7 +458,7 @@ trait Iterator[+A] extends TraversableOnce[A] { * @usecase def ++(that: => Iterator[A]): Iterator[A] * @inheritdoc */ - def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.JoinIterator(self, that) + def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.ConcatIterator(self) ++ that /** Creates a new iterator by applying a function to all values produced by this iterator * and concatenating the results. @@ -522,13 +560,13 @@ trait Iterator[+A] extends TraversableOnce[A] { def collect[B](pf: PartialFunction[A, B]): Iterator[B] = new AbstractIterator[B] { // Manually buffer to avoid extra layer of wrapping with buffered private[this] var hd: A = _ - + // Little state machine to keep track of where we are // Seek = 0; Found = 1; Empty = -1 // Not in vals because scalac won't make them static (@inline def only works with -optimize) // BE REALLY CAREFUL TO KEEP COMMENTS AND NUMBERS IN SYNC! private[this] var status = 0/*Seek*/ - + def hasNext = { while (status == 0/*Seek*/) { if (self.hasNext) { @@ -698,13 +736,13 @@ trait Iterator[+A] extends TraversableOnce[A] { } def trailer: A = hd } - + val leading = new Leading - + val trailing = new AbstractIterator[A] { private[this] var myLeading = leading - /* Status flags meanings: - * -1 not yet accesssed + /* Status flag meanings: + * -1 not yet accessed * 0 single element waiting in leading * 1 defer to self */ @@ -736,7 +774,7 @@ trait Iterator[+A] extends TraversableOnce[A] { } else Iterator.empty.next() } - + override def toString = "unknown-if-empty iterator" } @@ -770,7 +808,7 @@ trait Iterator[+A] extends TraversableOnce[A] { status = 1 false } - def next() = + def next() = if (hasNext) { if (status == 1) self.next() else { @@ -953,8 +991,25 @@ trait Iterator[+A] extends TraversableOnce[A] { * or -1 if such an element does not exist until the end of the iterator is reached. * @note Reuse: $consumesIterator */ - def indexWhere(p: A => Boolean): Int = { + def indexWhere(p: A => Boolean): Int = indexWhere(p, 0) + + /** Returns the index of the first produced value satisfying a predicate, or -1, after or at + * some start index. + * $mayNotTerminateInf + * + * @param p the predicate to test values + * @param from the start index + * @return the index `>= from` of the first produced value satisfying `p`, + * or -1 if such an element does not exist until the end of the iterator is reached. + * @note Reuse: $consumesIterator + */ + def indexWhere(p: A => Boolean, from: Int): Int = { var i = 0 + while (i < from && hasNext) { + next() + i += 1 + } + while (hasNext) { if (p(next())) return i i += 1 @@ -971,8 +1026,26 @@ trait Iterator[+A] extends TraversableOnce[A] { * or -1 if such an element does not exist until the end of the iterator is reached. * @note Reuse: $consumesIterator */ - def indexOf[B >: A](elem: B): Int = { + def indexOf[B >: A](elem: B): Int = indexOf(elem, 0) + + /** Returns the index of the first occurrence of the specified object in this iterable object + * after or at some start index. + * $mayNotTerminateInf + * + * @param elem element to search for. + * @param from the start index + * @return the index `>= from` of the first occurrence of `elem` in the values produced by this + * iterator, or -1 if such an element does not exist until the end of the iterator is + * reached. + * @note Reuse: $consumesIterator + */ + def indexOf[B >: A](elem: B, from: Int): Int = { var i = 0 + while (i < from && hasNext) { + next() + i += 1 + } + while (hasNext) { if (next() == elem) return i i += 1 @@ -1018,7 +1091,7 @@ trait Iterator[+A] extends TraversableOnce[A] { extends AbstractIterator[Seq[B]] with Iterator[Seq[B]] { - require(size >= 1 && step >= 1, "size=%d and step=%d, but both must be positive".format(size, step)) + require(size >= 1 && step >= 1, f"size=$size%d and step=$step%d, but both must be positive") private[this] var buffer: ArrayBuffer[B] = ArrayBuffer() // the buffer private[this] var filled = false // whether the buffer is "hot" @@ -1026,30 +1099,30 @@ trait Iterator[+A] extends TraversableOnce[A] { private[this] var pad: Option[() => B] = None // what to pad short sequences with /** Public functions which can be used to configure the iterator before use. - * - * Pads the last segment if necessary so that all segments will - * have the same size. - * - * @param x The element that will be appended to the last segment, if necessary. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPartial(true)`. - */ + * + * Pads the last segment if necessary so that all segments will + * have the same size. + * + * @param x The element that will be appended to the last segment, if necessary. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPartial(true)`. + */ def withPadding(x: => B): this.type = { pad = Some(() => x) this } - /** Public functions which can be used to configure the iterator before use. - * - * Select whether the last segment may be returned with less than `size` - * elements. If not, some elements of the original iterator may not be - * returned at all. - * - * @param x `true` if partial segments may be returned, `false` otherwise. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPadding`. - */ + /** Public functions which can be used to configure the iterator before use. + * + * Select whether the last segment may be returned with less than `size` + * elements. If not, some elements of the original iterator may not be + * returned at all. + * + * @param x `true` if partial segments may be returned, `false` otherwise. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPadding`. + */ def withPartial(x: Boolean): this.type = { _partial = x if (_partial == true) // reset pad since otherwise it will take precedence @@ -1158,9 +1231,15 @@ trait Iterator[+A] extends TraversableOnce[A] { new GroupedIterator[B](self, size, size) /** Returns an iterator which presents a "sliding window" view of - * another iterator. The first argument is the window size, and - * the second is how far to advance the window on each iteration; - * defaults to `1`. Example usages: + * this iterator. The first argument is the window size, and + * the second argument `step` is how far to advance the window + * on each iteration. The `step` defaults to `1`. + * + * The default `GroupedIterator` can be configured to either + * pad a partial result to size `size` or suppress the partial + * result entirely. + * + * Example usages: * {{{ * // Returns List(List(1, 2, 3), List(2, 3, 4), List(3, 4, 5)) * (1 to 5).iterator.sliding(3).toList @@ -1174,6 +1253,11 @@ trait Iterator[+A] extends TraversableOnce[A] { * (1 to 5).iterator.sliding(4, 3).withPadding(it2.next).toList * }}} * + * @return An iterator producing `Seq[B]`s of size `size`, except the + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. + * This behavior can be configured. + * * @note Reuse: $consumesAndProducesIterator */ def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] = @@ -1287,7 +1371,6 @@ trait Iterator[+A] extends TraversableOnce[A] { * $willNotTerminateInf */ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = { - require(start >= 0 && (start < xs.length || xs.length == 0), s"start $start out of range ${xs.length}") var i = start val end = start + math.min(len, xs.length - start) while (i < end && hasNext) { diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 7bfa60771f..93994d80bf 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -11,21 +11,21 @@ package collection import convert._ -/** A collection of implicit conversions supporting interoperability between - * Scala and Java collections. +/** A variety of implicit conversions supporting interoperability between + * Scala and Java collections. * - * The following conversions are supported: + * The following conversions are supported: *{{{ - * scala.collection.Iterable <=> java.lang.Iterable - * scala.collection.Iterable <=> java.util.Collection - * scala.collection.Iterator <=> java.util.{ Iterator, Enumeration } + * scala.collection.Iterable <=> java.lang.Iterable + * scala.collection.Iterable <=> java.util.Collection + * scala.collection.Iterator <=> java.util.{ Iterator, Enumeration } * scala.collection.mutable.Buffer <=> java.util.List - * scala.collection.mutable.Set <=> java.util.Set - * scala.collection.mutable.Map <=> java.util.{ Map, Dictionary } + * scala.collection.mutable.Set <=> java.util.Set + * scala.collection.mutable.Map <=> java.util.{ Map, Dictionary } * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap *}}} - * In all cases, converting from a source type to a target type and back - * again will return the original source object, eg. + * In all cases, converting from a source type to a target type and back + * again will return the original source object: * *{{{ * import scala.collection.JavaConversions._ @@ -45,8 +45,16 @@ import convert._ * java.util.Properties => scala.collection.mutable.Map[String, String] *}}} * + * The transparent conversions provided here are considered + * fragile because they can result in unexpected behavior and performance. + * + * Therefore, this API has been deprecated and `JavaConverters` should be + * used instead. `JavaConverters` provides the same conversions, but through + * extension methods. + * * @author Miles Sabin * @author Martin Odersky * @since 2.8 */ +@deprecated("use JavaConverters", since="2.12.0") object JavaConversions extends WrapAsScala with WrapAsJava diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 86e86d4584..2337f0ef84 100644 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -11,50 +11,62 @@ package collection import convert._ -// TODO: I cleaned all this documentation up in JavaConversions, but the -// documentation in here is basically the pre-cleaned-up version with minor -// additions. Would be nice to have in one place. - -/** A collection of decorators that allow converting between - * Scala and Java collections using `asScala` and `asJava` methods. - * - * The following conversions are supported via `asJava`, `asScala` +/** A variety of decorators that enable converting between + * Scala and Java collections using extension methods, `asScala` and `asJava`. * - * - `scala.collection.Iterable` <=> `java.lang.Iterable` - * - `scala.collection.Iterator` <=> `java.util.Iterator` - * - `scala.collection.mutable.Buffer` <=> `java.util.List` - * - `scala.collection.mutable.Set` <=> `java.util.Set` - * - `scala.collection.mutable.Map` <=> `java.util.Map` - * - `scala.collection.mutable.concurrent.Map` <=> `java.util.concurrent.ConcurrentMap` + * The extension methods return adapters for the corresponding API. * + * The following conversions are supported via `asScala` and `asJava`: + *{{{ + * scala.collection.Iterable <=> java.lang.Iterable + * scala.collection.Iterator <=> java.util.Iterator + * scala.collection.mutable.Buffer <=> java.util.List + * scala.collection.mutable.Set <=> java.util.Set + * scala.collection.mutable.Map <=> java.util.Map + * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap + *}}} + * The following conversions are supported via `asScala` and through + * specially-named extension methods to convert to Java collections, as shown: + *{{{ + * scala.collection.Iterable <=> java.util.Collection (via asJavaCollection) + * scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration) + * scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary) + *}}} + * In addition, the following one-way conversions are provided via `asJava`: + *{{{ + * scala.collection.Seq => java.util.List + * scala.collection.mutable.Seq => java.util.List + * scala.collection.Set => java.util.Set + * scala.collection.Map => java.util.Map + *}}} + * The following one way conversion is provided via `asScala`: + *{{{ + * java.util.Properties => scala.collection.mutable.Map + *}}} * In all cases, converting from a source type to a target type and back - * again will return the original source object, e.g. + * again will return the original source object. For example: * {{{ * import scala.collection.JavaConverters._ * - * val sl = new scala.collection.mutable.ListBuffer[Int] - * val jl : java.util.List[Int] = sl.asJava - * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala - * assert(sl eq sl2) + * val source = new scala.collection.mutable.ListBuffer[Int] + * val target: java.util.List[Int] = source.asJava + * val other: scala.collection.mutable.Buffer[Int] = target.asScala + * assert(source eq other) * }}} - * The following conversions are also supported, but the - * direction from Scala to Java is done by the more specifically named methods: - * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`. - * - * - `scala.collection.Iterable` <=> `java.util.Collection` - * - `scala.collection.Iterator` <=> `java.util.Enumeration` - * - `scala.collection.mutable.Map` <=> `java.util.Dictionary` - * - * In addition, the following one way conversions are provided via `asJava`: + * Alternatively, the conversion methods have descriptive names and can be invoked explicitly. + * {{{ + * scala> val vs = java.util.Arrays.asList("hi", "bye") + * vs: java.util.List[String] = [hi, bye] * - * - `scala.collection.Seq` => `java.util.List` - * - `scala.collection.mutable.Seq` => `java.util.List` - * - `scala.collection.Set` => `java.util.Set` - * - `scala.collection.Map` => `java.util.Map` + * scala> val ss = asScalaIterator(vs.iterator) + * ss: Iterator[String] = non-empty iterator * - * The following one way conversion is provided via `asScala`: + * scala> .toList + * res0: List[String] = List(hi, bye) * - * - `java.util.Properties` => `scala.collection.mutable.Map` + * scala> val ss = asScalaBuffer(vs) + * ss: scala.collection.mutable.Buffer[String] = Buffer(hi, bye) + * }}} * * @since 2.8.1 */ diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala index b7af8840a9..68b85dcfe5 100644 --- a/src/library/scala/collection/LinearSeqOptimized.scala +++ b/src/library/scala/collection/LinearSeqOptimized.scala @@ -9,8 +9,6 @@ package scala package collection -import mutable.ListBuffer -import immutable.List import scala.annotation.tailrec /** A template trait for linear sequences of type `LinearSeq[A]` which optimizes @@ -133,9 +131,9 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea else op(head, tail.foldRight(z)(op)) override /*TraversableLike*/ - def reduceLeft[B >: A](f: (B, A) => B): B = + def reduceLeft[B >: A](@deprecatedName('f) op: (B, A) => B): B = if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") - else tail.foldLeft[B](head)(f) + else tail.foldLeft[B](head)(op) override /*IterableLike*/ def reduceRight[B >: A](op: (A, B) => B): B = @@ -293,7 +291,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea override /*SeqLike*/ def indexWhere(p: A => Boolean, from: Int): Int = { - var i = from + var i = math.max(from, 0) var these = this drop from while (these.nonEmpty) { if (p(these.head)) diff --git a/src/library/scala/collection/Map.scala b/src/library/scala/collection/Map.scala index 1e40fd8c24..c9a943f1f7 100644 --- a/src/library/scala/collection/Map.scala +++ b/src/library/scala/collection/Map.scala @@ -12,7 +12,7 @@ package collection import generic._ /** - * A map from keys of type `A` to values of type `B`. + * A map from keys of type `K` to values of type `V`. * * $mapNote * @@ -22,15 +22,15 @@ import generic._ * '''Note:''' If your additions and mutations return the same kind of map as the map * you are defining, you should inherit from `MapLike` as well. * - * @tparam A the type of the keys in this map. - * @tparam B the type of the values associated with keys. + * @tparam K the type of the keys in this map. + * @tparam V the type of the values associated with keys. * * @since 1.0 */ -trait Map[A, +B] extends Iterable[(A, B)] with GenMap[A, B] with MapLike[A, B, Map[A, B]] { - def empty: Map[A, B] = Map.empty +trait Map[K, +V] extends Iterable[(K, V)] with GenMap[K, V] with MapLike[K, V, Map[K, V]] { + def empty: Map[K, V] = Map.empty - override def seq: Map[A, B] = this + override def seq: Map[K, V] = this } /** $factoryInfo @@ -38,22 +38,22 @@ trait Map[A, +B] extends Iterable[(A, B)] with GenMap[A, B] with MapLike[A, B, M * @define coll map */ object Map extends MapFactory[Map] { - def empty[A, B]: immutable.Map[A, B] = immutable.Map.empty + def empty[K, V]: immutable.Map[K, V] = immutable.Map.empty /** $mapCanBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] = new MapCanBuildFrom[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: Map[A, B], d: A => B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + abstract class WithDefault[K, +V](underlying: Map[K, V], d: K => V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = underlying.size - def get(key: A) = underlying.get(key) // removed in 2.9: orElse Some(default(key)) + def get(key: K) = underlying.get(key) // removed in 2.9: orElse Some(default(key)) def iterator = underlying.iterator - override def default(key: A): B = d(key) + override def default(key: K): V = d(key) } } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -abstract class AbstractMap[A, +B] extends AbstractIterable[(A, B)] with Map[A, B] +abstract class AbstractMap[K, +V] extends AbstractIterable[(K, V)] with Map[K, V] diff --git a/src/library/scala/collection/MapLike.scala b/src/library/scala/collection/MapLike.scala index 99ed67325c..a087cb0f45 100644 --- a/src/library/scala/collection/MapLike.scala +++ b/src/library/scala/collection/MapLike.scala @@ -11,7 +11,7 @@ package collection import generic._ import mutable.{ Builder, MapBuilder } -import scala.annotation.{migration, bridge} +import scala.annotation.migration import parallel.ParMap /** A template trait for maps, which associate keys with values. @@ -28,10 +28,10 @@ import parallel.ParMap * To implement a concrete map, you need to provide implementations of the * following methods: * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def + [B1 >: B](kv: (A, B1)): This - * def -(key: A): This + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def + [V1 >: V](kv: (K, V1)): This + * def -(key: K): This * }}} * If you wish that methods like `take`, `drop`, `filter` also return the same kind of map * you should also override: @@ -42,8 +42,8 @@ import parallel.ParMap * `size` for efficiency. * * @define mapTags - * @tparam A the type of the keys. - * @tparam B the type of associated values. + * @tparam K the type of the keys. + * @tparam V the type of associated values. * @tparam This the type of the map itself. * * @author Martin Odersky @@ -54,12 +54,12 @@ import parallel.ParMap * @define willNotTerminateInf * @define mayNotTerminateInf */ -trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] - extends PartialFunction[A, B] - with IterableLike[(A, B), This] - with GenMapLike[A, B, This] - with Subtractable[A, This] - with Parallelizable[(A, B), ParMap[A, B]] +trait MapLike[K, +V, +This <: MapLike[K, V, This] with Map[K, V]] + extends PartialFunction[K, V] + with IterableLike[(K, V), This] + with GenMapLike[K, V, This] + with Subtractable[K, This] + with Parallelizable[(K, V), ParMap[K, V]] { self => @@ -71,7 +71,7 @@ self => /** A common implementation of `newBuilder` for all maps in terms of `empty`. * Overridden for mutable maps in `mutable.MapLike`. */ - override protected[this] def newBuilder: Builder[(A, B), This] = new MapBuilder[A, B, This](empty) + override protected[this] def newBuilder: Builder[(K, V), This] = new MapBuilder[K, V, This](empty) /** Optionally returns the value associated with a key. * @@ -79,32 +79,32 @@ self => * @return an option value containing the value associated with `key` in this map, * or `None` if none exists. */ - def get(key: A): Option[B] + def get(key: K): Option[V] /** Creates a new iterator over all key/value pairs of this map * * @return the new iterator */ - def iterator: Iterator[(A, B)] + def iterator: Iterator[(K, V)] /** Adds a key/value pair to this map, returning a new map. * @param kv the key/value pair - * @tparam B1 the type of the value in the key/value pair. + * @tparam V1 the type of the value in the key/value pair. * @return a new map with the new binding added to this map * - * @usecase def + (kv: (A, B)): Map[A, B] + * @usecase def + (kv: (K, V)): Map[K, V] * @inheritdoc */ - def + [B1 >: B] (kv: (A, B1)): Map[A, B1] + def + [V1 >: V] (kv: (K, V1)): Map[K, V1] /** Removes a key from this map, returning a new map. * @param key the key to be removed * @return a new map without a binding for `key` * - * @usecase def - (key: A): Map[A, B] + * @usecase def - (key: K): Map[K, V] * @inheritdoc */ - def - (key: A): This + def - (key: K): This /** Tests whether the map is empty. * @@ -116,14 +116,14 @@ self => * @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. + * @tparam V1 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 + * @usecase def getOrElse(key: K, default: => V): V * @inheritdoc */ - def getOrElse[B1 >: B](key: A, default: => B1): B1 = get(key) match { + def getOrElse[V1 >: V](key: K, default: => V1): V1 = get(key) match { case Some(v) => v case None => default } @@ -137,7 +137,7 @@ self => * @return the value associated with the given key, or the result of the * map's `default` method, if none exists. */ - def apply(key: A): B = get(key) match { + def apply(key: K): V = get(key) match { case None => default(key) case Some(value) => value } @@ -147,7 +147,7 @@ self => * @param key the key * @return `true` if there is a binding for `key` in this map, `false` otherwise. */ - def contains(key: A): Boolean = get(key).isDefined + def contains(key: K): Boolean = get(key).isDefined /** Tests whether this map contains a binding for a key. This method, * which implements an abstract method of trait `PartialFunction`, @@ -156,29 +156,33 @@ self => * @param key the key * @return `true` if there is a binding for `key` in this map, `false` otherwise. */ - def isDefinedAt(key: A) = contains(key) + def isDefinedAt(key: K) = contains(key) + + override /*PartialFunction*/ + def applyOrElse[K1 <: K, V1 >: V](x: K1, default: K1 => V1): V1 = + getOrElse(x, default(x)) /** Collects all keys of this map in a set. * @return a set containing all keys of this map. */ - def keySet: Set[A] = new DefaultKeySet + def keySet: Set[K] = new DefaultKeySet /** The implementation class of the set returned by `keySet`. */ - protected class DefaultKeySet extends AbstractSet[A] with Set[A] with Serializable { - def contains(key : A) = self.contains(key) + protected class DefaultKeySet extends AbstractSet[K] with Set[K] with Serializable { + def contains(key : K) = self.contains(key) def iterator = keysIterator - def + (elem: A): Set[A] = (Set[A]() ++ this + elem).asInstanceOf[Set[A]] // !!! concrete overrides abstract problem - def - (elem: A): Set[A] = (Set[A]() ++ this - elem).asInstanceOf[Set[A]] // !!! concrete overrides abstract problem + def + (elem: K): Set[K] = (Set[K]() ++ this + elem).asInstanceOf[Set[K]] // !!! concrete overrides abstract problem + def - (elem: K): Set[K] = (Set[K]() ++ this - elem).asInstanceOf[Set[K]] // !!! concrete overrides abstract problem override def size = self.size - override def foreach[U](f: A => U) = self.keysIterator foreach f + override def foreach[U](f: K => U) = self.keysIterator foreach f } /** Creates an iterator for all keys. * * @return an iterator over all keys. */ - def keysIterator: Iterator[A] = new AbstractIterator[A] { + def keysIterator: Iterator[K] = new AbstractIterator[K] { val iter = self.iterator def hasNext = iter.hasNext def next() = iter.next()._1 @@ -188,29 +192,29 @@ self => * * @return the keys of this map as an iterable. */ - @migration("`keys` returns `Iterable[A]` rather than `Iterator[A]`.", "2.8.0") - def keys: Iterable[A] = keySet + @migration("`keys` returns `Iterable[K]` rather than `Iterator[K]`.", "2.8.0") + def keys: Iterable[K] = keySet /** Collects all values of this map in an iterable collection. * * @return the values of this map as an iterable. */ - @migration("`values` returns `Iterable[B]` rather than `Iterator[B]`.", "2.8.0") - def values: Iterable[B] = new DefaultValuesIterable + @migration("`values` returns `Iterable[V]` rather than `Iterator[V]`.", "2.8.0") + def values: Iterable[V] = new DefaultValuesIterable /** The implementation class of the iterable returned by `values`. */ - protected class DefaultValuesIterable extends AbstractIterable[B] with Iterable[B] with Serializable { + protected class DefaultValuesIterable extends AbstractIterable[V] with Iterable[V] with Serializable { def iterator = valuesIterator override def size = self.size - override def foreach[U](f: B => U) = self.valuesIterator foreach f + override def foreach[U](f: V => U) = self.valuesIterator foreach f } /** 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] = new AbstractIterator[B] { + def valuesIterator: Iterator[V] = new AbstractIterator[V] { val iter = self.iterator def hasNext = iter.hasNext def next() = iter.next()._2 @@ -224,29 +228,33 @@ self => * @param key the given key value for which a binding is missing. * @throws NoSuchElementException */ - def default(key: A): B = + def default(key: K): V = throw new NoSuchElementException("key not found: " + key) - protected class FilteredKeys(p: A => Boolean) extends AbstractMap[A, B] with DefaultMap[A, B] { - override def foreach[U](f: ((A, B)) => U): Unit = for (kv <- self) if (p(kv._1)) f(kv) + protected class FilteredKeys(p: K => Boolean) extends AbstractMap[K, V] with DefaultMap[K, V] { + override def foreach[U](f: ((K, V)) => U): Unit = for (kv <- self) if (p(kv._1)) f(kv) def iterator = self.iterator.filter(kv => p(kv._1)) - override def contains(key: A) = self.contains(key) && p(key) - def get(key: A) = if (!p(key)) None else self.get(key) + override def contains(key: K) = p(key) && self.contains(key) + def get(key: K) = if (!p(key)) None else self.get(key) } /** Filters this map by retaining only keys satisfying a predicate. + * + * '''Note''': the predicate must accept any key of type `K`, not just those already + * present in the map, as the predicate is tested before the underlying map is queried. + * * @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): Map[A, B] = new FilteredKeys(p) + def filterKeys(p: K => Boolean): Map[K, V] = new FilteredKeys(p) - protected class MappedValues[C](f: B => C) extends AbstractMap[A, C] with DefaultMap[A, C] { - override def foreach[U](g: ((A, C)) => U): Unit = for ((k, v) <- self) g((k, f(v))) + protected class MappedValues[W](f: V => W) extends AbstractMap[K, W] with DefaultMap[K, W] { + override def foreach[U](g: ((K, W)) => U): Unit = for ((k, v) <- self) g((k, f(v))) def iterator = for ((k, v) <- self.iterator) yield (k, f(v)) override def size = self.size - override def contains(key: A) = self.contains(key) - def get(key: A) = self.get(key).map(f) + override def contains(key: K) = self.contains(key) + def get(key: K) = self.get(key).map(f) } /** Transforms this map by applying a function to every retrieved value. @@ -254,22 +262,22 @@ self => * @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): Map[A, C] = new MappedValues(f) + def mapValues[W](f: V => W): Map[K, W] = new MappedValues(f) // The following 5 operations (updated, two times +, two times ++) should really be - // generic, returning This[B]. We need better covariance support to express that though. + // generic, returning This[V]. We need better covariance support to express that though. // So right now we do the brute force approach of code duplication. /** Creates a new map obtained by updating this map with a given key/value pair. * @param key the key * @param value the value - * @tparam B1 the type of the added value + * @tparam V1 the type of the added value * @return A new map with the new key/value mapping added to this map. * - * @usecase def updated(key: A, value: B): Map[A, B] + * @usecase def updated(key: K, value: V): Map[K, V] * @inheritdoc */ - def updated [B1 >: B](key: A, value: B1): Map[A, B1] = this + ((key, value)) + def updated [V1 >: V](key: K, value: V1): Map[K, V1] = this + ((key, value)) /** Adds key/value pairs to this map, returning a new map. * @@ -279,27 +287,27 @@ self => * @param kv1 the first key/value pair * @param kv2 the second key/value pair * @param kvs the remaining key/value pairs - * @tparam B1 the type of the added values + * @tparam V1 the type of the added values * @return a new map with the given bindings added to this map * - * @usecase def + (kvs: (A, B)*): Map[A, B] + * @usecase def + (kvs: (K, V)*): Map[K, V] * @inheritdoc * @param kvs the key/value pairs */ - def + [B1 >: B] (kv1: (A, B1), kv2: (A, B1), kvs: (A, B1) *): Map[A, B1] = + def + [V1 >: V] (kv1: (K, V1), kv2: (K, V1), kvs: (K, V1) *): Map[K, V1] = this + kv1 + kv2 ++ kvs /** Adds all key/value pairs in a traversable collection to this map, returning a new map. * * @param xs the collection containing the added key/value pairs - * @tparam B1 the type of the added values + * @tparam V1 the type of the added values * @return a new map with the given bindings added to this map * - * @usecase def ++ (xs: Traversable[(A, B)]): Map[A, B] + * @usecase def ++ (xs: Traversable[(K, V)]): Map[K, V] * @inheritdoc */ - def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1] = - ((repr: Map[A, B1]) /: xs.seq) (_ + _) + def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): Map[K, V1] = + ((repr: Map[K, V1]) /: xs.seq) (_ + _) /** Returns a new map obtained by removing all key/value pairs for which the predicate * `p` returns `true`. @@ -312,22 +320,31 @@ self => * @param p A predicate over key-value pairs * @return A new map containing elements not satisfying the predicate. */ - override def filterNot(p: ((A, B)) => Boolean): This = { + override def filterNot(p: ((K, V)) => Boolean): This = { var res: This = repr for (kv <- this) if (p(kv)) res = (res - kv._1).asInstanceOf[This] // !!! concrete overrides abstract problem res } - /* Overridden for efficiency. */ - override def toSeq: Seq[(A, B)] = toBuffer[(A, B)] - override def toBuffer[C >: (A, B)]: mutable.Buffer[C] = { - val result = new mutable.ArrayBuffer[C](size) - copyToBuffer(result) + override def toSeq: Seq[(K, V)] = { + if (isEmpty) Vector.empty[(K, V)] + else { + // Default appropriate for immutable collections; mutable collections override this + val vb = Vector.newBuilder[(K, V)] + foreach(vb += _) + vb.result + } + } + + override def toBuffer[E >: (K, V)]: mutable.Buffer[E] = { + val result = new mutable.ArrayBuffer[E](size) + // Faster to let the map iterate itself than to defer through copyToBuffer + foreach(result += _) result } - protected[this] override def parCombiner = ParMap.newCombiner[A, B] + protected[this] override def parCombiner = ParMap.newCombiner[K, V] /** Appends all bindings of this map to a string builder using start, end, and separator strings. * The written text begins with the string `start` and ends with the string diff --git a/src/library/scala/collection/MapProxy.scala b/src/library/scala/collection/MapProxy.scala index 26a7c710ee..2faf689973 100644 --- a/src/library/scala/collection/MapProxy.scala +++ b/src/library/scala/collection/MapProxy.scala @@ -17,5 +17,5 @@ package collection * @version 1.0, 21/07/2003 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait MapProxy[A, +B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] diff --git a/src/library/scala/collection/MapProxyLike.scala b/src/library/scala/collection/MapProxyLike.scala index dd80a538e3..73a6935788 100644 --- a/src/library/scala/collection/MapProxyLike.scala +++ b/src/library/scala/collection/MapProxyLike.scala @@ -18,7 +18,7 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait MapProxyLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] extends MapLike[A, B, This] with IterableProxyLike[(A, B), This] diff --git a/src/library/scala/collection/Parallelizable.scala b/src/library/scala/collection/Parallelizable.scala index b737752458..c131556388 100644 --- a/src/library/scala/collection/Parallelizable.scala +++ b/src/library/scala/collection/Parallelizable.scala @@ -12,7 +12,7 @@ package collection import parallel.Combiner /** This trait describes collections which can be turned into parallel collections - * by invoking the method `par`. Parallelizable collections may be parametrized with + * by invoking the method `par`. Parallelizable collections may be parameterized with * a target type different than their own. * * @tparam A the type of the elements in the collection diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index b775480532..3e025bc43f 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -9,11 +9,10 @@ package scala package collection -import mutable.{ ListBuffer, ArraySeq } import immutable.{ List, Range } import generic._ import parallel.ParSeq -import scala.math.{ min, max, Ordering } +import scala.math.Ordering /** A template trait for sequences of type `Seq[A]` * $seqInfo @@ -114,13 +113,12 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ } def indexWhere(p: A => Boolean, from: Int): Int = { - var i = from + var i = math.max(from, 0) val it = iterator.drop(from) while (it.hasNext) { if (p(it.next())) return i else i += 1 } - -1 } @@ -146,7 +144,7 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ * more than one way to generate the same subsequence, only one will be returned. * * For example, `"xyyy"` has three different ways to generate `"xy"` depending on - * whether the first, second, or third `"y"` is selected. However, since all are + * whether the first, second, or third `"y"` is selected. However, since all are * identical, only one will be chosen. Which of the three will be taken is an * implementation detail that is not defined. * diff --git a/src/library/scala/collection/SeqProxy.scala b/src/library/scala/collection/SeqProxy.scala index f728ba8585..f2b39c7b55 100644 --- a/src/library/scala/collection/SeqProxy.scala +++ b/src/library/scala/collection/SeqProxy.scala @@ -18,5 +18,5 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SeqProxy[+A] extends Seq[A] with SeqProxyLike[A, Seq[A]] diff --git a/src/library/scala/collection/SeqProxyLike.scala b/src/library/scala/collection/SeqProxyLike.scala index b01d227d10..b493c70796 100644 --- a/src/library/scala/collection/SeqProxyLike.scala +++ b/src/library/scala/collection/SeqProxyLike.scala @@ -23,7 +23,7 @@ import generic._ * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SeqProxyLike[+A, +Repr <: SeqLike[A, Repr] with Seq[A]] extends SeqLike[A, Repr] with IterableProxyLike[A, Repr] { override def size = self.size override def toSeq: Seq[A] = self.toSeq diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index 3473c8aff1..1fbcb6531e 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -96,6 +96,14 @@ trait SeqViewLike[+A, if (idx < self.length) self(idx) else restSeq(idx - self.length) } + trait Prepended[B >: A] extends super.Prepended[B] with Transformed[B] { + protected[this] lazy val fstSeq = fst.toSeq + def length: Int = fstSeq.length + self.length + def apply(idx: Int): B = + if (idx < fstSeq.length) fstSeq(idx) + else self.apply(idx - fstSeq.length) + } + trait Filtered extends super.Filtered with Transformed[A] { protected[this] lazy val index = { var len = 0 @@ -179,21 +187,12 @@ trait SeqViewLike[+A, final override protected[this] def viewIdentifier = "P" } - trait Prepended[B >: A] extends Transformed[B] { - protected[this] val fst: B - override def iterator: Iterator[B] = Iterator.single(fst) ++ self.iterator - def length: Int = 1 + self.length - def apply(idx: Int): B = - if (idx == 0) fst - else self.apply(idx - 1) - final override protected[this] def viewIdentifier = "A" - } - /** Boilerplate method, to override in each subclass * This method could be eliminated if Scala had virtual classes */ protected override def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { protected[this] val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered @@ -212,7 +211,6 @@ trait SeqViewLike[+A, val patch = _patch val replaced = _replaced } with AbstractTransformed[B] with Patched[B] - protected def newPrepended[B >: A](elem: B): Transformed[B] = new { protected[this] val fst = elem } with AbstractTransformed[B] with Prepended[B] // see comment in IterableViewLike. protected override def newTaken(n: Int): Transformed[A] = newSliced(SliceInterval(0, n)) @@ -242,7 +240,7 @@ trait SeqViewLike[+A, } override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = - newPrepended(elem).asInstanceOf[That] + newPrepended(elem :: Nil).asInstanceOf[That] override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = ++(Iterator.single(elem))(bf) diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala index f8ac1d754d..440452ce99 100644 --- a/src/library/scala/collection/SetLike.scala +++ b/src/library/scala/collection/SetLike.scala @@ -11,7 +11,7 @@ package collection import generic._ import mutable.{ Builder, SetBuilder } -import scala.annotation.{migration, bridge} +import scala.annotation.migration import parallel.ParSet /** A template trait for sets. @@ -77,11 +77,20 @@ self => protected[this] override def parCombiner = ParSet.newCombiner[A] - /* Overridden for efficiency. */ - override def toSeq: Seq[A] = toBuffer[A] + // Default collection type appropriate for immutable collections; mutable collections override this + override def toSeq: Seq[A] = { + if (isEmpty) Vector.empty[A] + else { + val vb = Vector.newBuilder[A] + foreach(vb += _) + vb.result + } + } + override def toBuffer[A1 >: A]: mutable.Buffer[A1] = { val result = new mutable.ArrayBuffer[A1](size) - copyToBuffer(result) + // Faster to let the map iterate itself than to defer through copyToBuffer + foreach(result += _) result } @@ -204,9 +213,9 @@ self => } } - /** An Iterator include all subsets containing exactly len elements. + /** An Iterator including all subsets containing exactly len elements. * If the elements in 'This' type is ordered, then the subsets will also be in the same order. - * ListSet(1,2,3).subsets => {1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}} + * ListSet(1,2,3).subsets => {{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}} * * @author Eastsun * @date 2010.12.6 diff --git a/src/library/scala/collection/SetProxy.scala b/src/library/scala/collection/SetProxy.scala index e17fb215b9..4a3fc17a78 100644 --- a/src/library/scala/collection/SetProxy.scala +++ b/src/library/scala/collection/SetProxy.scala @@ -17,5 +17,5 @@ package collection * @author Martin Odersky * @version 2.0, 01/01/2007 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]] diff --git a/src/library/scala/collection/SetProxyLike.scala b/src/library/scala/collection/SetProxyLike.scala index 4cd215cd89..fa23fe5450 100644 --- a/src/library/scala/collection/SetProxyLike.scala +++ b/src/library/scala/collection/SetProxyLike.scala @@ -17,7 +17,7 @@ package collection * @author Martin Odersky * @version 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SetProxyLike[A, +This <: SetLike[A, This] with Set[A]] extends SetLike[A, This] with IterableProxyLike[A, This] { def empty: This override def contains(elem: A): Boolean = self.contains(elem) diff --git a/src/library/scala/collection/SortedSet.scala b/src/library/scala/collection/SortedSet.scala index 43189d2e8c..0fa5ce0966 100644 --- a/src/library/scala/collection/SortedSet.scala +++ b/src/library/scala/collection/SortedSet.scala @@ -29,6 +29,6 @@ trait SortedSet[A] extends Set[A] with SortedSetLike[A, SortedSet[A]] { object SortedSet extends SortedSetFactory[SortedSet] { def empty[A](implicit ord: Ordering[A]): immutable.SortedSet[A] = immutable.SortedSet.empty[A](ord) def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = newCanBuildFrom[A] - // Force a declaration here so that BitSet's (which does not inherit from SortedSetFactory) can be more specific + // Force a declaration here so that BitSet (which does not inherit from SortedSetFactory) can be more specific override implicit def newCanBuildFrom[A](implicit ord : Ordering[A]) : CanBuildFrom[Coll, A, SortedSet[A]] = super.newCanBuildFrom } diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index bbbc33b3f5..c9482fe0a2 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -11,7 +11,7 @@ package collection import generic._ import mutable.{ Builder } -import scala.annotation.{tailrec, migration, bridge} +import scala.annotation.migration import scala.annotation.unchecked.{ uncheckedVariance => uV } import parallel.ParIterable import scala.language.higherKinds @@ -242,7 +242,7 @@ trait TraversableLike[+A, +Repr] extends Any b.result } - private def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { + private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { val b = newBuilder for (x <- this) if (p(x) != isFlipped) b += x @@ -605,13 +605,69 @@ trait TraversableLike[+A, +Repr] extends Any * applied to this $coll. By default the string prefix is the * simple name of the collection class $coll. */ - def stringPrefix : String = { - var string = repr.getClass.getName - val idx1 = string.lastIndexOf('.' : Int) - if (idx1 != -1) string = string.substring(idx1 + 1) - val idx2 = string.indexOf('$') - if (idx2 != -1) string = string.substring(0, idx2) - string + def stringPrefix: String = { + /* This method is written in a style that avoids calling `String.split()` + * as well as methods of java.lang.Character that require the Unicode + * database information. This is mostly important for Scala.js, so that + * using the collection library does automatically bring java.util.regex.* + * and the Unicode database in the generated code. + * + * This algorithm has the additional benefit that it won't allocate + * anything except the result String in the common case, where the class + * is not an inner class (i.e., when the result contains no '.'). + */ + val fqn = repr.getClass.getName + var pos: Int = fqn.length - 1 + + // Skip trailing $'s + while (pos != -1 && fqn.charAt(pos) == '$') { + pos -= 1 + } + if (pos == -1 || fqn.charAt(pos) == '.') { + return "" + } + + var result: String = "" + while (true) { + // Invariant: if we enter the loop, there is a non-empty part + + // Look for the beginning of the part, remembering where was the last non-digit + val partEnd = pos + 1 + while (pos != -1 && fqn.charAt(pos) <= '9' && fqn.charAt(pos) >= '0') { + pos -= 1 + } + val lastNonDigit = pos + while (pos != -1 && fqn.charAt(pos) != '$' && fqn.charAt(pos) != '.') { + pos -= 1 + } + val partStart = pos + 1 + + // A non-last part which contains only digits marks a method-local part -> drop the prefix + if (pos == lastNonDigit && partEnd != fqn.length) { + return result + } + + // Skip to the next part, and determine whether we are the end + while (pos != -1 && fqn.charAt(pos) == '$') { + pos -= 1 + } + val atEnd = pos == -1 || fqn.charAt(pos) == '.' + + // Handle the actual content of the part (we ignore parts that are likely synthetic) + def isPartLikelySynthetic = { + val firstChar = fqn.charAt(partStart) + (firstChar > 'Z' && firstChar < 0x7f) || (firstChar < 'A') + } + if (atEnd || !isPartLikelySynthetic) { + val part = fqn.substring(partStart, partEnd) + result = if (result.isEmpty) part else part + '.' + result + if (atEnd) + return result + } + } + + // dead code + result } /** Creates a non-strict view of this $coll. diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index 75c0d82922..b87fcd166e 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -9,7 +9,7 @@ package scala package collection -import mutable.{ Buffer, Builder, ListBuffer, ArrayBuffer } +import mutable.{ Buffer, Builder, ArrayBuffer } import generic.CanBuildFrom import scala.annotation.unchecked.{ uncheckedVariance => uV } import scala.language.{implicitConversions, higherKinds} diff --git a/src/library/scala/collection/TraversableProxy.scala b/src/library/scala/collection/TraversableProxy.scala index 9eec685d10..0c7219c5f9 100644 --- a/src/library/scala/collection/TraversableProxy.scala +++ b/src/library/scala/collection/TraversableProxy.scala @@ -21,5 +21,5 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait TraversableProxy[+A] extends Traversable[A] with TraversableProxyLike[A, Traversable[A]] diff --git a/src/library/scala/collection/TraversableProxyLike.scala b/src/library/scala/collection/TraversableProxyLike.scala index fa470ea238..c8b641f88b 100644 --- a/src/library/scala/collection/TraversableProxyLike.scala +++ b/src/library/scala/collection/TraversableProxyLike.scala @@ -24,7 +24,7 @@ import scala.reflect.ClassTag * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait TraversableProxyLike[+A, +Repr <: TraversableLike[A, Repr] with Traversable[A]] extends TraversableLike[A, Repr] with Proxy { def self: Repr diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 5926c69ebf..0901d749c3 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -189,6 +189,15 @@ trait TraversableViewLike[+A, } final override protected[this] def viewIdentifier = "A" } + + trait Prepended[B >: A] extends Transformed[B] { + protected[this] val fst: GenTraversable[B] + def foreach[U](f: B => U) { + fst foreach f + self foreach f + } + final override protected[this] def viewIdentifier = "A" + } trait Filtered extends Transformed[A] { protected[this] val pred: A => Boolean @@ -222,11 +231,15 @@ trait TraversableViewLike[+A, final override protected[this] def viewIdentifier = "D" } - override def ++[B >: A, That](xs: GenTraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = { + override def ++[B >: A, That](xs: GenTraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = newAppended(xs.seq.toTraversable).asInstanceOf[That] -// was: if (bf.isInstanceOf[ByPassCanBuildFrom]) newAppended(that).asInstanceOf[That] -// else super.++[B, That](that)(bf) - } + + override def ++:[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = + newPrepended(xs.seq.toTraversable).asInstanceOf[That] + + // Need second one because of optimization in TraversableLike + override def ++:[B >: A, That](xs: Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = + newPrepended(xs).asInstanceOf[That] override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = { newMapped(f).asInstanceOf[That] @@ -253,6 +266,7 @@ trait TraversableViewLike[+A, */ protected def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val fst = that } with AbstractTransformed[B] with Prepended[B] protected def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered diff --git a/src/library/scala/collection/concurrent/Map.scala b/src/library/scala/collection/concurrent/Map.scala index cfb567abe9..f27dfd57fc 100644 --- a/src/library/scala/collection/concurrent/Map.scala +++ b/src/library/scala/collection/concurrent/Map.scala @@ -86,4 +86,15 @@ trait Map[A, B] extends scala.collection.mutable.Map[A, B] { * @return `Some(v)` if the given key was previously mapped to some value `v`, or `None` otherwise */ def replace(k: A, v: B): Option[B] + + override def getOrElseUpdate(key: A, op: =>B): B = get(key) match { + case Some(v) => v + case None => + val v = op + putIfAbsent(key, v) match { + case Some(nv) => nv + case None => v + } + } + } diff --git a/src/library/scala/collection/concurrent/TrieMap.scala b/src/library/scala/collection/concurrent/TrieMap.scala index bcfea7a463..fe0b5c4f0e 100644 --- a/src/library/scala/collection/concurrent/TrieMap.scala +++ b/src/library/scala/collection/concurrent/TrieMap.scala @@ -11,13 +11,11 @@ package collection package concurrent import java.util.concurrent.atomic._ -import scala.collection.immutable.{ ListMap => ImmutableListMap } import scala.collection.parallel.mutable.ParTrieMap import scala.util.hashing.Hashing import scala.util.control.ControlThrowable import generic._ import scala.annotation.tailrec -import scala.annotation.switch private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends INodeBase[K, V](g) { import INodeBase._ @@ -471,7 +469,7 @@ private[collection] final class CNode[K, V](val bitmap: Int, val array: Array[Ba val offset = if (array.length > 0) //util.Random.nextInt(array.length) /* <-- benchmarks show that this causes observable contention */ - scala.concurrent.forkjoin.ThreadLocalRandom.current.nextInt(0, array.length) + java.util.concurrent.ThreadLocalRandom.current.nextInt(0, array.length) else 0 while (i < array.length) { val pos = (i + offset) % array.length @@ -641,7 +639,8 @@ extends scala.collection.concurrent.Map[K, V] private var rootupdater = rtupd def hashing = hashingobj def equality = equalityobj - @volatile var root = r + @deprecated("this field will be made private", "2.12.0") + @volatile /*private*/ var root = r def this(hashf: Hashing[K], ef: Equiv[K]) = this( INode.newRootNode, @@ -685,11 +684,14 @@ extends scala.collection.concurrent.Map[K, V] } while (obj != TrieMapSerializationEnd) } - def CAS_ROOT(ov: AnyRef, nv: AnyRef) = rootupdater.compareAndSet(this, ov, nv) + @deprecated("this method will be made private", "2.12.0") + /*private*/ def CAS_ROOT(ov: AnyRef, nv: AnyRef) = rootupdater.compareAndSet(this, ov, nv) - def readRoot(abort: Boolean = false): INode[K, V] = RDCSS_READ_ROOT(abort) + @deprecated("this method will be made private", "2.12.0") + /*private[collection]*/ def readRoot(abort: Boolean = false): INode[K, V] = RDCSS_READ_ROOT(abort) - def RDCSS_READ_ROOT(abort: Boolean = false): INode[K, V] = { + @deprecated("this method will be made private", "2.12.0") + /*private[concurrent]*/ def RDCSS_READ_ROOT(abort: Boolean = false): INode[K, V] = { val r = /*READ*/root r match { case in: INode[K, V] => in @@ -884,7 +886,7 @@ extends scala.collection.concurrent.Map[K, V] * * If the specified mapping function throws an exception, * that exception is rethrown. - * + * * Note: This method will invoke op at most once. * However, `op` may be invoked without the result being added to the map if * a concurrent process is also trying to add a value corresponding to the @@ -930,6 +932,33 @@ extends scala.collection.concurrent.Map[K, V] if (nonReadOnly) readOnlySnapshot().iterator else new TrieMapIterator(0, this) + //////////////////////////////////////////////////////////////////////////// + // + // SI-10177 These methods need overrides as the inherited implementations + // call `.iterator` more than once, which doesn't guarantee a coherent + // view of the data if there is a concurrent writer + // Note that the we don't need overrides for keysIterator or valuesIterator + // TrieMapTest validates the behaviour. + override def values: Iterable[V] = { + if (nonReadOnly) readOnlySnapshot().values + else super.values + } + override def keySet: Set[K] = { + if (nonReadOnly) readOnlySnapshot().keySet + else super.keySet + } + override def filterKeys(p: K => Boolean): collection.Map[K, V] = { + if (nonReadOnly) readOnlySnapshot().filterKeys(p) + else super.filterKeys(p) + } + override def mapValues[W](f: V => W): collection.Map[K, W] = { + if (nonReadOnly) readOnlySnapshot().mapValues(f) + else super.mapValues(f) + } + // END extra overrides + /////////////////////////////////////////////////////////////////// + + private def cachedSize() = { val r = RDCSS_READ_ROOT() r.cachedSize(this) @@ -1083,6 +1112,7 @@ private[collection] class TrieMapIterator[K, V](var level: Int, private var ct: Seq(this) } + @deprecated("this method will be removed", "2.12.0") def printDebug() { println("ctrie iterator") println(stackpos.mkString(",")) @@ -1103,14 +1133,14 @@ private[concurrent] case object TrieMapSerializationEnd private[concurrent] object Debug { - import scala.collection._ + import JavaConverters._ lazy val logbuffer = new java.util.concurrent.ConcurrentLinkedQueue[AnyRef] def log(s: AnyRef) = logbuffer.add(s) def flush() { - for (s <- JavaConversions.asScalaIterator(logbuffer.iterator())) Console.out.println(s.toString) + for (s <- logbuffer.iterator().asScala) Console.out.println(s.toString) logbuffer.clear() } diff --git a/src/library/scala/collection/convert/AsJavaConverters.scala b/src/library/scala/collection/convert/AsJavaConverters.scala new file mode 100644 index 0000000000..c7c1fb9c74 --- /dev/null +++ b/src/library/scala/collection/convert/AsJavaConverters.scala @@ -0,0 +1,262 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package convert + +import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } + +/** Defines converter methods from Scala to Java collections. */ +trait AsJavaConverters { + import Wrappers._ + + /** + * Converts a Scala `Iterator` to a Java `Iterator`. + * + * The returned Java `Iterator` is backed by the provided Scala `Iterator` and any side-effects of + * using it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Iterator` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaIterator]](java.util.Iterator)` then the original Java `Iterator` will + * be returned. + * + * @param i The Scala `Iterator` to be converted. + * @return A Java `Iterator` view of the argument. + */ + def asJavaIterator[A](i: Iterator[A]): ju.Iterator[A] = i match { + case null => null + case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] + case _ => IteratorWrapper(i) + } + + /** + * Converts a Scala `Iterator` to a Java `Enumeration`. + * + * The returned Java `Enumeration` is backed by the provided Scala `Iterator` and any side-effects + * of using it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Iterator` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.enumerationAsScalaIterator]](java.util.Enumeration)` then the original Java + * `Enumeration` will be returned. + * + * @param i The Scala `Iterator` to be converted. + * @return A Java `Enumeration` view of the argument. + */ + def asJavaEnumeration[A](i: Iterator[A]): ju.Enumeration[A] = i match { + case null => null + case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]] + case _ => IteratorWrapper(i) + } + + /** + * Converts a Scala `Iterable` to a Java `Iterable`. + * + * The returned Java `Iterable` is backed by the provided Scala `Iterable` and any side-effects of + * using it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Iterable` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.iterableAsScalaIterable]](java.lang.Iterable)` then the original Java + * `Iterable` will be returned. + * + * @param i The Scala `Iterable` to be converted. + * @return A Java `Iterable` view of the argument. + */ + def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match { + case null => null + case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] + case _ => IterableWrapper(i) + } + + /** + * Converts a Scala `Iterable` to an immutable Java `Collection`. + * + * If the Scala `Iterable` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.collectionAsScalaIterable]](java.util.Collection)` then the original Java + * `Collection` will be returned. + * + * @param i The Scala `Iterable` to be converted. + * @return A Java `Collection` view of the argument. + */ + def asJavaCollection[A](i: Iterable[A]): ju.Collection[A] = i match { + case null => null + case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] + case _ => new IterableWrapper(i) + } + + /** + * Converts a Scala mutable `Buffer` to a Java List. + * + * The returned Java List is backed by the provided Scala `Buffer` and any side-effects of using + * it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Buffer` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be + * returned. + * + * @param b The Scala `Buffer` to be converted. + * @return A Java `List` view of the argument. + */ + def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match { + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableBufferWrapper(b) + } + + /** + * Converts a Scala mutable `Seq` to a Java `List`. + * + * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Seq` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be + * returned. + * + * @param s The Scala `Seq` to be converted. + * @return A Java `List` view of the argument. + */ + def mutableSeqAsJavaList[A](s: mutable.Seq[A]): ju.List[A] = s match { + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableSeqWrapper(s) + } + + /** + * Converts a Scala `Seq` to a Java `List`. + * + * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Seq` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be + * returned. + * + * @param s The Scala `Seq` to be converted. + * @return A Java `List` view of the argument. + */ + def seqAsJavaList[A](s: Seq[A]): ju.List[A] = s match { + case null => null + case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] + case _ => new SeqWrapper(s) + } + + /** + * Converts a Scala mutable `Set` to a Java `Set`. + * + * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Set` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaSet]](java.util.Set)` then the original Java `Set` will be returned. + * + * @param s The Scala mutable `Set` to be converted. + * @return A Java `Set` view of the argument. + */ + def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match { + case null => null + case JSetWrapper(wrapped) => wrapped + case _ => new MutableSetWrapper(s) + } + + /** + * Converts a Scala `Set` to a Java `Set`. + * + * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Set` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaSet]](java.util.Set)` then the original Java `Set` will be returned. + * + * @param s The Scala `Set` to be converted. + * @return A Java `Set` view of the argument. + */ + def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match { + case null => null + case JSetWrapper(wrapped) => wrapped + case _ => new SetWrapper(s) + } + + /** + * Converts a Scala mutable `Map` to a Java `Map`. + * + * The returned Java `Map` is backed by the provided Scala `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 `Map` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mapAsScalaMap]](java.util.Map)` then the original Java `Map` will be + * returned. + * + * @param m The Scala mutable `Map` to be converted. + * @return A Java `Map` view of the argument. + */ + def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match { + case null => null + case JMapWrapper(wrapped) => wrapped + case _ => new MutableMapWrapper(m) + } + + /** + * Converts a Scala mutable `Map` to a Java `Dictionary`. + * + * The returned Java `Dictionary` is backed by the provided Scala `Dictionary` and any + * side-effects of using it via the Java interface will be visible via the Scala interface and + * vice versa. + * + * If the Scala `Dictionary` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.dictionaryAsScalaMap]](java.util.Dictionary)` then the original Java + * `Dictionary` will be returned. + * + * @param m The Scala `Map` to be converted. + * @return A Java `Dictionary` view of the argument. + */ + def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match { + case null => null + case JDictionaryWrapper(wrapped) => wrapped + case _ => new DictionaryWrapper(m) + } + + /** + * Converts a Scala `Map` to a Java `Map`. + * + * The returned Java `Map` is backed by the provided Scala `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 `Map` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mapAsScalaMap]](java.util.Map)` then the original Java `Map` will be + * returned. + * + * @param m The Scala `Map` to be converted. + * @return A Java `Map` view of the argument. + */ + def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match { + case null => null + case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]] + case _ => new MapWrapper(m) + } + + /** + * 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 + * `[[JavaConverters.mapAsScalaConcurrentMap]](java.util.concurrent.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. + */ + def mapAsJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { + case null => null + case JConcurrentMapWrapper(wrapped) => wrapped + case _ => new ConcurrentMapWrapper(m) + } +} diff --git a/src/library/scala/collection/convert/AsScalaConverters.scala b/src/library/scala/collection/convert/AsScalaConverters.scala new file mode 100644 index 0000000000..f9e38797e1 --- /dev/null +++ b/src/library/scala/collection/convert/AsScalaConverters.scala @@ -0,0 +1,207 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package convert + +import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } + +/** Defines converter methods from Java to Scala collections. */ +trait AsScalaConverters { + import Wrappers._ + + /** + * Converts a Java `Iterator` to a Scala `Iterator`. + * + * The returned Scala `Iterator` is backed by the provided Java `Iterator` and any side-effects of + * using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Iterator` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaIterator]](scala.collection.Iterator)` then the original Scala + * `Iterator` will be returned. + * + * @param i The Java `Iterator` to be converted. + * @return A Scala `Iterator` view of the argument. + */ + def asScalaIterator[A](i: ju.Iterator[A]): Iterator[A] = i match { + case null => null + case IteratorWrapper(wrapped) => wrapped + case _ => JIteratorWrapper(i) + } + + /** + * Converts a Java `Enumeration` to a Scala `Iterator`. + * + * The returned Scala `Iterator` is backed by the provided Java `Enumeration` and any side-effects + * of using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Enumeration` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaEnumeration]](scala.collection.Iterator)` then the original Scala + * `Iterator` will be returned. + * + * @param i The Java `Enumeration` to be converted. + * @return A Scala `Iterator` view of the argument. + */ + def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match { + case null => null + case IteratorWrapper(wrapped) => wrapped + case _ => JEnumerationWrapper(i) + } + + /** + * Converts a Java `Iterable` to a Scala `Iterable`. + * + * The returned Scala `Iterable` is backed by the provided Java `Iterable` and any side-effects of + * using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Iterable` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaIterable]](scala.collection.Iterable) then the original Scala + * `Iterable` will be returned. + * + * @param i The Java `Iterable` to be converted. + * @return A Scala `Iterable` view of the argument. + */ + def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match { + case null => null + case IterableWrapper(wrapped) => wrapped + case _ => JIterableWrapper(i) + } + + /** + * Converts a Java `Collection` to an Scala `Iterable`. + * + * If the Java `Collection` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaCollection]](scala.collection.Iterable)` then the original Scala + * `Iterable` will be returned. + * + * @param i The Java `Collection` to be converted. + * @return A Scala `Iterable` view of the argument. + */ + def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match { + case null => null + case IterableWrapper(wrapped) => wrapped + case _ => JCollectionWrapper(i) + } + + /** + * Converts a Java `List` to a Scala mutable `Buffer`. + * + * The returned Scala `Buffer` is backed by the provided Java `List` and any side-effects of using + * it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `List` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.bufferAsJavaList]](scala.collection.mutable.Buffer)` then the original Scala + * `Buffer` will be returned. + * + * @param l The Java `List` to be converted. + * @return A Scala mutable `Buffer` view of the argument. + */ + def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match { + case null => null + case MutableBufferWrapper(wrapped) => wrapped + case _ => new JListWrapper(l) + } + + /** + * Converts a Java `Set` to a Scala mutable `Set`. + * + * The returned Scala `Set` is backed by the provided Java `Set` and any side-effects of using it + * via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Set` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mutableSetAsJavaSet]](scala.collection.mutable.Set)` then the original Scala + * `Set` will be returned. + * + * @param s The Java `Set` to be converted. + * @return A Scala mutable `Set` view of the argument. + */ + def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match { + case null => null + case MutableSetWrapper(wrapped) => wrapped + case _ => new JSetWrapper(s) + } + + /** + * Converts a Java `Map` to a Scala mutable `Map`. + * + * The returned Scala `Map` is backed by the provided Java `Map` and any side-effects of using it + * via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Map` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mutableMapAsJavaMap]](scala.collection.mutable.Map)` then the original Scala + * `Map` will be returned. + * + * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), it is + * your responsibility to wrap all non-atomic operations with `underlying.synchronized`. + * This includes `get`, as `java.util.Map`'s API does not allow for an atomic `get` when `null` + * values may be present. + * + * @param m The Java `Map` to be converted. + * @return A Scala mutable `Map` view of the argument. + */ + def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match { + case null => null + case MutableMapWrapper(wrapped) => wrapped + case _ => new JMapWrapper(m) + } + + /** + * 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 + * `[[JavaConverters.mapAsJavaConcurrentMap]](scala.collection.mutable.ConcurrentMap)` + * then the original Scala `ConcurrentMap` will be returned. + * + * @param m The Java `ConcurrentMap` to be converted. + * @return A Scala mutable `ConcurrentMap` view of the argument. + */ + def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match { + case null => null + case cmw: ConcurrentMapWrapper[_, _] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) + } + + /** + * Converts a Java `Dictionary` to a Scala mutable `Map`. + * + * The returned Scala `Map` is backed by the provided Java `Dictionary` and any side-effects of + * using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Dictionary` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaDictionary]](scala.collection.mutable.Map)` then the original + * Scala `Map` will be returned. + * + * @param p The Java `Dictionary` to be converted. + * @return A Scala mutable `Map` view of the argument. + */ + def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { + case null => null + case DictionaryWrapper(wrapped) => wrapped + case _ => new JDictionaryWrapper(p) + } + + /** + * Converts a Java `Properties` to a Scala mutable `Map[String, String]`. + * + * The returned Scala `Map[String, String]` is backed by the provided Java `Properties` and any + * side-effects of using it via the Scala interface will be visible via the Java interface and + * vice versa. + * + * @param p The Java `Properties` to be converted. + * @return A Scala mutable `Map[String, String]` view of the argument. + */ + def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match { + case null => null + case _ => new JPropertiesWrapper(p) + } +} diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index e6aa5da067..83fffa5940 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -12,289 +12,97 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import Decorators._ -import WrapAsJava._ import scala.language.implicitConversions - -/** A collection of decorators that allow converting between - * Scala and Java collections using `asScala` and `asJava` methods. - * - * The following conversions are supported via `asJava`, `asScala` - * - * - `scala.collection.Iterable` <=> `java.lang.Iterable` - * - `scala.collection.Iterator` <=> `java.util.Iterator` - * - `scala.collection.mutable.Buffer` <=> `java.util.List` - * - `scala.collection.mutable.Set` <=> `java.util.Set` - * - `scala.collection.mutable.Map` <=> `java.util.Map` - * - `scala.collection.mutable.concurrent.Map` <=> `java.util.concurrent.ConcurrentMap` - * - * In all cases, converting from a source type to a target type and back - * again will return the original source object, e.g. - * {{{ - * import scala.collection.JavaConverters._ - * - * val sl = new scala.collection.mutable.ListBuffer[Int] - * val jl : java.util.List[Int] = sl.asJava - * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala - * assert(sl eq sl2) - * }}} - * The following conversions are also supported, but the - * direction from Scala to Java is done by the more specifically named methods: - * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`. - * - * - `scala.collection.Iterable` <=> `java.util.Collection` - * - `scala.collection.Iterator` <=> `java.util.Enumeration` - * - `scala.collection.mutable.Map` <=> `java.util.Dictionary` - * - * In addition, the following one way conversions are provided via `asJava`: - * - * - `scala.collection.Seq` => `java.util.List` - * - `scala.collection.mutable.Seq` => `java.util.List` - * - `scala.collection.Set` => `java.util.Set` - * - `scala.collection.Map` => `java.util.Map` - * - * The following one way conversion is provided via `asScala`: - * - * - `java.util.Properties` => `scala.collection.mutable.Map` - * - * @since 2.8.1 - */ -trait DecorateAsJava { +/** Defines `asJava` extension methods for [[JavaConverters]]. */ +trait DecorateAsJava extends AsJavaConverters { /** - * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a - * Java `Iterator`. The returned Java `Iterator` is backed by the provided Scala - * `Iterator` and any side-effects of using it via the Java interface will - * be visible via the Scala interface and vice versa. - * - * If the Scala `Iterator` was previously obtained from an implicit or explicit - * call of `asIterator(java.util.Iterator)` then the original Java `Iterator` - * will be returned by the `asJava` method. - * - * @param i The `Iterator` to be converted. - * @return An object with an `asJava` method that returns a Java `Iterator` view of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a Java `Iterator`. + * @see [[asJavaIterator]] */ implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] = new AsJava(asJavaIterator(i)) /** - * Adds an `asJavaEnumeration` method that implicitly converts a Scala - * `Iterator` to a Java `Enumeration`. The returned Java `Enumeration` is - * backed by the provided Scala `Iterator` and any side-effects of using - * it via the Java interface will be visible via the Scala interface and - * vice versa. - * - * If the Scala `Iterator` was previously obtained from an implicit or - * explicit call of `asIterator(java.util.Enumeration)` then the - * original Java `Enumeration` will be returned. - * - * @param i The `Iterator` to be converted. - * @return An object with an `asJavaEnumeration` method that returns a Java - * `Enumeration` view of the argument. + * Adds an `asJavaEnumeration` method that implicitly converts a Scala `Iterator` to a Java `Enumeration`. + * @see [[asJavaEnumeration]] */ implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] = new AsJavaEnumeration(i) /** - * Adds an `asJava` method that implicitly converts a Scala `Iterable` to - * a Java `Iterable`. - * - * The returned Java `Iterable` is backed by the provided Scala `Iterable` - * and any side-effects of using it via the Java interface will be visible - * via the Scala interface and vice versa. - * - * If the Scala `Iterable` was previously obtained from an implicit or - * explicit call of `asIterable(java.lang.Iterable)` then the original - * Java `Iterable` will be returned. - * - * @param i The `Iterable` to be converted. - * @return An object with an `asJavaCollection` method that returns a Java - * `Iterable` view of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Iterable` to a Java `Iterable`. + * @see [[asJavaIterable]] */ implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] = new AsJava(asJavaIterable(i)) /** - * Adds an `asJavaCollection` method that implicitly converts a Scala - * `Iterable` to an immutable Java `Collection`. - * - * If the Scala `Iterable` was previously obtained from an implicit or - * explicit call of `asSizedIterable(java.util.Collection)` then the - * original Java `Collection` will be returned. - * - * @param i The `SizedIterable` to be converted. - * @return An object with an `asJava` method that returns a Java - * `Collection` view of the argument. + * Adds an `asJavaCollection` method that implicitly converts a Scala `Iterable` to an immutable Java `Collection`. + * @see [[asJavaCollection]] */ implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] = new AsJavaCollection(i) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer` - * to a Java `List`. - * - * The returned Java `List` is backed by the provided Scala `Buffer` and any - * side-effects of using it via the Java interface will be visible via the - * Scala interface and vice versa. - * - * If the Scala `Buffer` was previously obtained from an implicit or explicit - * call of `asBuffer(java.util.List)` then the original Java `List` will be - * returned. - * - * @param b The `Buffer` to be converted. - * @return An object with an `asJava` method that returns a Java `List` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer` to a Java `List`. + * @see [[bufferAsJavaList]] */ implicit def bufferAsJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] = new AsJava(bufferAsJavaList(b)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Seq` - * to a Java `List`. - * - * The returned Java `List` is backed by the provided Scala `Seq` and any - * side-effects of using it via the Java interface will be visible via the - * Scala interface and vice versa. - * - * If the Scala `Seq` was previously obtained from an implicit or explicit - * call of `asSeq(java.util.List)` then the original Java `List` will be - * returned. - * - * @param b The `Seq` to be converted. - * @return An object with an `asJava` method that returns a Java `List` - * view of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Seq` to a Java `List`. + * @see [[mutableSeqAsJavaList]] */ implicit def mutableSeqAsJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] = new AsJava(mutableSeqAsJavaList(b)) /** - * Adds an `asJava` method that implicitly converts a Scala `Seq` to a - * Java `List`. - * - * The returned Java `List` is backed by the provided Scala `Seq` and any - * side-effects of using it via the Java interface will be visible via the - * Scala interface and vice versa. - * - * If the Scala `Seq` was previously obtained from an implicit or explicit - * call of `asSeq(java.util.List)` then the original Java `List` will be - * returned. - * - * @param b The `Seq` to be converted. - * @return An object with an `asJava` method that returns a Java `List` - * view of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Seq` to a Java `List`. + * @see [[seqAsJavaList]] */ implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] = new AsJava(seqAsJavaList(b)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Set`> - * to a Java `Set`. - * - * The returned Java `Set` is backed by the provided Scala `Set` and any - * side-effects of using it via the Java interface will be visible via - * the Scala interface and vice versa. - * - * If the Scala `Set` was previously obtained from an implicit or explicit - * call of `asSet(java.util.Set)` then the original Java `Set` will be - * returned. - * - * @param s The `Set` to be converted. - * @return An object with an `asJava` method that returns a Java `Set` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Set` to a Java `Set`. + * @see [[mutableSetAsJavaSet]] */ implicit def mutableSetAsJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] = new AsJava(mutableSetAsJavaSet(s)) /** - * Adds an `asJava` method that implicitly converts a Scala `Set` to a - * Java `Set`. - * - * The returned Java `Set` is backed by the provided Scala `Set` and any - * side-effects of using it via the Java interface will be visible via - * the Scala interface and vice versa. - * - * If the Scala `Set` was previously obtained from an implicit or explicit - * call of `asSet(java.util.Set)` then the original Java `Set` will be - * returned. - * - * @param s The `Set` to be converted. - * @return An object with an `asJava` method that returns a Java `Set` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Set` to a Java `Set`. + * @see [[setAsJavaSet]] */ implicit def setAsJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] = new AsJava(setAsJavaSet(s)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Map` - * to a Java `Map`. - * - * The returned Java `Map` is backed by the provided Scala `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 `Map` was previously obtained from an implicit or explicit - * call of `asMap(java.util.Map)` then the original Java `Map` will be - * returned. - * - * @param m The `Map` to be converted. - * @return An object with an `asJava` method that returns a Java `Map` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Map` to a Java `Map`. + * @see [[mutableMapAsJavaMap]] */ implicit def mutableMapAsJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] = new AsJava(mutableMapAsJavaMap(m)) /** - * Adds an `asJavaDictionary` method that implicitly converts a Scala - * mutable `Map` to a Java `Dictionary`. - * - * The returned Java `Dictionary` is backed by the provided Scala - * `Dictionary` and any side-effects of using it via the Java interface - * will be visible via the Scala interface and vice versa. - * - * If the Scala `Dictionary` was previously obtained from an implicit or - * explicit call of `asMap(java.util.Dictionary)` then the original - * Java `Dictionary` will be returned. - * - * @param m The `Map` to be converted. - * @return An object with an `asJavaDictionary` method that returns a - * Java `Dictionary` view of the argument. + * Adds an `asJavaDictionary` method that implicitly converts a Scala mutable `Map` to a Java `Dictionary`. + * @see [[asJavaDictionary]] */ implicit def asJavaDictionaryConverter[A, B](m : mutable.Map[A, B]): AsJavaDictionary[A, B] = new AsJavaDictionary(m) /** - * Adds an `asJava` method that implicitly converts a Scala `Map` to - * a Java `Map`. - * - * The returned Java `Map` is backed by the provided Scala `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 `Map` was previously obtained from an implicit or explicit - * call of `asMap(java.util.Map)` then the original Java `Map` will be - * returned. - * - * @param m The `Map` to be converted. - * @return An object with an `asJava` method that returns a Java `Map` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Map` to a Java `Map`. + * @see [[mapAsJavaMap]] */ implicit def mapAsJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] = new AsJava(mapAsJavaMap(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.concurrent.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. + * Adds an `asJava` method that implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * @see [[mapAsJavaConcurrentMap]]. */ implicit def mapAsJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] = new AsJava(mapAsJavaConcurrentMap(m)) diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala index 5448f5f91c..f680aa5267 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -12,185 +12,76 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import Decorators._ -import WrapAsScala._ import scala.language.implicitConversions -trait DecorateAsScala { +/** Defines `asScala` extension methods for [[JavaConverters]]. */ +trait DecorateAsScala extends AsScalaConverters { /** - * Adds an `asScala` method that implicitly converts a Java `Iterator` to - * a Scala `Iterator`. - * - * The returned Scala `Iterator` is backed by the provided Java `Iterator` - * and any side-effects of using it via the Scala interface will be visible - * via the Java interface and vice versa. - * - * If the Java `Iterator` was previously obtained from an implicit or - * explicit call of `asIterator(scala.collection.Iterator)` then the - * original Scala `Iterator` will be returned. - * - * @param i The `Iterator` to be converted. - * @return An object with an `asScala` method that returns a Scala - * `Iterator` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Iterator` to a Scala `Iterator`. + * @see [[asScalaIterator]] */ implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] = new AsScala(asScalaIterator(i)) /** - * Adds an `asScala` method that implicitly converts a Java `Enumeration` - * to a Scala `Iterator`. - * - * The returned Scala `Iterator` is backed by the provided Java - * `Enumeration` and any side-effects of using it via the Scala interface - * will be visible via the Java interface and vice versa. - * - * If the Java `Enumeration` was previously obtained from an implicit or - * explicit call of `asEnumeration(scala.collection.Iterator)` then the - * original Scala `Iterator` will be returned. - * - * @param i The `Enumeration` to be converted. - * @return An object with an `asScala` method that returns a Scala - * `Iterator` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Enumeration` to a Scala `Iterator`. + * @see [[enumerationAsScalaIterator]] */ implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] = new AsScala(enumerationAsScalaIterator(i)) /** - * Adds an `asScala` method that implicitly converts a Java `Iterable` to - * a Scala `Iterable`. - * - * The returned Scala `Iterable` is backed by the provided Java `Iterable` - * and any side-effects of using it via the Scala interface will be visible - * via the Java interface and vice versa. - * - * If the Java `Iterable` was previously obtained from an implicit or - * explicit call of `asIterable(scala.collection.Iterable)` then the original - * Scala `Iterable` will be returned. - * - * @param i The `Iterable` to be converted. - * @return An object with an `asScala` method that returns a Scala `Iterable` - * view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Iterable` to a Scala `Iterable`. + * @see [[iterableAsScalaIterable]] */ implicit def iterableAsScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] = new AsScala(iterableAsScalaIterable(i)) /** - * Adds an `asScala` method that implicitly converts a Java `Collection` to - * an Scala `Iterable`. - * - * If the Java `Collection` was previously obtained from an implicit or - * explicit call of `asCollection(scala.collection.SizedIterable)` then - * the original Scala `SizedIterable` will be returned. - * - * @param i The `Collection` to be converted. - * @return An object with an `asScala` method that returns a Scala - * `SizedIterable` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Collection` to an Scala `Iterable`. + * @see [[collectionAsScalaIterable]] */ implicit def collectionAsScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] = new AsScala(collectionAsScalaIterable(i)) /** - * Adds an `asScala` method that implicitly converts a Java `List` to a - * Scala mutable `Buffer`. - * - * The returned Scala `Buffer` is backed by the provided Java `List` and - * any side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * If the Java `List` was previously obtained from an implicit or explicit - * call of `asList(scala.collection.mutable.Buffer)` then the original - * Scala `Buffer` will be returned. - * - * @param l The `List` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Buffer` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `List` to a Scala mutable `Buffer`. + * @see [[asScalaBuffer]] */ implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] = new AsScala(asScalaBuffer(l)) /** - * Adds an `asScala` method that implicitly converts a Java `Set` to a - * Scala mutable `Set`. - * - * The returned Scala `Set` is backed by the provided Java `Set` and any - * side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * If the Java `Set` was previously obtained from an implicit or explicit - * call of `asSet(scala.collection.mutable.Set)` then the original - * Scala `Set` will be returned. - * - * @param s The `Set` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Set` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Set` to a Scala mutable `Set`. + * @see [[asScalaSet]] */ implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] = new AsScala(asScalaSet(s)) /** - * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala - * mutable `Map`. The returned Scala `Map` is backed by the provided Java - * `Map` and any side-effects of using it via the Scala interface will - * be visible via the Java interface and vice versa. - * - * If the Java `Map` was previously obtained from an implicit or explicit - * call of `asMap(scala.collection.mutable.Map)` then the original - * Scala `Map` will be returned. - * - * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), - * it is your responsibility to wrap all - * non-atomic operations with `underlying.synchronized`. - * This includes `get`, as `java.util.Map`'s API does not allow for an - * atomic `get` when `null` values may be present. - * - * @param m The `Map` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Map` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala mutable `Map`. + * @see [[mapAsScalaMap]] */ implicit def mapAsScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] = new AsScala(mapAsScalaMap(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. + * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` to a Scala mutable `concurrent.Map`. + * @see [[mapAsScalaConcurrentMap]] */ 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 - * any side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * @param p The `Dictionary` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Map[String, String]` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Dictionary` to a Scala mutable `Map`. + * @see [[dictionaryAsScalaMap]] */ implicit def dictionaryAsScalaMapConverter[A, B](p: ju.Dictionary[A, B]): AsScala[mutable.Map[A, B]] = new AsScala(dictionaryAsScalaMap(p)) /** - * Adds an `asScala` method that implicitly converts a Java `Properties` - * to a Scala mutable `Map[String, String]`. The returned Scala - * `Map[String, String]` is backed by the provided Java `Properties` and - * any side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * @param p The `Properties` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Map[String, String]` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Properties` to a Scala mutable `Map[String, String]`. + * @see [[propertiesAsScalaMap]] */ implicit def propertiesAsScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = new AsScala(propertiesAsScalaMap(p)) diff --git a/src/library/scala/collection/convert/Decorators.scala b/src/library/scala/collection/convert/Decorators.scala index d232fa04e1..3e45a02254 100644 --- a/src/library/scala/collection/convert/Decorators.scala +++ b/src/library/scala/collection/convert/Decorators.scala @@ -12,7 +12,7 @@ package convert import java.{ util => ju } -private[collection] trait Decorators { +private[collection] object Decorators { /** Generic class containing the `asJava` converter method */ class AsJava[A](op: => A) { /** Converts a Scala collection to the corresponding Java collection */ @@ -28,20 +28,18 @@ private[collection] trait Decorators { /** Generic class containing the `asJavaCollection` converter method */ class AsJavaCollection[A](i: Iterable[A]) { /** Converts a Scala `Iterable` to a Java `Collection` */ - def asJavaCollection: ju.Collection[A] = JavaConversions.asJavaCollection(i) + def asJavaCollection: ju.Collection[A] = JavaConverters.asJavaCollection(i) } /** Generic class containing the `asJavaEnumeration` converter method */ class AsJavaEnumeration[A](i: Iterator[A]) { /** Converts a Scala `Iterator` to a Java `Enumeration` */ - def asJavaEnumeration: ju.Enumeration[A] = JavaConversions.asJavaEnumeration(i) + def asJavaEnumeration: ju.Enumeration[A] = JavaConverters.asJavaEnumeration(i) } /** Generic class containing the `asJavaDictionary` converter method */ class AsJavaDictionary[A, B](m : mutable.Map[A, B]) { /** Converts a Scala `Map` to a Java `Dictionary` */ - def asJavaDictionary: ju.Dictionary[A, B] = JavaConversions.asJavaDictionary(m) + def asJavaDictionary: ju.Dictionary[A, B] = JavaConverters.asJavaDictionary(m) } } - -private[collection] object Decorators extends Decorators diff --git a/src/library/scala/collection/convert/ImplicitConversions.scala b/src/library/scala/collection/convert/ImplicitConversions.scala new file mode 100644 index 0000000000..35e6ce1616 --- /dev/null +++ b/src/library/scala/collection/convert/ImplicitConversions.scala @@ -0,0 +1,171 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package convert + +import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } +import scala.language.implicitConversions + +import JavaConverters._ + +/** Defines implicit converter methods from Java to Scala collections. */ +trait ToScalaImplicits { + /** Implicitly converts a Java `Iterator` to a Scala `Iterator`. + * @see [[AsScalaConverters.asScalaIterator]] + */ + implicit def `iterator asScala`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it) + + /** Implicitly converts a Java `Enumeration` to a Scala `Iterator`. + * @see [[AsScalaConverters.enumerationAsScalaIterator]] + */ + implicit def `enumeration AsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i) + + /** Implicitly converts a Java `Iterable` to a Scala `Iterable`. + * @see [[AsScalaConverters.iterableAsScalaIterable]] + */ + implicit def `iterable AsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i) + + /** Implicitly converts a Java `Collection` to an Scala `Iterable`. + * @see [[AsScalaConverters.collectionAsScalaIterable]] + */ + implicit def `collection AsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i) + + /** Implicitly converts a Java `List` to a Scala mutable `Buffer`. + * @see [[AsScalaConverters.asScalaBuffer]] + */ + implicit def `list asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l) + + /** Implicitly converts a Java `Set` to a Scala mutable `Set`. + * @see [[AsScalaConverters.asScalaSet]] + */ + implicit def `set asScala`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s) + + /** Implicitly converts a Java `Map` to a Scala mutable `Map`. + * @see [[AsScalaConverters.mapAsScalaMap]] + */ + implicit def `map AsScala`[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m) + + /** Implicitly converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`. + * @see [[AsScalaConverters.mapAsScalaConcurrentMap]] + */ + implicit def `map AsScalaConcurrentMap`[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m) + + /** Implicitly converts a Java `Dictionary` to a Scala mutable `Map`. + * @see [[AsScalaConverters.dictionaryAsScalaMap]] + */ + implicit def `dictionary AsScalaMap`[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(p) + + /** Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`. + * @see [[AsScalaConverters.propertiesAsScalaMap]] + */ + implicit def `properties AsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) +} + +/** Defines implicit conversions from Scala to Java collections. */ +trait ToJavaImplicits { + /** Implicitly converts a Scala `Iterator` to a Java `Iterator`. + * @see [[AsJavaConverters.asJavaIterator]] + */ + implicit def `iterator asJava`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it) + + /** Implicitly converts a Scala `Iterator` to a Java `Enumeration`. + * @see [[AsJavaConverters.asJavaEnumeration]] + */ + implicit def `enumeration asJava`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it) + + /** Implicitly converts a Scala `Iterable` to a Java `Iterable`. + * @see [[AsJavaConverters.asJavaIterable]] + */ + implicit def `iterable asJava`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i) + + /** Implicitly converts a Scala `Iterable` to an immutable Java `Collection`. + * @see [[AsJavaConverters.asJavaCollection]] + */ + implicit def `collection asJava`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it) + + /** Implicitly converts a Scala mutable `Buffer` to a Java `List`. + * @see [[AsJavaConverters.bufferAsJavaList]] + */ + implicit def `buffer AsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b) + + /** Implicitly converts a Scala mutable `Seq` to a Java `List`. + * @see [[AsJavaConverters.mutableSeqAsJavaList]] + */ + implicit def `mutableSeq AsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq) + + /** Implicitly converts a Scala `Seq` to a Java `List`. + * @see [[AsJavaConverters.seqAsJavaList]] + */ + implicit def `seq AsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq) + + /** Implicitly converts a Scala mutable `Set` to a Java `Set`. + * @see [[AsJavaConverters.mutableSetAsJavaSet]] + */ + implicit def `mutableSet AsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s) + + /** Implicitly converts a Scala `Set` to a Java `Set`. + * @see [[AsJavaConverters.setAsJavaSet]] + */ + implicit def `set AsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s) + + /** Implicitly converts a Scala mutable `Map` to a Java `Map`. + * @see [[AsJavaConverters.mutableMapAsJavaMap]] + */ + implicit def `mutableMap AsJavaMap`[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap(m) + + /** Implicitly converts a Scala mutable `Map` to a Java `Dictionary`. + * @see [[AsJavaConverters.asJavaDictionary]] + */ + implicit def `dictionary asJava`[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary(m) + + /** Implicitly converts a Scala `Map` to a Java `Map`. + * @see [[AsJavaConverters.mapAsJavaMap]] + */ + implicit def `map AsJavaMap`[A, B](m: Map[A, B]): ju.Map[A, B] = mapAsJavaMap(m) + + /** Implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * @see [[AsJavaConverters.mapAsJavaConcurrentMap]] + */ + implicit def `map AsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m) +} + +/** + * Convenience for miscellaneous implicit conversions from Scala to Java collections API. + * + * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead. + * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]]. + */ +object ImplicitConversionsToJava extends ToJavaImplicits + +/** + * Convenience for miscellaneous implicit conversions from Java to Scala collections API. + * + * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead. + * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]]. + */ +object ImplicitConversionsToScala extends ToScalaImplicits + +/** + * Convenience for miscellaneous implicit conversions between Java and Scala collections API. + * + * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead. + * Implicit conversions may cause unexpected issues. Example: + * + * {{{ + * import collection.convert.ImplicitConversions._ + * case class StringBox(s: String) + * val m = Map(StringBox("one") -> "uno") + * m.get("one") + * }}} + * + * The above example returns `null` instead of producing a type error at compile-time. The map is + * implicitly converted to a `java.util.Map` which provides a method `get(x: AnyRef)`. + */ +object ImplicitConversions extends ToScalaImplicits with ToJavaImplicits diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 9916fe9843..e3a064b79d 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -13,7 +13,27 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import scala.language.implicitConversions -trait WrapAsJava { +@deprecated("use JavaConverters or consider ToJavaImplicits", since="2.12.0") +trait WrapAsJava extends LowPriorityWrapAsJava { + // provide higher-priority implicits with names that don't exist in JavaConverters for the case + // when importing both JavaConverters._ and JavaConversions._. otherwise implicit conversions + // would not apply, see https://github.com/scala/scala/pull/5109#issuecomment-212417789 + implicit def `deprecated asJavaIterator`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it) + implicit def `deprecated asJavaEnumeration`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it) + implicit def `deprecated asJavaIterable`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i) + implicit def `deprecated asJavaCollection`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it) + implicit def `deprecated bufferAsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b) + implicit def `deprecated mutableSeqAsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq) + implicit def `deprecated seqAsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq) + implicit def `deprecated mutableSetAsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s) + implicit def `deprecated setAsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s) + implicit def `deprecated mutableMapAsJavaMap`[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap(m) + implicit def `deprecated asJavaDictionary`[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary(m) + implicit def `deprecated mapAsJavaMap`[A, B](m: Map[A, B]): ju.Map[A, B] = mapAsJavaMap(m) + implicit def `deprecated mapAsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m) +} + +private[convert] trait LowPriorityWrapAsJava { import Wrappers._ /** @@ -30,8 +50,9 @@ trait WrapAsJava { * @return A Java Iterator view of the argument. */ implicit def asJavaIterator[A](it: Iterator[A]): ju.Iterator[A] = it match { - case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] - case _ => IteratorWrapper(it) + case null => null + case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] + case _ => IteratorWrapper(it) } /** @@ -48,8 +69,9 @@ trait WrapAsJava { * @return A Java Enumeration view of the argument. */ implicit def asJavaEnumeration[A](it: Iterator[A]): ju.Enumeration[A] = it match { + case null => null case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]] - case _ => IteratorWrapper(it) + case _ => IteratorWrapper(it) } /** @@ -66,8 +88,9 @@ trait WrapAsJava { * @return A Java Iterable view of the argument. */ implicit def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match { - case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] - case _ => IterableWrapper(i) + case null => null + case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] + case _ => IterableWrapper(i) } /** @@ -82,8 +105,9 @@ trait WrapAsJava { * @return A Java Collection view of the argument. */ implicit def asJavaCollection[A](it: Iterable[A]): ju.Collection[A] = it match { - case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] - case _ => new IterableWrapper(it) + case null => null + case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] + case _ => new IterableWrapper(it) } /** @@ -100,8 +124,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match { - case JListWrapper(wrapped) => wrapped - case _ => new MutableBufferWrapper(b) + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableBufferWrapper(b) } /** @@ -118,8 +143,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def mutableSeqAsJavaList[A](seq: mutable.Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped - case _ => new MutableSeqWrapper(seq) + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableSeqWrapper(seq) } /** @@ -136,8 +162,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def seqAsJavaList[A](seq: Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] - case _ => new SeqWrapper(seq) + case null => null + case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] + case _ => new SeqWrapper(seq) } /** @@ -154,8 +181,9 @@ trait WrapAsJava { * @return A Java Set view of the argument. */ implicit def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match { + case null => null case JSetWrapper(wrapped) => wrapped - case _ => new MutableSetWrapper(s) + case _ => new MutableSetWrapper(s) } /** @@ -172,8 +200,9 @@ trait WrapAsJava { * @return A Java Set view of the argument. */ implicit def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match { + case null => null case JSetWrapper(wrapped) => wrapped - case _ => new SetWrapper(s) + case _ => new SetWrapper(s) } /** @@ -190,9 +219,9 @@ trait WrapAsJava { * @return A Java Map view of the argument. */ implicit def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped + case null => null case JMapWrapper(wrapped) => wrapped - case _ => new MutableMapWrapper(m) + case _ => new MutableMapWrapper(m) } /** @@ -210,9 +239,9 @@ trait WrapAsJava { * @return A Java `Dictionary` view of the argument. */ implicit def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped - case JDictionaryWrapper(wrapped) => wrapped - case _ => new DictionaryWrapper(m) + case null => null + case JDictionaryWrapper(wrapped) => wrapped + case _ => new DictionaryWrapper(m) } /** @@ -230,9 +259,9 @@ trait WrapAsJava { * @return A Java `Map` view of the argument. */ implicit def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped + case null => null case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]] - case _ => new MapWrapper(m) + case _ => new MapWrapper(m) } /** @@ -251,9 +280,11 @@ trait WrapAsJava { * @return A Java `ConcurrentMap` view of the argument. */ implicit def mapAsJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { + case null => null case JConcurrentMapWrapper(wrapped) => wrapped - case _ => new ConcurrentMapWrapper(m) + case _ => new ConcurrentMapWrapper(m) } } -object WrapAsJava extends WrapAsJava { } +@deprecated("use JavaConverters or consider ImplicitConversionsToJava", since="2.12.0") +object WrapAsJava extends WrapAsJava diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index ab151a6778..fbaafde798 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -13,8 +13,26 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import scala.language.implicitConversions -trait WrapAsScala { +@deprecated("use JavaConverters or consider ToScalaImplicits", since="2.12.0") +trait WrapAsScala extends LowPriorityWrapAsScala { + // provide higher-priority implicits with names that don't exist in JavaConverters for the case + // when importing both JavaConverters._ and JavaConversions._. otherwise implicit conversions + // would not apply, see https://github.com/scala/scala/pull/5109#issuecomment-212417789 + implicit def `deprecated asScalaIterator`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it) + implicit def `deprecated enumerationAsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i) + implicit def `deprecated iterableAsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i) + implicit def `deprecated collectionAsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i) + implicit def `deprecated asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l) + implicit def `deprecated asScalaSet`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s) + implicit def `deprecated mapAsScalaMap`[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m) + implicit def `deprecated mapAsScalaConcurrentMap`[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m) + implicit def `deprecated dictionaryAsScalaMap`[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(p) + implicit def `deprecated propertiesAsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) +} + +private[convert] trait LowPriorityWrapAsScala { import Wrappers._ + /** * Implicitly converts a Java `Iterator` to a Scala `Iterator`. * @@ -30,8 +48,9 @@ trait WrapAsScala { * @return A Scala `Iterator` view of the argument. */ implicit def asScalaIterator[A](it: ju.Iterator[A]): Iterator[A] = it match { + case null => null case IteratorWrapper(wrapped) => wrapped - case _ => JIteratorWrapper(it) + case _ => JIteratorWrapper(it) } /** @@ -48,8 +67,9 @@ trait WrapAsScala { * @return A Scala Iterator view of the argument. */ implicit def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match { + case null => null case IteratorWrapper(wrapped) => wrapped - case _ => JEnumerationWrapper(i) + case _ => JEnumerationWrapper(i) } /** @@ -67,8 +87,9 @@ trait WrapAsScala { * @return A Scala Iterable view of the argument. */ implicit def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match { + case null => null case IterableWrapper(wrapped) => wrapped - case _ => JIterableWrapper(i) + case _ => JIterableWrapper(i) } /** @@ -82,8 +103,9 @@ trait WrapAsScala { * @return A Scala Iterable view of the argument. */ implicit def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match { + case null => null case IterableWrapper(wrapped) => wrapped - case _ => JCollectionWrapper(i) + case _ => JCollectionWrapper(i) } /** @@ -101,8 +123,9 @@ trait WrapAsScala { * @return A Scala mutable `Buffer` view of the argument. */ implicit def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match { - case MutableBufferWrapper(wrapped) => wrapped - case _ =>new JListWrapper(l) + case null => null + case MutableBufferWrapper(wrapped) => wrapped + case _ => new JListWrapper(l) } /** @@ -119,8 +142,9 @@ trait WrapAsScala { * @return A Scala mutable Set view of the argument. */ implicit def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match { + case null => null case MutableSetWrapper(wrapped) => wrapped - case _ =>new JSetWrapper(s) + case _ => new JSetWrapper(s) } /** @@ -133,20 +157,20 @@ trait WrapAsScala { * If the Java `Map` was previously obtained from an implicit or * explicit call of `mapAsScalaMap(scala.collection.mutable.Map)` then * the original Scala Map will be returned. - * + * * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), - * it is your responsibility to wrap all + * it is your responsibility to wrap all * non-atomic operations with `underlying.synchronized`. * This includes `get`, as `java.util.Map`'s API does not allow for an * atomic `get` when `null` values may be present. - * + * * @param m The Map to be converted. * @return A Scala mutable Map view of the argument. */ implicit def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match { - //case ConcurrentMapWrapper(wrapped) => wrapped + case null => null case MutableMapWrapper(wrapped) => wrapped - case _ => new JMapWrapper(m) + case _ => new JMapWrapper(m) } /** @@ -163,24 +187,26 @@ trait WrapAsScala { * @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) + case null => null + case cmw: ConcurrentMapWrapper[_, _] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) } /** * Implicitly converts a Java `Dictionary` to a Scala mutable - * `Map[String, String]`. + * `Map`. * - * The returned Scala `Map[String, String]` is backed by the provided Java + * The returned Scala `Map` is backed by the provided Java * `Dictionary` and any side-effects of using it via the Scala interface * will be visible via the Java interface and vice versa. * * @param p The Dictionary to be converted. - * @return A Scala mutable Map[String, String] view of the argument. + * @return A Scala mutable Map view of the argument. */ implicit def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { + case null => null case DictionaryWrapper(wrapped) => wrapped - case _ => new JDictionaryWrapper(p) + case _ => new JDictionaryWrapper(p) } /** @@ -194,8 +220,10 @@ trait WrapAsScala { * @return A Scala mutable Map[String, String] view of the argument. */ implicit def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match { - case _ => new JPropertiesWrapper(p) + case null => null + case _ => new JPropertiesWrapper(p) } } -object WrapAsScala extends WrapAsScala { } +@deprecated("use JavaConverters or consider ImplicitConversionsToScala", since="2.12.0") +object WrapAsScala extends WrapAsScala diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index e829a0215b..9f7e3e8174 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -14,10 +14,7 @@ import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import WrapAsScala._ import WrapAsJava._ -/** Don't put the implementations in the same scope as the implicits - * which utilize them, or they will stow away into every scope which - * extends one of those implementations. See SI-5580. - */ +/** Adapters for Java/Scala collections API. */ private[collection] trait Wrappers { trait IterableWrapperTrait[A] extends ju.AbstractCollection[A] { val underlying: Iterable[A] @@ -31,7 +28,7 @@ private[collection] trait Wrappers { def next() = underlying.next() def hasMoreElements = underlying.hasNext def nextElement() = underlying.next() - def remove() = throw new UnsupportedOperationException + override def remove() = throw new UnsupportedOperationException } class ToIteratorWrapper[A](underlying : Iterator[A]) { @@ -102,9 +99,9 @@ private[collection] trait Wrappers { override def clone(): JListWrapper[A] = JListWrapper(new ju.ArrayList[A](underlying)) } - // Note various overrides to avoid performance gotchas. - class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] { - self => + @SerialVersionUID(1L) + class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] with Serializable { self => + // Note various overrides to avoid performance gotchas. override def contains(o: Object): Boolean = { try { underlying.contains(o.asInstanceOf[A]) } catch { case cce: ClassCastException => false } @@ -116,7 +113,7 @@ private[collection] trait Wrappers { var prev: Option[A] = None def hasNext = ui.hasNext def next = { val e = ui.next(); prev = Some(e); e } - def remove = prev match { + override def remove() = prev match { case Some(e) => underlying match { case ms: mutable.Set[a] => @@ -165,7 +162,8 @@ private[collection] trait Wrappers { new JSetWrapper[A](new ju.LinkedHashSet[A](underlying)) } - class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] { self => + @SerialVersionUID(1L) + class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] with Serializable { self => override def size = underlying.size override def get(key: AnyRef): B = try { @@ -202,7 +200,7 @@ private[collection] trait Wrappers { } } - def remove() { + override def remove() { prev match { case Some(k) => underlying match { @@ -295,24 +293,24 @@ private[collection] trait Wrappers { 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 { + override 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 { + override 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 { + override 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) + override def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) } /** Wraps a concurrent Java map as a Scala one. Single-element concurrent diff --git a/src/library/scala/collection/convert/package.scala b/src/library/scala/collection/convert/package.scala index 13970f9a3e..810d112cd5 100644 --- a/src/library/scala/collection/convert/package.scala +++ b/src/library/scala/collection/convert/package.scala @@ -10,10 +10,17 @@ package scala package collection package object convert { + @deprecated("use JavaConverters", since="2.12.0") val decorateAsJava = new DecorateAsJava { } + @deprecated("use JavaConverters", since="2.12.0") val decorateAsScala = new DecorateAsScala { } - val decorateAll = new DecorateAsJava with DecorateAsScala { } + @deprecated("use JavaConverters", since="2.12.0") + val decorateAll = JavaConverters + + @deprecated("use JavaConverters or consider ImplicitConversionsToJava", since="2.12.0") val wrapAsJava = new WrapAsJava { } + @deprecated("use JavaConverters or consider ImplicitConversionsToScala", since="2.12.0") val wrapAsScala = new WrapAsScala { } + @deprecated("use JavaConverters or consider ImplicitConversions", since="2.12.0") val wrapAll = new WrapAsJava with WrapAsScala { } } diff --git a/src/library/scala/collection/generic/BitOperations.scala b/src/library/scala/collection/generic/BitOperations.scala index d430ece2f5..2f460eee1f 100644 --- a/src/library/scala/collection/generic/BitOperations.scala +++ b/src/library/scala/collection/generic/BitOperations.scala @@ -26,16 +26,7 @@ private[collection] object BitOperations { def complement(i: Int) = (-1) ^ i def bits(num: Int) = 31 to 0 by -1 map (i => (num >>> i & 1) != 0) def bitString(num: Int, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep - - def highestOneBit(j: Int) = { - var i = j - i |= (i >> 1) - i |= (i >> 2) - i |= (i >> 4) - i |= (i >> 8) - i |= (i >> 16) - i - (i >>> 1) - } + def highestOneBit(j: Int) = java.lang.Integer.highestOneBit(j) } object Int extends Int @@ -49,17 +40,7 @@ private[collection] object BitOperations { def complement(i: Long) = (-1L) ^ i def bits(num: Long) = 63L to 0L by -1L map (i => (num >>> i & 1L) != 0L) def bitString(num: Long, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep - - def highestOneBit(j: Long) = { - var i = j - i |= (i >> 1) - i |= (i >> 2) - i |= (i >> 4) - i |= (i >> 8) - i |= (i >> 16) - i |= (i >> 32) - i - (i >>> 1) - } + def highestOneBit(j: Long) = java.lang.Long.highestOneBit(j) } object Long extends Long } diff --git a/src/library/scala/collection/generic/GenSetFactory.scala b/src/library/scala/collection/generic/GenSetFactory.scala index 800f66eb53..65404a4991 100644 --- a/src/library/scala/collection/generic/GenSetFactory.scala +++ b/src/library/scala/collection/generic/GenSetFactory.scala @@ -40,7 +40,11 @@ abstract class GenSetFactory[CC[X] <: GenSet[X] with GenSetLike[X, CC[X]]] /** $setCanBuildFromInfo */ def setCanBuildFrom[A] = new CanBuildFrom[CC[_], A, CC[A]] { - def apply(from: CC[_]) = newBuilder[A] + def apply(from: CC[_]) = from match { + // When building from an existing Set, try to preserve its type: + case from: Set[_] => from.genericBuilder.asInstanceOf[Builder[A, CC[A]]] + case _ => newBuilder[A] + } def apply() = newBuilder[A] } } diff --git a/src/library/scala/collection/generic/GenTraversableFactory.scala b/src/library/scala/collection/generic/GenTraversableFactory.scala index 2092c0c5f5..7c2aa5615c 100644 --- a/src/library/scala/collection/generic/GenTraversableFactory.scala +++ b/src/library/scala/collection/generic/GenTraversableFactory.scala @@ -229,7 +229,7 @@ extends GenericCompanion[CC] { /** Produces a $coll containing repeated applications of a function to a start value. * * @param start the start value of the $coll - * @param len the number of elements contained inthe $coll + * @param len the number of elements contained in the $coll * @param f the function that's repeatedly applied * @return a $coll with `len` values in the sequence `start, f(start), f(f(start)), ...` */ diff --git a/src/library/scala/collection/generic/GenericParTemplate.scala b/src/library/scala/collection/generic/GenericParTemplate.scala index b9b7043270..44a778a953 100644 --- a/src/library/scala/collection/generic/GenericParTemplate.scala +++ b/src/library/scala/collection/generic/GenericParTemplate.scala @@ -13,7 +13,6 @@ package generic import scala.collection.parallel.Combiner import scala.collection.parallel.ParIterable import scala.collection.parallel.ParMap -import scala.collection.parallel.TaskSupport import scala.annotation.unchecked.uncheckedVariance import scala.language.higherKinds diff --git a/src/library/scala/collection/generic/IterableForwarder.scala b/src/library/scala/collection/generic/IterableForwarder.scala index 7387dbe667..7f6eb6e131 100644 --- a/src/library/scala/collection/generic/IterableForwarder.scala +++ b/src/library/scala/collection/generic/IterableForwarder.scala @@ -26,7 +26,7 @@ import scala.collection._ * @version 2.8 * @since 2.8 */ -@deprecated("Forwarding is inherently unreliable since it is not automated and methods can be forgotten.", "2.11.0") +@deprecated("forwarding is inherently unreliable since it is not automated and methods can be forgotten", "2.11.0") trait IterableForwarder[+A] extends Iterable[A] with TraversableForwarder[A] { /** The iterable object to which calls are forwarded */ diff --git a/src/library/scala/collection/generic/MapFactory.scala b/src/library/scala/collection/generic/MapFactory.scala index b9f3d4b010..255d695303 100644 --- a/src/library/scala/collection/generic/MapFactory.scala +++ b/src/library/scala/collection/generic/MapFactory.scala @@ -10,8 +10,6 @@ package scala package collection package generic - -import mutable.{Builder, MapBuilder} import scala.language.higherKinds /** A template for companion objects of `Map` and subclasses thereof. diff --git a/src/library/scala/collection/generic/MutableSortedMapFactory.scala b/src/library/scala/collection/generic/MutableSortedMapFactory.scala new file mode 100644 index 0000000000..b6fa933ca8 --- /dev/null +++ b/src/library/scala/collection/generic/MutableSortedMapFactory.scala @@ -0,0 +1,24 @@ +package scala +package collection +package generic + +import scala.language.higherKinds + +/** + * A template for companion objects of `SortedMap` and subclasses thereof. + * + * @tparam CC the type of the collection. + * + * @author Rui Gonçalves + * @since 2.12 + * @version 2.12 + * + * @define Coll `mutable.SortedMap` + * @define coll mutable sorted map + * @define factoryInfo + * This object provides a set of operations needed to create sorted maps of type `$Coll`. + * @define sortedMapCanBuildFromInfo + * The standard `CanBuildFrom` instance for sorted maps + */ +abstract class MutableSortedMapFactory[CC[A, B] <: mutable.SortedMap[A, B] with SortedMapLike[A, B, CC[A, B]]] + extends SortedMapFactory[CC] diff --git a/src/library/scala/collection/generic/ParFactory.scala b/src/library/scala/collection/generic/ParFactory.scala index 4486cea419..901e9fc239 100644 --- a/src/library/scala/collection/generic/ParFactory.scala +++ b/src/library/scala/collection/generic/ParFactory.scala @@ -11,7 +11,6 @@ package collection package generic import scala.collection.parallel.ParIterable -import scala.collection.parallel.Combiner import scala.language.higherKinds /** A template class for companion objects of `ParIterable` and subclasses diff --git a/src/library/scala/collection/generic/ParSetFactory.scala b/src/library/scala/collection/generic/ParSetFactory.scala index 4320635ae6..1341ddcb38 100644 --- a/src/library/scala/collection/generic/ParSetFactory.scala +++ b/src/library/scala/collection/generic/ParSetFactory.scala @@ -10,7 +10,6 @@ package scala package collection package generic -import scala.collection.mutable.Builder import scala.collection.parallel.Combiner import scala.collection.parallel.ParSet import scala.collection.parallel.ParSetLike diff --git a/src/library/scala/collection/generic/SeqForwarder.scala b/src/library/scala/collection/generic/SeqForwarder.scala index e21e2ea016..cee93d2ddb 100644 --- a/src/library/scala/collection/generic/SeqForwarder.scala +++ b/src/library/scala/collection/generic/SeqForwarder.scala @@ -25,7 +25,7 @@ import scala.collection.immutable.Range * @version 2.8 * @since 2.8 */ -@deprecated("Forwarding is inherently unreliable since it is not automated and new methods can be forgotten.", "2.11.0") +@deprecated("forwarding is inherently unreliable since it is not automated and new methods can be forgotten", "2.11.0") trait SeqForwarder[+A] extends Seq[A] with IterableForwarder[A] { protected override def underlying: Seq[A] diff --git a/src/library/scala/collection/generic/SetFactory.scala b/src/library/scala/collection/generic/SetFactory.scala index fcd8d00c18..5e50844cc9 100644 --- a/src/library/scala/collection/generic/SetFactory.scala +++ b/src/library/scala/collection/generic/SetFactory.scala @@ -12,7 +12,6 @@ package scala package collection package generic -import mutable.Builder import scala.language.higherKinds abstract class SetFactory[CC[X] <: Set[X] with SetLike[X, CC[X]]] diff --git a/src/library/scala/collection/generic/TraversableForwarder.scala b/src/library/scala/collection/generic/TraversableForwarder.scala index 359ea402b6..b94507d6ef 100644 --- a/src/library/scala/collection/generic/TraversableForwarder.scala +++ b/src/library/scala/collection/generic/TraversableForwarder.scala @@ -27,7 +27,7 @@ import scala.reflect.ClassTag * @version 2.8 * @since 2.8 */ -@deprecated("Forwarding is inherently unreliable since it is not automated and new methods can be forgotten.", "2.11.0") +@deprecated("forwarding is inherently unreliable since it is not automated and new methods can be forgotten", "2.11.0") trait TraversableForwarder[+A] extends Traversable[A] { /** The traversable object to which calls are forwarded. */ protected def underlying: Traversable[A] diff --git a/src/library/scala/collection/generic/package.scala b/src/library/scala/collection/generic/package.scala index 1beb4a8599..015c3455db 100644 --- a/src/library/scala/collection/generic/package.scala +++ b/src/library/scala/collection/generic/package.scala @@ -1,6 +1,5 @@ package scala package collection -import generic.CanBuildFrom import scala.language.higherKinds diff --git a/src/library/scala/collection/immutable/BitSet.scala b/src/library/scala/collection/immutable/BitSet.scala index 70543aa3a6..ecf3326c7f 100644 --- a/src/library/scala/collection/immutable/BitSet.scala +++ b/src/library/scala/collection/immutable/BitSet.scala @@ -14,7 +14,7 @@ package immutable import generic._ import BitSetLike.{LogWL, updateArray} -import mutable.{ Builder, SetBuilder } +import mutable.Builder /** A class for immutable bitsets. * $bitsetinfo @@ -68,6 +68,8 @@ object BitSet extends BitSetFactory[BitSet] { /** The empty bitset */ val empty: BitSet = new BitSet1(0L) + private def createSmall(a: Long, b: Long): BitSet = if (b == 0L) new BitSet1(a) else new BitSet2(a, b) + /** A builder that takes advantage of mutable BitSets. */ def newBuilder: Builder[Int, BitSet] = new Builder[Int, BitSet] { private[this] val b = new mutable.BitSet @@ -84,7 +86,7 @@ object BitSet extends BitSetFactory[BitSet] { val len = elems.length if (len == 0) empty else if (len == 1) new BitSet1(elems(0)) - else if (len == 2) new BitSet2(elems(0), elems(1)) + else if (len == 2) createSmall(elems(0), elems(1)) else { val a = new Array[Long](len) Array.copy(elems, 0, a, 0, len) @@ -99,17 +101,24 @@ object BitSet extends BitSetFactory[BitSet] { val len = elems.length if (len == 0) empty else if (len == 1) new BitSet1(elems(0)) - else if (len == 2) new BitSet2(elems(0), elems(1)) + else if (len == 2) createSmall(elems(0), elems(1)) else new BitSetN(elems) } + @SerialVersionUID(2260107458435649300L) class BitSet1(val elems: Long) extends BitSet { protected def nwords = 1 protected def word(idx: Int) = if (idx == 0) elems else 0L protected def updateWord(idx: Int, w: Long): BitSet = if (idx == 0) new BitSet1(w) - else if (idx == 1) new BitSet2(elems, w) + else if (idx == 1) createSmall(elems, w) else fromBitMaskNoCopy(updateArray(Array(elems), idx, w)) + override def head: Int = + if (elems == 0L) throw new NoSuchElementException("Empty BitSet") + else java.lang.Long.numberOfTrailingZeros(elems) + override def tail: BitSet = + if (elems == 0L) throw new NoSuchElementException("Empty BitSet") + else new BitSet1(elems - java.lang.Long.lowestOneBit(elems)) } class BitSet2(val elems0: Long, elems1: Long) extends BitSet { @@ -117,8 +126,20 @@ object BitSet extends BitSetFactory[BitSet] { protected def word(idx: Int) = if (idx == 0) elems0 else if (idx == 1) elems1 else 0L protected def updateWord(idx: Int, w: Long): BitSet = if (idx == 0) new BitSet2(w, elems1) - else if (idx == 1) new BitSet2(elems0, w) + else if (idx == 1) createSmall(elems0, w) else fromBitMaskNoCopy(updateArray(Array(elems0, elems1), idx, w)) + override def head: Int = + if (elems0 == 0L) { + if (elems1 == 0) throw new NoSuchElementException("Empty BitSet") + 64 + java.lang.Long.numberOfTrailingZeros(elems1) + } + else java.lang.Long.numberOfTrailingZeros(elems0) + override def tail: BitSet = + if (elems0 == 0L) { + if (elems1 == 0L) throw new NoSuchElementException("Empty BitSet") + createSmall(elems0, elems1 - java.lang.Long.lowestOneBit(elems1)) + } + else new BitSet2(elems0 - java.lang.Long.lowestOneBit(elems0), elems1) } /** The implementing class for bit sets with elements >= 128 (exceeding @@ -131,5 +152,15 @@ object BitSet extends BitSetFactory[BitSet] { protected def nwords = elems.length protected def word(idx: Int) = if (idx < nwords) elems(idx) else 0L protected def updateWord(idx: Int, w: Long): BitSet = fromBitMaskNoCopy(updateArray(elems, idx, w)) + override def tail: BitSet = { + val n = nwords + var i = 0 + while (i < n) { + val wi = word(i) + if (wi != 0L) return fromBitMaskNoCopy(updateArray(elems, i, wi - java.lang.Long.lowestOneBit(wi))) + i += 1 + } + throw new NoSuchElementException("Empty BitSet") + } } } diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 3e482f1369..627f723cb0 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -33,8 +33,7 @@ import parallel.immutable.ParHashMap * @define willNotTerminateInf */ @SerialVersionUID(2L) -@deprecatedInheritance("The implementation details of immutable hash maps make inheriting from them unwise.", "2.11.0") -class HashMap[A, +B] extends AbstractMap[A, B] +sealed class HashMap[A, +B] extends AbstractMap[A, B] with Map[A, B] with MapLike[A, B, HashMap[A, B]] with Serializable @@ -53,6 +52,9 @@ class HashMap[A, +B] extends AbstractMap[A, B] def get(key: A): Option[B] = get0(key, computeHash(key), 0) + override final def contains(key: A): Boolean = + contains0(key, computeHash(key), 0) + override def updated [B1 >: B] (key: A, value: B1): HashMap[A, B1] = updated0(key, computeHash(key), 0, value, null, null) @@ -65,6 +67,8 @@ class HashMap[A, +B] extends AbstractMap[A, B] def - (key: A): HashMap[A, B] = removed0(key, computeHash(key), 0) + override def tail: HashMap[A, B] = this - head._1 + override def filter(p: ((A, B)) => Boolean) = { val buffer = new Array[HashMap[A, B]](bufferSize(size)) nullToEmpty(filter0(p, false, 0, buffer, 0)) @@ -91,7 +95,7 @@ class HashMap[A, +B] extends AbstractMap[A, B] import HashMap.{Merger, MergeFunction, liftMerger} private[collection] def get0(key: A, hash: Int, level: Int): Option[B] = None - + protected def contains0(key: A, hash: Int, level: Int): Boolean = false private[collection] def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = new HashMap.HashMap1(key, hash, value, kv) @@ -156,7 +160,10 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), HashMap[A, B]] = new MapCanBuildFrom[A, B] def empty[A, B]: HashMap[A, B] = EmptyHashMap.asInstanceOf[HashMap[A, B]] - private object EmptyHashMap extends HashMap[Any, Nothing] { } + private object EmptyHashMap extends HashMap[Any, Nothing] { + override def head: (Any, Nothing) = throw new NoSuchElementException("Empty Map") + override def tail: HashMap[Any, Nothing] = throw new NoSuchElementException("Empty Map") + } // utility method to create a HashTrieMap from two leaf HashMaps (HashMap1 or HashMapCollision1) with non-colliding hash code) private def makeHashTrieMap[A, B](hash0:Int, elem0:HashMap[A, B], hash1:Int, elem1:HashMap[A, B], level:Int, size:Int) : HashTrieMap[A, B] = { @@ -181,6 +188,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { override def size = 1 @@ -191,6 +199,8 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash && key == this.key) Some(value) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && key == this.key private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash && key == this.key ) { if (merger eq null) { @@ -235,6 +245,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash) kvs.get(key) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && kvs.contains(key) + private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash) { if ((merger eq null) || !kvs.contains(key)) new HashMapCollision1(hash, kvs.updated(key, value)) @@ -290,6 +303,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashTrieMap[A, +B]( private[collection] val bitmap: Int, private[collection] val elems: Array[HashMap[A, B @uV]], @@ -302,21 +316,41 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def size = size0 override def get0(key: A, hash: Int, level: Int): Option[B] = { + // Note: this code is duplicated with `contains0` + val index = (hash >>> level) & 0x1f + if (bitmap == - 1) { + elems(index).get0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).get0(key, hash, level + 5) + } else { + None + } + } + } + + override protected def contains0(key: A, hash: Int, level: Int): Boolean = { + // Note: this code is duplicated from `get0` val index = (hash >>> level) & 0x1f - val mask = (1 << index) if (bitmap == - 1) { - elems(index & 0x1f).get0(key, hash, level + 5) - } else if ((bitmap & mask) != 0) { - val offset = Integer.bitCount(bitmap & (mask-1)) - elems(offset).get0(key, hash, level + 5) - } else - None + elems(index).contains0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).contains0(key, hash, level + 5) + } else { + false + } + } } private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.updated0(key, hash, level + 5, value, kv, merger) @@ -338,7 +372,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.removed0(key, hash, level + 5) diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 050e90b49b..fc937e3a22 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -31,8 +31,7 @@ import scala.annotation.tailrec * @define coll immutable hash set */ @SerialVersionUID(2L) -@deprecatedInheritance("The implementation details of immutable hash sets make inheriting from them unwise.", "2.11.0") -class HashSet[A] extends AbstractSet[A] +sealed class HashSet[A] extends AbstractSet[A] with Set[A] with GenericSetTemplate[A, HashSet] with SetLike[A, HashSet[A]] @@ -162,6 +161,8 @@ class HashSet[A] extends AbstractSet[A] def - (e: A): HashSet[A] = nullToEmpty(removed0(e, computeHash(e), 0)) + override def tail: HashSet[A] = this - head + override def filter(p: A => Boolean) = { val buffer = new Array[HashSet[A]](bufferSize(size)) nullToEmpty(filter0(p, false, 0, buffer, 0)) @@ -187,7 +188,7 @@ class HashSet[A] extends AbstractSet[A] protected def get0(key: A, hash: Int, level: Int): Boolean = false - def updated0(key: A, hash: Int, level: Int): HashSet[A] = + private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = new HashSet.HashSet1(key, hash) protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = this @@ -213,7 +214,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { /** $setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A] - private object EmptyHashSet extends HashSet[Any] { } + private object EmptyHashSet extends HashSet[Any] { + override def head: Any = throw new NoSuchElementException("Empty Set") + override def tail: HashSet[Any] = throw new NoSuchElementException("Empty Set") + } private[collection] def emptyInstance: HashSet[Any] = EmptyHashSet // utility method to create a HashTrieSet from two leaf HashSets (HashSet1 or HashSetCollision1) with non-colliding hash code) @@ -250,10 +254,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { class HashSet1[A](private[HashSet] val key: A, private[HashSet] val hash: Int) extends LeafHashSet[A] { override def size = 1 - override def get0(key: A, hash: Int, level: Int): Boolean = + override protected def get0(key: A, hash: Int, level: Int): Boolean = (hash == this.hash && key == this.key) - override def subsetOf0(that: HashSet[A], level: Int) = { + override protected def subsetOf0(that: HashSet[A], level: Int) = { // check if that contains this.key // we use get0 with our key and hash at the correct level instead of calling contains, // which would not work since that might not be a top-level HashSet @@ -261,7 +265,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { that.get0(key, hash, level) } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash && key == this.key) this else { if (hash != this.hash) { @@ -306,7 +310,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override private[immutable] def diff0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = if (that.get0(key, hash, level)) null else this - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash && key == this.key) null else this override protected def filter0(p: A => Boolean, negate: Boolean, level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = @@ -320,10 +324,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def size = ks.size - override def get0(key: A, hash: Int, level: Int): Boolean = + override protected def get0(key: A, hash: Int, level: Int): Boolean = if (hash == this.hash) ks.contains(key) else false - override def subsetOf0(that: HashSet[A], level: Int) = { + override protected def subsetOf0(that: HashSet[A], level: Int) = { // we have to check each element // we use get0 with our hash at the correct level instead of calling contains, // which would not work since that might not be a top-level HashSet @@ -331,11 +335,11 @@ object HashSet extends ImmutableSetFactory[HashSet] { ks.forall(key => that.get0(key, hash, level)) } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) new HashSetCollision1(hash, ks + key) else makeHashTrieSet(this.hash, this, hash, new HashSet1(key, hash), level) - override def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { + override private[immutable] def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { case that if that.hash != this.hash => // different hash code, so there is no need to investigate further. // Just create a branch node containing the two. @@ -368,7 +372,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { + override private[immutable] def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { case that: LeafHashSet[A] => // switch to the simpler Tree/Leaf implementation this.union0(that, level) @@ -425,7 +429,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) { val ks1 = ks - key ks1.size match { @@ -522,7 +526,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def size = size0 - override def get0(key: A, hash: Int, level: Int): Boolean = { + override protected def get0(key: A, hash: Int, level: Int): Boolean = { val index = (hash >>> level) & 0x1f val mask = (1 << index) if (bitmap == - 1) { @@ -534,7 +538,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { false } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = { + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) @@ -836,7 +840,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { case _ => this } - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = { + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) @@ -873,7 +877,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def subsetOf0(that: HashSet[A], level: Int): Boolean = if (that eq this) true else that match { + override protected def subsetOf0(that: HashSet[A], level: Int): Boolean = if (that eq this) true else that match { case that: HashTrieSet[A] if this.size0 <= that.size0 => // create local mutable copies of members var abm = this.bitmap diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 8e8bf953f3..550b987cb6 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -13,7 +13,7 @@ package immutable import generic._ import mutable.{Builder, ListBuffer} import scala.annotation.tailrec -import java.io._ +import java.io.{ObjectOutputStream, ObjectInputStream} /** A class for immutable linked lists representing ordered collections * of elements of type `A`. @@ -25,6 +25,8 @@ import java.io._ * This class is optimal for last-in-first-out (LIFO), stack-like access patterns. If you need another access * pattern, for example, random access or FIFO, consider using a collection more suited to this than `List`. * + * $usesMutableState + * * ==Performance== * '''Time:''' `List` has `O(1)` prepend and head/tail access. Most other operations are `O(n)` on the number of elements in the list. * This includes the index-based lookup of elements, `length`, `append` and `reverse`. @@ -86,11 +88,9 @@ sealed abstract class List[+A] extends AbstractSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] - with Serializable { + with scala.Serializable { override def companion: GenericCompanion[List] = List - import scala.collection.{Iterable, Traversable, Seq, IndexedSeq} - def isEmpty: Boolean def head: A def tail: List[A] @@ -276,8 +276,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] } (b.toList, these) } - - @noinline // TODO - fix optimizer bug that requires noinline (see SI-8334) + final override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That = { if (bf eq List.ReusableCBF) { if (this eq Nil) Nil.asInstanceOf[That] else { @@ -295,8 +294,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] } else super.map(f) } - - @noinline // TODO - fix optimizer bug that requires noinline for map; applied here to be safe (see SI-8334) + final override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[List[A], B, That]): That = { if (bf eq List.ReusableCBF) { if (this eq Nil) Nil.asInstanceOf[That] else { @@ -325,8 +323,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] } else super.collect(pf) } - - @noinline // TODO - fix optimizer bug that requires noinline for map; applied here to be safe (see SI-8334) + final override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = { if (bf eq List.ReusableCBF) { if (this eq Nil) Nil.asInstanceOf[That] else { @@ -414,7 +411,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] else new Stream.Cons(head, tail.toStream) // Create a proxy for Java serialization that allows us to avoid mutation - // during de-serialization. This is the Serialization Proxy Pattern. + // during deserialization. This is the Serialization Proxy Pattern. protected final def writeReplace(): AnyRef = new List.SerializationProxy(this) } @@ -466,7 +463,7 @@ object List extends SeqFactory[List] { override def empty[A]: List[A] = Nil override def apply[A](xs: A*): List[A] = xs.toList - + private[collection] val partialNotApplied = new Function1[Any, Any] { def apply(x: Any): Any = this } @SerialVersionUID(1L) @@ -482,7 +479,7 @@ object List extends SeqFactory[List] { out.writeObject(ListSerializeEnd) } - // Java serialization calls this before readResolve during de-serialization. + // Java serialization calls this before readResolve during deserialization. // Read the whole list and store it in `orig`. private def readObject(in: ObjectInputStream) { in.defaultReadObject() diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala index 1eedf93269..589f8bbba9 100644 --- a/src/library/scala/collection/immutable/ListMap.scala +++ b/src/library/scala/collection/immutable/ListMap.scala @@ -6,202 +6,161 @@ ** |/ ** \* */ - - package scala package collection package immutable import generic._ -import scala.annotation.{tailrec, bridge} - -/** $factoryInfo - * @since 1 - * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list_maps "Scala's Collection Library overview"]] - * section on `List Maps` for more information. - * - * @define Coll immutable.ListMap - * @define coll immutable list map - */ +import scala.annotation.tailrec + +/** + * $factoryInfo + * + * Note that each element insertion takes O(n) time, which means that creating a list map with + * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of + * elements. + * + * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list_maps "Scala's Collection Library overview"]] + * section on `List Maps` for more information. + * @since 1 + * @define Coll ListMap + * @define coll list map + */ object ListMap extends ImmutableMapFactory[ListMap] { - /** $mapCanBuildFromInfo */ + + /** + * $mapCanBuildFromInfo + */ implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), ListMap[A, B]] = new MapCanBuildFrom[A, B] + def empty[A, B]: ListMap[A, B] = EmptyListMap.asInstanceOf[ListMap[A, B]] - private object EmptyListMap extends ListMap[Any, Nothing] { } + @SerialVersionUID(-8256686706655863282L) + private object EmptyListMap extends ListMap[Any, Nothing] } -/** This class implements immutable maps using a list-based data structure, which preserves insertion order. - * Instances of `ListMap` represent empty maps; they can be either created by - * calling the constructor directly, or by applying the function `ListMap.empty`. - * - * @tparam A the type of the keys in this list map. - * @tparam B the type of the values associated with the keys. - * - * @author Matthias Zenger - * @author Martin Odersky - * @version 2.0, 01/01/2007 - * @since 1 - * @define Coll immutable.ListMap - * @define coll immutable list map - * @define mayNotTerminateInf - * @define willNotTerminateInf - */ +/** + * This class implements immutable maps using a list-based data structure. List map iterators and + * traversal methods visit key-value pairs in the order whey were first inserted. + * + * Entries are stored internally in reversed insertion order, which means the newest key is at the + * head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and `init` + * are O(1). Other operations, such as inserting or removing entries, are also O(n), which makes + * this collection suitable only for a small number of elements. + * + * Instances of `ListMap` represent empty maps; they can be either created by calling the + * constructor directly, or by applying the function `ListMap.empty`. + * + * @tparam A the type of the keys contained in this list map + * @tparam B the type of the values associated with the keys + * + * @author Matthias Zenger + * @author Martin Odersky + * @version 2.0, 01/01/2007 + * @since 1 + * @define Coll ListMap + * @define coll list map + * @define mayNotTerminateInf + * @define willNotTerminateInf + */ @SerialVersionUID(301002838095710379L) -@deprecatedInheritance("The semantics of immutable collections makes inheriting from ListMap error-prone.", "2.11.0") -class ListMap[A, +B] -extends AbstractMap[A, B] - with Map[A, B] - with MapLike[A, B, ListMap[A, B]] - with Serializable { +sealed class ListMap[A, +B] extends AbstractMap[A, B] + with Map[A, B] + with MapLike[A, B, ListMap[A, B]] + with Serializable { override def empty = ListMap.empty - /** Returns the number of mappings in this map. - * - * @return number of mappings in this map. - */ override def size: Int = 0 + override def isEmpty: Boolean = true - /** Checks if this map maps `key` to a value and return the - * value if it exists. - * - * @param key the key of the mapping of interest - * @return the value of the mapping, if it exists - */ def get(key: A): Option[B] = None - /** This method allows one to create a new map with an additional mapping - * from `key` to `value`. If the map contains already a mapping for `key`, - * it will be overridden by this function. - * - * @param key the key element of the updated entry. - * @param value the value element of the updated entry. - */ - override def updated [B1 >: B] (key: A, value: B1): ListMap[A, B1] = - new Node[B1](key, value) - - /** Add a key/value pair to this map. - * @param kv the key/value pair - * @return A new map with the new binding added to this map - */ - def + [B1 >: B] (kv: (A, B1)): ListMap[A, B1] = updated(kv._1, kv._2) - - /** Adds two or more elements to this collection and returns - * either the collection itself (if it is mutable), or a new collection - * with the added elements. - * - * @param elem1 the first element to add. - * @param elem2 the second element to add. - * @param elems the remaining elements to add. - */ - override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): ListMap[A, B1] = - this + elem1 + elem2 ++ elems - - /** Adds a number of elements provided by a traversable object - * and returns a new collection with the added elements. - * - * @param xs the traversable object. - */ + override def updated[B1 >: B](key: A, value: B1): ListMap[A, B1] = new Node[B1](key, value) + + def +[B1 >: B](kv: (A, B1)): ListMap[A, B1] = new Node[B1](kv._1, kv._2) + def -(key: A): ListMap[A, B] = this + override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): ListMap[A, B1] = - ((repr: ListMap[A, B1]) /: xs.seq) (_ + _) - - /** This creates a new mapping without the given `key`. - * If the map does not contain a mapping for the given key, the - * method returns the same map. - * - * @param key a map without a mapping for the given key. - */ - def - (key: A): ListMap[A, B] = this - - /** Returns an iterator over key-value pairs. - */ - def iterator: Iterator[(A,B)] = - new AbstractIterator[(A,B)] { - var self: ListMap[A,B] = ListMap.this - def hasNext = !self.isEmpty - def next(): (A,B) = - if (!hasNext) throw new NoSuchElementException("next on empty iterator") - else { val res = (self.key, self.value); self = self.next; res } - }.toList.reverseIterator - - protected def key: A = throw new NoSuchElementException("empty map") - protected def value: B = throw new NoSuchElementException("empty map") - protected def next: ListMap[A, B] = throw new NoSuchElementException("empty map") - - /** This class represents an entry in the `ListMap`. - */ + if (xs.isEmpty) this + else ((repr: ListMap[A, B1]) /: xs) (_ + _) + + def iterator: Iterator[(A, B)] = { + def reverseList = { + var curr: ListMap[A, B] = this + var res: List[(A, B)] = Nil + while (!curr.isEmpty) { + res = (curr.key, curr.value) :: res + curr = curr.next + } + res + } + reverseList.iterator + } + + protected def key: A = throw new NoSuchElementException("key of empty map") + protected def value: B = throw new NoSuchElementException("value of empty map") + protected def next: ListMap[A, B] = throw new NoSuchElementException("next of empty map") + + override def stringPrefix = "ListMap" + + /** + * Represents an entry in the `ListMap`. + */ @SerialVersionUID(-6453056603889598734L) protected class Node[B1 >: B](override protected val key: A, override protected val value: B1) extends ListMap[A, B1] with Serializable { - /** Returns the number of mappings in this map. - * - * @return number of mappings. - */ - override def size: Int = size0(this, 0) - - // to allow tail recursion and prevent stack overflows - @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.next, acc + 1) - - /** Is this an empty map? - * - * @return true, iff the map is empty. - */ - override def isEmpty: Boolean = false - /** Retrieves the value which is associated with the given key. This - * method throws an exception if there is no mapping from the given - * key to a value. - * - * @param k the key - * @return the value associated with the given key. - */ - override def apply(k: A): B1 = apply0(this, k) + override def size: Int = sizeInternal(this, 0) + @tailrec private[this] def sizeInternal(cur: ListMap[A, B1], acc: Int): Int = + if (cur.isEmpty) acc + else sizeInternal(cur.next, acc + 1) - @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = - if (cur.isEmpty) throw new NoSuchElementException("key not found: "+k) + override def isEmpty: Boolean = false + + override def apply(k: A): B1 = applyInternal(this, k) + + @tailrec private[this] def applyInternal(cur: ListMap[A, B1], k: A): B1 = + if (cur.isEmpty) throw new NoSuchElementException("key not found: " + k) else if (k == cur.key) cur.value - else apply0(cur.next, k) - - /** Checks if this map maps `key` to a value and return the - * value if it exists. - * - * @param k the key of the mapping of interest - * @return the value of the mapping, if it exists - */ - override def get(k: A): Option[B1] = get0(this, k) - - @tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] = - if (k == cur.key) Some(cur.value) - else if (cur.next.nonEmpty) get0(cur.next, k) else None - - /** This method allows one to create a new map with an additional mapping - * from `key` to `value`. If the map contains already a mapping for `key`, - * it will be overridden by this function. - */ - override def updated [B2 >: B1](k: A, v: B2): ListMap[A, B2] = { + else applyInternal(cur.next, k) + + override def get(k: A): Option[B1] = getInternal(this, k) + + @tailrec private[this] def getInternal(cur: ListMap[A, B1], k: A): Option[B1] = + if (cur.isEmpty) None + else if (k == cur.key) Some(cur.value) + else getInternal(cur.next, k) + + override def contains(k: A): Boolean = containsInternal(this, k) + + @tailrec private[this] def containsInternal(cur: ListMap[A, B1], k: A): Boolean = + if(cur.isEmpty) false + else if (k == cur.key) true + else containsInternal(cur.next, k) + + override def updated[B2 >: B1](k: A, v: B2): ListMap[A, B2] = { val m = this - k new m.Node[B2](k, v) } - /** Creates a new mapping without the given `key`. - * If the map does not contain a mapping for the given key, the - * method returns the same map. - */ - override def - (k: A): ListMap[A, B1] = remove0(k, this, Nil) - - @tailrec private def remove0(k: A, cur: ListMap[A, B1], acc: List[ListMap[A, B1]]): ListMap[A, B1] = - if (cur.isEmpty) - acc.last - else if (k == cur.key) - (cur.next /: acc) { - case (t, h) => val tt = t; new tt.Node(h.key, h.value) // SI-7459 - } - else - remove0(k, cur.next, cur::acc) + override def +[B2 >: B1](kv: (A, B2)): ListMap[A, B2] = { + val m = this - kv._1 + new m.Node[B2](kv._1, kv._2) + } + + override def -(k: A): ListMap[A, B1] = removeInternal(k, this, Nil) + + @tailrec private[this] def removeInternal(k: A, cur: ListMap[A, B1], acc: List[ListMap[A, B1]]): ListMap[A, B1] = + if (cur.isEmpty) acc.last + else if (k == cur.key) (cur.next /: acc) { case (t, h) => new t.Node(h.key, h.value) } + else removeInternal(k, cur.next, cur :: acc) override protected def next: ListMap[A, B1] = ListMap.this + + override def last: (A, B1) = (key, value) + override def init: ListMap[A, B1] = next } } diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala index adc975479a..d9795e9161 100644 --- a/src/library/scala/collection/immutable/ListSet.scala +++ b/src/library/scala/collection/immutable/ListSet.scala @@ -11,174 +11,126 @@ package collection package immutable import generic._ -import scala.annotation.{tailrec, bridge} -import mutable.{ ListBuffer, Builder } - -/** $factoryInfo - * @define Coll immutable.ListSet - * @define coll immutable list set - * @since 1 - */ +import scala.annotation.tailrec + +/** + * $factoryInfo + * + * Note that each element insertion takes O(n) time, which means that creating a list set with + * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of + * elements. + * + * @since 1 + * @define Coll ListSet + * @define coll list set + */ object ListSet extends ImmutableSetFactory[ListSet] { - /** setCanBuildFromInfo */ - implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = setCanBuildFrom[A] - override def newBuilder[A]: Builder[A, ListSet[A]] = new ListSetBuilder[A] + /** + * $setCanBuildFromInfo + */ + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = + setCanBuildFrom[A] - private object EmptyListSet extends ListSet[Any] { } + @SerialVersionUID(5010379588739277132L) + private object EmptyListSet extends ListSet[Any] private[collection] def emptyInstance: ListSet[Any] = EmptyListSet - - /** A custom builder because forgetfully adding elements one at - * a time to a list backed set puts the "squared" in N^2. There is a - * temporary space cost, but it's improbable a list backed set could - * become large enough for this to matter given its pricy element lookup. - */ - class ListSetBuilder[Elem](initial: ListSet[Elem]) extends Builder[Elem, ListSet[Elem]] { - def this() = this(empty[Elem]) - protected val elems = (new mutable.ListBuffer[Elem] ++= initial).reverse - protected val seen = new mutable.HashSet[Elem] ++= initial - - def +=(x: Elem): this.type = { - if (!seen(x)) { - elems += x - seen += x - } - this - } - def clear() = { elems.clear() ; seen.clear() } - def result() = elems.foldLeft(empty[Elem])(_ unchecked_+ _) - } } -/** This class implements immutable sets using a list-based data - * structure. Instances of `ListSet` represent - * empty sets; they can be either created by calling the constructor - * directly, or by applying the function `ListSet.empty`. - * - * @tparam A the type of the elements contained in this list set. - * - * @author Matthias Zenger - * @version 1.0, 09/07/2003 - * @since 1 - * @define Coll immutable.ListSet - * @define coll immutable list set - * @define mayNotTerminateInf - * @define willNotTerminateInf - */ -@deprecatedInheritance("The semantics of immutable collections makes inheriting from ListSet error-prone.", "2.11.0") -class ListSet[A] extends AbstractSet[A] - with Set[A] - with GenericSetTemplate[A, ListSet] - with SetLike[A, ListSet[A]] - with Serializable{ self => +/** + * This class implements immutable sets using a list-based data structure. List set iterators and + * traversal methods visit elements in the order whey were first inserted. + * + * Elements are stored internally in reversed insertion order, which means the newest element is at + * the head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and + * `init` are O(1). Other operations, such as inserting or removing entries, are also O(n), which + * makes this collection suitable only for a small number of elements. + * + * Instances of `ListSet` represent empty sets; they can be either created by calling the + * constructor directly, or by applying the function `ListSet.empty`. + * + * @tparam A the type of the elements contained in this list set + * + * @author Matthias Zenger + * @version 1.0, 09/07/2003 + * @since 1 + * @define Coll ListSet + * @define coll list set + * @define mayNotTerminateInf + * @define willNotTerminateInf + */ +@SerialVersionUID(-8417059026623606218L) +sealed class ListSet[A] extends AbstractSet[A] + with Set[A] + with GenericSetTemplate[A, ListSet] + with SetLike[A, ListSet[A]] + with Serializable { + override def companion: GenericCompanion[ListSet] = ListSet - /** Returns the number of elements in this set. - * - * @return number of set elements. - */ override def size: Int = 0 override def isEmpty: Boolean = true - /** Checks if this set contains element `elem`. - * - * @param elem the element to check for membership. - * @return `'''true'''`, iff `elem` is contained in this set. - */ def contains(elem: A): Boolean = false - /** This method creates a new set with an additional element. - */ - def + (elem: A): ListSet[A] = new Node(elem) - - /** `-` can be used to remove a single element. - */ - def - (elem: A): ListSet[A] = this + def +(elem: A): ListSet[A] = new Node(elem) + def -(elem: A): ListSet[A] = this - /** If we are bulk adding elements and desire a runtime measured in - * sub-interstellar time units, we better find a way to avoid traversing - * the collection on each element. That's what the custom builder does, - * so we take the easy way out and add ourselves and the argument to - * a new builder. - */ override def ++(xs: GenTraversableOnce[A]): ListSet[A] = if (xs.isEmpty) this - else (new ListSet.ListSetBuilder(this) ++= xs.seq).result() - - private[ListSet] def unchecked_+(e: A): ListSet[A] = new Node(e) - private[ListSet] def unchecked_outer: ListSet[A] = - throw new NoSuchElementException("Empty ListSet has no outer pointer") - - /** Creates a new iterator over all elements contained in this set. - * - * @throws java.util.NoSuchElementException - * @return the new iterator - */ - def iterator: Iterator[A] = new AbstractIterator[A] { - var that: ListSet[A] = self - def hasNext = that.nonEmpty - def next: A = - if (hasNext) { - val res = that.head - that = that.tail - res + else (repr /: xs) (_ + _) + + def iterator: Iterator[A] = { + def reverseList = { + var curr: ListSet[A] = this + var res: List[A] = Nil + while (!curr.isEmpty) { + res = curr.elem :: res + curr = curr.next } - else Iterator.empty.next() + res + } + reverseList.iterator } - /** - * @throws java.util.NoSuchElementException - */ - override def head: A = throw new NoSuchElementException("Set has no elements") + protected def elem: A = throw new NoSuchElementException("elem of empty set") + protected def next: ListSet[A] = throw new NoSuchElementException("next of empty set") - /** - * @throws java.util.NoSuchElementException - */ - override def tail: ListSet[A] = throw new NoSuchElementException("Next of an empty set") + override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]] override def stringPrefix = "ListSet" - /** Represents an entry in the `ListSet`. - */ - protected class Node(override val head: A) extends ListSet[A] with Serializable { - override private[ListSet] def unchecked_outer = self + /** + * Represents an entry in the `ListSet`. + */ + @SerialVersionUID(-787710309854855049L) + protected class Node(override protected val elem: A) extends ListSet[A] with Serializable { - /** Returns the number of elements in this set. - * - * @return number of set elements. - */ override def size = sizeInternal(this, 0) - @tailrec private def sizeInternal(n: ListSet[A], acc: Int): Int = + + @tailrec private[this] def sizeInternal(n: ListSet[A], acc: Int): Int = if (n.isEmpty) acc - else sizeInternal(n.unchecked_outer, acc + 1) + else sizeInternal(n.next, acc + 1) - /** Checks if this set is empty. - * - * @return true, iff there is no element in the set. - */ override def isEmpty: Boolean = false - /** Checks if this set contains element `elem`. - * - * @param e the element to check for membership. - * @return `'''true'''`, iff `elem` is contained in this set. - */ override def contains(e: A) = containsInternal(this, e) - @tailrec private def containsInternal(n: ListSet[A], e: A): Boolean = - !n.isEmpty && (n.head == e || containsInternal(n.unchecked_outer, e)) - /** This method creates a new set with an additional element. - */ + @tailrec private[this] def containsInternal(n: ListSet[A], e: A): Boolean = + !n.isEmpty && (n.elem == e || containsInternal(n.next, e)) + override def +(e: A): ListSet[A] = if (contains(e)) this else new Node(e) - /** `-` can be used to remove a single element from a set. - */ - override def -(e: A): ListSet[A] = if (e == head) self else { - val tail = self - e; new tail.Node(head) - } + override def -(e: A): ListSet[A] = removeInternal(e, this, Nil) + + @tailrec private[this] def removeInternal(k: A, cur: ListSet[A], acc: List[ListSet[A]]): ListSet[A] = + if (cur.isEmpty) acc.last + else if (k == cur.elem) (cur.next /: acc) { case (t, h) => new t.Node(h.elem) } + else removeInternal(k, cur.next, cur :: acc) - override def tail: ListSet[A] = self + override protected def next: ListSet[A] = ListSet.this + + override def last: A = elem + override def init: ListSet[A] = next } - - override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]] } diff --git a/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala index 2c5b444c70..4107b6414d 100644 --- a/src/library/scala/collection/immutable/Map.scala +++ b/src/library/scala/collection/immutable/Map.scala @@ -18,30 +18,30 @@ import generic._ * functionality for the abstract methods in `Map`: * * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def + [B1 >: B](kv: (A, B1)): Map[A, B1] - * def -(key: A): Map[A, B] + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def + [V1 >: V](kv: (K, V1)): Map[K, V1] + * def -(key: K): Map[K, V] * }}} * * @since 1 */ -trait Map[A, +B] extends Iterable[(A, B)] -// with GenMap[A, B] - with scala.collection.Map[A, B] - with MapLike[A, B, Map[A, B]] { self => +trait Map[K, +V] extends Iterable[(K, V)] +// with GenMap[K, V] + with scala.collection.Map[K, V] + with MapLike[K, V, Map[K, V]] { self => - override def empty: Map[A, B] = Map.empty + override def empty: Map[K, V] = Map.empty /** Returns this $coll as an immutable map. * * A new map will not be built; lazy collections will stay lazy. */ @deprecatedOverriding("Immutable maps should do nothing on toMap except return themselves cast as a map.", "2.11.0") - override def toMap[T, U](implicit ev: (A, B) <:< (T, U)): immutable.Map[T, U] = + override def toMap[T, U](implicit ev: (K, V) <:< (T, U)): immutable.Map[T, U] = self.asInstanceOf[immutable.Map[T, U]] - override def seq: Map[A, B] = this + override def seq: Map[K, V] = this /** The same map with a given default function. * Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefault`. @@ -51,7 +51,7 @@ trait Map[A, +B] extends Iterable[(A, B)] * @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[B1 >: B](d: A => B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, d) + def withDefault[V1 >: V](d: K => V1): immutable.Map[K, V1] = new Map.WithDefault[K, V1](this, d) /** The same map with a given default value. * Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefaultValue`. @@ -61,15 +61,15 @@ trait Map[A, +B] extends Iterable[(A, B)] * @param d default value used for non-present keys * @return a wrapper of the map with a default value */ - def withDefaultValue[B1 >: B](d: B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, x => d) + def withDefaultValue[V1 >: V](d: V1): immutable.Map[K, V1] = new Map.WithDefault[K, V1](this, x => d) /** Add a key/value pair to this map. * @param key the key * @param value the value * @return A new map with the new binding added to this map */ - override def updated [B1 >: B](key: A, value: B1): Map[A, B1] - def + [B1 >: B](kv: (A, B1)): Map[A, B1] + override def updated [V1 >: V](key: K, value: V1): Map[K, V1] + def + [V1 >: V](kv: (K, V1)): Map[K, V1] } /** $factoryInfo @@ -79,116 +79,138 @@ trait Map[A, +B] extends Iterable[(A, B)] object Map extends ImmutableMapFactory[Map] { /** $mapCanBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] = new MapCanBuildFrom[K, V] - def empty[A, B]: Map[A, B] = EmptyMap.asInstanceOf[Map[A, B]] + def empty[K, V]: Map[K, V] = EmptyMap.asInstanceOf[Map[K, V]] - class WithDefault[A, +B](underlying: Map[A, B], d: A => B) extends scala.collection.Map.WithDefault[A, B](underlying, d) with Map[A, B] { + class WithDefault[K, +V](underlying: Map[K, V], d: K => V) extends scala.collection.Map.WithDefault[K, V](underlying, d) with Map[K, V] { override def empty = new WithDefault(underlying.empty, d) - override def updated[B1 >: B](key: A, value: B1): WithDefault[A, B1] = new WithDefault[A, B1](underlying.updated[B1](key, value), d) - override def + [B1 >: B](kv: (A, B1)): WithDefault[A, B1] = updated(kv._1, kv._2) - override def - (key: A): WithDefault[A, B] = new WithDefault(underlying - key, d) - override def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1] = new WithDefault[A, B1](underlying, d) - override def withDefaultValue[B1 >: B](d: B1): immutable.Map[A, B1] = new WithDefault[A, B1](underlying, x => d) + override def updated[V1 >: V](key: K, value: V1): WithDefault[K, V1] = new WithDefault[K, V1](underlying.updated[V1](key, value), d) + override def + [V1 >: V](kv: (K, V1)): WithDefault[K, V1] = updated(kv._1, kv._2) + override def - (key: K): WithDefault[K, V] = new WithDefault(underlying - key, d) + override def withDefault[V1 >: V](d: K => V1): immutable.Map[K, V1] = new WithDefault[K, V1](underlying, d) + override def withDefaultValue[V1 >: V](d: V1): immutable.Map[K, V1] = new WithDefault[K, V1](underlying, x => d) } private object EmptyMap extends AbstractMap[Any, Nothing] with Map[Any, Nothing] with Serializable { override def size: Int = 0 + override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key) + override def contains(key: Any) = false def get(key: Any): Option[Nothing] = None def iterator: Iterator[(Any, Nothing)] = Iterator.empty - override def updated [B1] (key: Any, value: B1): Map[Any, B1] = new Map1(key, value) - def + [B1](kv: (Any, B1)): Map[Any, B1] = updated(kv._1, kv._2) + override def updated [V1] (key: Any, value: V1): Map[Any, V1] = new Map1(key, value) + def + [V1](kv: (Any, V1)): Map[Any, V1] = updated(kv._1, kv._2) def - (key: Any): Map[Any, Nothing] = this } - class Map1[A, +B](key1: A, value1: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map1[K, +V](key1: K, value1: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 1 - def get(key: A): Option[B] = + override def apply(key: K) = if (key == key1) value1 else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = key == key1 + def get(key: K): Option[V] = if (key == key1) Some(value1) else None def iterator = Iterator((key1, value1)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map1(key1, value) else new Map2(key1, value1, key, value) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) Map.empty else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)) } } - class Map2[A, +B](key1: A, value1: B, key2: A, value2: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map2[K, +V](key1: K, value1: V, key2: K, value2: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 2 - def get(key: A): Option[B] = + override def apply(key: K) = + if (key == key1) value1 + else if (key == key2) value2 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = (key == key1) || (key == key2) + def get(key: K): Option[V] = if (key == key1) Some(value1) else if (key == key2) Some(value2) else None def iterator = Iterator((key1, value1), (key2, value2)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map2(key1, value, key2, value2) else if (key == key2) new Map2(key1, value1, key2, value) else new Map3(key1, value1, key2, value2, key, value) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) new Map1(key2, value2) else if (key == key2) new Map1(key1, value1) else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)); f((key2, value2)) } } - class Map3[A, +B](key1: A, value1: B, key2: A, value2: B, key3: A, value3: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map3[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 3 - def get(key: A): Option[B] = + override def apply(key: K) = + if (key == key1) value1 + else if (key == key2) value2 + else if (key == key3) value3 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = (key == key1) || (key == key2) || (key == key3) + def get(key: K): Option[V] = if (key == key1) Some(value1) else if (key == key2) Some(value2) else if (key == key3) Some(value3) else None def iterator = Iterator((key1, value1), (key2, value2), (key3, value3)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map3(key1, value, key2, value2, key3, value3) else if (key == key2) new Map3(key1, value1, key2, value, key3, value3) else if (key == key3) new Map3(key1, value1, key2, value2, key3, value) else new Map4(key1, value1, key2, value2, key3, value3, key, value) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) new Map2(key2, value2, key3, value3) else if (key == key2) new Map2(key1, value1, key3, value3) else if (key == key3) new Map2(key1, value1, key2, value2) else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)); f((key2, value2)); f((key3, value3)) } } - class Map4[A, +B](key1: A, value1: B, key2: A, value2: B, key3: A, value3: B, key4: A, value4: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map4[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V, key4: K, value4: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 4 - def get(key: A): Option[B] = + override def apply(key: K) = + if (key == key1) value1 + else if (key == key2) value2 + else if (key == key3) value3 + else if (key == key4) value4 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = (key == key1) || (key == key2) || (key == key3) || (key == key4) + def get(key: K): Option[V] = if (key == key1) Some(value1) else if (key == key2) Some(value2) else if (key == key3) Some(value3) else if (key == key4) Some(value4) else None def iterator = Iterator((key1, value1), (key2, value2), (key3, value3), (key4, value4)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map4(key1, value, key2, value2, key3, value3, key4, value4) else if (key == key2) new Map4(key1, value1, key2, value, key3, value3, key4, value4) else if (key == key3) new Map4(key1, value1, key2, value2, key3, value, key4, value4) else if (key == key4) new Map4(key1, value1, key2, value2, key3, value3, key4, value) - else new HashMap + ((key1, value1), (key2, value2), (key3, value3), (key4, value4), (key, value)) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + else (new HashMap).updated(key1,value1).updated(key2, value2).updated(key3, value3).updated(key4, value4).updated(key, value) + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) new Map3(key2, value2, key3, value3, key4, value4) else if (key == key2) new Map3(key1, value1, key3, value3, key4, value4) else if (key == key3) new Map3(key1, value1, key2, value2, key4, value4) else if (key == key4) new Map3(key1, value1, key2, value2, key3, value3) else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)); f((key2, value2)); f((key3, value3)); f((key4, value4)) } } } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -abstract class AbstractMap[A, +B] extends scala.collection.AbstractMap[A, B] with Map[A, B] +abstract class AbstractMap[K, +V] extends scala.collection.AbstractMap[K, V] with Map[K, V] diff --git a/src/library/scala/collection/immutable/MapLike.scala b/src/library/scala/collection/immutable/MapLike.scala index bd5b9c9faf..5867383b52 100644 --- a/src/library/scala/collection/immutable/MapLike.scala +++ b/src/library/scala/collection/immutable/MapLike.scala @@ -14,16 +14,16 @@ import generic._ import parallel.immutable.ParMap /** - * A generic template for immutable maps from keys of type `A` - * to values of type `B`. + * A generic template for immutable maps from keys of type `K` + * to values of type `V`. * To implement a concrete map, you need to provide implementations of the * following methods (where `This` is the type of the actual map implementation): * * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def + [B1 >: B](kv: (A, B)): Map[A, B1] - * def - (key: A): This + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def + [V1 >: V](kv: (K, V)): Map[K, V1] + * def - (key: K): This * }}} * * If you wish that transformer methods like `take`, `drop`, `filter` return the @@ -36,8 +36,8 @@ import parallel.immutable.ParMap * It is also good idea to override methods `foreach` and * `size` for efficiency. * - * @tparam A the type of the keys contained in this collection. - * @tparam B the type of the values associated with the keys. + * @tparam K the type of the keys contained in this collection. + * @tparam V the type of the values associated with the keys. * @tparam This The type of the actual map implementation. * * @author Martin Odersky @@ -46,26 +46,26 @@ import parallel.immutable.ParMap * @define Coll immutable.Map * @define coll immutable map */ -trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] - extends scala.collection.MapLike[A, B, This] - with Parallelizable[(A, B), ParMap[A, B]] +trait MapLike[K, +V, +This <: MapLike[K, V, This] with Map[K, V]] + extends scala.collection.MapLike[K, V, This] + with Parallelizable[(K, V), ParMap[K, V]] { self => - protected[this] override def parCombiner = ParMap.newCombiner[A, B] + protected[this] override def parCombiner = ParMap.newCombiner[K, V] /** A new immutable map containing updating this map with a given key/value mapping. * @param key the key * @param value the value * @return A new map with the new key/value mapping */ - override def updated [B1 >: B](key: A, value: B1): immutable.Map[A, B1] = this + ((key, value)) + override def updated [V1 >: V](key: K, value: V1): immutable.Map[K, V1] = this + ((key, value)) /** Add a key/value pair to this map, returning a new map. * @param kv the key/value pair. * @return A new map with the new binding added to this map. */ - def + [B1 >: B] (kv: (A, B1)): immutable.Map[A, B1] + def + [V1 >: V] (kv: (K, V1)): immutable.Map[K, V1] /** Adds two or more elements to this collection and returns * a new collection. @@ -75,7 +75,7 @@ self => * @param elems the remaining elements to add. * @return A new map with the new bindings added to this map. */ - override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): immutable.Map[A, B1] = + override def + [V1 >: V] (elem1: (K, V1), elem2: (K, V1), elems: (K, V1) *): immutable.Map[K, V1] = this + elem1 + elem2 ++ elems /** Adds a number of elements provided by a traversable object @@ -84,40 +84,40 @@ self => * @param xs the traversable object consisting of key-value pairs. * @return a new immutable map with the bindings of this map and those from `xs`. */ - override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): immutable.Map[A, B1] = - ((repr: immutable.Map[A, B1]) /: xs.seq) (_ + _) + override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): immutable.Map[K, V1] = + ((repr: immutable.Map[K, V1]) /: xs.seq) (_ + _) /** 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: A => Boolean): Map[A, B] = new FilteredKeys(p) with DefaultMap[A, B] + override def filterKeys(p: K => Boolean): Map[K, V] = new FilteredKeys(p) with DefaultMap[K, V] /** 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[C](f: B => C): Map[A, C] = new MappedValues(f) with DefaultMap[A, C] + override def mapValues[W](f: V => W): Map[K, W] = new MappedValues(f) with DefaultMap[K, W] /** Collects all keys of this map in a set. * @return a set containing all keys of this map. */ - override def keySet: immutable.Set[A] = new ImmutableDefaultKeySet + override def keySet: immutable.Set[K] = new ImmutableDefaultKeySet - protected class ImmutableDefaultKeySet extends super.DefaultKeySet with immutable.Set[A] { - override def + (elem: A): immutable.Set[A] = + protected class ImmutableDefaultKeySet extends super.DefaultKeySet with immutable.Set[K] { + override def + (elem: K): immutable.Set[K] = if (this(elem)) this - else immutable.Set[A]() ++ this + elem - override def - (elem: A): immutable.Set[A] = - if (this(elem)) immutable.Set[A]() ++ this - elem + else immutable.Set[K]() ++ this + elem + override def - (elem: K): immutable.Set[K] = + if (this(elem)) immutable.Set[K]() ++ this - elem else this // ImmutableDefaultKeySet is only protected, so we won't warn on override. // Someone could override in a way that makes widening not okay // (e.g. by overriding +, though the version in this class is fine) - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] + override def toSet[B >: K]: Set[B] = this.asInstanceOf[Set[B]] } /** This function transforms all the values of mappings contained @@ -126,10 +126,9 @@ self => * @param f A function over keys and values * @return the updated map */ - def transform[C, That](f: (A, B) => C)(implicit bf: CanBuildFrom[This, (A, C), That]): That = { + def transform[W, That](f: (K, V) => W)(implicit bf: CanBuildFrom[This, (K, W), That]): That = { val b = bf(repr) for ((key, value) <- this) b += ((key, f(key, value))) b.result() } } - diff --git a/src/library/scala/collection/immutable/MapProxy.scala b/src/library/scala/collection/immutable/MapProxy.scala index d126b9e7a6..0d1c17d4b3 100644 --- a/src/library/scala/collection/immutable/MapProxy.scala +++ b/src/library/scala/collection/immutable/MapProxy.scala @@ -23,7 +23,7 @@ package immutable * @version 2.0, 31/12/2006 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait MapProxy[A, +B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] { override def repr = this private def newProxy[B1 >: B](newSelf: Map[A, B1]): MapProxy[A, B1] = diff --git a/src/library/scala/collection/immutable/NumericRange.scala b/src/library/scala/collection/immutable/NumericRange.scala index 59b8a40c64..f1b831bf75 100644 --- a/src/library/scala/collection/immutable/NumericRange.scala +++ b/src/library/scala/collection/immutable/NumericRange.scala @@ -10,8 +10,6 @@ package scala package collection package immutable -import mutable.{ Builder, ListBuffer } - // TODO: Now the specialization exists there is no clear reason to have // separate classes for Range/NumericRange. Investigate and consolidate. @@ -121,7 +119,7 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { // (Integral <: Ordering). This can happen for custom Integral types. // - The Ordering is the default Ordering of a well-known Integral type. if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) { - if (num.signum(step) > 0) start + if (num.signum(step) > 0) head else last } else super.min(ord) @@ -129,7 +127,7 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { // See comment for fast path in min(). if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) { if (num.signum(step) > 0) last - else start + else head } else super.max(ord) // Motivated by the desire for Double ranges with BigDecimal precision, @@ -168,6 +166,12 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { override def isEmpty = underlyingRange.isEmpty override def apply(idx: Int): A = fm(underlyingRange(idx)) override def containsTyped(el: A) = underlyingRange exists (x => fm(x) == el) + + override def toString = { + def simpleOf(x: Any): String = x.getClass.getName.split("\\.").last + val stepped = simpleOf(underlyingRange.step) + s"${super.toString} (using $underlyingRange of $stepped)" + } } } @@ -198,7 +202,7 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { // Either numRangeElements or (head + last) must be even, so divide the even one before multiplying val a = head.toLong val b = last.toLong - val ans = + val ans = if ((numRangeElements & 1) == 0) (numRangeElements / 2) * (a + b) else numRangeElements * { // Sum is even, but we might overflow it, so divide in pieces and add back remainder @@ -257,9 +261,11 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { super.equals(other) } - override def toString() = { - val endStr = if (length > Range.MAX_PRINT) ", ... )" else ")" - take(Range.MAX_PRINT).mkString("NumericRange(", ", ", endStr) + override def toString = { + val empty = if (isEmpty) "empty " else "" + val preposition = if (isInclusive) "to" else "until" + val stepped = if (step == 1) "" else s" by $step" + s"${empty}NumericRange $start $preposition $end$stepped" } } diff --git a/src/library/scala/collection/immutable/PagedSeq.scala b/src/library/scala/collection/immutable/PagedSeq.scala index 982c10687c..01854b1797 100644 --- a/src/library/scala/collection/immutable/PagedSeq.scala +++ b/src/library/scala/collection/immutable/PagedSeq.scala @@ -12,8 +12,7 @@ package scala package collection package immutable -import java.io._ -import scala.util.matching.Regex +import java.io.{File, FileReader, Reader} import scala.reflect.ClassTag /** The `PagedSeq` object defines a lazy implementations of @@ -23,7 +22,7 @@ import scala.reflect.ClassTag * `fromIterator` and `fromIterable` provide generalised instances of `PagedSeq` * @since 2.7 */ -@deprecated("This object will be moved to the scala-parser-combinators module", "2.11.8") +@deprecated("this object will be moved to the scala-parser-combinators module", "2.11.8") object PagedSeq { final val UndeterminedEnd = Int.MaxValue @@ -127,7 +126,7 @@ import PagedSeq._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecated("This class will be moved to the scala-parser-combinators module", "2.11.8") +@deprecated("this class will be moved to the scala-parser-combinators module", "2.11.8") class PagedSeq[T: ClassTag] protected( more: (Array[T], Int, Int) => Int, first1: Page[T], diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala index 16cdc6d080..5081b39bdc 100644 --- a/src/library/scala/collection/immutable/Queue.scala +++ b/src/library/scala/collection/immutable/Queue.scala @@ -12,7 +12,6 @@ package immutable import generic._ import mutable.{ Builder, ListBuffer } -import scala.annotation.tailrec /** `Queue` objects implement data structures that allow to * insert and retrieve elements in a first-in-first-out (FIFO) manner. @@ -38,8 +37,7 @@ import scala.annotation.tailrec */ @SerialVersionUID(-7622936493364270175L) -@deprecatedInheritance("The implementation details of immutable queues make inheriting from them unwise.", "2.11.0") -class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) +sealed class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) extends AbstractSeq[A] with LinearSeq[A] with GenericTraversableTemplate[A, Queue] @@ -86,6 +84,14 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) else if (in.nonEmpty) new Queue(Nil, in.reverse.tail) else throw new NoSuchElementException("tail on empty queue") + /* This is made to avoid inefficient implementation of iterator. */ + override def forall(p: A => Boolean): Boolean = + in.forall(p) && out.forall(p) + + /* This is made to avoid inefficient implementation of iterator. */ + override def exists(p: A => Boolean): Boolean = + in.exists(p) || out.exists(p) + /** Returns the length of the queue. */ override def length = in.length + out.length @@ -100,6 +106,15 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) case _ => super.:+(elem)(bf) } + override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Queue[A], B, That]): That = { + if (bf eq Queue.ReusableCBF) { + val thatQueue = that.asInstanceOf[Queue[B]] + new Queue[B](thatQueue.in ++ (thatQueue.out reverse_::: this.in), this.out).asInstanceOf[That] + } else { + super.++(that)(bf) + } + } + /** Creates a new queue with element added at the end * of the old queue. * diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index ca6720da19..82203b3d1a 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -33,7 +33,7 @@ import scala.collection.parallel.immutable.ParRange * `init`) are also permitted on overfull ranges. * * @param start the start of this range. - * @param end the end of the range. For exclusive ranges, e.g. + * @param end the end of the range. For exclusive ranges, e.g. * `Range(0,3)` or `(0 until 3)`, this is one * step past the last one in the range. For inclusive * ranges, e.g. `Range.inclusive(0,3)` or `(0 to 3)`, @@ -57,8 +57,7 @@ import scala.collection.parallel.immutable.ParRange * and its complexity is O(1). */ @SerialVersionUID(7618862778670199309L) -@deprecatedInheritance("The implementation details of Range makes inheriting from it unwise.", "2.11.0") -class Range(val start: Int, val end: Int, val step: Int) +sealed class Range(val start: Int, val end: Int, val step: Int) extends scala.collection.AbstractSeq[Int] with IndexedSeq[Int] with scala.collection.CustomParallelizable[Int, ParRange] @@ -81,8 +80,8 @@ extends scala.collection.AbstractSeq[Int] || (start < end && step < 0) || (start == end && !isInclusive) ) - @deprecated("This method will be made private, use `length` instead.", "2.11") - final val numRangeElements: Int = { + + private val numRangeElements: Int = { if (step == 0) throw new IllegalArgumentException("step cannot be 0.") else if (isEmpty) 0 else { @@ -91,21 +90,17 @@ extends scala.collection.AbstractSeq[Int] else len.toInt } } - @deprecated("This method will be made private, use `last` instead.", "2.11") - final val lastElement = - if (isEmpty) start - step - else step match { - case 1 => if (isInclusive) end else end-1 - case -1 => if (isInclusive) end else end+1 - case _ => - val remainder = (gap % step).toInt - if (remainder != 0) end - remainder - else if (isInclusive) end - else end - step - } - - @deprecated("This method will be made private.", "2.11") - final val terminalElement = lastElement + step + + // This field has a sensible value only for non-empty ranges + private val lastElement = step match { + case 1 => if (isInclusive) end else end-1 + case -1 => if (isInclusive) end else end+1 + case _ => + val remainder = (gap % step).toInt + if (remainder != 0) end - remainder + else if (isInclusive) end + else end - step + } /** The last element of this range. This method will return the correct value * even if there are too many elements to iterate over. @@ -199,6 +194,23 @@ extends scala.collection.AbstractSeq[Int] } ) + /** Creates a new range containing the elements starting at `from` up to but not including `until`. + * + * $doesNotUseBuilders + * + * @param from the element at which to start + * @param until the element at which to end (not included in the range) + * @return a new range consisting of a contiguous interval of values in the old range + */ + override def slice(from: Int, until: Int): Range = + if (from <= 0) take(until) + else if (until >= numRangeElements && numRangeElements >= 0) drop(from) + else { + val fromValue = locationAfterN(from) + if (from >= until) newEmptyRange(fromValue) + else new Range.Inclusive(fromValue, locationAfterN(until-1), step) + } + /** Creates a new range containing all the elements of this range except the last one. * * $doesNotUseBuilders @@ -380,22 +392,20 @@ extends scala.collection.AbstractSeq[Int] case _ => super.equals(other) } - /** Note: hashCode can't be overridden without breaking Seq's - * equals contract. - */ - override def toString() = { - val endStr = - if (numRangeElements > Range.MAX_PRINT || (!isEmpty && numRangeElements < 0)) ", ... )" else ")" - take(Range.MAX_PRINT).mkString("Range(", ", ", endStr) + /* Note: hashCode can't be overridden without breaking Seq's equals contract. */ + + override def toString = { + val preposition = if (isInclusive) "to" else "until" + val stepped = if (step == 1) "" else s" by $step" + val prefix = if (isEmpty) "empty " else if (!isExact) "inexact " else "" + s"${prefix}Range $start $preposition $end$stepped" } } /** A companion object for the `Range` class. */ object Range { - private[immutable] val MAX_PRINT = 512 // some arbitrary value - /** Counts the number of range elements. * @pre step != 0 * If the size of the range exceeds Int.MaxValue, the @@ -427,7 +437,7 @@ object Range { def count(start: Int, end: Int, step: Int): Int = count(start, end, step, isInclusive = false) - class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { + final class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { // override def par = new ParRange(this) override def isInclusive = true override protected def copy(start: Int, end: Int, step: Int): Range = new Inclusive(start, end, step) @@ -496,8 +506,9 @@ object Range { // As there is no appealing default step size for not-really-integral ranges, // we offer a partially constructed object. - class Partial[T, U](f: T => U) { + class Partial[T, U](private val f: T => U) extends AnyVal { def by(x: T): U = f(x) + override def toString = "Range requires step" } // Illustrating genericity with Int Range, which should have the same behavior diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index 031e5248c1..0f16f97cb0 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -65,6 +65,7 @@ object Set extends ImmutableSetFactory[Set] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] /** An optimized representation for immutable empty sets */ + @SerialVersionUID(-2443710944435909512L) private object EmptySet extends AbstractSet[Any] with Set[Any] with Serializable { override def size: Int = 0 def contains(elem: Any): Boolean = false @@ -103,10 +104,11 @@ object Set extends ImmutableSetFactory[Set] { if (p(elem1)) Some(elem1) else None } + override def head: A = elem1 + override def tail: Set[A] = Set.empty // Why is Set1 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set1[B]] - } /** An optimized representation for immutable sets of size 2 */ @@ -138,6 +140,8 @@ object Set extends ImmutableSetFactory[Set] { else if (p(elem2)) Some(elem2) else None } + override def head: A = elem1 + override def tail: Set[A] = new Set1(elem2) // Why is Set2 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set2[B]] @@ -174,6 +178,8 @@ object Set extends ImmutableSetFactory[Set] { else if (p(elem3)) Some(elem3) else None } + override def head: A = elem1 + override def tail: Set[A] = new Set2(elem2, elem3) // Why is Set3 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set3[B]] @@ -187,7 +193,7 @@ object Set extends ImmutableSetFactory[Set] { elem == elem1 || elem == elem2 || elem == elem3 || elem == elem4 def + (elem: A): Set[A] = if (contains(elem)) this - else new HashSet[A] + (elem1, elem2, elem3, elem4, elem) + else new HashSet[A] + elem1 + elem2 + elem3 + elem4 + elem def - (elem: A): Set[A] = if (elem == elem1) new Set3(elem2, elem3, elem4) else if (elem == elem2) new Set3(elem1, elem3, elem4) @@ -212,6 +218,8 @@ object Set extends ImmutableSetFactory[Set] { else if (p(elem4)) Some(elem4) else None } + override def head: A = elem1 + override def tail: Set[A] = new Set3(elem2, elem3, elem4) // Why is Set4 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set4[B]] diff --git a/src/library/scala/collection/immutable/SetProxy.scala b/src/library/scala/collection/immutable/SetProxy.scala index d505185e1d..b421b48597 100644 --- a/src/library/scala/collection/immutable/SetProxy.scala +++ b/src/library/scala/collection/immutable/SetProxy.scala @@ -12,8 +12,7 @@ package scala package collection package immutable -/** This is a simple wrapper class for <a href="Set.html" - * target="contentFrame">`scala.collection.immutable.Set`</a>. +/** This is a simple wrapper class for [[scala.collection.immutable.Set]]. * * It is most useful for assembling customized set abstractions * dynamically using object composition and forwarding. @@ -22,7 +21,7 @@ package immutable * * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]] { override def repr = this private def newProxy[B >: A](newSelf: Set[B]): SetProxy[B] = diff --git a/src/library/scala/collection/immutable/SortedMap.scala b/src/library/scala/collection/immutable/SortedMap.scala index 682788e18e..0f3bd2e195 100644 --- a/src/library/scala/collection/immutable/SortedMap.scala +++ b/src/library/scala/collection/immutable/SortedMap.scala @@ -14,7 +14,6 @@ package immutable import generic._ import mutable.Builder -import scala.annotation.unchecked.uncheckedVariance /** A map whose keys are sorted. * diff --git a/src/library/scala/collection/immutable/SortedSet.scala b/src/library/scala/collection/immutable/SortedSet.scala index 4a8859a7ab..75b2b1f4dc 100644 --- a/src/library/scala/collection/immutable/SortedSet.scala +++ b/src/library/scala/collection/immutable/SortedSet.scala @@ -13,7 +13,6 @@ package collection package immutable import generic._ -import mutable.Builder /** A subtrait of `collection.SortedSet` which represents sorted sets * which cannot be mutated. @@ -38,6 +37,6 @@ object SortedSet extends ImmutableSortedSetFactory[SortedSet] { /** $sortedSetCanBuildFromInfo */ def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = newCanBuildFrom[A] def empty[A](implicit ord: Ordering[A]): SortedSet[A] = TreeSet.empty[A] - // Force a declaration here so that BitSet's (which does not inherit from SortedSetFactory) can be more specific + // Force a declaration here so that BitSet (which does not inherit from SortedSetFactory) can be more specific override implicit def newCanBuildFrom[A](implicit ord : Ordering[A]) : CanBuildFrom[Coll, A, SortedSet[A]] = super.newCanBuildFrom } diff --git a/src/library/scala/collection/immutable/Stack.scala b/src/library/scala/collection/immutable/Stack.scala index 1c28093b2c..02bdadb5dd 100644 --- a/src/library/scala/collection/immutable/Stack.scala +++ b/src/library/scala/collection/immutable/Stack.scala @@ -46,7 +46,7 @@ object Stack extends SeqFactory[Stack] { * @define willNotTerminateInf */ @SerialVersionUID(1976480595012942526L) -@deprecated("Stack is an inelegant and potentially poorly-performing wrapper around List. Use List instead: stack push x becomes x :: list; stack.pop is list.tail.", "2.11.0") +@deprecated("Stack is an inelegant and potentially poorly-performing wrapper around List. Use List instead: stack push x becomes x :: list; stack.pop is list.tail.", "2.11.0") class Stack[+A] protected (protected val elems: List[A]) extends AbstractSeq[A] with LinearSeq[A] diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index d3be809255..8f26de153a 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -11,7 +11,7 @@ package collection package immutable import generic._ -import mutable.{Builder, StringBuilder, LazyBuilder, ListBuffer} +import mutable.{Builder, StringBuilder, LazyBuilder} import scala.annotation.tailrec import Stream.cons import scala.language.implicitConversions @@ -23,7 +23,7 @@ import scala.language.implicitConversions * import scala.math.BigInt * object Main extends App { * - * val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 } + * lazy val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 } * * fibs take 5 foreach println * } @@ -46,7 +46,7 @@ import scala.language.implicitConversions * import scala.math.BigInt * object Main extends App { * - * val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip( + * lazy val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip( * fibs.tail).map(n => { * println("Adding %d and %d".format(n._1, n._2)) * n._1 + n._2 @@ -162,7 +162,7 @@ import scala.language.implicitConversions * // The first time we try to access the tail we're going to need more * // information which will require us to recurse, which will require us to * // recurse, which... - * val sov: Stream[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 } + * lazy val sov: Stream[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 } * }}} * * The definition of `fibs` above creates a larger number of objects than @@ -198,16 +198,13 @@ import scala.language.implicitConversions * @define orderDependentFold * @define willTerminateInf Note: lazily evaluated; will terminate for infinite-sized collections. */ -@deprecatedInheritance("This class will be sealed.", "2.11.0") -abstract class Stream[+A] extends AbstractSeq[A] +sealed abstract class Stream[+A] extends AbstractSeq[A] with LinearSeq[A] with GenericTraversableTemplate[A, Stream] with LinearSeqOptimized[A, Stream[A]] - with Serializable { -self => - override def companion: GenericCompanion[Stream] = Stream + with Serializable { self => - import scala.collection.{Traversable, Iterable, Seq, IndexedSeq} + override def companion: GenericCompanion[Stream] = Stream /** Indicates whether or not the `Stream` is empty. * @@ -360,7 +357,7 @@ self => * `List(BigInt(12)) ++ fibs`. * * @tparam B The element type of the returned collection.'''That''' - * @param that The [[scala.collection.GenTraversableOnce]] the be concatenated + * @param that The [[scala.collection.GenTraversableOnce]] to be concatenated * to this `Stream`. * @return A new collection containing the result of concatenating `this` with * `that`. @@ -499,80 +496,19 @@ self => ) else super.flatMap(f)(bf) - /** Returns all the elements of this `Stream` that satisfy the predicate `p` - * in a new `Stream` - i.e., it is still a lazy data structure. The order of - * the elements is preserved - * - * @param p the predicate used to filter the stream. - * @return the elements of this stream satisfying `p`. - * - * @example {{{ - * $naturalsEx - * naturalsFrom(1) filter { _ % 5 == 0 } take 10 mkString(", ") - * // produces "5, 10, 15, 20, 25, 30, 35, 40, 45, 50" - * }}} - */ - override def filter(p: A => Boolean): Stream[A] = { + override private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = { // optimization: drop leading prefix of elems for which f returns false // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise var rest = this - while (!rest.isEmpty && !p(rest.head)) rest = rest.tail + while (!rest.isEmpty && p(rest.head) == isFlipped) rest = rest.tail // private utility func to avoid `this` on stack (would be needed for the lazy arg) - if (rest.nonEmpty) Stream.filteredTail(rest, p) + if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped) else Stream.Empty } - override final def withFilter(p: A => Boolean): StreamWithFilter = new StreamWithFilter(p) - - /** A lazier implementation of WithFilter than TraversableLike's. - */ - final class StreamWithFilter(p: A => Boolean) extends WithFilter(p) { - - override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { - def tailMap(coll: Stream[A]): Stream[B] = { - var head: A = null.asInstanceOf[A] - var tail: Stream[A] = coll - while (true) { - if (tail.isEmpty) - return Stream.Empty - head = tail.head - tail = tail.tail - if (p(head)) - return cons(f(head), tailMap(tail)) - } - throw new RuntimeException() - } - - if (isStreamBuilder(bf)) asThat(tailMap(Stream.this)) - else super.map(f)(bf) - } - - override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { - def tailFlatMap(coll: Stream[A]): Stream[B] = { - var head: A = null.asInstanceOf[A] - var tail: Stream[A] = coll - while (true) { - if (tail.isEmpty) - return Stream.Empty - head = tail.head - tail = tail.tail - if (p(head)) - return f(head).toStream append tailFlatMap(tail) - } - throw new RuntimeException() - } - - if (isStreamBuilder(bf)) asThat(tailFlatMap(Stream.this)) - else super.flatMap(f)(bf) - } - - override def foreach[U](f: A => U) = - for (x <- self) - if (p(x)) f(x) - - override def withFilter(q: A => Boolean): StreamWithFilter = - new StreamWithFilter(x => p(x) && q(x)) - } + /** A FilterMonadic which allows GC of the head of stream during processing */ + @noinline // Workaround SI-9137, see https://github.com/scala/scala/pull/4284#issuecomment-73180791 + override final def withFilter(p: A => Boolean): FilterMonadic[A, Stream[A]] = new Stream.StreamWithFilter(this, p) /** A lazier Iterator than LinearSeqLike's. */ override def iterator: Iterator[A] = new StreamIterator(self) @@ -1093,6 +1029,8 @@ self => */ override def stringPrefix = "Stream" + override def equals(that: Any): Boolean = + if (this eq that.asInstanceOf[AnyRef]) true else super.equals(that) } /** A specialized, extra-lazy implementation of a stream iterator, so it can @@ -1152,14 +1090,12 @@ object Stream extends SeqFactory[Stream] { /** Creates a new builder for a stream */ def newBuilder[A]: Builder[A, Stream[A]] = new StreamBuilder[A] - import scala.collection.{Iterable, Seq, IndexedSeq} - /** A builder for streams * @note This builder is lazy only in the sense that it does not go downs the spine * of traversables that are added as a whole. If more laziness can be achieved, * this builder should be bypassed. */ - class StreamBuilder[A] extends scala.collection.mutable.LazyBuilder[A, Stream[A]] { + class StreamBuilder[A] extends LazyBuilder[A, Stream[A]] { def result: Stream[A] = parts.toStream flatMap (_.toStream) } @@ -1183,11 +1119,11 @@ object Stream extends SeqFactory[Stream] { /** Construct a stream consisting of a given first element followed by elements * from a lazily evaluated Stream. */ - def #::(hd: A): Stream[A] = cons(hd, tl) + def #::[B >: A](hd: B): Stream[B] = cons(hd, tl) /** Construct a stream consisting of the concatenation of the given stream and * a lazily evaluated Stream. */ - def #:::(prefix: Stream[A]): Stream[A] = prefix append tl + def #:::[B >: A](prefix: Stream[B]): Stream[B] = prefix append tl } /** A wrapper method that adds `#::` for cons and `#:::` for concat as operations @@ -1237,6 +1173,27 @@ object Stream extends SeqFactory[Stream] { tlVal } + + override /*LinearSeqOptimized*/ + def sameElements[B >: A](that: GenIterable[B]): Boolean = { + @tailrec def consEq(a: Cons[_], b: Cons[_]): Boolean = { + if (a.head != b.head) false + else { + a.tail match { + case at: Cons[_] => + b.tail match { + case bt: Cons[_] => (at eq bt) || consEq(at, bt) + case _ => false + } + case _ => b.tail.isEmpty + } + } + } + that match { + case that: Cons[_] => consEq(this, that) + case _ => super.sameElements(that) + } + } } /** An infinite stream that repeatedly applies a given function to a start value. @@ -1295,13 +1252,36 @@ object Stream extends SeqFactory[Stream] { else cons(start, range(start + step, end, step)) } - private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean) = { - cons(stream.head, stream.tail filter p) + private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean, isFlipped: Boolean) = { + cons(stream.head, stream.tail.filterImpl(p, isFlipped)) } private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = { cons(head, stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]]) } -} + /** An implementation of `FilterMonadic` allowing GC of the filtered-out elements of + * the `Stream` as it is processed. + * + * Because this is not an inner class of `Stream` with a reference to the original + * head, it is now possible for GC to collect any leading and filtered-out elements + * which do not satisfy the filter, while the tail is still processing (see SI-8990). + */ + private[immutable] final class StreamWithFilter[A](sl: => Stream[A], p: A => Boolean) extends FilterMonadic[A, Stream[A]] { + private var s = sl // set to null to allow GC after filtered + private lazy val filtered = { val f = s filter p; s = null; f } // don't set to null if throw during filter + + def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = + filtered map f + + def flatMap[B, That](f: A => scala.collection.GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = + filtered flatMap f + def foreach[U](f: A => U): Unit = + filtered foreach f + + def withFilter(q: A => Boolean): FilterMonadic[A, Stream[A]] = + new StreamWithFilter[A](filtered, q) + } + +} diff --git a/src/library/scala/collection/immutable/StreamViewLike.scala b/src/library/scala/collection/immutable/StreamViewLike.scala index c2eb85815d..4d7eaeff2a 100644 --- a/src/library/scala/collection/immutable/StreamViewLike.scala +++ b/src/library/scala/collection/immutable/StreamViewLike.scala @@ -53,6 +53,7 @@ extends SeqView[A, Coll] /** boilerplate */ protected override def newForced[B](xs: => scala.collection.GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: scala.collection.GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: scala.collection.GenTraversable[B]): Transformed[B] = new { protected[this] val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => scala.collection.GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered @@ -67,7 +68,6 @@ extends SeqView[A, Coll] protected override def newPatched[B >: A](_from: Int, _patch: scala.collection.GenSeq[B], _replaced: Int): Transformed[B] = { new { val from = _from; val patch = _patch; val replaced = _replaced } with AbstractTransformed[B] with Patched[B] } - protected override def newPrepended[B >: A](elem: B): Transformed[B] = new { protected[this] val fst = elem } with AbstractTransformed[B] with Prepended[B] override def stringPrefix = "StreamView" } diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index 232d67df4f..fce0f073aa 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -10,7 +10,7 @@ package scala package collection package immutable -import mutable.{ ArrayBuilder, Builder } +import mutable.Builder import scala.util.matching.Regex import scala.math.ScalaNumber import scala.reflect.ClassTag @@ -100,11 +100,13 @@ self => /** Return all lines in this string in an iterator, including trailing * line end characters. * - * The number of strings returned is one greater than the number of line - * end characters in this string. For an empty string, a single empty - * line is returned. A line end character is one of - * - `LF` - line feed (`0x0A` hex) - * - `FF` - form feed (`0x0C` hex) + * This method is analogous to `s.split(EOL).toIterator`, + * except that any existing line endings are preserved in the result strings, + * and the empty string yields an empty iterator. + * + * A line end character is one of + * - `LF` - line feed (`0x0A`) + * - `FF` - form feed (`0x0C`) */ def linesWithSeparators: Iterator[String] = new AbstractIterator[String] { val str = self.toString @@ -121,17 +123,17 @@ self => } /** Return all lines in this string in an iterator, excluding trailing line - * end characters, i.e., apply `.stripLineEnd` to all lines + * end characters; i.e., apply `.stripLineEnd` to all lines * returned by `linesWithSeparators`. */ def lines: Iterator[String] = linesWithSeparators map (line => new WrappedString(line).stripLineEnd) /** Return all lines in this string in an iterator, excluding trailing line - * end characters, i.e., apply `.stripLineEnd` to all lines + * end characters; i.e., apply `.stripLineEnd` to all lines * returned by `linesWithSeparators`. */ - @deprecated("Use `lines` instead.","2.11.0") + @deprecated("use `lines` instead","2.11.0") def linesIterator: Iterator[String] = linesWithSeparators map (line => new WrappedString(line).stripLineEnd) @@ -163,20 +165,14 @@ self => if (toString.endsWith(suffix)) toString.substring(0, toString.length() - suffix.length) else toString - /** Replace all literal occurrences of `literal` with the string `replacement`. - * This is equivalent to [[java.lang.String#replaceAll]] except that both arguments - * are appropriately quoted to avoid being interpreted as metacharacters. + /** Replace all literal occurrences of `literal` with the literal string `replacement`. + * This method is equivalent to [[java.lang.String#replace]]. * * @param literal the string which should be replaced everywhere it occurs * @param replacement the replacement string * @return the resulting string */ - def replaceAllLiterally(literal: String, replacement: String): String = { - val arg1 = Regex.quote(literal) - val arg2 = Regex.quoteReplacement(replacement) - - toString.replaceAll(arg1, arg2) - } + def replaceAllLiterally(literal: String, replacement: String): String = toString.replace(literal, replacement) /** For every line in this string: * @@ -202,35 +198,64 @@ self => */ def stripMargin: String = stripMargin('|') - private def escape(ch: Char): String = "\\Q" + ch + "\\E" - - def split(separator: Char): Array[String] = { - val thisString = toString - var pos = thisString.indexOf(separator) - - if (pos != -1) { - val res = new ArrayBuilder.ofRef[String] - - var prev = 0 - do { - res += thisString.substring(prev, pos) - prev = pos + 1 - pos = thisString.indexOf(separator, prev) - } while (pos != -1) - - if (prev != thisString.length) - res += thisString.substring(prev, thisString.length) - - val initialResult = res.result() - pos = initialResult.length - while (pos > 0 && initialResult(pos - 1).isEmpty) pos = pos - 1 - if (pos != initialResult.length) { - val trimmed = new Array[String](pos) - Array.copy(initialResult, 0, trimmed, 0, pos) - trimmed - } else initialResult - } else Array[String](thisString) - } + private def escape(ch: Char): String = if ( + (ch >= 'a') && (ch <= 'z') || + (ch >= 'A') && (ch <= 'Z') || + (ch >= '0' && ch <= '9')) ch.toString + else "\\" + ch + + /** Split this string around the separator character + * + * If this string is the empty string, returns an array of strings + * that contains a single empty string. + * + * If this string is not the empty string, returns an array containing + * the substrings terminated by the start of the string, the end of the + * string or the separator character, excluding empty trailing substrings + * + * If the separator character is a surrogate character, only split on + * matching surrogate characters if they are not part of a surrogate pair + * + * The behaviour follows, and is implemented in terms of <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split%28java.lang.String%29">String.split(re: String)</a> + * + * + * @example {{{ + * "a.b".split('.') //returns Array("a", "b") + * + * //splitting the empty string always returns the array with a single + * //empty string + * "".split('.') //returns Array("") + * + * //only trailing empty substrings are removed + * "a.".split('.') //returns Array("a") + * ".a.".split('.') //returns Array("", "a") + * "..a..".split('.') //returns Array("", "", "a") + * + * //all parts are empty and trailing + * ".".split('.') //returns Array() + * "..".split('.') //returns Array() + * + * //surrogate pairs + * val high = 0xD852.toChar + * val low = 0xDF62.toChar + * val highstring = high.toString + * val lowstring = low.toString + * + * //well-formed surrogate pairs are not split + * val highlow = highstring + lowstring + * highlow.split(high) //returns Array(highlow) + * + * //bare surrogate characters are split + * val bare = "_" + highstring + "_" + * bare.split(high) //returns Array("_", "_") + * + * }}} + * + * @param separator the character used as a delimiter + */ + def split(separator: Char): Array[String] = + toString.split(escape(separator)) + @throws(classOf[java.util.regex.PatternSyntaxException]) def split(separators: Array[Char]): Array[String] = { @@ -256,31 +281,39 @@ self => def r(groupNames: String*): Regex = new Regex(toString, groupNames: _*) /** - * @throws java.lang.IllegalArgumentException - If the string does not contain a parsable boolean. + * @throws java.lang.IllegalArgumentException If the string does not contain a parsable `Boolean`. */ def toBoolean: Boolean = parseBoolean(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable byte. + * Parse as a `Byte` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Byte`. */ def toByte: Byte = java.lang.Byte.parseByte(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable short. + * Parse as a `Short` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Short`. */ def toShort: Short = java.lang.Short.parseShort(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable int. + * Parse as an `Int` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Int`. */ def toInt: Int = java.lang.Integer.parseInt(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable long. + * Parse as a `Long` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Long`. */ def toLong: Long = java.lang.Long.parseLong(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable float. + * Parse as a `Float` (surrounding whitespace is removed with a `trim`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Float`. + * @throws java.lang.NullPointerException If the string is null. */ def toFloat: Float = java.lang.Float.parseFloat(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable double. + * Parse as a `Double` (surrounding whitespace is removed with a `trim`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Double`. + * @throws java.lang.NullPointerException If the string is null. */ def toDouble: Double = java.lang.Double.parseDouble(toString) @@ -306,8 +339,7 @@ self => * holes. * * The interpretation of the formatting patterns is described in - * <a href="" target="contentFrame" class="java/util/Formatter"> - * `java.util.Formatter`</a>, with the addition that + * [[java.util.Formatter]], with the addition that * classes deriving from `ScalaNumber` (such as [[scala.BigInt]] and * [[scala.BigDecimal]]) are unwrapped to pass a type which `Formatter` * understands. @@ -322,8 +354,7 @@ self => * which influences formatting as in `java.lang.String`'s format. * * The interpretation of the formatting patterns is described in - * <a href="" target="contentFrame" class="java/util/Formatter"> - * `java.util.Formatter`</a>, with the addition that + * [[java.util.Formatter]], with the addition that * classes deriving from `ScalaNumber` (such as `scala.BigInt` and * `scala.BigDecimal`) are unwrapped to pass a type which `Formatter` * understands. diff --git a/src/library/scala/collection/immutable/Traversable.scala b/src/library/scala/collection/immutable/Traversable.scala index 5fc0607a00..3d4ba95a16 100644 --- a/src/library/scala/collection/immutable/Traversable.scala +++ b/src/library/scala/collection/immutable/Traversable.scala @@ -18,6 +18,17 @@ import mutable.Builder /** A trait for traversable collections that are guaranteed immutable. * $traversableInfo * @define mutability immutable + * + * @define usesMutableState + * + * Note: Despite being an immutable collection, the implementation uses mutable state internally during + * construction. These state changes are invisible in single-threaded code but can lead to race conditions + * in some multi-threaded scenarios. The state of a new collection instance may not have been "published" + * (in the sense of the Java Memory Model specification), so that an unsynchronized non-volatile read from + * another thread may observe the object in an invalid state (see + * [[https://issues.scala-lang.org/browse/SI-7838 SI-7838]] for details). Note that such a read is not + * guaranteed to ''ever'' see the written object at all, and should therefore not be used, regardless + * of this issue. The easiest workaround is to exchange values between threads through a volatile var. */ trait Traversable[+A] extends scala.collection.Traversable[A] // with GenTraversable[A] diff --git a/src/library/scala/collection/immutable/TreeMap.scala b/src/library/scala/collection/immutable/TreeMap.scala index b845b76026..2d1bf0f6b1 100644 --- a/src/library/scala/collection/immutable/TreeMap.scala +++ b/src/library/scala/collection/immutable/TreeMap.scala @@ -44,8 +44,7 @@ object TreeMap extends ImmutableSortedMapFactory[TreeMap] { * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecatedInheritance("The implementation details of immutable tree maps make inheriting from them unwise.", "2.11.0") -class TreeMap[A, +B] private (tree: RB.Tree[A, B])(implicit val ordering: Ordering[A]) +final class TreeMap[A, +B] private (tree: RB.Tree[A, B])(implicit val ordering: Ordering[A]) extends SortedMap[A, B] with SortedMapLike[A, B, TreeMap[A, B]] with MapLike[A, B, TreeMap[A, B]] diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala index 2800030d67..2cdf3b3521 100644 --- a/src/library/scala/collection/immutable/TreeSet.scala +++ b/src/library/scala/collection/immutable/TreeSet.scala @@ -49,8 +49,7 @@ object TreeSet extends ImmutableSortedSetFactory[TreeSet] { * @define willNotTerminateInf */ @SerialVersionUID(-5685982407650748405L) -@deprecatedInheritance("The implementation details of immutable tree sets make inheriting from them unwise.", "2.11.0") -class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: Ordering[A]) +final class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: Ordering[A]) extends SortedSet[A] with SortedSetLike[A, TreeSet[A]] with Serializable { if (ordering eq null) diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index 5a9734a99e..1093084b9d 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -11,9 +11,8 @@ package collection package immutable import scala.annotation.unchecked.uncheckedVariance -import scala.compat.Platform import scala.collection.generic._ -import scala.collection.mutable.Builder +import scala.collection.mutable.{Builder, ReusableBuilder} import scala.collection.parallel.immutable.ParVector /** Companion object to the Vector class @@ -24,7 +23,7 @@ object Vector extends IndexedSeqFactory[Vector] { ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] private[immutable] val NIL = new Vector[Nothing](0, 0, 0) override def empty[A]: Vector[A] = NIL - + // Constants governing concat strategy for performance private final val Log2ConcatFaster = 5 private final val TinyAppendFaster = 2 @@ -40,6 +39,8 @@ object Vector extends IndexedSeqFactory[Vector] { * endian bit-mapped vector trie with a branching factor of 32. Locality is very good, but not * contiguous, which is good for very large sequences. * + * $usesMutableState + * * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#vectors "Scala's Collection Library overview"]] * section on `Vectors` for more information. * @@ -59,6 +60,7 @@ object Vector extends IndexedSeqFactory[Vector] { * @define mayNotTerminateInf * @define willNotTerminateInf */ +@SerialVersionUID(-1334388273712300479L) final class Vector[+A] private[immutable] (private[collection] val startIndex: Int, private[collection] val endIndex: Int, focus: Int) extends AbstractSeq[A] with IndexedSeq[A] @@ -69,12 +71,7 @@ extends AbstractSeq[A] with CustomParallelizable[A, ParVector[A]] { self => -override def companion: GenericCompanion[Vector] = Vector - - //assert(startIndex >= 0, startIndex+"<0") - //assert(startIndex <= endIndex, startIndex+">"+endIndex) - //assert(focus >= 0, focus+"<0") - //assert(focus <= endIndex, focus+">"+endIndex) + override def companion: GenericCompanion[Vector] = Vector private[immutable] var dirty = false @@ -98,8 +95,6 @@ override def companion: GenericCompanion[Vector] = Vector s } - - // can still be improved override /*SeqLike*/ def reverseIterator: Iterator[A] = new AbstractIterator[A] { private var i = self.length @@ -111,22 +106,18 @@ override def companion: GenericCompanion[Vector] = Vector } else Iterator.empty.next() } - // TODO: reverse - - // TODO: check performance of foreach/map etc. should override or not? // Ideally, clients will inline calls to map all the way down, including the iterator/builder methods. // In principle, escape analysis could even remove the iterator/builder allocations and do it // with local variables exclusively. But we're not quite there yet ... def apply(index: Int): A = { val idx = checkRangeConvert(index) - //println("get elem: "+index + "/"+idx + "(focus:" +focus+" xor:"+(idx^focus)+" depth:"+depth+")") getElem(idx, idx ^ focus) } private def checkRangeConvert(index: Int) = { val idx = index + startIndex - if (0 <= index && idx < endIndex) + if (index >= 0 && idx < endIndex) idx else throw new IndexOutOfBoundsException(index.toString) @@ -135,7 +126,7 @@ override def companion: GenericCompanion[Vector] = Vector // If we have a default builder, there are faster ways to perform some operations @inline private[this] def isDefaultCBF[A, B, That](bf: CanBuildFrom[Vector[A], B, That]): Boolean = (bf eq IndexedSeq.ReusableCBF) || (bf eq collection.immutable.Seq.ReusableCBF) || (bf eq collection.Seq.ReusableCBF) - + // SeqLike api override def updated[B >: A, That](index: Int, elem: B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = @@ -189,31 +180,36 @@ override def companion: GenericCompanion[Vector] = Vector Vector.empty } - override /*IterableLike*/ def head: A = { + override /*IterableLike*/ + def head: A = { if (isEmpty) throw new UnsupportedOperationException("empty.head") apply(0) } - override /*TraversableLike*/ def tail: Vector[A] = { + override /*TraversableLike*/ + def tail: Vector[A] = { if (isEmpty) throw new UnsupportedOperationException("empty.tail") drop(1) } - override /*TraversableLike*/ def last: A = { + override /*TraversableLike*/ + def last: A = { if (isEmpty) throw new UnsupportedOperationException("empty.last") - apply(length-1) + apply(length - 1) } - override /*TraversableLike*/ def init: Vector[A] = { + override /*TraversableLike*/ + def init: Vector[A] = { if (isEmpty) throw new UnsupportedOperationException("empty.init") dropRight(1) } - override /*IterableLike*/ def slice(from: Int, until: Int): Vector[A] = + override /*IterableLike*/ + def slice(from: Int, until: Int): Vector[A] = take(until).drop(from) - override /*IterableLike*/ def splitAt(n: Int): (Vector[A], Vector[A]) = (take(n), drop(n)) - + override /*IterableLike*/ + def splitAt(n: Int): (Vector[A], Vector[A]) = (take(n), drop(n)) // concat (suboptimal but avoids worst performance gotchas) override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Vector[A], B, That]): That = { @@ -225,11 +221,11 @@ override def companion: GenericCompanion[Vector] = Vector val again = if (!that.isTraversableAgain) that.toVector else that.seq again.size match { // Often it's better to append small numbers of elements (or prepend if RHS is a vector) - case n if n <= TinyAppendFaster || n < (this.size >> Log2ConcatFaster) => + case n if n <= TinyAppendFaster || n < (this.size >>> Log2ConcatFaster) => var v: Vector[B] = this for (x <- again) v = v :+ x v.asInstanceOf[That] - case n if this.size < (n >> Log2ConcatFaster) && again.isInstanceOf[Vector[_]] => + case n if this.size < (n >>> Log2ConcatFaster) && again.isInstanceOf[Vector[_]] => var v = again.asInstanceOf[Vector[B]] val ri = this.reverseIterator while (ri.hasNext) v = ri.next +: v @@ -241,8 +237,6 @@ override def companion: GenericCompanion[Vector] = Vector else super.++(that.seq) } - - // semi-private api private[immutable] def updateAt[B >: A](index: Int, elem: B): Vector[B] = { @@ -251,11 +245,10 @@ override def companion: GenericCompanion[Vector] = Vector s.initFrom(this) s.dirty = dirty s.gotoPosWritable(focus, idx, focus ^ idx) // if dirty commit changes; go to new pos and prepare for writing - s.display0(idx & 0x1f) = elem.asInstanceOf[AnyRef] + s.display0(idx & 31) = elem.asInstanceOf[AnyRef] s } - private def gotoPosWritable(oldIndex: Int, newIndex: Int, xor: Int) = if (dirty) { gotoPosWritable1(oldIndex, newIndex, xor) } else { @@ -270,7 +263,7 @@ override def companion: GenericCompanion[Vector] = Vector dirty = true } - private[immutable] def appendFront[B>:A](value: B): Vector[B] = { + private[immutable] def appendFront[B >: A](value: B): Vector[B] = { if (endIndex != startIndex) { val blockIndex = (startIndex - 1) & ~31 val lo = (startIndex - 1) & 31 @@ -284,61 +277,46 @@ override def companion: GenericCompanion[Vector] = Vector s } else { - val freeSpace = ((1<<5*(depth)) - endIndex) // free space at the right given the current tree-structure depth - val shift = freeSpace & ~((1<<5*(depth-1))-1) // number of elements by which we'll shift right (only move at top level) - val shiftBlocks = freeSpace >>> 5*(depth-1) // number of top-level blocks + val freeSpace = (1 << (5 * depth)) - endIndex // free space at the right given the current tree-structure depth + val shift = freeSpace & ~((1 << (5 * (depth - 1))) - 1) // number of elements by which we'll shift right (only move at top level) + val shiftBlocks = freeSpace >>> (5 * (depth - 1)) // number of top-level blocks - //println("----- appendFront " + value + " at " + (startIndex - 1) + " reached block start") if (shift != 0) { // case A: we can shift right on the top level - debug() - //println("shifting right by " + shiftBlocks + " at level " + (depth-1) + " (had "+freeSpace+" free space)") - if (depth > 1) { val newBlockIndex = blockIndex + shift val newFocus = focus + shift + val s = new Vector(startIndex - 1 + shift, endIndex + shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(0, shiftBlocks) // shift right by n blocks - s.debug() s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) // maybe create pos; prepare for writing s.display0(lo) = value.asInstanceOf[AnyRef] - //assert(depth == s.depth) s } else { val newBlockIndex = blockIndex + 32 val newFocus = focus - //assert(newBlockIndex == 0) - //assert(newFocus == 0) - val s = new Vector(startIndex - 1 + shift, endIndex + shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(0, shiftBlocks) // shift right by n elements s.gotoPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) // prepare for writing - s.display0(shift-1) = value.asInstanceOf[AnyRef] - s.debug() + s.display0(shift - 1) = value.asInstanceOf[AnyRef] s } } else if (blockIndex < 0) { // case B: we need to move the whole structure - val move = (1 << 5*(depth+1)) - (1 << 5*(depth)) - //println("moving right by " + move + " at level " + (depth-1) + " (had "+freeSpace+" free space)") - + val move = (1 << (5 * (depth + 1))) - (1 << (5 * depth)) val newBlockIndex = blockIndex + move val newFocus = focus + move - val s = new Vector(startIndex - 1 + move, endIndex + move, newBlockIndex) s.initFrom(this) s.dirty = dirty - s.debug() s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) // could optimize: we know it will create a whole branch s.display0(lo) = value.asInstanceOf[AnyRef] - s.debug() - //assert(s.depth == depth+1) s } else { val newBlockIndex = blockIndex @@ -349,31 +327,26 @@ override def companion: GenericCompanion[Vector] = Vector s.dirty = dirty s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(lo) = value.asInstanceOf[AnyRef] - //assert(s.depth == depth) s } - } } else { // empty vector, just insert single element at the back val elems = new Array[AnyRef](32) elems(31) = value.asInstanceOf[AnyRef] - val s = new Vector(31,32,0) + val s = new Vector(31, 32, 0) s.depth = 1 s.display0 = elems s } } - private[immutable] def appendBack[B>:A](value: B): Vector[B] = { -// //println("------- append " + value) -// debug() + private[immutable] def appendBack[B >: A](value: B): Vector[B] = { if (endIndex != startIndex) { val blockIndex = endIndex & ~31 val lo = endIndex & 31 if (endIndex != blockIndex) { - //println("will make writable block (from "+focus+") at: " + blockIndex) val s = new Vector(startIndex, endIndex + 1, blockIndex) s.initFrom(this) s.dirty = dirty @@ -381,41 +354,31 @@ override def companion: GenericCompanion[Vector] = Vector s.display0(lo) = value.asInstanceOf[AnyRef] s } else { - val shift = startIndex & ~((1<<5*(depth-1))-1) - val shiftBlocks = startIndex >>> 5*(depth-1) - - //println("----- appendBack " + value + " at " + endIndex + " reached block end") + val shift = startIndex & ~((1 << (5 * (depth - 1))) - 1) + val shiftBlocks = startIndex >>> (5 * (depth - 1)) if (shift != 0) { - debug() - //println("shifting left by " + shiftBlocks + " at level " + (depth-1) + " (had "+startIndex+" free space)") if (depth > 1) { val newBlockIndex = blockIndex - shift val newFocus = focus - shift + val s = new Vector(startIndex - shift, endIndex + 1 - shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(shiftBlocks, 0) // shift left by n blocks - s.debug() s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(lo) = value.asInstanceOf[AnyRef] - s.debug() - //assert(depth == s.depth) s } else { val newBlockIndex = blockIndex - 32 val newFocus = focus - //assert(newBlockIndex == 0) - //assert(newFocus == 0) - val s = new Vector(startIndex - shift, endIndex + 1 - shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(shiftBlocks, 0) // shift right by n elements s.gotoPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(32 - shift) = value.asInstanceOf[AnyRef] - s.debug() s } } else { @@ -427,18 +390,13 @@ override def companion: GenericCompanion[Vector] = Vector s.dirty = dirty s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(lo) = value.asInstanceOf[AnyRef] - //assert(s.depth == depth+1) might or might not create new level! - if (s.depth == depth+1) { - //println("creating new level " + s.depth + " (had "+0+" free space)") - s.debug() - } s } } } else { val elems = new Array[AnyRef](32) elems(0) = value.asInstanceOf[AnyRef] - val s = new Vector(0,1,0) + val s = new Vector(0, 1, 0) s.depth = 1 s.display0 = elems s @@ -449,39 +407,39 @@ override def companion: GenericCompanion[Vector] = Vector // low-level implementation (needs cleanup, maybe move to util class) private def shiftTopLevel(oldLeft: Int, newLeft: Int) = (depth - 1) match { - case 0 => - display0 = copyRange(display0, oldLeft, newLeft) - case 1 => - display1 = copyRange(display1, oldLeft, newLeft) - case 2 => - display2 = copyRange(display2, oldLeft, newLeft) - case 3 => - display3 = copyRange(display3, oldLeft, newLeft) - case 4 => - display4 = copyRange(display4, oldLeft, newLeft) - case 5 => - display5 = copyRange(display5, oldLeft, newLeft) + case 0 => display0 = copyRange(display0, oldLeft, newLeft) + case 1 => display1 = copyRange(display1, oldLeft, newLeft) + case 2 => display2 = copyRange(display2, oldLeft, newLeft) + case 3 => display3 = copyRange(display3, oldLeft, newLeft) + case 4 => display4 = copyRange(display4, oldLeft, newLeft) + case 5 => display5 = copyRange(display5, oldLeft, newLeft) } private def zeroLeft(array: Array[AnyRef], index: Int): Unit = { - var i = 0; while (i < index) { array(i) = null; i+=1 } + var i = 0 + while (i < index) { + array(i) = null + i += 1 + } } private def zeroRight(array: Array[AnyRef], index: Int): Unit = { - var i = index; while (i < array.length) { array(i) = null; i+=1 } + var i = index + while (i < array.length) { + array(i) = null + i += 1 + } } private def copyLeft(array: Array[AnyRef], right: Int): Array[AnyRef] = { -// if (array eq null) -// println("OUCH!!! " + right + "/" + depth + "/"+startIndex + "/" + endIndex + "/" + focus) - val a2 = new Array[AnyRef](array.length) - Platform.arraycopy(array, 0, a2, 0, right) - a2 + val copy = new Array[AnyRef](array.length) + java.lang.System.arraycopy(array, 0, copy, 0, right) + copy } private def copyRight(array: Array[AnyRef], left: Int): Array[AnyRef] = { - val a2 = new Array[AnyRef](array.length) - Platform.arraycopy(array, left, a2, left, a2.length - left) - a2 + val copy = new Array[AnyRef](array.length) + java.lang.System.arraycopy(array, left, copy, left, copy.length - left) + copy } private def preClean(depth: Int) = { @@ -513,38 +471,33 @@ override def companion: GenericCompanion[Vector] = Vector // requires structure is at index cutIndex and writable at level 0 private def cleanLeftEdge(cutIndex: Int) = { - if (cutIndex < (1 << 5)) { + if (cutIndex < (1 << 5)) { zeroLeft(display0, cutIndex) - } else - if (cutIndex < (1 << 10)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5)) - } else - if (cutIndex < (1 << 15)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10)) - } else - if (cutIndex < (1 << 20)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10) & 0x1f) - display3 = copyRight(display3, (cutIndex >>> 15)) - } else - if (cutIndex < (1 << 25)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10) & 0x1f) - display3 = copyRight(display3, (cutIndex >>> 15) & 0x1f) - display4 = copyRight(display4, (cutIndex >>> 20)) - } else - if (cutIndex < (1 << 30)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10) & 0x1f) - display3 = copyRight(display3, (cutIndex >>> 15) & 0x1f) - display4 = copyRight(display4, (cutIndex >>> 20) & 0x1f) - display5 = copyRight(display5, (cutIndex >>> 25)) + } else if (cutIndex < (1 << 10)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, cutIndex >>> 5) + } else if (cutIndex < (1 << 15)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, cutIndex >>> 10) + } else if (cutIndex < (1 << 20)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, (cutIndex >>> 10) & 31) + display3 = copyRight(display3, cutIndex >>> 15) + } else if (cutIndex < (1 << 25)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, (cutIndex >>> 10) & 31) + display3 = copyRight(display3, (cutIndex >>> 15) & 31) + display4 = copyRight(display4, cutIndex >>> 20) + } else if (cutIndex < (1 << 30)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, (cutIndex >>> 10) & 31) + display3 = copyRight(display3, (cutIndex >>> 15) & 31) + display4 = copyRight(display4, (cutIndex >>> 20) & 31) + display5 = copyRight(display5, cutIndex >>> 25) } else { throw new IllegalArgumentException() } @@ -552,49 +505,43 @@ override def companion: GenericCompanion[Vector] = Vector // requires structure is writable and at index cutIndex private def cleanRightEdge(cutIndex: Int) = { - // we're actually sitting one block left if cutIndex lies on a block boundary // this means that we'll end up erasing the whole block!! - if (cutIndex <= (1 << 5)) { + if (cutIndex <= (1 << 5)) { zeroRight(display0, cutIndex) - } else - if (cutIndex <= (1 << 10)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (cutIndex >>> 5)) - } else - if (cutIndex <= (1 << 15)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (cutIndex >>> 10)) - } else - if (cutIndex <= (1 << 20)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (((cutIndex-1) >>> 10) & 0x1f) + 1) - display3 = copyLeft(display3, (cutIndex >>> 15)) - } else - if (cutIndex <= (1 << 25)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (((cutIndex-1) >>> 10) & 0x1f) + 1) - display3 = copyLeft(display3, (((cutIndex-1) >>> 15) & 0x1f) + 1) - display4 = copyLeft(display4, (cutIndex >>> 20)) - } else - if (cutIndex <= (1 << 30)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (((cutIndex-1) >>> 10) & 0x1f) + 1) - display3 = copyLeft(display3, (((cutIndex-1) >>> 15) & 0x1f) + 1) - display4 = copyLeft(display4, (((cutIndex-1) >>> 20) & 0x1f) + 1) - display5 = copyLeft(display5, (cutIndex >>> 25)) + } else if (cutIndex <= (1 << 10)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, cutIndex >>> 5) + } else if (cutIndex <= (1 << 15)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, cutIndex >>> 10) + } else if (cutIndex <= (1 << 20)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, (((cutIndex - 1) >>> 10) & 31) + 1) + display3 = copyLeft(display3, cutIndex >>> 15) + } else if (cutIndex <= (1 << 25)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, (((cutIndex - 1) >>> 10) & 31) + 1) + display3 = copyLeft(display3, (((cutIndex - 1) >>> 15) & 31) + 1) + display4 = copyLeft(display4, cutIndex >>> 20) + } else if (cutIndex <= (1 << 30)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, (((cutIndex - 1) >>> 10) & 31) + 1) + display3 = copyLeft(display3, (((cutIndex - 1) >>> 15) & 31) + 1) + display4 = copyLeft(display4, (((cutIndex - 1) >>> 20) & 31) + 1) + display5 = copyLeft(display5, cutIndex >>> 25) } else { throw new IllegalArgumentException() } } private def requiredDepth(xor: Int) = { - if (xor < (1 << 5)) 1 + if (xor < (1 << 5)) 1 else if (xor < (1 << 10)) 2 else if (xor < (1 << 15)) 3 else if (xor < (1 << 20)) 4 @@ -607,24 +554,11 @@ override def companion: GenericCompanion[Vector] = Vector val blockIndex = cutIndex & ~31 val xor = cutIndex ^ (endIndex - 1) val d = requiredDepth(xor) - val shift = (cutIndex & ~((1 << (5*d))-1)) - - //println("cut front at " + cutIndex + ".." + endIndex + " (xor: "+xor+" shift: " + shift + " d: " + d +")") - -/* - val s = new Vector(cutIndex-shift, endIndex-shift, blockIndex-shift) - s.initFrom(this) - if (s.depth > 1) - s.gotoPos(blockIndex, focus ^ blockIndex) - s.depth = d - s.stabilize(blockIndex-shift) - s.cleanLeftEdge(cutIndex-shift) - s -*/ + val shift = cutIndex & ~((1 << (5 * d)) - 1) // need to init with full display iff going to cutIndex requires swapping block at level >= d - val s = new Vector(cutIndex-shift, endIndex-shift, blockIndex-shift) + val s = new Vector(cutIndex - shift, endIndex - shift, blockIndex - shift) s.initFrom(this) s.dirty = dirty s.gotoPosWritable(focus, blockIndex, focus ^ blockIndex) @@ -637,25 +571,18 @@ override def companion: GenericCompanion[Vector] = Vector val blockIndex = (cutIndex - 1) & ~31 val xor = startIndex ^ (cutIndex - 1) val d = requiredDepth(xor) - val shift = (startIndex & ~((1 << (5*d))-1)) - -/* - println("cut back at " + startIndex + ".." + cutIndex + " (xor: "+xor+" d: " + d +")") - if (cutIndex == blockIndex + 32) - println("OUCH!!!") -*/ - val s = new Vector(startIndex-shift, cutIndex-shift, blockIndex-shift) + val shift = startIndex & ~((1 << (5 * d)) - 1) + + val s = new Vector(startIndex - shift, cutIndex - shift, blockIndex - shift) s.initFrom(this) s.dirty = dirty s.gotoPosWritable(focus, blockIndex, focus ^ blockIndex) s.preClean(d) - s.cleanRightEdge(cutIndex-shift) + s.cleanRightEdge(cutIndex - shift) s } - } - class VectorIterator[+A](_startIndex: Int, endIndex: Int) extends AbstractIterator[A] with Iterator[A] @@ -678,7 +605,7 @@ extends AbstractIterator[A] if (lo == endLo) { if (blockIndex + lo < endIndex) { - val newBlockIndex = blockIndex+32 + val newBlockIndex = blockIndex + 32 gotoNextBlockStart(newBlockIndex, blockIndex ^ newBlockIndex) blockIndex = newBlockIndex @@ -704,8 +631,8 @@ extends AbstractIterator[A] } } - -final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A @uncheckedVariance] { +/** A class to build instances of `Vector`. This builder is reusable. */ +final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with VectorPointer[A @uncheckedVariance] { // possible alternative: start with display0 = null, blockIndex = -32, lo = 32 // to avoid allocating initial array if the result will be empty anyways @@ -716,9 +643,9 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A private var blockIndex = 0 private var lo = 0 - def += (elem: A): this.type = { + def +=(elem: A): this.type = { if (lo >= display0.length) { - val newBlockIndex = blockIndex+32 + val newBlockIndex = blockIndex + 32 gotoNextBlockStartWritable(newBlockIndex, blockIndex ^ newBlockIndex) blockIndex = newBlockIndex lo = 0 @@ -728,8 +655,7 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A this } - override def ++=(xs: TraversableOnce[A]): this.type = - super.++=(xs) + override def ++=(xs: TraversableOnce[A]): this.type = super.++=(xs) def result: Vector[A] = { val size = blockIndex + lo @@ -749,10 +675,8 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A } } - - private[immutable] trait VectorPointer[T] { - private[immutable] var depth: Int = _ + private[immutable] var depth: Int = _ private[immutable] var display0: Array[AnyRef] = _ private[immutable] var display1: Array[AnyRef] = _ private[immutable] var display2: Array[AnyRef] = _ @@ -797,98 +721,102 @@ private[immutable] trait VectorPointer[T] { } } - // requires structure is at pos oldIndex = xor ^ index private[immutable] final def getElem(index: Int, xor: Int): T = { - if (xor < (1 << 5)) { // level = 0 - display0(index & 31).asInstanceOf[T] - } else - if (xor < (1 << 10)) { // level = 1 - display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 15)) { // level = 2 - display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 20)) { // level = 3 - display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]]((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 25)) { // level = 4 - display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]]((index >> 15) & 31).asInstanceOf[Array[AnyRef]]((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 30)) { // level = 5 - display5((index >> 25) & 31).asInstanceOf[Array[AnyRef]]((index >> 20) & 31).asInstanceOf[Array[AnyRef]]((index >> 15) & 31).asInstanceOf[Array[AnyRef]]((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else { // level = 6 + if (xor < (1 << 5)) { // level = 0 + (display0 + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 10)) { // level = 1 + (display1 + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 15)) { // level = 2 + (display2 + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 20)) { // level = 3 + (display3 + ((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 25)) { // level = 4 + (display4 + ((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 30)) { // level = 5 + (display5 + ((index >>> 25) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else { // level = 6 throw new IllegalArgumentException() } } - // go to specific position // requires structure is at pos oldIndex = xor ^ index, // ensures structure is at pos index private[immutable] final def gotoPos(index: Int, xor: Int): Unit = { - if (xor < (1 << 5)) { // level = 0 (could maybe removed) - } else - if (xor < (1 << 10)) { // level = 1 - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 15)) { // level = 2 - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 20)) { // level = 3 - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 25)) { // level = 4 - display3 = display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 30)) { // level = 5 - display4 = display5((index >> 25) & 31).asInstanceOf[Array[AnyRef]] - display3 = display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else { // level = 6 + if (xor < (1 << 5)) { // level = 0 + // we're already at the block start pos + } else if (xor < (1 << 10)) { // level = 1 + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 15)) { // level = 2 + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 20)) { // level = 3 + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 25)) { // level = 4 + display3 = display4((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 30)) { // level = 5 + display4 = display5((index >>> 25) & 31).asInstanceOf[Array[AnyRef]] + display3 = display4((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else { // level = 6 throw new IllegalArgumentException() } } - - // USED BY ITERATOR // xor: oldIndex ^ index private[immutable] final def gotoNextBlockStart(index: Int, xor: Int): Unit = { // goto block start pos - if (xor < (1 << 10)) { // level = 1 - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 15)) { // level = 2 - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] + if (xor < (1 << 10)) { // level = 1 + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 15)) { // level = 2 + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 20)) { // level = 3 - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 20)) { // level = 3 + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] display1 = display2(0).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 25)) { // level = 4 - display3 = display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 25)) { // level = 4 + display3 = display4((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] display2 = display3(0).asInstanceOf[Array[AnyRef]] display1 = display2(0).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 30)) { // level = 5 - display4 = display5((index >> 25) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 30)) { // level = 5 + display4 = display5((index >>> 25) & 31).asInstanceOf[Array[AnyRef]] display3 = display4(0).asInstanceOf[Array[AnyRef]] display2 = display3(0).asInstanceOf[Array[AnyRef]] display1 = display2(0).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else { // level = 6 + } else { // level = 6 throw new IllegalArgumentException() } } @@ -897,73 +825,65 @@ private[immutable] trait VectorPointer[T] { // xor: oldIndex ^ index private[immutable] final def gotoNextBlockStartWritable(index: Int, xor: Int): Unit = { // goto block start pos - if (xor < (1 << 10)) { // level = 1 - if (depth == 1) { display1 = new Array(32); display1(0) = display0; depth+=1} + if (xor < (1 << 10)) { // level = 1 + if (depth == 1) { display1 = new Array(32); display1(0) = display0; depth += 1 } display0 = new Array(32) - display1((index >> 5) & 31) = display0 - } else - if (xor < (1 << 15)) { // level = 2 - if (depth == 2) { display2 = new Array(32); display2(0) = display1; depth+=1} + display1((index >>> 5) & 31) = display0 + } else if (xor < (1 << 15)) { // level = 2 + if (depth == 2) { display2 = new Array(32); display2(0) = display1; depth += 1 } display0 = new Array(32) display1 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - } else - if (xor < (1 << 20)) { // level = 3 - if (depth == 3) { display3 = new Array(32); display3(0) = display2; depth+=1} + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + } else if (xor < (1 << 20)) { // level = 3 + if (depth == 3) { display3 = new Array(32); display3(0) = display2; depth += 1 } display0 = new Array(32) display1 = new Array(32) display2 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - display3((index >> 15) & 31) = display2 - } else - if (xor < (1 << 25)) { // level = 4 - if (depth == 4) { display4 = new Array(32); display4(0) = display3; depth+=1} + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display3((index >>> 15) & 31) = display2 + } else if (xor < (1 << 25)) { // level = 4 + if (depth == 4) { display4 = new Array(32); display4(0) = display3; depth += 1 } display0 = new Array(32) display1 = new Array(32) display2 = new Array(32) display3 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - display3((index >> 15) & 31) = display2 - display4((index >> 20) & 31) = display3 - } else - if (xor < (1 << 30)) { // level = 5 - if (depth == 5) { display5 = new Array(32); display5(0) = display4; depth+=1} + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display3((index >>> 15) & 31) = display2 + display4((index >>> 20) & 31) = display3 + } else if (xor < (1 << 30)) { // level = 5 + if (depth == 5) { display5 = new Array(32); display5(0) = display4; depth += 1 } display0 = new Array(32) display1 = new Array(32) display2 = new Array(32) display3 = new Array(32) display4 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - display3((index >> 15) & 31) = display2 - display4((index >> 20) & 31) = display3 - display5((index >> 25) & 31) = display4 - } else { // level = 6 + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display3((index >>> 15) & 31) = display2 + display4((index >>> 20) & 31) = display3 + display5((index >>> 25) & 31) = display4 + } else { // level = 6 throw new IllegalArgumentException() } } - - // STUFF BELOW USED BY APPEND / UPDATE - private[immutable] final def copyOf(a: Array[AnyRef]) = { - val b = new Array[AnyRef](a.length) - Platform.arraycopy(a, 0, b, 0, a.length) - b + private[immutable] final def copyOf(a: Array[AnyRef]): Array[AnyRef] = { + val copy = new Array[AnyRef](a.length) + java.lang.System.arraycopy(a, 0, copy, 0, a.length) + copy } - private[immutable] final def nullSlotAndCopy(array: Array[AnyRef], index: Int) = { - //println("copy and null") + private[immutable] final def nullSlotAndCopy(array: Array[AnyRef], index: Int): Array[AnyRef] = { val x = array(index) array(index) = null copyOf(x.asInstanceOf[Array[AnyRef]]) } - // make sure there is no aliasing // requires structure is at pos index // ensures structure is clean and at pos index and writable at all levels except 0 @@ -975,40 +895,39 @@ private[immutable] trait VectorPointer[T] { display3 = copyOf(display3) display2 = copyOf(display2) display1 = copyOf(display1) - display5((index >> 25) & 31) = display4 - display4((index >> 20) & 31) = display3 - display3((index >> 15) & 31) = display2 - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display5((index >>> 25) & 31) = display4 + display4((index >>> 20) & 31) = display3 + display3((index >>> 15) & 31) = display2 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 4 => display4 = copyOf(display4) display3 = copyOf(display3) display2 = copyOf(display2) display1 = copyOf(display1) - display4((index >> 20) & 31) = display3 - display3((index >> 15) & 31) = display2 - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display4((index >>> 20) & 31) = display3 + display3((index >>> 15) & 31) = display2 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 3 => display3 = copyOf(display3) display2 = copyOf(display2) display1 = copyOf(display1) - display3((index >> 15) & 31) = display2 - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display3((index >>> 15) & 31) = display2 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 2 => display2 = copyOf(display2) display1 = copyOf(display1) - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 1 => display1 = copyOf(display1) - display1((index >> 5) & 31) = display0 + display1((index >>> 5) & 31) = display0 case 0 => } - /// USED IN UPDATE AND APPEND BACK // prepare for writing at an existing position @@ -1018,29 +937,29 @@ private[immutable] trait VectorPointer[T] { private[immutable] final def gotoPosWritable0(newIndex: Int, xor: Int): Unit = (depth - 1) match { case 5 => display5 = copyOf(display5) - display4 = nullSlotAndCopy(display5, (newIndex >> 25) & 31).asInstanceOf[Array[AnyRef]] - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display4 = nullSlotAndCopy(display5, (newIndex >>> 25) & 31) + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 4 => display4 = copyOf(display4) - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 3 => display3 = copyOf(display3) - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 2 => display2 = copyOf(display2) - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 1 => display1 = copyOf(display1) - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 0 => display0 = copyOf(display0) } @@ -1049,64 +968,59 @@ private[immutable] trait VectorPointer[T] { // requires structure is dirty and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 private[immutable] final def gotoPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { - if (xor < (1 << 5)) { // level = 0 + if (xor < (1 << 5)) { // level = 0 display0 = copyOf(display0) - } else - if (xor < (1 << 10)) { // level = 1 + } else if (xor < (1 << 10)) { // level = 1 display1 = copyOf(display1) - display1((oldIndex >> 5) & 31) = display0 - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31) - } else - if (xor < (1 << 15)) { // level = 2 + display1((oldIndex >>> 5) & 31) = display0 + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 15)) { // level = 2 display1 = copyOf(display1) display2 = copyOf(display2) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 20)) { // level = 3 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 20)) { // level = 3 display1 = copyOf(display1) display2 = copyOf(display2) display3 = copyOf(display3) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display3((oldIndex >> 15) & 31) = display2 - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 25)) { // level = 4 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display3((oldIndex >>> 15) & 31) = display2 + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 25)) { // level = 4 display1 = copyOf(display1) display2 = copyOf(display2) display3 = copyOf(display3) display4 = copyOf(display4) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display3((oldIndex >> 15) & 31) = display2 - display4((oldIndex >> 20) & 31) = display3 - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 30)) { // level = 5 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display3((oldIndex >>> 15) & 31) = display2 + display4((oldIndex >>> 20) & 31) = display3 + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 30)) { // level = 5 display1 = copyOf(display1) display2 = copyOf(display2) display3 = copyOf(display3) display4 = copyOf(display4) display5 = copyOf(display5) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display3((oldIndex >> 15) & 31) = display2 - display4((oldIndex >> 20) & 31) = display3 - display5((oldIndex >> 25) & 31) = display4 - display4 = nullSlotAndCopy(display5, (newIndex >> 25) & 31).asInstanceOf[Array[AnyRef]] - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else { // level = 6 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display3((oldIndex >>> 15) & 31) = display2 + display4((oldIndex >>> 20) & 31) = display3 + display5((oldIndex >>> 25) & 31) = display4 + display4 = nullSlotAndCopy(display5, (newIndex >>> 25) & 31) + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else { // level = 6 throw new IllegalArgumentException() } } @@ -1116,117 +1030,83 @@ private[immutable] trait VectorPointer[T] { private[immutable] final def copyRange(array: Array[AnyRef], oldLeft: Int, newLeft: Int) = { val elems = new Array[AnyRef](32) - Platform.arraycopy(array, oldLeft, elems, newLeft, 32 - math.max(newLeft,oldLeft)) + java.lang.System.arraycopy(array, oldLeft, elems, newLeft, 32 - math.max(newLeft, oldLeft)) elems } - - // USED IN APPEND // create a new block at the bottom level (and possibly nodes on its path) and prepares for writing // requires structure is clean and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 private[immutable] final def gotoFreshPosWritable0(oldIndex: Int, newIndex: Int, xor: Int): Unit = { // goto block start pos - if (xor < (1 << 5)) { // level = 0 - //println("XXX clean with low xor") - } else - if (xor < (1 << 10)) { // level = 1 + if (xor < (1 << 5)) { // level = 0 + // we're already at the block start + } else if (xor < (1 << 10)) { // level = 1 if (depth == 1) { display1 = new Array(32) - display1((oldIndex >> 5) & 31) = display0 - depth +=1 + display1((oldIndex >>> 5) & 31) = display0 + depth += 1 } display0 = new Array(32) - } else - if (xor < (1 << 15)) { // level = 2 + } else if (xor < (1 << 15)) { // level = 2 if (depth == 2) { display2 = new Array(32) - display2((oldIndex >> 10) & 31) = display1 - depth +=1 + display2((oldIndex >>> 10) & 31) = display1 + depth += 1 } - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else - if (xor < (1 << 20)) { // level = 3 + } else if (xor < (1 << 20)) { // level = 3 if (depth == 3) { display3 = new Array(32) - display3((oldIndex >> 15) & 31) = display2 - depth +=1 + display3((oldIndex >>> 15) & 31) = display2 + depth += 1 } - display2 = display3((newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((newIndex >>> 15) & 31).asInstanceOf[Array[AnyRef]] if (display2 == null) display2 = new Array(32) - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else - if (xor < (1 << 25)) { // level = 4 + } else if (xor < (1 << 25)) { // level = 4 if (depth == 4) { display4 = new Array(32) - display4((oldIndex >> 20) & 31) = display3 - depth +=1 + display4((oldIndex >>> 20) & 31) = display3 + depth += 1 } - display3 = display4((newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] + display3 = display4((newIndex >>> 20) & 31).asInstanceOf[Array[AnyRef]] if (display3 == null) display3 = new Array(32) - display2 = display3((newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((newIndex >>> 15) & 31).asInstanceOf[Array[AnyRef]] if (display2 == null) display2 = new Array(32) - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else - if (xor < (1 << 30)) { // level = 5 + } else if (xor < (1 << 30)) { // level = 5 if (depth == 5) { display5 = new Array(32) - display5((oldIndex >> 25) & 31) = display4 - depth +=1 + display5((oldIndex >>> 25) & 31) = display4 + depth += 1 } - display4 = display5((newIndex >> 25) & 31).asInstanceOf[Array[AnyRef]] + display4 = display5((newIndex >>> 25) & 31).asInstanceOf[Array[AnyRef]] if (display4 == null) display4 = new Array(32) - display3 = display4((newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] + display3 = display4((newIndex >>> 20) & 31).asInstanceOf[Array[AnyRef]] if (display3 == null) display3 = new Array(32) - display2 = display3((newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((newIndex >>> 15) & 31).asInstanceOf[Array[AnyRef]] if (display2 == null) display2 = new Array(32) - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else { // level = 6 + } else { // level = 6 throw new IllegalArgumentException() } } - // requires structure is dirty and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 private[immutable] final def gotoFreshPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { stabilize(oldIndex) gotoFreshPosWritable0(oldIndex, newIndex, xor) } - - - - - // DEBUG STUFF - - private[immutable] def debug(): Unit = { - return -/* - //println("DISPLAY 5: " + display5 + " ---> " + (if (display5 ne null) display5.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 4: " + display4 + " ---> " + (if (display4 ne null) display4.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 3: " + display3 + " ---> " + (if (display3 ne null) display3.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 2: " + display2 + " ---> " + (if (display2 ne null) display2.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 1: " + display1 + " ---> " + (if (display1 ne null) display1.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 0: " + display0 + " ---> " + (if (display0 ne null) display0.map(x=> if (x eq null) "." else x.toString).mkString(" ") else "null")) -*/ - //println("DISPLAY 5: " + (if (display5 ne null) display5.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 4: " + (if (display4 ne null) display4.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 3: " + (if (display3 ne null) display3.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 2: " + (if (display2 ne null) display2.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 1: " + (if (display1 ne null) display1.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 0: " + (if (display0 ne null) display0.map(x=> if (x eq null) "." else x.toString).mkString(" ") else "null")) - } - - } - diff --git a/src/library/scala/collection/immutable/WrappedString.scala b/src/library/scala/collection/immutable/WrappedString.scala index 7592316650..8726bd2ed9 100644 --- a/src/library/scala/collection/immutable/WrappedString.scala +++ b/src/library/scala/collection/immutable/WrappedString.scala @@ -29,8 +29,7 @@ import mutable.{Builder, StringBuilder} * @define Coll `WrappedString` * @define coll wrapped string */ -@deprecatedInheritance("Inherit from StringLike instead of WrappedString.", "2.11.0") -class WrappedString(val self: String) extends AbstractSeq[Char] with IndexedSeq[Char] with StringLike[WrappedString] { +final class WrappedString(val self: String) extends AbstractSeq[Char] with IndexedSeq[Char] with StringLike[WrappedString] { override protected[this] def thisCollection: WrappedString = this override protected[this] def toCollection(repr: WrappedString): WrappedString = repr diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala deleted file mode 100644 index b63d0aae33..0000000000 --- a/src/library/scala/collection/mutable/AVLTree.scala +++ /dev/null @@ -1,250 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala -package collection -package mutable - -/** - * An immutable AVL Tree implementation formerly used by mutable.TreeSet - * - * @author Lucien Pereira - */ -@deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.2") -private[mutable] sealed trait AVLTree[+A] extends Serializable { - def balance: Int - - def depth: Int - - def iterator[B >: A]: Iterator[B] = Iterator.empty - - def contains[B >: A](value: B, ordering: Ordering[B]): Boolean = false - - /** - * Returns a new tree containing the given element. - * Throws an IllegalArgumentException if element is already present. - * - */ - def insert[B >: A](value: B, ordering: Ordering[B]): AVLTree[B] = Node(value, Leaf, Leaf) - - /** - * Return a new tree which not contains given element. - * - */ - def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] = - throw new NoSuchElementException(String.valueOf(value)) - - /** - * Return a tuple containing the smallest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - def removeMin[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.") - - /** - * Return a tuple containing the biggest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - def removeMax[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.") - - def rebalance[B >: A]: AVLTree[B] = this - - def leftRotation[B >: A]: Node[B] = sys.error("Should not happen.") - - def rightRotation[B >: A]: Node[B] = sys.error("Should not happen.") - - def doubleLeftRotation[B >: A]: Node[B] = sys.error("Should not happen.") - - def doubleRightRotation[B >: A]: Node[B] = sys.error("Should not happen.") -} - -/** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") - */ -private case object Leaf extends AVLTree[Nothing] { - override val balance: Int = 0 - - override val depth: Int = -1 -} - -/** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") - */ -private case class Node[A](data: A, left: AVLTree[A], right: AVLTree[A]) extends AVLTree[A] { - override val balance: Int = right.depth - left.depth - - override val depth: Int = math.max(left.depth, right.depth) + 1 - - override def iterator[B >: A]: Iterator[B] = new AVLIterator(this) - - override def contains[B >: A](value: B, ordering: Ordering[B]) = { - val ord = ordering.compare(value, data) - if (0 == ord) - true - else if (ord < 0) - left.contains(value, ordering) - else - right.contains(value, ordering) - } - - /** - * Returns a new tree containing the given element. - * Throws an IllegalArgumentException if element is already present. - * - */ - override def insert[B >: A](value: B, ordering: Ordering[B]) = { - val ord = ordering.compare(value, data) - if (0 == ord) - throw new IllegalArgumentException() - else if (ord < 0) - Node(data, left.insert(value, ordering), right).rebalance - else - Node(data, left, right.insert(value, ordering)).rebalance - } - - /** - * Return a new tree which not contains given element. - * - */ - override def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] = { - val ord = ordering.compare(value, data) - if(ord == 0) { - if (Leaf == left) { - if (Leaf == right) { - Leaf - } else { - val (min, newRight) = right.removeMin - Node(min, left, newRight).rebalance - } - } else { - val (max, newLeft) = left.removeMax - Node(max, newLeft, right).rebalance - } - } else if (ord < 0) { - Node(data, left.remove(value, ordering), right).rebalance - } else { - Node(data, left, right.remove(value, ordering)).rebalance - } - } - - /** - * Return a tuple containing the smallest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - override def removeMin[B >: A]: (B, AVLTree[B]) = { - if (Leaf == left) - (data, right) - else { - val (min, newLeft) = left.removeMin - (min, Node(data, newLeft, right).rebalance) - } - } - - /** - * Return a tuple containing the biggest element of the provided tree - * and a new tree from which this element has been extracted. - * - */ - override def removeMax[B >: A]: (B, AVLTree[B]) = { - if (Leaf == right) - (data, left) - else { - val (max, newRight) = right.removeMax - (max, Node(data, left, newRight).rebalance) - } - } - - override def rebalance[B >: A] = { - if (-2 == balance) { - if (1 == left.balance) - doubleRightRotation - else - rightRotation - } else if (2 == balance) { - if (-1 == right.balance) - doubleLeftRotation - else - leftRotation - } else { - this - } - } - - override def leftRotation[B >: A] = { - if (Leaf != right) { - val r: Node[A] = right.asInstanceOf[Node[A]] - Node(r.data, Node(data, left, r.left), r.right) - } else sys.error("Should not happen.") - } - - override def rightRotation[B >: A] = { - if (Leaf != left) { - val l: Node[A] = left.asInstanceOf[Node[A]] - Node(l.data, l.left, Node(data, l.right, right)) - } else sys.error("Should not happen.") - } - - override def doubleLeftRotation[B >: A] = { - if (Leaf != right) { - val r: Node[A] = right.asInstanceOf[Node[A]] - // Let's save an instanceOf by 'inlining' the left rotation - val rightRotated = r.rightRotation - Node(rightRotated.data, Node(data, left, rightRotated.left), rightRotated.right) - } else sys.error("Should not happen.") - } - - override def doubleRightRotation[B >: A] = { - if (Leaf != left) { - val l: Node[A] = left.asInstanceOf[Node[A]] - // Let's save an instanceOf by 'inlining' the right rotation - val leftRotated = l.leftRotation - Node(leftRotated.data, leftRotated.left, Node(data, leftRotated.right, right)) - } else sys.error("Should not happen.") - } -} - -/** - * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0") - */ -private class AVLIterator[A](root: Node[A]) extends Iterator[A] { - val stack = mutable.ArrayStack[Node[A]](root) - diveLeft() - - private def diveLeft(): Unit = { - if (Leaf != stack.head.left) { - val left: Node[A] = stack.head.left.asInstanceOf[Node[A]] - stack.push(left) - diveLeft() - } - } - - private def engageRight(): Unit = { - if (Leaf != stack.head.right) { - val right: Node[A] = stack.head.right.asInstanceOf[Node[A]] - stack.pop() - stack.push(right) - diveLeft() - } else - stack.pop() - } - - override def hasNext: Boolean = !stack.isEmpty - - override def next(): A = { - if (stack.isEmpty) - throw new NoSuchElementException() - else { - val result = stack.head.data - // Let's maintain stack for the next invocation - engageRight() - result - } - } -} diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index 369d596ec3..6ff79dd1b8 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -27,10 +27,12 @@ import generic.CanBuildFrom * rapidly as 2^30^ is approached. * */ +@SerialVersionUID(1L) final class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initialBufferSize: Int, initBlank: Boolean) extends AbstractMap[K, V] with Map[K, V] with MapLike[K, V, AnyRefMap[K, V]] + with Serializable { import AnyRefMap._ def this() = this(AnyRefMap.exceptionDefault, 16, true) @@ -335,6 +337,24 @@ extends AbstractMap[K, V] arm } + override def +[V1 >: V](kv: (K, V1)): AnyRefMap[K, V1] = { + val arm = clone().asInstanceOf[AnyRefMap[K, V1]] + arm += kv + arm + } + + override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): AnyRefMap[K, V1] = { + val arm = clone().asInstanceOf[AnyRefMap[K, V1]] + xs.foreach(kv => arm += kv) + arm + } + + override def updated[V1 >: V](key: K, value: V1): AnyRefMap[K, V1] = { + val arm = clone().asInstanceOf[AnyRefMap[K, V1]] + arm += (key, value) + arm + } + private[this] def foreachElement[A,B](elems: Array[AnyRef], f: A => B) { var i,j = 0 while (i < _hashes.length & j < _size) { @@ -399,7 +419,11 @@ object AnyRefMap { private final val VacantBit = 0x40000000 private final val MissVacant = 0xC0000000 - private val exceptionDefault = (k: Any) => throw new NoSuchElementException(if (k == null) "(null)" else k.toString) + @SerialVersionUID(1L) + private class ExceptionDefault extends (Any => Nothing) with Serializable { + def apply(k: Any): Nothing = throw new NoSuchElementException(if (k == null) "(null)" else k.toString) + } + private val exceptionDefault = new ExceptionDefault implicit def canBuildFrom[K <: AnyRef, V, J <: AnyRef, U]: CanBuildFrom[AnyRefMap[K,V], (J, U), AnyRefMap[J,U]] = new CanBuildFrom[AnyRefMap[K,V], (J, U), AnyRefMap[J,U]] { @@ -407,7 +431,11 @@ object AnyRefMap { def apply(): AnyRefMapBuilder[J, U] = new AnyRefMapBuilder[J, U] } - final class AnyRefMapBuilder[K <: AnyRef, V] extends Builder[(K, V), AnyRefMap[K, V]] { + /** A builder for instances of `AnyRefMap`. + * + * This builder can be reused to create multiple instances. + */ + final class AnyRefMapBuilder[K <: AnyRef, V] extends ReusableBuilder[(K, V), AnyRefMap[K, V]] { private[collection] var elems: AnyRefMap[K, V] = new AnyRefMap[K, V] def +=(entry: (K, V)): this.type = { elems += entry diff --git a/src/library/scala/collection/mutable/ArrayBuffer.scala b/src/library/scala/collection/mutable/ArrayBuffer.scala index 011fd415ee..23d386f729 100644 --- a/src/library/scala/collection/mutable/ArrayBuffer.scala +++ b/src/library/scala/collection/mutable/ArrayBuffer.scala @@ -67,7 +67,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) override def sizeHint(len: Int) { if (len > size && len >= 1) { val newarray = new Array[AnyRef](len) - scala.compat.Platform.arraycopy(array, 0, newarray, 0, size0) + java.lang.System.arraycopy(array, 0, newarray, 0, size0) array = newarray } } @@ -149,13 +149,16 @@ class ArrayBuffer[A](override protected val initialSize: Int) /** Removes the element on a given index position. It takes time linear in * the buffer size. * - * @param n the index which refers to the first element to delete. - * @param count the number of elements to delete - * @throws IndexOutOfBoundsException if `n` is out of bounds. + * @param n the index which refers to the first element to remove. + * @param count the number of elements to remove. + * @throws IndexOutOfBoundsException if the index `n` is not in the valid range + * `0 <= n <= length - count` (with `count > 0`). + * @throws IllegalArgumentException if `count < 0`. */ override def remove(n: Int, count: Int) { - require(count >= 0, "removing negative number of elements") - if (n < 0 || n > size0 - count) throw new IndexOutOfBoundsException(n.toString) + if (count < 0) throw new IllegalArgumentException("removing negative number of elements: " + count.toString) + else if (count == 0) return // Did nothing + if (n < 0 || n > size0 - count) throw new IndexOutOfBoundsException("at " + n.toString + " deleting " + count.toString) copy(n + count, n, size0 - (n + count)) reduceToSize(size0 - count) } diff --git a/src/library/scala/collection/mutable/ArrayBuilder.scala b/src/library/scala/collection/mutable/ArrayBuilder.scala index f4ca27dcba..d023110c1b 100644 --- a/src/library/scala/collection/mutable/ArrayBuilder.scala +++ b/src/library/scala/collection/mutable/ArrayBuilder.scala @@ -11,7 +11,6 @@ package collection package mutable import scala.reflect.ClassTag -import scala.runtime.ScalaRunTime /** A builder class for arrays. * @@ -19,7 +18,7 @@ import scala.runtime.ScalaRunTime * * @tparam T the type of the elements for the builder. */ -abstract class ArrayBuilder[T] extends Builder[T, Array[T]] with Serializable +abstract class ArrayBuilder[T] extends ReusableBuilder[T, Array[T]] with Serializable /** A companion object for array builders. * @@ -50,10 +49,11 @@ object ArrayBuilder { /** A class for array builders for arrays of reference types. * + * This builder can be reused. + * * @tparam T type of elements for the array builder, subtype of `AnyRef` with a `ClassTag` context bound. */ - @deprecatedInheritance("ArrayBuilder.ofRef is an internal implementation not intended for subclassing.", "2.11.0") - class ofRef[T <: AnyRef : ClassTag] extends ArrayBuilder[T] { + final class ofRef[T <: AnyRef : ClassTag] extends ArrayBuilder[T] { private var elems: Array[T] = _ private var capacity: Int = 0 @@ -99,9 +99,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -119,9 +117,8 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofRef" } - /** A class for array builders for arrays of `byte`s. */ - @deprecatedInheritance("ArrayBuilder.ofByte is an internal implementation not intended for subclassing.", "2.11.0") - class ofByte extends ArrayBuilder[Byte] { + /** A class for array builders for arrays of `byte`s. It can be reused. */ + final class ofByte extends ArrayBuilder[Byte] { private var elems: Array[Byte] = _ private var capacity: Int = 0 @@ -167,9 +164,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -187,9 +182,8 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofByte" } - /** A class for array builders for arrays of `short`s. */ - @deprecatedInheritance("ArrayBuilder.ofShort is an internal implementation not intended for subclassing.", "2.11.0") - class ofShort extends ArrayBuilder[Short] { + /** A class for array builders for arrays of `short`s. It can be reused. */ + final class ofShort extends ArrayBuilder[Short] { private var elems: Array[Short] = _ private var capacity: Int = 0 @@ -235,9 +229,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -255,9 +247,8 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofShort" } - /** A class for array builders for arrays of `char`s. */ - @deprecatedInheritance("ArrayBuilder.ofChar is an internal implementation not intended for subclassing.", "2.11.0") - class ofChar extends ArrayBuilder[Char] { + /** A class for array builders for arrays of `char`s. It can be reused. */ + final class ofChar extends ArrayBuilder[Char] { private var elems: Array[Char] = _ private var capacity: Int = 0 @@ -303,9 +294,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -323,9 +312,8 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofChar" } - /** A class for array builders for arrays of `int`s. */ - @deprecatedInheritance("ArrayBuilder.ofInt is an internal implementation not intended for subclassing.", "2.11.0") - class ofInt extends ArrayBuilder[Int] { + /** A class for array builders for arrays of `int`s. It can be reused. */ + final class ofInt extends ArrayBuilder[Int] { private var elems: Array[Int] = _ private var capacity: Int = 0 @@ -371,9 +359,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -391,9 +377,8 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofInt" } - /** A class for array builders for arrays of `long`s. */ - @deprecatedInheritance("ArrayBuilder.ofLong is an internal implementation not intended for subclassing.", "2.11.0") - class ofLong extends ArrayBuilder[Long] { + /** A class for array builders for arrays of `long`s. It can be reused. */ + final class ofLong extends ArrayBuilder[Long] { private var elems: Array[Long] = _ private var capacity: Int = 0 @@ -439,9 +424,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -459,9 +442,8 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofLong" } - /** A class for array builders for arrays of `float`s. */ - @deprecatedInheritance("ArrayBuilder.ofFloat is an internal implementation not intended for subclassing.", "2.11.0") - class ofFloat extends ArrayBuilder[Float] { + /** A class for array builders for arrays of `float`s. It can be reused. */ + final class ofFloat extends ArrayBuilder[Float] { private var elems: Array[Float] = _ private var capacity: Int = 0 @@ -507,9 +489,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -527,9 +507,8 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofFloat" } - /** A class for array builders for arrays of `double`s. */ - @deprecatedInheritance("ArrayBuilder.ofDouble is an internal implementation not intended for subclassing.", "2.11.0") - class ofDouble extends ArrayBuilder[Double] { + /** A class for array builders for arrays of `double`s. It can be reused. */ + final class ofDouble extends ArrayBuilder[Double] { private var elems: Array[Double] = _ private var capacity: Int = 0 @@ -575,9 +554,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -595,7 +572,7 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofDouble" } - /** A class for array builders for arrays of `boolean`s. */ + /** A class for array builders for arrays of `boolean`s. It can be reused. */ class ofBoolean extends ArrayBuilder[Boolean] { private var elems: Array[Boolean] = _ @@ -642,9 +619,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -662,68 +637,32 @@ object ArrayBuilder { override def toString = "ArrayBuilder.ofBoolean" } - /** A class for array builders for arrays of `Unit` type. */ - @deprecatedInheritance("ArrayBuilder.ofUnit is an internal implementation not intended for subclassing.", "2.11.0") - class ofUnit extends ArrayBuilder[Unit] { + /** A class for array builders for arrays of `Unit` type. It can be reused. */ + final class ofUnit extends ArrayBuilder[Unit] { - private var elems: Array[Unit] = _ - private var capacity: Int = 0 private var size: Int = 0 - private def mkArray(size: Int): Array[Unit] = { - val newelems = new Array[Unit](size) - if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size) - newelems - } - - private def resize(size: Int) { - elems = mkArray(size) - capacity = size - } - - override def sizeHint(size: Int) { - if (capacity < size) resize(size) - } - - private def ensureSize(size: Int) { - if (capacity < size || capacity == 0) { - var newsize = if (capacity == 0) 16 else capacity * 2 - while (newsize < size) newsize *= 2 - resize(newsize) - } - } - def +=(elem: Unit): this.type = { - ensureSize(size + 1) - elems(size) = elem size += 1 this } - override def ++=(xs: TraversableOnce[Unit]): this.type = xs match { - case xs: WrappedArray.ofUnit => - ensureSize(this.size + xs.length) - Array.copy(xs.array, 0, elems, this.size, xs.length) - size += xs.length - this - case _ => - super.++=(xs) + override def ++=(xs: TraversableOnce[Unit]): this.type = { + size += xs.size + this } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { - if (capacity != 0 && capacity == size) { - capacity = 0 - elems - } - else mkArray(size) + val ans = new Array[Unit](size) + var i = 0 + while (i < size) { ans(i) = (); i += 1 } + ans } override def equals(other: Any): Boolean = other match { - case x: ofUnit => (size == x.size) && (elems == x.elems) + case x: ofUnit => (size == x.size) case _ => false } diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 00491ef20e..0f83fd92c1 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -10,9 +10,7 @@ package scala package collection package mutable -import scala.compat.Platform.arraycopy import scala.reflect.ClassTag -import scala.runtime.ScalaRunTime._ import parallel.mutable.ParArray /** This class serves as a wrapper for `Array`s with all the operations found in @@ -33,20 +31,29 @@ import parallel.mutable.ParArray * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecatedInheritance("ArrayOps will be sealed to facilitate greater flexibility with array/collections integration in future releases.", "2.11.0") -trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] { +sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] { private def elementClass: Class[_] = - arrayElementClass(repr.getClass) + repr.getClass.getComponentType override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) { - var l = math.min(len, repr.length) - if (xs.length - start < l) l = xs.length - start max 0 - Array.copy(repr, 0, xs, start, l) + val l = len min repr.length min (xs.length - start) + if (l > 0) Array.copy(repr, 0, xs, start, l) + } + + override def slice(from: Int, until: Int): Array[T] = { + val lo = math.max(from, 0) + val hi = math.min(math.max(until, 0), repr.length) + val size = math.max(hi - lo, 0) + val result = java.lang.reflect.Array.newInstance(elementClass, size) + if (size > 0) { + Array.copy(repr, lo, result, 0, size) + } + result.asInstanceOf[Array[T]] } override def toArray[U >: T : ClassTag]: Array[U] = { - val thatElementClass = arrayElementClass(implicitly[ClassTag[U]]) + val thatElementClass = implicitly[ClassTag[U]].runtimeClass if (elementClass eq thatElementClass) repr.asInstanceOf[Array[U]] else @@ -94,7 +101,7 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza val bb: Builder[Array[U], Array[Array[U]]] = Array.newBuilder(ClassTag[Array[U]](elementClass)) if (isEmpty) bb.result() else { - def mkRowBuilder() = Array.newBuilder(ClassTag[U](arrayElementClass(elementClass))) + def mkRowBuilder() = Array.newBuilder(ClassTag[U](elementClass.getComponentType)) val bs = asArray(head) map (_ => mkRowBuilder()) for (xs <- this) { var i = 0 @@ -107,9 +114,9 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza bb.result() } } - + /** Converts an array of pairs into an array of first elements and an array of second elements. - * + * * @tparam T1 the type of the first half of the element pairs * @tparam T2 the type of the second half of the element pairs * @param asPair an implicit conversion which asserts that the element type @@ -135,9 +142,9 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza } (a1, a2) } - + /** Converts an array of triples into three arrays, one containing the elements from each position of the triple. - * + * * @tparam T1 the type of the first of three elements in the triple * @tparam T2 the type of the second of three elements in the triple * @tparam T3 the type of the third of three elements in the triple @@ -169,10 +176,8 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza } (a1, a2, a3) } - def seq = thisCollection - } /** @@ -187,15 +192,15 @@ object ArrayOps { override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr) override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr) - override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](arrayElementClass(repr.getClass))) + override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](repr.getClass.getComponentType)) def length: Int = repr.length def apply(index: Int): T = repr(index) def update(index: Int, elem: T) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `byte`s. */ -final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { + /** A subclass of `ArrayOps` for arrays containing `Byte`s. */ + final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr) @@ -206,8 +211,8 @@ final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Byte) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `short`s. */ -final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { + /** A subclass of `ArrayOps` for arrays containing `Short`s. */ + final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr) @@ -218,8 +223,8 @@ final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOp def update(index: Int, elem: Short) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `char`s. */ -final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { + /** A subclass of `ArrayOps` for arrays containing `Char`s. */ + final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr) @@ -230,8 +235,8 @@ final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Char) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `int`s. */ -final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { + /** A subclass of `ArrayOps` for arrays containing `Int`s. */ + final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr) @@ -242,8 +247,8 @@ final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[In def update(index: Int, elem: Int) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `long`s. */ -final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { + /** A subclass of `ArrayOps` for arrays containing `Long`s. */ + final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr) @@ -254,8 +259,8 @@ final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Long) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `float`s. */ -final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { + /** A subclass of `ArrayOps` for arrays containing `Float`s. */ + final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr) @@ -266,8 +271,8 @@ final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOp def update(index: Int, elem: Float) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `double`s. */ -final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { + /** A subclass of `ArrayOps` for arrays containing `Double`s. */ + final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr) @@ -278,8 +283,8 @@ final class ofDouble(override val repr: Array[Double]) extends AnyVal with Array def update(index: Int, elem: Double) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `boolean`s. */ -final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { + /** A subclass of `ArrayOps` for arrays containing `Boolean`s. */ + final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) @@ -290,8 +295,8 @@ final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with Arr def update(index: Int, elem: Boolean) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays of `Unit` types. */ -final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { + /** A subclass of `ArrayOps` for arrays of `Unit` types. */ + final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr) diff --git a/src/library/scala/collection/mutable/ArraySeq.scala b/src/library/scala/collection/mutable/ArraySeq.scala index ddb48627af..1e82096baf 100644 --- a/src/library/scala/collection/mutable/ArraySeq.scala +++ b/src/library/scala/collection/mutable/ArraySeq.scala @@ -87,7 +87,7 @@ extends AbstractSeq[A] */ override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) { val len1 = len min (xs.length - start) min length - Array.copy(array, 0, xs, start, len1) + if (len1 > 0) Array.copy(array, 0, xs, start, len1) } override def clone(): ArraySeq[A] = { diff --git a/src/library/scala/collection/mutable/ArrayStack.scala b/src/library/scala/collection/mutable/ArrayStack.scala index 8ff128c026..951a90b084 100644 --- a/src/library/scala/collection/mutable/ArrayStack.scala +++ b/src/library/scala/collection/mutable/ArrayStack.scala @@ -64,9 +64,10 @@ object ArrayStack extends SeqFactory[ArrayStack] { class ArrayStack[T] private(private var table : Array[AnyRef], private var index : Int) extends AbstractSeq[T] - with Seq[T] - with SeqLike[T, ArrayStack[T]] + with IndexedSeq[T] + with IndexedSeqLike[T, ArrayStack[T]] with GenericTraversableTemplate[T, ArrayStack] + with IndexedSeqOptimized[T, ArrayStack[T]] with Cloneable[ArrayStack[T]] with Builder[T, ArrayStack[T]] with Serializable @@ -224,7 +225,7 @@ extends AbstractSeq[T] /** Creates and iterator over the stack in LIFO order. * @return an iterator over the elements of the stack. */ - def iterator: Iterator[T] = new AbstractIterator[T] { + override def iterator: Iterator[T] = new AbstractIterator[T] { var currentIndex = index def hasNext = currentIndex > 0 def next() = { diff --git a/src/library/scala/collection/mutable/BitSet.scala b/src/library/scala/collection/mutable/BitSet.scala index e92d48cfeb..e74ee65dda 100644 --- a/src/library/scala/collection/mutable/BitSet.scala +++ b/src/library/scala/collection/mutable/BitSet.scala @@ -13,7 +13,7 @@ package collection package mutable import generic._ -import BitSetLike.{LogWL, MaxSize, updateArray} +import BitSetLike.{LogWL, MaxSize} /** A class for mutable bitsets. * @@ -56,7 +56,7 @@ class BitSet(protected final var elems: Array[Long]) extends AbstractSet[Int] @deprecatedOverriding("Internal implementation does not admit sensible overriding of this method.", "2.11.0") protected def nwords = elems.length - + @deprecatedOverriding("Internal implementation does not admit sensible overriding of this method.", "2.11.0") protected def word(idx: Int): Long = if (idx < nwords) elems(idx) else 0L @@ -100,7 +100,7 @@ class BitSet(protected final var elems: Array[Long]) extends AbstractSet[Int] @deprecatedOverriding("Override add to prevent += and add from exhibiting different behavior.", "2.11.0") def += (elem: Int): this.type = { add(elem); this } - + @deprecatedOverriding("Override add to prevent += and add from exhibiting different behavior.", "2.11.0") def -= (elem: Int): this.type = { remove(elem); this } @@ -164,7 +164,7 @@ class BitSet(protected final var elems: Array[Long]) extends AbstractSet[Int] */ @deprecated("If this BitSet contains a value that is 128 or greater, the result of this method is an 'immutable' " + "BitSet that shares state with this mutable BitSet. Thus, if the mutable BitSet is modified, it will violate the " + - "immutability of the result.", "2.11.6") + "immutability of the result.", "2.12.0") def toImmutable = immutable.BitSet.fromBitMaskNoCopy(elems) override def clone(): BitSet = { diff --git a/src/library/scala/collection/mutable/BufferLike.scala b/src/library/scala/collection/mutable/BufferLike.scala index 3c57387c03..c78d59297b 100644 --- a/src/library/scala/collection/mutable/BufferLike.scala +++ b/src/library/scala/collection/mutable/BufferLike.scala @@ -14,7 +14,7 @@ package mutable import generic._ import script._ -import scala.annotation.{migration, bridge} +import scala.annotation.migration /** A template trait for buffers of type `Buffer[A]`. * @@ -105,15 +105,18 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] */ def remove(n: Int): A - /** Removes a number of elements from a given index position. + /** Removes a number of elements from a given index position. Subclasses of `BufferLike` + * will typically override this method to provide better performance than `count` + * successive calls to single-element `remove`. * * @param n the index which refers to the first element to remove. * @param count the number of elements to remove. * @throws IndexOutOfBoundsException if the index `n` is not in the valid range - * `0 <= n <= length - count`. + * `0 <= n <= length - count` (with `count > 0`). * @throws IllegalArgumentException if `count < 0`. */ def remove(n: Int, count: Int) { + if (count < 0) throw new IllegalArgumentException("removing negative number of elements: " + count.toString) for (i <- 0 until count) remove(n) } @@ -184,7 +187,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] * * @param cmd the message to send. */ - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") def <<(cmd: Message[A]): Unit = cmd match { case Include(Start, x) => prepend(x) case Include(End, x) => append(x) @@ -211,13 +214,6 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] */ override def stringPrefix: String = "Buffer" - /** Returns the current evolving(!) state of this buffer as a read-only sequence. - * - * @return A sequence that forwards to this buffer for all its operations. - */ - @deprecated("The returned sequence changes as this buffer is mutated. For an immutable copy, use, e.g., toList.", "2.11.0") - def readOnly: scala.collection.Seq[A] = toSeq - /** Creates a new collection containing both the elements of this collection and the provided * traversable object. * diff --git a/src/library/scala/collection/mutable/BufferProxy.scala b/src/library/scala/collection/mutable/BufferProxy.scala index d9632cce91..60f0e29746 100644 --- a/src/library/scala/collection/mutable/BufferProxy.scala +++ b/src/library/scala/collection/mutable/BufferProxy.scala @@ -26,7 +26,7 @@ import script._ * @define Coll `BufferProxy` * @define coll buffer proxy */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait BufferProxy[A] extends Buffer[A] with Proxy { def self: Buffer[A] @@ -43,8 +43,6 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { */ def +=(elem: A): this.type = { self.+=(elem); this } - override def readOnly = self.readOnly - /** Appends a number of elements provided by a traversable object. * * @param xs the traversable object. @@ -132,7 +130,7 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { * * @param cmd the message to send. */ - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") override def <<(cmd: Message[A]) { self << cmd } /** Return a clone of this buffer. diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala index 75560580cc..528f78bd98 100644 --- a/src/library/scala/collection/mutable/Builder.scala +++ b/src/library/scala/collection/mutable/Builder.scala @@ -18,6 +18,14 @@ import generic._ * elements to the builder with `+=` and then converting to the required * collection type with `result`. * + * One cannot assume that a single `Builder` can build more than one + * instance of the desired collection. Particular subclasses may allow + * such behavior. Otherwise, `result` should be treated as a terminal + * operation: after it is called, no further methods should be called on + * the builder. Extend the [[collection.mutable.ReusableBuilder]] trait + * instead of `Builder` for builders that may be reused to build multiple + * instances. + * * @tparam Elem the type of elements that get added to the builder. * @tparam To the type of collection that it produced. * @@ -36,8 +44,10 @@ trait Builder[-Elem, +To] extends Growable[Elem] { */ def clear() - /** Produces a collection from the added elements. - * The builder's contents are undefined after this operation. + /** Produces a collection from the added elements. This is a terminal operation: + * the builder's contents are undefined after this operation, and no further + * methods should be called. + * * @return a collection containing the elements added to this builder. */ def result(): To @@ -55,18 +65,18 @@ trait Builder[-Elem, +To] extends Growable[Elem] { /** Gives a hint that one expects the `result` of this builder * to have the same size as the given collection, plus some delta. This will * provide a hint only if the collection is known to have a cheap - * `size` method. Currently this is assumed to be the case if and only if - * the collection is of type `IndexedSeqLike`. - * Some builder classes - * will optimize their representation based on the hint. However, + * `size` method, which is determined by calling `sizeHint`. + * + * Some builder classes will optimize their representation based on the hint. However, * builder implementations are still required to work correctly even if the hint is * wrong, i.e. a different number of elements is added. * * @param coll the collection which serves as a hint for the result's size. */ def sizeHint(coll: TraversableLike[_, _]) { - if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) { - sizeHint(coll.size) + coll.sizeHintIfCheap match { + case -1 => + case n => sizeHint(n) } } @@ -84,8 +94,9 @@ trait Builder[-Elem, +To] extends Growable[Elem] { * @param delta a correction to add to the `coll.size` to produce the size hint. */ def sizeHint(coll: TraversableLike[_, _], delta: Int) { - if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) { - sizeHint(coll.size + delta) + coll.sizeHintIfCheap match { + case -1 => + case n => sizeHint(n + delta) } } @@ -102,8 +113,10 @@ trait Builder[-Elem, +To] extends Growable[Elem] { * than collection's size are reduced. */ def sizeHintBounded(size: Int, boundingColl: TraversableLike[_, _]) { - if (boundingColl.isInstanceOf[collection.IndexedSeqLike[_,_]]) - sizeHint(size min boundingColl.size) + boundingColl.sizeHintIfCheap match { + case -1 => + case n => sizeHint(size min n) + } } /** Creates a new builder by applying a transformation function to @@ -112,6 +125,8 @@ trait Builder[-Elem, +To] extends Growable[Elem] { * @tparam NewTo the type of collection returned by `f`. * @return a new builder which is the same as the current builder except * that a transformation function is applied to this builder's result. + * + * @note The original builder should no longer be used after `mapResult` is called. */ def mapResult[NewTo](f: To => NewTo): Builder[Elem, NewTo] = new Builder[Elem, NewTo] with Proxy { diff --git a/src/library/scala/collection/mutable/DefaultMapModel.scala b/src/library/scala/collection/mutable/DefaultMapModel.scala index 0088620540..7f832c0766 100644 --- a/src/library/scala/collection/mutable/DefaultMapModel.scala +++ b/src/library/scala/collection/mutable/DefaultMapModel.scala @@ -19,7 +19,7 @@ package mutable * @version 1.0, 08/07/2003 * @since 1 */ -@deprecated("This trait will be removed.", "2.11.0") +@deprecated("this trait will be removed", "2.11.0") trait DefaultMapModel[A, B] extends Map[A, B] { type Entry = DefaultEntry[A, B] diff --git a/src/library/scala/collection/mutable/DoubleLinkedList.scala b/src/library/scala/collection/mutable/DoubleLinkedList.scala index fd95e74fbc..537cebd903 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedList.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedList.scala @@ -41,7 +41,7 @@ import generic._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") @SerialVersionUID(-8144992287952814767L) class DoubleLinkedList[A]() extends AbstractSeq[A] with LinearSeq[A] @@ -78,7 +78,7 @@ class DoubleLinkedList[A]() extends AbstractSeq[A] * @define coll double linked list * @define Coll `DoubleLinkedList` */ -@deprecated("Low-level linked lists are deprecated.", "2.11.0") +@deprecated("low-level linked lists are deprecated", "2.11.0") object DoubleLinkedList extends SeqFactory[DoubleLinkedList] { /** $genericCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, DoubleLinkedList[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] diff --git a/src/library/scala/collection/mutable/DoubleLinkedListLike.scala b/src/library/scala/collection/mutable/DoubleLinkedListLike.scala index aafe34f50a..e85ef05319 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedListLike.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedListLike.scala @@ -56,7 +56,7 @@ import scala.annotation.migration * @define Coll `DoubleLinkedList` * @define coll double linked list */ -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") trait DoubleLinkedListLike[A, This <: Seq[A] with DoubleLinkedListLike[A, This]] extends SeqLike[A, This] with LinkedListLike[A, This] { self => /** A reference to the node in the linked list preceding the current node. */ diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 8c4115b1dd..0d8799282f 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -47,9 +47,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { @transient protected var seedvalue: Int = tableSizeSeed - import HashTable.powerOfTwo - - protected def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) + protected def capacity(expectedSize: Int) = HashTable.nextPositivePowerOfTwo(expectedSize) /** The initial size of the hash table. */ diff --git a/src/library/scala/collection/mutable/GrowingBuilder.scala b/src/library/scala/collection/mutable/GrowingBuilder.scala index c4b5e546aa..27d554d98e 100644 --- a/src/library/scala/collection/mutable/GrowingBuilder.scala +++ b/src/library/scala/collection/mutable/GrowingBuilder.scala @@ -15,6 +15,8 @@ import generic._ /** The canonical builder for collections that are growable, i.e. that support an * efficient `+=` method which adds an element to the collection. * + * GrowableBuilders can produce only a single instance of the collection they are growing. + * * @author Paul Phillips * @version 2.8 * @since 2.8 @@ -25,6 +27,6 @@ import generic._ class GrowingBuilder[Elem, To <: Growable[Elem]](empty: To) extends Builder[Elem, To] { protected var elems: To = empty def +=(x: Elem): this.type = { elems += x; this } - def clear() { elems = empty } + def clear() { empty.clear } def result: To = elems } diff --git a/src/library/scala/collection/mutable/HashMap.scala b/src/library/scala/collection/mutable/HashMap.scala index 11ff1f0893..de61ebb796 100644 --- a/src/library/scala/collection/mutable/HashMap.scala +++ b/src/library/scala/collection/mutable/HashMap.scala @@ -73,10 +73,18 @@ extends AbstractMap[A, B] } override def getOrElseUpdate(key: A, defaultValue: => B): B = { - val i = index(elemHashCode(key)) + val hash = elemHashCode(key) + val i = index(hash) val entry = findEntry(key, i) if (entry != null) entry.value - else addEntry(createNewEntry(key, defaultValue), i) + else { + val table0 = table + val default = defaultValue + // Avoid recomputing index if the `defaultValue()` hasn't triggered + // a table resize. + val newEntryIndex = if (table0 eq table) i else index(hash) + addEntry(createNewEntry(key, default), newEntryIndex) + } } /* inlined HashTable.findEntry0 to preserve its visibility */ diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index 4873aa3c3e..01ec1defad 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -367,7 +367,11 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU * Note: we take the most significant bits of the hashcode, not the lower ones * this is of crucial importance when populating the table in parallel */ - protected final def index(hcode: Int): Int = if (table.length == 1) 0 else improve(hcode, seedvalue) >>> numberOfLeadingZeros(table.length - 1) + protected final def index(hcode: Int): Int = { + val ones = table.length - 1 + val exponent = Integer.numberOfLeadingZeros(ones) + (improve(hcode, seedvalue) >>> exponent) & ones + } protected def initWithContents(c: HashTable.Contents[A, Entry]) = { if (c != null) { @@ -395,13 +399,13 @@ private[collection] object HashTable { /** The load factor for the hash table (in 0.001 step). */ private[collection] final def defaultLoadFactor: Int = 750 // corresponds to 75% - private[collection] final def loadFactorDenum = 1000 + private[collection] final def loadFactorDenum = 1000 // should be loadFactorDenom, but changing that isn't binary compatible private[collection] final def newThreshold(_loadFactor: Int, size: Int) = ((size.toLong * _loadFactor) / loadFactorDenum).toInt 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) + private[collection] final def capacity(expectedSize: Int) = nextPositivePowerOfTwo(expectedSize) trait HashUtils[KeyType] { protected final def sizeMapBucketBitSize = 5 @@ -429,16 +433,7 @@ private[collection] object HashTable { /** * Returns a power of two >= `target`. */ - private[collection] def powerOfTwo(target: Int): Int = { - /* See http://bits.stephan-brumme.com/roundUpToNextPowerOfTwo.html */ - var c = target - 1 - c |= c >>> 1 - c |= c >>> 2 - c |= c >>> 4 - c |= c >>> 8 - c |= c >>> 16 - c + 1 - } + private[collection] def nextPositivePowerOfTwo(target: Int): Int = 1 << -numberOfLeadingZeros(target - 1) class Contents[A, Entry >: Null <: HashEntry[A, Entry]]( val loadFactor: Int, diff --git a/src/library/scala/collection/mutable/History.scala b/src/library/scala/collection/mutable/History.scala index 19148c0ac2..13e2f32225 100644 --- a/src/library/scala/collection/mutable/History.scala +++ b/src/library/scala/collection/mutable/History.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/tPFL ** +** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** diff --git a/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala b/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala index 9ece8b1335..7ab4dd2d9d 100644 --- a/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala +++ b/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala @@ -25,7 +25,7 @@ import scala.annotation.migration * @version 2.0, 01/01/2007 * @since 1 */ -@deprecated("Adaptors are inherently unreliable and prone to performance problems.", "2.11.0") +@deprecated("adaptors are inherently unreliable and prone to performance problems", "2.11.0") class ImmutableMapAdaptor[A, B](protected var imap: immutable.Map[A, B]) extends AbstractMap[A, B] with Map[A, B] diff --git a/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala b/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala index d7eec70b15..aa21c4cc11 100644 --- a/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala +++ b/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala @@ -20,7 +20,7 @@ package mutable * @version 1.0, 21/07/2003 * @since 1 */ -@deprecated("Adaptors are inherently unreliable and prone to performance problems.", "2.11.0") +@deprecated("adaptors are inherently unreliable and prone to performance problems", "2.11.0") class ImmutableSetAdaptor[A](protected var set: immutable.Set[A]) extends AbstractSet[A] with Set[A] diff --git a/src/library/scala/collection/mutable/IndexedSeqView.scala b/src/library/scala/collection/mutable/IndexedSeqView.scala index 7acdeeff18..b525baaf5f 100644 --- a/src/library/scala/collection/mutable/IndexedSeqView.scala +++ b/src/library/scala/collection/mutable/IndexedSeqView.scala @@ -15,7 +15,6 @@ package mutable import generic._ import TraversableView.NoBuilder -import scala.language.implicitConversions /** A non-strict view of a mutable `IndexedSeq`. * $viewInfo diff --git a/src/library/scala/collection/mutable/LazyBuilder.scala b/src/library/scala/collection/mutable/LazyBuilder.scala index ebee38b77f..f0a5e6971a 100644 --- a/src/library/scala/collection/mutable/LazyBuilder.scala +++ b/src/library/scala/collection/mutable/LazyBuilder.scala @@ -13,12 +13,14 @@ package mutable /** A builder that constructs its result lazily. Iterators or iterables to * be added to this builder with `++=` are not evaluated until `result` is called. * + * This builder can be reused. + * * @since 2.8 * * @tparam Elem type of the elements for this builder. * @tparam To type of the collection this builder builds. */ -abstract class LazyBuilder[Elem, +To] extends Builder[Elem, To] { +abstract class LazyBuilder[Elem, +To] extends ReusableBuilder[Elem, To] { /** The different segments of elements to be added to the builder, represented as iterators */ protected var parts = new ListBuffer[TraversableOnce[Elem]] def +=(x: Elem): this.type = { parts += List(x); this } diff --git a/src/library/scala/collection/mutable/LinkedList.scala b/src/library/scala/collection/mutable/LinkedList.scala index b3500367af..5d03cd4410 100644 --- a/src/library/scala/collection/mutable/LinkedList.scala +++ b/src/library/scala/collection/mutable/LinkedList.scala @@ -76,7 +76,7 @@ import generic._ * }}} */ @SerialVersionUID(-7308240733518833071L) -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") class LinkedList[A]() extends AbstractSeq[A] with LinearSeq[A] with GenericTraversableTemplate[A, LinkedList] @@ -114,7 +114,7 @@ class LinkedList[A]() extends AbstractSeq[A] * @define Coll `LinkedList` * @define coll linked list */ -@deprecated("Low-level linked lists are deprecated.", "2.11.0") +@deprecated("low-level linked lists are deprecated", "2.11.0") object LinkedList extends SeqFactory[LinkedList] { override def empty[A]: LinkedList[A] = new LinkedList[A] implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, LinkedList[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] diff --git a/src/library/scala/collection/mutable/LinkedListLike.scala b/src/library/scala/collection/mutable/LinkedListLike.scala index d0748b8a9f..27c4466c99 100644 --- a/src/library/scala/collection/mutable/LinkedListLike.scala +++ b/src/library/scala/collection/mutable/LinkedListLike.scala @@ -55,7 +55,7 @@ import scala.annotation.tailrec * * }}} */ -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") trait LinkedListLike[A, This <: Seq[A] with LinkedListLike[A, This]] extends SeqLike[A, This] { self => var elem: A = _ diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index f9bab40a1e..aa79e972d5 100644 --- a/src/library/scala/collection/mutable/ListBuffer.scala +++ b/src/library/scala/collection/mutable/ListBuffer.scala @@ -12,8 +12,7 @@ package mutable import generic._ import immutable.{List, Nil, ::} -import java.io._ -import scala.annotation.migration +import java.io.{ObjectOutputStream, ObjectInputStream} /** A `Buffer` implementation backed by a list. It provides constant time * prepend and append. Most other operations are linear. @@ -47,7 +46,7 @@ final class ListBuffer[A] with Buffer[A] with GenericTraversableTemplate[A, ListBuffer] with BufferLike[A, ListBuffer[A]] - with Builder[A, List[A]] + with ReusableBuilder[A, List[A]] with SeqForwarder[A] with Serializable { @@ -120,6 +119,10 @@ final class ListBuffer[A] // Don't use the inherited size, which forwards to a List and is O(n). override def size = length + // Override with efficient implementations using the extra size information available to ListBuffer. + override def isEmpty: Boolean = len == 0 + override def nonEmpty: Boolean = len > 0 + // Implementations of abstract methods in Buffer override def apply(n: Int): A = @@ -262,13 +265,14 @@ final class ListBuffer[A] * * @param n the index which refers to the first element to remove. * @param count the number of elements to remove. + * @throws IndexOutOfBoundsException if the index `n` is not in the valid range + * `0 <= n <= length - count` (with `count > 0`). + * @throws IllegalArgumentException if `count < 0`. */ - @migration("Invalid input values will be rejected in future releases.", "2.11") override def remove(n: Int, count: Int) { - if (n >= len) - return - if (count < 0) - throw new IllegalArgumentException(s"removing negative number ($count) of elements") + if (count < 0) throw new IllegalArgumentException("removing negative number of elements: " + count.toString) + else if (count == 0) return // Nothing to do + if (n < 0 || n > len - count) throw new IndexOutOfBoundsException("at " + n.toString + " deleting " + count.toString) if (exported) copy() val n1 = n max 0 val count1 = count min (len - n1) @@ -297,6 +301,10 @@ final class ListBuffer[A] // Implementation of abstract method in Builder + /** Returns the accumulated `List`. + * + * This method may be called multiple times to obtain snapshots of the list in different stages of construction. + */ def result: List[A] = toList /** Converts this buffer to a list. Takes constant time. The buffer is @@ -382,6 +390,25 @@ final class ListBuffer[A] this } + /** Selects the last element. + * + * Runs in constant time. + * + * @return the last element of this buffer. + * @throws NoSuchElementException if this buffer is empty. + */ + override def last: A = + if (last0 eq null) throw new NoSuchElementException("last of empty ListBuffer") + else last0.head + + /** Optionally selects the last element. + * + * Runs in constant time. + * + * @return `Some` of the last element of this buffer if the buffer is nonempty, `None` if it is empty. + */ + override def lastOption: Option[A] = if (last0 eq null) None else Some(last0.head) + /** Returns an iterator over this `ListBuffer`. The iterator will reflect * changes made to the underlying `ListBuffer` beyond the next element; * the next element's value is cached so that `hasNext` and `next` are @@ -408,9 +435,6 @@ final class ListBuffer[A] } } - @deprecated("The result of this method will change along with this buffer, which is often not what's expected.", "2.11.0") - override def readOnly: List[A] = start - // Private methods /** Copy contents of this buffer */ @@ -426,7 +450,7 @@ final class ListBuffer[A] } override def equals(that: Any): Boolean = that match { - case that: ListBuffer[_] => this.readOnly equals that.readOnly + case that: ListBuffer[_] => this.start equals that.start case _ => super.equals(that) } diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala index 198e34bd29..ecbb1952af 100644 --- a/src/library/scala/collection/mutable/LongMap.scala +++ b/src/library/scala/collection/mutable/LongMap.scala @@ -415,6 +415,24 @@ extends AbstractMap[Long, V] lm } + override def +[V1 >: V](kv: (Long, V1)): LongMap[V1] = { + val lm = clone().asInstanceOf[LongMap[V1]] + lm += kv + lm + } + + override def ++[V1 >: V](xs: GenTraversableOnce[(Long, V1)]): LongMap[V1] = { + val lm = clone().asInstanceOf[LongMap[V1]] + xs.foreach(kv => lm += kv) + lm + } + + override def updated[V1 >: V](key: Long, value: V1): LongMap[V1] = { + val lm = clone().asInstanceOf[LongMap[V1]] + lm += (key, value) + lm + } + /** Applies a function to all keys of this map. */ def foreachKey[A](f: Long => A) { if ((extraKeys & 1) == 1) f(0L) @@ -501,7 +519,11 @@ object LongMap { def apply(): LongMapBuilder[U] = new LongMapBuilder[U] } - final class LongMapBuilder[V] extends Builder[(Long, V), LongMap[V]] { + /** A builder for instances of `LongMap`. + * + * This builder can be reused to create multiple instances. + */ + final class LongMapBuilder[V] extends ReusableBuilder[(Long, V), LongMap[V]] { private[collection] var elems: LongMap[V] = new LongMap[V] def +=(entry: (Long, V)): this.type = { elems += entry @@ -541,7 +563,7 @@ object LongMap { /** Creates a new `LongMap` from keys and values. * Equivalent to but more efficient than `LongMap((keys zip values): _*)`. */ - def fromZip[V](keys: Iterable[Long], values: Iterable[V]): LongMap[V] = { + def fromZip[V](keys: collection.Iterable[Long], values: collection.Iterable[V]): LongMap[V] = { val sz = math.min(keys.size, values.size) val lm = new LongMap[V](sz * 2) val ki = keys.iterator diff --git a/src/library/scala/collection/mutable/Map.scala b/src/library/scala/collection/mutable/Map.scala index 2ac3cb65b5..460a8b8f77 100644 --- a/src/library/scala/collection/mutable/Map.scala +++ b/src/library/scala/collection/mutable/Map.scala @@ -20,15 +20,15 @@ import generic._ * @since 1.0 * @author Matthias Zenger */ -trait Map[A, B] - extends Iterable[(A, B)] -// with GenMap[A, B] - with scala.collection.Map[A, B] - with MapLike[A, B, Map[A, B]] { +trait Map[K, V] + extends Iterable[(K, V)] +// with GenMap[K, V] + with scala.collection.Map[K, V] + with MapLike[K, V, Map[K, V]] { - override def empty: Map[A, B] = Map.empty + override def empty: Map[K, V] = Map.empty - override def seq: Map[A, B] = this + override def seq: Map[K, V] = this /** The same map with a given default function. * @@ -37,7 +37,7 @@ trait Map[A, B] * @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: A => B): mutable.Map[A, B] = new Map.WithDefault[A, B](this, d) + def withDefault(d: K => V): mutable.Map[K, V] = new Map.WithDefault[K, V](this, d) /** The same map with a given default value. * @@ -46,7 +46,7 @@ trait Map[A, B] * @param d default value used for non-present keys * @return a wrapper of the map with a default value */ - def withDefaultValue(d: B): mutable.Map[A, B] = new Map.WithDefault[A, B](this, x => d) + def withDefaultValue(d: V): mutable.Map[K, V] = new Map.WithDefault[K, V](this, x => d) } /** $factoryInfo @@ -56,25 +56,25 @@ trait Map[A, B] */ object Map extends MutableMapFactory[Map] { /** $canBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] = new MapCanBuildFrom[K, V] - def empty[A, B]: Map[A, B] = new HashMap[A, B] + def empty[K, V]: Map[K, V] = new HashMap[K, V] - class WithDefault[A, B](underlying: Map[A, B], d: A => B) extends scala.collection.Map.WithDefault(underlying, d) with Map[A, B] { - override def += (kv: (A, B)) = {underlying += kv; this} - def -= (key: A) = {underlying -= key; this} + class WithDefault[K, V](underlying: Map[K, V], d: K => V) extends scala.collection.Map.WithDefault(underlying, d) with Map[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[B1 >: B](key: A, value: B1): WithDefault[A, B1] = new WithDefault[A, B1](underlying.updated[B1](key, value), d) - override def + [B1 >: B](kv: (A, B1)): WithDefault[A, B1] = updated(kv._1, kv._2) - override def - (key: A): WithDefault[A, B] = new WithDefault(underlying - key, d) + override def updated[V1 >: V](key: K, value: V1): WithDefault[K, V1] = new WithDefault[K, V1](underlying.updated[V1](key, value), d) + override def + [V1 >: V](kv: (K, V1)): WithDefault[K, V1] = updated(kv._1, kv._2) + override def - (key: K): WithDefault[K, V] = new WithDefault(underlying - key, d) /** If these methods aren't overridden to thread through the underlying map, * successive calls to withDefault* have no effect. */ - override def withDefault(d: A => B): mutable.Map[A, B] = new WithDefault[A, B](underlying, d) - override def withDefaultValue(d: B): mutable.Map[A, B] = new WithDefault[A, B](underlying, x => d) + override def withDefault(d: K => V): mutable.Map[K, V] = new WithDefault[K, V](underlying, d) + override def withDefaultValue(d: V): mutable.Map[K, V] = new WithDefault[K, V](underlying, x => d) } } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -abstract class AbstractMap[A, B] extends scala.collection.AbstractMap[A, B] with Map[A, B] +abstract class AbstractMap[K, V] extends scala.collection.AbstractMap[K, V] with Map[K, V] diff --git a/src/library/scala/collection/mutable/MapBuilder.scala b/src/library/scala/collection/mutable/MapBuilder.scala index a5a6b12ea9..cfc3079f41 100644 --- a/src/library/scala/collection/mutable/MapBuilder.scala +++ b/src/library/scala/collection/mutable/MapBuilder.scala @@ -23,7 +23,7 @@ package mutable * @since 2.8 */ class MapBuilder[A, B, Coll <: scala.collection.GenMap[A, B] with scala.collection.GenMapLike[A, B, Coll]](empty: Coll) -extends Builder[(A, B), Coll] { +extends ReusableBuilder[(A, B), Coll] { protected var elems: Coll = empty def +=(x: (A, B)): this.type = { elems = (elems + x).asInstanceOf[Coll] diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala index 44af886cf5..238b6d1be1 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -31,10 +31,10 @@ import scala.collection.parallel.mutable.ParMap * To implement a concrete mutable map, you need to provide * implementations of the following methods: * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def += (kv: (A, B)): This - * def -= (key: A): This + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def += (kv: (K, V)): This + * def -= (key: K): This * }}} * If you wish that methods like `take`, `drop`, `filter` also return the same kind of map * you should also override: @@ -44,13 +44,13 @@ import scala.collection.parallel.mutable.ParMap * It is also good idea to override methods `foreach` and * `size` for efficiency. */ -trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] - extends scala.collection.MapLike[A, B, This] - with Builder[(A, B), This] - with Growable[(A, B)] - with Shrinkable[A] +trait MapLike[K, V, +This <: MapLike[K, V, This] with Map[K, V]] + extends scala.collection.MapLike[K, V, This] + with Builder[(K, V), This] + with Growable[(K, V)] + with Shrinkable[K] with Cloneable[This] - with Parallelizable[(A, B), ParMap[A, B]] + with Parallelizable[(K, V), ParMap[K, V]] { self => /** A common implementation of `newBuilder` for all mutable maps @@ -58,9 +58,21 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * * Overrides `MapLike` implementation for better efficiency. */ - override protected[this] def newBuilder: Builder[(A, B), This] = empty + override protected[this] def newBuilder: Builder[(K, V), This] = empty + + protected[this] override def parCombiner = ParMap.newCombiner[K, V] + + /** Converts this $coll to a sequence. + * + * ```Note```: assumes a fast `size` method. Subclasses should override if this is not true. + */ + override def toSeq: collection.Seq[(K, V)] = { + // ArrayBuffer for efficiency, preallocated to the right size. + val result = new ArrayBuffer[(K, V)](size) + foreach(result += _) + result + } - protected[this] override def parCombiner = ParMap.newCombiner[A, B] /** Adds a new key/value pair to this map and optionally returns previously bound value. * If the map already contains a @@ -72,7 +84,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * before the `put` operation was executed, or `None` if `key` * was not defined in the map before. */ - def put(key: A, value: B): Option[B] = { + def put(key: K, value: V): Option[V] = { val r = get(key) update(key, value) r @@ -85,7 +97,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param key The key to update * @param value The new value */ - def update(key: A, value: B) { this += ((key, value)) } + def update(key: K, value: V) { this += ((key, value)) } /** Adds a new key/value pair to this map. * If the map already contains a @@ -93,7 +105,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param kv the key/value pair. * @return the map itself */ - def += (kv: (A, B)): this.type + def += (kv: (K, V)): this.type /** Creates a new map consisting of all key/value pairs of the current map * plus a new pair of a given key and value. @@ -103,7 +115,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return A fresh immutable map with the binding from `key` to * `value` added to this map. */ - override def updated[B1 >: B](key: A, value: B1): Map[A, B1] = this + ((key, value)) + override def updated[V1 >: V](key: K, value: V1): Map[K, V1] = this + ((key, value)) /** Creates a new map containing a new key/value mapping and all the key/value mappings * of this map. @@ -114,7 +126,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map containing mappings of this map and the mapping `kv`. */ @migration("`+` creates a new map. Use `+=` to add an element to this map and return that map itself.", "2.8.0") - def + [B1 >: B] (kv: (A, B1)): Map[A, B1] = clone().asInstanceOf[Map[A, B1]] += kv + def + [V1 >: V] (kv: (K, V1)): Map[K, V1] = clone().asInstanceOf[Map[K, V1]] += kv /** Creates a new map containing two or more key/value mappings and all the key/value * mappings of this map. @@ -127,8 +139,8 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map containing mappings of this map and two or more specified mappings. */ @migration("`+` creates a new map. Use `+=` to add an element to this map and return that map itself.", "2.8.0") - override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): Map[A, B1] = - clone().asInstanceOf[Map[A, B1]] += elem1 += elem2 ++= elems + override def + [V1 >: V] (elem1: (K, V1), elem2: (K, V1), elems: (K, V1) *): Map[K, V1] = + clone().asInstanceOf[Map[K, V1]] += elem1 += elem2 ++= elems /** Creates a new map containing the key/value mappings provided by the specified traversable object * and all the key/value mappings of this map. @@ -139,8 +151,8 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map containing mappings of this map and those provided by `xs`. */ @migration("`++` creates a new map. Use `++=` to add an element to this map and return that map itself.", "2.8.0") - override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1] = - clone().asInstanceOf[Map[A, B1]] ++= xs.seq + override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): Map[K, V1] = + clone().asInstanceOf[Map[K, V1]] ++= xs.seq /** Removes a key from this map, returning the value associated previously * with that key as an option. @@ -148,7 +160,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return an option value containing the value associated previously with `key`, * or `None` if `key` was not defined in the map before. */ - def remove(key: A): Option[B] = { + def remove(key: K): Option[V] = { val r = get(key) this -= key r @@ -158,7 +170,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param key the key to be removed * @return the map itself. */ - def -= (key: A): this.type + def -= (key: K): this.type /** Creates a new map with all the key/value mappings of this map except the key/value mapping * with the specified key. @@ -167,7 +179,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map with all the mappings of this map except that with a key `key`. */ @migration("`-` creates a new map. Use `-=` to remove an element from this map and return that map itself.", "2.8.0") - override def -(key: A): This = clone() -= key + override def -(key: K): This = clone() -= key /** Removes all bindings from the map. After this operation has completed, * the map will be empty. @@ -188,7 +200,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return the value associated with key (either previously or as a result * of executing the method). */ - def getOrElseUpdate(key: A, op: => B): B = + def getOrElseUpdate(key: K, op: => V): V = get(key) match { case Some(v) => v case None => val d = op; this(key) = d; d @@ -201,7 +213,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param f the transformation to apply * @return the map itself. */ - def transform(f: (A, B) => B): this.type = { + def transform(f: (K, V) => V): this.type = { this.iterator foreach { case (key, value) => update(key, f(key, value)) } @@ -213,7 +225,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * * @param p The test predicate */ - def retain(p: (A, B) => Boolean): this.type = { + def retain(p: (K, V) => Boolean): this.type = { for ((k, v) <- this.toList) // SI-7269 toList avoids ConcurrentModificationException if (!p(k, v)) this -= k @@ -237,7 +249,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * with a key equal to `elem1`, `elem2` or any of `elems`. */ @migration("`-` creates a new map. Use `-=` to remove an element from this map and return that map itself.", "2.8.0") - override def -(elem1: A, elem2: A, elems: A*): This = + override def -(elem1: K, elem2: K, elems: K*): This = clone() -= elem1 -= elem2 --= elems /** Creates a new map with all the key/value mappings of this map except mappings with keys @@ -248,5 +260,5 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * with a key equal to a key from `xs`. */ @migration("`--` creates a new map. Use `--=` to remove an element from this map and return that map itself.", "2.8.0") - override def --(xs: GenTraversableOnce[A]): This = clone() --= xs.seq + override def --(xs: GenTraversableOnce[K]): This = clone() --= xs.seq } diff --git a/src/library/scala/collection/mutable/MapProxy.scala b/src/library/scala/collection/mutable/MapProxy.scala index 552cd9769b..63b14d328a 100644 --- a/src/library/scala/collection/mutable/MapProxy.scala +++ b/src/library/scala/collection/mutable/MapProxy.scala @@ -20,7 +20,7 @@ package mutable * @version 2.0, 31/12/2006 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait MapProxy[A, B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] { private def newProxy[B1 >: B](newSelf: Map[A, B1]): MapProxy[A, B1] = new MapProxy[A, B1] { val self = newSelf } diff --git a/src/library/scala/collection/mutable/MutableList.scala b/src/library/scala/collection/mutable/MutableList.scala index 646023f469..a333eedb1a 100644 --- a/src/library/scala/collection/mutable/MutableList.scala +++ b/src/library/scala/collection/mutable/MutableList.scala @@ -11,7 +11,7 @@ package collection package mutable import generic._ -import immutable.{List, Nil} +import immutable.List /** * This class is used internally to represent mutable lists. It is the diff --git a/src/library/scala/collection/mutable/ObservableBuffer.scala b/src/library/scala/collection/mutable/ObservableBuffer.scala index 9c3247f83b..53d26f4c6f 100644 --- a/src/library/scala/collection/mutable/ObservableBuffer.scala +++ b/src/library/scala/collection/mutable/ObservableBuffer.scala @@ -23,9 +23,8 @@ import script._ * @version 1.0, 08/07/2003 * @since 1 */ -@deprecated("Observables are deprecated because scripting is deprecated.", "2.11.0") -trait ObservableBuffer[A] extends Buffer[A] with Publisher[Message[A] with Undoable] -{ +@deprecated("observables are deprecated because scripting is deprecated", "2.11.0") +trait ObservableBuffer[A] extends Buffer[A] with Publisher[Message[A] with Undoable] { type Pub <: ObservableBuffer[A] abstract override def +=(element: A): this.type = { diff --git a/src/library/scala/collection/mutable/ObservableMap.scala b/src/library/scala/collection/mutable/ObservableMap.scala index 7509b72568..421302b700 100644 --- a/src/library/scala/collection/mutable/ObservableMap.scala +++ b/src/library/scala/collection/mutable/ObservableMap.scala @@ -25,9 +25,8 @@ import script._ * @version 2.0, 31/12/2006 * @since 1 */ -@deprecated("Observables are deprecated because scripting is deprecated.", "2.11.0") -trait ObservableMap[A, B] extends Map[A, B] with Publisher[Message[(A, B)] with Undoable] -{ +@deprecated("observables are deprecated because scripting is deprecated", "2.11.0") +trait ObservableMap[A, B] extends Map[A, B] with Publisher[Message[(A, B)] with Undoable] { type Pub <: ObservableMap[A, B] diff --git a/src/library/scala/collection/mutable/ObservableSet.scala b/src/library/scala/collection/mutable/ObservableSet.scala index 19b4a5e39f..eb55a1f822 100644 --- a/src/library/scala/collection/mutable/ObservableSet.scala +++ b/src/library/scala/collection/mutable/ObservableSet.scala @@ -23,9 +23,8 @@ import script._ * @version 1.0, 08/07/2003 * @since 1 */ -@deprecated("Observables are deprecated because scripting is deprecated.", "2.11.0") -trait ObservableSet[A] extends Set[A] with Publisher[Message[A] with Undoable] -{ +@deprecated("observables are deprecated because scripting is deprecated", "2.11.0") +trait ObservableSet[A] extends Set[A] with Publisher[Message[A] with Undoable] { type Pub <: ObservableSet[A] diff --git a/src/library/scala/collection/mutable/OpenHashMap.scala b/src/library/scala/collection/mutable/OpenHashMap.scala index c86357efad..b2e9ee27b9 100644 --- a/src/library/scala/collection/mutable/OpenHashMap.scala +++ b/src/library/scala/collection/mutable/OpenHashMap.scala @@ -21,12 +21,16 @@ object OpenHashMap { def apply[K, V](elems : (K, V)*) = new OpenHashMap[K, V] ++= elems def empty[K, V] = new OpenHashMap[K, V] - final private class OpenEntry[Key, Value](val key: Key, - val hash: Int, + /** A hash table entry. + * + * The entry is occupied if and only if its `value` is a `Some`; + * deleted if and only if its `value` is `None`. + * If its `key` is not the default value of type `Key`, the entry is occupied. + * If the entry is occupied, `hash` contains the hash value of `key`. + */ + final private class OpenEntry[Key, Value](var key: Key, + var hash: Int, var value: Option[Value]) - extends HashEntry[Key, OpenEntry[Key, Value]] - - private[mutable] def nextPositivePowerOfTwo(i : Int) = 1 << (32 - Integer.numberOfLeadingZeros(i - 1)) } /** A mutable hash map based on an open hashing scheme. The precise scheme is @@ -61,10 +65,17 @@ extends AbstractMap[Key, Value] override def empty: OpenHashMap[Key, Value] = OpenHashMap.empty[Key, Value] - private[this] val actualInitialSize = OpenHashMap.nextPositivePowerOfTwo(initialSize) + private[this] val actualInitialSize = HashTable.nextPositivePowerOfTwo(initialSize) private var mask = actualInitialSize - 1 - private var table : Array[Entry] = new Array[Entry](actualInitialSize) + + /** The hash table. + * + * The table's entries are initialized to `null`, indication of an empty slot. + * A slot is either deleted or occupied if and only if the entry is non-`null`. + */ + private[this] var table = new Array[Entry](actualInitialSize) + private var _size = 0 private var deleted = 0 @@ -91,39 +102,41 @@ extends AbstractMap[Key, Value] table = new Array[Entry](newSize) mask = newSize - 1 oldTable.foreach( entry => - if (entry != null && entry.value != None) addEntry(entry)) + if (entry != null && entry.value != None) + table(findIndex(entry.key, entry.hash)) = entry ) deleted = 0 } /** Return the index of the first slot in the hash table (in probe order) - * that either is empty, or is or was last occupied by the given key. - */ - private[this] def findIndex(key: Key) : Int = findIndex(key, hashOf(key)) - - /** Return the index of the first slot in the hash table (in probe order) - * that either is empty, or is or was last occupied by the given key. - * - * This method is an optimization for when the hash value is in hand. + * that is, in order of preference, either occupied by the given key, deleted, or empty. * * @param hash hash value for `key` */ private[this] def findIndex(key: Key, hash: Int): Int = { var index = hash & mask var j = 0 - while(table(index) != null && - !(table(index).hash == hash && - table(index).key == key)){ + + /** Index of the first slot containing a deleted entry, or -1 if none found yet. */ + var firstDeletedIndex = -1 + + var entry = table(index) + while (entry != null) { + if (entry.hash == hash && entry.key == key && entry.value != None) + return index + + if (firstDeletedIndex == -1 && entry.value == None) + firstDeletedIndex = index + j += 1 index = (index + j) & mask + entry = table(index) } - index - } - private[this] def addEntry(entry: Entry) = - if (entry != null) table(findIndex(entry.key, entry.hash)) = entry + if (firstDeletedIndex == -1) index else firstDeletedIndex + } override def update(key: Key, value: Value) { - put(key, hashOf(key), value) + put(key, value) } @deprecatedOverriding("+= should not be overridden in order to maintain consistency with put.", "2.11.0") @@ -147,6 +160,8 @@ extends AbstractMap[Key, Value] } else { val res = entry.value if (entry.value == None) { + entry.key = key + entry.hash = hash size += 1 deleted -= 1 modCount += 1 @@ -156,13 +171,22 @@ extends AbstractMap[Key, Value] } } + /** Delete the hash table slot contained in the given entry. */ + @inline + private[this] def deleteSlot(entry: Entry) = { + entry.key = null.asInstanceOf[Key] + entry.hash = 0 + entry.value = None + + size -= 1 + deleted += 1 + } + override def remove(key : Key): Option[Value] = { - val index = findIndex(key) - if (table(index) != null && table(index).value != None){ - val res = table(index).value - table(index).value = None - size -= 1 - deleted += 1 + val entry = table(findIndex(key, hashOf(key))) + if (entry != null && entry.value != None) { + val res = entry.value + deleteSlot(entry) res } else None } @@ -243,7 +267,7 @@ extends AbstractMap[Key, Value] } override def retain(f : (Key, Value) => Boolean) = { - foreachUndeletedEntry(entry => if (!f(entry.key, entry.value.get)) {entry.value = None; size -= 1; deleted += 1} ) + foreachUndeletedEntry(entry => if (!f(entry.key, entry.value.get)) deleteSlot(entry)) this } diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index 2562f60355..ed43ef6db9 100644 --- a/src/library/scala/collection/mutable/PriorityQueue.scala +++ b/src/library/scala/collection/mutable/PriorityQueue.scala @@ -16,7 +16,7 @@ import generic._ * To prioritize elements of type A there must be an implicit * Ordering[A] available at creation. * - * Only the `dequeue` and `dequeueAll` methods will return methods in priority + * Only the `dequeue` and `dequeueAll` methods will return elements in priority * order (while removing elements from the heap). Standard collection methods * including `drop`, `iterator`, and `toString` will remove or traverse the heap * in whichever order seems most convenient. @@ -46,8 +46,7 @@ import generic._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecatedInheritance("PriorityQueue is not intended to be subclassed due to extensive private implementation details.", "2.11.0") -class PriorityQueue[A](implicit val ord: Ordering[A]) +sealed class PriorityQueue[A](implicit val ord: Ordering[A]) extends AbstractIterable[A] with Iterable[A] with GenericOrderedTraversableTemplate[A, PriorityQueue] @@ -67,7 +66,7 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) def p_swap(a: Int, b: Int) = super.swap(a, b) } - protected[this] override def newBuilder = new PriorityQueue[A] + protected[this] override def newBuilder = PriorityQueue.newBuilder[A] private val resarr = new ResizableArrayAccess[A] @@ -90,14 +89,15 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) } } - protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Unit = { + protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Boolean = { + // returns true if any swaps were done (used in heapify) var k: Int = m while (n >= 2 * k) { var j = 2 * k if (j < n && toA(as(j)) < toA(as(j + 1))) j += 1 if (toA(as(k)) >= toA(as(j))) - return + return k != m else { val h = as(k) as(k) = as(j) @@ -105,6 +105,7 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) k = j } } + k != m } /** Inserts a single element into the priority queue. @@ -120,6 +121,66 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) this } + override def ++=(xs: TraversableOnce[A]): this.type = { + val from = resarr.p_size0 + for (x <- xs) unsafeAdd(x) + heapify(from) + this + } + + private def unsafeAdd(elem: A): Unit = { + // like += but skips fixUp, which breaks the ordering invariant + // a series of unsafeAdds MUST be followed by heapify + resarr.p_ensureSize(resarr.p_size0 + 1) + resarr.p_array(resarr.p_size0) = elem.asInstanceOf[AnyRef] + resarr.p_size0 += 1 + } + + private def heapify(from: Int): Unit = { + // elements at indices 1..from-1 were already in heap order before any adds + // elements at indices from..n are newly added, their order must be fixed + val n = length + + if (from <= 2) { + // no pre-existing order to maintain, do the textbook heapify algorithm + for (i <- n/2 to 1 by -1) fixDown(resarr.p_array, i, n) + } + else if (n - from < 4) { + // for very small adds, doing the simplest fix is faster + for (i <- from to n) fixUp(resarr.p_array, i) + } + else { + var min = from/2 // tracks the minimum element in the queue + val queue = scala.collection.mutable.Queue[Int](min) + + // do fixDown on the parents of all the new elements + // except the parent of the first new element, which is in the queue + // (that parent is treated specially because it might be the root) + for (i <- n/2 until min by -1) { + if (fixDown(resarr.p_array, i, n)) { + // there was a swap, so also need to fixDown i's parent + val parent = i/2 + if (parent < min) { // make sure same parent isn't added twice + min = parent + queue += parent + } + } + } + + while (queue.nonEmpty) { + val i = queue.dequeue() + if (fixDown(resarr.p_array, i, n)) { + val parent = i/2 + if (parent < min && parent > 0) { + // the "parent > 0" is to avoid adding the parent of the root + min = parent + queue += parent + } + } + } + } + } + /** Adds all elements provided by a `TraversableOnce` object * into the priority queue. * @@ -143,9 +204,11 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) def dequeue(): A = if (resarr.p_size0 > 1) { resarr.p_size0 = resarr.p_size0 - 1 - resarr.p_swap(1, resarr.p_size0) + val result = resarr.p_array(1) + resarr.p_array(1) = resarr.p_array(resarr.p_size0) + resarr.p_array(resarr.p_size0) = null // erase reference from array fixDown(resarr.p_array, 1, resarr.p_size0 - 1) - toA(resarr.p_array(resarr.p_size0)) + toA(result) } else throw new NoSuchElementException("no element to remove from heap") @@ -187,27 +250,34 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) } } - /** Returns the reverse of this queue. The priority queue that gets - * returned will have an inversed ordering - if for some elements - * `x` and `y` the original queue's ordering - * had `compare` returning an integer ''w'', the new one will return ''-w'', - * assuming the original ordering abides its contract. + /** Returns the reverse of this priority queue. The new priority queue has + * the same elements as the original, but the opposite ordering. * - * Note that the order of the elements will be reversed unless the - * `compare` method returns 0. In this case, such elements - * will be subsequent, but their corresponding subinterval may be inappropriately - * reversed. However, due to the compare-equals contract, they will also be equal. + * For example, the element with the highest priority in `pq` has the lowest + * priority in `pq.reverse`, and vice versa. * - * @return A reversed priority queue. + * Ties are handled arbitrarily. Elements with equal priority may or + * may not be reversed with respect to each other. + * + * @return the reversed priority queue. */ def reverse = { - val revq = new PriorityQueue[A]()(new scala.math.Ordering[A] { - def compare(x: A, y: A) = ord.compare(y, x) - }) - for (i <- 1 until resarr.length) revq += resarr(i) + val revq = new PriorityQueue[A]()(ord.reverse) + // copy the existing data into the new array backwards + // this won't put it exactly into the correct order, + // but will require less fixing than copying it in + // the original order + val n = resarr.p_size0 + revq.resarr.p_ensureSize(n) + revq.resarr.p_size0 = n + val from = resarr.p_array + val to = revq.resarr.p_array + for (i <- 1 until n) to(i) = from(n-i) + revq.heapify(1) revq } + /** Returns an iterator which yields all the elements in the reverse order * than that returned by the method `iterator`. * @@ -257,12 +327,198 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) * * @return a priority queue with the same elements. */ - override def clone(): PriorityQueue[A] = new PriorityQueue[A] ++= this.iterator + override def clone(): PriorityQueue[A] = { + val pq = new PriorityQueue[A] + val n = resarr.p_size0 + pq.resarr.p_ensureSize(n) + java.lang.System.arraycopy(resarr.p_array, 1, pq.resarr.p_array, 1, n-1) + pq.resarr.p_size0 = n + pq + } } object PriorityQueue extends OrderedTraversableFactory[PriorityQueue] { - def newBuilder[A](implicit ord: Ordering[A]) = new PriorityQueue[A] + def newBuilder[A](implicit ord: Ordering[A]): Builder[A, PriorityQueue[A]] = { + new Builder[A, PriorityQueue[A]] { + val pq = new PriorityQueue[A] + def +=(elem: A): this.type = { pq.unsafeAdd(elem); this } + def result(): PriorityQueue[A] = { pq.heapify(1); pq } + def clear(): Unit = pq.clear() + } + } + implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, PriorityQueue[A]] = new GenericCanBuildFrom[A] } + +/** This class servers as a proxy for priority queues. The + * elements of the queue have to be ordered in terms of the + * `Ordered[T]` class. + * + * @author Matthias Zenger + * @version 1.0, 03/05/2004 + * @since 1 + */ +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") +sealed abstract class PriorityQueueProxy[A](implicit ord: Ordering[A]) extends PriorityQueue[A] with Proxy { + def self: PriorityQueue[A] + + /** Creates a new iterator over all elements contained in this + * object. + * + * @return the new iterator + */ + override def iterator: Iterator[A] = self.iterator + + /** Returns the length of this priority queue. + */ + override def length: Int = self.length + + /** Checks if the queue is empty. + * + * @return true, iff there is no element in the queue. + */ + override def isEmpty: Boolean = self.isEmpty + + /** Inserts a single element into the priority queue. + * + * @param elem the element to insert + */ + override def +=(elem: A): this.type = { self += elem; this } + + /** Adds all elements provided by an iterator into the priority queue. + * + * @param it an iterator + */ + override def ++=(it: TraversableOnce[A]): this.type = { + self ++= it + this + } + + /** Adds all elements to the queue. + * + * @param elems the elements to add. + */ + override def enqueue(elems: A*): Unit = self ++= elems + + /** Returns the element with the highest priority in the queue, + * and removes this element from the queue. + * + * @return the element with the highest priority. + */ + override def dequeue(): A = self.dequeue() + + /** Returns the element with the highest priority in the queue, + * or throws an error if there is no element contained in the queue. + * + * @return the element with the highest priority. + */ + override def head: A = self.head + + /** Removes all elements from the queue. After this operation is completed, + * the queue will be empty. + */ + override def clear(): Unit = self.clear() + + /** Returns a regular queue containing the same elements. + */ + override def toQueue: Queue[A] = self.toQueue + + /** This method clones the priority queue. + * + * @return a priority queue with the same elements. + */ + override def clone(): PriorityQueue[A] = new PriorityQueueProxy[A] { + def self = PriorityQueueProxy.this.self.clone() + } +} + + +/** This class implements synchronized priority queues using a binary heap. + * The elements of the queue have to be ordered in terms of the `Ordered[T]` class. + * + * @tparam A type of the elements contained in this synchronized priority queue + * @param ord implicit ordering used to compared elements of type `A` + * + * @author Matthias Zenger + * @version 1.0, 03/05/2004 + * @since 1 + * @define Coll `SynchronizedPriorityQueue` + * @define coll synchronized priority queue + */ +@deprecated("Comprehensive synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentSkipListSet as an alternative.", "2.11.0") +sealed class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQueue[A] { + + /** Checks if the queue is empty. + * + * @return true, iff there is no element in the queue. + */ + override def isEmpty: Boolean = synchronized { super.isEmpty } + + /** Inserts a single element into the priority queue. + * + * @param elem the element to insert + */ + override def +=(elem: A): this.type = { + synchronized { + super.+=(elem) + } + this + } + + /** Adds all elements of a traversable object into the priority queue. + * + * @param xs a traversable object + */ + override def ++=(xs: TraversableOnce[A]): this.type = { + synchronized { + super.++=(xs) + } + this + } + + /** Adds all elements to the queue. + * + * @param elems the elements to add. + */ + override def enqueue(elems: A*): Unit = synchronized { super.++=(elems) } + + /** Returns the element with the highest priority in the queue, + * and removes this element from the queue. + * + * @return the element with the highest priority. + */ + override def dequeue(): A = synchronized { super.dequeue() } + + /** Returns the element with the highest priority in the queue, + * or throws an error if there is no element contained in the queue. + * + * @return the element with the highest priority. + */ + override def head: A = synchronized { super.head } + + /** Removes all elements from the queue. After this operation is completed, + * the queue will be empty. + */ + override def clear(): Unit = synchronized { super.clear() } + + /** Returns an iterator which yield all the elements of the priority + * queue in descending priority order. + * + * @return an iterator over all elements sorted in descending order. + */ + override def iterator: Iterator[A] = synchronized { super.iterator } + + /** Checks if two queues are structurally identical. + * + * @return true, iff both queues contain the same sequence of elements. + */ + override def equals(that: Any): Boolean = synchronized { super.equals(that) } + + /** Returns a textual representation of a queue as a string. + * + * @return the string representation of this queue. + */ + override def toString(): String = synchronized { super.toString() } +} diff --git a/src/library/scala/collection/mutable/PriorityQueueProxy.scala b/src/library/scala/collection/mutable/PriorityQueueProxy.scala deleted file mode 100644 index b24551a6b7..0000000000 --- a/src/library/scala/collection/mutable/PriorityQueueProxy.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - -package scala -package collection -package mutable - -/** This class servers as a proxy for priority queues. The - * elements of the queue have to be ordered in terms of the - * `Ordered[T]` class. - * - * @author Matthias Zenger - * @version 1.0, 03/05/2004 - * @since 1 - */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") -abstract class PriorityQueueProxy[A](implicit ord: Ordering[A]) extends PriorityQueue[A] - with Proxy -{ - def self: PriorityQueue[A] - - /** Creates a new iterator over all elements contained in this - * object. - * - * @return the new iterator - */ - override def iterator: Iterator[A] = self.iterator - - /** Returns the length of this priority queue. - */ - override def length: Int = self.length - - /** Checks if the queue is empty. - * - * @return true, iff there is no element in the queue. - */ - override def isEmpty: Boolean = self.isEmpty - - /** Inserts a single element into the priority queue. - * - * @param elem the element to insert - */ - override def +=(elem: A): this.type = { self += elem; this } - - /** Adds all elements provided by an iterator into the priority queue. - * - * @param it an iterator - */ - override def ++=(it: TraversableOnce[A]): this.type = { - self ++= it - this - } - - /** Adds all elements to the queue. - * - * @param elems the elements to add. - */ - override def enqueue(elems: A*): Unit = self ++= elems - - /** Returns the element with the highest priority in the queue, - * and removes this element from the queue. - * - * @return the element with the highest priority. - */ - override def dequeue(): A = self.dequeue() - - /** Returns the element with the highest priority in the queue, - * or throws an error if there is no element contained in the queue. - * - * @return the element with the highest priority. - */ - override def head: A = self.head - - /** Removes all elements from the queue. After this operation is completed, - * the queue will be empty. - */ - override def clear(): Unit = self.clear() - - /** Returns a regular queue containing the same elements. - */ - override def toQueue: Queue[A] = self.toQueue - - /** This method clones the priority queue. - * - * @return a priority queue with the same elements. - */ - override def clone(): PriorityQueue[A] = new PriorityQueueProxy[A] { - def self = PriorityQueueProxy.this.self.clone() - } -} diff --git a/src/library/scala/collection/mutable/Queue.scala b/src/library/scala/collection/mutable/Queue.scala index ad60173b64..fd5fe9aecc 100644 --- a/src/library/scala/collection/mutable/Queue.scala +++ b/src/library/scala/collection/mutable/Queue.scala @@ -143,7 +143,7 @@ extends MutableList[A] /** Return the proper suffix of this list which starts with the first element that satisfies `p`. * That element is unlinked from the list. If no element satisfies `p`, return None. */ - @deprecated("extractFirst inappropriately exposes implementation details. Use dequeue or dequeueAll.", "2.11.0") + @deprecated("extractFirst inappropriately exposes implementation details. Use dequeue or dequeueAll.", "2.11.0") def extractFirst(start: LinkedList[A], p: A => Boolean): Option[LinkedList[A]] = { if (isEmpty) None else { diff --git a/src/library/scala/collection/mutable/QueueProxy.scala b/src/library/scala/collection/mutable/QueueProxy.scala index 22ff3306d5..e780cc2cf0 100644 --- a/src/library/scala/collection/mutable/QueueProxy.scala +++ b/src/library/scala/collection/mutable/QueueProxy.scala @@ -21,7 +21,7 @@ package mutable * @version 1.1, 03/05/2004 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait QueueProxy[A] extends Queue[A] with Proxy { def self: Queue[A] diff --git a/src/library/scala/collection/mutable/RedBlackTree.scala b/src/library/scala/collection/mutable/RedBlackTree.scala new file mode 100644 index 0000000000..e4793242bf --- /dev/null +++ b/src/library/scala/collection/mutable/RedBlackTree.scala @@ -0,0 +1,580 @@ +package scala.collection.mutable + +import scala.annotation.tailrec +import scala.collection.Iterator + +/** + * An object containing the red-black tree implementation used by mutable `TreeMaps`. + * + * The trees implemented in this object are *not* thread safe. + * + * @author Rui Gonçalves + * @version 2.12 + * @since 2.12 + */ +private[collection] object RedBlackTree { + + // ---- class structure ---- + + // For performance reasons, this implementation uses `null` references to represent leaves instead of a sentinel node. + // Currently, the internal nodes do not store their subtree size - only the tree object keeps track of their size. + // Therefore, while obtaining the size of the whole tree is O(1), knowing the number of entries inside a range is O(n) + // on the size of the range. + + @SerialVersionUID(21575944040195605L) + final class Tree[A, B](var root: Node[A, B], var size: Int) extends Serializable + + @SerialVersionUID(1950599696441054720L) + final class Node[A, B](var key: A, var value: B, var red: Boolean, + var left: Node[A, B], var right: Node[A, B], var parent: Node[A, B]) extends Serializable { + + override def toString: String = "Node(" + key + ", " + value + ", " + red + ", " + left + ", " + right + ")" + } + + object Tree { + def empty[A, B]: Tree[A, B] = new Tree(null, 0) + } + + object Node { + + @inline def apply[A, B](key: A, value: B, red: Boolean, + left: Node[A, B], right: Node[A, B], parent: Node[A, B]): Node[A, B] = + new Node(key, value, red, left, right, parent) + + @inline def leaf[A, B](key: A, value: B, red: Boolean, parent: Node[A, B]): Node[A, B] = + new Node(key, value, red, null, null, parent) + + def unapply[A, B](t: Node[A, B]) = Some((t.key, t.value, t.left, t.right, t.parent)) + } + + // ---- getters ---- + + def isRed(node: Node[_, _]) = (node ne null) && node.red + def isBlack(node: Node[_, _]) = (node eq null) || !node.red + + // ---- size ---- + + def size(node: Node[_, _]): Int = if (node eq null) 0 else 1 + size(node.left) + size(node.right) + def size(tree: Tree[_, _]): Int = tree.size + def isEmpty(tree: Tree[_, _]) = tree.root eq null + def clear(tree: Tree[_, _]): Unit = { tree.root = null; tree.size = 0 } + + // ---- search ---- + + def get[A: Ordering, B](tree: Tree[A, B], key: A): Option[B] = getNode(tree.root, key) match { + case null => None + case node => Some(node.value) + } + + @tailrec private[this] def getNode[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = + if (node eq null) null + else { + val cmp = ord.compare(key, node.key) + if (cmp < 0) getNode(node.left, key) + else if (cmp > 0) getNode(node.right, key) + else node + } + + def contains[A: Ordering](tree: Tree[A, _], key: A) = getNode(tree.root, key) ne null + + def min[A, B](tree: Tree[A, B]): Option[(A, B)] = minNode(tree.root) match { + case null => None + case node => Some((node.key, node.value)) + } + + def minKey[A](tree: Tree[A, _]): Option[A] = minNode(tree.root) match { + case null => None + case node => Some(node.key) + } + + private def minNode[A, B](node: Node[A, B]): Node[A, B] = + if (node eq null) null else minNodeNonNull(node) + + @tailrec def minNodeNonNull[A, B](node: Node[A, B]): Node[A, B] = + if (node.left eq null) node else minNodeNonNull(node.left) + + def max[A, B](tree: Tree[A, B]): Option[(A, B)] = maxNode(tree.root) match { + case null => None + case node => Some((node.key, node.value)) + } + + def maxKey[A](tree: Tree[A, _]): Option[A] = maxNode(tree.root) match { + case null => None + case node => Some(node.key) + } + + private def maxNode[A, B](node: Node[A, B]): Node[A, B] = + if (node eq null) null else maxNodeNonNull(node) + + @tailrec def maxNodeNonNull[A, B](node: Node[A, B]): Node[A, B] = + if (node.right eq null) node else maxNodeNonNull(node.right) + + /** + * Returns the first (lowest) map entry with a key equal or greater than `key`. Returns `None` if there is no such + * node. + */ + def minAfter[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] = + minNodeAfter(tree.root, key) match { + case null => None + case node => Some((node.key, node.value)) + } + + def minKeyAfter[A](tree: Tree[A, _], key: A)(implicit ord: Ordering[A]): Option[A] = + minNodeAfter(tree.root, key) match { + case null => None + case node => Some(node.key) + } + + private[this] def minNodeAfter[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = { + if (node eq null) null + else { + var y: Node[A, B] = null + var x = node + var cmp = 1 + while ((x ne null) && cmp != 0) { + y = x + cmp = ord.compare(key, x.key) + x = if (cmp < 0) x.left else x.right + } + if (cmp <= 0) y else successor(y) + } + } + + /** + * Returns the last (highest) map entry with a key smaller than `key`. Returns `None` if there is no such node. + */ + def maxBefore[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] = + maxNodeBefore(tree.root, key) match { + case null => None + case node => Some((node.key, node.value)) + } + + def maxKeyBefore[A](tree: Tree[A, _], key: A)(implicit ord: Ordering[A]): Option[A] = + maxNodeBefore(tree.root, key) match { + case null => None + case node => Some(node.key) + } + + private[this] def maxNodeBefore[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = { + if (node eq null) null + else { + var y: Node[A, B] = null + var x = node + var cmp = 1 + while ((x ne null) && cmp != 0) { + y = x + cmp = ord.compare(key, x.key) + x = if (cmp < 0) x.left else x.right + } + if (cmp > 0) y else predecessor(y) + } + } + + // ---- insertion ---- + + def insert[A, B](tree: Tree[A, B], key: A, value: B)(implicit ord: Ordering[A]): Unit = { + var y: Node[A, B] = null + var x = tree.root + var cmp = 1 + while ((x ne null) && cmp != 0) { + y = x + cmp = ord.compare(key, x.key) + x = if (cmp < 0) x.left else x.right + } + + if (cmp == 0) y.value = value + else { + val z = Node.leaf(key, value, red = true, y) + + if (y eq null) tree.root = z + else if (cmp < 0) y.left = z + else y.right = z + + fixAfterInsert(tree, z) + tree.size += 1 + } + } + + private[this] def fixAfterInsert[A, B](tree: Tree[A, B], node: Node[A, B]): Unit = { + var z = node + while (isRed(z.parent)) { + if (z.parent eq z.parent.parent.left) { + val y = z.parent.parent.right + if (isRed(y)) { + z.parent.red = false + y.red = false + z.parent.parent.red = true + z = z.parent.parent + } else { + if (z eq z.parent.right) { + z = z.parent + rotateLeft(tree, z) + } + z.parent.red = false + z.parent.parent.red = true + rotateRight(tree, z.parent.parent) + } + } else { // symmetric cases + val y = z.parent.parent.left + if (isRed(y)) { + z.parent.red = false + y.red = false + z.parent.parent.red = true + z = z.parent.parent + } else { + if (z eq z.parent.left) { + z = z.parent + rotateRight(tree, z) + } + z.parent.red = false + z.parent.parent.red = true + rotateLeft(tree, z.parent.parent) + } + } + } + tree.root.red = false + } + + // ---- deletion ---- + + def delete[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Unit = { + val z = getNode(tree.root, key) + if (z ne null) { + var y = z + var yIsRed = y.red + var x: Node[A, B] = null + var xParent: Node[A, B] = null + + if (z.left eq null) { + x = z.right + transplant(tree, z, z.right) + xParent = z.parent + } + else if (z.right eq null) { + x = z.left + transplant(tree, z, z.left) + xParent = z.parent + } + else { + y = minNodeNonNull(z.right) + yIsRed = y.red + x = y.right + + if (y.parent eq z) xParent = y + else { + xParent = y.parent + transplant(tree, y, y.right) + y.right = z.right + y.right.parent = y + } + transplant(tree, z, y) + y.left = z.left + y.left.parent = y + y.red = z.red + } + + if (!yIsRed) fixAfterDelete(tree, x, xParent) + tree.size -= 1 + } + } + + private[this] def fixAfterDelete[A, B](tree: Tree[A, B], node: Node[A, B], parent: Node[A, B]): Unit = { + var x = node + var xParent = parent + while ((x ne tree.root) && isBlack(x)) { + if (x eq xParent.left) { + var w = xParent.right + // assert(w ne null) + + if (w.red) { + w.red = false + xParent.red = true + rotateLeft(tree, xParent) + w = xParent.right + } + if (isBlack(w.left) && isBlack(w.right)) { + w.red = true + x = xParent + } else { + if (isBlack(w.right)) { + w.left.red = false + w.red = true + rotateRight(tree, w) + w = xParent.right + } + w.red = xParent.red + xParent.red = false + w.right.red = false + rotateLeft(tree, xParent) + x = tree.root + } + } else { // symmetric cases + var w = xParent.left + // assert(w ne null) + + if (w.red) { + w.red = false + xParent.red = true + rotateRight(tree, xParent) + w = xParent.left + } + if (isBlack(w.right) && isBlack(w.left)) { + w.red = true + x = xParent + } else { + if (isBlack(w.left)) { + w.right.red = false + w.red = true + rotateLeft(tree, w) + w = xParent.left + } + w.red = xParent.red + xParent.red = false + w.left.red = false + rotateRight(tree, xParent) + x = tree.root + } + } + xParent = x.parent + } + if (x ne null) x.red = false + } + + // ---- helpers ---- + + /** + * Returns the node that follows `node` in an in-order tree traversal. If `node` has the maximum key (and is, + * therefore, the last node), this method returns `null`. + */ + private[this] def successor[A, B](node: Node[A, B]): Node[A, B] = { + if (node.right ne null) minNodeNonNull(node.right) + else { + var x = node + var y = x.parent + while ((y ne null) && (x eq y.right)) { + x = y + y = y.parent + } + y + } + } + + /** + * Returns the node that precedes `node` in an in-order tree traversal. If `node` has the minimum key (and is, + * therefore, the first node), this method returns `null`. + */ + private[this] def predecessor[A, B](node: Node[A, B]): Node[A, B] = { + if (node.left ne null) maxNodeNonNull(node.left) + else { + var x = node + var y = x.parent + while ((y ne null) && (x eq y.left)) { + x = y + y = y.parent + } + y + } + } + + private[this] def rotateLeft[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) { + // assert(x.right ne null) + val y = x.right + x.right = y.left + + if (y.left ne null) y.left.parent = x + y.parent = x.parent + + if (x.parent eq null) tree.root = y + else if (x eq x.parent.left) x.parent.left = y + else x.parent.right = y + + y.left = x + x.parent = y + } + + private[this] def rotateRight[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) { + // assert(x.left ne null) + val y = x.left + x.left = y.right + + if (y.right ne null) y.right.parent = x + y.parent = x.parent + + if (x.parent eq null) tree.root = y + else if (x eq x.parent.right) x.parent.right = y + else x.parent.left = y + + y.right = x + x.parent = y + } + + /** + * Transplant the node `from` to the place of node `to`. This is done by setting `from` as a child of `to`'s previous + * parent and setting `from`'s parent to the `to`'s previous parent. The children of `from` are left unchanged. + */ + private[this] def transplant[A, B](tree: Tree[A, B], to: Node[A, B], from: Node[A, B]): Unit = { + if (to.parent eq null) tree.root = from + else if (to eq to.parent.left) to.parent.left = from + else to.parent.right = from + + if (from ne null) from.parent = to.parent + } + + // ---- tree traversal ---- + + def foreach[A, B, U](tree: Tree[A, B], f: ((A, B)) => U): Unit = foreachNode(tree.root, f) + + private[this] def foreachNode[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit = + if (node ne null) foreachNodeNonNull(node, f) + + private[this] def foreachNodeNonNull[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit = { + if (node.left ne null) foreachNodeNonNull(node.left, f) + f((node.key, node.value)) + if (node.right ne null) foreachNodeNonNull(node.right, f) + } + + def foreachKey[A, U](tree: Tree[A, _], f: A => U): Unit = foreachNodeKey(tree.root, f) + + private[this] def foreachNodeKey[A, U](node: Node[A, _], f: A => U): Unit = + if (node ne null) foreachNodeKeyNonNull(node, f) + + private[this] def foreachNodeKeyNonNull[A, U](node: Node[A, _], f: A => U): Unit = { + if (node.left ne null) foreachNodeKeyNonNull(node.left, f) + f(node.key) + if (node.right ne null) foreachNodeKeyNonNull(node.right, f) + } + + def transform[A, B](tree: Tree[A, B], f: (A, B) => B): Unit = transformNode(tree.root, f) + + private[this] def transformNode[A, B, U](node: Node[A, B], f: (A, B) => B): Unit = + if (node ne null) transformNodeNonNull(node, f) + + private[this] def transformNodeNonNull[A, B, U](node: Node[A, B], f: (A, B) => B): Unit = { + if (node.left ne null) transformNodeNonNull(node.left, f) + node.value = f(node.key, node.value) + if (node.right ne null) transformNodeNonNull(node.right, f) + } + + def iterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[(A, B)] = + new EntriesIterator(tree, start, end) + + def keysIterator[A: Ordering](tree: Tree[A, _], start: Option[A] = None, end: Option[A] = None): Iterator[A] = + new KeysIterator(tree, start, end) + + def valuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[B] = + new ValuesIterator(tree, start, end) + + private[this] abstract class TreeIterator[A, B, R](tree: Tree[A, B], start: Option[A], end: Option[A]) + (implicit ord: Ordering[A]) extends Iterator[R] { + + protected[this] def nextResult(node: Node[A, B]): R + + def hasNext: Boolean = nextNode ne null + + def next(): R = nextNode match { + case null => throw new NoSuchElementException("next on empty iterator") + case node => + nextNode = successor(node) + setNullIfAfterEnd() + nextResult(node) + } + + private[this] var nextNode: Node[A, B] = start match { + case None => minNode(tree.root) + case Some(from) => minNodeAfter(tree.root, from) + } + + private[this] def setNullIfAfterEnd(): Unit = + if (end.isDefined && (nextNode ne null) && ord.compare(nextNode.key, end.get) >= 0) + nextNode = null + + setNullIfAfterEnd() + } + + private[this] final class EntriesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + extends TreeIterator[A, B, (A, B)](tree, start, end) { + + def nextResult(node: Node[A, B]) = (node.key, node.value) + } + + private[this] final class KeysIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + extends TreeIterator[A, B, A](tree, start, end) { + + def nextResult(node: Node[A, B]) = node.key + } + + private[this] final class ValuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A]) + extends TreeIterator[A, B, B](tree, start, end) { + + def nextResult(node: Node[A, B]) = node.value + } + + // ---- debugging ---- + + /** + * Checks if the tree is in a valid state. That happens if: + * - It is a valid binary search tree; + * - All red-black properties are satisfied; + * - All non-null nodes have their `parent` reference correct; + * - The size variable in `tree` corresponds to the actual size of the tree. + */ + def isValid[A: Ordering, B](tree: Tree[A, B]): Boolean = + isValidBST(tree.root) && hasProperParentRefs(tree) && isValidRedBlackTree(tree) && size(tree.root) == tree.size + + /** + * Returns true if all non-null nodes have their `parent` reference correct. + */ + private[this] def hasProperParentRefs[A, B](tree: Tree[A, B]): Boolean = { + + def hasProperParentRefs(node: Node[A, B]): Boolean = { + if (node eq null) true + else { + if ((node.left ne null) && (node.left.parent ne node) || + (node.right ne null) && (node.right.parent ne node)) false + else hasProperParentRefs(node.left) && hasProperParentRefs(node.right) + } + } + + if(tree.root eq null) true + else (tree.root.parent eq null) && hasProperParentRefs(tree.root) + } + + /** + * Returns true if this node follows the properties of a binary search tree. + */ + private[this] def isValidBST[A, B](node: Node[A, B])(implicit ord: Ordering[A]): Boolean = { + if (node eq null) true + else { + if ((node.left ne null) && (ord.compare(node.key, node.left.key) <= 0) || + (node.right ne null) && (ord.compare(node.key, node.right.key) >= 0)) false + else isValidBST(node.left) && isValidBST(node.right) + } + } + + /** + * Returns true if the tree has all the red-black tree properties: if the root node is black, if all children of red + * nodes are black and if the path from any node to any of its null children has the same number of black nodes. + */ + private[this] def isValidRedBlackTree[A, B](tree: Tree[A, B]): Boolean = { + + def noRedAfterRed(node: Node[A, B]): Boolean = { + if (node eq null) true + else if (node.red && (isRed(node.left) || isRed(node.right))) false + else noRedAfterRed(node.left) && noRedAfterRed(node.right) + } + + def blackHeight(node: Node[A, B]): Int = { + if (node eq null) 1 + else { + val lh = blackHeight(node.left) + val rh = blackHeight(node.right) + + if (lh == -1 || lh != rh) -1 + else if (isRed(node)) lh + else lh + 1 + } + } + + isBlack(tree.root) && noRedAfterRed(tree.root) && blackHeight(tree.root) >= 0 + } +} diff --git a/src/library/scala/collection/mutable/ResizableArray.scala b/src/library/scala/collection/mutable/ResizableArray.scala index c3047522e2..50d3513784 100644 --- a/src/library/scala/collection/mutable/ResizableArray.scala +++ b/src/library/scala/collection/mutable/ResizableArray.scala @@ -74,7 +74,7 @@ trait ResizableArray[A] extends IndexedSeq[A] */ override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) { val len1 = len min (xs.length - start) min length - Array.copy(array, 0, xs, start, len1) + if (len1 > 0) Array.copy(array, 0, xs, start, len1) } //########################################################################## @@ -101,7 +101,7 @@ trait ResizableArray[A] extends IndexedSeq[A] if (newSize > Int.MaxValue) newSize = Int.MaxValue val newArray: Array[AnyRef] = new Array(newSize.toInt) - scala.compat.Platform.arraycopy(array, 0, newArray, 0, size0) + java.lang.System.arraycopy(array, 0, newArray, 0, size0) array = newArray } } diff --git a/src/library/scala/collection/mutable/ReusableBuilder.scala b/src/library/scala/collection/mutable/ReusableBuilder.scala new file mode 100644 index 0000000000..dee2cd6393 --- /dev/null +++ b/src/library/scala/collection/mutable/ReusableBuilder.scala @@ -0,0 +1,49 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + +package scala +package collection +package mutable + +/** `ReusableBuilder` is a marker trait that indicates that a `Builder` + * can be reused to build more than one instance of a collection. In + * particular, calling `result` followed by `clear` will produce a + * collection and reset the builder to begin building a new collection + * of the same type. + * + * It is up to subclasses to implement this behavior, and to document any + * other behavior that varies from standard `ReusableBuilder` usage + * (e.g. operations being well-defined after a call to `result`, or allowing + * multiple calls to result to obtain different snapshots of a collection under + * construction). + * + * @tparam Elem the type of elements that get added to the builder. + * @tparam To the type of collection that it produced. + * + * @since 2.12 + */ +trait ReusableBuilder[-Elem, +To] extends Builder[Elem, To] { + /** Clears the contents of this builder. + * After execution of this method, the builder will contain no elements. + * + * If executed immediately after a call to `result`, this allows a new + * instance of the same type of collection to be built. + */ + override def clear(): Unit // Note: overriding for Scaladoc only! + + /** Produces a collection from the added elements. + * + * After a call to `result`, the behavior of all other methods is undefined + * save for `clear`. If `clear` is called, then the builder is reset and + * may be used to build another instance. + * + * @return a collection containing the elements added to this builder. + */ + override def result(): To // Note: overriding for Scaladoc only! +} diff --git a/src/library/scala/collection/mutable/SetBuilder.scala b/src/library/scala/collection/mutable/SetBuilder.scala index 01bfdc96ed..5d1e9ffc3a 100644 --- a/src/library/scala/collection/mutable/SetBuilder.scala +++ b/src/library/scala/collection/mutable/SetBuilder.scala @@ -17,7 +17,9 @@ package mutable * @param empty The empty element of the collection. * @since 2.8 */ -class SetBuilder[A, Coll <: scala.collection.Set[A] with scala.collection.SetLike[A, Coll]](empty: Coll) extends Builder[A, Coll] { +class SetBuilder[A, Coll <: scala.collection.Set[A] +with scala.collection.SetLike[A, Coll]](empty: Coll) +extends ReusableBuilder[A, Coll] { protected var elems: Coll = empty def +=(x: A): this.type = { elems = elems + x; this } def clear() { elems = empty } diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala index 01075a2633..0797a83154 100644 --- a/src/library/scala/collection/mutable/SetLike.scala +++ b/src/library/scala/collection/mutable/SetLike.scala @@ -72,6 +72,17 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] protected[this] override def parCombiner = ParSet.newCombiner[A] + /** Converts this $coll to a sequence. + * + * ```Note```: assumes a fast `size` method. Subclasses should override if this is not true. + */ + override def toSeq: collection.Seq[A] = { + // ArrayBuffer for efficiency, preallocated to the right size. + val result = new ArrayBuffer[A](size) + foreach(result += _) + result + } + /** Adds an element to this $coll. * * @param elem the element to be added @@ -213,7 +224,7 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] * @throws UnsupportedOperationException * if the message was not understood. */ - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") def <<(cmd: Message[A]): Unit = cmd match { case Include(_, x) => this += x case Remove(_, x) => this -= x diff --git a/src/library/scala/collection/mutable/SetProxy.scala b/src/library/scala/collection/mutable/SetProxy.scala index 74279507ff..43b6aa57af 100644 --- a/src/library/scala/collection/mutable/SetProxy.scala +++ b/src/library/scala/collection/mutable/SetProxy.scala @@ -18,7 +18,7 @@ package mutable * @version 1.1, 09/05/2004 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]] { override def repr = this override def empty = new SetProxy[A] { val self = SetProxy.this.self.empty } diff --git a/src/library/scala/collection/mutable/SortedMap.scala b/src/library/scala/collection/mutable/SortedMap.scala new file mode 100644 index 0000000000..806b30e79a --- /dev/null +++ b/src/library/scala/collection/mutable/SortedMap.scala @@ -0,0 +1,57 @@ +package scala +package collection +package mutable + +import generic._ + +/** + * A mutable map whose keys are sorted. + * + * @tparam A the type of the keys contained in this sorted map. + * @tparam B the type of the values associated with the keys. + * + * @author Rui Gonçalves + * @version 2.12 + * @since 2.12 + * + * @define Coll mutable.SortedMap + * @define coll mutable sorted map + */ +trait SortedMap[A, B] + extends Map[A, B] + with collection.SortedMap[A, B] + with MapLike[A, B, SortedMap[A, B]] + with SortedMapLike[A, B, SortedMap[A, B]] { + + override protected[this] def newBuilder: Builder[(A, B), SortedMap[A, B]] = SortedMap.newBuilder[A, B] + + override def empty: SortedMap[A, B] = SortedMap.empty + + override def updated[B1 >: B](key: A, value: B1): SortedMap[A, B1] = this + ((key, value)) + + override def +[B1 >: B](kv: (A, B1)): SortedMap[A, B1] = clone().asInstanceOf[SortedMap[A, B1]] += kv + + override def +[B1 >: B](elem1: (A, B1), elem2: (A, B1), elems: (A, B1)*): SortedMap[A, B1] = + clone().asInstanceOf[SortedMap[A, B1]] += elem1 += elem2 ++= elems + + override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): SortedMap[A, B1] = + clone().asInstanceOf[SortedMap[A, B1]] ++= xs.seq +} + +/** + * $factoryInfo + * + * @define Coll mutable.SortedMap + * @define coll mutable sorted map + */ +object SortedMap extends MutableSortedMapFactory[SortedMap] { + + def empty[A, B](implicit ord: Ordering[A]): SortedMap[A, B] = TreeMap.empty[A, B] + + /** $sortedMapCanBuildFromInfo */ + implicit def canBuildFrom[A, B](implicit ord: Ordering[A]): CanBuildFrom[Coll, (A, B), SortedMap[A, B]] = + new SortedMapCanBuildFrom[A, B] +} + +/** Explicit instantiation of the `SortedMap` trait to reduce class file size in subclasses. */ +abstract class AbstractSortedMap[A, B] extends scala.collection.mutable.AbstractMap[A, B] with SortedMap[A, B] diff --git a/src/library/scala/collection/mutable/SortedSet.scala b/src/library/scala/collection/mutable/SortedSet.scala index 0f2fa75abd..304469916d 100644 --- a/src/library/scala/collection/mutable/SortedSet.scala +++ b/src/library/scala/collection/mutable/SortedSet.scala @@ -43,8 +43,13 @@ trait SortedSet[A] extends scala.collection.SortedSet[A] with scala.collection.S * */ object SortedSet extends MutableSortedSetFactory[SortedSet] { - implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = new SortedSetCanBuildFrom[A] + def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = new SortedSetCanBuildFrom[A] def empty[A](implicit ord: Ordering[A]): SortedSet[A] = TreeSet.empty[A] + // Force a declaration here so that BitSet (which does not inherit from SortedSetFactory) can be more specific + override implicit def newCanBuildFrom[A](implicit ord : Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = super.newCanBuildFrom } + +/** Explicit instantiation of the `SortedSet` trait to reduce class file size in subclasses. */ +abstract class AbstractSortedSet[A] extends scala.collection.mutable.AbstractSet[A] with SortedSet[A] diff --git a/src/library/scala/collection/mutable/Stack.scala b/src/library/scala/collection/mutable/Stack.scala index 1a92f23b7b..28d50af1f9 100644 --- a/src/library/scala/collection/mutable/Stack.scala +++ b/src/library/scala/collection/mutable/Stack.scala @@ -54,6 +54,7 @@ object Stack extends SeqFactory[Stack] { * @define mayNotTerminateInf * @define willNotTerminateInf */ +@deprecated("Stack is an inelegant and potentially poorly-performing wrapper around List. Use a List assigned to a var instead.", "2.12.0") class Stack[A] private (var elems: List[A]) extends AbstractSeq[A] with Seq[A] diff --git a/src/library/scala/collection/mutable/StackProxy.scala b/src/library/scala/collection/mutable/StackProxy.scala index 81e63b05d2..ac52bbba21 100644 --- a/src/library/scala/collection/mutable/StackProxy.scala +++ b/src/library/scala/collection/mutable/StackProxy.scala @@ -19,7 +19,7 @@ package mutable * @version 1.0, 10/05/2004 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait StackProxy[A] extends Stack[A] with Proxy { def self: Stack[A] diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala index c56d40786e..b5b9498374 100644 --- a/src/library/scala/collection/mutable/StringBuilder.scala +++ b/src/library/scala/collection/mutable/StringBuilder.scala @@ -33,7 +33,7 @@ final class StringBuilder(private val underlying: JavaStringBuilder) with java.lang.CharSequence with IndexedSeq[Char] with StringLike[StringBuilder] - with Builder[Char, String] + with ReusableBuilder[Char, String] with Serializable { override protected[this] def thisCollection: StringBuilder = this @@ -435,7 +435,11 @@ final class StringBuilder(private val underlying: JavaStringBuilder) */ override def mkString = toString - /** Returns the result of this Builder (a String) + /** Returns the result of this Builder (a String). + * + * If this method is called multiple times, each call will result in a snapshot of the buffer at that point in time. + * In particular, a `StringBuilder` can be used to build multiple independent strings by emptying the buffer with `clear` + * after each call to `result`. * * @return the string assembled by this StringBuilder */ diff --git a/src/library/scala/collection/mutable/SynchronizedBuffer.scala b/src/library/scala/collection/mutable/SynchronizedBuffer.scala index 8c646b0ce5..9c27f8b003 100644 --- a/src/library/scala/collection/mutable/SynchronizedBuffer.scala +++ b/src/library/scala/collection/mutable/SynchronizedBuffer.scala @@ -25,7 +25,7 @@ import script._ * @define Coll `SynchronizedBuffer` * @define coll synchronized buffer */ -@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") +@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") trait SynchronizedBuffer[A] extends Buffer[A] { import scala.collection.Traversable @@ -162,7 +162,7 @@ trait SynchronizedBuffer[A] extends Buffer[A] { super.clear() } - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") override def <<(cmd: Message[A]): Unit = synchronized { super.<<(cmd) } diff --git a/src/library/scala/collection/mutable/SynchronizedMap.scala b/src/library/scala/collection/mutable/SynchronizedMap.scala index 9876296ebe..8618798dbd 100644 --- a/src/library/scala/collection/mutable/SynchronizedMap.scala +++ b/src/library/scala/collection/mutable/SynchronizedMap.scala @@ -24,7 +24,7 @@ import scala.annotation.migration * @define Coll `SynchronizedMap` * @define coll synchronized map */ -@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap as an alternative.", "2.11.0") +@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap as an alternative.", "2.11.0") trait SynchronizedMap[A, B] extends Map[A, B] { abstract override def get(key: A): Option[B] = synchronized { super.get(key) } @@ -54,7 +54,7 @@ trait SynchronizedMap[A, B] extends Map[A, B] { override def contains(key: A): Boolean = synchronized {super.contains(key) } override def isDefinedAt(key: A) = synchronized { super.isDefinedAt(key) } - // @deprecated("See Map.+ for explanation") override def +(kv: (A, B)): this.type = synchronized[this.type] { super.+(kv) } + // @deprecated("see Map.+ for explanation") override def +(kv: (A, B)): this.type = synchronized[this.type] { super.+(kv) } // can't override -, -- same type! // @deprecated override def -(key: A): Self = synchronized { super.-(key) } diff --git a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala b/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala deleted file mode 100644 index d3c0b85f69..0000000000 --- a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala +++ /dev/null @@ -1,101 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala -package collection -package mutable - -/** This class implements synchronized priority queues using a binary heap. - * The elements of the queue have to be ordered in terms of the `Ordered[T]` class. - * - * @tparam A type of the elements contained in this synchronized priority queue - * @param ord implicit ordering used to compared elements of type `A` - * - * @author Matthias Zenger - * @version 1.0, 03/05/2004 - * @since 1 - * @define Coll `SynchronizedPriorityQueue` - * @define coll synchronized priority queue - */ -@deprecated("Comprehensive synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentSkipListSet as an alternative.", "2.11.0") -class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQueue[A] { - - /** Checks if the queue is empty. - * - * @return true, iff there is no element in the queue. - */ - override def isEmpty: Boolean = synchronized { super.isEmpty } - - /** Inserts a single element into the priority queue. - * - * @param elem the element to insert - */ - override def +=(elem: A): this.type = { - synchronized { - super.+=(elem) - } - this - } - - /** Adds all elements of a traversable object into the priority queue. - * - * @param xs a traversable object - */ - override def ++=(xs: TraversableOnce[A]): this.type = { - synchronized { - super.++=(xs) - } - this - } - - /** Adds all elements to the queue. - * - * @param elems the elements to add. - */ - override def enqueue(elems: A*): Unit = synchronized { super.++=(elems) } - - /** Returns the element with the highest priority in the queue, - * and removes this element from the queue. - * - * @return the element with the highest priority. - */ - override def dequeue(): A = synchronized { super.dequeue() } - - /** Returns the element with the highest priority in the queue, - * or throws an error if there is no element contained in the queue. - * - * @return the element with the highest priority. - */ - override def head: A = synchronized { super.head } - - /** Removes all elements from the queue. After this operation is completed, - * the queue will be empty. - */ - override def clear(): Unit = synchronized { super.clear() } - - /** Returns an iterator which yield all the elements of the priority - * queue in descending priority order. - * - * @return an iterator over all elements sorted in descending order. - */ - override def iterator: Iterator[A] = synchronized { super.iterator } - - /** Checks if two queues are structurally identical. - * - * @return true, iff both queues contain the same sequence of elements. - */ - override def equals(that: Any): Boolean = synchronized { super.equals(that) } - - /** Returns a textual representation of a queue as a string. - * - * @return the string representation of this queue. - */ - override def toString(): String = synchronized { super.toString() } -} diff --git a/src/library/scala/collection/mutable/SynchronizedQueue.scala b/src/library/scala/collection/mutable/SynchronizedQueue.scala index 48e40ab27f..ee44f07df2 100644 --- a/src/library/scala/collection/mutable/SynchronizedQueue.scala +++ b/src/library/scala/collection/mutable/SynchronizedQueue.scala @@ -25,7 +25,7 @@ package mutable * @define Coll `SynchronizedQueue` * @define coll synchronized queue */ -@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") +@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") class SynchronizedQueue[A] extends Queue[A] { /** Checks if the queue is empty. * diff --git a/src/library/scala/collection/mutable/SynchronizedSet.scala b/src/library/scala/collection/mutable/SynchronizedSet.scala index dd842f26ce..399630eb3c 100644 --- a/src/library/scala/collection/mutable/SynchronizedSet.scala +++ b/src/library/scala/collection/mutable/SynchronizedSet.scala @@ -24,7 +24,7 @@ import script._ * @define Coll `SynchronizedSet` * @define coll synchronized set */ -@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap[A,Unit] as an alternative.", "2.11.0") +@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap[A,Unit] as an alternative.", "2.11.0") trait SynchronizedSet[A] extends Set[A] { abstract override def size: Int = synchronized { super.size @@ -94,7 +94,7 @@ trait SynchronizedSet[A] extends Set[A] { super.toString } - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") override def <<(cmd: Message[A]): Unit = synchronized { super.<<(cmd) } diff --git a/src/library/scala/collection/mutable/SynchronizedStack.scala b/src/library/scala/collection/mutable/SynchronizedStack.scala index bbb6f5a9bb..2954a1f768 100644 --- a/src/library/scala/collection/mutable/SynchronizedStack.scala +++ b/src/library/scala/collection/mutable/SynchronizedStack.scala @@ -25,9 +25,8 @@ package mutable * @define Coll `SynchronizedStack` * @define coll synchronized stack */ -@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.LinkedBlockingDequeue instead.", "2.11.0") +@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.LinkedBlockingDequeue instead.", "2.11.0") class SynchronizedStack[A] extends Stack[A] { - import scala.collection.Traversable /** Checks if the stack is empty. * diff --git a/src/library/scala/collection/mutable/TreeMap.scala b/src/library/scala/collection/mutable/TreeMap.scala new file mode 100644 index 0000000000..14ae7c9c8c --- /dev/null +++ b/src/library/scala/collection/mutable/TreeMap.scala @@ -0,0 +1,188 @@ +package scala +package collection +package mutable + +import scala.collection.generic._ +import scala.collection.mutable.{RedBlackTree => RB} + +/** + * $factoryInfo + * + * @define Coll mutable.TreeMap + * @define coll mutable tree map + */ +object TreeMap extends MutableSortedMapFactory[TreeMap] { + + def empty[A, B](implicit ord: Ordering[A]) = new TreeMap[A, B]()(ord) + + /** $sortedMapCanBuildFromInfo */ + implicit def canBuildFrom[A, B](implicit ord: Ordering[A]): CanBuildFrom[Coll, (A, B), TreeMap[A, B]] = + new SortedMapCanBuildFrom[A, B] +} + +/** + * A mutable sorted map implemented using a mutable red-black tree as underlying data structure. + * + * @param ordering the implicit ordering used to compare objects of type `A`. + * @tparam A the type of the keys contained in this tree map. + * @tparam B the type of the values associated with the keys. + * + * @author Rui Gonçalves + * @version 2.12 + * @since 2.12 + * + * @define Coll mutable.TreeMap + * @define coll mutable tree map + */ +@SerialVersionUID(-2558985573956740112L) +sealed class TreeMap[A, B] private (tree: RB.Tree[A, B])(implicit val ordering: Ordering[A]) + extends AbstractSortedMap[A, B] + with SortedMap[A, B] + with MapLike[A, B, TreeMap[A, B]] + with SortedMapLike[A, B, TreeMap[A, B]] + with Serializable { + + /** + * Creates an empty `TreeMap`. + * @param ord the implicit ordering used to compare objects of type `A`. + * @return an empty `TreeMap`. + */ + def this()(implicit ord: Ordering[A]) = this(RB.Tree.empty)(ord) + + override def empty = TreeMap.empty + override protected[this] def newBuilder = TreeMap.newBuilder[A, B] + + /** + * Creates a ranged projection of this map. Any mutations in the ranged projection will update the original map and + * vice versa. + * + * Only entries with keys between this projection's key range will ever appear as elements of this map, independently + * of whether the entries are added through the original map or through this view. That means that if one inserts a + * key-value in a view whose key is outside the view's bounds, calls to `get` or `contains` will _not_ consider the + * newly added entry. Mutations are always reflected in the original map, though. + * + * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower + * bound. + * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper + * bound. + */ + def rangeImpl(from: Option[A], until: Option[A]): TreeMap[A, B] = new TreeMapView(from, until) + + def -=(key: A): this.type = { RB.delete(tree, key); this } + def +=(kv: (A, B)): this.type = { RB.insert(tree, kv._1, kv._2); this } + + def get(key: A) = RB.get(tree, key) + + def iterator = RB.iterator(tree) + def iteratorFrom(start: A) = RB.iterator(tree, Some(start)) + def keysIteratorFrom(start: A) = RB.keysIterator(tree, Some(start)) + def valuesIteratorFrom(start: A) = RB.valuesIterator(tree, Some(start)) + + override def size = RB.size(tree) + override def isEmpty = RB.isEmpty(tree) + override def contains(key: A) = RB.contains(tree, key) + + override def head = RB.min(tree).get + override def headOption = RB.min(tree) + override def last = RB.max(tree).get + override def lastOption = RB.max(tree) + + override def keysIterator = RB.keysIterator(tree) + override def valuesIterator = RB.valuesIterator(tree) + + override def foreach[U](f: ((A, B)) => U): Unit = RB.foreach(tree, f) + override def transform(f: (A, B) => B) = { RB.transform(tree, f); this } + override def clear(): Unit = RB.clear(tree) + + override def stringPrefix = "TreeMap" + + /** + * A ranged projection of a [[TreeMap]]. Mutations on this map affect the original map and vice versa. + * + * Only entries with keys between this projection's key range will ever appear as elements of this map, independently + * of whether the entries are added through the original map or through this view. That means that if one inserts a + * key-value in a view whose key is outside the view's bounds, calls to `get` or `contains` will _not_ consider the + * newly added entry. Mutations are always reflected in the original map, though. + * + * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower + * bound. + * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper + * bound. + */ + @SerialVersionUID(2219159283273389116L) + private[this] final class TreeMapView(from: Option[A], until: Option[A]) extends TreeMap[A, B](tree) { + + /** + * Given a possible new lower bound, chooses and returns the most constraining one (the maximum). + */ + private[this] def pickLowerBound(newFrom: Option[A]): Option[A] = (from, newFrom) match { + case (Some(fr), Some(newFr)) => Some(ordering.max(fr, newFr)) + case (None, _) => newFrom + case _ => from + } + + /** + * Given a possible new upper bound, chooses and returns the most constraining one (the minimum). + */ + private[this] def pickUpperBound(newUntil: Option[A]): Option[A] = (until, newUntil) match { + case (Some(unt), Some(newUnt)) => Some(ordering.min(unt, newUnt)) + case (None, _) => newUntil + case _ => until + } + + /** + * Returns true if the argument is inside the view bounds (between `from` and `until`). + */ + private[this] def isInsideViewBounds(key: A): Boolean = { + val afterFrom = from.isEmpty || ordering.compare(from.get, key) <= 0 + val beforeUntil = until.isEmpty || ordering.compare(key, until.get) < 0 + afterFrom && beforeUntil + } + + override def rangeImpl(from: Option[A], until: Option[A]): TreeMap[A, B] = + new TreeMapView(pickLowerBound(from), pickUpperBound(until)) + + override def get(key: A) = if (isInsideViewBounds(key)) RB.get(tree, key) else None + + override def iterator = RB.iterator(tree, from, until) + override def iteratorFrom(start: A) = RB.iterator(tree, pickLowerBound(Some(start)), until) + override def keysIteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until) + override def valuesIteratorFrom(start: A) = RB.valuesIterator(tree, pickLowerBound(Some(start)), until) + + override def size = iterator.length + override def isEmpty = !iterator.hasNext + override def contains(key: A) = isInsideViewBounds(key) && RB.contains(tree, key) + + override def head = headOption.get + override def headOption = { + val entry = if (from.isDefined) RB.minAfter(tree, from.get) else RB.min(tree) + (entry, until) match { + case (Some(e), Some(unt)) if ordering.compare(e._1, unt) >= 0 => None + case _ => entry + } + } + + override def last = lastOption.get + override def lastOption = { + val entry = if (until.isDefined) RB.maxBefore(tree, until.get) else RB.max(tree) + (entry, from) match { + case (Some(e), Some(fr)) if ordering.compare(e._1, fr) < 0 => None + case _ => entry + } + } + + // Using the iterator should be efficient enough; if performance is deemed a problem later, specialized + // `foreach(f, from, until)` and `transform(f, from, until)` methods can be created in `RedBlackTree`. See + // https://github.com/scala/scala/pull/4608#discussion_r34307985 for a discussion about this. + override def foreach[U](f: ((A, B)) => U): Unit = iterator.foreach(f) + override def transform(f: (A, B) => B) = { + iterator.foreach { case (key, value) => update(key, f(key, value)) } + this + } + + override def valuesIterator: Iterator[B] = RB.valuesIterator(tree, from, until) + override def keysIterator: Iterator[A] = RB.keysIterator(tree, from, until) + + override def clone() = super.clone().rangeImpl(from, until) + } +} diff --git a/src/library/scala/collection/mutable/TreeSet.scala b/src/library/scala/collection/mutable/TreeSet.scala index f849eea569..ada6f145ad 100644 --- a/src/library/scala/collection/mutable/TreeSet.scala +++ b/src/library/scala/collection/mutable/TreeSet.scala @@ -11,8 +11,7 @@ package collection package mutable import generic._ -import scala.collection.immutable.{RedBlackTree => RB} -import scala.runtime.ObjectRef +import scala.collection.mutable.{RedBlackTree => RB} /** * @define Coll `mutable.TreeSet` @@ -29,88 +28,162 @@ object TreeSet extends MutableSortedSetFactory[TreeSet] { */ def empty[A](implicit ordering: Ordering[A]) = new TreeSet[A]() + /** $sortedMapCanBuildFromInfo */ + implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, TreeSet[A]] = + new SortedSetCanBuildFrom[A] } /** - * A mutable SortedSet using an immutable RedBlack Tree as underlying data structure. + * A mutable sorted set implemented using a mutable red-black tree as underlying data structure. * - * @author Lucien Pereira + * @param ordering the implicit ordering used to compare objects of type `A`. + * @tparam A the type of the keys contained in this tree set. + * + * @author Rui Gonçalves + * @version 2.12 + * @since 2.10 * + * @define Coll mutable.TreeSet + * @define coll mutable tree set */ -@deprecatedInheritance("TreeSet is not designed to enable meaningful subclassing.", "2.11.0") -class TreeSet[A] private (treeRef: ObjectRef[RB.Tree[A, Null]], from: Option[A], until: Option[A])(implicit val ordering: Ordering[A]) - extends SortedSet[A] with SetLike[A, TreeSet[A]] - with SortedSetLike[A, TreeSet[A]] with Set[A] with Serializable { +// Original API designed in part by Lucien Pereira +@SerialVersionUID(-3642111301929493640L) +sealed class TreeSet[A] private (tree: RB.Tree[A, Null])(implicit val ordering: Ordering[A]) + extends AbstractSortedSet[A] + with SortedSet[A] + with SetLike[A, TreeSet[A]] + with SortedSetLike[A, TreeSet[A]] + with Serializable { if (ordering eq null) throw new NullPointerException("ordering must not be null") - def this()(implicit ordering: Ordering[A]) = this(new ObjectRef(null), None, None) + /** + * Creates an empty `TreeSet`. + * @param ord the implicit ordering used to compare objects of type `A`. + * @return an empty `TreeSet`. + */ + def this()(implicit ord: Ordering[A]) = this(RB.Tree.empty)(ord) - override def size: Int = RB.countInRange(treeRef.elem, from, until) + override def empty = TreeSet.empty + override protected[this] def newBuilder = TreeSet.newBuilder[A] - override def stringPrefix = "TreeSet" + /** + * Creates a ranged projection of this set. Any mutations in the ranged projection affect will update the original set + * and vice versa. + * + * Only keys between this projection's key range will ever appear as elements of this set, independently of whether + * the elements are added through the original set or through this view. That means that if one inserts an element in + * a view whose key is outside the view's bounds, calls to `contains` will _not_ consider the newly added element. + * Mutations are always reflected in the original set, though. + * + * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower + * bound. + * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper + * bound. + */ + def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] = new TreeSetView(from, until) - override def empty: TreeSet[A] = TreeSet.empty + def -=(key: A): this.type = { RB.delete(tree, key); this } + def +=(elem: A): this.type = { RB.insert(tree, elem, null); this } - private def pickBound(comparison: (A, A) => A, oldBound: Option[A], newBound: Option[A]) = (newBound, oldBound) match { - case (Some(newB), Some(oldB)) => Some(comparison(newB, oldB)) - case (None, _) => oldBound - case _ => newBound - } + def contains(elem: A) = RB.contains(tree, elem) - override def rangeImpl(fromArg: Option[A], untilArg: Option[A]): TreeSet[A] = { - val newFrom = pickBound(ordering.max, fromArg, from) - val newUntil = pickBound(ordering.min, untilArg, until) + def iterator = RB.keysIterator(tree) + def keysIteratorFrom(start: A) = RB.keysIterator(tree, Some(start)) + override def iteratorFrom(start: A) = RB.keysIterator(tree, Some(start)) - new TreeSet(treeRef, newFrom, newUntil) - } + override def size = RB.size(tree) + override def isEmpty = RB.isEmpty(tree) - override def -=(elem: A): this.type = { - treeRef.elem = RB.delete(treeRef.elem, elem) - this - } + override def head = RB.minKey(tree).get + override def headOption = RB.minKey(tree) + override def last = RB.maxKey(tree).get + override def lastOption = RB.maxKey(tree) - override def +=(elem: A): this.type = { - treeRef.elem = RB.update(treeRef.elem, elem, null, overwrite = false) - this - } + override def foreach[U](f: A => U): Unit = RB.foreachKey(tree, f) + override def clear(): Unit = RB.clear(tree) + + override def stringPrefix = "TreeSet" /** - * Thanks to the immutable nature of the - * underlying Tree, we can share it with - * the clone. So clone complexity in time is O(1). + * A ranged projection of a [[TreeSet]]. Mutations on this set affect the original set and vice versa. * + * Only keys between this projection's key range will ever appear as elements of this set, independently of whether + * the elements are added through the original set or through this view. That means that if one inserts an element in + * a view whose key is outside the view's bounds, calls to `contains` will _not_ consider the newly added element. + * Mutations are always reflected in the original set, though. + * + * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower + * bound. + * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper + * bound. */ - override def clone(): TreeSet[A] = - new TreeSet[A](new ObjectRef(treeRef.elem), from, until) - - private val notProjection = !(from.isDefined || until.isDefined) + @SerialVersionUID(7087824939194006086L) + private[this] final class TreeSetView(from: Option[A], until: Option[A]) extends TreeSet[A](tree) { + + /** + * Given a possible new lower bound, chooses and returns the most constraining one (the maximum). + */ + private[this] def pickLowerBound(newFrom: Option[A]): Option[A] = (from, newFrom) match { + case (Some(fr), Some(newFr)) => Some(ordering.max(fr, newFr)) + case (None, _) => newFrom + case _ => from + } - override def contains(elem: A): Boolean = { - def leftAcceptable: Boolean = from match { - case Some(lb) => ordering.gteq(elem, lb) - case _ => true + /** + * Given a possible new upper bound, chooses and returns the most constraining one (the minimum). + */ + private[this] def pickUpperBound(newUntil: Option[A]): Option[A] = (until, newUntil) match { + case (Some(unt), Some(newUnt)) => Some(ordering.min(unt, newUnt)) + case (None, _) => newUntil + case _ => until } - def rightAcceptable: Boolean = until match { - case Some(ub) => ordering.lt(elem, ub) - case _ => true + /** + * Returns true if the argument is inside the view bounds (between `from` and `until`). + */ + private[this] def isInsideViewBounds(key: A): Boolean = { + val afterFrom = from.isEmpty || ordering.compare(from.get, key) <= 0 + val beforeUntil = until.isEmpty || ordering.compare(key, until.get) < 0 + afterFrom && beforeUntil } - (notProjection || (leftAcceptable && rightAcceptable)) && - RB.contains(treeRef.elem, elem) - } + override def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] = + new TreeSetView(pickLowerBound(from), pickUpperBound(until)) + + override def contains(key: A) = isInsideViewBounds(key) && RB.contains(tree, key) + + override def iterator = RB.keysIterator(tree, from, until) + override def keysIteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until) + override def iteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until) - override def iterator: Iterator[A] = iteratorFrom(None) + override def size = iterator.length + override def isEmpty = !iterator.hasNext - override def keysIteratorFrom(start: A) = iteratorFrom(Some(start)) + override def head = headOption.get + override def headOption = { + val elem = if (from.isDefined) RB.minKeyAfter(tree, from.get) else RB.minKey(tree) + (elem, until) match { + case (Some(e), Some(unt)) if ordering.compare(e, unt) >= 0 => None + case _ => elem + } + } - private def iteratorFrom(start: Option[A]) = { - val it = RB.keysIterator(treeRef.elem, pickBound(ordering.max, from, start)) - until match { - case None => it - case Some(ub) => it takeWhile (k => ordering.lt(k, ub)) + override def last = lastOption.get + override def lastOption = { + val elem = if (until.isDefined) RB.maxKeyBefore(tree, until.get) else RB.maxKey(tree) + (elem, from) match { + case (Some(e), Some(fr)) if ordering.compare(e, fr) < 0 => None + case _ => elem + } } + + // Using the iterator should be efficient enough; if performance is deemed a problem later, a specialized + // `foreachKey(f, from, until)` method can be created in `RedBlackTree`. See + // https://github.com/scala/scala/pull/4608#discussion_r34307985 for a discussion about this. + override def foreach[U](f: A => U): Unit = iterator.foreach(f) + + override def clone() = super.clone().rangeImpl(from, until) } } diff --git a/src/library/scala/collection/mutable/UnrolledBuffer.scala b/src/library/scala/collection/mutable/UnrolledBuffer.scala index 2212486bcf..b49d009a17 100644 --- a/src/library/scala/collection/mutable/UnrolledBuffer.scala +++ b/src/library/scala/collection/mutable/UnrolledBuffer.scala @@ -43,8 +43,7 @@ import scala.reflect.ClassTag * */ @SerialVersionUID(1L) -@deprecatedInheritance("UnrolledBuffer is not designed to enable meaningful subclassing.", "2.11.0") -class UnrolledBuffer[T](implicit val tag: ClassTag[T]) +sealed class UnrolledBuffer[T](implicit val tag: ClassTag[T]) extends scala.collection.mutable.AbstractBuffer[T] with scala.collection.mutable.Buffer[T] with scala.collection.mutable.BufferLike[T, UnrolledBuffer[T]] @@ -350,3 +349,11 @@ object UnrolledBuffer extends ClassTagTraversableFactory[UnrolledBuffer] { } } + + +// This is used by scala.collection.parallel.mutable.UnrolledParArrayCombiner: +// Todo -- revisit whether inheritance is the best way to achieve this functionality +private[collection] class DoublingUnrolledBuffer[T](implicit t: ClassTag[T]) extends UnrolledBuffer[T]()(t) { + override def calcNextLength(sz: Int) = if (sz < 10000) sz * 2 else sz + protected override def newUnrolled = new UnrolledBuffer.Unrolled[T](0, new Array[T](4), null, this) +} diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala index 8740bda835..0b5ebe7e9a 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -13,9 +13,12 @@ package collection package mutable import scala.reflect.ClassTag -import scala.runtime.ScalaRunTime._ +import scala.runtime.BoxedUnit import scala.collection.generic._ import scala.collection.parallel.mutable.ParArray +import scala.util.hashing.MurmurHash3 + +import java.util.Arrays /** * A class representing `Array[T]`. @@ -46,7 +49,7 @@ extends AbstractSeq[T] def elemTag: ClassTag[T] @deprecated("use elemTag instead", "2.10.0") - def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](arrayElementClass(elemTag).asInstanceOf[Class[T]]) + def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](elemTag.runtimeClass.asInstanceOf[Class[T]]) /** The length of the array */ def length: Int @@ -63,10 +66,10 @@ extends AbstractSeq[T] override def par = ParArray.handoff(array) private def elementClass: Class[_] = - arrayElementClass(array.getClass) + array.getClass.getComponentType override def toArray[U >: T : ClassTag]: Array[U] = { - val thatElementClass = arrayElementClass(implicitly[ClassTag[U]]) + val thatElementClass = implicitly[ClassTag[U]].runtimeClass if (elementClass eq thatElementClass) array.asInstanceOf[Array[U]] else @@ -122,10 +125,15 @@ object WrappedArray { def newBuilder[A]: Builder[A, IndexedSeq[A]] = new ArrayBuffer final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArray[T] with Serializable { - lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass)) + lazy val elemTag = ClassTag[T](array.getClass.getComponentType) def length: Int = array.length def apply(index: Int): T = array(index).asInstanceOf[T] def update(index: Int, elem: T) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofRef[_] => Arrays.equals(array.asInstanceOf[Array[AnyRef]], that.array.asInstanceOf[Array[AnyRef]]) + case _ => super.equals(that) + } } final class ofByte(val array: Array[Byte]) extends WrappedArray[Byte] with Serializable { @@ -133,6 +141,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Byte = array(index) def update(index: Int, elem: Byte) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedBytesHash(array) + override def equals(that: Any) = that match { + case that: ofByte => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofShort(val array: Array[Short]) extends WrappedArray[Short] with Serializable { @@ -140,6 +153,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Short = array(index) def update(index: Int, elem: Short) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofShort => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofChar(val array: Array[Char]) extends WrappedArray[Char] with Serializable { @@ -147,6 +165,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Char = array(index) def update(index: Int, elem: Char) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofChar => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofInt(val array: Array[Int]) extends WrappedArray[Int] with Serializable { @@ -154,6 +177,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Int = array(index) def update(index: Int, elem: Int) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofInt => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofLong(val array: Array[Long]) extends WrappedArray[Long] with Serializable { @@ -161,6 +189,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Long = array(index) def update(index: Int, elem: Long) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofLong => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofFloat(val array: Array[Float]) extends WrappedArray[Float] with Serializable { @@ -168,6 +201,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Float = array(index) def update(index: Int, elem: Float) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofFloat => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofDouble(val array: Array[Double]) extends WrappedArray[Double] with Serializable { @@ -175,6 +213,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Double = array(index) def update(index: Int, elem: Double) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofDouble => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofBoolean(val array: Array[Boolean]) extends WrappedArray[Boolean] with Serializable { @@ -182,6 +225,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Boolean = array(index) def update(index: Int, elem: Boolean) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofBoolean => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofUnit(val array: Array[Unit]) extends WrappedArray[Unit] with Serializable { @@ -189,5 +237,10 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Unit = array(index) def update(index: Int, elem: Unit) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofUnit => array.length == that.array.length + case _ => super.equals(that) + } } } diff --git a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala index 5781ec91be..5bc5811450 100644 --- a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala +++ b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala @@ -13,16 +13,17 @@ package collection package mutable import scala.reflect.ClassTag -import scala.runtime.ScalaRunTime._ /** A builder class for arrays. * + * This builder can be reused. + * * @tparam A type of elements that can be added to this builder. * @param tag class tag for objects of type `A`. * * @since 2.8 */ -class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A]] { +class WrappedArrayBuilder[A](tag: ClassTag[A]) extends ReusableBuilder[A, WrappedArray[A]] { @deprecated("use tag instead", "2.10.0") val manifest: ClassTag[A] = tag @@ -32,7 +33,7 @@ class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A private var size: Int = 0 private def mkArray(size: Int): WrappedArray[A] = { - val runtimeClass = arrayElementClass(tag) + val runtimeClass = tag.runtimeClass val newelems = runtimeClass match { case java.lang.Byte.TYPE => new WrappedArray.ofByte(new Array[Byte](size)).asInstanceOf[WrappedArray[A]] case java.lang.Short.TYPE => new WrappedArray.ofShort(new Array[Short](size)).asInstanceOf[WrappedArray[A]] @@ -73,9 +74,7 @@ class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A this } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { diff --git a/src/library/scala/collection/package.scala b/src/library/scala/collection/package.scala index 856f901b77..6df254c0e0 100644 --- a/src/library/scala/collection/package.scala +++ b/src/library/scala/collection/package.scala @@ -76,13 +76,9 @@ package scala * The concrete parallel collections also have specific performance characteristics which are * described in [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#performance-characteristics the parallel collections guide]] * - * === Converting between Java Collections === + * === Converting to and from Java Collections === * - * The [[scala.collection.JavaConversions]] object provides implicit defs that - * will allow mostly seamless integration between APIs using Java Collections - * and the Scala collections library. - * - * Alternatively the [[scala.collection.JavaConverters]] object provides a collection + * The [[scala.collection.JavaConverters]] object provides a collection * of decorators that allow converting between Scala and Java collections using `asScala` * and `asJava` methods. */ diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 8c9b959569..2e60089df5 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -9,6 +9,8 @@ package scala package collection.parallel +import scala.language.{ higherKinds, implicitConversions } + import scala.collection.mutable.Builder import scala.collection.mutable.ArrayBuffer import scala.collection.IterableLike @@ -21,13 +23,9 @@ import scala.collection.GenIterable import scala.collection.GenTraversableOnce import scala.collection.GenTraversable import immutable.HashMapCombiner -import scala.reflect.{ClassTag, classTag} - -import java.util.concurrent.atomic.AtomicBoolean +import scala.reflect.ClassTag import scala.annotation.unchecked.uncheckedVariance -import scala.annotation.unchecked.uncheckedStable -import scala.language.{ higherKinds, implicitConversions } import scala.collection.parallel.ParallelCollectionImplicits._ @@ -195,7 +193,7 @@ self: ParIterableLike[T, Repr, Sequential] => * import scala.collection.parallel._ * val pc = mutable.ParArray(1, 2, 3) * pc.tasksupport = new ForkJoinTaskSupport( - * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * new java.util.concurrent.ForkJoinPool(2)) * }}} * * @see [[scala.collection.parallel.TaskSupport]] @@ -844,7 +842,7 @@ self: ParIterableLike[T, Repr, Sequential] => tasksupport.executeAndWaitResult(new ToParMap(combinerFactory(cbf), splitter)(ev) mapResult { _.resultWithTaskSupport }) } - @deprecated("Use .seq.view instead", "2.11.0") + @deprecated("use .seq.view instead", "2.11.0") def view = seq.view override def toArray[U >: T: ClassTag]: Array[U] = { @@ -1284,7 +1282,7 @@ self: ParIterableLike[T, Repr, Sequential] => extends Transformer[Combiner[(U, S), That], Zip[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](othpit, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling val sizes = pits.map(_.remaining) @@ -1300,7 +1298,7 @@ self: ParIterableLike[T, Repr, Sequential] => extends Transformer[Combiner[(U, S), That], ZipAll[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zipAll2combiner[U, S, That](othpit, thiselem, thatelem, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = if (pit.remaining <= len) { val pits = pit.splitWithSignalling val sizes = pits.map(_.remaining) @@ -1322,7 +1320,7 @@ self: ParIterableLike[T, Repr, Sequential] => extends Accessor[Unit, CopyToArray[U, This]] { @volatile var result: Unit = () def leaf(prev: Option[Unit]) = pit.copyToArray(array, from, len) - protected[this] def newSubtask(p: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(0)(_ + _.remaining); if untilp < len) yield { @@ -1379,7 +1377,7 @@ self: ParIterableLike[T, Repr, Sequential] => val half = howmany / 2 ScanNode(mergeTrees(trees, from, half), mergeTrees(trees, from + half, howmany - half)) } else trees(from) - protected[this] def newSubtask(pit: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(pit: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(from)(_ + _.remaining)) yield { @@ -1416,7 +1414,7 @@ self: ParIterableLike[T, Repr, Sequential] => new FromScanTree(left, z, op, cbf), new FromScanTree(right, z, op, cbf) ) - case _ => unsupportedop("Cannot be split further") + case _ => throw new UnsupportedOperationException("Cannot be split further") } def shouldSplitFurther = tree match { case ScanNode(_, _) => true diff --git a/src/library/scala/collection/parallel/ParMap.scala b/src/library/scala/collection/parallel/ParMap.scala index 9f92e6c1e8..70afe5174b 100644 --- a/src/library/scala/collection/parallel/ParMap.scala +++ b/src/library/scala/collection/parallel/ParMap.scala @@ -11,7 +11,6 @@ package collection.parallel import scala.collection.Map import scala.collection.GenMap -import scala.collection.mutable.Builder import scala.collection.generic.ParMapFactory import scala.collection.generic.GenericParMapTemplate import scala.collection.generic.GenericParMapCompanion diff --git a/src/library/scala/collection/parallel/ParMapLike.scala b/src/library/scala/collection/parallel/ParMapLike.scala index 0a671fb085..a3ac388587 100644 --- a/src/library/scala/collection/parallel/ParMapLike.scala +++ b/src/library/scala/collection/parallel/ParMapLike.scala @@ -12,10 +12,8 @@ package collection.parallel import scala.collection.MapLike import scala.collection.GenMapLike import scala.collection.Map -import scala.collection.mutable.Builder + import scala.annotation.unchecked.uncheckedVariance -import scala.collection.generic.IdleSignalling -import scala.collection.generic.Signalling /** A template trait for mutable parallel maps. This trait is to be mixed in * with concrete parallel maps to override the representation type. diff --git a/src/library/scala/collection/parallel/ParSeqLike.scala b/src/library/scala/collection/parallel/ParSeqLike.scala index 0b6fec364e..60fa1858e7 100644 --- a/src/library/scala/collection/parallel/ParSeqLike.scala +++ b/src/library/scala/collection/parallel/ParSeqLike.scala @@ -9,11 +9,10 @@ package scala package collection.parallel -import scala.collection.{ Parallel, SeqLike, GenSeqLike, GenSeq, GenIterable, Iterator } +import scala.collection.{ SeqLike, GenSeq, GenIterable, Iterator } import scala.collection.generic.DefaultSignalling import scala.collection.generic.AtomicIndexFlag import scala.collection.generic.CanBuildFrom -import scala.collection.generic.CanCombineFrom import scala.collection.generic.VolatileAbort import scala.collection.parallel.ParallelCollectionImplicits._ @@ -365,7 +364,7 @@ self => pit.setIndexFlagIfLesser(from) } } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(from)(_ + _.remaining)) yield new IndexWhere(pred, untilp, p) @@ -386,7 +385,7 @@ self => pit.setIndexFlagIfGreater(pos) } } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(pos)(_ + _.remaining)) yield new LastIndexWhere(pred, untilp, p) @@ -420,7 +419,7 @@ self => result = pit.sameElements(otherpit) if (!result) pit.abort() } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val fp = pit.remaining / 2 val sp = pit.remaining - fp @@ -434,7 +433,7 @@ self => extends Transformer[Combiner[U, That], Updated[U, That]] { @volatile var result: Combiner[U, That] = null def leaf(prev: Option[Combiner[U, That]]) = result = pit.updated2combiner(pos, elem, pbf()) - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(0)(_ + _.remaining)) yield new Updated(pos - untilp, elem, pbf, p) @@ -447,7 +446,7 @@ self => extends Transformer[Combiner[(U, S), That], Zip[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](otherpit, cf()) - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val fp = len / 2 val sp = len - len / 2 @@ -468,7 +467,7 @@ self => result = pit.corresponds(corr)(otherpit) if (!result) pit.abort() } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val fp = pit.remaining / 2 val sp = pit.remaining - fp diff --git a/src/library/scala/collection/parallel/RemainsIterator.scala b/src/library/scala/collection/parallel/RemainsIterator.scala index 5f2ceac0e0..63d63d9ef3 100644 --- a/src/library/scala/collection/parallel/RemainsIterator.scala +++ b/src/library/scala/collection/parallel/RemainsIterator.scala @@ -9,13 +9,10 @@ package scala package collection.parallel -import scala.collection.Parallel import scala.collection.generic.Signalling import scala.collection.generic.DelegatedSignalling import scala.collection.generic.IdleSignalling -import scala.collection.generic.CanCombineFrom import scala.collection.mutable.Builder -import scala.collection.Iterator.empty import scala.collection.GenTraversableOnce import scala.collection.parallel.immutable.repetition @@ -456,6 +453,15 @@ self => } it } + /** Drop implemented as simple eager consumption. */ + override def drop(n: Int): IterableSplitter[T] = { + var i = 0 + while (i < n && hasNext) { + next() + i += 1 + } + this + } override def take(n: Int): IterableSplitter[T] = newTaken(n) override def slice(from1: Int, until1: Int): IterableSplitter[T] = newSliceInternal(newTaken(until1), from1) diff --git a/src/library/scala/collection/parallel/TaskSupport.scala b/src/library/scala/collection/parallel/TaskSupport.scala index 9064018d46..4d633253ce 100644 --- a/src/library/scala/collection/parallel/TaskSupport.scala +++ b/src/library/scala/collection/parallel/TaskSupport.scala @@ -10,13 +10,13 @@ package scala package collection.parallel import java.util.concurrent.ThreadPoolExecutor -import scala.concurrent.forkjoin.ForkJoinPool +import java.util.concurrent.ForkJoinPool import scala.concurrent.ExecutionContext /** A trait implementing the scheduling of a parallel collection operation. * * Parallel collections are modular in the way operations are scheduled. Each - * parallel collection is parametrized with a task support object which is + * parallel collection is parameterized with a task support object which is * responsible for scheduling and load-balancing tasks to processors. * * A task support object can be changed in a parallel collection after it has @@ -41,7 +41,7 @@ import scala.concurrent.ExecutionContext * import scala.collection.parallel._ * val pc = mutable.ParArray(1, 2, 3) * pc.tasksupport = new ForkJoinTaskSupport( - * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * new java.util.concurrent.ForkJoinPool(2)) * }}} * * @see [[http://docs.scala-lang.org/overviews/parallel-collections/configuration.html Configuring Parallel Collections]] section @@ -60,7 +60,7 @@ extends TaskSupport with AdaptiveWorkStealingForkJoinTasks * * @see [[scala.collection.parallel.TaskSupport]] for more information. */ -@deprecated("Use `ForkJoinTaskSupport` instead.", "2.11.0") +@deprecated("use `ForkJoinTaskSupport` instead", "2.11.0") class ThreadPoolTaskSupport(val environment: ThreadPoolExecutor = ThreadPoolTasks.defaultThreadPool) extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks @@ -71,7 +71,7 @@ extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks * forkjoin based task support or a thread pool executor one, depending on * what the execution context uses. * - * By default, parallel collections are parametrized with this task support + * By default, parallel collections are parameterized with this task support * object, so parallel collections share the same execution context backend * as the rest of the `scala.concurrent` package. * diff --git a/src/library/scala/collection/parallel/Tasks.scala b/src/library/scala/collection/parallel/Tasks.scala index fcf0dff846..f472c6be5c 100644 --- a/src/library/scala/collection/parallel/Tasks.scala +++ b/src/library/scala/collection/parallel/Tasks.scala @@ -10,7 +10,7 @@ package scala package collection.parallel import java.util.concurrent.ThreadPoolExecutor -import scala.concurrent.forkjoin._ +import java.util.concurrent.{ForkJoinPool, RecursiveAction, ForkJoinWorkerThread} import scala.concurrent.ExecutionContext import scala.util.control.Breaks._ import scala.annotation.unchecked.uncheckedVariance @@ -66,13 +66,10 @@ trait Task[R, +Tp] { } private[parallel] def mergeThrowables(that: Task[_, _]) { - // TODO: As soon as we target Java >= 7, use Throwable#addSuppressed - // to pass additional Throwables to the caller, e. g. - // if (this.throwable != null && that.throwable != null) - // this.throwable.addSuppressed(that.throwable) - // For now, we just use whatever Throwable comes across “first”. - if (this.throwable == null && that.throwable != null) - this.throwable = that.throwable + if (this.throwable != null && that.throwable != null) + this.throwable.addSuppressed(that.throwable) + else if (this.throwable == null && that.throwable != null) + this.throwable = that.throwable } // override in concrete task implementations to signal abort to other tasks @@ -211,7 +208,7 @@ trait AdaptiveWorkStealingTasks extends Tasks { /** An implementation of tasks objects based on the Java thread pooling API. */ -@deprecated("Use `ForkJoinTasks` instead.", "2.11.0") +@deprecated("use `ForkJoinTasks` instead", "2.11.0") trait ThreadPoolTasks extends Tasks { import java.util.concurrent._ @@ -320,7 +317,7 @@ trait ThreadPoolTasks extends Tasks { } -@deprecated("Use `ForkJoinTasks` instead.", "2.11.0") +@deprecated("use `ForkJoinTasks` instead", "2.11.0") object ThreadPoolTasks { import java.util.concurrent._ @@ -448,7 +445,7 @@ trait AdaptiveWorkStealingForkJoinTasks extends ForkJoinTasks with AdaptiveWorkS def newWrappedTask[R, Tp](b: Task[R, Tp]) = new WrappedTask[R, Tp](b) } -@deprecated("Use `AdaptiveWorkStealingForkJoinTasks` instead.", "2.11.0") +@deprecated("use `AdaptiveWorkStealingForkJoinTasks` instead", "2.11.0") trait AdaptiveWorkStealingThreadPoolTasks extends ThreadPoolTasks with AdaptiveWorkStealingTasks { class WrappedTask[R, Tp](val body: Task[R, Tp]) @@ -526,7 +523,7 @@ private[parallel] final class FutureTasks(executor: ExecutionContext) extends Ta } /** This tasks implementation uses execution contexts to spawn a parallel computation. - * + * * As an optimization, it internally checks whether the execution context is the * standard implementation based on fork/join pools, and if it is, creates a * `ForkJoinTaskSupport` that shares the same pool to forward its request to it. @@ -540,7 +537,7 @@ trait ExecutionContextTasks extends Tasks { val environment: ExecutionContext /** A driver serves as a target for this proxy `Tasks` object. - * + * * If the execution context has the standard implementation and uses fork/join pools, * the driver is `ForkJoinTaskSupport` with the same pool, as an optimization. * Otherwise, the driver will be a Scala `Future`-based implementation. diff --git a/src/library/scala/collection/parallel/immutable/ParHashSet.scala b/src/library/scala/collection/parallel/immutable/ParHashSet.scala index 65a632470e..3a1ec7fff8 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashSet.scala @@ -197,7 +197,7 @@ extends scala.collection.parallel.BucketCombiner[T, ParHashSet[T], Any, HashSetC while (i < chunksz) { val v = chunkarr(i).asInstanceOf[T] val hc = trie.computeHash(v) - trie = trie.updated0(v, hc, rootbits) + trie = trie.updated0(v, hc, rootbits) // internal API, private[collection] i += 1 } i = 0 diff --git a/src/library/scala/collection/parallel/immutable/ParMap.scala b/src/library/scala/collection/parallel/immutable/ParMap.scala index 2956c2a883..65bb2e12c5 100644 --- a/src/library/scala/collection/parallel/immutable/ParMap.scala +++ b/src/library/scala/collection/parallel/immutable/ParMap.scala @@ -16,7 +16,6 @@ import scala.collection.generic.GenericParMapCompanion import scala.collection.generic.CanCombineFrom import scala.collection.parallel.ParMapLike import scala.collection.parallel.Combiner -import scala.collection.GenMapLike /** A template trait for immutable parallel maps. * diff --git a/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala index ec90de3a7d..de2b53a6c0 100644 --- a/src/library/scala/collection/parallel/immutable/ParRange.scala +++ b/src/library/scala/collection/parallel/immutable/ParRange.scala @@ -12,7 +12,6 @@ package collection.parallel.immutable import scala.collection.immutable.Range import scala.collection.parallel.Combiner import scala.collection.parallel.SeqSplitter -import scala.collection.generic.CanCombineFrom import scala.collection.Iterator /** Parallel ranges. @@ -108,6 +107,7 @@ self => } } + override def toString = s"Par$range" } object ParRange { diff --git a/src/library/scala/collection/parallel/immutable/package.scala b/src/library/scala/collection/parallel/immutable/package.scala index 8fd84eaf4d..3cafdba5f7 100644 --- a/src/library/scala/collection/parallel/immutable/package.scala +++ b/src/library/scala/collection/parallel/immutable/package.scala @@ -20,7 +20,12 @@ package immutable { self => def apply(idx: Int) = if (0 <= idx && idx < length) elem else throw new IndexOutOfBoundsException("" + idx) - override def seq = throw new UnsupportedOperationException + override def seq: collection.immutable.Seq[T] = new collection.AbstractSeq[T] with collection.immutable.Seq[T] { + override def length: Int = self.length + override def apply(idx: Int): T = self.apply(idx) + override def iterator: Iterator[T] = Iterator.continually(elem).take(length) + override def par: ParSeq[T] = self + } def update(idx: Int, elem: T) = throw new UnsupportedOperationException class ParIterator(var i: Int = 0, val until: Int = length, elem: T = self.elem) extends SeqSplitter[T] { diff --git a/src/library/scala/collection/parallel/mutable/LazyCombiner.scala b/src/library/scala/collection/parallel/mutable/LazyCombiner.scala index 5ab2bb81c6..cc25b5b4b2 100644 --- a/src/library/scala/collection/parallel/mutable/LazyCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/LazyCombiner.scala @@ -30,7 +30,6 @@ trait LazyCombiner[Elem, +To, Buff <: Growable[Elem] with Sizing] extends Combin def result: To = allocateAndCopy def clear() = { chain.clear() } def combine[N <: Elem, NewTo >: To](other: Combiner[N, NewTo]): Combiner[N, NewTo] = if (this ne other) { - import language.existentials // FIXME: See SI-7750 if (other.isInstanceOf[LazyCombiner[_, _, _]]) { val that = other.asInstanceOf[LazyCombiner[Elem, To, Buff]] newLazyCombiner(chain ++= that.chain) diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala index d0d022db4b..8a2cf2716a 100644 --- a/src/library/scala/collection/parallel/mutable/ParArray.scala +++ b/src/library/scala/collection/parallel/mutable/ParArray.scala @@ -18,7 +18,6 @@ import scala.collection.generic.GenericParCompanion import scala.collection.generic.CanCombineFrom import scala.collection.generic.CanBuildFrom import scala.collection.generic.ParFactory -import scala.collection.generic.Sizing import scala.collection.parallel.Combiner import scala.collection.parallel.SeqSplitter import scala.collection.parallel.ParSeqLike diff --git a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala index a1dc37cec9..2faf223b99 100644 --- a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala @@ -152,18 +152,9 @@ extends TrieMapIterator[K, V](lev, ct, mustInit) /** Only used within the `ParTrieMap`. */ private[mutable] trait ParTrieMapCombiner[K, V] extends Combiner[(K, V), ParTrieMap[K, V]] { - def combine[N <: (K, V), NewTo >: ParTrieMap[K, V]](other: Combiner[N, NewTo]): Combiner[N, NewTo] = if (this eq other) this else { - throw new UnsupportedOperationException("This shouldn't have been called in the first place.") - - val thiz = this.asInstanceOf[ParTrieMap[K, V]] - val that = other.asInstanceOf[ParTrieMap[K, V]] - val result = new ParTrieMap[K, V] - - result ++= thiz.iterator - result ++= that.iterator - - result - } + def combine[N <: (K, V), NewTo >: ParTrieMap[K, V]](other: Combiner[N, NewTo]): Combiner[N, NewTo] = + if (this eq other) this + else throw new UnsupportedOperationException("This shouldn't have been called in the first place.") override def canBeShared = true } diff --git a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala index 79322c85b1..6883457fef 100644 --- a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala @@ -9,18 +9,10 @@ package scala package collection.parallel.mutable - - -import scala.collection.generic.Sizing import scala.collection.mutable.ArraySeq import scala.collection.mutable.ArrayBuffer -import scala.collection.parallel.TaskSupport -import scala.collection.parallel.unsupportedop -import scala.collection.parallel.Combiner import scala.collection.parallel.Task - - /** An array combiner that uses a chain of arraybuffers to store elements. */ trait ResizableParArrayCombiner[T] extends LazyCombiner[T, ParArray[T], ExposedArrayBuffer[T]] { diff --git a/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala b/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala index d1379cde11..e71e61f2f1 100644 --- a/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala @@ -9,23 +9,11 @@ package scala package collection.parallel.mutable -import scala.collection.generic.Sizing import scala.collection.mutable.ArraySeq -import scala.collection.mutable.ArrayBuffer -import scala.collection.mutable.UnrolledBuffer +import scala.collection.mutable.DoublingUnrolledBuffer import scala.collection.mutable.UnrolledBuffer.Unrolled -import scala.collection.parallel.TaskSupport -import scala.collection.parallel.unsupportedop import scala.collection.parallel.Combiner import scala.collection.parallel.Task -import scala.reflect.ClassTag - -// Todo -- revisit whether inheritance is the best way to achieve this functionality -private[mutable] class DoublingUnrolledBuffer[T](implicit t: ClassTag[T]) extends UnrolledBuffer[T]()(t) { - override def calcNextLength(sz: Int) = if (sz < 10000) sz * 2 else sz - protected override def newUnrolled = new Unrolled[T](0, new Array[T](4), null, this) -} - /** An array combiner that uses doubling unrolled buffers to store elements. */ trait UnrolledParArrayCombiner[T] @@ -62,7 +50,7 @@ extends Combiner[T, ParArray[T]] { case that: UnrolledParArrayCombiner[t] => buff concat that.buff this - case _ => unsupportedop("Cannot combine with combiner of different type.") + case _ => throw new UnsupportedOperationException("Cannot combine with combiner of different type.") } def size = buff.size diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala index d77dcb0658..eaa87b675a 100644 --- a/src/library/scala/collection/parallel/package.scala +++ b/src/library/scala/collection/parallel/package.scala @@ -35,15 +35,7 @@ package object parallel { else sz } - private[parallel] def unsupported = throw new UnsupportedOperationException - - private[parallel] def unsupportedop(msg: String) = throw new UnsupportedOperationException(msg) - - private[parallel] def outofbounds(idx: Int) = throw new IndexOutOfBoundsException(idx.toString) - - private[parallel] def getTaskSupport: TaskSupport = new ExecutionContextTaskSupport - - val defaultTaskSupport: TaskSupport = getTaskSupport + val defaultTaskSupport: TaskSupport = new ExecutionContextTaskSupport def setTaskSupport[Coll](c: Coll, t: TaskSupport): Coll = { c match { @@ -98,7 +90,7 @@ package parallel { } } } - + trait FactoryOps[From, Elem, To] { trait Otherwise[R] { def otherwise(notbody: => R): R @@ -122,9 +114,9 @@ package parallel { def ifParSeq[R](isbody: ParSeq[T] => R): Otherwise[R] } - @deprecated("This trait will be removed.", "2.11.0") + @deprecated("this trait will be removed", "2.11.0") trait ThrowableOps { - @deprecated("This method will be removed.", "2.11.0") + @deprecated("this method will be removed", "2.11.0") def alongWith(that: Throwable): Throwable } @@ -143,7 +135,7 @@ package parallel { } /** Composite throwable - thrown when multiple exceptions are thrown at the same time. */ - @deprecated("This class will be removed.", "2.11.0") + @deprecated("this class will be removed.", "2.11.0") final case class CompositeThrowable(throwables: Set[Throwable]) extends Exception( "Multiple exceptions thrown during a parallel computation: " + throwables.map(t => t + "\n" + t.getStackTrace.take(10).++("...").mkString("\n")).mkString("\n\n") diff --git a/src/library/scala/collection/script/Location.scala b/src/library/scala/collection/script/Location.scala index bed74bf9ca..8a0b10c331 100644 --- a/src/library/scala/collection/script/Location.scala +++ b/src/library/scala/collection/script/Location.scala @@ -18,17 +18,17 @@ package script * @since 2.8 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") sealed abstract class Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case object Start extends Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case object End extends Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case object NoLo extends Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Index(n: Int) extends Location diff --git a/src/library/scala/collection/script/Message.scala b/src/library/scala/collection/script/Message.scala index 3fc2a0ec7e..a6ba9d9523 100644 --- a/src/library/scala/collection/script/Message.scala +++ b/src/library/scala/collection/script/Message.scala @@ -21,7 +21,7 @@ import mutable.ArrayBuffer * @version 1.0, 08/07/2003 * @since 2.8 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") trait Message[+A] /** This observable update refers to inclusion operations that add new elements @@ -30,7 +30,7 @@ trait Message[+A] * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Include[+A](location: Location, elem: A) extends Message[A] { def this(elem: A) = this(NoLo, elem) } @@ -41,7 +41,7 @@ case class Include[+A](location: Location, elem: A) extends Message[A] { * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Update[+A](location: Location, elem: A) extends Message[A] { def this(elem: A) = this(NoLo, elem) } @@ -52,7 +52,7 @@ case class Update[+A](location: Location, elem: A) extends Message[A] { * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Remove[+A](location: Location, elem: A) extends Message[A] { def this(elem: A) = this(NoLo, elem) } @@ -62,7 +62,7 @@ case class Remove[+A](location: Location, elem: A) extends Message[A] { * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Reset[+A]() extends Message[A] /** Objects of this class represent compound messages consisting @@ -71,7 +71,7 @@ case class Reset[+A]() extends Message[A] * @author Matthias Zenger * @version 1.0, 10/05/2004 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") class Script[A] extends ArrayBuffer[Message[A]] with Message[A] { override def toString(): String = { diff --git a/src/library/scala/collection/script/Scriptable.scala b/src/library/scala/collection/script/Scriptable.scala index 4db75ddd3e..8965286b0d 100644 --- a/src/library/scala/collection/script/Scriptable.scala +++ b/src/library/scala/collection/script/Scriptable.scala @@ -17,7 +17,7 @@ package script * @version 1.0, 09/05/2004 * @since 2.8 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") trait Scriptable[A] { /** Send a message to this scriptable object. */ diff --git a/src/library/scala/compat/Platform.scala b/src/library/scala/compat/Platform.scala index 42dfcbfdde..f3745bc189 100644 --- a/src/library/scala/compat/Platform.scala +++ b/src/library/scala/compat/Platform.scala @@ -105,8 +105,7 @@ object Platform { /** The default line separator. * * On the JVM, this is equivalent to calling the method: - * `System.getProperty("line.separator")` - * with a default value of "\n". + * `java.lang.System.lineSeparator` */ val EOL = scala.util.Properties.lineSeparator diff --git a/src/library/scala/concurrent/BatchingExecutor.scala b/src/library/scala/concurrent/BatchingExecutor.scala index a0d7aaea47..fd31f3470e 100644 --- a/src/library/scala/concurrent/BatchingExecutor.scala +++ b/src/library/scala/concurrent/BatchingExecutor.scala @@ -103,7 +103,7 @@ private[concurrent] trait BatchingExecutor extends Executor { override def execute(runnable: Runnable): Unit = { if (batchable(runnable)) { // If we can batch the runnable _tasksLocal.get match { - case null => unbatchedExecute(new Batch(List(runnable))) // If we aren't in batching mode yet, enqueue batch + case null => unbatchedExecute(new Batch(runnable :: Nil)) // If we aren't in batching mode yet, enqueue batch case some => _tasksLocal.set(runnable :: some) // If we are already in batching mode, add to batch } } else unbatchedExecute(runnable) // If not batchable, just delegate to underlying diff --git a/src/library/scala/concurrent/BlockContext.scala b/src/library/scala/concurrent/BlockContext.scala index 747cc393c3..2b8ed4c7ca 100644 --- a/src/library/scala/concurrent/BlockContext.scala +++ b/src/library/scala/concurrent/BlockContext.scala @@ -41,7 +41,7 @@ package scala.concurrent trait BlockContext { /** Used internally by the framework; - * Designates (and eventually executes) a thunk which potentially blocks the calling `Thread`. + * Designates (and eventually executes) a thunk which potentially blocks the calling `java.lang.Thread`. * * Clients must use `scala.concurrent.blocking` or `scala.concurrent.Await` instead. */ @@ -53,9 +53,16 @@ object BlockContext { override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = thunk } + /** + * @return the `BlockContext` that will be used if no other is found. + **/ + def defaultBlockContext: BlockContext = DefaultBlockContext + private val contextLocal = new ThreadLocal[BlockContext]() - /** Obtain the current thread's current `BlockContext`. */ + /** + @return the `BlockContext` that would be used for the current `java.lang.Thread` at this point + **/ def current: BlockContext = contextLocal.get match { case null => Thread.currentThread match { case ctx: BlockContext => ctx @@ -64,7 +71,9 @@ object BlockContext { case some => some } - /** Pushes a current `BlockContext` while executing `body`. */ + /** + * Installs a current `BlockContext` around executing `body`. + **/ def withBlockContext[T](blockContext: BlockContext)(body: => T): T = { val old = contextLocal.get // can be null try { diff --git a/src/library/scala/concurrent/ExecutionContext.scala b/src/library/scala/concurrent/ExecutionContext.scala index e380c55880..f46f294387 100644 --- a/src/library/scala/concurrent/ExecutionContext.scala +++ b/src/library/scala/concurrent/ExecutionContext.scala @@ -11,7 +11,6 @@ package scala.concurrent import java.util.concurrent.{ ExecutorService, Executor } import scala.annotation.implicitNotFound -import scala.util.Try /** * An `ExecutionContext` can execute program logic asynchronously, @@ -26,21 +25,20 @@ import scala.util.Try * and an implicit `ExecutionContext`. The implicit `ExecutionContext` * will be used to execute the callback. * - * It is possible to simply import + * While it is possible to simply import * `scala.concurrent.ExecutionContext.Implicits.global` to obtain an - * implicit `ExecutionContext`. This global context is a reasonable - * default thread pool. - * - * However, application developers should carefully consider where they - * want to set policy; ideally, one place per application (or per - * logically-related section of code) will make a decision about - * which `ExecutionContext` to use. That is, you might want to avoid - * hardcoding `scala.concurrent.ExecutionContext.Implicits.global` all - * over the place in your code. - * One approach is to add `(implicit ec: ExecutionContext)` - * to methods which need an `ExecutionContext`. Then import a specific - * context in one place for the entire application or module, - * passing it implicitly to individual methods. + * implicit `ExecutionContext`, application developers should carefully + * consider where they want to set execution policy; + * ideally, one place per application—or per logically related section of code— + * will make a decision about which `ExecutionContext` to use. + * That is, you will mostly want to avoid hardcoding, especially via an import, + * `scala.concurrent.ExecutionContext.Implicits.global`. + * The recommended approach is to add `(implicit ec: ExecutionContext)` to methods, + * or class constructor parameters, which need an `ExecutionContext`. + * + * Then locally import a specific `ExecutionContext` in one place for the entire + * application or module, passing it implicitly to individual methods. + * Alternatively define a local implicit val with the required `ExecutionContext`. * * A custom `ExecutionContext` may be appropriate to execute code * which blocks on IO or performs long-running computations. @@ -72,22 +70,24 @@ trait ExecutionContext { */ def reportFailure(@deprecatedName('t) cause: Throwable): Unit - /** Prepares for the execution of a task. Returns the prepared execution context. - * - * `prepare` should be called at the site where an `ExecutionContext` is received (for - * example, through an implicit method parameter). The returned execution context may - * then be used to execute tasks. The role of `prepare` is to save any context relevant - * to an execution's ''call site'', so that this context may be restored at the - * ''execution site''. (These are often different: for example, execution may be - * suspended through a `Promise`'s future until the `Promise` is completed, which may - * be done in another thread, on another stack.) - * - * Note: a valid implementation of `prepare` is one that simply returns `this`. - * - * @return the prepared execution context - */ + /** Prepares for the execution of a task. Returns the prepared + * execution context. The recommended implementation of + * `prepare` is to return `this`. + * + * This method should no longer be overridden or called. It was + * originally expected that `prepare` would be called by + * all libraries that consume ExecutionContexts, in order to + * capture thread local context. However, this usage has proven + * difficult to implement in practice and instead it is + * now better to avoid using `prepare` entirely. + * + * Instead, if an `ExecutionContext` needs to capture thread + * local context, it should capture that context when it is + * constructed, so that it doesn't need any additional + * preparation later. + */ + @deprecated("preparation of ExecutionContexts will be removed", "2.12.0") def prepare(): ExecutionContext = this - } /** @@ -110,13 +110,22 @@ object ExecutionContext { * The explicit global `ExecutionContext`. Invoke `global` when you want to provide the global * `ExecutionContext` explicitly. * - * The default `ExecutionContext` implementation is backed by a work-stealing thread pool. By default, - * the thread pool uses a target number of worker threads equal to the number of - * [[https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors-- available processors]]. + * The default `ExecutionContext` implementation is backed by a work-stealing thread pool. + * It can be configured via the following [[scala.sys.SystemProperties]]: + * + * `scala.concurrent.context.minThreads` = defaults to "1" + * `scala.concurrent.context.numThreads` = defaults to "x1" (i.e. the current number of available processors * 1) + * `scala.concurrent.context.maxThreads` = defaults to "x1" (i.e. the current number of available processors * 1) + * `scala.concurrent.context.maxExtraThreads` = defaults to "256" + * + * The pool size of threads is then `numThreads` bounded by `minThreads` on the lower end and `maxThreads` on the high end. + * + * The `maxExtraThreads` is the maximum number of extra threads to have at any given time to evade deadlock, + * see [[scala.concurrent.BlockContext]]. * * @return the global `ExecutionContext` */ - def global: ExecutionContextExecutor = Implicits.global + def global: ExecutionContextExecutor = Implicits.global.asInstanceOf[ExecutionContextExecutor] object Implicits { /** @@ -127,7 +136,7 @@ object ExecutionContext { * the thread pool uses a target number of worker threads equal to the number of * [[https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors-- available processors]]. */ - implicit lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor) + implicit lazy val global: ExecutionContext = impl.ExecutionContextImpl.fromExecutor(null: Executor) } /** Creates an `ExecutionContext` from the given `ExecutorService`. diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala index ebc1e76ca1..6c1c9a0c80 100644 --- a/src/library/scala/concurrent/Future.scala +++ b/src/library/scala/concurrent/Future.scala @@ -10,34 +10,30 @@ package scala.concurrent import scala.language.higherKinds -import java.util.concurrent.{ ConcurrentLinkedQueue, TimeUnit, Callable } -import java.util.concurrent.TimeUnit.{ NANOSECONDS => NANOS, MILLISECONDS ⇒ MILLIS } -import java.lang.{ Iterable => JIterable } -import java.util.{ LinkedList => JLinkedList } -import java.util.concurrent.atomic.{ AtomicReferenceFieldUpdater, AtomicInteger, AtomicLong, AtomicBoolean } +import java.util.concurrent.{CountDownLatch, TimeUnit} +import java.util.concurrent.atomic.AtomicInteger import scala.util.control.NonFatal -import scala.Option import scala.util.{Try, Success, Failure} - -import scala.annotation.tailrec -import scala.collection.mutable.Builder +import scala.concurrent.duration._ import scala.collection.generic.CanBuildFrom import scala.reflect.ClassTag - -/** The trait that represents futures. +/** A `Future` represents a value which may or may not *currently* be available, + * but will be available at some point, or an exception if that value could not be made available. * - * Asynchronous computations that yield futures are created with the `Future` call: + * Asynchronous computations that yield futures are created with the `Future.apply` call and are computed using a supplied `ExecutionContext`, + * which can be backed by a Thread pool. * * {{{ + * import ExecutionContext.Implicits.global * val s = "Hello" * val f: Future[String] = Future { * s + " future!" * } - * f onSuccess { - * case msg => println(msg) + * f foreach { + * msg => println(msg) * } * }}} * @@ -62,6 +58,10 @@ import scala.reflect.ClassTag * If a future is failed with a `scala.runtime.NonLocalReturnControl`, * it is completed with a value from that throwable instead. * + * @define swallowsExceptions + * Since this method executes asynchronously and does not produce a return value, + * any non-fatal exceptions thrown will be reported to the `ExecutionContext`. + * * @define nonDeterministic * Note: using this method yields nondeterministic dataflow programs. * @@ -91,16 +91,10 @@ import scala.reflect.ClassTag * thread. That is, the implementation may run multiple callbacks * in a batch within a single `execute()` and it may run * `execute()` either immediately or asynchronously. + * Completion of the Future must *happen-before* the invocation of the callback. */ trait Future[+T] extends Awaitable[T] { - - // The executor within the lexical scope - // of the Future trait. Note that this will - // (modulo bugs) _never_ execute a callback - // other than those below in this same file. - // - // See the documentation on `InternalCallbackExecutor` for more details. - private def internalExecutor = Future.InternalCallbackExecutor + import Future.{ InternalCallbackExecutor => internalExecutor } /* Callbacks */ @@ -111,12 +105,18 @@ trait Future[+T] extends Awaitable[T] { * If the future has already been completed with a value, * this will either be applied immediately or be scheduled asynchronously. * + * Note that the returned value of `pf` will be discarded. + * + * $swallowsExceptions * $multipleCallbacks * $callbackInContext + * + * @group Callbacks */ + @deprecated("use `foreach` or `onComplete` instead (keep in mind that they take total rather than partial functions)", "2.12.0") def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = onComplete { case Success(v) => - pf.applyOrElse[T, Any](v, Predef.conforms[T]) // Exploiting the cached function to avoid MatchError + pf.applyOrElse[T, Any](v, Predef.identity[T]) // Exploiting the cached function to avoid MatchError case _ => } @@ -130,12 +130,18 @@ trait Future[+T] extends Awaitable[T] { * * Will not be called in case that the future is completed with a value. * + * Note that the returned value of `pf` will be discarded. + * + * $swallowsExceptions * $multipleCallbacks * $callbackInContext + * + * @group Callbacks */ + @deprecated("use `onComplete` or `failed.foreach` instead (keep in mind that they take total rather than partial functions)", "2.12.0") def onFailure[U](@deprecatedName('callback) pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = onComplete { case Failure(t) => - pf.applyOrElse[Throwable, Any](t, Predef.conforms[Throwable]) // Exploiting the cached function to avoid MatchError + pf.applyOrElse[Throwable, Any](t, Predef.identity[Throwable]) // Exploiting the cached function to avoid MatchError case _ => } @@ -145,63 +151,75 @@ trait Future[+T] extends Awaitable[T] { * If the future has already been completed, * this will either be applied immediately or be scheduled asynchronously. * + * Note that the returned value of `f` will be discarded. + * + * $swallowsExceptions * $multipleCallbacks * $callbackInContext + * + * @tparam U only used to accept any return type of the given callback function + * @param f the function to be executed when this `Future` completes + * @group Callbacks */ def onComplete[U](@deprecatedName('func) f: Try[T] => U)(implicit executor: ExecutionContext): Unit /* Miscellaneous */ - /** Returns whether the future has already been completed with + /** Returns whether the future had already been completed with * a value or an exception. * * $nonDeterministic * - * @return `true` if the future is already completed, `false` otherwise + * @return `true` if the future was completed, `false` otherwise + * @group Polling */ def isCompleted: Boolean - /** The value of this `Future`. + /** The current value of this `Future`. + * + * $nonDeterministic * - * If the future is not completed the returned value will be `None`. - * If the future is completed the value will be `Some(Success(t))` - * if it contains a valid result, or `Some(Failure(error))` if it contains + * If the future was not completed the returned value will be `None`. + * If the future was completed the value will be `Some(Success(t))` + * if it contained a valid result, or `Some(Failure(error))` if it contained * an exception. + * + * @return `None` if the `Future` wasn't completed, `Some` if it was. + * @group Polling */ def value: Option[Try[T]] /* Projections */ - /** Returns a failed projection of this future. - * - * The failed projection is a future holding a value of type `Throwable`. + /** The returned `Future` will be successfully completed with the `Throwable` of the original `Future` + * if the original `Future` fails. * - * It is completed with a value which is the throwable of the original future - * in case the original future is failed. + * If the original `Future` is successful, the returned `Future` is failed with a `NoSuchElementException`. * - * It is failed with a `NoSuchElementException` if the original future is completed successfully. - * - * Blocking on this future returns a value if the original future is completed with an exception - * and throws a corresponding exception if the original future fails. + * @return a failed projection of this `Future`. + * @group Transformations */ - def failed: Future[Throwable] = { - implicit val ec = internalExecutor - val p = Promise[Throwable]() - onComplete { - case Failure(t) => p success t - case Success(v) => p failure (new NoSuchElementException("Future.failed not completed with a throwable.")) - } - p.future - } + def failed: Future[Throwable] = + transform({ + case Failure(t) => Success(t) + case Success(v) => Failure(new NoSuchElementException("Future.failed not completed with a throwable.")) + })(internalExecutor) /* Monadic operations */ /** Asynchronously processes the value in the future once the value becomes available. * - * Will not be called if the future fails. + * WARNING: Will not be called if this future is never completed or if it is completed with a failure. + * + * $swallowsExceptions + * + * @tparam U only used to accept any return type of the given callback function + * @param f the function which will be executed if this `Future` completes with a result, + * the return value of `f` will be discarded. + * @group Callbacks */ def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = onComplete { _ foreach f } @@ -210,33 +228,63 @@ trait Future[+T] extends Awaitable[T] { * exception thrown when 's' or 'f' is applied, that exception will be propagated * to the resulting future. * - * @param s function that transforms a successful result of the receiver into a - * successful result of the returned future - * @param f function that transforms a failure of the receiver into a failure of - * the returned future - * @return a future that will be completed with the transformed value - */ - def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = { - val p = Promise[S]() - // transform on Try has the wrong shape for us here - onComplete { - case Success(r) => p complete Try(s(r)) - case Failure(t) => p complete Try(throw f(t)) // will throw fatal errors! + * @tparam S the type of the returned `Future` + * @param s function that transforms a successful result of the receiver into a successful result of the returned future + * @param f function that transforms a failure of the receiver into a failure of the returned future + * @return a `Future` that will be completed with the transformed value + * @group Transformations + */ + def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = + transform { + case Success(r) => Try(s(r)) + case Failure(t) => Try(throw f(t)) // will throw fatal errors! } - p.future - } + + /** Creates a new Future by applying the specified function to the result + * of this Future. If there is any non-fatal exception thrown when 'f' + * is applied then that exception will be propagated to the resulting future. + * + * @tparam S the type of the returned `Future` + * @param f function that transforms the result of this future + * @return a `Future` that will be completed with the transformed value + * @group Transformations + */ + def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] + + /** Creates a new Future by applying the specified function, which produces a Future, to the result + * of this Future. If there is any non-fatal exception thrown when 'f' + * is applied then that exception will be propagated to the resulting future. + * + * @tparam S the type of the returned `Future` + * @param f function that transforms the result of this future + * @return a `Future` that will be completed with the transformed value + * @group Transformations + */ + def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] + /** Creates a new future by applying a function to the successful result of * this future. If this future is completed with an exception then the new * future will also contain this exception. * - * $forComprehensionExamples + * Example: + * + * {{{ + * val f = Future { "The future" } + * val g = f map { x: String => x + " is now!" } + * }}} + * + * Note that a for comprehension involving a `Future` + * may expand to include a call to `map` and or `flatMap` + * and `withFilter`. See [[scala.concurrent.Future#flatMap]] for an example of such a comprehension. + * + * + * @tparam S the type of the returned `Future` + * @param f the function which will be applied to the successful result of this `Future` + * @return a `Future` which will be completed with the result of the application of the function + * @group Transformations */ - def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { // transform(f, identity) - val p = Promise[S]() - onComplete { v => p complete (v map f) } - p.future - } + def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_ map f) /** Creates a new future by applying a function to the successful result of * this future, and returns the result of the function as the new future. @@ -244,21 +292,25 @@ trait Future[+T] extends Awaitable[T] { * also contain this exception. * * $forComprehensionExamples + * + * @tparam S the type of the returned `Future` + * @param f the function which will be applied to the successful result of this `Future` + * @return a `Future` which will be completed with the result of the application of the function + * @group Transformations */ - def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = { - import impl.Promise.DefaultPromise - val p = new DefaultPromise[S]() - onComplete { - case f: Failure[_] => p complete f.asInstanceOf[Failure[S]] - case Success(v) => try f(v) match { - // If possible, link DefaultPromises to avoid space leaks - case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p) - case fut => fut.onComplete(p.complete)(internalExecutor) - } catch { case NonFatal(t) => p failure t } - } - p.future + def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = transformWith { + case Success(s) => f(s) + case Failure(_) => this.asInstanceOf[Future[S]] } + /** Creates a new future with one level of nesting flattened, this method is equivalent + * to `flatMap(identity)`. + * + * @tparam S the type of the returned `Future` + * @group Transformations + */ + def flatten[S](implicit ev: T <:< Future[S]): Future[S] = flatMap(ev)(internalExecutor) + /** Creates a new future by filtering the value of the current future with a predicate. * * If the current future contains a value which satisfies the predicate, the new future will also hold that value. @@ -271,16 +323,19 @@ trait Future[+T] extends Awaitable[T] { * val f = Future { 5 } * val g = f filter { _ % 2 == 1 } * val h = f filter { _ % 2 == 0 } - * Await.result(g, Duration.Zero) // evaluates to 5 + * g foreach println // Eventually prints 5 * Await.result(h, Duration.Zero) // throw a NoSuchElementException * }}} + * + * @param p the predicate to apply to the successful result of this `Future` + * @return a `Future` which will hold the successful result of this `Future` if it matches the predicate or a `NoSuchElementException` + * @group Transformations */ def filter(@deprecatedName('pred) p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = - map { - r => if (p(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") - } + map { r => if (p(r)) r else throw new NoSuchElementException("Future.filter predicate is not satisfied") } /** Used by for-comprehensions. + * @group Transformations */ final def withFilter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = filter(p)(executor) @@ -300,9 +355,14 @@ trait Future[+T] extends Awaitable[T] { * val h = f collect { * case x if x > 0 => x * 2 * } - * Await.result(g, Duration.Zero) // evaluates to 5 + * g foreach println // Eventually prints 5 * Await.result(h, Duration.Zero) // throw a NoSuchElementException * }}} + * + * @tparam S the type of the returned `Future` + * @param pf the `PartialFunction` to apply to the successful result of this `Future` + * @return a `Future` holding the result of application of the `PartialFunction` or a `NoSuchElementException` + * @group Transformations */ def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = map { @@ -320,12 +380,14 @@ trait Future[+T] extends Awaitable[T] { * Future (6 / 0) recover { case e: NotFoundException => 0 } // result: exception * Future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3 * }}} + * + * @tparam U the type of the returned `Future` + * @param pf the `PartialFunction` to apply if this `Future` fails + * @return a `Future` with the successful value of this `Future` or the result of the `PartialFunction` + * @group Transformations */ - def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = { - val p = Promise[U]() - onComplete { v => p complete (v recover pf) } - p.future - } + def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = + transform { _ recover pf } /** Creates a new future that will handle any matching throwable that this * future might contain by assigning it a value of another future. @@ -339,15 +401,17 @@ trait Future[+T] extends Awaitable[T] { * val f = Future { Int.MaxValue } * Future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue * }}} + * + * @tparam U the type of the returned `Future` + * @param pf the `PartialFunction` to apply if this `Future` fails + * @return a `Future` with the successful value of this `Future` or the outcome of the `Future` returned by the `PartialFunction` + * @group Transformations */ - def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = { - val p = Promise[U]() - onComplete { - case Failure(t) => try pf.applyOrElse(t, (_: Throwable) => this).onComplete(p.complete)(internalExecutor) catch { case NonFatal(t) => p failure t } - case other => p complete other + def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = + transformWith { + case Failure(t) => pf.applyOrElse(t, (_: Throwable) => this) + case Success(_) => this } - p.future - } /** Zips the values of `this` and `that` future, and creates * a new future holding the tuple of their results. @@ -356,17 +420,37 @@ trait Future[+T] extends Awaitable[T] { * with the throwable stored in `this`. * Otherwise, if `that` future fails, the resulting future is failed * with the throwable stored in `that`. + * + * @tparam U the type of the other `Future` + * @param that the other `Future` + * @return a `Future` with the results of both futures or the failure of the first of them that failed + * @group Transformations */ def zip[U](that: Future[U]): Future[(T, U)] = { implicit val ec = internalExecutor - val p = Promise[(T, U)]() - onComplete { - case f: Failure[_] => p complete f.asInstanceOf[Failure[(T, U)]] - case Success(s) => that onComplete { c => p.complete(c map { s2 => (s, s2) }) } - } - p.future + flatMap { r1 => that.map(r2 => (r1, r2)) } } + /** Zips the values of `this` and `that` future using a function `f`, + * and creates a new future holding the result. + * + * If `this` future fails, the resulting future is failed + * with the throwable stored in `this`. + * Otherwise, if `that` future fails, the resulting future is failed + * with the throwable stored in `that`. + * If the application of `f` throws a throwable, the resulting future + * is failed with that throwable if it is non-fatal. + * + * @tparam U the type of the other `Future` + * @tparam R the type of the resulting `Future` + * @param that the other `Future` + * @param f the function to apply to the results of `this` and `that` + * @return a `Future` with the result of the application of `f` to the results of `this` and `that` + * @group Transformations + */ + def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] = + flatMap(r1 => that.map(r2 => f(r1, r2)))(internalExecutor) + /** Creates a new future which holds the result of this future if it was completed successfully, or, if not, * the result of the `that` future if `that` is completed successfully. * If both futures are failed, the resulting future holds the throwable object of the first future. @@ -378,24 +462,28 @@ trait Future[+T] extends Awaitable[T] { * val f = Future { sys.error("failed") } * val g = Future { 5 } * val h = f fallbackTo g - * Await.result(h, Duration.Zero) // evaluates to 5 + * h foreach println // Eventually prints 5 * }}} + * + * @tparam U the type of the other `Future` and the resulting `Future` + * @param that the `Future` whose result we want to use if this `Future` fails. + * @return a `Future` with the successful result of this or that `Future` or the failure of this `Future` if both fail + * @group Transformations */ - def fallbackTo[U >: T](that: Future[U]): Future[U] = { - implicit val ec = internalExecutor - val p = Promise[U]() - onComplete { - case s @ Success(_) => p complete s - case f @ Failure(_) => that onComplete { - case s2 @ Success(_) => p complete s2 - case _ => p complete f // Use the first failure as the failure - } + def fallbackTo[U >: T](that: Future[U]): Future[U] = + if (this eq that) this + else { + implicit val ec = internalExecutor + recoverWith { case _ => that } recoverWith { case _ => this } } - 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. + * + * @tparam S the type of the returned `Future` + * @param tag the `ClassTag` which will be used to cast the result of this `Future` + * @return a `Future` holding the casted result of this `Future` or a `ClassCastException` otherwise + * @group Transformations */ def mapTo[S](implicit tag: ClassTag[S]): Future[S] = { implicit val ec = internalExecutor @@ -429,15 +517,22 @@ trait Future[+T] extends Awaitable[T] { * case Success(v) => println(v) * } * }}} + * + * $swallowsExceptions + * + * @tparam U only used to accept any return type of the given `PartialFunction` + * @param pf a `PartialFunction` which will be conditionally applied to the outcome of this `Future` + * @return a `Future` which will be completed with the exact same outcome as this `Future` but after the `PartialFunction` has been executed. + * @group Callbacks */ - def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = { - val p = Promise[T]() - onComplete { - case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r - } - p.future - } + def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = + transform { + result => + try pf.applyOrElse[Try[T], Any](result, Predef.identity[Try[T]]) + catch { case NonFatal(t) => executor reportFailure t } + result + } } @@ -461,48 +556,122 @@ object Future { classOf[Unit] -> classOf[scala.runtime.BoxedUnit] ) + /** A Future which is never completed. + */ + final object never extends Future[Nothing] { + + @throws(classOf[TimeoutException]) + @throws(classOf[InterruptedException]) + override def ready(atMost: Duration)(implicit permit: CanAwait): this.type = { + atMost match { + case e if e eq Duration.Undefined => throw new IllegalArgumentException("cannot wait for Undefined period") + case Duration.Inf => new CountDownLatch(1).await() + case Duration.MinusInf => // Drop out + case f: FiniteDuration => + if (f > Duration.Zero) new CountDownLatch(1).await(f.toNanos, TimeUnit.NANOSECONDS) + } + throw new TimeoutException(s"Future timed out after [$atMost]") + } + + @throws(classOf[Exception]) + override def result(atMost: Duration)(implicit permit: CanAwait): Nothing = { + ready(atMost) + throw new TimeoutException(s"Future timed out after [$atMost]") + } + + override def onSuccess[U](pf: PartialFunction[Nothing, U])(implicit executor: ExecutionContext): Unit = () + override def onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = () + override def onComplete[U](f: Try[Nothing] => U)(implicit executor: ExecutionContext): Unit = () + override def isCompleted: Boolean = false + override def value: Option[Try[Nothing]] = None + override def failed: Future[Throwable] = this + override def foreach[U](f: Nothing => U)(implicit executor: ExecutionContext): Unit = () + override def transform[S](s: Nothing => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = this + override def transform[S](f: Try[Nothing] => Try[S])(implicit executor: ExecutionContext): Future[S] = this + override def transformWith[S](f: Try[Nothing] => Future[S])(implicit executor: ExecutionContext): Future[S] = this + override def map[S](f: Nothing => S)(implicit executor: ExecutionContext): Future[S] = this + override def flatMap[S](f: Nothing => Future[S])(implicit executor: ExecutionContext): Future[S] = this + override def flatten[S](implicit ev: Nothing <:< Future[S]): Future[S] = this + override def filter(p: Nothing => Boolean)(implicit executor: ExecutionContext): Future[Nothing] = this + override def collect[S](pf: PartialFunction[Nothing, S])(implicit executor: ExecutionContext): Future[S] = this + override def recover[U >: Nothing](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = this + override def recoverWith[U >: Nothing](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = this + override def zip[U](that: Future[U]): Future[(Nothing, U)] = this + override def zipWith[U, R](that: Future[U])(f: (Nothing, U) => R)(implicit executor: ExecutionContext): Future[R] = this + override def fallbackTo[U >: Nothing](that: Future[U]): Future[U] = this + override def mapTo[S](implicit tag: ClassTag[S]): Future[S] = this + override def andThen[U](pf: PartialFunction[Try[Nothing], U])(implicit executor: ExecutionContext): Future[Nothing] = this + + override def toString: String = "Future(<never>)" + } + + /** A Future which is always completed with the Unit value. + */ + val unit: Future[Unit] = successful(()) + /** Creates an already completed Future with the specified exception. * - * @tparam T the type of the value in the future - * @return the newly created `Future` object + * @tparam T the type of the value in the future + * @param exception the non-null instance of `Throwable` + * @return the newly created `Future` instance */ def failed[T](exception: Throwable): Future[T] = Promise.failed(exception).future /** Creates an already completed Future with the specified result. * * @tparam T the type of the value in the future - * @return the newly created `Future` object + * @param result the given successful value + * @return the newly created `Future` instance */ def successful[T](result: T): Future[T] = Promise.successful(result).future /** Creates an already completed Future with the specified result or exception. * - * @tparam T the type of the value in the promise - * @return the newly created `Future` object + * @tparam T the type of the value in the `Future` + * @param result the result of the returned `Future` instance + * @return the newly created `Future` instance */ def fromTry[T](result: Try[T]): Future[T] = Promise.fromTry(result).future - /** Starts an asynchronous computation and returns a `Future` object with the result of that computation. + /** Starts an asynchronous computation and returns a `Future` instance with the result of that computation. + * + * The following expressions are equivalent: + * + * {{{ + * val f1 = Future(expr) + * val f2 = Future.unit.map(_ => expr) + * }}} * * The result becomes available once the asynchronous computation is completed. * - * @tparam T the type of the result - * @param body the asynchronous computation + * @tparam T the type of the result + * @param body the asynchronous computation * @param executor the execution context on which the future is run - * @return the `Future` holding the result of the computation + * @return the `Future` holding the result of the computation */ - def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = impl.Future(body) + def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = + unit.map(_ => body) - /** Simple version of `Future.traverse`. Transforms a `TraversableOnce[Future[A]]` into a `Future[TraversableOnce[A]]`. - * Useful for reducing many `Future`s into a single `Future`. + /** Simple version of `Future.traverse`. Asynchronously and non-blockingly transforms a `TraversableOnce[Future[A]]` + * into a `Future[TraversableOnce[A]]`. Useful for reducing many `Future`s into a single `Future`. + * + * @tparam A the type of the value inside the Futures + * @tparam M the type of the `TraversableOnce` of Futures + * @param in the `TraversableOnce` of Futures which will be sequenced + * @return the `Future` of the `TraversableOnce` of results */ def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = { in.foldLeft(successful(cbf(in))) { - (fr, fa) => for (r <- fr; a <- fa) yield (r += a) + (fr, fa) => fr.zipWith(fa)(_ += _) }.map(_.result())(InternalCallbackExecutor) } - /** Returns a new `Future` to the result of the first future in the list that is completed. + /** Asynchronously and non-blockingly returns a new `Future` to the result of the first future + * in the list that is completed. This means no matter if it is completed as a success or as a failure. + * + * @tparam T the type of the value in the future + * @param futures the `TraversableOnce` of Futures in which to find the first completed + * @return the `Future` holding the result of the future that is first to be completed */ def firstCompletedOf[T](futures: TraversableOnce[Future[T]])(implicit executor: ExecutionContext): Future[T] = { val p = Promise[T]() @@ -511,8 +680,15 @@ object Future { p.future } - /** Returns a `Future` that will hold the optional result of the first `Future` with a result that matches the predicate. + /** Asynchronously and non-blockingly returns a `Future` that will hold the optional result + * of the first `Future` with a result that matches the predicate. + * + * @tparam T the type of the value in the future + * @param futures the `TraversableOnce` of Futures to search + * @param p the predicate which indicates if it's a match + * @return the `Future` holding the optional result of the search */ + @deprecated("use the overloaded version of this method that takes a scala.collection.immutable.Iterable instead", "2.12.0") def find[T](@deprecatedName('futurestravonce) futures: TraversableOnce[Future[T]])(@deprecatedName('predicate) p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = { val futuresBuffer = futures.toBuffer if (futuresBuffer.isEmpty) successful[Option[T]](None) @@ -536,46 +712,133 @@ object Future { } } - /** A non-blocking fold over the specified futures, with the start value of the given zero. + + /** Asynchronously and non-blockingly returns a `Future` that will hold the optional result + * of the first `Future` with a result that matches the predicate, failed `Future`s will be ignored. + * + * @tparam T the type of the value in the future + * @param futures the `scala.collection.immutable.Iterable` of Futures to search + * @param p the predicate which indicates if it's a match + * @return the `Future` holding the optional result of the search + */ + def find[T](futures: scala.collection.immutable.Iterable[Future[T]])(p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = { + def searchNext(i: Iterator[Future[T]]): Future[Option[T]] = + if (!i.hasNext) successful[Option[T]](None) + else { + i.next().transformWith { + case Success(r) if p(r) => successful(Some(r)) + case other => searchNext(i) + } + } + searchNext(futures.iterator) + } + + /** A non-blocking, asynchronous left fold over the specified futures, + * with the start value of the given zero. + * The fold is performed asynchronously in left-to-right order as the futures become completed. + * The result will be the first failure of any of the futures, or any failure in the actual fold, + * or the result of the fold. + * + * Example: + * {{{ + * val futureSum = Future.foldLeft(futures)(0)(_ + _) + * }}} + * + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `scala.collection.immutable.Iterable` of Futures to be folded + * @param zero the start value of the fold + * @param op the fold operation to be applied to the zero and futures + * @return the `Future` holding the result of the fold + */ + def foldLeft[T, R](futures: scala.collection.immutable.Iterable[Future[T]])(zero: R)(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = + foldNext(futures.iterator, zero, op) + + private[this] def foldNext[T, R](i: Iterator[Future[T]], prevValue: R, op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = + if (!i.hasNext) successful(prevValue) + else i.next().flatMap { value => foldNext(i, op(prevValue, value), op) } + + /** A non-blocking, asynchronous fold over the specified futures, with the start value of the given zero. * The fold is performed on the thread where the last future is completed, * the result will be the first failure of any of the futures, or any failure in the actual fold, * or the result of the fold. * * Example: * {{{ - * val result = Await.result(Future.fold(futures)(0)(_ + _), 5 seconds) + * val futureSum = Future.fold(futures)(0)(_ + _) * }}} + * + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `TraversableOnce` of Futures to be folded + * @param zero the start value of the fold + * @param op the fold operation to be applied to the zero and futures + * @return the `Future` holding the result of the fold */ + @deprecated("use Future.foldLeft instead", "2.12.0") def fold[T, R](futures: TraversableOnce[Future[T]])(zero: R)(@deprecatedName('foldFun) op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { if (futures.isEmpty) successful(zero) else sequence(futures).map(_.foldLeft(zero)(op)) } - /** Initiates a fold over the supplied futures where the fold-zero is the result value of the `Future` that's completed first. + /** Initiates a non-blocking, asynchronous, fold over the supplied futures + * where the fold-zero is the result value of the `Future` that's completed first. * * Example: * {{{ - * val result = Await.result(Future.reduce(futures)(_ + _), 5 seconds) + * val futureSum = Future.reduce(futures)(_ + _) * }}} + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `TraversableOnce` of Futures to be reduced + * @param op the reduce operation which is applied to the results of the futures + * @return the `Future` holding the result of the reduce */ + @deprecated("use Future.reduceLeft instead", "2.12.0") def reduce[T, R >: T](futures: TraversableOnce[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { if (futures.isEmpty) failed(new NoSuchElementException("reduce attempted on empty collection")) else sequence(futures).map(_ reduceLeft op) } - /** Transforms a `TraversableOnce[A]` into a `Future[TraversableOnce[B]]` using the provided function `A => Future[B]`. + /** Initiates a non-blocking, asynchronous, left reduction over the supplied futures + * where the zero is the result value of the first `Future`. + * + * Example: + * {{{ + * val futureSum = Future.reduceLeft(futures)(_ + _) + * }}} + * @tparam T the type of the value of the input Futures + * @tparam R the type of the value of the returned `Future` + * @param futures the `scala.collection.immutable.Iterable` of Futures to be reduced + * @param op the reduce operation which is applied to the results of the futures + * @return the `Future` holding the result of the reduce + */ + def reduceLeft[T, R >: T](futures: scala.collection.immutable.Iterable[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { + val i = futures.iterator + if (!i.hasNext) failed(new NoSuchElementException("reduceLeft attempted on empty collection")) + else i.next() flatMap { v => foldNext(i, v, op) } + } + + /** Asynchronously and non-blockingly transforms a `TraversableOnce[A]` into a `Future[TraversableOnce[B]]` + * using the provided function `A => Future[B]`. * This is useful for performing a parallel map. For example, to apply a function to all items of a list * in parallel: * * {{{ * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x))) * }}} + * @tparam A the type of the value inside the Futures in the `TraversableOnce` + * @tparam B the type of the value of the returned `Future` + * @tparam M the type of the `TraversableOnce` of Futures + * @param in the `TraversableOnce` of Futures which will be sequenced + * @param fn the function to apply to the `TraversableOnce` of Futures to produce the results + * @return the `Future` of the `TraversableOnce` of results */ def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = - in.foldLeft(successful(cbf(in))) { (fr, a) => - val fb = fn(a) - for (r <- fr; b <- fb) yield (r += b) - }.map(_.result()) + in.foldLeft(successful(cbf(in))) { + (fr, a) => fr.zipWith(fn(a))(_ += _) + }.map(_.result())(InternalCallbackExecutor) + // This is used to run callbacks which are internal // to scala.concurrent; our own callbacks are only diff --git a/src/library/scala/concurrent/FutureTaskRunner.scala b/src/library/scala/concurrent/FutureTaskRunner.scala deleted file mode 100644 index 089e67cedd..0000000000 --- a/src/library/scala/concurrent/FutureTaskRunner.scala +++ /dev/null @@ -1,39 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2009-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent - -import scala.language.{implicitConversions, higherKinds} - -/** The `FutureTaskRunner` trait is a base trait of task runners - * that provide some sort of future abstraction. - * - * @author Philipp Haller - */ -@deprecated("Use `ExecutionContext` instead.", "2.10.0") -private[scala] trait FutureTaskRunner extends TaskRunner { - - /** The type of the futures that the underlying task runner supports. - */ - type Future[T] - - /** An implicit conversion from futures to zero-parameter functions. - */ - implicit def futureAsFunction[S](x: Future[S]): () => S - - /** Submits a task to run which returns its result in a future. - */ - def submit[S](task: Task[S]): Future[S] - - /* Possibly blocks the current thread, for example, waiting for - * a lock or condition. - */ - @deprecated("Use `blocking` instead.", "2.10.0") - def managedBlock(blocker: ManagedBlocker): Unit - -} diff --git a/src/library/scala/concurrent/Lock.scala b/src/library/scala/concurrent/Lock.scala index 8d18da2d38..757fb94cc7 100644 --- a/src/library/scala/concurrent/Lock.scala +++ b/src/library/scala/concurrent/Lock.scala @@ -15,7 +15,7 @@ package scala.concurrent * @author Martin Odersky * @version 1.0, 10/03/2003 */ -@deprecated("Use java.util.concurrent.locks.Lock", "2.11.2") +@deprecated("use java.util.concurrent.locks.Lock", "2.11.2") class Lock { var available = true diff --git a/src/library/scala/concurrent/ManagedBlocker.scala b/src/library/scala/concurrent/ManagedBlocker.scala deleted file mode 100644 index b5a6e21893..0000000000 --- a/src/library/scala/concurrent/ManagedBlocker.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent - -/** The `ManagedBlocker` trait... - * - * @author Philipp Haller - */ -@deprecated("Use `blocking` instead.", "2.10.0") -private[scala] trait ManagedBlocker { - - /** - * Possibly blocks the current thread, for example waiting for - * a lock or condition. - * - * @return true if no additional blocking is necessary (i.e., - * if `isReleasable` would return `true`). - * @throws InterruptedException if interrupted while waiting - * (the method is not required to do so, but is allowed to). - */ - def block(): Boolean - - /** - * Returns `true` if blocking is unnecessary. - */ - def isReleasable: Boolean - -} diff --git a/src/library/scala/concurrent/Promise.scala b/src/library/scala/concurrent/Promise.scala index 0f4e98db57..894b134e83 100644 --- a/src/library/scala/concurrent/Promise.scala +++ b/src/library/scala/concurrent/Promise.scala @@ -26,12 +26,6 @@ import scala.util.{ Try, Success, Failure } * Note: Using this method may result in non-deterministic concurrent programs. */ trait Promise[T] { - - // used for internal callbacks defined in - // the lexical scope of this trait; - // _never_ for application callbacks. - private implicit def internalExecutor: ExecutionContext = Future.InternalCallbackExecutor - /** Future containing the value of this promise. */ def future: Future[T] @@ -73,7 +67,9 @@ trait Promise[T] { * @return This promise */ final def tryCompleteWith(other: Future[T]): this.type = { - other onComplete { this tryComplete _ } + if (other ne this.future) { // this tryCompleteWith this doesn't make much sense + other.onComplete(this tryComplete _)(Future.InternalCallbackExecutor) + } this } @@ -139,5 +135,5 @@ object Promise { * @tparam T the type of the value in the promise * @return the newly created `Promise` object */ - def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.KeptPromise[T](result) + def fromTry[T](result: Try[T]): Promise[T] = impl.Promise.KeptPromise[T](result) } diff --git a/src/library/scala/concurrent/SyncChannel.scala b/src/library/scala/concurrent/SyncChannel.scala index ec584b3eb0..735598935c 100644 --- a/src/library/scala/concurrent/SyncChannel.scala +++ b/src/library/scala/concurrent/SyncChannel.scala @@ -31,10 +31,10 @@ class SyncChannel[A] { pendingReads = pendingReads.tail // let reader continue - readReq set data + readReq put data // resolve write request - writeReq set true + writeReq put true } else { // enqueue write request @@ -57,10 +57,10 @@ class SyncChannel[A] { pendingWrites = pendingWrites.tail // let writer continue - writeReq set true + writeReq.put(true) // resolve read request - readReq set data + readReq.put (data) } else { // enqueue read request diff --git a/src/library/scala/concurrent/SyncVar.scala b/src/library/scala/concurrent/SyncVar.scala index 1ee27b0f36..77bfa95119 100644 --- a/src/library/scala/concurrent/SyncVar.scala +++ b/src/library/scala/concurrent/SyncVar.scala @@ -19,17 +19,17 @@ import java.util.concurrent.TimeUnit */ class SyncVar[A] { private var isDefined: Boolean = false - private var value: Option[A] = None + private var value: A = _ /** - * Waits for this SyncVar to become defined and returns - * the result, without modifying the stored value. + * Wait for this SyncVar to become defined and then get + * the stored value without modifying it. * * @return value that is held in this container */ def get: A = synchronized { while (!isDefined) wait() - value.get + value } /** Waits `timeout` millis. If `timeout <= 0` just returns 0. @@ -44,11 +44,10 @@ class SyncVar[A] { if (elapsed < 0) 0 else TimeUnit.NANOSECONDS.toMillis(elapsed) } - /** Waits for this SyncVar to become defined at least for - * `timeout` milliseconds (possibly more), and gets its - * value. + /** Wait at least `timeout` milliseconds (possibly more) for this `SyncVar` + * to become defined and then get its value. * - * @param timeout the amount of milliseconds to wait, 0 means forever + * @param timeout time in milliseconds to wait * @return `None` if variable is undefined after `timeout`, `Some(value)` otherwise */ def get(timeout: Long): Option[A] = synchronized { @@ -61,12 +60,12 @@ class SyncVar[A] { val elapsed = waitMeasuringElapsed(rest) rest -= elapsed } - value + if (isDefined) Some(value) else None } /** - * Waits for this SyncVar to become defined and returns - * the result, unsetting the stored value before returning. + * Wait for this SyncVar to become defined and then get + * the stored value, unsetting it as a side effect. * * @return value that was held in this container */ @@ -75,12 +74,11 @@ class SyncVar[A] { finally unsetVal() } - /** Waits for this SyncVar to become defined at least for - * `timeout` milliseconds (possibly more), and takes its - * value by first reading and then removing the value from - * the SyncVar. + /** Wait at least `timeout` milliseconds (possibly more) for this `SyncVar` + * to become defined and then get the stored value, unsetting it + * as a side effect. * - * @param timeout the amount of milliseconds to wait, 0 means forever + * @param timeout the amount of milliseconds to wait * @return the value or a throws an exception if the timeout occurs * @throws NoSuchElementException on timeout */ @@ -93,18 +91,18 @@ class SyncVar[A] { // [Heather] the reason why: it doesn't take into consideration // whether or not the SyncVar is already defined. So, set has been // deprecated in order to eventually be able to make "setting" private - @deprecated("Use `put` instead, as `set` is potentially error-prone", "2.10.0") - // NOTE: Used by SBT 0.13.0-M2 and below + @deprecated("use `put` to ensure a value cannot be overwritten without a corresponding `take`", "2.10.0") + // NOTE: Used by sbt 0.13.0-M2 and below def set(x: A): Unit = setVal(x) - /** Places a value in the SyncVar. If the SyncVar already has a stored value, - * it waits until another thread takes it */ + /** Place a value in the SyncVar. If the SyncVar already has a stored value, + * wait until another thread takes it. */ def put(x: A): Unit = synchronized { while (isDefined) wait() setVal(x) } - /** Checks whether a value is stored in the synchronized variable */ + /** Check whether a value is stored in the synchronized variable. */ def isSet: Boolean = synchronized { isDefined } @@ -113,11 +111,11 @@ class SyncVar[A] { // [Heather] the reason why: it doesn't take into consideration // whether or not the SyncVar is already defined. So, unset has been // deprecated in order to eventually be able to make "unsetting" private - @deprecated("Use `take` instead, as `unset` is potentially error-prone", "2.10.0") - // NOTE: Used by SBT 0.13.0-M2 and below + @deprecated("use `take` to ensure a value is never discarded", "2.10.0") + // NOTE: Used by sbt 0.13.0-M2 and below def unset(): Unit = synchronized { isDefined = false - value = None + value = null.asInstanceOf[A] notifyAll() } @@ -126,7 +124,7 @@ class SyncVar[A] { // implementation of `set` was moved to `setVal` to achieve this private def setVal(x: A): Unit = synchronized { isDefined = true - value = Some(x) + value = x notifyAll() } @@ -135,8 +133,7 @@ class SyncVar[A] { // implementation of `unset` was moved to `unsetVal` to achieve this private def unsetVal(): Unit = synchronized { isDefined = false - value = None + value = null.asInstanceOf[A] notifyAll() } - } diff --git a/src/library/scala/concurrent/TaskRunner.scala b/src/library/scala/concurrent/TaskRunner.scala deleted file mode 100644 index 1ea23b35e8..0000000000 --- a/src/library/scala/concurrent/TaskRunner.scala +++ /dev/null @@ -1,27 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent - -import scala.language.{higherKinds, implicitConversions} - -/** The `TaskRunner` trait... - * - * @author Philipp Haller - */ -@deprecated("Use `ExecutionContext` instead.", "2.10.0") -private[scala] trait TaskRunner { - - type Task[T] - - implicit def functionAsTask[S](fun: () => S): Task[S] - - def execute[S](task: Task[S]): Unit - - def shutdown(): Unit -} diff --git a/src/library/scala/concurrent/ThreadPoolRunner.scala b/src/library/scala/concurrent/ThreadPoolRunner.scala deleted file mode 100644 index 7784681f71..0000000000 --- a/src/library/scala/concurrent/ThreadPoolRunner.scala +++ /dev/null @@ -1,51 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent - -import java.util.concurrent.{ExecutorService, Callable, TimeUnit} -import scala.language.implicitConversions - -/** The `ThreadPoolRunner` trait uses a `java.util.concurrent.ExecutorService` - * to run submitted tasks. - * - * @author Philipp Haller - */ -@deprecated("Use `ExecutionContext` instead.", "2.10.0") -private[scala] trait ThreadPoolRunner extends FutureTaskRunner { - - type Task[T] = Callable[T] with Runnable - type Future[T] = java.util.concurrent.Future[T] - - private class RunCallable[S](fun: () => S) extends Runnable with Callable[S] { - def run() = fun() - def call() = fun() - } - - implicit def functionAsTask[S](fun: () => S): Task[S] = - new RunCallable(fun) - - implicit def futureAsFunction[S](x: Future[S]): () => S = - () => x.get() - - protected def executor: ExecutorService - - def submit[S](task: Task[S]): Future[S] = { - executor.submit[S](task) - } - - def execute[S](task: Task[S]) { - executor execute task - } - - @deprecated("Use `blocking` instead.", "2.10.0") - def managedBlock(blocker: ManagedBlocker) { - blocker.block() - } - -} diff --git a/src/library/scala/concurrent/duration/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala index e68a897f82..d912f614c2 100644 --- a/src/library/scala/concurrent/duration/Duration.scala +++ b/src/library/scala/concurrent/duration/Duration.scala @@ -9,8 +9,6 @@ package scala.concurrent.duration import java.lang.{ Double => JDouble, Long => JLong } -import scala.language.implicitConversions -import scala.language.postfixOps object Duration { @@ -49,7 +47,7 @@ object Duration { * whitespace is allowed before, between and after the parts. Infinities are * designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`. * - * @throws NumberFormatException if format is not parseable + * @throws NumberFormatException if format is not parsable */ def apply(s: String): Duration = { val s1: String = s filterNot (_.isWhitespace) @@ -57,7 +55,7 @@ object Duration { case "Inf" | "PlusInf" | "+Inf" => Inf case "MinusInf" | "-Inf" => MinusInf case _ => - val unitName = s1.reverse takeWhile (_.isLetter) reverse; + val unitName = s1.reverse.takeWhile(_.isLetter).reverse; timeUnit get unitName match { case Some(unit) => val valueStr = s1 dropRight unitName.length @@ -87,11 +85,11 @@ object Duration { // TimeUnit => standard label protected[duration] val timeUnitName: Map[TimeUnit, String] = - timeUnitLabels.toMap mapValues (s => words(s).last) toMap + timeUnitLabels.toMap.mapValues(s => words(s).last).toMap // Label => TimeUnit protected[duration] val timeUnit: Map[String, TimeUnit] = - timeUnitLabels flatMap { case (unit, names) => expandLabels(names) map (_ -> unit) } toMap + timeUnitLabels.flatMap{ case (unit, names) => expandLabels(names) map (_ -> unit) }.toMap /** * Extract length and time unit out of a string, where the format must match the description for [[Duration$.apply(s:String)* apply(String)]]. @@ -122,7 +120,7 @@ object Duration { def fromNanos(nanos: Double): Duration = { if (nanos.isInfinite) if (nanos > 0) Inf else MinusInf - else if (nanos.isNaN) + else if (JDouble.isNaN(nanos)) Undefined else if (nanos > Long.MaxValue || nanos < Long.MinValue) throw new IllegalArgumentException("trying to construct too large duration with " + nanos + "ns") @@ -198,11 +196,11 @@ object Duration { } def *(factor: Double): Duration = - if (factor == 0d || factor.isNaN) Undefined + if (factor == 0d || JDouble.isNaN(factor)) Undefined else if (factor < 0d) -this else this def /(divisor: Double): Duration = - if (divisor.isNaN || divisor.isInfinite) Undefined + if (JDouble.isNaN(divisor) || divisor.isInfinite) Undefined else if ((divisor compare 0d) < 0) -this else this def /(divisor: Duration): Double = divisor match { @@ -287,7 +285,7 @@ object Duration { * whitespace is allowed before, between and after the parts. Infinities are * designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`. * - * @throws NumberFormatException if format is not parseable + * @throws NumberFormatException if format is not parsable */ def create(s: String): Duration = apply(s) @@ -629,13 +627,13 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio def *(factor: Double) = if (!factor.isInfinite) fromNanos(toNanos * factor) - else if (factor.isNaN) Undefined + else if (JDouble.isNaN(factor)) Undefined else if ((factor > 0) ^ (this < Zero)) Inf else MinusInf def /(divisor: Double) = if (!divisor.isInfinite) fromNanos(toNanos / divisor) - else if (divisor.isNaN) Undefined + else if (JDouble.isNaN(divisor)) Undefined else Zero // if this is made a constant, then scalac will elide the conditional and always return +0.0, SI-6331 @@ -708,7 +706,7 @@ final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duratio final def isFinite() = true - final def toCoarsest: Duration = { + final override def toCoarsest: FiniteDuration = { def loop(length: Long, unit: TimeUnit): FiniteDuration = { def coarserOrThis(coarser: TimeUnit, divider: Int) = if (length % divider == 0) loop(length / divider, coarser) diff --git a/src/library/scala/concurrent/forkjoin/package.scala b/src/library/scala/concurrent/forkjoin/package.scala new file mode 100644 index 0000000000..889890e30b --- /dev/null +++ b/src/library/scala/concurrent/forkjoin/package.scala @@ -0,0 +1,60 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2015, LAMP/EPFL and Typesafe, Inc. ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.concurrent +import java.util.{concurrent => juc} +import java.util.Collection + +package object forkjoin { + @deprecated("use java.util.concurrent.ForkJoinPool directly, instead of this alias", "2.12.0") + type ForkJoinPool = juc.ForkJoinPool + @deprecated("use java.util.concurrent.ForkJoinPool directly, instead of this alias", "2.12.0") + object ForkJoinPool { + type ForkJoinWorkerThreadFactory = juc.ForkJoinPool.ForkJoinWorkerThreadFactory + type ManagedBlocker = juc.ForkJoinPool.ManagedBlocker + + val defaultForkJoinWorkerThreadFactory: ForkJoinWorkerThreadFactory = juc.ForkJoinPool.defaultForkJoinWorkerThreadFactory + def managedBlock(blocker: ManagedBlocker): Unit = juc.ForkJoinPool.managedBlock(blocker) + } + + @deprecated("use java.util.concurrent.ForkJoinTask directly, instead of this alias", "2.12.0") + type ForkJoinTask[T] = juc.ForkJoinTask[T] + @deprecated("use java.util.concurrent.ForkJoinTask directly, instead of this alias", "2.12.0") + object ForkJoinTask extends scala.Serializable { + def adapt(runnable: Runnable): ForkJoinTask[_] = juc.ForkJoinTask.adapt(runnable) + def adapt[T](callable: juc.Callable[_ <: T]): ForkJoinTask[T] = juc.ForkJoinTask.adapt(callable) + def adapt[T](runnable: Runnable, result: T): ForkJoinTask[T] = juc.ForkJoinTask.adapt(runnable, result) + def getPool(): ForkJoinPool = juc.ForkJoinTask.getPool + def getQueuedTaskCount(): Int = juc.ForkJoinTask.getQueuedTaskCount + def getSurplusQueuedTaskCount(): Int = juc.ForkJoinTask.getSurplusQueuedTaskCount + def helpQuiesce(): Unit = juc.ForkJoinTask.helpQuiesce + def inForkJoinPool(): Boolean = juc.ForkJoinTask.inForkJoinPool + def invokeAll[T <: ForkJoinTask[_]](tasks: Collection[T]): Collection[T] = juc.ForkJoinTask.invokeAll(tasks) + def invokeAll[T](t1: ForkJoinTask[T]): Unit = juc.ForkJoinTask.invokeAll(t1) + def invokeAll[T](tasks: ForkJoinTask[T]*): Unit = juc.ForkJoinTask.invokeAll(tasks: _*) + } + + @deprecated("use java.util.concurrent.ForkJoinWorkerThread directly, instead of this alias", "2.12.0") + type ForkJoinWorkerThread = juc.ForkJoinWorkerThread + @deprecated("use java.util.concurrent.LinkedTransferQueue directly, instead of this alias", "2.12.0") + type LinkedTransferQueue[T] = juc.LinkedTransferQueue[T] + @deprecated("use java.util.concurrent.RecursiveAction directly, instead of this alias", "2.12.0") + type RecursiveAction = juc.RecursiveAction + @deprecated("use java.util.concurrent.RecursiveTask directly, instead of this alias", "2.12.0") + type RecursiveTask[T] = juc.RecursiveTask[T] + + @deprecated("use java.util.concurrent.ThreadLocalRandom directly, instead of this alias", "2.12.0") + type ThreadLocalRandom = juc.ThreadLocalRandom + @deprecated("use java.util.concurrent.ThreadLocalRandom directly, instead of this alias", "2.12.0") + object ThreadLocalRandom extends scala.Serializable { + // For source compatibility, current must declare the empty argument list. + // Having no argument list makes more sense since it doesn't have any side effects, + // but existing callers will break if they invoked it as `current()`. + def current() = juc.ThreadLocalRandom.current + } +} diff --git a/src/library/scala/concurrent/impl/AbstractPromise.java b/src/library/scala/concurrent/impl/AbstractPromise.java deleted file mode 100644 index c2520a1692..0000000000 --- a/src/library/scala/concurrent/impl/AbstractPromise.java +++ /dev/null @@ -1,17 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2015, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent.impl; - -import java.util.concurrent.atomic.AtomicReference; - -@Deprecated // Since 2.11.8. Extend java.util.concurrent.atomic.AtomicReference instead. -abstract class AbstractPromise extends AtomicReference<Object> { - protected final boolean updateState(Object oldState, Object newState) { return compareAndSet(oldState, newState); } - protected final Object getState() { return get(); } -} diff --git a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala index 479720287c..19233d7531 100644 --- a/src/library/scala/concurrent/impl/ExecutionContextImpl.scala +++ b/src/library/scala/concurrent/impl/ExecutionContextImpl.scala @@ -8,55 +8,87 @@ package scala.concurrent.impl - - -import java.util.concurrent.{ LinkedBlockingQueue, Callable, Executor, ExecutorService, Executors, ThreadFactory, TimeUnit, ThreadPoolExecutor } +import java.util.concurrent.{ ForkJoinPool, ForkJoinWorkerThread, ForkJoinTask, Callable, Executor, ExecutorService, ThreadFactory, TimeUnit } +import java.util.concurrent.atomic.AtomicInteger import java.util.Collection -import scala.concurrent.forkjoin._ -import scala.concurrent.{ BlockContext, ExecutionContext, Awaitable, CanAwait, ExecutionContextExecutor, ExecutionContextExecutorService } -import scala.util.control.NonFatal +import scala.concurrent.{ BlockContext, ExecutionContext, CanAwait, ExecutionContextExecutor, ExecutionContextExecutorService } +import scala.annotation.tailrec +private[scala] class ExecutionContextImpl private[impl] (val executor: Executor, val reporter: Throwable => Unit) extends ExecutionContextExecutor { + require(executor ne null, "Executor must not be null") + override def execute(runnable: Runnable) = executor execute runnable + override def reportFailure(t: Throwable) = reporter(t) +} -private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: Throwable => Unit) extends ExecutionContextExecutor { - // Placed here since the creation of the executor needs to read this val - private[this] val uncaughtExceptionHandler: Thread.UncaughtExceptionHandler = new Thread.UncaughtExceptionHandler { - def uncaughtException(thread: Thread, cause: Throwable): Unit = reporter(cause) - } - val executor: Executor = es match { - case null => createExecutorService - case some => some - } +private[concurrent] object ExecutionContextImpl { // Implement BlockContext on FJP threads - class DefaultThreadFactory(daemonic: Boolean) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory { + final class DefaultThreadFactory( + daemonic: Boolean, + maxThreads: Int, + prefix: String, + uncaught: Thread.UncaughtExceptionHandler) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory { + + require(prefix ne null, "DefaultThreadFactory.prefix must be non null") + require(maxThreads > 0, "DefaultThreadFactory.maxThreads must be greater than 0") + + private final val currentNumberOfThreads = new AtomicInteger(0) + + @tailrec private final def reserveThread(): Boolean = currentNumberOfThreads.get() match { + case `maxThreads` | Int.`MaxValue` => false + case other => currentNumberOfThreads.compareAndSet(other, other + 1) || reserveThread() + } + + @tailrec private final def deregisterThread(): Boolean = currentNumberOfThreads.get() match { + case 0 => false + case other => currentNumberOfThreads.compareAndSet(other, other - 1) || deregisterThread() + } + def wire[T <: Thread](thread: T): T = { thread.setDaemon(daemonic) - thread.setUncaughtExceptionHandler(uncaughtExceptionHandler) + thread.setUncaughtExceptionHandler(uncaught) + thread.setName(prefix + "-" + thread.getId()) thread } - def newThread(runnable: Runnable): Thread = wire(new Thread(runnable)) - - def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread = wire(new ForkJoinWorkerThread(fjp) with BlockContext { - override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = { - var result: T = null.asInstanceOf[T] - ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker { - @volatile var isdone = false - override def block(): Boolean = { - result = try thunk finally { isdone = true } - true + // As per ThreadFactory contract newThread should return `null` if cannot create new thread. + def newThread(runnable: Runnable): Thread = + if (reserveThread()) + wire(new Thread(new Runnable { + // We have to decrement the current thread count when the thread exits + override def run() = try runnable.run() finally deregisterThread() + })) else null + + def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread = + if (reserveThread()) { + wire(new ForkJoinWorkerThread(fjp) with BlockContext { + // We have to decrement the current thread count when the thread exits + final override def onTermination(exception: Throwable): Unit = deregisterThread() + final override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = { + var result: T = null.asInstanceOf[T] + ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker { + @volatile var isdone = false + override def block(): Boolean = { + result = try { + // When we block, switch out the BlockContext temporarily so that nested blocking does not created N new Threads + BlockContext.withBlockContext(BlockContext.defaultBlockContext) { thunk } + } finally { + isdone = true + } + + true + } + override def isReleasable = isdone + }) + result } - override def isReleasable = isdone }) - result - } - }) + } else null } - def createExecutorService: ExecutorService = { - + def createDefaultExecutorService(reporter: Throwable => Unit): ExecutorService = { def getInt(name: String, default: String) = (try System.getProperty(name, default) catch { case e: SecurityException => default }) match { @@ -65,87 +97,79 @@ private[scala] class ExecutionContextImpl private[impl] (es: Executor, reporter: } def range(floor: Int, desired: Int, ceiling: Int) = scala.math.min(scala.math.max(floor, desired), ceiling) + val numThreads = getInt("scala.concurrent.context.numThreads", "x1") + // The hard limit on the number of active threads that the thread factory will produce + // SI-8955 Deadlocks can happen if maxNoOfThreads is too low, although we're currently not sure + // about what the exact threshold is. numThreads + 256 is conservatively high. + val maxNoOfThreads = getInt("scala.concurrent.context.maxThreads", "x1") val desiredParallelism = range( getInt("scala.concurrent.context.minThreads", "1"), - getInt("scala.concurrent.context.numThreads", "x1"), - getInt("scala.concurrent.context.maxThreads", "x1")) - - val threadFactory = new DefaultThreadFactory(daemonic = true) - - try { - new ForkJoinPool( - desiredParallelism, - threadFactory, - uncaughtExceptionHandler, - true) // Async all the way baby - } catch { - case NonFatal(t) => - System.err.println("Failed to create ForkJoinPool for the default ExecutionContext, falling back to ThreadPoolExecutor") - t.printStackTrace(System.err) - val exec = new ThreadPoolExecutor( - desiredParallelism, - desiredParallelism, - 5L, - TimeUnit.MINUTES, - new LinkedBlockingQueue[Runnable], - threadFactory - ) - exec.allowCoreThreadTimeOut(true) - exec - } - } + numThreads, + maxNoOfThreads) - def execute(runnable: Runnable): Unit = executor match { - case fj: ForkJoinPool => - val fjt: ForkJoinTask[_] = runnable match { - case t: ForkJoinTask[_] => t - case r => new ExecutionContextImpl.AdaptedForkJoinTask(r) - } - Thread.currentThread match { - case fjw: ForkJoinWorkerThread if fjw.getPool eq fj => fjt.fork() - case _ => fj execute fjt - } - case generic => generic execute runnable - } + // The thread factory must provide additional threads to support managed blocking. + val maxExtraThreads = getInt("scala.concurrent.context.maxExtraThreads", "256") - def reportFailure(t: Throwable) = reporter(t) -} + val uncaughtExceptionHandler: Thread.UncaughtExceptionHandler = new Thread.UncaughtExceptionHandler { + override def uncaughtException(thread: Thread, cause: Throwable): Unit = reporter(cause) + } + val threadFactory = new ExecutionContextImpl.DefaultThreadFactory(daemonic = true, + maxThreads = maxNoOfThreads + maxExtraThreads, + prefix = "scala-execution-context-global", + uncaught = uncaughtExceptionHandler) -private[concurrent] object ExecutionContextImpl { + new ForkJoinPool(desiredParallelism, threadFactory, uncaughtExceptionHandler, true) { + override def execute(runnable: Runnable): Unit = { + val fjt: ForkJoinTask[_] = runnable match { + case t: ForkJoinTask[_] => t + case r => new ExecutionContextImpl.AdaptedForkJoinTask(r) + } + Thread.currentThread match { + case fjw: ForkJoinWorkerThread if fjw.getPool eq this => fjt.fork() + case _ => super.execute(fjt) + } + } + } + } final class AdaptedForkJoinTask(runnable: Runnable) extends ForkJoinTask[Unit] { - final override def setRawResult(u: Unit): Unit = () - final override def getRawResult(): Unit = () - final override def exec(): Boolean = try { runnable.run(); true } catch { - case anything: Throwable ⇒ - val t = Thread.currentThread - t.getUncaughtExceptionHandler match { - case null ⇒ - case some ⇒ some.uncaughtException(t, anything) - } - throw anything - } + final override def setRawResult(u: Unit): Unit = () + final override def getRawResult(): Unit = () + final override def exec(): Boolean = try { runnable.run(); true } catch { + case anything: Throwable => + val t = Thread.currentThread + t.getUncaughtExceptionHandler match { + case null => + case some => some.uncaughtException(t, anything) } + throw anything + } + } - def fromExecutor(e: Executor, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl = new ExecutionContextImpl(e, reporter) - def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl with ExecutionContextExecutorService = - new ExecutionContextImpl(es, reporter) with ExecutionContextExecutorService { - final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService] - override def execute(command: Runnable) = executor.execute(command) - override def shutdown() { asExecutorService.shutdown() } - override def shutdownNow() = asExecutorService.shutdownNow() - override def isShutdown = asExecutorService.isShutdown - override def isTerminated = asExecutorService.isTerminated - override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit) - override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable) - override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t) - override def submit(runnable: Runnable) = asExecutorService.submit(runnable) - override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables) - override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit) - override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables) - override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit) + def fromExecutor(e: Executor, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextImpl = + new ExecutionContextImpl(Option(e).getOrElse(createDefaultExecutorService(reporter)), reporter) + + def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter): + ExecutionContextImpl with ExecutionContextExecutorService = { + new ExecutionContextImpl(Option(es).getOrElse(createDefaultExecutorService(reporter)), reporter) + with ExecutionContextExecutorService { + final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService] + override def execute(command: Runnable) = executor.execute(command) + override def shutdown() { asExecutorService.shutdown() } + override def shutdownNow() = asExecutorService.shutdownNow() + override def isShutdown = asExecutorService.isShutdown + override def isTerminated = asExecutorService.isTerminated + override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit) + override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable) + override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t) + override def submit(runnable: Runnable) = asExecutorService.submit(runnable) + override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables) + override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit) + override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables) + override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit) + } } } diff --git a/src/library/scala/concurrent/impl/Future.scala b/src/library/scala/concurrent/impl/Future.scala deleted file mode 100644 index 042d32c234..0000000000 --- a/src/library/scala/concurrent/impl/Future.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala.concurrent.impl - - - -import scala.concurrent.ExecutionContext -import scala.util.control.NonFatal -import scala.util.{ Success, Failure } - - -private[concurrent] object Future { - class PromiseCompletingRunnable[T](body: => T) extends Runnable { - val promise = new Promise.DefaultPromise[T]() - - override def run() = { - promise complete { - try Success(body) catch { case NonFatal(e) => Failure(e) } - } - } - } - - def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = { - val runnable = new PromiseCompletingRunnable(body) - executor.prepare.execute(runnable) - runnable.promise.future - } -} diff --git a/src/library/scala/concurrent/impl/Promise.scala b/src/library/scala/concurrent/impl/Promise.scala index 6d2fc5c87c..7fcc8c9f2d 100644 --- a/src/library/scala/concurrent/impl/Promise.scala +++ b/src/library/scala/concurrent/impl/Promise.scala @@ -8,17 +8,41 @@ package scala.concurrent.impl -import scala.concurrent.{ ExecutionContext, CanAwait, OnCompleteRunnable, TimeoutException, ExecutionException, blocking } +import scala.concurrent.{ ExecutionContext, CanAwait, OnCompleteRunnable, TimeoutException, ExecutionException } import scala.concurrent.Future.InternalCallbackExecutor -import scala.concurrent.duration.{ Duration, Deadline, FiniteDuration, NANOSECONDS } +import scala.concurrent.duration.{ Duration, FiniteDuration } import scala.annotation.tailrec import scala.util.control.NonFatal import scala.util.{ Try, Success, Failure } -import java.io.ObjectInputStream + import java.util.concurrent.locks.AbstractQueuedSynchronizer +import java.util.concurrent.atomic.AtomicReference private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] { def future: this.type = this + + import scala.concurrent.Future + import scala.concurrent.impl.Promise.DefaultPromise + + override def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] = { + val p = new DefaultPromise[S]() + onComplete { result => p.complete(try f(result) catch { case NonFatal(t) => Failure(t) }) } + p.future + } + + // If possible, link DefaultPromises to avoid space leaks + override def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] = { + val p = new DefaultPromise[S]() + onComplete { + v => try f(v) match { + case fut if fut eq this => p complete v.asInstanceOf[Try[S]] + case dp: DefaultPromise[_] => dp.asInstanceOf[DefaultPromise[S]].linkRootOf(p) + case fut => p completeWith fut + } catch { case NonFatal(t) => p failure t } + } + p.future + } + override def toString: String = value match { case Some(result) => "Future("+result+")" case None => "Future(<not completed>)" @@ -27,7 +51,7 @@ private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with sc /* Precondition: `executor` is prepared, i.e., `executor` has been returned from invocation of `prepare` on some other `ExecutionContext`. */ -private class CallbackRunnable[T](val executor: ExecutionContext, val onComplete: Try[T] => Any) extends Runnable with OnCompleteRunnable { +private final class CallbackRunnable[T](val executor: ExecutionContext, val onComplete: Try[T] => Any) extends Runnable with OnCompleteRunnable { // must be filled in before running it var value: Try[T] = null @@ -93,7 +117,7 @@ private[concurrent] object Promise { * incomplete, or as complete with the same result value. * * A DefaultPromise stores its state entirely in the AnyRef cell exposed by - * AbstractPromise. The type of object stored in the cell fully describes the + * AtomicReference. The type of object stored in the cell fully describes the * current state of the promise. * * 1. List[CallbackRunnable] - The promise is incomplete and has zero or more callbacks @@ -154,8 +178,9 @@ private[concurrent] object Promise { * DefaultPromises, and `linkedRootOf` is currently only designed to be called * by Future.flatMap. */ - class DefaultPromise[T] extends AbstractPromise with Promise[T] { self => - updateState(null, Nil) // The promise is incomplete and has no callbacks + // Left non-final to enable addition of extra fields by Java/Scala converters + // in scala-java8-compat. + class DefaultPromise[T] extends AtomicReference[AnyRef](Nil) with Promise[T] { /** Get the root promise for this promise, compressing the link chain to that * promise if necessary. @@ -171,14 +196,23 @@ private[concurrent] object Promise { * be garbage collected. Also, subsequent calls to this method should be * faster as the link chain will be shorter. */ - @tailrec - private def compressedRoot(): DefaultPromise[T] = { - getState match { - case linked: DefaultPromise[_] => - val target = linked.asInstanceOf[DefaultPromise[T]].root - if (linked eq target) target else if (updateState(linked, target)) target else compressedRoot() + private def compressedRoot(): DefaultPromise[T] = + get() match { + case linked: DefaultPromise[_] => compressedRoot(linked) case _ => this } + + @tailrec + private[this] final def compressedRoot(linked: DefaultPromise[_]): DefaultPromise[T] = { + val target = linked.asInstanceOf[DefaultPromise[T]].root + if (linked eq target) target + else if (compareAndSet(linked, target)) target + else { + get() match { + case newLinked: DefaultPromise[_] => compressedRoot(newLinked) + case _ => this + } + } } /** Get the promise at the root of the chain of linked promises. Used by `compressedRoot()`. @@ -186,18 +220,16 @@ private[concurrent] object Promise { * to compress the link chain whenever possible. */ @tailrec - private def root: DefaultPromise[T] = { - getState match { + private def root: DefaultPromise[T] = + get() match { case linked: DefaultPromise[_] => linked.asInstanceOf[DefaultPromise[T]].root case _ => this } - } /** Try waiting for this promise to be completed. */ protected final def tryAwait(atMost: Duration): Boolean = if (!isCompleted) { import Duration.Undefined - import scala.concurrent.Future.InternalCallbackExecutor atMost match { case e if e eq Undefined => throw new IllegalArgumentException("cannot wait for Undefined period") case Duration.Inf => @@ -218,33 +250,33 @@ private[concurrent] object Promise { @throws(classOf[TimeoutException]) @throws(classOf[InterruptedException]) - def ready(atMost: Duration)(implicit permit: CanAwait): this.type = + final def ready(atMost: Duration)(implicit permit: CanAwait): this.type = if (tryAwait(atMost)) this else throw new TimeoutException("Futures timed out after [" + atMost + "]") @throws(classOf[Exception]) - def result(atMost: Duration)(implicit permit: CanAwait): T = + final def result(atMost: Duration)(implicit permit: CanAwait): T = ready(atMost).value.get.get // ready throws TimeoutException if timeout so value.get is safe here def value: Option[Try[T]] = value0 @tailrec - private def value0: Option[Try[T]] = getState match { + private def value0: Option[Try[T]] = get() match { case c: Try[_] => Some(c.asInstanceOf[Try[T]]) - case _: DefaultPromise[_] => compressedRoot().value0 + case dp: DefaultPromise[_] => compressedRoot(dp).value0 case _ => None } - override def isCompleted: Boolean = isCompleted0 + override final def isCompleted: Boolean = isCompleted0 @tailrec - private def isCompleted0: Boolean = getState match { + private def isCompleted0: Boolean = get() match { case _: Try[_] => true - case _: DefaultPromise[_] => compressedRoot().isCompleted0 + case dp: DefaultPromise[_] => compressedRoot(dp).isCompleted0 case _ => false } - def tryComplete(value: Try[T]): Boolean = { + final def tryComplete(value: Try[T]): Boolean = { val resolved = resolveTry(value) tryCompleteAndGetListeners(resolved) match { case null => false @@ -258,37 +290,34 @@ private[concurrent] object Promise { */ @tailrec private def tryCompleteAndGetListeners(v: Try[T]): List[CallbackRunnable[T]] = { - getState match { + get() match { case raw: List[_] => val cur = raw.asInstanceOf[List[CallbackRunnable[T]]] - if (updateState(cur, v)) cur else tryCompleteAndGetListeners(v) - case _: DefaultPromise[_] => - compressedRoot().tryCompleteAndGetListeners(v) + if (compareAndSet(cur, v)) cur else tryCompleteAndGetListeners(v) + case dp: DefaultPromise[_] => compressedRoot(dp).tryCompleteAndGetListeners(v) case _ => null } } - def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = { - val preparedEC = executor.prepare() - val runnable = new CallbackRunnable[T](preparedEC, func) - dispatchOrAddCallback(runnable) - } + final def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = + dispatchOrAddCallback(new CallbackRunnable[T](executor.prepare(), func)) /** Tries to add the callback, if already completed, it dispatches the callback to be executed. * Used by `onComplete()` to add callbacks to a promise and by `link()` to transfer callbacks - * to the root promise when linking two promises togehter. + * to the root promise when linking two promises together. */ @tailrec private def dispatchOrAddCallback(runnable: CallbackRunnable[T]): Unit = { - getState match { + get() match { case r: Try[_] => runnable.executeWithValue(r.asInstanceOf[Try[T]]) - case _: DefaultPromise[_] => compressedRoot().dispatchOrAddCallback(runnable) - case listeners: List[_] => if (updateState(listeners, runnable :: listeners)) () else dispatchOrAddCallback(runnable) + case dp: DefaultPromise[_] => compressedRoot(dp).dispatchOrAddCallback(runnable) + case listeners: List[_] => if (compareAndSet(listeners, runnable :: listeners)) () + else dispatchOrAddCallback(runnable) } } /** Link this promise to the root of another promise using `link()`. Should only be - * be called by Future.flatMap. + * be called by transformWith. */ protected[concurrent] final def linkRootOf(target: DefaultPromise[T]): Unit = link(target.compressedRoot()) @@ -303,18 +332,17 @@ private[concurrent] object Promise { */ @tailrec private def link(target: DefaultPromise[T]): Unit = if (this ne target) { - getState match { + get() match { case r: Try[_] => - if (!target.tryComplete(r.asInstanceOf[Try[T]])) { - // Currently linking is done from Future.flatMap, which should ensure only - // one promise can be completed. Therefore this situation is unexpected. + if (!target.tryComplete(r.asInstanceOf[Try[T]])) throw new IllegalStateException("Cannot link completed promises together") - } - case _: DefaultPromise[_] => - compressedRoot().link(target) - case listeners: List[_] => if (updateState(listeners, target)) { - if (!listeners.isEmpty) listeners.asInstanceOf[List[CallbackRunnable[T]]].foreach(target.dispatchOrAddCallback(_)) - } else link(target) + case dp: DefaultPromise[_] => + compressedRoot(dp).link(target) + case listeners: List[_] if compareAndSet(listeners, target) => + if (listeners.nonEmpty) + listeners.asInstanceOf[List[CallbackRunnable[T]]].foreach(target.dispatchOrAddCallback(_)) + case _ => + link(target) } } } @@ -323,23 +351,58 @@ private[concurrent] object Promise { * * Useful in Future-composition when a value to contribute is already available. */ - final class KeptPromise[T](suppliedValue: Try[T]) extends Promise[T] { + object KeptPromise { + import scala.concurrent.Future + import scala.reflect.ClassTag + + private[this] sealed trait Kept[T] extends Promise[T] { + def result: Try[T] + + override def value: Option[Try[T]] = Some(result) - val value = Some(resolveTry(suppliedValue)) + override def isCompleted: Boolean = true - override def isCompleted: Boolean = true + override def tryComplete(value: Try[T]): Boolean = false - def tryComplete(value: Try[T]): Boolean = false + override def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = + (new CallbackRunnable(executor.prepare(), func)).executeWithValue(result) - def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = { - val completedAs = value.get - val preparedEC = executor.prepare() - (new CallbackRunnable(preparedEC, func)).executeWithValue(completedAs) + override def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this + + override def result(atMost: Duration)(implicit permit: CanAwait): T = result.get } - def ready(atMost: Duration)(implicit permit: CanAwait): this.type = this + private[this] final class Successful[T](val result: Success[T]) extends Kept[T] { + override def onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = () + override def failed: Future[Throwable] = KeptPromise(Failure(new NoSuchElementException("Future.failed not completed with a throwable."))).future + override def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = this + override def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = this + override def fallbackTo[U >: T](that: Future[U]): Future[U] = this + } - def result(atMost: Duration)(implicit permit: CanAwait): T = value.get.get + private[this] final class Failed[T](val result: Failure[T]) extends Kept[T] { + private[this] final def thisAs[S]: Future[S] = future.asInstanceOf[Future[S]] + + override def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = () + override def failed: Future[Throwable] = KeptPromise(Success(result.exception)).future + override def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = () + override def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = thisAs[S] + override def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = thisAs[S] + override def flatten[S](implicit ev: T <:< Future[S]): Future[S] = thisAs[S] + override def filter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = this + override def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = thisAs[S] + override def zip[U](that: Future[U]): Future[(T, U)] = thisAs[(T,U)] + override def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] = thisAs[R] + override def fallbackTo[U >: T](that: Future[U]): Future[U] = + if (this eq that) this else that.recoverWith({ case _ => this })(InternalCallbackExecutor) + override def mapTo[S](implicit tag: ClassTag[S]): Future[S] = thisAs[S] + } + + def apply[T](result: Try[T]): scala.concurrent.Promise[T] = + resolveTry(result) match { + case s @ Success(_) => new Successful(s) + case f @ Failure(_) => new Failed(f) + } } } diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala index d159dda414..0695ee3351 100644 --- a/src/library/scala/concurrent/package.scala +++ b/src/library/scala/concurrent/package.scala @@ -20,14 +20,33 @@ import scala.annotation.implicitNotFound * [[http://docs.scala-lang.org/overviews/core/futures.html]]. * * == Common Imports == - * + * * When working with Futures, you will often find that importing the whole concurrent - * package is convenient, furthermore you are likely to need an implicit ExecutionContext - * in scope for many operations involving Futures and Promises: - * + * package is convenient: + * * {{{ * import scala.concurrent._ - * import ExecutionContext.Implicits.global + * }}} + * + * When using things like `Future`s, it is often required to have an implicit `ExecutionContext` + * in scope. The general advice for these implicits are as follows. + * + * If the code in question is a class or method definition, and no `ExecutionContext` is available, + * request one from the caller by adding an implicit parameter list: + * + * {{{ + * def myMethod(myParam: MyType)(implicit ec: ExecutionContext) = … + * //Or + * class MyClass(myParam: MyType)(implicit ec: ExecutionContext) { … } + * }}} + * + * This allows the caller of the method, or creator of the instance of the class, to decide which + * `ExecutionContext` should be used. + * + * For typical REPL usage and experimentation, importing the global `ExecutionContext` is often desired. + * + * {{{ + * import scala.concurrent.ExcutionContext.Implicits.global * }}} * * == Specifying Durations == @@ -41,7 +60,7 @@ import scala.annotation.implicitNotFound * }}} * * == Using Futures For Non-blocking Computation == - * + * * Basic use of futures is easy with the factory method on Future, which executes a * provided function asynchronously, handing you back a future result of that function * without blocking the current thread. In order to create the Future you will need @@ -50,7 +69,7 @@ import scala.annotation.implicitNotFound * {{{ * import scala.concurrent._ * import ExecutionContext.Implicits.global // implicit execution context - * + * * val firstZebra: Future[Int] = Future { * val source = scala.io.Source.fromFile("/etc/dictionaries-common/words") * source.toSeq.indexOfSlice("zebra") @@ -80,7 +99,7 @@ import scala.annotation.implicitNotFound * animalRange.onSuccess { * case x if x > 500000 => println("It's a long way from Aardvark to Zebra") * } - * }}} + * }}} */ package object concurrent { type ExecutionException = java.util.concurrent.ExecutionException @@ -96,7 +115,7 @@ package object concurrent { * @param executor the execution context on which the future is run * @return the `Future` holding the result of the computation */ - @deprecated("Use `Future { ... }` instead.", "2.11.0") + @deprecated("use `Future { ... }` instead", "2.11.0") // removal planned for 2.13.0 def future[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = Future[T](body) @@ -105,7 +124,7 @@ package object concurrent { * @tparam T the type of the value in the promise * @return the newly created `Promise` object */ - @deprecated("Use `Promise[T]()` instead.", "2.11.0") + @deprecated("use `Promise[T]()` instead", "2.11.0") // removal planned for 2.13.0 def promise[T](): Promise[T] = Promise[T]() @@ -140,17 +159,20 @@ package concurrent { /** * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances. * - * While occasionally useful, e.g. for testing, it is recommended that you avoid Await - * when possible in favor of callbacks and combinators like onComplete and use in - * for comprehensions. Await will block the thread on which it runs, and could cause - * performance and deadlock issues. + * While occasionally useful, e.g. for testing, it is recommended that you avoid Await whenever possible— + * instead favoring combinators and/or callbacks. + * Await's `result` and `ready` methods will block the calling thread's execution until they return, + * which will cause performance degradation, and possibly, deadlock issues. */ object Await { /** * Await the "completed" state of an `Awaitable`. * * Although this method is blocking, the internal use of [[scala.concurrent.blocking blocking]] ensures that - * the underlying [[ExecutionContext]] is prepared to properly manage the blocking. + * the underlying [[ExecutionContext]] is given an opportunity to properly manage the blocking. + * + * WARNING: It is strongly discouraged to supply lengthy timeouts since the progress of the calling thread will be + * suspended—blocked—until either the `Awaitable` becomes ready or the timeout expires. * * @param awaitable * the `Awaitable` to be awaited @@ -172,7 +194,10 @@ package concurrent { * Await and return the result (of type `T`) of an `Awaitable`. * * Although this method is blocking, the internal use of [[scala.concurrent.blocking blocking]] ensures that - * the underlying [[ExecutionContext]] to properly detect blocking and ensure that there are no deadlocks. + * the underlying [[ExecutionContext]] is given an opportunity to properly manage the blocking. + * + * WARNING: It is strongly discouraged to supply lengthy timeouts since the progress of the calling thread will be + * suspended—blocked—until either the `Awaitable` has a result or the timeout expires. * * @param awaitable * the `Awaitable` to be awaited diff --git a/src/library/scala/deprecated.scala b/src/library/scala/deprecated.scala index e940a4bfbe..a57745dbea 100644 --- a/src/library/scala/deprecated.scala +++ b/src/library/scala/deprecated.scala @@ -11,11 +11,54 @@ package scala import scala.annotation.meta._ /** An annotation that designates that a definition is deprecated. - * Access to the member then generates a deprecated warning. + * A deprecation warning is issued upon usage of the annotated definition. * + * Library authors should state the library's deprecation policy in their documentation to give + * developers guidance on how long a deprecated definition will be preserved. + * + * Library authors should prepend the name of their library to the version number to help + * developers distinguish deprecations coming from different libraries: + * + * {{{ + * @deprecated("this method will be removed", "FooLib 12.0") + * def oldMethod(x: Int) = ... + * }}} + * + * The compiler will emit deprecation warnings grouped by library and version: + * + * {{{ + * oldMethod(1) + * oldMethod(2) + * aDeprecatedMethodFromLibraryBar(3, 4) + * + * // warning: there was one deprecation warning (since BarLib 3.2) + * // warning: there were two deprecation warnings (since FooLib 12.0) + * // warning: there were three deprecation warnings in total; re-run with -deprecation for details + * }}} + * + * '''`@deprecated` in the Scala language and its standard library'''<br/> + * + * A deprecated element of the Scala language or a definition in the Scala standard library will + * be preserved at least for the current major version. + * + * This means that an element deprecated in some 2.12.x release will be preserved in + * all 2.12.x releases, but may be removed in 2.13. (A deprecated element + * might be kept longer to ease migration. Developers should not rely on this.) + * + * '''Special deprecation policy for Scala 2.12'''<br> + * The Scala team has decided to enact a special deprecation policy for Scala 2.12:<br/> + * + * As an upgrade from 2.11 to 2.12 also requires upgrading from Java 6 to Java 8, + * deprecated elements will not normally be removed in this release, to ease migration + * and cross-building. + * + * @see The official documentation on [[http://www.scala-lang.org/news/2.11.0/#binary-compatibility binary compatibility]]. * @param message the message to print during compilation if the definition is accessed * @param since a string identifying the first version in which the definition was deprecated * @since 2.3 + * @see [[scala.deprecatedInheritance]] + * @see [[scala.deprecatedOverriding]] + * @see [[scala.deprecatedName]] */ @getter @setter @beanGetter @beanSetter class deprecated(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation diff --git a/src/library/scala/deprecatedInheritance.scala b/src/library/scala/deprecatedInheritance.scala index 7d20219d4d..994eac9ed8 100644 --- a/src/library/scala/deprecatedInheritance.scala +++ b/src/library/scala/deprecatedInheritance.scala @@ -8,16 +8,40 @@ package scala +import scala.annotation.meta._ + /** An annotation that designates that inheriting from a class is deprecated. * * This is usually done to warn about a non-final class being made final in a future version. - * Sub-classing such a class then generates a warning. No warnings are generated if the - * subclass is in the same compilation unit. + * Sub-classing such a class then generates a warning. + * + * No warnings are generated if the subclass is in the same compilation unit. + * + * Library authors should state the library's deprecation policy in their documentation to give + * developers guidance on when a type annotated with `@deprecatedInheritance` will be `final`ized. + * + * Library authors should prepend the name of their library to the version number to help + * developers distinguish deprecations coming from different libraries: + * + * {{{ + * @deprecatedInheritance("this class will be made final", "FooLib 12.0") + * class Foo + * }}} + * + * {{{ + * val foo = new Foo // no deprecation warning + * class Bar extends Foo + * // warning: inheritance from class Foo is deprecated (since FooLib 12.0): this class will be made final + * // class Bar extends Foo + * // ^ + * }}} * * @param message the message to print during compilation if the class was sub-classed * @param since a string identifying the first version in which inheritance was deprecated * @since 2.10 + * @see [[scala.deprecated]] * @see [[scala.deprecatedOverriding]] + * @see [[scala.deprecatedName]] */ -private[scala] // for now, this needs to be generalized to communicate other modifier deltas +@getter @setter @beanGetter @beanSetter class deprecatedInheritance(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation diff --git a/src/library/scala/deprecatedName.scala b/src/library/scala/deprecatedName.scala index 07c5c8925c..f8c6bd32ad 100644 --- a/src/library/scala/deprecatedName.scala +++ b/src/library/scala/deprecatedName.scala @@ -10,23 +10,32 @@ package scala import scala.annotation.meta._ -/** - * An annotation that designates the name of the parameter to which it is - * applied as deprecated. Using that name in a named argument generates - * a deprecation warning. - * - * For instance, evaluating the code below in the Scala interpreter - * {{{ - * def inc(x: Int, @deprecatedName('y) n: Int): Int = x + n - * inc(1, y = 2) - * }}} - * will produce the following output: - * {{{ - * warning: there were 1 deprecation warnings; re-run with -deprecation for details - * res0: Int = 3 - * }}} - * - * @since 2.8.1 - */ + + /** An annotation that designates that the name of a parameter is deprecated. + * + * Using this name in a named argument generates a deprecation warning. + * + * Library authors should state the library's deprecation policy in their documentation to give + * developers guidance on how long a deprecated name will be preserved. + * + * Library authors should prepend the name of their library to the version number to help + * developers distinguish deprecations coming from different libraries: + * + * {{{ + * def inc(x: Int, @deprecatedName('y, "FooLib 12.0") n: Int): Int = x + n + * inc(1, y = 2) + * }}} + * will produce the following warning: + * {{{ + * warning: the parameter name y is deprecated (since FooLib 12.0): use n instead + * inc(1, y = 2) + * ^ + * }}} + * + * @since 2.8.1 + * @see [[scala.deprecated]] + * @see [[scala.deprecatedInheritance]] + * @see [[scala.deprecatedOverriding]] + */ @param -class deprecatedName(name: Symbol) extends scala.annotation.StaticAnnotation +class deprecatedName(name: Symbol = Symbol("<none>"), since: String = "") extends scala.annotation.StaticAnnotation diff --git a/src/library/scala/deprecatedOverriding.scala b/src/library/scala/deprecatedOverriding.scala index 04bce343a0..5be6830b27 100644 --- a/src/library/scala/deprecatedOverriding.scala +++ b/src/library/scala/deprecatedOverriding.scala @@ -8,14 +8,41 @@ package scala +import scala.annotation.meta._ + /** An annotation that designates that overriding a member is deprecated. * * Overriding such a member in a sub-class then generates a warning. * + * Library authors should state the library's deprecation policy in their documentation to give + * developers guidance on when a method annotated with `@deprecatedOverriding` will be `final`ized. + * + * Library authors should prepend the name of their library to the version number to help + * developers distinguish deprecations coming from different libraries: + * + * {{{ + * class Foo { + * @deprecatedOverriding("this method will be made final", "FooLib 12.0") + * def add(x: Int, y: Int) = x + y + * } + * }}} + * + * {{{ + * class Bar extends Foo // no deprecation warning + * class Baz extends Foo { + * override def add(x: Int, y: Int) = x - y + * } + * // warning: overriding method add in class Foo is deprecated (since FooLib 12.0): this method will be made final + * // override def add(x: Int, y: Int) = x - y + * // ^ + * }}} + * * @param message the message to print during compilation if the member was overridden * @param since a string identifying the first version in which overriding was deprecated * @since 2.10 + * @see [[scala.deprecated]] * @see [[scala.deprecatedInheritance]] + * @see [[scala.deprecatedName]] */ -private[scala] // for the same reasons as deprecatedInheritance +@getter @setter @beanGetter @beanSetter class deprecatedOverriding(message: String = "", since: String = "") extends scala.annotation.StaticAnnotation diff --git a/src/library/scala/inline.scala b/src/library/scala/inline.scala index a21cced928..f188ccab07 100644 --- a/src/library/scala/inline.scala +++ b/src/library/scala/inline.scala @@ -11,8 +11,30 @@ package scala /** - * An annotation on methods that requests that the compiler should - * try especially hard to inline the annotated method. + * An annotation on methods that requests that the compiler should try especially hard to inline the + * annotated method. The annotation can be used at definition site or at callsite. + * + * {{{ + * @inline final def f1(x: Int) = x + * @noinline final def f2(x: Int) = x + * final def f3(x: Int) = x + * + * def t1 = f1(1) // inlined if possible + * def t2 = f2(1) // not inlined + * def t3 = f3(1) // may be inlined (heuristics) + * def t4 = f1(1): @noinline // not inlined (override at callsite) + * def t5 = f2(1): @inline // inlined if possible (override at callsite) + * def t6 = f3(1): @inline // inlined if possible + * def t7 = f3(1): @noinline // not inlined + * } + * }}} + * + * Note: parentheses are required when annotating a callsite within a larger expression. + * + * {{{ + * def t1 = f1(1) + f1(1): @noinline // equivalent to (f1(1) + f1(1)): @noinline + * def t2 = f1(1) + (f1(1): @noinline) // the second call to f1 is not inlined + * }}} * * @author Lex Spoon * @version 1.0, 2007-5-21 diff --git a/src/library/scala/io/AnsiColor.scala b/src/library/scala/io/AnsiColor.scala index 39e2e3b0ca..df589bc66c 100644 --- a/src/library/scala/io/AnsiColor.scala +++ b/src/library/scala/io/AnsiColor.scala @@ -1,52 +1,163 @@ package scala package io +/** ANSI escape codes providing control over text formatting and color on supporting text terminals. + * + * ==ANSI Style and Control Codes== + * + * This group of escape codes provides control over text styling. For example, to turn on reverse video with bold and + * then turn off all styling embed these codes, + * + * {{{ + * import io.AnsiColor._ + * + * object ColorDemo extends App { + * + * println(s"${REVERSED}${BOLD}Hello 1979!${RESET}") + * } + * }}} + * + * ==Foreground and Background Colors== + * + * Embedding ANSI color codes in text output will control the text foreground and background colors. + * + * <table> + * <tr><th style="padding:4px 15px;text-decoration:underline">Foreground</th><th style="width:50%"></th><th style="padding:4px 15px;text-decoration:underline">Background</th></tr> + * <tr><td style="padding:4px 15px">BLACK </td><td style="background-color:#000"></td><td style="padding:4px 15px">BLACK_B </td></tr> + * <tr><td style="padding:4px 15px">RED </td><td style="background-color:#f00"></td><td style="padding:4px 15px">RED_B </td></tr> + * <tr><td style="padding:4px 15px">GREEN </td><td style="background-color:#0f0"></td><td style="padding:4px 15px">GREEN_B </td></tr> + * <tr><td style="padding:4px 15px">YELLOW </td><td style="background-color:#ff0"></td><td style="padding:4px 15px">YELLOW_B </td></tr> + * <tr><td style="padding:4px 15px">BLUE </td><td style="background-color:#00f"></td><td style="padding:4px 15px">BLUE_B </td></tr> + * <tr><td style="padding:4px 15px">MAGENTA</td><td style="background-color:#f0f"></td><td style="padding:4px 15px">MAGENTA_B</td></tr> + * <tr><td style="padding:4px 15px">CYAN </td><td style="background-color:#0ff"></td><td style="padding:4px 15px">CYAN_B </td></tr> + * <tr><td style="padding:4px 15px">WHITE </td><td style="background-color:#fff"></td><td style="padding:4px 15px">WHITE_B </td></tr> + * </table> + * + * @groupname style-control ANSI Style and Control Codes + * @groupprio style-control 101 + * + * @groupname color-black ANSI Black + * @groupdesc color-black <table style="width:100%"><tr><td style="background-color:#000"> </td></tr></table> + * @groupprio color-black 110 + * + * @groupname color-red ANSI Red + * @groupdesc color-red <table style="width:100%"><tr><td style="background-color:#f00"> </td></tr></table> + * @groupprio color-red 120 + * + * @groupname color-green ANSI Green + * @groupdesc color-green <table style="width:100%"><tr><td style="background-color:#0f0"> </td></tr></table> + * @groupprio color-green 130 + * + * @groupname color-yellow ANSI Yellow + * @groupdesc color-yellow <table style="width:100%"><tr><td style="background-color:#ff0"> </td></tr></table> + * @groupprio color-yellow 140 + * + * @groupname color-blue ANSI Blue + * @groupdesc color-blue <table style="width:100%"><tr><td style="background-color:#00f"> </td></tr></table> + * @groupprio color-blue 150 + * + * @groupname color-magenta ANSI Magenta + * @groupdesc color-magenta <table style="width:100%"><tr><td style="background-color:#f0f"> </td></tr></table> + * @groupprio color-magenta 160 + * + * @groupname color-cyan ANSI Cyan + * @groupdesc color-cyan <table style="width:100%"><tr><td style="background-color:#0ff"> </td></tr></table> + * @groupprio color-cyan 170 + * + * @groupname color-white ANSI White + * @groupdesc color-white <table style="width:100%"><tr><td style="background-color:#fff"> </td></tr></table> + * @groupprio color-white 180 + */ trait AnsiColor { - /** Foreground color for ANSI black */ + /** Foreground color for ANSI black + * @group color-black + */ final val BLACK = "\u001b[30m" - /** Foreground color for ANSI red */ + /** Foreground color for ANSI red + * @group color-red + */ final val RED = "\u001b[31m" - /** Foreground color for ANSI green */ + /** Foreground color for ANSI green + * @group color-green + */ final val GREEN = "\u001b[32m" - /** Foreground color for ANSI yellow */ + /** Foreground color for ANSI yellow + * @group color-yellow + */ final val YELLOW = "\u001b[33m" - /** Foreground color for ANSI blue */ + /** Foreground color for ANSI blue + * @group color-blue + */ final val BLUE = "\u001b[34m" - /** Foreground color for ANSI magenta */ + /** Foreground color for ANSI magenta + * @group color-magenta + */ final val MAGENTA = "\u001b[35m" - /** Foreground color for ANSI cyan */ + /** Foreground color for ANSI cyan + * @group color-cyan + */ final val CYAN = "\u001b[36m" - /** Foreground color for ANSI white */ + /** Foreground color for ANSI white + * @group color-white + */ final val WHITE = "\u001b[37m" - /** Background color for ANSI black */ + /** Background color for ANSI black + * @group color-black + */ final val BLACK_B = "\u001b[40m" - /** Background color for ANSI red */ + /** Background color for ANSI red + * @group color-red + */ final val RED_B = "\u001b[41m" - /** Background color for ANSI green */ + /** Background color for ANSI green + * @group color-green + */ final val GREEN_B = "\u001b[42m" - /** Background color for ANSI yellow */ + /** Background color for ANSI yellow + * @group color-yellow + */ final val YELLOW_B = "\u001b[43m" - /** Background color for ANSI blue */ + /** Background color for ANSI blue + * @group color-blue + */ final val BLUE_B = "\u001b[44m" - /** Background color for ANSI magenta */ + /** Background color for ANSI magenta + * @group color-magenta + */ final val MAGENTA_B = "\u001b[45m" - /** Background color for ANSI cyan */ + /** Background color for ANSI cyan + * @group color-cyan + */ final val CYAN_B = "\u001b[46m" - /** Background color for ANSI white */ + /** Background color for ANSI white + * @group color-white + */ final val WHITE_B = "\u001b[47m" - /** Reset ANSI styles */ + /** Reset ANSI styles + * @group style-control + */ final val RESET = "\u001b[0m" - /** ANSI bold */ + /** ANSI bold + * @group style-control + */ final val BOLD = "\u001b[1m" - /** ANSI underlines */ + /** ANSI underlines + * @group style-control + */ final val UNDERLINED = "\u001b[4m" - /** ANSI blink */ + /** ANSI blink + * @group style-control + */ final val BLINK = "\u001b[5m" - /** ANSI reversed */ + /** ANSI reversed + * @group style-control + */ final val REVERSED = "\u001b[7m" - /** ANSI invisible */ + /** ANSI invisible + * @group style-control + */ final val INVISIBLE = "\u001b[8m" } diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala index 52fa525b24..33b5a1468e 100644 --- a/src/library/scala/io/BufferedSource.scala +++ b/src/library/scala/io/BufferedSource.scala @@ -8,11 +8,9 @@ package scala.io -import java.util.Arrays import java.io.{ InputStream, BufferedReader, InputStreamReader, PushbackReader } import Source.DefaultBufSize import scala.collection.{ Iterator, AbstractIterator } -import scala.collection.mutable.ArrayBuffer /** This object provides convenience methods to create an iterable * representation of a source file. diff --git a/src/library/scala/io/Position.scala b/src/library/scala/io/Position.scala index 011d0f17af..0435ca95ad 100644 --- a/src/library/scala/io/Position.scala +++ b/src/library/scala/io/Position.scala @@ -33,7 +33,7 @@ package io * }}} * @author Burak Emir (translated from work by Matthias Zenger and others) */ -@deprecated("This class will be removed.", "2.10.0") +@deprecated("this class will be removed", "2.10.0") private[scala] abstract class Position { /** Definable behavior for overflow conditions. */ diff --git a/src/library/scala/io/Source.scala b/src/library/scala/io/Source.scala index 9f0b56b4fe..b4f542a252 100644 --- a/src/library/scala/io/Source.scala +++ b/src/library/scala/io/Source.scala @@ -10,7 +10,7 @@ package scala package io import scala.collection.AbstractIterator -import java.io.{ FileInputStream, InputStream, PrintStream, File => JFile } +import java.io.{ FileInputStream, InputStream, PrintStream, File => JFile, Closeable } import java.net.{ URI, URL } /** This object provides convenience methods to create an iterable @@ -59,7 +59,7 @@ object Source { def fromFile(name: String, enc: String): BufferedSource = fromFile(name)(Codec(enc)) - /** creates `ource` from file with given file `URI`. + /** creates `source` from file with given file `URI`. */ def fromFile(uri: URI)(implicit codec: Codec): BufferedSource = fromFile(new JFile(uri))(codec) @@ -167,27 +167,35 @@ object Source { def fromInputStream(is: InputStream)(implicit codec: Codec): BufferedSource = createBufferedSource(is, reset = () => fromInputStream(is)(codec), close = () => is.close())(codec) + + /** Reads data from a classpath resource, using either a context classloader (default) or a passed one. + * + * @param resource name of the resource to load from the classpath + * @param classLoader classloader to be used, or context classloader if not specified + * @return the buffered source + */ + def fromResource(resource: String, classLoader: ClassLoader = Thread.currentThread().getContextClassLoader())(implicit codec: Codec): BufferedSource = + fromInputStream(classLoader.getResourceAsStream(resource)) + } /** An iterable representation of source data. - * It may be reset with the optional `reset` method. + * It may be reset with the optional [[reset]] method. * - * Subclasses must supply [[scala.io.Source@iter the underlying iterator]]. + * Subclasses must supply [[scala.io.Source.iter the underlying iterator]]. * - * Error handling may be customized by overriding the [[scala.io.Source@report report]] method. + * Error handling may be customized by overriding the [[scala.io.Source.report report]] method. * - * The [[scala.io.Source@ch current input]] and [[scala.io.Source@pos position]], - * as well as the [[scala.io.Source@next next character]] methods delegate to - * [[scala.io.Source$Positioner the positioner]]. + * The [[scala.io.Source.ch current input]] and [[scala.io.Source.pos position]], + * as well as the [[scala.io.Source.next next character]] methods delegate to + * [[scala.io.Source#Positioner the positioner]]. * - * The default positioner encodes line and column numbers in the position passed to `report`. + * The default positioner encodes line and column numbers in the position passed to [[report]]. * This behavior can be changed by supplying a - * [[scala.io.Source@withPositioning(pos:Source.this.Positioner):Source.this.type custom positioner]]. + * [[scala.io.Source.withPositioning(pos:* custom positioner]]. * - * @author Burak Emir - * @version 1.0 */ -abstract class Source extends Iterator[Char] { +abstract class Source extends Iterator[Char] with Closeable { /** the actual iterator */ protected val iter: Iterator[Char] diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index bb337e7a1d..4bc0c0cf95 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -10,13 +10,12 @@ package scala package math -import java.{ lang => jl } -import java.math.{ MathContext, BigDecimal => BigDec } -import scala.collection.immutable.NumericRange import scala.language.implicitConversions +import java.math.{ MathContext, BigDecimal => BigDec } +import scala.collection.immutable.NumericRange -/** +/** * @author Stephane Micheloud * @author Rex Kerr * @version 1.1 @@ -44,17 +43,17 @@ object BigDecimal { val HALF_UP = Value(RM.HALF_UP.ordinal) val HALF_DOWN = Value(RM.HALF_DOWN.ordinal) val HALF_EVEN = Value(RM.HALF_EVEN.ordinal) - val UNNECESSARY = Value(RM.UNNECESSARY.ordinal) + val UNNECESSARY = Value(RM.UNNECESSARY.ordinal) } - + /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`, rounding if necessary. */ def decimal(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(java.lang.Double.toString(d), mc), mc) /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`. */ def decimal(d: Double): BigDecimal = decimal(d, defaultMathContext) - - /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`, rounding if necessary. + + /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`, rounding if necessary. * Note that `BigDecimal.decimal(0.1f) != 0.1f` since equality agrees with the `Double` representation, and * `0.1 != 0.1f`. */ @@ -66,18 +65,18 @@ object BigDecimal { * `0.1 != 0.1f`. */ def decimal(f: Float): BigDecimal = decimal(f, defaultMathContext) - + // This exists solely to avoid conversion from Int/Long to Float, screwing everything up. /** Constructs a `BigDecimal` from a `Long`, rounding if necessary. This is identical to `BigDecimal(l, mc)`. */ def decimal(l: Long, mc: MathContext): BigDecimal = apply(l, mc) - + // This exists solely to avoid conversion from Int/Long to Float, screwing everything up. /** Constructs a `BigDecimal` from a `Long`. This is identical to `BigDecimal(l)`. */ def decimal(l: Long): BigDecimal = apply(l) - + /** Constructs a `BigDecimal` using a `java.math.BigDecimal`, rounding if necessary. */ def decimal(bd: BigDec, mc: MathContext): BigDecimal = new BigDecimal(bd.round(mc), mc) - + /** Constructs a `BigDecimal` by expanding the binary fraction * contained by `Double` value `d` into a decimal representation, * rounding if necessary. When a `Float` is converted to a @@ -85,50 +84,50 @@ object BigDecimal { * also works for converted `Float`s. */ def binary(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(d, mc), mc) - + /** Constructs a `BigDecimal` by expanding the binary fraction * contained by `Double` value `d` into a decimal representation. * Note: this also works correctly on converted `Float`s. */ def binary(d: Double): BigDecimal = binary(d, defaultMathContext) - + /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. The * precision is the default for `BigDecimal` or enough to represent * the `java.math.BigDecimal` exactly, whichever is greater. */ def exact(repr: BigDec): BigDecimal = { - val mc = + val mc = if (repr.precision <= defaultMathContext.getPrecision) defaultMathContext else new MathContext(repr.precision, java.math.RoundingMode.HALF_EVEN) new BigDecimal(repr, mc) } - + /** Constructs a `BigDecimal` by fully expanding the binary fraction * contained by `Double` value `d`, adjusting the precision as * necessary. Note: this works correctly on converted `Float`s also. */ def exact(d: Double): BigDecimal = exact(new BigDec(d)) - + /** Constructs a `BigDecimal` that exactly represents a `BigInt`. */ def exact(bi: BigInt): BigDecimal = exact(new BigDec(bi.bigInteger)) - + /** Constructs a `BigDecimal` that exactly represents a `Long`. Note that * all creation methods for `BigDecimal` that do not take a `MathContext` * represent a `Long`; this is equivalent to `apply`, `valueOf`, etc.. */ def exact(l: Long): BigDecimal = apply(l) - + /** Constructs a `BigDecimal` that exactly represents the number * specified in a `String`. */ def exact(s: String): BigDecimal = exact(new BigDec(s)) - + /** Constructs a `BigDecimal` that exactly represents the number * specified in base 10 in a character array. */ def exact(cs: Array[Char]): BigDecimal = exact(new BigDec(cs)) - + /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. Equivalent to `BigDecimal.decimal`. @@ -137,7 +136,7 @@ object BigDecimal { * @return the constructed `BigDecimal` */ def valueOf(d: Double): BigDecimal = apply(BigDec valueOf d) - + /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor, specifying a `MathContext` that is * used for computations but isn't used for rounding. Use @@ -149,9 +148,9 @@ object BigDecimal { * @param mc the `MathContext` used for future computations * @return the constructed `BigDecimal` */ - @deprecated("MathContext is not applied to Doubles in valueOf. Use BigDecimal.decimal to use rounding, or java.math.BigDecimal.valueOf to avoid it.","2.11") + @deprecated("MathContext is not applied to Doubles in valueOf. Use BigDecimal.decimal to use rounding, or java.math.BigDecimal.valueOf to avoid it.", "2.11.0") def valueOf(d: Double, mc: MathContext): BigDecimal = apply(BigDec valueOf d, mc) - + /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. * @@ -159,22 +158,22 @@ object BigDecimal { * @return the constructed `BigDecimal` */ def valueOf(x: Long): BigDecimal = apply(x) - + /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. This is unlikely to do what you want; * use `valueOf(f.toDouble)` or `decimal(f)` instead. */ - @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).","2.11") + @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).", "2.11.0") def valueOf(f: Float): BigDecimal = valueOf(f.toDouble) - + /** Constructs a `BigDecimal` using the java BigDecimal static * valueOf constructor. This is unlikely to do what you want; * use `valueOf(f.toDouble)` or `decimal(f)` instead. */ - @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).","2.11") + @deprecated("Float arguments to valueOf may not do what you wish. Use decimal or valueOf(f.toDouble).", "2.11.0") def valueOf(f: Float, mc: MathContext): BigDecimal = valueOf(f.toDouble, mc) - + /** Constructs a `BigDecimal` whose value is equal to that of the * specified `Integer` value. * @@ -247,7 +246,7 @@ object BigDecimal { * @return the constructed `BigDecimal` */ def apply(d: Double): BigDecimal = decimal(d, defaultMathContext) - + // note we don't use the static valueOf because it doesn't let us supply // a MathContext, but we should be duplicating its logic, modulo caching. /** Constructs a `BigDecimal` whose value is equal to that of the @@ -260,10 +259,10 @@ object BigDecimal { */ def apply(d: Double, mc: MathContext): BigDecimal = decimal(d, mc) - @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11") + @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11.0") def apply(x: Float): BigDecimal = apply(x.toDouble) - @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11") + @deprecated("The default conversion from Float may not do what you want. Use BigDecimal.decimal for a String representation, or explicitly convert the Float with .toDouble.", "2.11.0") def apply(x: Float, mc: MathContext): BigDecimal = apply(x.toDouble, mc) /** Translates a character array representation of a `BigDecimal` @@ -281,7 +280,7 @@ object BigDecimal { * into a `BigDecimal`. */ def apply(x: String): BigDecimal = exact(x) - + /** Translates the decimal String representation of a `BigDecimal` * into a `BigDecimal`, rounding if necessary. */ @@ -295,12 +294,12 @@ object BigDecimal { * @return the constructed `BigDecimal` */ def apply(x: BigInt): BigDecimal = exact(x) - + /** Constructs a `BigDecimal` whose value is equal to that of the * specified `BigInt` value, rounding if necessary. * * @param x the specified `BigInt` value - * @param mc the precision and rounding mode for creation of this value and future operations on it + * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(x: BigInt, mc: MathContext): BigDecimal = @@ -315,13 +314,13 @@ object BigDecimal { */ def apply(unscaledVal: BigInt, scale: Int): BigDecimal = exact(new BigDec(unscaledVal.bigInteger, scale)) - + /** Constructs a `BigDecimal` whose unscaled value is equal to that * of the specified `BigInt` value. * * @param unscaledVal the specified `BigInt` value * @param scale the scale - * @param mc the precision and rounding mode for creation of this value and future operations on it + * @param mc the precision and rounding mode for creation of this value and future operations on it * @return the constructed `BigDecimal` */ def apply(unscaledVal: BigInt, scale: Int, mc: MathContext): BigDecimal = @@ -329,8 +328,8 @@ object BigDecimal { /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. */ def apply(bd: BigDec): BigDecimal = apply(bd, defaultMathContext) - - @deprecated("This method appears to round a java.math.BigDecimal but actually doesn't. Use new BigDecimal(bd, mc) instead for no rounding, or BigDecimal.decimal(bd, mc) for rounding.", "2.11") + + @deprecated("This method appears to round a java.math.BigDecimal but actually doesn't. Use new BigDecimal(bd, mc) instead for no rounding, or BigDecimal.decimal(bd, mc) for rounding.", "2.11.0") def apply(bd: BigDec, mc: MathContext): BigDecimal = new BigDecimal(bd, mc) /** Implicit conversion from `Int` to `BigDecimal`. */ @@ -398,11 +397,11 @@ object BigDecimal { * @version 1.1 */ final class BigDecimal(val bigDecimal: BigDec, val mc: MathContext) -extends ScalaNumber with ScalaNumericConversions with Serializable { +extends ScalaNumber with ScalaNumericConversions with Serializable with Ordered[BigDecimal] { def this(bigDecimal: BigDec) = this(bigDecimal, BigDecimal.defaultMathContext) import BigDecimal.RoundingMode._ import BigDecimal.{decimal, binary, exact} - + if (bigDecimal eq null) throw new IllegalArgumentException("null value for BigDecimal") if (mc eq null) throw new IllegalArgumentException("null MathContext for BigDecimal") @@ -423,7 +422,7 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { scala.util.hashing.MurmurHash3.mixLast( temp.scaleByPowerOfTen(temp.scale).toBigInteger.hashCode, temp.scale ) } } - + /** Returns the hash code for this BigDecimal. * Note that this does not merely use the underlying java object's * `hashCode` because we compare `BigDecimal`s with `compareTo` @@ -444,15 +443,15 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { */ override def equals (that: Any): Boolean = that match { case that: BigDecimal => this equals that - case that: BigInt => - that.bitLength > (precision-scale-2)*BigDecimal.deci2binary && + case that: BigInt => + that.bitLength > (precision-scale-2)*BigDecimal.deci2binary && this.toBigIntExact.exists(that equals _) - case that: Double => + case that: Double => !that.isInfinity && { val d = toDouble !d.isInfinity && d == that && equals(decimal(d)) } - case that: Float => + case that: Float => !that.isInfinity && { val f = toFloat !f.isInfinity && f == that && equals(decimal(f.toDouble)) @@ -468,7 +467,7 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { * `isExactFloat`, `isBinaryFloat`, or `isDecimalFloat`, depending on the intended meaning. * By default, `decimal` creation is used, so `isDecimalFloat` is probably what you want. */ - @deprecated("What constitutes validity is unclear. Use `isExactFloat`, `isBinaryFloat`, or `isDecimalFloat` instead.", "2.11") + @deprecated("What constitutes validity is unclear. Use `isExactFloat`, `isBinaryFloat`, or `isDecimalFloat` instead.", "2.11.0") def isValidFloat = { val f = toFloat !f.isInfinity && bigDecimal.compareTo(new BigDec(f.toDouble)) == 0 @@ -477,48 +476,48 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { * `isExactDouble`, `isBinaryDouble`, or `isDecimalDouble`, depending on the intended meaning. * By default, `decimal` creation is used, so `isDecimalDouble` is probably what you want. */ - @deprecated("Validity has distinct meanings. Use `isExactDouble`, `isBinaryDouble`, or `isDecimalDouble` instead.", "2.11") + @deprecated("Validity has distinct meanings. Use `isExactDouble`, `isBinaryDouble`, or `isDecimalDouble` instead.", "2.11.0") def isValidDouble = { val d = toDouble !d.isInfinity && bigDecimal.compareTo(new BigDec(d)) == 0 } - + /** Tests whether this `BigDecimal` holds the decimal representation of a `Double`. */ def isDecimalDouble = { val d = toDouble !d.isInfinity && equals(decimal(d)) } - + /** Tests whether this `BigDecimal` holds the decimal representation of a `Float`. */ def isDecimalFloat = { val f = toFloat !f.isInfinity && equals(decimal(f)) } - + /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Double`. */ def isBinaryDouble = { val d = toDouble !d.isInfinity && equals(binary(d,mc)) } - + /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Float`. */ def isBinaryFloat = { val f = toFloat !f.isInfinity && equals(binary(f,mc)) } - + /** Tests whether this `BigDecimal` holds the exact expansion of a `Double`'s binary fractional form into base 10. */ def isExactDouble = { val d = toDouble !d.isInfinity && equals(exact(d)) } - + /** Tests whether this `BigDecimal` holds the exact expansion of a `Float`'s binary fractional form into base 10. */ def isExactFloat = { val f = toFloat !f.isInfinity && equals(exact(f.toDouble)) } - + private def noArithmeticException(body: => Unit): Boolean = { try { body ; true } @@ -526,9 +525,9 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { } def isWhole() = scale <= 0 || bigDecimal.stripTrailingZeros.scale <= 0 - + def underlying = bigDecimal - + /** Compares this BigDecimal with the specified BigDecimal for equality. */ @@ -538,22 +537,6 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { */ def compare (that: BigDecimal): Int = this.bigDecimal compareTo that.bigDecimal - /** Less-than-or-equals comparison of BigDecimals - */ - def <= (that: BigDecimal): Boolean = compare(that) <= 0 - - /** Greater-than-or-equals comparison of BigDecimals - */ - def >= (that: BigDecimal): Boolean = compare(that) >= 0 - - /** Less-than of BigDecimals - */ - def < (that: BigDecimal): Boolean = compare(that) < 0 - - /** Greater-than comparison of BigDecimals - */ - def > (that: BigDecimal): Boolean = compare(that) > 0 - /** Addition of BigDecimals */ def + (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal add that.bigDecimal, mc) @@ -589,14 +572,14 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { case x if x <= 0 => this case _ => that } - + /** Returns the maximum of this and that, or this if the two are equal */ def max (that: BigDecimal): BigDecimal = (this compare that) match { case x if x >= 0 => this case _ => that } - + /** Remainder after dividing this by that. */ def remainder (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal remainder that.bigDecimal, mc) @@ -635,7 +618,7 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { val r = this.bigDecimal round mc if (r eq bigDecimal) this else new BigDecimal(r, this.mc) } - + /** Returns a `BigDecimal` rounded according to its own `MathContext` */ def rounded: BigDecimal = { val r = bigDecimal round mc @@ -657,7 +640,7 @@ extends ScalaNumber with ScalaNumericConversions with Serializable { /** Returns a `BigDecimal` whose scale is the specified value, and whose value is * numerically equal to this BigDecimal's. */ - def setScale(scale: Int): BigDecimal = + def setScale(scale: Int): BigDecimal = if (this.scale == scale) this else new BigDecimal(this.bigDecimal setScale scale, mc) diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index abc7371d9f..707a5c0769 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -109,7 +109,12 @@ object BigInt { * @author Martin Odersky * @version 1.0, 15/07/2003 */ -final class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNumericConversions with Serializable { +final class BigInt(val bigInteger: BigInteger) + extends ScalaNumber + with ScalaNumericConversions + with Serializable + with Ordered[BigInt] +{ /** Returns the hash code for this BigInt. */ override def hashCode(): Int = if (isValidLong) unifiedPrimitiveHashcode() @@ -155,8 +160,8 @@ final class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNum } ) && !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 . + /** 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. */ @@ -176,22 +181,6 @@ final class BigInt(val bigInteger: BigInteger) extends ScalaNumber with ScalaNum */ def compare (that: BigInt): Int = this.bigInteger.compareTo(that.bigInteger) - /** Less-than-or-equals comparison of BigInts - */ - def <= (that: BigInt): Boolean = compare(that) <= 0 - - /** Greater-than-or-equals comparison of BigInts - */ - def >= (that: BigInt): Boolean = compare(that) >= 0 - - /** Less-than of BigInts - */ - def < (that: BigInt): Boolean = compare(that) < 0 - - /** Greater-than comparison of BigInts - */ - def > (that: BigInt): Boolean = compare(that) > 0 - /** Addition of BigInts */ def + (that: BigInt): BigInt = new BigInt(this.bigInteger.add(that.bigInteger)) diff --git a/src/library/scala/math/Integral.scala b/src/library/scala/math/Integral.scala index ff1f695f6d..44009fd4a2 100644 --- a/src/library/scala/math/Integral.scala +++ b/src/library/scala/math/Integral.scala @@ -6,8 +6,6 @@ ** |/ ** \* */ - - package scala package math diff --git a/src/library/scala/math/Ordering.scala b/src/library/scala/math/Ordering.scala index 827cccc77e..37096d5ed0 100644 --- a/src/library/scala/math/Ordering.scala +++ b/src/library/scala/math/Ordering.scala @@ -224,42 +224,32 @@ object Ordering extends LowPriorityOrderingImplicits { implicit object Unit extends UnitOrdering trait BooleanOrdering extends Ordering[Boolean] { - def compare(x: Boolean, y: Boolean) = (x, y) match { - case (false, true) => -1 - case (true, false) => 1 - case _ => 0 - } + def compare(x: Boolean, y: Boolean) = java.lang.Boolean.compare(x, y) } implicit object Boolean extends BooleanOrdering trait ByteOrdering extends Ordering[Byte] { - def compare(x: Byte, y: Byte) = x.toInt - y.toInt + def compare(x: Byte, y: Byte) = java.lang.Byte.compare(x, y) } implicit object Byte extends ByteOrdering trait CharOrdering extends Ordering[Char] { - def compare(x: Char, y: Char) = x.toInt - y.toInt + def compare(x: Char, y: Char) = java.lang.Character.compare(x, y) } implicit object Char extends CharOrdering trait ShortOrdering extends Ordering[Short] { - def compare(x: Short, y: Short) = x.toInt - y.toInt + def compare(x: Short, y: Short) = java.lang.Short.compare(x, y) } implicit object Short extends ShortOrdering trait IntOrdering extends Ordering[Int] { - def compare(x: Int, y: Int) = - if (x < y) -1 - else if (x == y) 0 - else 1 + def compare(x: Int, y: Int) = java.lang.Integer.compare(x, y) } implicit object Int extends IntOrdering trait LongOrdering extends Ordering[Long] { - def compare(x: Long, y: Long) = - if (x < y) -1 - else if (x == y) 0 - else 1 + def compare(x: Long, y: Long) = java.lang.Long.compare(x, y) } implicit object Long extends LongOrdering diff --git a/src/library/scala/math/package.scala b/src/library/scala/math/package.scala index a75979385c..546efef114 100644 --- a/src/library/scala/math/package.scala +++ b/src/library/scala/math/package.scala @@ -11,28 +11,90 @@ package scala /** The package object `scala.math` contains methods for performing basic * numeric operations such as elementary exponential, logarithmic, root and * trigonometric functions. + * + * All methods forward to [[java.lang.Math]] unless otherwise noted. + * + * @see [[java.lang.Math]] + * + * @groupname math-const Mathematical Constants + * @groupprio math-const 10 + * + * @groupname minmax Minimum and Maximum + * @groupdesc minmax Find the min or max of two numbers. Note: [[scala.collection.TraversableOnce]] has + * min and max methods which determine the min or max of a collection. + * @groupprio minmax 20 + * + * @groupname rounding Rounding + * @groupprio rounding 30 + * + * @groupname explog Exponential and Logarithmic + * @groupprio explog 40 + * + * @groupname trig Trigonometric + * @groupdesc trig Arguments in radians + * @groupprio trig 50 + * + * @groupname angle-conversion Angular Measurement Conversion + * @groupprio angle-conversion 60 + * + * @groupname hyperbolic Hyperbolic + * @groupprio hyperbolic 70 + * + * @groupname abs Absolute Values + * @groupdesc abs Determine the magnitude of a value by discarding the sign. Results are >= 0. + * @groupprio abs 80 + * + * @groupname signum Signs + * @groupdesc signum Extract the sign of a value. Results are -1, 0 or 1. + * Note that these are not pure forwarders to the java versions. + * In particular, the return type of java.lang.Long.signum is Int, + * but here it is widened to Long so that each overloaded variant + * will return the same numeric type it is passed. + * @groupprio signum 90 + * + * @groupname root-extraction Root Extraction + * @groupprio root-extraction 100 + * + * @groupname polar-coords Polar Coordinates + * @groupprio polar-coords 110 + * + * @groupname ulp Unit of Least Precision + * @groupprio ulp 120 + * + * @groupname randomisation Pseudo Random Number Generation + * @groupprio randomisation 130 */ package object math { - /** The `double` value that is closer than any other to `e`, the base of + /** The `Double` value that is closer than any other to `e`, the base of * the natural logarithms. + * @group math-const */ @inline final val E = java.lang.Math.E - /** The `double` value that is closer than any other to `pi`, the ratio of + /** The `Double` value that is closer than any other to `pi`, the ratio of * the circumference of a circle to its diameter. + * @group math-const */ @inline final val Pi = java.lang.Math.PI - /** Returns a `double` value with a positive sign, greater than or equal + /** Returns a `Double` value with a positive sign, greater than or equal * to `0.0` and less than `1.0`. + * + * @group randomisation */ - def random: Double = java.lang.Math.random() + def random(): Double = java.lang.Math.random() + /** @group trig */ def sin(x: Double): Double = java.lang.Math.sin(x) + /** @group trig */ def cos(x: Double): Double = java.lang.Math.cos(x) + /** @group trig */ def tan(x: Double): Double = java.lang.Math.tan(x) + /** @group trig */ def asin(x: Double): Double = java.lang.Math.asin(x) + /** @group trig */ def acos(x: Double): Double = java.lang.Math.acos(x) + /** @group trig */ def atan(x: Double): Double = java.lang.Math.atan(x) /** Converts an angle measured in degrees to an approximately equivalent @@ -40,6 +102,7 @@ package object math { * * @param x an angle, in degrees * @return the measurement of the angle `x` in radians. + * @group angle-conversion */ def toRadians(x: Double): Double = java.lang.Math.toRadians(x) @@ -48,44 +111,10 @@ package object math { * * @param x angle, in radians * @return the measurement of the angle `x` in degrees. + * @group angle-conversion */ def toDegrees(x: Double): Double = java.lang.Math.toDegrees(x) - /** Returns Euler's number `e` raised to the power of a `double` value. - * - * @param x the exponent to raise `e` to. - * @return the value `e^a^`, where `e` is the base of the natural - * logarithms. - */ - def exp(x: Double): Double = java.lang.Math.exp(x) - - /** Returns the natural logarithm of a `double` value. - * - * @param x the number to take the natural logarithm of - * @return the value `logₑ(x)` where `e` is Eulers number - */ - def log(x: Double): Double = java.lang.Math.log(x) - - /** Returns the square root of a `double` value. - * - * @param x the number to take the square root of - * @return the value √x - */ - def sqrt(x: Double): Double = java.lang.Math.sqrt(x) - def IEEEremainder(x: Double, y: Double): Double = java.lang.Math.IEEEremainder(x, y) - - def ceil(x: Double): Double = java.lang.Math.ceil(x) - def floor(x: Double): Double = java.lang.Math.floor(x) - - /** Returns the `double` value that is closest in value to the - * argument and is equal to a mathematical integer. - * - * @param x a `double` value - * @return the closest floating-point value to a that is equal to a - * mathematical integer. - */ - def rint(x: Double): Double = java.lang.Math.rint(x) - /** Converts rectangular coordinates `(x, y)` to polar `(r, theta)`. * * @param x the ordinate coordinate @@ -93,110 +122,206 @@ package object math { * @return the ''theta'' component of the point `(r, theta)` in polar * coordinates that corresponds to the point `(x, y)` in * Cartesian coordinates. + * @group polar-coords */ def atan2(y: Double, x: Double): Double = java.lang.Math.atan2(y, x) - /** Returns the value of the first argument raised to the power of the - * second argument. + /** Returns the square root of the sum of the squares of both given `Double` + * values without intermediate underflow or overflow. + * + * The ''r'' component of the point `(r, theta)` in polar + * coordinates that corresponds to the point `(x, y)` in + * Cartesian coordinates. + * @group polar-coords + */ + def hypot(x: Double, y: Double): Double = java.lang.Math.hypot(x, y) + + // ----------------------------------------------------------------------- + // rounding functions + // ----------------------------------------------------------------------- + + /** @group rounding */ + def ceil(x: Double): Double = java.lang.Math.ceil(x) + /** @group rounding */ + def floor(x: Double): Double = java.lang.Math.floor(x) + + /** Returns the `Double` value that is closest in value to the + * argument and is equal to a mathematical integer. + * + * @param x a `Double` value + * @return the closest floating-point value to a that is equal to a + * mathematical integer. + * @group rounding + */ + def rint(x: Double): Double = java.lang.Math.rint(x) + + /** There is no reason to round a `Long`, but this method prevents unintended conversion to `Float` followed by rounding to `Int`. * - * @param x the base. - * @param y the exponent. - * @return the value `x^y^`. + * @note Does not forward to [[java.lang.Math]] + * @group rounding */ - def pow(x: Double, y: Double): Double = java.lang.Math.pow(x, y) - - /** There is no reason to round a `Long`, but this method prevents unintended conversion to `Float` followed by rounding to `Int`. */ - @deprecated("This is an integer type; there is no reason to round it. Perhaps you meant to call this with a floating-point value?", "2.11.0") + @deprecated("This is an integer type; there is no reason to round it. Perhaps you meant to call this with a floating-point value?", "2.11.0") def round(x: Long): Long = x /** Returns the closest `Int` to the argument. * * @param x a floating-point value to be rounded to a `Int`. * @return the value of the argument rounded to the nearest `Int` value. + * @group rounding */ def round(x: Float): Int = java.lang.Math.round(x) - + /** Returns the closest `Long` to the argument. * * @param x a floating-point value to be rounded to a `Long`. * @return the value of the argument rounded to the nearest`long` value. + * @group rounding */ def round(x: Double): Long = java.lang.Math.round(x) + /** @group abs */ def abs(x: Int): Int = java.lang.Math.abs(x) + /** @group abs */ def abs(x: Long): Long = java.lang.Math.abs(x) + /** @group abs */ def abs(x: Float): Float = java.lang.Math.abs(x) + /** @group abs */ def abs(x: Double): Double = java.lang.Math.abs(x) + /** @group minmax */ def max(x: Int, y: Int): Int = java.lang.Math.max(x, y) + /** @group minmax */ def max(x: Long, y: Long): Long = java.lang.Math.max(x, y) + /** @group minmax */ def max(x: Float, y: Float): Float = java.lang.Math.max(x, y) + /** @group minmax */ def max(x: Double, y: Double): Double = java.lang.Math.max(x, y) + /** @group minmax */ def min(x: Int, y: Int): Int = java.lang.Math.min(x, y) + /** @group minmax */ def min(x: Long, y: Long): Long = java.lang.Math.min(x, y) + /** @group minmax */ def min(x: Float, y: Float): Float = java.lang.Math.min(x, y) + /** @group minmax */ def min(x: Double, y: Double): Double = java.lang.Math.min(x, y) - /** Note that these are not pure forwarders to the java versions. - * In particular, the return type of java.lang.Long.signum is Int, - * but here it is widened to Long so that each overloaded variant - * will return the same numeric type it is passed. - */ + /** @group signum + * @note Forwards to [[java.lang.Integer]] + */ def signum(x: Int): Int = java.lang.Integer.signum(x) + /** @group signum + * @note Forwards to [[java.lang.Long]] + */ def signum(x: Long): Long = java.lang.Long.signum(x) + /** @group signum */ def signum(x: Float): Float = java.lang.Math.signum(x) + /** @group signum */ def signum(x: Double): Double = java.lang.Math.signum(x) // ----------------------------------------------------------------------- // root functions // ----------------------------------------------------------------------- - /** Returns the cube root of the given `Double` value. */ + /** Returns the square root of a `Double` value. + * + * @param x the number to take the square root of + * @return the value √x + * @group root-extraction + */ + def sqrt(x: Double): Double = java.lang.Math.sqrt(x) + + /** Returns the cube root of the given `Double` value. + * + * @param x the number to take the cube root of + * @return the value ∛x + * @group root-extraction + */ def cbrt(x: Double): Double = java.lang.Math.cbrt(x) // ----------------------------------------------------------------------- // exponential functions // ----------------------------------------------------------------------- - /** Returns `exp(x) - 1`. */ + /** Returns the value of the first argument raised to the power of the + * second argument. + * + * @param x the base. + * @param y the exponent. + * @return the value `x^y^`. + * @group explog + */ + def pow(x: Double, y: Double): Double = java.lang.Math.pow(x, y) + + /** Returns Euler's number `e` raised to the power of a `Double` value. + * + * @param x the exponent to raise `e` to. + * @return the value `e^a^`, where `e` is the base of the natural + * logarithms. + * @group explog + */ + def exp(x: Double): Double = java.lang.Math.exp(x) + + /** Returns `exp(x) - 1`. + * @group explog + */ def expm1(x: Double): Double = java.lang.Math.expm1(x) // ----------------------------------------------------------------------- // logarithmic functions // ----------------------------------------------------------------------- - /** Returns the natural logarithm of the sum of the given `Double` value and 1. */ + /** Returns the natural logarithm of a `Double` value. + * + * @param x the number to take the natural logarithm of + * @return the value `logₑ(x)` where `e` is Eulers number + * @group explog + */ + def log(x: Double): Double = java.lang.Math.log(x) + + /** Returns the natural logarithm of the sum of the given `Double` value and 1. + * @group explog + */ def log1p(x: Double): Double = java.lang.Math.log1p(x) - /** Returns the base 10 logarithm of the given `Double` value. */ + /** Returns the base 10 logarithm of the given `Double` value. + * @group explog + */ def log10(x: Double): Double = java.lang.Math.log10(x) // ----------------------------------------------------------------------- // trigonometric functions // ----------------------------------------------------------------------- - /** Returns the hyperbolic sine of the given `Double` value. */ + /** Returns the hyperbolic sine of the given `Double` value. + * @group hyperbolic + */ def sinh(x: Double): Double = java.lang.Math.sinh(x) - /** Returns the hyperbolic cosine of the given `Double` value. */ + /** Returns the hyperbolic cosine of the given `Double` value. + * @group hyperbolic + */ def cosh(x: Double): Double = java.lang.Math.cosh(x) - /** Returns the hyperbolic tangent of the given `Double` value. */ + /** Returns the hyperbolic tangent of the given `Double` value. + * @group hyperbolic + */ def tanh(x: Double):Double = java.lang.Math.tanh(x) // ----------------------------------------------------------------------- // miscellaneous functions // ----------------------------------------------------------------------- - /** Returns the square root of the sum of the squares of both given `Double` - * values without intermediate underflow or overflow. + /** Returns the size of an ulp of the given `Double` value. + * @group ulp */ - def hypot(x: Double, y: Double): Double = java.lang.Math.hypot(x, y) - - /** Returns the size of an ulp of the given `Double` value. */ def ulp(x: Double): Double = java.lang.Math.ulp(x) - /** Returns the size of an ulp of the given `Float` value. */ + /** Returns the size of an ulp of the given `Float` value. + * @group ulp + */ def ulp(x: Float): Float = java.lang.Math.ulp(x) + + /** @group rounding */ + def IEEEremainder(x: Double, y: Double): Double = java.lang.Math.IEEEremainder(x, y) } diff --git a/src/library/scala/native.scala b/src/library/scala/native.scala index dbacc78618..49d3ced805 100644 --- a/src/library/scala/native.scala +++ b/src/library/scala/native.scala @@ -16,8 +16,11 @@ package scala * @native def f(x: Int, y: List[Long]): String = ... * }}} * - * Method body is not generated if method is marked with `@native`, - * but it is type checked when present. + * A `@native` method is compiled to the platform's native method, + * while discarding the method's body (if any). The body will be type checked if present. * - * @since 2.6 */ + * A method marked @native must be a member of a class, not a trait (since 2.12). + * + * @since 2.6 + */ class native extends scala.annotation.StaticAnnotation {} diff --git a/src/library/scala/noinline.scala b/src/library/scala/noinline.scala index 38fd4c39d6..6c21ed667d 100644 --- a/src/library/scala/noinline.scala +++ b/src/library/scala/noinline.scala @@ -11,8 +11,30 @@ package scala /** - * An annotation on methods that forbids the compiler to inline the - * method, no matter how safe the inlining appears to be. + * An annotation on methods that forbids the compiler to inline the method, no matter how safe the + * inlining appears to be. The annotation can be used at definition site or at callsite. + * + * {{{ + * @inline final def f1(x: Int) = x + * @noinline final def f2(x: Int) = x + * final def f3(x: Int) = x + * + * def t1 = f1(1) // inlined if possible + * def t2 = f2(1) // not inlined + * def t3 = f3(1) // may be inlined (heuristics) + * def t4 = f1(1): @noinline // not inlined (override at callsite) + * def t5 = f2(1): @inline // inlined if possible (override at callsite) + * def t6 = f3(1): @inline // inlined if possible + * def t7 = f3(1): @noinline // not inlined + * } + * }}} + * + * Note: parentheses are required when annotating a callsite within a larger expression. + * + * {{{ + * def t1 = f1(1) + f1(1): @noinline // equivalent to (f1(1) + f1(1)): @noinline + * def t2 = f1(1) + (f1(1): @noinline) // the second call to f1 is not inlined + * }}} * * @author Lex Spoon * @version 1.0, 2007-5-21 diff --git a/src/library/scala/ref/SoftReference.scala b/src/library/scala/ref/SoftReference.scala index e4ce667981..5e60f00788 100644 --- a/src/library/scala/ref/SoftReference.scala +++ b/src/library/scala/ref/SoftReference.scala @@ -20,6 +20,19 @@ class SoftReference[+T <: AnyRef](value : T, queue : ReferenceQueue[T]) extends } /** + * A companion object that implements an extractor for `SoftReference` values + * @author Rebecca Claire Murphy + */ +object SoftReference { + + /** Creates a `SoftReference` pointing to `value` */ + def apply[T <: AnyRef](value: T) = new SoftReference(value) + + /** Optionally returns the referenced value, or `None` if that value no longer exists */ + def unapply[T <: AnyRef](sr: SoftReference[T]): Option[T] = Option(sr.underlying.get) +} + +/** * @author Philipp Haller */ private class SoftReferenceWithWrapper[T <: AnyRef](value: T, queue: ReferenceQueue[T], val wrapper: SoftReference[T]) diff --git a/src/library/scala/reflect/ClassManifestDeprecatedApis.scala b/src/library/scala/reflect/ClassManifestDeprecatedApis.scala index 82ec872806..d2ae10747d 100644 --- a/src/library/scala/reflect/ClassManifestDeprecatedApis.scala +++ b/src/library/scala/reflect/ClassManifestDeprecatedApis.scala @@ -12,12 +12,12 @@ package reflect import scala.collection.mutable.{ WrappedArray, ArrayBuilder } import java.lang.{ Class => jClass } -@deprecated("Use scala.reflect.ClassTag instead", "2.10.0") +@deprecated("use scala.reflect.ClassTag instead", "2.10.0") trait ClassManifestDeprecatedApis[T] extends OptManifest[T] { self: ClassManifest[T] => // Still in use in target test.junit.comp. - @deprecated("Use runtimeClass instead", "2.10.0") + @deprecated("use runtimeClass instead", "2.10.0") def erasure: jClass[_] = runtimeClass private def subtype(sub: jClass[_], sup: jClass[_]): Boolean = { @@ -44,7 +44,7 @@ trait ClassManifestDeprecatedApis[T] extends OptManifest[T] { * of the type represented by `that` manifest, subject to the limitations * described in the header. */ - @deprecated("Use scala.reflect.runtime.universe.TypeTag for subtype checking instead", "2.10.0") + @deprecated("use scala.reflect.runtime.universe.TypeTag for subtype checking instead", "2.10.0") def <:<(that: ClassManifest[_]): Boolean = { // All types which could conform to these types will override <:<. def cannotMatch = { @@ -78,7 +78,7 @@ trait ClassManifestDeprecatedApis[T] extends OptManifest[T] { * of the type represented by `that` manifest, subject to the limitations * described in the header. */ - @deprecated("Use scala.reflect.runtime.universe.TypeTag for subtype checking instead", "2.10.0") + @deprecated("use scala.reflect.runtime.universe.TypeTag for subtype checking instead", "2.10.0") def >:>(that: ClassManifest[_]): Boolean = that <:< this @@ -90,44 +90,44 @@ trait ClassManifestDeprecatedApis[T] extends OptManifest[T] { protected def arrayClass[T](tp: jClass[_]): jClass[Array[T]] = java.lang.reflect.Array.newInstance(tp, 0).getClass.asInstanceOf[jClass[Array[T]]] - @deprecated("Use wrap instead", "2.10.0") + @deprecated("use wrap instead", "2.10.0") def arrayManifest: ClassManifest[Array[T]] = ClassManifest.classType[Array[T]](arrayClass[T](runtimeClass), this) override def newArray(len: Int): Array[T] = java.lang.reflect.Array.newInstance(runtimeClass, len).asInstanceOf[Array[T]] - @deprecated("Use wrap.newArray instead", "2.10.0") + @deprecated("use wrap.newArray instead", "2.10.0") def newArray2(len: Int): Array[Array[T]] = java.lang.reflect.Array.newInstance(arrayClass[T](runtimeClass), len) .asInstanceOf[Array[Array[T]]] - @deprecated("Use wrap.wrap.newArray instead", "2.10.0") + @deprecated("use wrap.wrap.newArray instead", "2.10.0") def newArray3(len: Int): Array[Array[Array[T]]] = java.lang.reflect.Array.newInstance(arrayClass[Array[T]](arrayClass[T](runtimeClass)), len) .asInstanceOf[Array[Array[Array[T]]]] - @deprecated("Use wrap.wrap.wrap.newArray instead", "2.10.0") + @deprecated("use wrap.wrap.wrap.newArray instead", "2.10.0") def newArray4(len: Int): Array[Array[Array[Array[T]]]] = java.lang.reflect.Array.newInstance(arrayClass[Array[Array[T]]](arrayClass[Array[T]](arrayClass[T](runtimeClass))), len) .asInstanceOf[Array[Array[Array[Array[T]]]]] - @deprecated("Use wrap.wrap.wrap.wrap.newArray instead", "2.10.0") + @deprecated("use wrap.wrap.wrap.wrap.newArray instead", "2.10.0") def newArray5(len: Int): Array[Array[Array[Array[Array[T]]]]] = java.lang.reflect.Array.newInstance(arrayClass[Array[Array[Array[T]]]](arrayClass[Array[Array[T]]](arrayClass[Array[T]](arrayClass[T](runtimeClass)))), len) .asInstanceOf[Array[Array[Array[Array[Array[T]]]]]] - @deprecated("Create WrappedArray directly instead", "2.10.0") + @deprecated("create WrappedArray directly instead", "2.10.0") def newWrappedArray(len: Int): WrappedArray[T] = // it's safe to assume T <: AnyRef here because the method is overridden for all value type manifests new WrappedArray.ofRef[T with AnyRef](newArray(len).asInstanceOf[Array[T with AnyRef]]).asInstanceOf[WrappedArray[T]] - @deprecated("Use ArrayBuilder.make(this) instead", "2.10.0") + @deprecated("use ArrayBuilder.make(this) instead", "2.10.0") def newArrayBuilder(): ArrayBuilder[T] = // it's safe to assume T <: AnyRef here because the method is overridden for all value type manifests new ArrayBuilder.ofRef[T with AnyRef]()(this.asInstanceOf[ClassManifest[T with AnyRef]]).asInstanceOf[ArrayBuilder[T]] - @deprecated("Use scala.reflect.runtime.universe.TypeTag to capture type structure instead", "2.10.0") + @deprecated("use scala.reflect.runtime.universe.TypeTag to capture type structure instead", "2.10.0") def typeArguments: List[OptManifest[_]] = List() protected def argString = @@ -143,8 +143,8 @@ trait ClassManifestDeprecatedApis[T] extends OptManifest[T] { * This is done to prevent avalanches of deprecation warnings in the code that calls methods with manifests. * * In a perfect world, we would just remove the @deprecated annotation from `ClassManifest` the object - * and then delete it in 2.11. After all, that object is explicitly marked as internal, so noone should use it. - * However a lot of existing libraries disregarded the scaladoc that comes with `ClassManifest`, + * and then delete it in 2.11. After all, that object is explicitly marked as internal, so no one should use it. + * However a lot of existing libraries disregarded the Scaladoc that comes with `ClassManifest`, * so we need to somehow nudge them into migrating prior to removing stuff out of the blue. * Hence we've introduced this design decision as the lesser of two evils. */ @@ -205,15 +205,18 @@ object ClassManifestFactory { case m: ClassManifest[_] => m.asInstanceOf[ClassManifest[T]].arrayManifest } + @SerialVersionUID(1L) + private class AbstractTypeClassManifest[T](prefix: OptManifest[_], name: String, clazz: jClass[_], args: OptManifest[_]*) extends ClassManifest[T] { + override def runtimeClass = clazz + override val typeArguments = args.toList + override def toString = prefix.toString+"#"+name+argString + } + /** ClassManifest for the abstract type `prefix # name`. `upperBound` is not * strictly necessary as it could be obtained by reflection. It was * added so that erasure can be calculated without reflection. */ def abstractType[T](prefix: OptManifest[_], name: String, clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] = - new ClassManifest[T] { - override def runtimeClass = clazz - override val typeArguments = args.toList - override def toString = prefix.toString+"#"+name+argString - } + new AbstractTypeClassManifest(prefix, name, clazz) /** ClassManifest for the abstract type `prefix # name`. `upperBound` is not * strictly necessary as it could be obtained by reflection. It was @@ -221,15 +224,12 @@ object ClassManifestFactory { * todo: remove after next bootstrap */ def abstractType[T](prefix: OptManifest[_], name: String, upperbound: ClassManifest[_], args: OptManifest[_]*): ClassManifest[T] = - new ClassManifest[T] { - override def runtimeClass = upperbound.runtimeClass - override val typeArguments = args.toList - override def toString = prefix.toString+"#"+name+argString - } + new AbstractTypeClassManifest(prefix, name, upperbound.runtimeClass) } /** Manifest for the class type `clazz[args]`, where `clazz` is * a top-level or static class */ +@SerialVersionUID(1L) private class ClassTypeManifest[T]( prefix: Option[OptManifest[_]], val runtimeClass: jClass[_], diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 9dd96183da..30ceadceeb 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -2,7 +2,6 @@ package scala package reflect import java.lang.{ Class => jClass } -import scala.runtime.ScalaRunTime.arrayElementClass /** * @@ -84,28 +83,13 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial ) Some(x.asInstanceOf[T]) else None - // TODO: deprecate overloads in 2.12.0, remove in 2.13.0 - def unapply(x: Byte) : Option[T] = unapplyImpl(x, classOf[Byte]) - def unapply(x: Short) : Option[T] = unapplyImpl(x, classOf[Short]) - def unapply(x: Char) : Option[T] = unapplyImpl(x, classOf[Char]) - def unapply(x: Int) : Option[T] = unapplyImpl(x, classOf[Int]) - def unapply(x: Long) : Option[T] = unapplyImpl(x, classOf[Long]) - def unapply(x: Float) : Option[T] = unapplyImpl(x, classOf[Float]) - def unapply(x: Double) : Option[T] = unapplyImpl(x, classOf[Double]) - def unapply(x: Boolean) : Option[T] = unapplyImpl(x, classOf[Boolean]) - def unapply(x: Unit) : Option[T] = unapplyImpl(x, classOf[Unit]) - - private[this] def unapplyImpl(x: Any, primitiveCls: java.lang.Class[_]): Option[T] = - if (runtimeClass.isInstance(x) || runtimeClass.isAssignableFrom(primitiveCls)) Some(x.asInstanceOf[T]) - else None - // case class accessories override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass - override def hashCode = scala.runtime.ScalaRunTime.hash(runtimeClass) + override def hashCode = runtimeClass.## override def toString = { def prettyprint(clazz: jClass[_]): String = - if (clazz.isArray) s"Array[${prettyprint(arrayElementClass(clazz))}]" else + if (clazz.isArray) s"Array[${prettyprint(clazz.getComponentType)}]" else clazz.getName prettyprint(runtimeClass) } @@ -135,6 +119,9 @@ object ClassTag { val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing val Null : ClassTag[scala.Null] = Manifest.Null + @SerialVersionUID(1L) + private class GenericClassTag[T](val runtimeClass: jClass[_]) extends ClassTag[T] + def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = runtimeClass1 match { case java.lang.Byte.TYPE => ClassTag.Byte.asInstanceOf[ClassTag[T]] @@ -149,7 +136,7 @@ object ClassTag { case ObjectTYPE => ClassTag.Object.asInstanceOf[ClassTag[T]] case NothingTYPE => ClassTag.Nothing.asInstanceOf[ClassTag[T]] case NullTYPE => ClassTag.Null.asInstanceOf[ClassTag[T]] - case _ => new ClassTag[T]{ def runtimeClass = runtimeClass1 } + case _ => new GenericClassTag[T](runtimeClass1) } def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.runtimeClass) diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index e099853463..8e5ba6376e 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -9,7 +9,7 @@ package scala package reflect -import scala.collection.mutable.{ ArrayBuilder, WrappedArray } +import scala.collection.mutable.{ArrayBuilder, WrappedArray} /** A `Manifest[T]` is an opaque descriptor for type T. Its supported use * is to give access to the erasure of the type as a `Class` instance, as @@ -21,27 +21,26 @@ import scala.collection.mutable.{ ArrayBuilder, WrappedArray } * which are not yet adequately represented in manifests. * * Example usages: -{{{ - def arr[T] = new Array[T](0) // does not compile - def arr[T](implicit m: Manifest[T]) = new Array[T](0) // compiles - def arr[T: Manifest] = new Array[T](0) // shorthand for the preceding - - // Methods manifest, classManifest, and optManifest are in [[scala.Predef]]. - def isApproxSubType[T: Manifest, U: Manifest] = manifest[T] <:< manifest[U] - isApproxSubType[List[String], List[AnyRef]] // true - isApproxSubType[List[String], List[Int]] // false - - def methods[T: ClassManifest] = classManifest[T].erasure.getMethods - def retType[T: ClassManifest](name: String) = - methods[T] find (_.getName == name) map (_.getGenericReturnType) - - retType[Map[_, _]]("values") // Some(scala.collection.Iterable<B>) -}}} + * {{{ + * def arr[T] = new Array[T](0) // does not compile + * def arr[T](implicit m: Manifest[T]) = new Array[T](0) // compiles + * def arr[T: Manifest] = new Array[T](0) // shorthand for the preceding * + * // Methods manifest, classManifest, and optManifest are in [[scala.Predef]]. + * def isApproxSubType[T: Manifest, U: Manifest] = manifest[T] <:< manifest[U] + * isApproxSubType[List[String], List[AnyRef]] // true + * isApproxSubType[List[String], List[Int]] // false + * + * def methods[T: ClassManifest] = classManifest[T].erasure.getMethods + * def retType[T: ClassManifest](name: String) = + * methods[T] find (_.getName == name) map (_.getGenericReturnType) + * + * retType[Map[_, _]]("values") // Some(scala.collection.Iterable<B>) + * }}} */ @scala.annotation.implicitNotFound(msg = "No Manifest available for ${T}.") // TODO undeprecated until Scala reflection becomes non-experimental -// @deprecated("Use scala.reflect.ClassTag (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") +// @deprecated("use scala.reflect.ClassTag (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") trait Manifest[T] extends ClassManifest[T] with Equals { override def typeArguments: List[Manifest[_]] = Nil @@ -63,7 +62,7 @@ trait Manifest[T] extends ClassManifest[T] with Equals { } // TODO undeprecated until Scala reflection becomes non-experimental -// @deprecated("Use type tags and manually check the corresponding class or type instead", "2.10.0") +// @deprecated("use type tags and manually check the corresponding class or type instead", "2.10.0") @SerialVersionUID(1L) abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals { override def <:<(that: ClassManifest[_]): Boolean = @@ -88,71 +87,88 @@ object ManifestFactory { def valueManifests: List[AnyValManifest[_]] = List(Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit) - val Byte: AnyValManifest[Byte] = new AnyValManifest[scala.Byte]("Byte") { + @SerialVersionUID(1L) + private class ByteManifest extends AnyValManifest[scala.Byte]("Byte") { def runtimeClass = java.lang.Byte.TYPE override def newArray(len: Int): Array[Byte] = new Array[Byte](len) override def newWrappedArray(len: Int): WrappedArray[Byte] = new WrappedArray.ofByte(new Array[Byte](len)) override def newArrayBuilder(): ArrayBuilder[Byte] = new ArrayBuilder.ofByte() private def readResolve(): Any = Manifest.Byte } + val Byte: AnyValManifest[Byte] = new ByteManifest - val Short: AnyValManifest[Short] = new AnyValManifest[scala.Short]("Short") { + @SerialVersionUID(1L) + private class ShortManifest extends AnyValManifest[scala.Short]("Short") { def runtimeClass = java.lang.Short.TYPE override def newArray(len: Int): Array[Short] = new Array[Short](len) override def newWrappedArray(len: Int): WrappedArray[Short] = new WrappedArray.ofShort(new Array[Short](len)) override def newArrayBuilder(): ArrayBuilder[Short] = new ArrayBuilder.ofShort() private def readResolve(): Any = Manifest.Short } + val Short: AnyValManifest[Short] = new ShortManifest - val Char: AnyValManifest[Char] = new AnyValManifest[scala.Char]("Char") { + @SerialVersionUID(1L) + private class CharManifest extends AnyValManifest[scala.Char]("Char") { def runtimeClass = java.lang.Character.TYPE override def newArray(len: Int): Array[Char] = new Array[Char](len) override def newWrappedArray(len: Int): WrappedArray[Char] = new WrappedArray.ofChar(new Array[Char](len)) override def newArrayBuilder(): ArrayBuilder[Char] = new ArrayBuilder.ofChar() private def readResolve(): Any = Manifest.Char } + val Char: AnyValManifest[Char] = new CharManifest - val Int: AnyValManifest[Int] = new AnyValManifest[scala.Int]("Int") { + @SerialVersionUID(1L) + private class IntManifest extends AnyValManifest[scala.Int]("Int") { def runtimeClass = java.lang.Integer.TYPE override def newArray(len: Int): Array[Int] = new Array[Int](len) override def newWrappedArray(len: Int): WrappedArray[Int] = new WrappedArray.ofInt(new Array[Int](len)) override def newArrayBuilder(): ArrayBuilder[Int] = new ArrayBuilder.ofInt() private def readResolve(): Any = Manifest.Int } + val Int: AnyValManifest[Int] = new IntManifest - val Long: AnyValManifest[Long] = new AnyValManifest[scala.Long]("Long") { + @SerialVersionUID(1L) + private class LongManifest extends AnyValManifest[scala.Long]("Long") { def runtimeClass = java.lang.Long.TYPE override def newArray(len: Int): Array[Long] = new Array[Long](len) override def newWrappedArray(len: Int): WrappedArray[Long] = new WrappedArray.ofLong(new Array[Long](len)) override def newArrayBuilder(): ArrayBuilder[Long] = new ArrayBuilder.ofLong() private def readResolve(): Any = Manifest.Long } + val Long: AnyValManifest[Long] = new LongManifest - val Float: AnyValManifest[Float] = new AnyValManifest[scala.Float]("Float") { + @SerialVersionUID(1L) + private class FloatManifest extends AnyValManifest[scala.Float]("Float") { def runtimeClass = java.lang.Float.TYPE override def newArray(len: Int): Array[Float] = new Array[Float](len) override def newWrappedArray(len: Int): WrappedArray[Float] = new WrappedArray.ofFloat(new Array[Float](len)) override def newArrayBuilder(): ArrayBuilder[Float] = new ArrayBuilder.ofFloat() private def readResolve(): Any = Manifest.Float } + val Float: AnyValManifest[Float] = new FloatManifest - val Double: AnyValManifest[Double] = new AnyValManifest[scala.Double]("Double") { + @SerialVersionUID(1L) + private class DoubleManifest extends AnyValManifest[scala.Double]("Double") { def runtimeClass = java.lang.Double.TYPE override def newArray(len: Int): Array[Double] = new Array[Double](len) override def newWrappedArray(len: Int): WrappedArray[Double] = new WrappedArray.ofDouble(new Array[Double](len)) override def newArrayBuilder(): ArrayBuilder[Double] = new ArrayBuilder.ofDouble() private def readResolve(): Any = Manifest.Double } + val Double: AnyValManifest[Double] = new DoubleManifest - val Boolean: AnyValManifest[Boolean] = new AnyValManifest[scala.Boolean]("Boolean") { + @SerialVersionUID(1L) + private class BooleanManifest extends AnyValManifest[scala.Boolean]("Boolean") { def runtimeClass = java.lang.Boolean.TYPE override def newArray(len: Int): Array[Boolean] = new Array[Boolean](len) override def newWrappedArray(len: Int): WrappedArray[Boolean] = new WrappedArray.ofBoolean(new Array[Boolean](len)) override def newArrayBuilder(): ArrayBuilder[Boolean] = new ArrayBuilder.ofBoolean() private def readResolve(): Any = Manifest.Boolean } + val Boolean: AnyValManifest[Boolean] = new BooleanManifest - val Unit: AnyValManifest[Unit] = new AnyValManifest[scala.Unit]("Unit") { + @SerialVersionUID(1L) + private class UnitManifest extends AnyValManifest[scala.Unit]("Unit") { def runtimeClass = java.lang.Void.TYPE override def newArray(len: Int): Array[Unit] = new Array[Unit](len) override def newWrappedArray(len: Int): WrappedArray[Unit] = new WrappedArray.ofUnit(new Array[Unit](len)) @@ -162,44 +178,56 @@ object ManifestFactory { else super.arrayClass(tp) private def readResolve(): Any = Manifest.Unit } + val Unit: AnyValManifest[Unit] = new UnitManifest private val ObjectTYPE = classOf[java.lang.Object] private val NothingTYPE = classOf[scala.runtime.Nothing$] private val NullTYPE = classOf[scala.runtime.Null$] - val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any](ObjectTYPE, "Any") { + @SerialVersionUID(1L) + private class AnyManifest extends PhantomManifest[scala.Any](ObjectTYPE, "Any") { override def newArray(len: Int) = new Array[scala.Any](len) override def <:<(that: ClassManifest[_]): Boolean = (that eq this) private def readResolve(): Any = Manifest.Any } + val Any: Manifest[scala.Any] = new AnyManifest - val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object](ObjectTYPE, "Object") { + @SerialVersionUID(1L) + private class ObjectManifest extends PhantomManifest[java.lang.Object](ObjectTYPE, "Object") { override def newArray(len: Int) = new Array[java.lang.Object](len) override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.Object } + val Object: Manifest[java.lang.Object] = new ObjectManifest val AnyRef: Manifest[scala.AnyRef] = Object.asInstanceOf[Manifest[scala.AnyRef]] - val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal](ObjectTYPE, "AnyVal") { + @SerialVersionUID(1L) + private class AnyValPhantomManifest extends PhantomManifest[scala.AnyVal](ObjectTYPE, "AnyVal") { override def newArray(len: Int) = new Array[scala.AnyVal](len) override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) private def readResolve(): Any = Manifest.AnyVal } + val AnyVal: Manifest[scala.AnyVal] = new AnyValPhantomManifest - val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null](NullTYPE, "Null") { + @SerialVersionUID(1L) + private class NullManifest extends PhantomManifest[scala.Null](NullTYPE, "Null") { override def newArray(len: Int) = new Array[scala.Null](len) override def <:<(that: ClassManifest[_]): Boolean = (that ne null) && (that ne Nothing) && !(that <:< AnyVal) private def readResolve(): Any = Manifest.Null } + val Null: Manifest[scala.Null] = new NullManifest - val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing](NothingTYPE, "Nothing") { + @SerialVersionUID(1L) + private class NothingManifest extends PhantomManifest[scala.Nothing](NothingTYPE, "Nothing") { override def newArray(len: Int) = new Array[scala.Nothing](len) override def <:<(that: ClassManifest[_]): Boolean = (that ne null) private def readResolve(): Any = Manifest.Nothing } + val Nothing: Manifest[scala.Nothing] = new NothingManifest + @SerialVersionUID(1L) private class SingletonTypeManifest[T <: AnyRef](value: AnyRef) extends Manifest[T] { lazy val runtimeClass = value.getClass override lazy val toString = value.toString + ".type" @@ -230,6 +258,7 @@ object ManifestFactory { def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = new ClassTypeManifest[T](Some(prefix), clazz, args.toList) + @SerialVersionUID(1L) private abstract class PhantomManifest[T](_runtimeClass: Predef.Class[_], override val toString: String) extends ClassTypeManifest[T](None, _runtimeClass, Nil) { override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] @@ -239,6 +268,7 @@ object ManifestFactory { /** Manifest for the class type `clazz[args]`, where `clazz` is * a top-level or static class. */ + @SerialVersionUID(1L) private class ClassTypeManifest[T](prefix: Option[Manifest[_]], val runtimeClass: Predef.Class[_], override val typeArguments: List[Manifest[_]]) extends Manifest[T] { @@ -251,31 +281,40 @@ object ManifestFactory { def arrayType[T](arg: Manifest[_]): Manifest[Array[T]] = arg.asInstanceOf[Manifest[T]].arrayManifest + @SerialVersionUID(1L) + private class AbstractTypeManifest[T](prefix: Manifest[_], name: String, upperBound: Predef.Class[_], args: Seq[Manifest[_]]) extends Manifest[T] { + def runtimeClass = upperBound + override val typeArguments = args.toList + override def toString = prefix.toString+"#"+name+argString + } + /** Manifest for the abstract type `prefix # name`. `upperBound` is not * strictly necessary as it could be obtained by reflection. It was * added so that erasure can be calculated without reflection. */ def abstractType[T](prefix: Manifest[_], name: String, upperBound: Predef.Class[_], args: Manifest[_]*): Manifest[T] = - new Manifest[T] { - def runtimeClass = upperBound - override val typeArguments = args.toList - override def toString = prefix.toString+"#"+name+argString - } + new AbstractTypeManifest[T](prefix, name, upperBound, args) + + @SerialVersionUID(1L) + private class WildcardManifest[T](lowerBound: Manifest[_], upperBound: Manifest[_]) extends Manifest[T] { + def runtimeClass = upperBound.runtimeClass + override def toString = + "_" + + (if (lowerBound eq Nothing) "" else " >: "+lowerBound) + + (if (upperBound eq Nothing) "" else " <: "+upperBound) + } /** Manifest for the unknown type `_ >: L <: U` in an existential. */ def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] = - new Manifest[T] { - def runtimeClass = upperBound.runtimeClass - override def toString = - "_" + - (if (lowerBound eq Nothing) "" else " >: "+lowerBound) + - (if (upperBound eq Nothing) "" else " <: "+upperBound) - } + new WildcardManifest[T](lowerBound, upperBound) + + @SerialVersionUID(1L) + private class IntersectionTypeManifest[T](parents: Seq[Manifest[_]]) extends Manifest[T] { + def runtimeClass = parents.head.runtimeClass + override def toString = parents.mkString(" with ") + } /** Manifest for the intersection type `parents_0 with ... with parents_n`. */ def intersectionType[T](parents: Manifest[_]*): Manifest[T] = - new Manifest[T] { - def runtimeClass = parents.head.runtimeClass - override def toString = parents.mkString(" with ") - } + new IntersectionTypeManifest[T](parents) } diff --git a/src/library/scala/reflect/NameTransformer.scala b/src/library/scala/reflect/NameTransformer.scala index a8430548f5..bdf5165df5 100644 --- a/src/library/scala/reflect/NameTransformer.scala +++ b/src/library/scala/reflect/NameTransformer.scala @@ -13,14 +13,16 @@ package reflect * Also provides some constants. */ object NameTransformer { - // XXX Short term: providing a way to alter these without having to recompile - // the compiler before recompiling the compiler. - val MODULE_SUFFIX_STRING = sys.props.getOrElse("SCALA_MODULE_SUFFIX_STRING", "$") - val NAME_JOIN_STRING = sys.props.getOrElse("SCALA_NAME_JOIN_STRING", "$") - val MODULE_INSTANCE_NAME = "MODULE$" - val LOCAL_SUFFIX_STRING = " " - val SETTER_SUFFIX_STRING = "_$eq" - val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" + // TODO: reduce duplication with and in StdNames + // I made these constants because we cannot change them without bumping our major version anyway. + final val NAME_JOIN_STRING = "$" + final val MODULE_SUFFIX_STRING = "$" + final val MODULE_INSTANCE_NAME = "MODULE$" + final val LOCAL_SUFFIX_STRING = " " + final val LAZY_LOCAL_SUFFIX_STRING = "$lzy" + final val MODULE_VAR_SUFFIX_STRING = "$module" + final val SETTER_SUFFIX_STRING = "_$eq" + final val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$" private val nops = 128 private val ncodes = 26 * 26 diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 509d181d87..88cdfb0ed4 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -25,21 +25,21 @@ package object reflect { * be wrong when variance is involved or when a subtype has a different * number of type arguments than a supertype. */ - @deprecated("Use scala.reflect.ClassTag instead", "2.10.0") + @deprecated("use scala.reflect.ClassTag instead", "2.10.0") @annotation.implicitNotFound(msg = "No ClassManifest available for ${T}.") type ClassManifest[T] = scala.reflect.ClassTag[T] /** The object `ClassManifest` defines factory methods for manifests. * It is intended for use by the compiler and should not be used in client code. */ - @deprecated("Use scala.reflect.ClassTag instead", "2.10.0") + @deprecated("use scala.reflect.ClassTag instead", "2.10.0") val ClassManifest = ClassManifestFactory /** The object `Manifest` defines factory methods for manifests. * It is intended for use by the compiler and should not be used in client code. */ // TODO undeprecated until Scala reflection becomes non-experimental - // @deprecated("Use scala.reflect.ClassTag (to capture erasures), scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") + // @deprecated("use scala.reflect.ClassTag (to capture erasures), scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0") val Manifest = ManifestFactory def classTag[T](implicit ctag: ClassTag[T]) = ctag diff --git a/src/library/scala/remote.scala b/src/library/scala/remote.scala index 4b16651af9..7265a15194 100644 --- a/src/library/scala/remote.scala +++ b/src/library/scala/remote.scala @@ -24,4 +24,5 @@ package scala * } * }}} */ +@deprecated("extend java.rmi.Remote instead and add @throws[java.rmi.RemoteException] to public methods", "2.12.0") class remote extends scala.annotation.StaticAnnotation {} diff --git a/src/library/scala/runtime/AbstractPartialFunction.scala b/src/library/scala/runtime/AbstractPartialFunction.scala index 986cd0390f..630966d0d4 100644 --- a/src/library/scala/runtime/AbstractPartialFunction.scala +++ b/src/library/scala/runtime/AbstractPartialFunction.scala @@ -9,8 +9,6 @@ package scala package runtime -import scala.annotation.unspecialized - /** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` * in terms of `isDefinedAt` and `applyOrElse`. * diff --git a/src/library/scala/runtime/ArrayRuntime.java b/src/library/scala/runtime/ArrayRuntime.java deleted file mode 100644 index 1a0f748931..0000000000 --- a/src/library/scala/runtime/ArrayRuntime.java +++ /dev/null @@ -1,26 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala.runtime; - -/** - * Methods on Java arrays - */ -class ArrayRuntime { - static boolean[] cloneArray(boolean[] array) { return array.clone(); } - static byte[] cloneArray(byte[] array) { return array.clone(); } - static short[] cloneArray(short[] array) { return array.clone(); } - static char[] cloneArray(char[] array) { return array.clone(); } - static int[] cloneArray(int[] array) { return array.clone(); } - static long[] cloneArray(long[] array) { return array.clone(); } - static float[] cloneArray(float[] array) { return array.clone(); } - static double[] cloneArray(double[] array) { return array.clone(); } - static Object[] cloneArray(Object[] array) { return array.clone(); } -} diff --git a/src/library/scala/runtime/Boxed.scala b/src/library/scala/runtime/Boxed.scala deleted file mode 100644 index 933444773d..0000000000 --- a/src/library/scala/runtime/Boxed.scala +++ /dev/null @@ -1,12 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -package scala -package runtime - -trait Boxed { } diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index 9cb1dee41c..6b3874fc1f 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -179,7 +179,7 @@ public final class BoxesRunTime return xc.equals(y); } - private static boolean equalsNumChar(java.lang.Number xn, java.lang.Character yc) { + public static boolean equalsNumChar(java.lang.Number xn, java.lang.Character yc) { if (yc == null) return xn == null; @@ -198,70 +198,6 @@ public final class BoxesRunTime } } - /** Hashcode algorithm is driven by the requirements imposed - * by primitive equality semantics, namely that equal objects - * have equal hashCodes. The first priority are the integral/char - * types, which already have the same hashCodes for the same - * values except for Long. So Long's hashCode is altered to - * conform to Int's for all values in Int's range. - * - * Float is problematic because it's far too small to hold - * all the Ints, so for instance Int.MaxValue.toFloat claims - * to be == to each of the largest 64 Ints. There is no way - * to preserve equals/hashCode alignment without compromising - * the hashCode distribution, so Floats are only guaranteed - * to have the same hashCode for whole Floats in the range - * Short.MinValue to Short.MaxValue (2^16 total.) - * - * Double has its hashCode altered to match the entire Int range, - * but is not guaranteed beyond that. (But could/should it be? - * The hashCode is only 32 bits so this is a more tractable - * issue than Float's, but it might be better simply to exclude it.) - * - * Note: BigInt and BigDecimal, being arbitrary precision, could - * be made consistent with all other types for the Int range, but - * as yet have not. - * - * Note: Among primitives, Float.NaN != Float.NaN, but the boxed - * versions are equal. This still needs reconciliation. - */ - public static int hashFromLong(java.lang.Long n) { - int iv = n.intValue(); - if (iv == n.longValue()) return iv; - else return n.hashCode(); - } - public static int hashFromDouble(java.lang.Double n) { - int iv = n.intValue(); - double dv = n.doubleValue(); - if (iv == dv) return iv; - - long lv = n.longValue(); - if (lv == dv) return java.lang.Long.valueOf(lv).hashCode(); - - float fv = n.floatValue(); - if (fv == dv) return java.lang.Float.valueOf(fv).hashCode(); - else return n.hashCode(); - } - public static int hashFromFloat(java.lang.Float n) { - int iv = n.intValue(); - float fv = n.floatValue(); - if (iv == fv) return iv; - - long lv = n.longValue(); - if (lv == fv) return java.lang.Long.valueOf(lv).hashCode(); - else return n.hashCode(); - } - public static int hashFromNumber(java.lang.Number n) { - if (n instanceof java.lang.Long) return hashFromLong((java.lang.Long)n); - else if (n instanceof java.lang.Double) return hashFromDouble((java.lang.Double)n); - else if (n instanceof java.lang.Float) return hashFromFloat((java.lang.Float)n); - else return n.hashCode(); - } - public static int hashFromObject(Object a) { - if (a instanceof Number) return hashFromNumber((Number)a); - else return a.hashCode(); - } - private static int unboxCharOrInt(Object arg1, int code) { if (code == CHAR) return ((java.lang.Character) arg1).charValue(); diff --git a/src/library/scala/runtime/LambdaDeserialize.java b/src/library/scala/runtime/LambdaDeserialize.java new file mode 100644 index 0000000000..4c5198cc48 --- /dev/null +++ b/src/library/scala/runtime/LambdaDeserialize.java @@ -0,0 +1,38 @@ +package scala.runtime; + + +import java.lang.invoke.*; +import java.util.HashMap; + +public final class LambdaDeserialize { + public static final MethodType DESERIALIZE_LAMBDA_MT = MethodType.fromMethodDescriptorString("(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", LambdaDeserialize.class.getClassLoader()); + + private MethodHandles.Lookup lookup; + private final HashMap<String, MethodHandle> cache = new HashMap<>(); + private final LambdaDeserializer$ l = LambdaDeserializer$.MODULE$; + private final HashMap<String, MethodHandle> targetMethodMap; + + private LambdaDeserialize(MethodHandles.Lookup lookup, MethodHandle[] targetMethods) { + this.lookup = lookup; + targetMethodMap = new HashMap<>(targetMethods.length); + for (MethodHandle targetMethod : targetMethods) { + MethodHandleInfo info = lookup.revealDirect(targetMethod); + String key = nameAndDescriptorKey(info.getName(), info.getMethodType().toMethodDescriptorString()); + targetMethodMap.put(key, targetMethod); + } + } + + public Object deserializeLambda(SerializedLambda serialized) { + return l.deserializeLambda(lookup, cache, targetMethodMap, serialized); + } + + public static CallSite bootstrap(MethodHandles.Lookup lookup, String invokedName, + MethodType invokedType, MethodHandle... targetMethods) throws Throwable { + MethodHandle deserializeLambda = lookup.findVirtual(LambdaDeserialize.class, "deserializeLambda", DESERIALIZE_LAMBDA_MT); + MethodHandle exact = deserializeLambda.bindTo(new LambdaDeserialize(lookup, targetMethods)).asType(invokedType); + return new ConstantCallSite(exact); + } + public static String nameAndDescriptorKey(String name, String descriptor) { + return name + descriptor; + } +} diff --git a/src/library/scala/runtime/LambdaDeserializer.scala b/src/library/scala/runtime/LambdaDeserializer.scala new file mode 100644 index 0000000000..25f41fd049 --- /dev/null +++ b/src/library/scala/runtime/LambdaDeserializer.scala @@ -0,0 +1,126 @@ +package scala.runtime + +import java.lang.invoke._ + +/** + * This class is only intended to be called by synthetic `$deserializeLambda$` method that the Scala 2.12 + * compiler will add to classes hosting lambdas. + * + * It is not intended to be consumed directly. + */ +object LambdaDeserializer { + /** + * Deserialize a lambda by calling `LambdaMetafactory.altMetafactory` to spin up a lambda class + * and instantiating this class with the captured arguments. + * + * A cache may be provided to ensure that subsequent deserialization of the same lambda expression + * is cheap, it amounts to a reflective call to the constructor of the previously created class. + * However, deserialization of the same lambda expression is not guaranteed to use the same class, + * concurrent deserialization of the same lambda expression may spin up more than one class. + * + * Assumptions: + * - No additional marker interfaces are required beyond `{java.io,scala.}Serializable`. These are + * not stored in `SerializedLambda`, so we can't reconstitute them. + * - No additional bridge methods are passed to `altMetafactory`. Again, these are not stored. + * + * @param lookup The factory for method handles. Must have access to the implementation method, the + * functional interface class, and `java.io.Serializable` or `scala.Serializable` as + * required. + * @param cache A cache used to avoid spinning up a class for each deserialization of a given lambda. May be `null` + * @param serialized The lambda to deserialize. Note that this is typically created by the `readResolve` + * member of the anonymous class created by `LambdaMetaFactory`. + * @return An instance of the functional interface + */ + def deserializeLambda(lookup: MethodHandles.Lookup, cache: java.util.Map[String, MethodHandle], + targetMethodMap: java.util.Map[String, MethodHandle], serialized: SerializedLambda): AnyRef = { + assert(targetMethodMap != null) + def slashDot(name: String) = name.replaceAll("/", ".") + val loader = lookup.lookupClass().getClassLoader + val implClass = loader.loadClass(slashDot(serialized.getImplClass)) + val key = LambdaDeserialize.nameAndDescriptorKey(serialized.getImplMethodName, serialized.getImplMethodSignature) + + def makeCallSite: CallSite = { + import serialized._ + def parseDescriptor(s: String) = + MethodType.fromMethodDescriptorString(s, loader) + + val funcInterfaceSignature = parseDescriptor(getFunctionalInterfaceMethodSignature) + val instantiated = parseDescriptor(getInstantiatedMethodType) + val functionalInterfaceClass = loader.loadClass(slashDot(getFunctionalInterfaceClass)) + + val implMethodSig = parseDescriptor(getImplMethodSignature) + // Construct the invoked type from the impl method type. This is the type of a factory + // that will be generated by the meta-factory. It is a method type, with param types + // coming form the types of the captures, and return type being the functional interface. + val invokedType: MethodType = { + // 1. Add receiver for non-static impl methods + val withReceiver = getImplMethodKind match { + case MethodHandleInfo.REF_invokeStatic | MethodHandleInfo.REF_newInvokeSpecial => + implMethodSig + case _ => + implMethodSig.insertParameterTypes(0, implClass) + } + // 2. Remove lambda parameters, leaving only captures. Note: the receiver may be a lambda parameter, + // such as in `Function<Object, String> s = Object::toString` + val lambdaArity = funcInterfaceSignature.parameterCount() + val from = withReceiver.parameterCount() - lambdaArity + val to = withReceiver.parameterCount() + + // 3. Drop the lambda return type and replace with the functional interface. + withReceiver.dropParameterTypes(from, to).changeReturnType(functionalInterfaceClass) + } + + // Lookup the implementation method + val implMethod: MethodHandle = try { + if (targetMethodMap.containsKey(key)) { + targetMethodMap.get(key) + } else { + throw new IllegalArgumentException("Illegal lambda deserialization") + } + } catch { + case e: ReflectiveOperationException => throw new IllegalArgumentException("Illegal lambda deserialization", e) + } + + val flags: Int = LambdaMetafactory.FLAG_SERIALIZABLE | LambdaMetafactory.FLAG_MARKERS + val isScalaFunction = functionalInterfaceClass.getName.startsWith("scala.Function") + val markerInterface: Class[_] = loader.loadClass(if (isScalaFunction) ScalaSerializable else JavaIOSerializable) + + LambdaMetafactory.altMetafactory( + lookup, getFunctionalInterfaceMethodName, invokedType, + + /* samMethodType = */ funcInterfaceSignature, + /* implMethod = */ implMethod, + /* instantiatedMethodType = */ instantiated, + /* flags = */ flags.asInstanceOf[AnyRef], + /* markerInterfaceCount = */ 1.asInstanceOf[AnyRef], + /* markerInterfaces[0] = */ markerInterface, + /* bridgeCount = */ 0.asInstanceOf[AnyRef] + ) + } + + val factory: MethodHandle = if (cache == null) { + makeCallSite.getTarget + } else cache.synchronized{ + cache.get(key) match { + case null => + val callSite = makeCallSite + val temp = callSite.getTarget + cache.put(key, temp) + temp + case target => target + } + } + + val captures = Array.tabulate(serialized.getCapturedArgCount)(n => serialized.getCapturedArg(n)) + factory.invokeWithArguments(captures: _*) + } + + private val ScalaSerializable = "scala.Serializable" + + private val JavaIOSerializable = { + // We could actually omit this marker interface as LambdaMetaFactory will add it if + // the FLAG_SERIALIZABLE is set and of the provided markers extend it. But the code + // is cleaner if we uniformly add a single marker, so I'm leaving it in place. + "java.io.Serializable" + } +} diff --git a/src/library/scala/runtime/LazyRef.scala b/src/library/scala/runtime/LazyRef.scala new file mode 100644 index 0000000000..5a0bd5442c --- /dev/null +++ b/src/library/scala/runtime/LazyRef.scala @@ -0,0 +1,157 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2016, LAMP/EPFL and Lightbend, Inc ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.runtime + +/** Classes used as holders for lazy vals defined in methods. */ + +class LazyRef[T] { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: T = _ + def value: T = _value + def initialize(value: T): T = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyRef ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyBoolean { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Boolean = _ + def value: Boolean = _value + def initialize(value: Boolean): Boolean = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyBoolean ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyByte { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Byte = _ + + def value: Byte = _value + + def initialize(value: Byte): Byte = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyByte ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyChar { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Char = _ + def value: Char = _value + def initialize(value: Char): Char = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyChar ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyShort { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Short = _ + def value: Short = _value + def initialize(value: Short): Short = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyShort ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyInt { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Int = _ + def value: Int = _value + def initialize(value: Int): Int = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyInt ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyLong { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Long = _ + def value: Long = _value + def initialize(value: Long): Long = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyLong ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyFloat { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Float = _ + def value: Float = _value + def initialize(value: Float): Float = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyFloat ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyDouble { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + private[this] var _value: Double = _ + def value: Double = _value + def initialize(value: Double): Double = { + _value = value + _initialized = true + value + } + + override def toString = s"LazyDouble ${if (_initialized) s"of: ${_value}" else "thunk"}" +} + +class LazyUnit { + @volatile private[this] var _initialized: Boolean = _ + def initialized = _initialized + + def initialize(): Unit = _initialized = true + + override def toString = s"LazyUnit${if (_initialized) "" else " thunk"}" +} diff --git a/src/library/scala/runtime/RichException.scala b/src/library/scala/runtime/RichException.scala index f01788a4e9..2863fb6d7c 100644 --- a/src/library/scala/runtime/RichException.scala +++ b/src/library/scala/runtime/RichException.scala @@ -11,7 +11,7 @@ package runtime import scala.compat.Platform.EOL -@deprecated("Use Throwable#getStackTrace", "2.11.0") +@deprecated("use Throwable#getStackTrace", "2.11.0") final class RichException(exc: Throwable) { def getStackTraceString = exc.getStackTrace().mkString("", EOL, EOL) } diff --git a/src/library/scala/runtime/RichInt.scala b/src/library/scala/runtime/RichInt.scala index cda9d2907a..37d236dfe9 100644 --- a/src/library/scala/runtime/RichInt.scala +++ b/src/library/scala/runtime/RichInt.scala @@ -36,9 +36,9 @@ final class RichInt(val self: Int) extends AnyVal with ScalaNumberProxy[Int] wit override def max(that: Int): Int = math.max(self, that) override def min(that: Int): Int = math.min(self, that) override def signum: Int = math.signum(self) - + /** There is no reason to round an `Int`, but this method is provided to avoid accidental loss of precision from a detour through `Float`. */ - @deprecated("This is an integer type; there is no reason to round it. Perhaps you meant to call this on a floating-point value?", "2.11.0") + @deprecated("this is an integer type; there is no reason to round it. Perhaps you meant to call this on a floating-point value?", "2.11.0") def round: Int = self def toBinaryString: String = java.lang.Integer.toBinaryString(self) diff --git a/src/library/scala/runtime/RichLong.scala b/src/library/scala/runtime/RichLong.scala index b405fcda3d..233ce231b4 100644 --- a/src/library/scala/runtime/RichLong.scala +++ b/src/library/scala/runtime/RichLong.scala @@ -32,9 +32,9 @@ final class RichLong(val self: Long) extends AnyVal with IntegralProxy[Long] { override def max(that: Long): Long = math.max(self, that) override def min(that: Long): Long = math.min(self, that) override def signum: Int = math.signum(self).toInt - + /** There is no reason to round a `Long`, but this method is provided to avoid accidental conversion to `Int` through `Float`. */ - @deprecated("This is an integer type; there is no reason to round it. Perhaps you meant to call this on a floating-point value?", "2.11.0") + @deprecated("this is an integer type; there is no reason to round it. Perhaps you meant to call this on a floating-point value?", "2.11.0") def round: Long = self def toBinaryString: String = java.lang.Long.toBinaryString(self) diff --git a/src/library/scala/runtime/ScalaNumberProxy.scala b/src/library/scala/runtime/ScalaNumberProxy.scala index 5e4da24c0d..9b4899aef6 100644 --- a/src/library/scala/runtime/ScalaNumberProxy.scala +++ b/src/library/scala/runtime/ScalaNumberProxy.scala @@ -9,8 +9,8 @@ package scala package runtime -import scala.collection.{ mutable, immutable } -import scala.math.{ ScalaNumericConversions, ScalaNumericAnyConversions } +import scala.collection.immutable +import scala.math.ScalaNumericAnyConversions import immutable.NumericRange import Proxy.Typed diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 026d5edd29..b31a94576a 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -9,16 +9,14 @@ package scala package runtime -import scala.collection.{ Seq, IndexedSeq, TraversableView, AbstractIterator, GenIterable } +import scala.collection.{ TraversableView, AbstractIterator, GenIterable } import scala.collection.mutable.WrappedArray -import scala.collection.immutable.{ StringLike, NumericRange, List, Stream, Nil, :: } +import scala.collection.immutable.{ StringLike, NumericRange } import scala.collection.generic.{ Sorted, IsTraversableLike } import scala.reflect.{ ClassTag, classTag } -import scala.util.control.ControlThrowable import java.lang.{ Class => jClass } -import java.lang.Double.doubleToLongBits -import java.lang.reflect.{ Modifier, Method => JMethod } +import java.lang.reflect.{ Method => JMethod } /** The object ScalaRunTime provides support methods required by * the scala runtime. All these methods should be considered @@ -31,15 +29,6 @@ object ScalaRunTime { private def isArrayClass(clazz: jClass[_], atLevel: Int): Boolean = clazz.isArray && (atLevel == 1 || isArrayClass(clazz.getComponentType, atLevel - 1)) - def isValueClass(clazz: jClass[_]) = clazz.isPrimitive() - - // includes specialized subclasses and future proofed against hypothetical TupleN (for N > 22) - def isTuple(x: Any) = x != null && x.getClass.getName.startsWith("scala.Tuple") - def isAnyVal(x: Any) = x match { - case _: Byte | _: Short | _: Char | _: Int | _: Long | _: Float | _: Double | _: Boolean | _: Unit => true - case _ => false - } - // A helper method to make my life in the pattern matcher a lot easier. def drop[Repr](coll: Repr, num: Int)(implicit traversable: IsTraversableLike[Repr]): Repr = traversable conversion coll drop num @@ -52,15 +41,6 @@ object ScalaRunTime { else java.lang.reflect.Array.newInstance(clazz, 0).getClass } - /** Return the class object representing elements in arrays described by a given schematic. - */ - def arrayElementClass(schematic: Any): jClass[_] = schematic match { - case cls: jClass[_] => cls.getComponentType - case tag: ClassTag[_] => tag.runtimeClass - case _ => - throw new UnsupportedOperationException(s"unsupported schematic $schematic (${schematic.getClass})") - } - /** Return the class object representing an unboxed value type, * e.g., classOf[int], not classOf[java.lang.Integer]. The compiler * rewrites expressions like 5.getClass to come here. @@ -118,15 +98,15 @@ object ScalaRunTime { } def array_clone(xs: AnyRef): AnyRef = xs match { - case x: Array[AnyRef] => ArrayRuntime.cloneArray(x) - case x: Array[Int] => ArrayRuntime.cloneArray(x) - case x: Array[Double] => ArrayRuntime.cloneArray(x) - case x: Array[Long] => ArrayRuntime.cloneArray(x) - case x: Array[Float] => ArrayRuntime.cloneArray(x) - case x: Array[Char] => ArrayRuntime.cloneArray(x) - case x: Array[Byte] => ArrayRuntime.cloneArray(x) - case x: Array[Short] => ArrayRuntime.cloneArray(x) - case x: Array[Boolean] => ArrayRuntime.cloneArray(x) + case x: Array[AnyRef] => x.clone() + case x: Array[Int] => x.clone() + case x: Array[Double] => x.clone() + case x: Array[Long] => x.clone() + case x: Array[Float] => x.clone() + case x: Array[Char] => x.clone() + case x: Array[Byte] => x.clone() + case x: Array[Short] => x.clone() + case x: Array[Boolean] => x.clone() case x: Array[Unit] => x case null => throw new NullPointerException } @@ -159,9 +139,6 @@ object ScalaRunTime { // More background at ticket #2318. def ensureAccessible(m: JMethod): JMethod = scala.reflect.ensureAccessible(m) - def checkInitialized[T <: AnyRef](x: T): T = - if (x == null) throw new UninitializedError else x - def _toString(x: Product): String = x.productIterator.mkString(x.productPrefix + "(", ",", ")") @@ -181,71 +158,9 @@ object ScalaRunTime { } } - /** Fast path equality method for inlining; used when -optimise is set. - */ - @inline def inlinedEquals(x: Object, y: Object): Boolean = - if (x eq y) true - else if (x eq null) false - else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.equalsNumObject(x.asInstanceOf[java.lang.Number], y) - else if (x.isInstanceOf[java.lang.Character]) BoxesRunTime.equalsCharObject(x.asInstanceOf[java.lang.Character], y) - else x.equals(y) - - def _equals(x: Product, y: Any): Boolean = y match { - case y: Product if x.productArity == y.productArity => x.productIterator sameElements y.productIterator - case _ => false - } - - // hashcode ----------------------------------------------------------- - // - // Note that these are the implementations called by ##, so they - // must not call ## themselves. - - def hash(x: Any): Int = - if (x == null) 0 - else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.hashFromNumber(x.asInstanceOf[java.lang.Number]) - else x.hashCode - - def hash(dv: Double): Int = { - val iv = dv.toInt - if (iv == dv) return iv - - val lv = dv.toLong - if (lv == dv) return lv.hashCode - - val fv = dv.toFloat - if (fv == dv) fv.hashCode else dv.hashCode - } - def hash(fv: Float): Int = { - val iv = fv.toInt - if (iv == fv) return iv - - val lv = fv.toLong - if (lv == fv) hash(lv) - else fv.hashCode - } - def hash(lv: Long): Int = { - val low = lv.toInt - val lowSign = low >>> 31 - val high = (lv >>> 32).toInt - low ^ (high + lowSign) - } - def hash(x: Number): Int = runtime.BoxesRunTime.hashFromNumber(x) - - // The remaining overloads are here for completeness, but the compiler - // inlines these definitions directly so they're not generally used. - def hash(x: Int): Int = x - def hash(x: Short): Int = x.toInt - def hash(x: Byte): Int = x.toInt - def hash(x: Char): Int = x.toInt - def hash(x: Boolean): Int = if (x) true.hashCode else false.hashCode - def hash(x: Unit): Int = 0 - - /** A helper method for constructing case class equality methods, - * because existential types get in the way of a clean outcome and - * it's performing a series of Any/Any equals comparisons anyway. - * See ticket #2867 for specifics. - */ - def sameElements(xs1: scala.collection.Seq[Any], xs2: scala.collection.Seq[Any]) = xs1 sameElements xs2 + /** Old implementation of `##`. */ + @deprecated("Use scala.runtime.Statics.anyHash instead.", "2.12.0") + def hash(x: Any): Int = Statics.anyHash(x.asInstanceOf[Object]) /** Given any Scala value, convert it to a String. * @@ -268,6 +183,9 @@ object ScalaRunTime { def isScalaClass(x: AnyRef) = packageOf(x) startsWith "scala." def isScalaCompilerClass(x: AnyRef) = packageOf(x) startsWith "scala.tools.nsc." + // includes specialized subclasses and future proofed against hypothetical TupleN (for N > 22) + def isTuple(x: Any) = x != null && x.getClass.getName.startsWith("scala.Tuple") + // We use reflection because the scala.xml package might not be available def isSubClassOf(potentialSubClass: Class[_], ofClass: String) = try { @@ -347,17 +265,4 @@ object ScalaRunTime { nl + s + "\n" } - - def box[T](clazz: jClass[T]): jClass[_] = clazz match { - case java.lang.Byte.TYPE => classOf[java.lang.Byte] - case java.lang.Short.TYPE => classOf[java.lang.Short] - case java.lang.Character.TYPE => classOf[java.lang.Character] - case java.lang.Integer.TYPE => classOf[java.lang.Integer] - case java.lang.Long.TYPE => classOf[java.lang.Long] - case java.lang.Float.TYPE => classOf[java.lang.Float] - case java.lang.Double.TYPE => classOf[java.lang.Double] - case java.lang.Void.TYPE => classOf[scala.runtime.BoxedUnit] - case java.lang.Boolean.TYPE => classOf[java.lang.Boolean] - case _ => clazz - } } diff --git a/src/library/scala/runtime/SeqCharSequence.scala b/src/library/scala/runtime/SeqCharSequence.scala index 74e67bb9e7..7751bf815c 100644 --- a/src/library/scala/runtime/SeqCharSequence.scala +++ b/src/library/scala/runtime/SeqCharSequence.scala @@ -9,9 +9,7 @@ package scala package runtime -import java.util.Arrays.copyOfRange - -@deprecated("Use Predef.SeqCharSequence", "2.11.0") +@deprecated("use Predef.SeqCharSequence", "2.11.0") final class SeqCharSequence(val xs: scala.collection.IndexedSeq[Char]) extends CharSequence { def length: Int = xs.length def charAt(index: Int): Char = xs(index) diff --git a/src/library/scala/runtime/Statics.java b/src/library/scala/runtime/Statics.java index 485511ecbb..62390cb9d0 100644 --- a/src/library/scala/runtime/Statics.java +++ b/src/library/scala/runtime/Statics.java @@ -36,10 +36,11 @@ public final class Statics { } public static int longHash(long lv) { - if ((int)lv == lv) - return (int)lv; - else - return (int)(lv ^ (lv >>> 32)); + int iv = (int)lv; + if (iv == lv) + return iv; + + return java.lang.Long.hashCode(lv); } public static int doubleHash(double dv) { @@ -47,16 +48,15 @@ public final class Statics { if (iv == dv) return iv; - float fv = (float)dv; - if (fv == dv) - return java.lang.Float.floatToIntBits(fv); - long lv = (long)dv; if (lv == dv) - return (int)lv; + return java.lang.Long.hashCode(lv); + + float fv = (float)dv; + if (fv == dv) + return java.lang.Float.hashCode(fv); - lv = Double.doubleToLongBits(dv); - return (int)(lv ^ (lv >>> 32)); + return java.lang.Double.hashCode(dv); } public static int floatHash(float fv) { @@ -66,11 +66,39 @@ public final class Statics { long lv = (long)fv; if (lv == fv) - return (int)(lv^(lv>>>32)); + return java.lang.Long.hashCode(lv); - return java.lang.Float.floatToIntBits(fv); + return java.lang.Float.hashCode(fv); } + /** + * Hashcode algorithm is driven by the requirements imposed + * by primitive equality semantics, namely that equal objects + * have equal hashCodes. The first priority are the integral/char + * types, which already have the same hashCodes for the same + * values except for Long. So Long's hashCode is altered to + * conform to Int's for all values in Int's range. + * + * Float is problematic because it's far too small to hold + * all the Ints, so for instance Int.MaxValue.toFloat claims + * to be == to each of the largest 64 Ints. There is no way + * to preserve equals/hashCode alignment without compromising + * the hashCode distribution, so Floats are only guaranteed + * to have the same hashCode for whole Floats in the range + * Short.MinValue to Short.MaxValue (2^16 total.) + * + * Double has its hashCode altered to match the entire Int range, + * but is not guaranteed beyond that. (But could/should it be? + * The hashCode is only 32 bits so this is a more tractable + * issue than Float's, but it might be better simply to exclude it.) + * + * Note: BigInt and BigDecimal, being arbitrary precision, could + * be made consistent with all other types for the Int range, but + * as yet have not. + * + * Note: Among primitives, Float.NaN != Float.NaN, but the boxed + * versions are equal. This still needs reconciliation. + */ public static int anyHash(Object x) { if (x == null) return 0; diff --git a/src/library/scala/runtime/StringAdd.scala b/src/library/scala/runtime/StringAdd.scala index d5b51a6e92..37f077bcad 100644 --- a/src/library/scala/runtime/StringAdd.scala +++ b/src/library/scala/runtime/StringAdd.scala @@ -11,7 +11,7 @@ package runtime /** A wrapper class that adds string concatenation `+` to any value */ -@deprecated("Use Predef.StringAdd", "2.11.0") +@deprecated("use Predef.StringAdd", "2.11.0") final class StringAdd(val self: Any) extends AnyVal { def +(other: String) = String.valueOf(self) + other } diff --git a/src/library/scala/runtime/StringFormat.scala b/src/library/scala/runtime/StringFormat.scala index de32ac7e86..5376c3f982 100644 --- a/src/library/scala/runtime/StringFormat.scala +++ b/src/library/scala/runtime/StringFormat.scala @@ -12,7 +12,7 @@ package runtime /** A wrapper class that adds a `formatted` operation to any value */ -@deprecated("Use Predef.StringFormat", "2.11.0") +@deprecated("use Predef.StringFormat", "2.11.0") final class StringFormat(val self: Any) extends AnyVal { /** Returns string formatted according to given `format` string. * Format strings are as for `String.format` diff --git a/src/library/scala/runtime/StructuralCallSite.java b/src/library/scala/runtime/StructuralCallSite.java new file mode 100644 index 0000000000..f73b4f08e6 --- /dev/null +++ b/src/library/scala/runtime/StructuralCallSite.java @@ -0,0 +1,43 @@ +package scala.runtime; + + +import java.lang.invoke.*; +import java.lang.ref.SoftReference; +import java.lang.reflect.Method; + +public final class StructuralCallSite { + + private Class<?>[] parameterTypes; + private SoftReference<MethodCache> cache = new SoftReference<>(new EmptyMethodCache()); + + private StructuralCallSite(MethodType callType) { + parameterTypes = callType.parameterArray(); + } + + public MethodCache get() { + MethodCache cache = this.cache.get(); + if (cache == null) { + cache = new EmptyMethodCache(); + this.cache = new SoftReference<>(cache); + } + return cache; + } + + public Method find(Class<?> receiver) { + return get().find(receiver); + } + + public Method add(Class<?> receiver, Method m) { + cache = new SoftReference<MethodCache>(get().add(receiver, m)); + return m; + } + public Class<?>[] parameterTypes() { + return parameterTypes; + } + + public static CallSite bootstrap(MethodHandles.Lookup lookup, String invokedName, + MethodType invokedType, MethodType reflectiveCallType) throws Throwable { + StructuralCallSite structuralCallSite = new StructuralCallSite(reflectiveCallType); + return new ConstantCallSite(MethodHandles.constant(StructuralCallSite.class, structuralCallSite)); + } +} diff --git a/src/library/scala/runtime/SymbolLiteral.java b/src/library/scala/runtime/SymbolLiteral.java new file mode 100644 index 0000000000..09a66c83d5 --- /dev/null +++ b/src/library/scala/runtime/SymbolLiteral.java @@ -0,0 +1,20 @@ +package scala.runtime; + +import java.lang.invoke.*; +import java.util.regex.Pattern; + +public final class SymbolLiteral { + private SymbolLiteral() { + } + + public static CallSite bootstrap(MethodHandles.Lookup lookup, String invokedName, + MethodType invokedType, + String value) throws Throwable { + ClassLoader classLoader = lookup.lookupClass().getClassLoader(); + MethodType type = MethodType.fromMethodDescriptorString("(Ljava/lang/Object;)Ljava/lang/Object;", classLoader); + Class<?> symbolClass = Class.forName("scala.Symbol", false, classLoader); + MethodHandle factoryMethod = lookup.findStatic(symbolClass, "apply", type); + Object symbolValue = factoryMethod.invokeWithArguments(value); + return new ConstantCallSite(MethodHandles.constant(symbolClass, symbolValue)); + } +} diff --git a/src/library/scala/runtime/TraitSetter.java b/src/library/scala/runtime/TraitSetter.java index d9907c0ac0..d8dd8c6b04 100644 --- a/src/library/scala/runtime/TraitSetter.java +++ b/src/library/scala/runtime/TraitSetter.java @@ -2,5 +2,6 @@ package scala.runtime; /** A marker annotation to tag a setter of a mutable variable in a trait */ +@Deprecated public @interface TraitSetter { }
\ No newline at end of file diff --git a/src/library/scala/runtime/Tuple2Zipped.scala b/src/library/scala/runtime/Tuple2Zipped.scala index 4109f5cb4b..52dd1da09e 100644 --- a/src/library/scala/runtime/Tuple2Zipped.scala +++ b/src/library/scala/runtime/Tuple2Zipped.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2002-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -34,14 +34,15 @@ object ZippedTraversable2 { } final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1, Repr1], IterableLike[El2, Repr2])) extends AnyVal with ZippedTraversable2[El1, El2] { - // This would be better as "private def coll1 = colls._1" but - // SI-6215 precludes private methods in value classes. + private def coll1 = colls._1 + private def coll2 = colls._2 + def map[B, To](f: (El1, El2) => B)(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(colls._1.repr) - b.sizeHint(colls._1) - val elems2 = colls._2.iterator + val b = cbf(coll1.repr) + b.sizeHint(coll1) + val elems2 = coll2.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext) b += f(el1, elems2.next()) else @@ -52,10 +53,10 @@ final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1 } def flatMap[B, To](f: (El1, El2) => TraversableOnce[B])(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(colls._1.repr) - val elems2 = colls._2.iterator + val b = cbf(coll1.repr) + val elems2 = coll2.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext) b ++= f(el1, elems2.next()) else @@ -66,11 +67,11 @@ final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1 } def filter[To1, To2](f: (El1, El2) => Boolean)(implicit cbf1: CBF[Repr1, El1, To1], cbf2: CBF[Repr2, El2, To2]): (To1, To2) = { - val b1 = cbf1(colls._1.repr) - val b2 = cbf2(colls._2.repr) - val elems2 = colls._2.iterator + val b1 = cbf1(coll1.repr) + val b2 = cbf2(coll2.repr) + val elems2 = coll2.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext) { val el2 = elems2.next() if (f(el1, el2)) { @@ -85,9 +86,9 @@ final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1 } def exists(@deprecatedName('f) p: (El1, El2) => Boolean): Boolean = { - val elems2 = colls._2.iterator + val elems2 = coll2.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext) { if (p(el1, elems2.next())) return true @@ -101,19 +102,21 @@ final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1 !exists((x, y) => !p(x, y)) def foreach[U](f: (El1, El2) => U): Unit = { - val elems2 = colls._2.iterator + val elems2 = coll2.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext) f(el1, elems2.next()) else return } } + + override def toString = s"($coll1, $coll2).zipped" } object Tuple2Zipped { - final class Ops[T1, T2](val x: (T1, T2)) extends AnyVal { + final class Ops[T1, T2](private val x: (T1, T2)) extends AnyVal { def invert[El1, CC1[X] <: TraversableOnce[X], El2, CC2[X] <: TraversableOnce[X], That] (implicit w1: T1 <:< CC1[El1], w2: T2 <:< CC2[El2], diff --git a/src/library/scala/runtime/Tuple3Zipped.scala b/src/library/scala/runtime/Tuple3Zipped.scala index cde7699d40..a4a86f8e55 100644 --- a/src/library/scala/runtime/Tuple3Zipped.scala +++ b/src/library/scala/runtime/Tuple3Zipped.scala @@ -34,12 +34,16 @@ object ZippedTraversable3 { final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (TraversableLike[El1, Repr1], IterableLike[El2, Repr2], IterableLike[El3, Repr3])) extends AnyVal with ZippedTraversable3[El1, El2, El3] { + private def coll1 = colls._1 + private def coll2 = colls._2 + private def coll3 = colls._3 + def map[B, To](f: (El1, El2, El3) => B)(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(colls._1.repr) - val elems2 = colls._2.iterator - val elems3 = colls._3.iterator + val b = cbf(coll1.repr) + val elems2 = coll2.iterator + val elems3 = coll3.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext && elems3.hasNext) b += f(el1, elems2.next(), elems3.next()) else @@ -49,11 +53,11 @@ final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (Travers } def flatMap[B, To](f: (El1, El2, El3) => TraversableOnce[B])(implicit cbf: CBF[Repr1, B, To]): To = { - val b = cbf(colls._1.repr) - val elems2 = colls._2.iterator - val elems3 = colls._3.iterator + val b = cbf(coll1.repr) + val elems2 = coll2.iterator + val elems3 = coll3.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext && elems3.hasNext) b ++= f(el1, elems2.next(), elems3.next()) else @@ -66,14 +70,14 @@ final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (Travers implicit cbf1: CBF[Repr1, El1, To1], cbf2: CBF[Repr2, El2, To2], cbf3: CBF[Repr3, El3, To3]): (To1, To2, To3) = { - val b1 = cbf1(colls._1.repr) - val b2 = cbf2(colls._2.repr) - val b3 = cbf3(colls._3.repr) - val elems2 = colls._2.iterator - val elems3 = colls._3.iterator + val b1 = cbf1(coll1.repr) + val b2 = cbf2(coll2.repr) + val b3 = cbf3(coll3.repr) + val elems2 = coll2.iterator + val elems3 = coll3.iterator def result = (b1.result(), b2.result(), b3.result()) - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext && elems3.hasNext) { val el2 = elems2.next() val el3 = elems3.next() @@ -91,10 +95,10 @@ final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (Travers } def exists(@deprecatedName('f) p: (El1, El2, El3) => Boolean): Boolean = { - val elems2 = colls._2.iterator - val elems3 = colls._3.iterator + val elems2 = coll2.iterator + val elems3 = coll3.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext && elems3.hasNext) { if (p(el1, elems2.next(), elems3.next())) return true @@ -108,20 +112,22 @@ final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (Travers !exists((x, y, z) => !p(x, y, z)) def foreach[U](f: (El1, El2, El3) => U): Unit = { - val elems2 = colls._2.iterator - val elems3 = colls._3.iterator + val elems2 = coll2.iterator + val elems3 = coll3.iterator - for (el1 <- colls._1) { + for (el1 <- coll1) { if (elems2.hasNext && elems3.hasNext) f(el1, elems2.next(), elems3.next()) else return } } + + override def toString = s"($coll1, $coll2, $coll3).zipped" } object Tuple3Zipped { - final class Ops[T1, T2, T3](val x: (T1, T2, T3)) extends AnyVal { + final class Ops[T1, T2, T3](private val x: (T1, T2, T3)) extends AnyVal { def invert[El1, CC1[X] <: TraversableOnce[X], El2, CC2[X] <: TraversableOnce[X], El3, CC3[X] <: TraversableOnce[X], That] (implicit w1: T1 <:< CC1[El1], w2: T2 <:< CC2[El2], diff --git a/src/library/scala/runtime/java8/JFunction0$mcB$sp.java b/src/library/scala/runtime/java8/JFunction0$mcB$sp.java new file mode 100644 index 0000000000..622dbabcf1 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcB$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcB$sp extends scala.Function0, java.io.Serializable { + byte apply$mcB$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToByte(apply$mcB$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcC$sp.java b/src/library/scala/runtime/java8/JFunction0$mcC$sp.java new file mode 100644 index 0000000000..ad9a14ffa8 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcC$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcC$sp extends scala.Function0, java.io.Serializable { + char apply$mcC$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToCharacter(apply$mcC$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcD$sp.java b/src/library/scala/runtime/java8/JFunction0$mcD$sp.java new file mode 100644 index 0000000000..291b50db4b --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcD$sp extends scala.Function0, java.io.Serializable { + double apply$mcD$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcD$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcF$sp.java b/src/library/scala/runtime/java8/JFunction0$mcF$sp.java new file mode 100644 index 0000000000..73b31dea0f --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcF$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcF$sp extends scala.Function0, java.io.Serializable { + float apply$mcF$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcF$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcI$sp.java b/src/library/scala/runtime/java8/JFunction0$mcI$sp.java new file mode 100644 index 0000000000..f9b2d659ad --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcI$sp extends scala.Function0, java.io.Serializable { + int apply$mcI$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcI$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcJ$sp.java b/src/library/scala/runtime/java8/JFunction0$mcJ$sp.java new file mode 100644 index 0000000000..73c41976b7 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcJ$sp extends scala.Function0, java.io.Serializable { + long apply$mcJ$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJ$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcS$sp.java b/src/library/scala/runtime/java8/JFunction0$mcS$sp.java new file mode 100644 index 0000000000..5fbabb2358 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcS$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcS$sp extends scala.Function0, java.io.Serializable { + short apply$mcS$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToShort(apply$mcS$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcV$sp.java b/src/library/scala/runtime/java8/JFunction0$mcV$sp.java new file mode 100644 index 0000000000..735843796c --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcV$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcV$sp extends scala.Function0, java.io.Serializable { + void apply$mcV$sp(); + + default Object apply() { apply$mcV$sp(); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction0$mcZ$sp.java b/src/library/scala/runtime/java8/JFunction0$mcZ$sp.java new file mode 100644 index 0000000000..01234c1728 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction0$mcZ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction0$mcZ$sp extends scala.Function0, java.io.Serializable { + boolean apply$mcZ$sp(); + + default Object apply() { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZ$sp()); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcDD$sp.java b/src/library/scala/runtime/java8/JFunction1$mcDD$sp.java new file mode 100644 index 0000000000..07b85eed59 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcDD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcDD$sp extends scala.Function1, java.io.Serializable { + double apply$mcDD$sp(double v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDD$sp(scala.runtime.BoxesRunTime.unboxToDouble(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcDF$sp.java b/src/library/scala/runtime/java8/JFunction1$mcDF$sp.java new file mode 100644 index 0000000000..f09edd2ce2 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcDF$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcDF$sp extends scala.Function1, java.io.Serializable { + double apply$mcDF$sp(float v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDF$sp(scala.runtime.BoxesRunTime.unboxToFloat(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcDI$sp.java b/src/library/scala/runtime/java8/JFunction1$mcDI$sp.java new file mode 100644 index 0000000000..3cf40cb749 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcDI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcDI$sp extends scala.Function1, java.io.Serializable { + double apply$mcDI$sp(int v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDI$sp(scala.runtime.BoxesRunTime.unboxToInt(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcDJ$sp.java b/src/library/scala/runtime/java8/JFunction1$mcDJ$sp.java new file mode 100644 index 0000000000..4023f30bc0 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcDJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcDJ$sp extends scala.Function1, java.io.Serializable { + double apply$mcDJ$sp(long v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDJ$sp(scala.runtime.BoxesRunTime.unboxToLong(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcFD$sp.java b/src/library/scala/runtime/java8/JFunction1$mcFD$sp.java new file mode 100644 index 0000000000..d460895838 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcFD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcFD$sp extends scala.Function1, java.io.Serializable { + float apply$mcFD$sp(double v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFD$sp(scala.runtime.BoxesRunTime.unboxToDouble(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcFF$sp.java b/src/library/scala/runtime/java8/JFunction1$mcFF$sp.java new file mode 100644 index 0000000000..6c591800ca --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcFF$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcFF$sp extends scala.Function1, java.io.Serializable { + float apply$mcFF$sp(float v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFF$sp(scala.runtime.BoxesRunTime.unboxToFloat(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcFI$sp.java b/src/library/scala/runtime/java8/JFunction1$mcFI$sp.java new file mode 100644 index 0000000000..6669195914 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcFI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcFI$sp extends scala.Function1, java.io.Serializable { + float apply$mcFI$sp(int v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFI$sp(scala.runtime.BoxesRunTime.unboxToInt(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcFJ$sp.java b/src/library/scala/runtime/java8/JFunction1$mcFJ$sp.java new file mode 100644 index 0000000000..cd953677ae --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcFJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcFJ$sp extends scala.Function1, java.io.Serializable { + float apply$mcFJ$sp(long v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFJ$sp(scala.runtime.BoxesRunTime.unboxToLong(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcID$sp.java b/src/library/scala/runtime/java8/JFunction1$mcID$sp.java new file mode 100644 index 0000000000..37f6864936 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcID$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcID$sp extends scala.Function1, java.io.Serializable { + int apply$mcID$sp(double v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcID$sp(scala.runtime.BoxesRunTime.unboxToDouble(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcIF$sp.java b/src/library/scala/runtime/java8/JFunction1$mcIF$sp.java new file mode 100644 index 0000000000..8a7656a286 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcIF$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcIF$sp extends scala.Function1, java.io.Serializable { + int apply$mcIF$sp(float v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIF$sp(scala.runtime.BoxesRunTime.unboxToFloat(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcII$sp.java b/src/library/scala/runtime/java8/JFunction1$mcII$sp.java new file mode 100644 index 0000000000..792627b400 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcII$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcII$sp extends scala.Function1, java.io.Serializable { + int apply$mcII$sp(int v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcII$sp(scala.runtime.BoxesRunTime.unboxToInt(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcIJ$sp.java b/src/library/scala/runtime/java8/JFunction1$mcIJ$sp.java new file mode 100644 index 0000000000..01c47a67da --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcIJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcIJ$sp extends scala.Function1, java.io.Serializable { + int apply$mcIJ$sp(long v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIJ$sp(scala.runtime.BoxesRunTime.unboxToLong(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcJD$sp.java b/src/library/scala/runtime/java8/JFunction1$mcJD$sp.java new file mode 100644 index 0000000000..d8d5274ca1 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcJD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcJD$sp extends scala.Function1, java.io.Serializable { + long apply$mcJD$sp(double v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJD$sp(scala.runtime.BoxesRunTime.unboxToDouble(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcJF$sp.java b/src/library/scala/runtime/java8/JFunction1$mcJF$sp.java new file mode 100644 index 0000000000..cc1fad36d0 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcJF$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcJF$sp extends scala.Function1, java.io.Serializable { + long apply$mcJF$sp(float v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJF$sp(scala.runtime.BoxesRunTime.unboxToFloat(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcJI$sp.java b/src/library/scala/runtime/java8/JFunction1$mcJI$sp.java new file mode 100644 index 0000000000..fe941dd61a --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcJI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcJI$sp extends scala.Function1, java.io.Serializable { + long apply$mcJI$sp(int v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJI$sp(scala.runtime.BoxesRunTime.unboxToInt(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcJJ$sp.java b/src/library/scala/runtime/java8/JFunction1$mcJJ$sp.java new file mode 100644 index 0000000000..7034115bad --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcJJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcJJ$sp extends scala.Function1, java.io.Serializable { + long apply$mcJJ$sp(long v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJJ$sp(scala.runtime.BoxesRunTime.unboxToLong(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcVD$sp.java b/src/library/scala/runtime/java8/JFunction1$mcVD$sp.java new file mode 100644 index 0000000000..dde9f55722 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcVD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcVD$sp extends scala.Function1, java.io.Serializable { + void apply$mcVD$sp(double v1); + + default Object apply(Object t) { apply$mcVD$sp(scala.runtime.BoxesRunTime.unboxToDouble(t)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcVF$sp.java b/src/library/scala/runtime/java8/JFunction1$mcVF$sp.java new file mode 100644 index 0000000000..0ffd80621f --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcVF$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcVF$sp extends scala.Function1, java.io.Serializable { + void apply$mcVF$sp(float v1); + + default Object apply(Object t) { apply$mcVF$sp(scala.runtime.BoxesRunTime.unboxToFloat(t)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcVI$sp.java b/src/library/scala/runtime/java8/JFunction1$mcVI$sp.java new file mode 100644 index 0000000000..2543d23e31 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcVI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcVI$sp extends scala.Function1, java.io.Serializable { + void apply$mcVI$sp(int v1); + + default Object apply(Object t) { apply$mcVI$sp(scala.runtime.BoxesRunTime.unboxToInt(t)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcVJ$sp.java b/src/library/scala/runtime/java8/JFunction1$mcVJ$sp.java new file mode 100644 index 0000000000..7564175402 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcVJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcVJ$sp extends scala.Function1, java.io.Serializable { + void apply$mcVJ$sp(long v1); + + default Object apply(Object t) { apply$mcVJ$sp(scala.runtime.BoxesRunTime.unboxToLong(t)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcZD$sp.java b/src/library/scala/runtime/java8/JFunction1$mcZD$sp.java new file mode 100644 index 0000000000..ce5bd30029 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcZD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcZD$sp extends scala.Function1, java.io.Serializable { + boolean apply$mcZD$sp(double v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZD$sp(scala.runtime.BoxesRunTime.unboxToDouble(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcZF$sp.java b/src/library/scala/runtime/java8/JFunction1$mcZF$sp.java new file mode 100644 index 0000000000..baa691e548 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcZF$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcZF$sp extends scala.Function1, java.io.Serializable { + boolean apply$mcZF$sp(float v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZF$sp(scala.runtime.BoxesRunTime.unboxToFloat(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcZI$sp.java b/src/library/scala/runtime/java8/JFunction1$mcZI$sp.java new file mode 100644 index 0000000000..bf04b5922b --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcZI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcZI$sp extends scala.Function1, java.io.Serializable { + boolean apply$mcZI$sp(int v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZI$sp(scala.runtime.BoxesRunTime.unboxToInt(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction1$mcZJ$sp.java b/src/library/scala/runtime/java8/JFunction1$mcZJ$sp.java new file mode 100644 index 0000000000..808eea87b8 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction1$mcZJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction1$mcZJ$sp extends scala.Function1, java.io.Serializable { + boolean apply$mcZJ$sp(long v1); + + default Object apply(Object t) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZJ$sp(scala.runtime.BoxesRunTime.unboxToLong(t))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDDD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDDD$sp.java new file mode 100644 index 0000000000..80ab5203d9 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDDD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDDD$sp extends scala.Function2, java.io.Serializable { + double apply$mcDDD$sp(double v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDDD$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDDI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDDI$sp.java new file mode 100644 index 0000000000..8e92338b82 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDDI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDDI$sp extends scala.Function2, java.io.Serializable { + double apply$mcDDI$sp(double v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDDI$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDDJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDDJ$sp.java new file mode 100644 index 0000000000..3d4f4a7cde --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDDJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDDJ$sp extends scala.Function2, java.io.Serializable { + double apply$mcDDJ$sp(double v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDDJ$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDID$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDID$sp.java new file mode 100644 index 0000000000..bd6652e51a --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDID$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDID$sp extends scala.Function2, java.io.Serializable { + double apply$mcDID$sp(int v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDID$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDII$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDII$sp.java new file mode 100644 index 0000000000..d06a246d33 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDII$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDII$sp extends scala.Function2, java.io.Serializable { + double apply$mcDII$sp(int v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDII$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDIJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDIJ$sp.java new file mode 100644 index 0000000000..cda23c4dcd --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDIJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDIJ$sp extends scala.Function2, java.io.Serializable { + double apply$mcDIJ$sp(int v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDIJ$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDJD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDJD$sp.java new file mode 100644 index 0000000000..723efd8451 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDJD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDJD$sp extends scala.Function2, java.io.Serializable { + double apply$mcDJD$sp(long v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDJD$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDJI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDJI$sp.java new file mode 100644 index 0000000000..c90352ef30 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDJI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDJI$sp extends scala.Function2, java.io.Serializable { + double apply$mcDJI$sp(long v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDJI$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcDJJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcDJJ$sp.java new file mode 100644 index 0000000000..3361219787 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcDJJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcDJJ$sp extends scala.Function2, java.io.Serializable { + double apply$mcDJJ$sp(long v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToDouble(apply$mcDJJ$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFDD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFDD$sp.java new file mode 100644 index 0000000000..2b9236b5d1 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFDD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFDD$sp extends scala.Function2, java.io.Serializable { + float apply$mcFDD$sp(double v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFDD$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFDI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFDI$sp.java new file mode 100644 index 0000000000..2c564962a7 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFDI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFDI$sp extends scala.Function2, java.io.Serializable { + float apply$mcFDI$sp(double v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFDI$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFDJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFDJ$sp.java new file mode 100644 index 0000000000..a0785f4cd2 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFDJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFDJ$sp extends scala.Function2, java.io.Serializable { + float apply$mcFDJ$sp(double v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFDJ$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFID$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFID$sp.java new file mode 100644 index 0000000000..ba67ddb593 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFID$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFID$sp extends scala.Function2, java.io.Serializable { + float apply$mcFID$sp(int v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFID$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFII$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFII$sp.java new file mode 100644 index 0000000000..d58284b752 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFII$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFII$sp extends scala.Function2, java.io.Serializable { + float apply$mcFII$sp(int v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFII$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFIJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFIJ$sp.java new file mode 100644 index 0000000000..4bc6eeb908 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFIJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFIJ$sp extends scala.Function2, java.io.Serializable { + float apply$mcFIJ$sp(int v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFIJ$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFJD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFJD$sp.java new file mode 100644 index 0000000000..f2435e23f7 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFJD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFJD$sp extends scala.Function2, java.io.Serializable { + float apply$mcFJD$sp(long v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFJD$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFJI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFJI$sp.java new file mode 100644 index 0000000000..1362d00e94 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFJI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFJI$sp extends scala.Function2, java.io.Serializable { + float apply$mcFJI$sp(long v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFJI$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcFJJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcFJJ$sp.java new file mode 100644 index 0000000000..c9bcf515b7 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcFJJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcFJJ$sp extends scala.Function2, java.io.Serializable { + float apply$mcFJJ$sp(long v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToFloat(apply$mcFJJ$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIDD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIDD$sp.java new file mode 100644 index 0000000000..28693910a5 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIDD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIDD$sp extends scala.Function2, java.io.Serializable { + int apply$mcIDD$sp(double v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIDD$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIDI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIDI$sp.java new file mode 100644 index 0000000000..50c775fbd9 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIDI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIDI$sp extends scala.Function2, java.io.Serializable { + int apply$mcIDI$sp(double v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIDI$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIDJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIDJ$sp.java new file mode 100644 index 0000000000..3231aa7a88 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIDJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIDJ$sp extends scala.Function2, java.io.Serializable { + int apply$mcIDJ$sp(double v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIDJ$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIID$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIID$sp.java new file mode 100644 index 0000000000..01568b2fd6 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIID$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIID$sp extends scala.Function2, java.io.Serializable { + int apply$mcIID$sp(int v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIID$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIII$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIII$sp.java new file mode 100644 index 0000000000..e0fba76675 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIII$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIII$sp extends scala.Function2, java.io.Serializable { + int apply$mcIII$sp(int v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIII$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIIJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIIJ$sp.java new file mode 100644 index 0000000000..7155548e9f --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIIJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIIJ$sp extends scala.Function2, java.io.Serializable { + int apply$mcIIJ$sp(int v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIIJ$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIJD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIJD$sp.java new file mode 100644 index 0000000000..f541cfdef4 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIJD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIJD$sp extends scala.Function2, java.io.Serializable { + int apply$mcIJD$sp(long v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIJD$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIJI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIJI$sp.java new file mode 100644 index 0000000000..e484efe427 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIJI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIJI$sp extends scala.Function2, java.io.Serializable { + int apply$mcIJI$sp(long v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIJI$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcIJJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcIJJ$sp.java new file mode 100644 index 0000000000..ec3538779c --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcIJJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcIJJ$sp extends scala.Function2, java.io.Serializable { + int apply$mcIJJ$sp(long v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToInteger(apply$mcIJJ$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJDD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJDD$sp.java new file mode 100644 index 0000000000..b13502de5b --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJDD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJDD$sp extends scala.Function2, java.io.Serializable { + long apply$mcJDD$sp(double v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJDD$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJDI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJDI$sp.java new file mode 100644 index 0000000000..9ec9adda60 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJDI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJDI$sp extends scala.Function2, java.io.Serializable { + long apply$mcJDI$sp(double v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJDI$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJDJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJDJ$sp.java new file mode 100644 index 0000000000..68ef9ead14 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJDJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJDJ$sp extends scala.Function2, java.io.Serializable { + long apply$mcJDJ$sp(double v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJDJ$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJID$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJID$sp.java new file mode 100644 index 0000000000..29c9c5e3d3 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJID$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJID$sp extends scala.Function2, java.io.Serializable { + long apply$mcJID$sp(int v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJID$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJII$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJII$sp.java new file mode 100644 index 0000000000..bb23086125 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJII$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJII$sp extends scala.Function2, java.io.Serializable { + long apply$mcJII$sp(int v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJII$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJIJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJIJ$sp.java new file mode 100644 index 0000000000..649fe24325 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJIJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJIJ$sp extends scala.Function2, java.io.Serializable { + long apply$mcJIJ$sp(int v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJIJ$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJJD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJJD$sp.java new file mode 100644 index 0000000000..8e6071d448 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJJD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJJD$sp extends scala.Function2, java.io.Serializable { + long apply$mcJJD$sp(long v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJJD$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJJI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJJI$sp.java new file mode 100644 index 0000000000..61366ac26d --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJJI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJJI$sp extends scala.Function2, java.io.Serializable { + long apply$mcJJI$sp(long v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJJI$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcJJJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcJJJ$sp.java new file mode 100644 index 0000000000..a44e97318e --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcJJJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcJJJ$sp extends scala.Function2, java.io.Serializable { + long apply$mcJJJ$sp(long v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToLong(apply$mcJJJ$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVDD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVDD$sp.java new file mode 100644 index 0000000000..8e7cbd7d1b --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVDD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVDD$sp extends scala.Function2, java.io.Serializable { + void apply$mcVDD$sp(double v1, double v2); + + default Object apply(Object v1, Object v2) { apply$mcVDD$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVDI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVDI$sp.java new file mode 100644 index 0000000000..1dee353d6b --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVDI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVDI$sp extends scala.Function2, java.io.Serializable { + void apply$mcVDI$sp(double v1, int v2); + + default Object apply(Object v1, Object v2) { apply$mcVDI$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToInt(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVDJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVDJ$sp.java new file mode 100644 index 0000000000..0b95608684 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVDJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVDJ$sp extends scala.Function2, java.io.Serializable { + void apply$mcVDJ$sp(double v1, long v2); + + default Object apply(Object v1, Object v2) { apply$mcVDJ$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToLong(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVID$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVID$sp.java new file mode 100644 index 0000000000..f0ed7e7e97 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVID$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVID$sp extends scala.Function2, java.io.Serializable { + void apply$mcVID$sp(int v1, double v2); + + default Object apply(Object v1, Object v2) { apply$mcVID$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVII$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVII$sp.java new file mode 100644 index 0000000000..52d7922cc1 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVII$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVII$sp extends scala.Function2, java.io.Serializable { + void apply$mcVII$sp(int v1, int v2); + + default Object apply(Object v1, Object v2) { apply$mcVII$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToInt(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVIJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVIJ$sp.java new file mode 100644 index 0000000000..ac256bf163 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVIJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVIJ$sp extends scala.Function2, java.io.Serializable { + void apply$mcVIJ$sp(int v1, long v2); + + default Object apply(Object v1, Object v2) { apply$mcVIJ$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToLong(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVJD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVJD$sp.java new file mode 100644 index 0000000000..6e2dea3fbf --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVJD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVJD$sp extends scala.Function2, java.io.Serializable { + void apply$mcVJD$sp(long v1, double v2); + + default Object apply(Object v1, Object v2) { apply$mcVJD$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVJI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVJI$sp.java new file mode 100644 index 0000000000..d1cba439e6 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVJI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVJI$sp extends scala.Function2, java.io.Serializable { + void apply$mcVJI$sp(long v1, int v2); + + default Object apply(Object v1, Object v2) { apply$mcVJI$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToInt(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcVJJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcVJJ$sp.java new file mode 100644 index 0000000000..67f848a60e --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcVJJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcVJJ$sp extends scala.Function2, java.io.Serializable { + void apply$mcVJJ$sp(long v1, long v2); + + default Object apply(Object v1, Object v2) { apply$mcVJJ$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToLong(v2)); return scala.runtime.BoxedUnit.UNIT; } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZDD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZDD$sp.java new file mode 100644 index 0000000000..b430c5f134 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZDD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZDD$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZDD$sp(double v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZDD$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZDI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZDI$sp.java new file mode 100644 index 0000000000..01fb8ba003 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZDI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZDI$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZDI$sp(double v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZDI$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZDJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZDJ$sp.java new file mode 100644 index 0000000000..a7d28e3cfc --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZDJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZDJ$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZDJ$sp(double v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZDJ$sp(scala.runtime.BoxesRunTime.unboxToDouble(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZID$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZID$sp.java new file mode 100644 index 0000000000..e77719bf75 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZID$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZID$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZID$sp(int v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZID$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZII$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZII$sp.java new file mode 100644 index 0000000000..5f1f83aaf8 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZII$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZII$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZII$sp(int v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZII$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZIJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZIJ$sp.java new file mode 100644 index 0000000000..38fabd6f69 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZIJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZIJ$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZIJ$sp(int v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZIJ$sp(scala.runtime.BoxesRunTime.unboxToInt(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZJD$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZJD$sp.java new file mode 100644 index 0000000000..59c82cb01e --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZJD$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZJD$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZJD$sp(long v1, double v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZJD$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToDouble(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZJI$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZJI$sp.java new file mode 100644 index 0000000000..3e73b8a794 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZJI$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZJI$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZJI$sp(long v1, int v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZJI$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToInt(v2))); } +} diff --git a/src/library/scala/runtime/java8/JFunction2$mcZJJ$sp.java b/src/library/scala/runtime/java8/JFunction2$mcZJJ$sp.java new file mode 100644 index 0000000000..96a14e98a5 --- /dev/null +++ b/src/library/scala/runtime/java8/JFunction2$mcZJJ$sp.java @@ -0,0 +1,13 @@ + +/* + * Copyright (C) 2012-2015 Typesafe Inc. <http://www.typesafe.com> + */ + +package scala.runtime.java8; + +@FunctionalInterface +public interface JFunction2$mcZJJ$sp extends scala.Function2, java.io.Serializable { + boolean apply$mcZJJ$sp(long v1, long v2); + + default Object apply(Object v1, Object v2) { return scala.runtime.BoxesRunTime.boxToBoolean(apply$mcZJJ$sp(scala.runtime.BoxesRunTime.unboxToLong(v1), scala.runtime.BoxesRunTime.unboxToLong(v2))); } +} diff --git a/src/library/scala/sys/SystemProperties.scala b/src/library/scala/sys/SystemProperties.scala index d2ebf8c044..e5606f3c3b 100644 --- a/src/library/scala/sys/SystemProperties.scala +++ b/src/library/scala/sys/SystemProperties.scala @@ -32,11 +32,18 @@ class SystemProperties extends mutable.AbstractMap[String, String] with mutable.Map[String, String] { - override def empty = new SystemProperties + override def empty = mutable.Map[String, String]() override def default(key: String): String = null - def iterator: Iterator[(String, String)] = - wrapAccess(System.getProperties().asScala.iterator) getOrElse Iterator.empty + def iterator: Iterator[(String, String)] = wrapAccess { + val ps = System.getProperties() + names map (k => (k, ps getProperty k)) filter (_._2 ne null) + } getOrElse Iterator.empty + + def names: Iterator[String] = wrapAccess ( + System.getProperties().stringPropertyNames().asScala.iterator + ) getOrElse Iterator.empty + def get(key: String) = wrapAccess(Option(System.getProperty(key))) flatMap (x => x) override def contains(key: String) = @@ -62,23 +69,25 @@ object SystemProperties { def exclusively[T](body: => T) = this synchronized body implicit def systemPropertiesToCompanion(p: SystemProperties): SystemProperties.type = this - private lazy val propertyHelp = mutable.Map[String, String]() - private def addHelp[P <: Prop[_]](p: P, helpText: String): P = { - propertyHelp(p.key) = helpText - p + + private final val HeadlessKey = "java.awt.headless" + private final val PreferIPv4StackKey = "java.net.preferIPv4Stack" + private final val PreferIPv6AddressesKey = "java.net.preferIPv6Addresses" + private final val NoTraceSuppressionKey = "scala.control.noTraceSuppression" + + def help(key: String): String = key match { + case HeadlessKey => "system should not utilize a display device" + case PreferIPv4StackKey => "system should prefer IPv4 sockets" + case PreferIPv6AddressesKey => "system should prefer IPv6 addresses" + case NoTraceSuppressionKey => "scala should not suppress any stack trace creation" + case _ => "" } - private def bool(key: String, helpText: String): BooleanProp = addHelp[BooleanProp]( - if (key startsWith "java.") BooleanProp.valueIsTrue(key) else BooleanProp.keyExists(key), - helpText - ) - def help(key: String) = propertyHelp.getOrElse(key, "") - - // Todo: bring some sanity to the intersection of system properties aka "mutable - // state shared by everyone and everything" and the reality that there is no other - // mechanism for accomplishing some things on the jvm. - lazy val headless = bool("java.awt.headless", "system should not utilize a display device") - lazy val preferIPv4Stack = bool("java.net.preferIPv4Stack", "system should prefer IPv4 sockets") - lazy val preferIPv6Addresses = bool("java.net.preferIPv6Addresses", "system should prefer IPv6 addresses") - lazy val noTraceSupression = bool("scala.control.noTraceSuppression", "scala should not suppress any stack trace creation") + + lazy val headless: BooleanProp = BooleanProp.keyExists(HeadlessKey) + lazy val preferIPv4Stack: BooleanProp = BooleanProp.keyExists(PreferIPv4StackKey) + lazy val preferIPv6Addresses: BooleanProp = BooleanProp.keyExists(PreferIPv6AddressesKey) + lazy val noTraceSuppression: BooleanProp = BooleanProp.valueIsTrue(NoTraceSuppressionKey) + @deprecated("use noTraceSuppression", "2.12.0") + def noTraceSupression = noTraceSuppression } diff --git a/src/library/scala/sys/process/BasicIO.scala b/src/library/scala/sys/process/BasicIO.scala index 066b2f5373..b39ae77c62 100644 --- a/src/library/scala/sys/process/BasicIO.scala +++ b/src/library/scala/sys/process/BasicIO.scala @@ -33,7 +33,7 @@ object BasicIO { final val BufferSize = 8192 /** Used to separate lines in the `processFully` function that takes `Appendable`. */ - final val Newline = props("line.separator") + final val Newline = System.lineSeparator private[process] final class Streamed[T]( val process: T => Unit, @@ -221,7 +221,7 @@ object BasicIO { */ def transferFully(in: InputStream, out: OutputStream): Unit = try transferFullyImpl(in, out) - catch onInterrupt(()) + catch onIOInterrupt(()) private[this] def appendLine(buffer: Appendable): String => Unit = line => { buffer append line diff --git a/src/library/scala/sys/process/Process.scala b/src/library/scala/sys/process/Process.scala index 06b9967908..0ec749e78a 100644 --- a/src/library/scala/sys/process/Process.scala +++ b/src/library/scala/sys/process/Process.scala @@ -26,11 +26,11 @@ import scala.language.implicitConversions * make it possible for one to block until the process exits and get the exit value, * or destroy the process altogether. * - * Presently, one cannot poll the `Process` to see if it has finished. - * * @see [[scala.sys.process.ProcessBuilder]] */ trait Process { + /** Returns this process alive status */ + def isAlive(): Boolean /** Blocks until this process exits and returns the exit code.*/ def exitValue(): Int /** Destroys this process. */ diff --git a/src/library/scala/sys/process/ProcessBuilder.scala b/src/library/scala/sys/process/ProcessBuilder.scala index e4344a857e..d0745e5833 100644 --- a/src/library/scala/sys/process/ProcessBuilder.scala +++ b/src/library/scala/sys/process/ProcessBuilder.scala @@ -15,8 +15,8 @@ import ProcessBuilder._ /** Represents a sequence of one or more external processes that can be * executed. A `ProcessBuilder` can be a single external process, or a - * combination of other `ProcessBuilder`. One can control where a - * the output of an external process will go to, and where its input will come + * combination of other `ProcessBuilder`. One can control where the + * output of an external process will go to, and where its input will come * from, or leave that decision to whoever starts it. * * One creates a `ProcessBuilder` through factories provided in @@ -172,9 +172,9 @@ trait ProcessBuilder extends Source with Sink { * and then throw an exception. */ def lineStream: Stream[String] - + /** Deprecated (renamed). Use `lineStream` instead. */ - @deprecated("Use lineStream instead.", "2.11.0") + @deprecated("use lineStream instead", "2.11.0") def lines: Stream[String] = lineStream /** Starts the process represented by this builder. The output is returned as @@ -184,9 +184,9 @@ trait ProcessBuilder extends Source with Sink { * to termination and then throw an exception. */ def lineStream(log: ProcessLogger): Stream[String] - + /** Deprecated (renamed). Use `lineStream(log: ProcessLogger)` instead. */ - @deprecated("Use stream instead.", "2.11.0") + @deprecated("use lineStream instead", "2.11.0") def lines(log: ProcessLogger): Stream[String] = lineStream(log) /** Starts the process represented by this builder. The output is returned as @@ -196,9 +196,9 @@ trait ProcessBuilder extends Source with Sink { * but will not throw an exception. */ def lineStream_! : Stream[String] - + /** Deprecated (renamed). Use `lineStream_!` instead. */ - @deprecated("Use lineStream_! instead.", "2.11.0") + @deprecated("use lineStream_! instead", "2.11.0") def lines_! : Stream[String] = lineStream_! /** Starts the process represented by this builder. The output is returned as @@ -208,9 +208,9 @@ trait ProcessBuilder extends Source with Sink { * to termination but will not throw an exception. */ def lineStream_!(log: ProcessLogger): Stream[String] - + /** Deprecated (renamed). Use `lineStream_!(log: ProcessLogger)` instead. */ - @deprecated("Use stream_! instead.", "2.11.0") + @deprecated("use lineStream_! instead", "2.11.0") def lines_!(log: ProcessLogger): Stream[String] = lineStream_!(log) /** Starts the process represented by this builder, blocks until it exits, and @@ -257,10 +257,9 @@ trait ProcessBuilder extends Source with Sink { */ def run(connectInput: Boolean): Process - /** Starts the process represented by this builder, blocks until it exits, and - * returns the exit code. Standard output and error are sent to the given - * ProcessLogger. The newly started process reads from standard input of the - * current process if `connectInput` is true. + /** Starts the process represented by this builder. Standard output and error + * are sent to the given ProcessLogger. The newly started process reads from + * standard input of the current process if `connectInput` is true. */ def run(log: ProcessLogger, connectInput: Boolean): Process @@ -342,7 +341,7 @@ object ProcessBuilder extends ProcessBuilderImpl { /** Writes the output stream of this process to a [[scala.sys.process.ProcessBuilder]]. */ def #>(b: ProcessBuilder): ProcessBuilder = new PipedBuilder(toSource, b, false) - /** Returnes a [[scala.sys.process.ProcessBuilder]] representing this `Source`. */ + /** Returns a [[scala.sys.process.ProcessBuilder]] representing this `Source`. */ def cat = toSource private def toFile(f: File, append: Boolean) = #> (new FileOutput(f, append)) } diff --git a/src/library/scala/sys/process/ProcessBuilderImpl.scala b/src/library/scala/sys/process/ProcessBuilderImpl.scala index 236baaf038..0df2e648e0 100644 --- a/src/library/scala/sys/process/ProcessBuilderImpl.scala +++ b/src/library/scala/sys/process/ProcessBuilderImpl.scala @@ -53,12 +53,14 @@ private[process] trait ProcessBuilderImpl { override def run(io: ProcessIO): Process = { val success = new SyncVar[Boolean] - success put false - val t = Spawn({ - runImpl(io) - success set true - }, io.daemonizeThreads) - + def go(): Unit = { + var ok = false + try { + runImpl(io) + ok = true + } finally success.put(ok) + } + val t = Spawn(go(), io.daemonizeThreads) new ThreadProcess(t, success) } } diff --git a/src/library/scala/sys/process/ProcessImpl.scala b/src/library/scala/sys/process/ProcessImpl.scala index 2b7fcdeb73..8a0002b316 100644 --- a/src/library/scala/sys/process/ProcessImpl.scala +++ b/src/library/scala/sys/process/ProcessImpl.scala @@ -27,18 +27,18 @@ private[process] trait ProcessImpl { } } private[process] object Future { - def apply[T](f: => T): () => T = { + def apply[T](f: => T): (Thread, () => T) = { val result = new SyncVar[Either[Throwable, T]] def run(): Unit = - try result set Right(f) - catch { case e: Exception => result set Left(e) } + try result.put(Right(f)) + catch { case e: Exception => result.put(Left(e)) } - Spawn(run()) + val t = Spawn(run()) - () => result.get match { + (t, () => result.get match { case Right(value) => value case Left(exception) => throw exception - } + }) } } @@ -84,17 +84,22 @@ private[process] trait ProcessImpl { } private[process] abstract class CompoundProcess extends BasicProcess { + def isAlive() = processThread.isAlive() def destroy() = destroyer() - def exitValue() = getExitValue() getOrElse scala.sys.error("No exit code: process destroyed.") - def start() = getExitValue + def exitValue() = futureValue() getOrElse scala.sys.error("No exit code: process destroyed.") + def start() = { futureThread ;() } - protected lazy val (getExitValue, destroyer) = { + protected lazy val (processThread, (futureThread, futureValue), destroyer) = { val code = new SyncVar[Option[Int]]() - code set None - val thread = Spawn(code set runAndExitValue()) + val thread = Spawn { + var value: Option[Int] = None + try value = runAndExitValue() + finally code.put(value) + } ( - Future { thread.join(); code.get }, + thread, + Future(code.get), // thread.join() () => thread.interrupt() ) } @@ -109,45 +114,46 @@ private[process] trait ProcessImpl { } private[process] class PipedProcesses(a: ProcessBuilder, b: ProcessBuilder, defaultIO: ProcessIO, toError: Boolean) extends CompoundProcess { - protected[this] override def runAndExitValue() = { - val currentSource = new SyncVar[Option[InputStream]] - val pipeOut = new PipedOutputStream - val source = new PipeSource(currentSource, pipeOut, a.toString) + protected[this] override def runAndExitValue() = runAndExitValue(new PipeSource(a.toString), new PipeSink(b.toString)) + protected[this] def runAndExitValue(source: PipeSource, sink: PipeSink): Option[Int] = { + source connectOut sink source.start() - - val pipeIn = new PipedInputStream(pipeOut) - val currentSink = new SyncVar[Option[OutputStream]] - val sink = new PipeSink(pipeIn, currentSink, b.toString) sink.start() - def handleOutOrError(fromOutput: InputStream) = currentSource put Some(fromOutput) + /** Release PipeSource, PipeSink and Process in the correct order. + * If once connect Process with Source or Sink, then the order of releasing them + * must be Source -> Sink -> Process, otherwise IOException will be thrown. */ + def releaseResources(so: PipeSource, sk: PipeSink, p: Process *) = { + so.release() + sk.release() + p foreach( _.destroy() ) + } val firstIO = - if (toError) - defaultIO.withError(handleOutOrError) - else - defaultIO.withOutput(handleOutOrError) - val secondIO = defaultIO.withInput(toInput => currentSink put Some(toInput)) - - val second = b.run(secondIO) - val first = a.run(firstIO) - try { - runInterruptible { - val exit1 = first.exitValue() - currentSource put None - currentSink put None - val exit2 = second.exitValue() - // Since file redirection (e.g. #>) is implemented as a piped process, - // we ignore its exit value so cmd #> file doesn't always return 0. - if (b.hasExitValue) exit2 else exit1 - } { - first.destroy() - second.destroy() + if (toError) defaultIO.withError(source.connectIn) + else defaultIO.withOutput(source.connectIn) + val secondIO = defaultIO.withInput(sink.connectOut) + + val second = + try b.run(secondIO) + catch onError { err => + releaseResources(source, sink) + throw err } - } - finally { - BasicIO close pipeIn - BasicIO close pipeOut + val first = + try a.run(firstIO) + catch onError { err => + releaseResources(source, sink, second) + throw err + } + runInterruptible { + val exit1 = first.exitValue() + val exit2 = second.exitValue() + // Since file redirection (e.g. #>) is implemented as a piped process, + // we ignore its exit value so cmd #> file doesn't always return 0. + if (b.hasExitValue) exit2 else exit1 + } { + releaseResources(source, sink, first, second) } } } @@ -168,53 +174,66 @@ private[process] trait ProcessImpl { } } - private[process] class PipeSource( - currentSource: SyncVar[Option[InputStream]], - pipe: PipedOutputStream, - label: => String - ) extends PipeThread(false, () => label) { - - final override def run(): Unit = currentSource.get match { - case Some(source) => - try runloop(source, pipe) - finally currentSource.unset() - - run() - case None => - currentSource.unset() - BasicIO close pipe + private[process] class PipeSource(label: => String) extends PipeThread(false, () => label) { + protected[this] val pipe = new PipedOutputStream + protected[this] val source = new LinkedBlockingQueue[Option[InputStream]] + override def run(): Unit = { + try { + source.take match { + case Some(in) => runloop(in, pipe) + case None => + } + } + catch onInterrupt(()) + finally BasicIO close pipe + } + def connectIn(in: InputStream): Unit = source add Some(in) + def connectOut(sink: PipeSink): Unit = sink connectIn pipe + def release(): Unit = { + interrupt() + source add None + join() } } - private[process] class PipeSink( - pipe: PipedInputStream, - currentSink: SyncVar[Option[OutputStream]], - label: => String - ) extends PipeThread(true, () => label) { - - final override def run(): Unit = currentSink.get match { - case Some(sink) => - try runloop(pipe, sink) - finally currentSink.unset() - - run() - case None => - currentSink.unset() + private[process] class PipeSink(label: => String) extends PipeThread(true, () => label) { + protected[this] val pipe = new PipedInputStream + protected[this] val sink = new LinkedBlockingQueue[Option[OutputStream]] + override def run(): Unit = { + try { + sink.take match { + case Some(out) => runloop(pipe, out) + case None => + } + } + catch onInterrupt(()) + finally BasicIO close pipe + } + def connectOut(out: OutputStream): Unit = sink add Some(out) + def connectIn(pipeOut: PipedOutputStream): Unit = pipe connect pipeOut + def release(): Unit = { + interrupt() + sink add None + join() } } /** A thin wrapper around a java.lang.Process. `ioThreads` are the Threads created to do I/O. - * The implementation of `exitValue` waits until these threads die before returning. */ + * The implementation of `exitValue` waits until these threads die before returning. + */ private[process] class DummyProcess(action: => Int) extends Process { - private[this] val exitCode = Future(action) - override def exitValue() = exitCode() + private[this] val (thread, value) = Future(action) + override def isAlive() = thread.isAlive() + override def exitValue() = value() override def destroy() { } } + /** A thin wrapper around a java.lang.Process. `outputThreads` are the Threads created to read from the * output and error streams of the process. `inputThread` is the Thread created to write to the input stream of * the process. * The implementation of `exitValue` interrupts `inputThread` and then waits until all I/O threads die before * returning. */ private[process] class SimpleProcess(p: JProcess, inputThread: Thread, outputThreads: List[Thread]) extends Process { + override def isAlive() = p.isAlive() override def exitValue() = { try p.waitFor() // wait for the process to terminate finally inputThread.interrupt() // we interrupt the input thread to notify it that it can terminate @@ -231,10 +250,8 @@ private[process] trait ProcessImpl { } } private[process] final class ThreadProcess(thread: Thread, success: SyncVar[Boolean]) extends Process { - override def exitValue() = { - thread.join() - if (success.get) 0 else 1 - } - override def destroy() { thread.interrupt() } + override def isAlive() = thread.isAlive() + override def exitValue() = if (success.get) 0 else 1 // thread.join() + override def destroy() = thread.interrupt() } } diff --git a/src/library/scala/sys/process/package.scala b/src/library/scala/sys/process/package.scala index ac6ab8f670..440e62b6aa 100644 --- a/src/library/scala/sys/process/package.scala +++ b/src/library/scala/sys/process/package.scala @@ -185,8 +185,8 @@ package scala.sys { * new URL("http://www.scala-lang.org/") #> new File("scala-lang.html") ! * }}} * - * More information about the other ways of controlling I/O can be looked at - * in the scaladoc for the associated objects, traits and classes. + * More information about the other ways of controlling I/O can be found + * in the Scaladoc for the associated objects, traits and classes. * * ==Running the Process== * @@ -203,9 +203,9 @@ package scala.sys { package object process extends ProcessImplicits { /** The arguments passed to `java` when creating this process */ def javaVmArguments: List[String] = { - import scala.collection.JavaConversions._ + import scala.collection.JavaConverters._ - java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments().toList + java.lang.management.ManagementFactory.getRuntimeMXBean.getInputArguments.asScala.toList } /** The input stream of this process */ def stdin = java.lang.System.in @@ -225,16 +225,26 @@ package scala.sys { final val processDebug = props contains "scala.process.debug" dbg("Initializing process package.") - type =?>[-A, +B] = PartialFunction[A, B] - type Closeable = java.io.Closeable - type File = java.io.File - type IOException = java.io.IOException - type InputStream = java.io.InputStream - type JProcess = java.lang.Process - type JProcessBuilder = java.lang.ProcessBuilder - type OutputStream = java.io.OutputStream - type SyncVar[T] = scala.concurrent.SyncVar[T] - type URL = java.net.URL + type =?>[-A, +B] = PartialFunction[A, B] + type Closeable = java.io.Closeable + type File = java.io.File + type IOException = java.io.IOException + type InterruptedIOException = java.io.InterruptedIOException + type InputStream = java.io.InputStream + type JProcess = java.lang.Process + type JProcessBuilder = java.lang.ProcessBuilder + type LinkedBlockingQueue[T] = java.util.concurrent.LinkedBlockingQueue[T] + type OutputStream = java.io.OutputStream + type SyncVar[T] = scala.concurrent.SyncVar[T] + type URL = java.net.URL + + def onError[T](handler: Throwable => T): Throwable =?> T = { + case e @ _ => handler(e) + } + + def onIOInterrupt[T](handler: => T): Throwable =?> T = { + case _: InterruptedIOException => handler + } def onInterrupt[T](handler: => T): Throwable =?> T = { case _: InterruptedException => handler diff --git a/src/library/scala/text/Document.scala b/src/library/scala/text/Document.scala index aa55ac4f0f..0c747c99a8 100644 --- a/src/library/scala/text/Document.scala +++ b/src/library/scala/text/Document.scala @@ -10,17 +10,17 @@ package scala.text import java.io.Writer -@deprecated("This object will be removed.", "2.11.0") +@deprecated("this object will be removed", "2.11.0") case object DocNil extends Document -@deprecated("This object will be removed.", "2.11.0") +@deprecated("this object will be removed", "2.11.0") case object DocBreak extends Document -@deprecated("This class will be removed.", "2.11.0") +@deprecated("this class will be removed", "2.11.0") case class DocText(txt: String) extends Document -@deprecated("This class will be removed.", "2.11.0") +@deprecated("this class will be removed", "2.11.0") case class DocGroup(doc: Document) extends Document -@deprecated("This class will be removed.", "2.11.0") +@deprecated("this class will be removed", "2.11.0") case class DocNest(indent: Int, doc: Document) extends Document -@deprecated("This class will be removed.", "2.11.0") +@deprecated("this class will be removed", "2.11.0") case class DocCons(hd: Document, tl: Document) extends Document /** @@ -30,7 +30,7 @@ case class DocCons(hd: Document, tl: Document) extends Document * @author Michel Schinz * @version 1.0 */ -@deprecated("This class will be removed.", "2.11.0") +@deprecated("this class will be removed", "2.11.0") abstract class Document { def ::(hd: Document): Document = DocCons(hd, this) def ::(hd: String): Document = DocCons(DocText(hd), this) @@ -103,7 +103,7 @@ abstract class Document { } } -@deprecated("This object will be removed.", "2.11.0") +@deprecated("this object will be removed", "2.11.0") object Document { /** The empty document */ def empty = DocNil diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala index 32b7ec4487..d295478698 100644 --- a/src/library/scala/util/Either.scala +++ b/src/library/scala/util/Either.scala @@ -6,291 +6,467 @@ ** |/ ** \* */ - - package scala package util -import scala.language.implicitConversions - /** Represents a value of one of two possible types (a disjoint union.) - * Instances of Either are either an instance of [[scala.util.Left]] or [[scala.util.Right]]. + * An instance of `Either` is an instance of either [[scala.util.Left]] or [[scala.util.Right]]. * - * A common use of Either is as an alternative to [[scala.Option]] for dealing - * with possible missing values. In this usage, [[scala.None]] is replaced + * A common use of `Either` is as an alternative to [[scala.Option]] for dealing + * with possibly missing values. In this usage, [[scala.None]] is replaced * with a [[scala.util.Left]] which can contain useful information. * [[scala.util.Right]] takes the place of [[scala.Some]]. Convention dictates - * that Left is used for failure and Right is used for success. + * that `Left` is used for failure and `Right` is used for success. * - * For example, you could use `Either[String, Int]` to detect whether a - * received input is a String or an Int. + * For example, you could use `Either[String, Int]` to indicate whether a + * received input is a `String` or an `Int`. * * {{{ - * val in = Console.readLine("Type Either a string or an Int: ") - * val result: Either[String,Int] = try { - * Right(in.toInt) - * } catch { - * case e: Exception => - * Left(in) - * } + * import scala.io.StdIn._ + * val in = readLine("Type Either a string or an Int: ") + * val result: Either[String,Int] = + * try Right(in.toInt) + * catch { + * case e: NumberFormatException => Left(in) + * } * - * println( result match { - * case Right(x) => "You passed me the Int: " + x + ", which I will increment. " + x + " + 1 = " + (x+1) - * case Left(x) => "You passed me the String: " + x - * }) + * result match { + * case Right(x) => s"You passed me the Int: $x, which I will increment. $x + 1 = ${x+1}" + * case Left(x) => s"You passed me the String: $x" + * } * }}} * - * A ''projection'' can be used to selectively operate on a value of type Either, - * depending on whether it is of type Left or Right. For example, to transform an - * Either using a function, in the case where it's a Left, one can first apply - * the `left` projection and invoke `map` on that projected Either. If a `right` - * projection is applied to that Left, the original Left is returned, unmodified. + * `Either` is right-biased, which means that `Right` is assumed to be the default case to + * operate on. If it is `Left`, operations like `map` and `flatMap` return the `Left` value unchanged: * * {{{ - * val l: Either[String, Int] = Left("flower") - * val r: Either[String, Int] = Right(12) - * l.left.map(_.size): Either[Int, Int] // Left(6) - * r.left.map(_.size): Either[Int, Int] // Right(12) - * l.right.map(_.toDouble): Either[String, Double] // Left("flower") - * r.right.map(_.toDouble): Either[String, Double] // Right(12.0) + * def doubled(i: Int) = i * 2 + * Right(42).map(doubled) // Right(84) + * Left(42).map(doubled) // Left(42) * }}} * - * Like with other types which define a `map` method, the same can be achieved - * using a for-comprehension: + * Since `Either` defines the methods `map` and `flatMap`, it can also be used in for comprehensions: * {{{ - * for (s <- l.left) yield s.size // Left(6) - * }}} + * val right1 = Right(1) : Right[Double, Int] + * val right2 = Right(2) + * val right3 = Right(3) + * val left23 = Left(23.0) : Left[Double, Int] + * val left42 = Left(42.0) + * + * for { + * a <- right1 + * b <- right2 + * c <- right3 + * } yield a + b + c // Right(6) + * + * for { + * a <- right1 + * b <- right2 + * c <- left23 + * } yield a + b + c // Left(23.0) + * + * for { + * a <- right1 + * b <- left23 + * c <- right2 + * } yield a + b + c // Left(23.0) * - * To support multiple projections as generators in for-comprehensions, the Either - * type also defines a `flatMap` method. + * // It may be necessary to provide the type of the “missing” value, especially the type + * // of the right value for `Left`. Otherwise, without any context that constrains the type, + * // it might be inferred as `Nothing`: + * for { + * a <- left23 + * b <- right1 + * c <- left42 // type at this position: Either[Double, Nothing] + * } yield a + b + c + * // ^ + * // error: ambiguous reference to overloaded definition, + * // both method + in class Int of type (x: Char)Int + * // and method + in class Int of type (x: Byte)Int + * // match argument types (Nothing) + * }}} * * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @version 2.0, 2016-07-15 * @since 2.7 */ -sealed abstract class Either[+A, +B] { - /** - * Projects this `Either` as a `Left`. - */ +sealed abstract class Either[+A, +B] extends Product with Serializable { + /** Projects this `Either` as a `Left`. */ def left = Either.LeftProjection(this) - /** - * Projects this `Either` as a `Right`. + /** Projects this `Either` as a `Right`. + * + * Because `Either` is right-biased, this method is not normally needed. */ def right = Either.RightProjection(this) - /** - * Applies `fa` if this is a `Left` or `fb` if this is a `Right`. + /** Applies `fa` if this is a `Left` or `fb` if this is a `Right`. * - * @example {{{ - * val result: Either[Exception, Value] = possiblyFailingOperation() - * log(result.fold( - * ex => "Operation failed with " + ex, - * v => "Operation produced value: " + v - * )) - * }}} + * @example {{{ + * val result = util.Try("42".toInt).toEither + * result.fold( + * e => s"Operation failed with $e", + * v => s"Operation produced value: $v" + * ) + * }}} * - * @param fa the function to apply if this is a `Left` - * @param fb the function to apply if this is a `Right` - * @return the results of applying the function + * @param fa the function to apply if this is a `Left` + * @param fb the function to apply if this is a `Right` + * @return the results of applying the function */ - def fold[X](fa: A => X, fb: B => X) = this match { - case Left(a) => fa(a) + def fold[C](fa: A => C, fb: B => C): C = this match { case Right(b) => fb(b) + case Left(a) => fa(a) } - /** - * If this is a `Left`, then return the left value in `Right` or vice versa. + /** If this is a `Left`, then return the left value in `Right` or vice versa. * - * @example {{{ - * val l: Either[String, Int] = Left("left") - * val r: Either[Int, String] = l.swap // Result: Right("left") - * }}} + * @example {{{ + * val left: Either[String, Int] = Left("left") + * val right: Either[Int, String] = left.swap // Result: Right("left") + * }}} + * @example {{{ + * val right = Right(2) + * val left = Left(3) + * for { + * r1 <- right + * r2 <- left.swap + * } yield r1 * r2 // Right(6) + * }}} */ - def swap = this match { - case Left(a) => Right(a) + def swap: Either[B, A] = this match { + case Left(a) => Right(a) case Right(b) => Left(b) } - /** - * Joins an `Either` through `Right`. + /** Joins an `Either` through `Right`. * - * This method requires that the right side of this Either is itself an - * Either type. That is, this must be some type like: {{{ - * Either[A, Either[A, C]] - * }}} (which respects the type parameter bounds, shown below.) + * This method requires that the right side of this `Either` is itself + * an `Either` type. That is, this must be some type like: {{{ + * Either[A, Either[A, C]] + * }}} (which respects the type parameter bounds, shown below.) * - * If this instance is a Right[Either[A, C]] then the contained Either[A, C] - * will be returned, otherwise this value will be returned unmodified. + * If this instance is a `Right[Either[A, C]]` then the contained `Either[A, C]` + * will be returned, otherwise this value will be returned unmodified. * - * @example {{{ - * Right[String, Either[String, Int]](Right(12)).joinRight // Result: Right(12) - * Right[String, Either[String, Int]](Left("flower")).joinRight // Result: Left("flower") - * Left[String, Either[String, Int]]("flower").joinRight // Result: Left("flower") - * }}} + * @example {{{ + * Right[String, Either[String, Int]](Right(12)).joinRight // Result: Right(12) + * Right[String, Either[String, Int]](Left("flower")).joinRight // Result: Left("flower") + * Left[String, Either[String, Int]]("flower").joinRight // Result: Left("flower") + * }}} * * This method, and `joinLeft`, are analogous to `Option#flatten` */ def joinRight[A1 >: A, B1 >: B, C](implicit ev: B1 <:< Either[A1, C]): Either[A1, C] = this match { - case Left(a) => Left(a) case Right(b) => b + case Left(a) => this.asInstanceOf[Either[A1, C]] + } - /** - * Joins an `Either` through `Left`. + /** Joins an `Either` through `Left`. * - * This method requires that the left side of this Either is itself an - * Either type. That is, this must be some type like: {{{ - * Either[Either[C, B], B] - * }}} (which respects the type parameter bounds, shown below.) + * This method requires that the left side of this `Either` is itself an + * `Either` type. That is, this must be some type like: {{{ + * Either[Either[C, B], B] + * }}} (which respects the type parameter bounds, shown below.) * - * If this instance is a Left[Either[C, B]] then the contained Either[C, B] - * will be returned, otherwise this value will be returned unmodified. + * If this instance is a `Left[Either[C, B]]` then the contained `Either[C, B]` + * will be returned, otherwise this value will be returned unmodified. * - * {{{ - * Left[Either[Int, String], String](Right("flower")).joinLeft // Result: Right("flower") - * Left[Either[Int, String], String](Left(12)).joinLeft // Result: Left(12) - * Right[Either[Int, String], String]("daisy").joinLeft // Result: Right("daisy") - * }}} + * {{{ + * Left[Either[Int, String], String](Right("flower")).joinLeft // Result: Right("flower") + * Left[Either[Int, String], String](Left(12)).joinLeft // Result: Left(12) + * Right[Either[Int, String], String]("daisy").joinLeft // Result: Right("daisy") + * }}} * - * This method, and `joinRight`, are analogous to `Option#flatten` + * This method, and `joinRight`, are analogous to `Option#flatten`. */ def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1] = this match { case Left(a) => a - case Right(b) => Right(b) + case Right(b) => this.asInstanceOf[Either[C, B1]] + } + + /** Executes the given side-effecting function if this is a `Right`. + * + * {{{ + * Right(12).foreach(println) // prints "12" + * Left(12).foreach(println) // doesn't print + * }}} + * @param f The side-effecting function to execute. + */ + def foreach[U](f: B => U): Unit = this match { + case Right(b) => f(b) + case Left(_) => + } + + /** Returns the value from this `Right` or the given argument if this is a `Left`. + * + * {{{ + * Right(12).getOrElse(17) // 12 + * Left(12).getOrElse(17) // 17 + * }}} + */ + def getOrElse[BB >: B](or: => BB): BB = this match { + case Right(b) => b + case Left(_) => or } - /** - * Returns `true` if this is a `Left`, `false` otherwise. + /** Returns `true` if this is a `Right` and its value is equal to `elem` (as determined by `==`), + * returns `false` otherwise. + * + * {{{ + * // Returns true because value of Right is "something" which equals "something". + * Right("something") contains "something" + * + * // Returns false because value of Right is "something" which does not equal "anything". + * Right("something") contains "anything" + * + * // Returns false because it's not a Right value. + * Left("something") contains "something" + * }}} + * + * @param elem the element to test. + * @return `true` if the option has an element that is equal (as determined by `==`) to `elem`, `false` otherwise. + */ + final def contains[BB >: B](elem: BB): Boolean = this match { + case Right(b) => b == elem + case Left(_) => false + } + + /** Returns `true` if `Left` or returns the result of the application of + * the given predicate to the `Right` value. + * + * {{{ + * Right(12).forall(_ > 10) // true + * Right(7).forall(_ > 10) // false + * Left(12).forall(_ => false) // true + * }}} + */ + def forall(f: B => Boolean): Boolean = this match { + case Right(b) => f(b) + case Left(_) => true + } + + /** Returns `false` if `Left` or returns the result of the application of + * the given predicate to the `Right` value. + * + * {{{ + * Right(12).exists(_ > 10) // true + * Right(7).exists(_ > 10) // false + * Left(12).exists(_ => true) // false + * }}} + */ + def exists(p: B => Boolean): Boolean = this match { + case Right(b) => p(b) + case Left(_) => false + } + + /** Binds the given function across `Right`. + * + * @param f The function to bind across `Right`. + */ + def flatMap[AA >: A, Y](f: B => Either[AA, Y]): Either[AA, Y] = this match { + case Right(b) => f(b) + case Left(a) => this.asInstanceOf[Either[AA, Y]] + } + + /** The given function is applied if this is a `Right`. + * + * {{{ + * Right(12).map(x => "flower") // Result: Right("flower") + * Left(12).map(x => "flower") // Result: Left(12) + * }}} + */ + def map[Y](f: B => Y): Either[A, Y] = this match { + case Right(b) => Right(f(b)) + case Left(a) => this.asInstanceOf[Either[A, Y]] + } + + /** Returns `Right` with the existing value of `Right` if this is a `Right` and the given predicate `p` holds for the right value, + * returns `Left(zero)` if this is a `Right` and the given predicate `p` does not hold for the right value, + * returns `Left` with the existing value of `Left` if this is a `Left`. * * {{{ - * Left("tulip").isLeft // true - * Right("venus fly-trap").isLeft // false + * Right(12).filterOrElse(_ > 10, -1) // Right(12) + * Right(7).filterOrElse(_ > 10, -1) // Left(-1) + * Left(7).filterOrElse(_ => false, -1) // Left(7) * }}} */ - def isLeft: Boolean + def filterOrElse[AA >: A](p: B => Boolean, zero: => AA): Either[AA, B] = this match { + case Right(b) => if (p(b)) this else Left(zero) + case Left(a) => this + } - /** - * Returns `true` if this is a `Right`, `false` otherwise. + /** Returns a `Seq` containing the `Right` value if + * it exists or an empty `Seq` if this is a `Left`. * * {{{ - * Left("tulip").isRight // false - * Right("venus fly-trap").isRight // true + * Right(12).toSeq // Seq(12) + * Left(12).toSeq // Seq() * }}} */ + def toSeq: collection.immutable.Seq[B] = this match { + case Right(b) => collection.immutable.Seq(b) + case Left(_) => collection.immutable.Seq.empty + } + + /** Returns a `Some` containing the `Right` value + * if it exists or a `None` if this is a `Left`. + * + * {{{ + * Right(12).toOption // Some(12) + * Left(12).toOption // None + * }}} + */ + def toOption: Option[B] = this match { + case Right(b) => Some(b) + case Left(_) => None + } + + def toTry(implicit ev: A <:< Throwable): Try[B] = this match { + case Right(b) => Success(b) + case Left(a) => Failure(a) + } + + /** Returns `true` if this is a `Left`, `false` otherwise. + * + * {{{ + * Left("tulip").isLeft // true + * Right("venus fly-trap").isLeft // false + * }}} + */ + def isLeft: Boolean + + /** Returns `true` if this is a `Right`, `false` otherwise. + * + * {{{ + * Left("tulip").isRight // false + * Right("venus fly-trap").isRight // true + * }}} + */ def isRight: Boolean } -/** - * The left side of the disjoint union, as opposed to the [[scala.util.Right]] side. +/** The left side of the disjoint union, as opposed to the [[scala.util.Right]] side. * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ -final case class Left[+A, +B](a: A) extends Either[A, B] { - def isLeft = true +final case class Left[+A, +B](@deprecatedName('a, "2.12.0") value: A) extends Either[A, B] { + def isLeft = true def isRight = false + + @deprecated("Use .value instead.", "2.12.0") def a: A = value } -/** - * The right side of the disjoint union, as opposed to the [[scala.util.Left]] side. +/** The right side of the disjoint union, as opposed to the [[scala.util.Left]] side. * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ -final case class Right[+A, +B](b: B) extends Either[A, B] { - def isLeft = false +final case class Right[+A, +B](@deprecatedName('b, "2.12.0") value: B) extends Either[A, B] { + def isLeft = false def isRight = true + + @deprecated("Use .value instead.", "2.12.0") def b: B = value } object Either { - /** - * Allows use of a `merge` method to extract values from Either instances - * regardless of whether they are Left or Right. + /** If the condition is satisfied, return the given `B` in `Right`, + * otherwise, return the given `A` in `Left`. * - * {{{ - * val l = Left(List(1)): Either[List[Int], Vector[Int]] - * val r = Right(Vector(1)): Either[List[Int], Vector[Int]] - * l.merge: Seq[Int] // List(1) - * r.merge: Seq[Int] // Vector(1) - * }}} + * {{{ + * val userInput: String = ... + * Either.cond( + * userInput.forall(_.isDigit) && userInput.size == 10, + * PhoneNumber(userInput), + * "The input (%s) does not look like a phone number".format(userInput) + * }}} + */ + def cond[X, Y](test: Boolean, right: => Y, left: => X): Either[X, Y] = + if (test) Right(right) else Left(left) + + /** Allows use of a `merge` method to extract values from Either instances + * regardless of whether they are Left or Right. + * + * {{{ + * val l = Left(List(1)): Either[List[Int], Vector[Int]] + * val r = Right(Vector(1)): Either[List[Int], Vector[Int]] + * l.merge: Seq[Int] // List(1) + * r.merge: Seq[Int] // Vector(1) + * }}} */ implicit class MergeableEither[A](private val x: Either[A, A]) extends AnyVal { def merge: A = x match { - case Left(a) => a case Right(a) => a + case Left(a) => a } } - /** - * Projects an `Either` into a `Left`. + /** Projects an `Either` into a `Left`. * - * This allows for-comprehensions over Either instances - for example {{{ - * for (s <- Left("flower").left) yield s.length // Left(6) - * }}} + * This allows for-comprehensions over the left side of Either instances, + * reversing Either's usual right-bias. * - * Continuing the analogy with [[scala.Option]], a `LeftProjection` declares - * that `Left` should be analogous to `Some` in some code. + * For example {{{ + * for (s <- Left("flower").left) yield s.length // Left(6) + * }}} * - * {{{ - * // using Option: - * def interactWithDB(x: Query): Option[Result] = - * try { - * Some(getResultFromDatabase(x)) - * } catch { - * case ex => None - * } + * Continuing the analogy with [[scala.Option]], a `LeftProjection` declares + * that `Left` should be analogous to `Some` in some code. * - * // this will only be executed if interactWithDB returns a Some - * val report = - * for (r <- interactWithDB(someQuery)) yield generateReport(r) - * if (report.isDefined) - * send(report) - * else - * log("report not generated, not sure why...") - * }}} + * {{{ + * // using Option: + * def interactWithDB(x: Query): Option[Result] = + * try Some(getResultFromDatabase(x)) + * catch { + * case _: SQLException => None + * } * - * {{{ - * // using Either - * def interactWithDB(x: Query): Either[Exception, Result] = - * try { - * Right(getResultFromDatabase(x)) - * } catch { - * case ex => Left(ex) - * } + * // this will only be executed if interactWithDB returns a Some + * val report = for (result <- interactWithDB(someQuery)) yield generateReport(result) + * report match { + * case Some(r) => send(r) + * case None => log("report not generated, not sure why...") + * }}} * - * // this will only be executed if interactWithDB returns a Right - * val report = - * for (r <- interactWithDB(someQuery).right) yield generateReport(r) - * if (report.isRight) - * send(report) - * else - * log("report not generated, reason was " + report.left.get) - * }}} + * {{{ + * // using Either + * def interactWithDB(x: Query): Either[Exception, Result] = + * try Right(getResultFromDatabase(x)) + * catch { + * case e: SQLException => Left(e) + * } + * + * // this will only be executed if interactWithDB returns a Right + * val report = for (result <- interactWithDB(someQuery).right) yield generateReport(result) + * report match { + * case Right(r) => send(r) + * case Left(e) => log(s"report not generated, reason was $e") + * } + * }}} * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ final case class LeftProjection[+A, +B](e: Either[A, B]) { - /** - * Returns the value from this `Left` or throws `java.util.NoSuchElementException` - * if this is a `Right`. + /** Returns the value from this `Left` or throws `java.util.NoSuchElementException` + * if this is a `Right`. * * {{{ - * Left(12).left.get // 12 + * Left(12).left.get // 12 * Right(12).left.get // NoSuchElementException * }}} * * @throws java.util.NoSuchElementException if the projection is [[scala.util.Right]] */ - def get = e match { - case Left(a) => a - case Right(_) => throw new NoSuchElementException("Either.left.value on Right") + def get: A = e match { + case Left(a) => a + case Right(_) => throw new NoSuchElementException("Either.left.get on Right") } - /** - * Executes the given side-effecting function if this is a `Left`. + /** Executes the given side-effecting function if this is a `Left`. * * {{{ * Left(12).left.foreach(x => println(x)) // prints "12" @@ -298,241 +474,215 @@ object Either { * }}} * @param f The side-effecting function to execute. */ - def foreach[U](f: A => U) = e match { - case Left(a) => f(a) - case Right(_) => {} + def foreach[U](f: A => U): Unit = e match { + case Left(a) => f(a) + case Right(_) => } - /** - * Returns the value from this `Left` or the given argument if this is a - * `Right`. - * - * {{{ - * Left(12).left.getOrElse(17) // 12 - * Right(12).left.getOrElse(17) // 17 - * }}} + /** Returns the value from this `Left` or the given argument if this is a `Right`. * + * {{{ + * Left(12).left.getOrElse(17) // 12 + * Right(12).left.getOrElse(17) // 17 + * }}} */ - def getOrElse[AA >: A](or: => AA) = e match { - case Left(a) => a + def getOrElse[AA >: A](or: => AA): AA = e match { + case Left(a) => a case Right(_) => or } - /** - * Returns `true` if `Right` or returns the result of the application of - * the given function to the `Left` value. - * - * {{{ - * Left(12).left.forall(_ > 10) // true - * Left(7).left.forall(_ > 10) // false - * Right(12).left.forall(_ > 10) // true - * }}} + /** Returns `true` if `Right` or returns the result of the application of + * the given function to the `Left` value. * + * {{{ + * Left(12).left.forall(_ > 10) // true + * Left(7).left.forall(_ > 10) // false + * Right(12).left.forall(_ > 10) // true + * }}} */ - def forall(@deprecatedName('f) p: A => Boolean) = e match { - case Left(a) => p(a) + def forall(@deprecatedName('f) p: A => Boolean): Boolean = e match { + case Left(a) => p(a) case Right(_) => true } - /** - * Returns `false` if `Right` or returns the result of the application of - * the given function to the `Left` value. - * - * {{{ - * Left(12).left.exists(_ > 10) // true - * Left(7).left.exists(_ > 10) // false - * Right(12).left.exists(_ > 10) // false - * }}} + /** Returns `false` if `Right` or returns the result of the application of + * the given function to the `Left` value. * + * {{{ + * Left(12).left.exists(_ > 10) // true + * Left(7).left.exists(_ > 10) // false + * Right(12).left.exists(_ > 10) // false + * }}} */ - def exists(@deprecatedName('f) p: A => Boolean) = e match { - case Left(a) => p(a) + def exists(@deprecatedName('f) p: A => Boolean): Boolean = e match { + case Left(a) => p(a) case Right(_) => false } - /** - * Binds the given function across `Left`. + /** Binds the given function across `Left`. * - * {{{ - * Left(12).left.flatMap(x => Left("scala")) // Left("scala") - * Right(12).left.flatMap(x => Left("scala") // Right(12) - * }}} - * @param f The function to bind across `Left`. + * {{{ + * Left(12).left.flatMap(x => Left("scala")) // Left("scala") + * Right(12).left.flatMap(x => Left("scala")) // Right(12) + * }}} + * @param f The function to bind across `Left`. */ - def flatMap[BB >: B, X](f: A => Either[X, BB]) = e match { - case Left(a) => f(a) - case Right(b) => Right(b) + def flatMap[BB >: B, X](f: A => Either[X, BB]): Either[X, BB] = e match { + case Left(a) => f(a) + case Right(b) => e.asInstanceOf[Either[X, BB]] } - /** - * Maps the function argument through `Left`. + /** Maps the function argument through `Left`. * - * {{{ - * Left(12).left.map(_ + 2) // Left(14) - * Right[Int, Int](12).left.map(_ + 2) // Right(12) - * }}} + * {{{ + * Left(12).left.map(_ + 2) // Left(14) + * Right[Int, Int](12).left.map(_ + 2) // Right(12) + * }}} */ - def map[X](f: A => X) = e match { - case Left(a) => Left(f(a)) - case Right(b) => Right(b) + def map[X](f: A => X): Either[X, B] = e match { + case Left(a) => Left(f(a)) + case Right(b) => e.asInstanceOf[Either[X, B]] } - /** - * Returns `None` if this is a `Right` or if the given predicate - * `p` does not hold for the left value, otherwise, returns a `Left`. + /** Returns `None` if this is a `Right` or if the given predicate + * `p` does not hold for the left value, otherwise, returns a `Left`. * - * {{{ - * Left(12).left.filter(_ > 10) // Some(Left(12)) - * Left(7).left.filter(_ > 10) // None - * Right(12).left.filter(_ > 10) // None - * }}} + * {{{ + * Left(12).left.filter(_ > 10) // Some(Left(12)) + * Left(7).left.filter(_ > 10) // None + * Right(12).left.filter(_ > 10) // None + * }}} */ def filter[Y](p: A => Boolean): Option[Either[A, Y]] = e match { - case Left(a) => if(p(a)) Some(Left(a)) else None + case Left(a) => if(p(a)) Some(Left(a)) else None case Right(b) => None } - /** - * Returns a `Seq` containing the `Left` value if it exists or an empty - * `Seq` if this is a `Right`. + /** Returns a `Seq` containing the `Left` value if it exists or an empty + * `Seq` if this is a `Right`. * - * {{{ - * Left(12).left.toSeq // Seq(12) - * Right(12).left.toSeq // Seq() - * }}} + * {{{ + * Left(12).left.toSeq // Seq(12) + * Right(12).left.toSeq // Seq() + * }}} */ - def toSeq = e match { - case Left(a) => Seq(a) + def toSeq: Seq[A] = e match { + case Left(a) => Seq(a) case Right(_) => Seq.empty } - /** - * Returns a `Some` containing the `Left` value if it exists or a - * `None` if this is a `Right`. + /** Returns a `Some` containing the `Left` value if it exists or a + * `None` if this is a `Right`. * - * {{{ - * Left(12).left.toOption // Some(12) - * Right(12).left.toOption // None - * }}} + * {{{ + * Left(12).left.toOption // Some(12) + * Right(12).left.toOption // None + * }}} */ - def toOption = e match { - case Left(a) => Some(a) + def toOption: Option[A] = e match { + case Left(a) => Some(a) case Right(_) => None } } - /** - * Projects an `Either` into a `Right`. + /** Projects an `Either` into a `Right`. * - * This allows for-comprehensions over Either instances - for example {{{ - * for (s <- Right("flower").right) yield s.length // Right(6) - * }}} - * - * Continuing the analogy with [[scala.Option]], a `RightProjection` declares - * that `Right` should be analogous to `Some` in some code. - * - * Analogous to `LeftProjection`, see example usage in its documentation above. + * Because `Either` is already right-biased, this class is not normally needed. + * (It is retained in the library for now for easy cross-compilation between Scala + * 2.11 and 2.12.) * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ final case class RightProjection[+A, +B](e: Either[A, B]) { - /** - * Returns the value from this `Right` or throws - * `java.util.NoSuchElementException` if this is a `Left`. + /** Returns the value from this `Right` or throws + * `java.util.NoSuchElementException` if this is a `Left`. * - * {{{ - * Right(12).right.get // 12 - * Left(12).right.get // NoSuchElementException - * }}} + * {{{ + * Right(12).right.get // 12 + * Left(12).right.get // NoSuchElementException + * }}} * * @throws java.util.NoSuchElementException if the projection is `Left`. */ - def get = e match { - case Left(_) => throw new NoSuchElementException("Either.right.value on Left") - case Right(a) => a + def get: B = e match { + case Right(b) => b + case Left(_) => throw new NoSuchElementException("Either.right.get on Left") } - /** - * Executes the given side-effecting function if this is a `Right`. + /** Executes the given side-effecting function if this is a `Right`. * - * {{{ - * Right(12).right.foreach(x => println(x)) // prints "12" - * Left(12).right.foreach(x => println(x)) // doesn't print - * }}} - * @param f The side-effecting function to execute. + * {{{ + * Right(12).right.foreach(x => println(x)) // prints "12" + * Left(12).right.foreach(x => println(x)) // doesn't print + * }}} + * @param f The side-effecting function to execute. */ - def foreach[U](f: B => U) = e match { - case Left(_) => {} + def foreach[U](f: B => U): Unit = e match { case Right(b) => f(b) + case Left(_) => } - /** - * Returns the value from this `Right` or the given argument if this is a - * `Left`. + /** Returns the value from this `Right` or the given argument if this is a `Left`. * - * {{{ - * Right(12).right.getOrElse(17) // 12 - * Left(12).right.getOrElse(17) // 17 - * }}} + * {{{ + * Right(12).right.getOrElse(17) // 12 + * Left(12).right.getOrElse(17) // 17 + * }}} */ - def getOrElse[BB >: B](or: => BB) = e match { - case Left(_) => or + def getOrElse[BB >: B](or: => BB): BB = e match { case Right(b) => b + case Left(_) => or } - /** - * Returns `true` if `Left` or returns the result of the application of - * the given function to the `Right` value. + /** Returns `true` if `Left` or returns the result of the application of + * the given function to the `Right` value. * - * {{{ - * Right(12).right.forall(_ > 10) // true - * Right(7).right.forall(_ > 10) // false - * Left(12).right.forall(_ > 10) // true - * }}} + * {{{ + * Right(12).right.forall(_ > 10) // true + * Right(7).right.forall(_ > 10) // false + * Left(12).right.forall(_ > 10) // true + * }}} */ - def forall(f: B => Boolean) = e match { - case Left(_) => true + def forall(f: B => Boolean): Boolean = e match { case Right(b) => f(b) + case Left(_) => true } - /** - * Returns `false` if `Left` or returns the result of the application of - * the given function to the `Right` value. + /** Returns `false` if `Left` or returns the result of the application of + * the given function to the `Right` value. * - * {{{ - * Right(12).right.exists(_ > 10) // true - * Right(7).right.exists(_ > 10) // false - * Left(12).right.exists(_ > 10) // false - * }}} + * {{{ + * Right(12).right.exists(_ > 10) // true + * Right(7).right.exists(_ > 10) // false + * Left(12).right.exists(_ > 10) // false + * }}} */ - def exists(@deprecatedName('f) p: B => Boolean) = e match { - case Left(_) => false + def exists(@deprecatedName('f) p: B => Boolean): Boolean = e match { case Right(b) => p(b) + case Left(_) => false } - /** - * Binds the given function across `Right`. + /** Binds the given function across `Right`. * - * @param f The function to bind across `Right`. + * @param f The function to bind across `Right`. */ - def flatMap[AA >: A, Y](f: B => Either[AA, Y]) = e match { - case Left(a) => Left(a) + def flatMap[AA >: A, Y](f: B => Either[AA, Y]): Either[AA, Y] = e match { case Right(b) => f(b) + case Left(a) => e.asInstanceOf[Either[AA, Y]] } - /** - * The given function is applied if this is a `Right`. + /** The given function is applied if this is a `Right`. * - * {{{ - * Right(12).right.map(x => "flower") // Result: Right("flower") - * Left(12).right.map(x => "flower") // Result: Left(12) - * }}} + * {{{ + * Right(12).right.map(x => "flower") // Result: Right("flower") + * Left(12).right.map(x => "flower") // Result: Left(12) + * }}} */ - def map[Y](f: B => Y) = e match { - case Left(a) => Left(a) + def map[Y](f: B => Y): Either[A, Y] = e match { case Right(b) => Right(f(b)) + case Left(a) => e.asInstanceOf[Either[A, Y]] } /** Returns `None` if this is a `Left` or if the @@ -546,8 +696,8 @@ object Either { * }}} */ def filter[X](p: B => Boolean): Option[Either[X, B]] = e match { - case Left(_) => None case Right(b) => if(p(b)) Some(Right(b)) else None + case Left(_) => None } /** Returns a `Seq` containing the `Right` value if @@ -558,9 +708,9 @@ object Either { * Left(12).right.toSeq // Seq() * }}} */ - def toSeq = e match { - case Left(_) => Seq.empty + def toSeq: Seq[B] = e match { case Right(b) => Seq(b) + case Left(_) => Seq.empty } /** Returns a `Some` containing the `Right` value @@ -571,23 +721,9 @@ object Either { * Left(12).right.toOption // None * }}} */ - def toOption = e match { - case Left(_) => None + def toOption: Option[B] = e match { case Right(b) => Some(b) + case Left(_) => None } } - - /** If the condition is satisfied, return the given `B` in `Right`, - * otherwise, return the given `A` in `Left`. - * - * {{{ - * val userInput: String = ... - * Either.cond( - * userInput.forall(_.isDigit) && userInput.size == 10, - * PhoneNumber(userInput), - * "The input (%s) does not look like a phone number".format(userInput) - * }}} - */ - def cond[A, B](test: Boolean, right: => B, left: => A): Either[A, B] = - if (test) Right(right) else Left(left) } diff --git a/src/library/scala/util/MurmurHash.scala b/src/library/scala/util/MurmurHash.scala index 1b6db5d6aa..cdc5c821fa 100644 --- a/src/library/scala/util/MurmurHash.scala +++ b/src/library/scala/util/MurmurHash.scala @@ -28,7 +28,7 @@ import scala.collection.Iterator * or can take individual hash values with append. Its own hash code is * set equal to the hash code of whatever it is hashing. */ -@deprecated("Use the object MurmurHash3 instead.", "2.10.0") +@deprecated("use the object MurmurHash3 instead", "2.10.0") class MurmurHash[@specialized(Int,Long,Float,Double) T](seed: Int) extends (T => Unit) { import MurmurHash._ @@ -81,8 +81,8 @@ class MurmurHash[@specialized(Int,Long,Float,Double) T](seed: Int) extends (T => * incorporate a new integer) to update the values. Only one method * needs to be called to finalize the hash. */ -@deprecated("Use the object MurmurHash3 instead.", "2.10.0") -// NOTE: Used by SBT 0.13.0-M2 and below +@deprecated("use the object MurmurHash3 instead", "2.10.0") +// NOTE: Used by sbt 0.13.0-M2 and below object MurmurHash { // Magic values used for MurmurHash's 32 bit hash. // Don't change these without consulting a hashing expert! diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 416aeeccb3..101a6437ec 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -120,7 +120,7 @@ private[scala] trait PropertiesTrait { /** The default end of line character. */ - def lineSeparator = propOrElse("line.separator", "\n") + def lineSeparator = System.lineSeparator() /* Various well-known properties. */ def javaClassPath = propOrEmpty("java.class.path") @@ -148,10 +148,18 @@ private[scala] trait PropertiesTrait { // the reason why we don't follow developer.apple.com/library/mac/#technotes/tn2002/tn2110. /** Returns `true` iff the underlying operating system is a version of Apple Mac OSX. */ def isMac = osName startsWith "Mac OS X" + /** Returns `true` iff the underlying operating system is a Linux distribution. */ + def isLinux = osName startsWith "Linux" /* Some runtime values. */ private[scala] def isAvian = javaVmName contains "Avian" + private[scala] def coloredOutputEnabled: Boolean = propOrElse("scala.color", "auto") match { + case "auto" => System.console() != null && !isWin + case a if a.toLowerCase() == "true" => true + case _ => false + } + // This is looking for javac, tools.jar, etc. // Tries JDK_HOME first, then the more common but likely jre JAVA_HOME, // and finally the system property based javaHome. @@ -166,27 +174,53 @@ private[scala] trait PropertiesTrait { /** Compares the given specification version to the specification version of the platform. * - * @param version a specification version of the form "major.minor" - * @return `true` iff the specification version of the current runtime - * is equal to or higher than the version denoted by the given string. - * @throws NumberFormatException if the given string is not a version string + * @param version a specification version number (legacy forms acceptable) + * @return `true` if the specification version of the current runtime + * is equal to or higher than the version denoted by the given string. + * @throws NumberFormatException if the given string is not a version string * - * @example {{{ - * // In this example, the runtime's Java specification is assumed to be at version 1.7. - * isJavaAtLeast("1.6") // true - * isJavaAtLeast("1.7") // true - * isJavaAtLeast("1.8") // false - * }}} + * @example {{{ + * // In this example, the runtime's Java specification is assumed to be at version 8. + * isJavaAtLeast("1.8") // true + * isJavaAtLeast("8") // true + * isJavaAtLeast("9") // false + * isJavaAtLeast("9.1") // false + * isJavaAtLeast("1.9") // throws + * }}} */ def isJavaAtLeast(version: String): Boolean = { - def parts(x: String) = { - val i = x.indexOf('.') - if (i < 0) throw new NumberFormatException("Not a version: " + x) - (x.substring(0, i), x.substring(i+1, x.length)) + def versionOf(s: String, depth: Int): (Int, String) = + s.indexOf('.') match { + case 0 => + (-2, s.substring(1)) + case 1 if depth == 0 && s.charAt(0) == '1' => + val r0 = s.substring(2) + val (v, r) = versionOf(r0, 1) + val n = if (v > 8 || r0.isEmpty) -2 else v // accept 1.8, not 1.9 or 1. + (n, r) + case -1 => + val n = if (!s.isEmpty) s.toInt else if (depth == 0) -2 else 0 + (n, "") + case i => + val r = s.substring(i + 1) + val n = if (depth < 2 && r.isEmpty) -2 else s.substring(0, i).toInt + (n, r) + } + def compareVersions(s: String, v: String, depth: Int): Int = { + if (depth >= 3) 0 + else { + val (sn, srest) = versionOf(s, depth) + val (vn, vrest) = versionOf(v, depth) + if (vn < 0) -2 + else if (sn < vn) -1 + else if (sn > vn) 1 + else compareVersions(srest, vrest, depth + 1) + } + } + compareVersions(javaSpecVersion, version, 0) match { + case -2 => throw new NumberFormatException(s"Not a version: $version") + case i => i >= 0 } - val (v, _v) = parts(version) - val (s, _s) = parts(javaSpecVersion) - s.toInt >= v.toInt && _s.toInt >= _v.toInt } // provide a main method so version info can be obtained by running this diff --git a/src/library/scala/util/Random.scala b/src/library/scala/util/Random.scala index 2d38c9d4a0..16d18d7d6d 100644 --- a/src/library/scala/util/Random.scala +++ b/src/library/scala/util/Random.scala @@ -121,9 +121,6 @@ class Random(val self: java.util.Random) extends AnyRef with Serializable { (bf(xs) ++= buf).result() } - @deprecated("Preserved for backwards binary compatibility. To remove in 2.12.x.", "2.11.6") - final def `scala$util$Random$$isAlphaNum$1`(c: Char) = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') - /** Returns a Stream of pseudorandomly chosen alphanumeric characters, * equally chosen from A-Z, a-z, and 0-9. * diff --git a/src/library/scala/util/Sorting.scala b/src/library/scala/util/Sorting.scala index b4f965f69b..3bda7c0d39 100644 --- a/src/library/scala/util/Sorting.scala +++ b/src/library/scala/util/Sorting.scala @@ -45,7 +45,7 @@ object Sorting { /** Sort an array of Floats using `java.util.Arrays.sort`. */ def quickSort(a: Array[Float]): Unit = java.util.Arrays.sort(a) - + private final val qsortThreshold = 16 /** Sort array `a` with quicksort, using the Ordering on its elements. @@ -57,9 +57,9 @@ object Sorting { def inner(a: Array[K], i0: Int, iN: Int, ord: Ordering[K]): Unit = { if (iN - i0 < qsortThreshold) insertionSort(a, i0, iN, ord) else { - var iK = (i0 + iN) >>> 1 // Unsigned div by 2 + val iK = (i0 + iN) >>> 1 // Unsigned div by 2 // Find index of median of first, central, and last elements - var pL = + var pL = if (ord.compare(a(i0), a(iN - 1)) <= 0) if (ord.compare(a(i0), a(iK)) < 0) if (ord.compare(a(iN - 1), a(iK)) < 0) iN - 1 else iK @@ -140,9 +140,9 @@ object Sorting { } inner(a, 0, a.length, implicitly[Ordering[K]]) } - + private final val mergeThreshold = 32 - + // Ordering[T] might be slow especially for boxed primitives, so use binary search variant of insertion sort // Caller must pass iN >= i0 or math will fail. Also, i0 >= 0. private def insertionSort[@specialized T](a: Array[T], i0: Int, iN: Int, ord: Ordering[T]): Unit = { @@ -176,7 +176,7 @@ object Sorting { m += 1 } } - + // Caller is required to pass iN >= i0, else math will fail. Also, i0 >= 0. private def mergeSort[@specialized T: ClassTag](a: Array[T], i0: Int, iN: Int, ord: Ordering[T], scratch: Array[T] = null): Unit = { if (iN - i0 < mergeThreshold) insertionSort(a, i0, iN, ord) @@ -188,7 +188,7 @@ object Sorting { mergeSorted(a, i0, iK, iN, ord, sc) } } - + // Must have 0 <= i0 < iK < iN private def mergeSorted[@specialized T](a: Array[T], i0: Int, iK: Int, iN: Int, ord: Ordering[T], scratch: Array[T]): Unit = { // Check to make sure we're not already in order @@ -212,7 +212,7 @@ object Sorting { // Don't need to finish a(i) because it's already in place, k = i } } - + // Why would you even do this? private def booleanSort(a: Array[Boolean]): Unit = { var i = 0 @@ -235,7 +235,7 @@ object Sorting { // TODO: add upper bound: T <: AnyRef, propagate to callers below (not binary compatible) // Maybe also rename all these methods to `sort`. @inline private def sort[T](a: Array[T], ord: Ordering[T]): Unit = a match { - case _: Array[AnyRef] => + case _: Array[AnyRef] => // Note that runtime matches are covariant, so could actually be any Array[T] s.t. T is not primitive (even boxed value classes) if (a.length > 1 && (ord eq null)) throw new NullPointerException("Ordering") java.util.Arrays.sort(a, ord) diff --git a/src/library/scala/util/Try.scala b/src/library/scala/util/Try.scala index b0eae74043..00e9585c38 100644 --- a/src/library/scala/util/Try.scala +++ b/src/library/scala/util/Try.scala @@ -9,9 +9,7 @@ package scala package util -import scala.collection.Seq import scala.util.control.NonFatal -import scala.language.implicitConversions /** * The `Try` type represents a computation that may either result in an exception, or return a @@ -61,7 +59,7 @@ import scala.language.implicitConversions * @author based on Twitter's original implementation in com.twitter.util. * @since 2.10 */ -sealed abstract class Try[+T] { +sealed abstract class Try[+T] extends Product with Serializable { /** Returns `true` if the `Try` is a `Failure`, `false` otherwise. */ @@ -75,16 +73,11 @@ sealed abstract class Try[+T] { * * ''Note:'': This will throw an exception if it is not a success and default throws an exception. */ - def getOrElse[U >: T](default: => U): U = - if (isSuccess) get else default + def getOrElse[U >: T](default: => U): U /** Returns this `Try` if it's a `Success` or the given `default` argument if this is a `Failure`. */ - def orElse[U >: T](default: => Try[U]): Try[U] = - try if (isSuccess) this else default - catch { - case NonFatal(e) => Failure(e) - } + def orElse[U >: T](default: => Try[U]): Try[U] /** Returns the value from this `Success` or throws the exception if this is a `Failure`. */ @@ -108,6 +101,11 @@ sealed abstract class Try[+T] { def map[U](f: T => U): Try[U] /** + * Applies the given partial function to the value from this `Success` or returns this if this is a `Failure`. + */ + def collect[U](pf: PartialFunction[T, U]): Try[U] + + /** * Converts this to a `Failure` if the predicate is not satisfied. */ def filter(p: T => Boolean): Try[T] @@ -134,6 +132,7 @@ sealed abstract class Try[+T] { * collection" contract even though it seems unlikely to matter much in a * collection with max size 1. */ + @deprecatedInheritance("You were never supposed to be able to extend this class.", "2.12.0") class WithFilter(p: T => Boolean) { def map[U](f: T => U): Try[U] = Try.this filter p map f def flatMap[U](f: T => Try[U]): Try[U] = Try.this filter p flatMap f @@ -145,18 +144,18 @@ sealed abstract class Try[+T] { * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`. * This is like `flatMap` for the exception. */ - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] + def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] /** * Applies the given function `f` if this is a `Failure`, otherwise returns this if this is a `Success`. * This is like map for the exception. */ - def recover[U >: T](f: PartialFunction[Throwable, U]): Try[U] + def recover[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, U]): Try[U] /** * Returns `None` if this is a `Failure` or a `Some` containing the value if this is a `Success`. */ - def toOption: Option[T] = if (isSuccess) Some(get) else None + def toOption: Option[T] /** * Transforms a nested `Try`, ie, a `Try` of type `Try[Try[T]]`, @@ -173,13 +172,31 @@ sealed abstract class Try[+T] { /** Completes this `Try` by applying the function `f` to this if this is of type `Failure`, or conversely, by applying * `s` if this is a `Success`. */ - def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = - try this match { - case Success(v) => s(v) - case Failure(e) => f(e) - } catch { - case NonFatal(e) => Failure(e) - } + def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] + + /** + * Returns `Left` with `Throwable` if this is a `Failure`, otherwise returns `Right` with `Success` value. + */ + def toEither: Either[Throwable, T] + + /** + * Applies `fa` if this is a `Failure` or `fb` if this is a `Success`. + * If `fb` is initially applied and throws an exception, + * then `fa` is applied with this exception. + * + * @example {{{ + * val result: Try[Throwable, Int] = Try { string.toInt } + * log(result.fold( + * ex => "Operation failed with " + ex, + * v => "Operation produced value: " + v + * )) + * }}} + * + * @param fa the function to apply if this is a `Failure` + * @param fb the function to apply if this is a `Success` + * @return the results of applying the function + */ + def fold[U](fa: Throwable => U, fb: T => U): U } @@ -192,57 +209,60 @@ object Try { try Success(r) catch { case NonFatal(e) => Failure(e) } - } final case class Failure[+T](exception: Throwable) extends Try[T] { - def isFailure: Boolean = true - def isSuccess: Boolean = false - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = - try { - if (f isDefinedAt exception) f(exception) else this - } catch { - case NonFatal(e) => Failure(e) - } - def get: T = throw exception - def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] - def foreach[U](f: T => U): Unit = () - def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] - def filter(p: T => Boolean): Try[T] = this - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = - try { - if (rescueException isDefinedAt exception) { - Try(rescueException(exception)) - } else this - } catch { - case NonFatal(e) => Failure(e) - } - def failed: Try[Throwable] = Success(exception) + override def isFailure: Boolean = true + override def isSuccess: Boolean = false + override def get: T = throw exception + override def getOrElse[U >: T](default: => U): U = default + override def orElse[U >: T](default: => Try[U]): Try[U] = + try default catch { case NonFatal(e) => Failure(e) } + override def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]] + override def flatten[U](implicit ev: T <:< Try[U]): Try[U] = this.asInstanceOf[Try[U]] + override def foreach[U](f: T => U): Unit = () + override def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = + try f(exception) catch { case NonFatal(e) => Failure(e) } + override def map[U](f: T => U): Try[U] = this.asInstanceOf[Try[U]] + override def collect[U](pf: PartialFunction[T, U]): Try[U] = this.asInstanceOf[Try[U]] + override def filter(p: T => Boolean): Try[T] = this + override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] = + try { if (pf isDefinedAt exception) Success(pf(exception)) else this } catch { case NonFatal(e) => Failure(e) } + override def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] = + try { if (pf isDefinedAt exception) pf(exception) else this } catch { case NonFatal(e) => Failure(e) } + override def failed: Try[Throwable] = Success(exception) + override def toOption: Option[T] = None + override def toEither: Either[Throwable, T] = Left(exception) + override def fold[U](fa: Throwable => U, fb: T => U): U = fa(exception) } final case class Success[+T](value: T) extends Try[T] { - def isFailure: Boolean = false - def isSuccess: Boolean = true - def recoverWith[U >: T](f: PartialFunction[Throwable, Try[U]]): Try[U] = this - def get = value - def flatMap[U](f: T => Try[U]): Try[U] = - try f(value) - catch { - case NonFatal(e) => Failure(e) - } - def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value - def foreach[U](f: T => U): Unit = f(value) - def map[U](f: T => U): Try[U] = Try[U](f(value)) - def filter(p: T => Boolean): Try[T] = { + override def isFailure: Boolean = false + override def isSuccess: Boolean = true + override def get = value + override def getOrElse[U >: T](default: => U): U = get + override def orElse[U >: T](default: => Try[U]): Try[U] = this + override def flatMap[U](f: T => Try[U]): Try[U] = + try f(value) catch { case NonFatal(e) => Failure(e) } + override def flatten[U](implicit ev: T <:< Try[U]): Try[U] = value + override def foreach[U](f: T => U): Unit = f(value) + override def transform[U](s: T => Try[U], f: Throwable => Try[U]): Try[U] = this flatMap s + override def map[U](f: T => U): Try[U] = Try[U](f(value)) + override def collect[U](pf: PartialFunction[T, U]): Try[U] = try { - if (p(value)) this + if (pf isDefinedAt value) Success(pf(value)) else Failure(new NoSuchElementException("Predicate does not hold for " + value)) - } catch { - case NonFatal(e) => Failure(e) - } - } - def recover[U >: T](rescueException: PartialFunction[Throwable, U]): Try[U] = this - def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) + } catch { case NonFatal(e) => Failure(e) } + override def filter(p: T => Boolean): Try[T] = + try { + if (p(value)) this else Failure(new NoSuchElementException("Predicate does not hold for " + value)) + } catch { case NonFatal(e) => Failure(e) } + override def recover[U >: T](@deprecatedName('rescueException) pf: PartialFunction[Throwable, U]): Try[U] = this + override def recoverWith[U >: T](@deprecatedName('f) pf: PartialFunction[Throwable, Try[U]]): Try[U] = this + override def failed: Try[Throwable] = Failure(new UnsupportedOperationException("Success.failed")) + override def toOption: Option[T] = Some(value) + override def toEither: Either[Throwable, T] = Right(value) + override def fold[U](fa: Throwable => U, fb: T => U): U = + try { fb(value) } catch { case NonFatal(e) => fa(e) } } diff --git a/src/library/scala/util/control/Exception.scala b/src/library/scala/util/control/Exception.scala index 24c297a2fc..64f491d7f0 100644 --- a/src/library/scala/util/control/Exception.scala +++ b/src/library/scala/util/control/Exception.scala @@ -10,26 +10,139 @@ package scala package util package control -import scala.collection.immutable.List import scala.reflect.{ ClassTag, classTag } -import java.lang.reflect.InvocationTargetException import scala.language.implicitConversions - /** Classes representing the components of exception handling. - * Each class is independently composable. Some example usages: + * + * Each class is independently composable. + * + * This class differs from [[scala.util.Try]] in that it focuses on composing exception handlers rather than + * composing behavior. All behavior should be composed first and fed to a [[Catch]] object using one of the + * `opt`, `either` or `withTry` methods. Taken together the classes provide a DSL for composing catch and finally + * behaviors. + * + * === Examples === + * + * Create a `Catch` which handles specified exceptions. * {{{ * import scala.util.control.Exception._ * import java.net._ * * val s = "http://www.scala-lang.org/" - * val x1 = catching(classOf[MalformedURLException]) opt new URL(s) - * val x2 = catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s) + * + * // Some(http://www.scala-lang.org/) + * val x1: Option[URL] = catching(classOf[MalformedURLException]) opt new URL(s) + * + * // Right(http://www.scala-lang.org/) + * val x2: Either[Throwable,URL] = + * catching(classOf[MalformedURLException], classOf[NullPointerException]) either new URL(s) + * + * // Success(http://www.scala-lang.org/) + * val x3: Try[URL] = catching(classOf[MalformedURLException], classOf[NullPointerException]) withTry new URL(s) + * + * val defaultUrl = new URL("http://example.com") + * // URL(http://example.com) because htt/xx throws MalformedURLException + * val x4: URL = failAsValue(classOf[MalformedURLException])(defaultUrl)(new URL("htt/xx")) + * }}} + * + * Create a `Catch` which logs exceptions using `handling` and `by`. + * {{{ + * def log(t: Throwable): Unit = t.printStackTrace + * + * val withThrowableLogging: Catch[Unit] = handling(classOf[MalformedURLException]) by (log) + * + * def printUrl(url: String) : Unit = { + * val con = new URL(url) openConnection() + * val source = scala.io.Source.fromInputStream(con.getInputStream()) + * source.getLines.foreach(println) + * } + * + * val badUrl = "htt/xx" + * // Prints stacktrace, + * // java.net.MalformedURLException: no protocol: htt/xx + * // at java.net.URL.<init>(URL.java:586) + * withThrowableLogging { printUrl(badUrl) } + * + * val goodUrl = "http://www.scala-lang.org/" + * // Prints page content, + * // <!DOCTYPE html> + * // <html> + * withThrowableLogging { printUrl(goodUrl) } + * }}} + * + * Use `unwrapping` to create a `Catch` that unwraps exceptions before rethrowing. + * {{{ + * class AppException(cause: Throwable) extends RuntimeException(cause) + * + * val unwrappingCatch: Catch[Nothing] = unwrapping(classOf[AppException]) + * + * def calcResult: Int = throw new AppException(new NullPointerException) + * + * // Throws NPE not AppException, + * // java.lang.NullPointerException + * // at .calcResult(<console>:17) + * val result = unwrappingCatch(calcResult) + * }}} + * + * Use `failAsValue` to provide a default when a specified exception is caught. + * + * {{{ + * val inputDefaulting: Catch[Int] = failAsValue(classOf[NumberFormatException])(0) + * val candidatePick = "seven" // scala.io.StdIn.readLine() + * + * // Int = 0 + * val pick = inputDefaulting(candidatePick.toInt) + * }}} + * + * Compose multiple `Catch`s with `or` to build a `Catch` that provides default values varied by exception. + * {{{ + * val formatDefaulting: Catch[Int] = failAsValue(classOf[NumberFormatException])(0) + * val nullDefaulting: Catch[Int] = failAsValue(classOf[NullPointerException])(-1) + * val otherDefaulting: Catch[Int] = nonFatalCatch withApply(_ => -100) + * + * val combinedDefaulting: Catch[Int] = formatDefaulting or nullDefaulting or otherDefaulting + * + * def p(s: String): Int = s.length * s.toInt + * + * // Int = 0 + * combinedDefaulting(p("tenty-nine")) + * + * // Int = -1 + * combinedDefaulting(p(null: String)) + * + * // Int = -100 + * combinedDefaulting(throw new IllegalStateException) + * + * // Int = 22 + * combinedDefaulting(p("11")) * }}} * - * This class differs from `scala.util.Try` in that it focuses on composing exception handlers rather than - * composing behavior. All behavior should be composed first and fed to a `Catch` object using one of the - * `opt` or `either` methods. + * @groupname composition-catch Catch behavior composition + * @groupprio composition-catch 10 + * @groupdesc composition-catch Build Catch objects from exception lists and catch logic + * + * @groupname composition-finally Finally behavior composition + * @groupprio composition-finally 20 + * @groupdesc composition-finally Build Catch objects from finally logic + * + * @groupname canned-behavior General purpose catch objects + * @groupprio canned-behavior 30 + * @groupdesc canned-behavior Catch objects with predefined behavior. Use combinator methods to compose additional behavior. + * + * @groupname dsl DSL behavior composition + * @groupprio dsl 40 + * @groupdesc dsl Expressive Catch behavior composition + * + * @groupname composition-catch-promiscuously Promiscuous Catch behaviors + * @groupprio composition-catch-promiscuously 50 + * @groupdesc composition-catch-promiscuously Useful if catching `ControlThrowable` or `InterruptedException` is required. + * + * @groupname logic-container Logic Containers + * @groupprio logic-container 60 + * @groupdesc logic-container Containers for catch and finally behavior. + * + * @define protectedExceptions `ControlThrowable` or `InterruptedException` * * @author Paul Phillips */ @@ -53,6 +166,7 @@ object Exception { /** !!! Not at all sure of every factor which goes into this, * and/or whether we need multiple standard variations. + * @return true if `x` is $protectedExceptions otherwise false. */ def shouldRethrow(x: Throwable): Boolean = x match { case _: ControlThrowable => true @@ -72,7 +186,9 @@ object Exception { override def toString() = name + "(" + desc + ")" } - /** A container class for finally code. */ + /** A container class for finally code. + * @group logic-container + */ class Finally private[Exception](body: => Unit) extends Described { protected val name = "Finally" @@ -85,6 +201,11 @@ object Exception { * Pass a different value for rethrow if you want to probably * unwisely allow catching control exceptions and other throwables * which the rest of the world may expect to get through. + * @tparam T result type of bodies used in try and catch blocks + * @param pf Partial function used when applying catch logic to determine result value + * @param fin Finally logic which if defined will be invoked after catch logic + * @param rethrow Predicate on throwables determining when to rethrow a caught [[Throwable]] + * @group logic-container */ class Catch[+T]( val pf: Catcher[T], @@ -107,10 +228,12 @@ object Exception { } finally fin foreach (_.invoke()) - /* Create an empty Try container with this Catch and the supplied `Finally`. */ - def andFinally(body: => Unit): Catch[T] = fin match { - case None => new Catch(pf, Some(new Finally(body)), rethrow) - case Some(f) => new Catch(pf, Some(f and body), rethrow) + /** Create a new Catch container from this object and the supplied finally body. + * @param body The additional logic to apply after all existing finally bodies + */ + def andFinally(body: => Unit): Catch[T] = { + val appendedFin = fin map(_ and body) getOrElse new Finally(body) + new Catch(pf, Some(appendedFin), rethrow) } /** Apply this catch logic to the supplied body, mapping the result @@ -119,13 +242,13 @@ object Exception { def opt[U >: T](body: => U): Option[U] = toOption(Some(body)) /** Apply this catch logic to the supplied body, mapping the result - * into Either[Throwable, T] - Left(exception) if an exception was caught, - * Right(T) otherwise. + * into `Either[Throwable, T]` - `Left(exception)` if an exception was caught, + * `Right(T)` otherwise. */ def either[U >: T](body: => U): Either[Throwable, U] = toEither(Right(body)) /** Apply this catch logic to the supplied body, mapping the result - * into Try[T] - Failure if an exception was caught, Success(T) otherwise. + * into `Try[T]` - `Failure` if an exception was caught, `Success(T)` otherwise. */ def withTry[U >: T](body: => U): scala.util.Try[U] = toTry(Success(body)) @@ -149,23 +272,30 @@ object Exception { final def nonFatalCatcher[T]: Catcher[T] = mkThrowableCatcher({ case NonFatal(_) => true; case _ => false }, throw _) final def allCatcher[T]: Catcher[T] = mkThrowableCatcher(_ => true, throw _) - /** The empty `Catch` object. */ + /** The empty `Catch` object. + * @group canned-behavior + **/ final val noCatch: Catch[Nothing] = new Catch(nothingCatcher) withDesc "<nothing>" - /** A `Catch` object which catches everything. */ + /** A `Catch` object which catches everything. + * @group canned-behavior + **/ final def allCatch[T]: Catch[T] = new Catch(allCatcher[T]) withDesc "<everything>" - /** A `Catch` object which catches non-fatal exceptions. */ + /** A `Catch` object which catches non-fatal exceptions. + * @group canned-behavior + **/ final def nonFatalCatch[T]: Catch[T] = new Catch(nonFatalCatcher[T]) withDesc "<non-fatal>" /** Creates a `Catch` object which will catch any of the supplied exceptions. * Since the returned `Catch` object has no specific logic defined and will simply - * rethrow the exceptions it catches, you will typically want to call `opt` or - * `either` on the return value, or assign custom logic by calling "withApply". + * rethrow the exceptions it catches, you will typically want to call `opt`, + * `either` or `withTry` on the return value, or assign custom logic by calling "withApply". * * Note that `Catch` objects automatically rethrow `ControlExceptions` and others * which should only be caught in exceptional circumstances. If you really want * to catch exactly what you specify, use `catchingPromiscuously` instead. + * @group composition-catch */ def catching[T](exceptions: Class[_]*): Catch[T] = new Catch(pfFromExceptions(exceptions : _*)) withDesc (exceptions map (_.getName) mkString ", ") @@ -174,42 +304,56 @@ object Exception { /** Creates a `Catch` object which will catch any of the supplied exceptions. * Unlike "catching" which filters out those in shouldRethrow, this one will - * catch whatever you ask of it: `ControlThrowable`, `InterruptedException`, - * `OutOfMemoryError`, you name it. + * catch whatever you ask of it including $protectedExceptions. + * @group composition-catch-promiscuously */ def catchingPromiscuously[T](exceptions: Class[_]*): Catch[T] = catchingPromiscuously(pfFromExceptions(exceptions : _*)) def catchingPromiscuously[T](c: Catcher[T]): Catch[T] = new Catch(c, None, _ => false) - /** Creates a `Catch` object which catches and ignores any of the supplied exceptions. */ + /** Creates a `Catch` object which catches and ignores any of the supplied exceptions. + * @group composition-catch + */ def ignoring(exceptions: Class[_]*): Catch[Unit] = catching(exceptions: _*) withApply (_ => ()) - /** Creates a `Catch` object which maps all the supplied exceptions to `None`. */ + /** Creates a `Catch` object which maps all the supplied exceptions to `None`. + * @group composition-catch + */ def failing[T](exceptions: Class[_]*): Catch[Option[T]] = catching(exceptions: _*) withApply (_ => None) - /** Creates a `Catch` object which maps all the supplied exceptions to the given value. */ + /** Creates a `Catch` object which maps all the supplied exceptions to the given value. + * @group composition-catch + */ def failAsValue[T](exceptions: Class[_]*)(value: => T): Catch[T] = catching(exceptions: _*) withApply (_ => value) + class By[T,R](f: T => R) { + def by(x: T): R = f(x) + } + /** Returns a partially constructed `Catch` object, which you must give - * an exception handler function as an argument to `by`. Example: + * an exception handler function as an argument to `by`. + * @example * {{{ - * handling(ex1, ex2) by (_.printStackTrace) + * handling(classOf[MalformedURLException], classOf[NullPointerException]) by (_.printStackTrace) * }}} + * @group dsl */ - class By[T,R](f: T => R) { - def by(x: T): R = f(x) - } + // TODO: Add return type def handling[T](exceptions: Class[_]*) = { def fun(f: Throwable => T) = catching(exceptions: _*) withApply f new By[Throwable => T, Catch[T]](fun _) } - /** Returns a `Catch` object with no catch logic and the argument as `Finally`. */ + /** Returns a `Catch` object with no catch logic and the argument as the finally logic. + * @group composition-finally + */ def ultimately[T](body: => Unit): Catch[T] = noCatch andFinally body - /** Creates a `Catch` object which unwraps any of the supplied exceptions. */ + /** Creates a `Catch` object which unwraps any of the supplied exceptions. + * @group composition-catch + */ def unwrapping[T](exceptions: Class[_]*): Catch[T] = { def unwrap(x: Throwable): Throwable = if (wouldMatch(x, exceptions) && x.getCause != null) unwrap(x.getCause) diff --git a/src/library/scala/util/control/NoStackTrace.scala b/src/library/scala/util/control/NoStackTrace.scala index b33b6a18dd..3647af4ac3 100644 --- a/src/library/scala/util/control/NoStackTrace.scala +++ b/src/library/scala/util/control/NoStackTrace.scala @@ -14,6 +14,8 @@ package util.control * on a global basis via a system property wrapper in * [[scala.sys.SystemProperties]]. * + * @note Since JDK 1.7, a similar effect can be achieved with `class Ex extends Throwable(..., writableStackTrace = false)` + * * @author Paul Phillips * @since 2.8 */ @@ -26,7 +28,7 @@ trait NoStackTrace extends Throwable { object NoStackTrace { final def noSuppression = _noSuppression - // two-stage init to make checkinit happy, since sys.SystemProperties.noTraceSupression.value calls back into NoStackTrace.noSuppression + // two-stage init to make checkinit happy, since sys.SystemProperties.noTraceSuppression.value calls back into NoStackTrace.noSuppression final private var _noSuppression = false - _noSuppression = sys.SystemProperties.noTraceSupression.value + _noSuppression = sys.SystemProperties.noTraceSuppression.value } diff --git a/src/library/scala/util/control/TailCalls.scala b/src/library/scala/util/control/TailCalls.scala index 953d5b407e..c7fefb1eba 100644 --- a/src/library/scala/util/control/TailCalls.scala +++ b/src/library/scala/util/control/TailCalls.scala @@ -55,7 +55,7 @@ object TailCalls { case Done(a) => Call(() => f(a)) case c@Call(_) => Cont(c, f) // Take advantage of the monad associative law to optimize the size of the required stack - case c: Cont[a1, b1] => Cont(c.a, (x: a1) => c f x flatMap f) + case c: Cont[a1, b1] => Cont(c.a, (x: a1) => c.f(x) flatMap f) } /** Returns either the next step of the tailcalling computation, diff --git a/src/library/scala/util/hashing/MurmurHash3.scala b/src/library/scala/util/hashing/MurmurHash3.scala index 6a56910451..fa725903e3 100644 --- a/src/library/scala/util/hashing/MurmurHash3.scala +++ b/src/library/scala/util/hashing/MurmurHash3.scala @@ -212,6 +212,9 @@ object MurmurHash3 extends MurmurHash3 { def stringHash(x: String): Int = stringHash(x, stringSeed) def unorderedHash(xs: TraversableOnce[Any]): Int = unorderedHash(xs, traversableSeed) + private[scala] def wrappedArrayHash[@specialized T](a: Array[T]): Int = arrayHash(a, seqSeed) + private[scala] def wrappedBytesHash(data: Array[Byte]): Int = bytesHash(data, seqSeed) + /** To offer some potential for optimization. */ def seqHash(xs: scala.collection.Seq[_]): Int = xs match { diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 6d3d015b1a..4822fe02b4 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -11,21 +11,14 @@ * with the main goal of pulling out information from those matches, or replacing * them with something else. * - * There are four classes and three objects, with most of them being members of - * Regex companion object. [[scala.util.matching.Regex]] is the class users instantiate - * to do regular expression matching. + * [[scala.util.matching.Regex]] is the class users instantiate to do regular expression matching. * - * The remaining classes and objects in the package are used in the following way: - * - * * The companion object to [[scala.util.matching.Regex]] just contains the other members. + * The companion object to [[scala.util.matching.Regex]] contains supporting members: * * [[scala.util.matching.Regex.Match]] makes more information about a match available. - * * [[scala.util.matching.Regex.MatchIterator]] is used to iterate over multiple matches. + * * [[scala.util.matching.Regex.MatchIterator]] is used to iterate over matched strings. * * [[scala.util.matching.Regex.MatchData]] is just a base trait for the above classes. * * [[scala.util.matching.Regex.Groups]] extracts group from a [[scala.util.matching.Regex.Match]] * without recomputing the match. - * * [[scala.util.matching.Regex.Match]] converts a [[scala.util.matching.Regex.Match]] - * into a [[java.lang.String]]. - * */ package scala.util.matching @@ -35,6 +28,7 @@ import java.util.regex.{ Pattern, Matcher } /** A regular expression is used to determine whether a string matches a pattern * and, if it does, to extract or transform the parts that match. * + * === Usage === * This class delegates to the [[java.util.regex]] package of the Java Platform. * See the documentation for [[java.util.regex.Pattern]] for details about * the regular expression syntax for pattern strings. @@ -47,12 +41,15 @@ import java.util.regex.{ Pattern, Matcher } * implicitly for strings: * * {{{ - * val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r + * val date = raw"(\d{4})-(\d{2})-(\d{2})".r * }}} * * Since escapes are not processed in multi-line string literals, using triple quotes * avoids having to escape the backslash character, so that `"\\d"` can be written `"""\d"""`. + * The same result is achieved with certain interpolators, such as `raw"\d".r` or + * a custom interpolator `r"\d"` that also compiles the `Regex`. * + * === Extraction === * To extract the capturing groups when a `Regex` is matched, use it as * an extractor in a pattern match: * @@ -92,48 +89,80 @@ import java.util.regex.{ Pattern, Matcher } * } * }}} * + * === Find Matches === * To find or replace matches of the pattern, use the various find and replace methods. - * There is a flavor of each method that produces matched strings and - * another that produces `Match` objects. + * For each method, there is a version for working with matched strings and + * another for working with `Match` objects. * * For example, pattern matching with an unanchored `Regex`, as in the previous example, - * is the same as using `findFirstMatchIn`, except that the findFirst methods return an `Option`, - * or `None` for no match: + * can also be accomplished using `findFirstMatchIn`. The `findFirst` methods return an `Option` + * which is non-empty if a match is found, or `None` for no match: * * {{{ * val dates = "Important dates in history: 2004-01-20, 1958-09-05, 2010-10-06, 2011-07-15" - * val firstDate = date findFirstIn dates getOrElse "No date found." - * val firstYear = for (m <- date findFirstMatchIn dates) yield m group 1 + * val firstDate = date.findFirstIn(dates).getOrElse("No date found.") + * val firstYear = for (m <- date.findFirstMatchIn(dates)) yield m.group(1) * }}} * * To find all matches: * * {{{ - * val allYears = for (m <- date findAllMatchIn dates) yield m group 1 + * val allYears = for (m <- date.findAllMatchIn(dates)) yield m.group(1) + * }}} + * + * To iterate over the matched strings, use `findAllIn`, which returns a special iterator + * that can be queried for the `MatchData` of the last match: + * + * {{{ + * val mi = date.findAllIn(dates) + * while (mi.hasNext) { + * val d = mi.next + * if (mi.group(1).toInt < 1960) println(s"$d: An oldie but goodie.") + * } * }}} * - * But `findAllIn` returns a special iterator of strings that can be queried for the `MatchData` - * of the last match: + * Although the `MatchIterator` returned by `findAllIn` is used like any `Iterator`, + * with alternating calls to `hasNext` and `next`, `hasNext` has the additional + * side effect of advancing the underlying matcher to the next unconsumed match. + * This effect is visible in the `MatchData` representing the "current match". * * {{{ - * val mi = date findAllIn dates - * val oldies = mi filter (_ => (mi group 1).toInt < 1960) map (s => s"$s: An oldie but goodie.") + * val r = "(ab+c)".r + * val s = "xxxabcyyyabbczzz" + * r.findAllIn(s).start // 3 + * val mi = r.findAllIn(s) + * mi.hasNext // true + * mi.start // 3 + * mi.next() // "abc" + * mi.start // 3 + * mi.hasNext // true + * mi.start // 9 + * mi.next() // "abbc" * }}} * + * The example shows that methods on `MatchData` such as `start` will advance to + * the first match, if necessary. It also shows that `hasNext` will advance to + * the next unconsumed match, if `next` has already returned the current match. + * + * The current `MatchData` can be captured using the `matchData` method. + * Alternatively, `findAllMatchIn` returns an `Iterator[Match]`, where there + * is no interaction between the iterator and `Match` objects it has already produced. + * * Note that `findAllIn` finds matches that don't overlap. (See [[findAllIn]] for more examples.) * * {{{ - * val num = """(\d+)""".r - * val all = (num findAllIn "123").toList // List("123"), not List("123", "23", "3") + * val num = raw"(\d+)".r + * val all = num.findAllIn("123").toList // List("123"), not List("123", "23", "3") * }}} * + * === Replace Text === * Text replacement can be performed unconditionally or as a function of the current match: * * {{{ - * val redacted = date replaceAllIn (dates, "XXXX-XX-XX") - * val yearsOnly = date replaceAllIn (dates, m => m group 1) - * val months = (0 to 11) map { i => val c = Calendar.getInstance; c.set(2014, i, 1); f"$c%tb" } - * val reformatted = date replaceAllIn (dates, _ match { case date(y,m,d) => f"${months(m.toInt - 1)} $d, $y" }) + * val redacted = date.replaceAllIn(dates, "XXXX-XX-XX") + * val yearsOnly = date.replaceAllIn(dates, m => m.group(1)) + * val months = (0 to 11).map { i => val c = Calendar.getInstance; c.set(2014, i, 1); f"$c%tb" } + * val reformatted = date.replaceAllIn(dates, _ match { case date(y,m,d) => f"${months(m.toInt - 1)} $d, $y" }) * }}} * * Pattern matching the `Match` against the `Regex` that created it does not reapply the `Regex`. @@ -142,7 +171,7 @@ import java.util.regex.{ Pattern, Matcher } * * {{{ * val docSpree = """2011(?:-\d{2}){2}""".r - * val docView = date replaceAllIn (dates, _ match { + * val docView = date.replaceAllIn(dates, _ match { * case docSpree() => "Historic doc spree!" * case _ => "Something else happened" * }) @@ -182,6 +211,9 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * val namedYears = for (m <- namedDate findAllMatchIn dates) yield m group "year" * }}} * + * Group names supplied to the constructor are preferred to inline group names + * when retrieving matched groups by name. Not all platforms support inline names. + * * This constructor does not support options as flags, which must be * supplied as inline flags in the pattern string: `(?idmsux-idmsux)`. * @@ -305,7 +337,7 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * @param target The string to match * @return The matches */ - @deprecated("Extracting a match result from anything but a CharSequence or Match is deprecated", "2.11.0") + @deprecated("extracting a match result from anything but a CharSequence or Match is deprecated", "2.11.0") def unapplySeq(target: Any): Option[List[String]] = target match { case s: CharSequence => val m = pattern matcher s @@ -318,16 +350,16 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends // @see UnanchoredRegex protected def runMatcher(m: Matcher) = m.matches() - /** Return all non-overlapping matches of this `Regex` in the given character + /** Return all non-overlapping matches of this `Regex` in the given character * sequence as a [[scala.util.matching.Regex.MatchIterator]], * which is a special [[scala.collection.Iterator]] that returns the * matched strings but can also be queried for more data about the last match, * such as capturing groups and start position. - * + * * A `MatchIterator` can also be converted into an iterator * that returns objects of type [[scala.util.matching.Regex.Match]], * such as is normally returned by `findAllMatchIn`. - * + * * Where potential matches overlap, the first possible match is returned, * followed by the next match that follows the input consumed by the * first match: @@ -335,8 +367,8 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * {{{ * val hat = "hat[^a]+".r * val hathaway = "hathatthattthatttt" - * val hats = (hat findAllIn hathaway).toList // List(hath, hattth) - * val pos = (hat findAllMatchIn hathaway map (_.start)).toList // List(0, 7) + * val hats = hat.findAllIn(hathaway).toList // List(hath, hattth) + * val pos = hat.findAllMatchIn(hathaway).map(_.start).toList // List(0, 7) * }}} * * To return overlapping matches, it is possible to formulate a regular expression @@ -344,13 +376,13 @@ class Regex private[matching](val pattern: Pattern, groupNames: String*) extends * * {{{ * val madhatter = "(h)(?=(at[^a]+))".r - * val madhats = (madhatter findAllMatchIn hathaway map { + * val madhats = madhatter.findAllMatchIn(hathaway).map { * case madhatter(x,y) => s"$x$y" - * }).toList // List(hath, hatth, hattth, hatttt) + * }.toList // List(hath, hatth, hattth, hatttt) * }}} * - * Attempting to retrieve match information before performing the first match - * or after exhausting the iterator results in [[java.lang.IllegalStateException]]. + * Attempting to retrieve match information after exhausting the iterator + * results in [[java.lang.IllegalStateException]]. * See [[scala.util.matching.Regex.MatchIterator]] for details. * * @param source The text to match against. @@ -578,6 +610,9 @@ object Regex { */ trait MatchData { + /** Basically, wraps a platform Matcher. */ + protected def matcher: Matcher + /** The source from which the match originated */ val source: CharSequence @@ -650,16 +685,25 @@ object Regex { private lazy val nameToIndex: Map[String, Int] = Map[String, Int]() ++ ("" :: groupNames.toList).zipWithIndex - /** Returns the group with given name. + /** Returns the group with the given name. + * + * Uses explicit group names when supplied; otherwise, + * queries the underlying implementation for inline named groups. + * Not all platforms support inline group names. * * @param id The group name * @return The requested group - * @throws NoSuchElementException if the requested group name is not defined + * @throws IllegalArgumentException if the requested group name is not defined */ - def group(id: String): String = nameToIndex.get(id) match { - case None => throw new NoSuchElementException("group name "+id+" not defined") - case Some(index) => group(index) - } + def group(id: String): String = ( + if (groupNames.isEmpty) + matcher group id + else + nameToIndex.get(id) match { + case Some(index) => group(index) + case None => matcher group id + } + ) /** The matched string; equivalent to `matched.toString`. */ override def toString = matched @@ -667,7 +711,7 @@ object Regex { /** Provides information about a successful match. */ class Match(val source: CharSequence, - private[matching] val matcher: Matcher, + protected[matching] val matcher: Matcher, val groupNames: Seq[String]) extends MatchData { /** The index of the first matched character. */ @@ -728,11 +772,13 @@ object Regex { /** A class to step through a sequence of regex matches. * - * All methods inherited from [[scala.util.matching.Regex.MatchData]] will throw - * a [[java.lang.IllegalStateException]] until the matcher is initialized. The - * matcher can be initialized by calling `hasNext` or `next()` or causing these - * methods to be called, such as by invoking `toString` or iterating through - * the iterator's elements. + * This is an iterator that returns the matched strings. + * + * Queries about match data pertain to the current state of the underlying + * matcher, which is advanced by calling `hasNext` or `next`. + * + * When matches are exhausted, queries about match data will throw + * [[java.lang.IllegalStateException]]. * * @see [[java.util.regex.Matcher]] */ @@ -740,37 +786,62 @@ object Regex { extends AbstractIterator[String] with Iterator[String] with MatchData { self => protected[Regex] val matcher = regex.pattern.matcher(source) - private var nextSeen = false - /** Is there another match? */ + // 0 = not yet matched, 1 = matched, 2 = advanced to match, 3 = no more matches + private[this] var nextSeen = 0 + + /** Return true if `next` will find a match. + * As a side effect, advance the underlying matcher if necessary; + * queries about the current match data pertain to the underlying matcher. + */ def hasNext: Boolean = { - if (!nextSeen) nextSeen = matcher.find() - nextSeen + nextSeen match { + case 0 => nextSeen = if (matcher.find()) 1 else 3 + case 1 => () + case 2 => nextSeen = 0 ; hasNext + case 3 => () + } + nextSeen == 1 // otherwise, 3 } - /** The next matched substring of `source`. */ + /** The next matched substring of `source`. + * As a side effect, advance the underlying matcher if necessary. + */ def next(): String = { - if (!hasNext) throw new NoSuchElementException - nextSeen = false + nextSeen match { + case 0 => if (!hasNext) throw new NoSuchElementException ; next() + case 1 => nextSeen = 2 + case 2 => nextSeen = 0 ; next() + case 3 => throw new NoSuchElementException + } matcher.group } + /** Report emptiness. */ override def toString = super[AbstractIterator].toString + // ensure we're at a match + private[this] def ensure(): Unit = nextSeen match { + case 0 => if (!hasNext) throw new IllegalStateException + case 1 => () + case 2 => () + case 3 => throw new IllegalStateException + } + /** The index of the first matched character. */ - def start: Int = matcher.start + def start: Int = { ensure() ; matcher.start } /** The index of the first matched character in group `i`. */ - def start(i: Int): Int = matcher.start(i) + def start(i: Int): Int = { ensure() ; matcher.start(i) } /** The index of the last matched character. */ - def end: Int = matcher.end + def end: Int = { ensure() ; matcher.end } /** The index following the last matched character in group `i`. */ - def end(i: Int): Int = matcher.end(i) + def end(i: Int): Int = { ensure() ; matcher.end(i) } /** The number of subgroups. */ - def groupCount = matcher.groupCount + def groupCount = { ensure() ; matcher.groupCount } /** Convert to an iterator that yields MatchData elements instead of Strings. */ def matchData: Iterator[Match] = new AbstractIterator[Match] { |