summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-06-09 15:11:27 +0000
committerPaul Phillips <paulp@improving.org>2009-06-09 15:11:27 +0000
commitf85a6749de6502d4138b4f6013286088c330d74f (patch)
tree02391b6a0ad3e5d96e36166a31b6bd33c29dab29 /src
parent5fa3710faaa8c1f5ae0899ec5b88abca3941d0c9 (diff)
downloadscala-f85a6749de6502d4138b4f6013286088c330d74f.tar.gz
scala-f85a6749de6502d4138b4f6013286088c330d74f.tar.bz2
scala-f85a6749de6502d4138b4f6013286088c330d74f.zip
A couple findbugs inspired bugfixes, and a new ...
A couple findbugs inspired bugfixes, and a new trait scala.util.Hashable, now used by GenericRange.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/library/scala/Range.scala10
-rw-r--r--src/library/scala/util/Hashable.scala55
3 files changed, 65 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala
index 71fe679902..36080c64fa 100644
--- a/src/compiler/scala/tools/nsc/Global.scala
+++ b/src/compiler/scala/tools/nsc/Global.scala
@@ -920,7 +920,7 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable
/** Returns the file with the given suffix for the given class. */
def getFile(clazz: Symbol, suffix: String): File = {
val outdirname = settings.outputDirs.outputDirFor(clazz.sourceFile)
- var outdir = new File(if (outdirname == "") "." else outdirname.path)
+ var outdir = new File(if (outdirname.path == "") "." else outdirname.path)
val filename = clazz.fullNameString('.')
var start = 0
var end = filename.indexOf('.', start)
diff --git a/src/library/scala/Range.scala b/src/library/scala/Range.scala
index 3c8138fb87..d7ee1d7a38 100644
--- a/src/library/scala/Range.scala
+++ b/src/library/scala/Range.scala
@@ -13,6 +13,7 @@ package scala
import collection.immutable.Vector
import collection.generic.VectorView
import util.control.Exception.catching
+import util.Hashable
/** <p>
* <code>GenericRange</code> is a generified version of the
@@ -36,7 +37,7 @@ import util.control.Exception.catching
abstract class GenericRange[T]
(val start: T, val end: T, val step: T, val isInclusive: Boolean = false)
(implicit num: Integral[T])
-extends VectorView[T, Vector[T]] with RangeToString[T] {
+extends VectorView[T, Vector[T]] with RangeToString[T] with Hashable {
import num._
// todo? - we could lift the length restriction by implementing a range as a sequence of
@@ -109,6 +110,13 @@ extends VectorView[T, Vector[T]] with RangeToString[T] {
catching(classOf[ClassCastException]) opt doContains getOrElse super.contains(_x)
}
+
+ // Using trueEnd gives us Range(1, 10, 1).inclusive == Range(1, 11, 1)
+ val hashValues = List(start, trueEnd, step)
+ override def equals(other: Any) = other match {
+ case x: GenericRange[_] => this equalHashValues x
+ case _ => false
+ }
}
private[scala] trait RangeToString[T] extends VectorView[T, Vector[T]] {
diff --git a/src/library/scala/util/Hashable.scala b/src/library/scala/util/Hashable.scala
new file mode 100644
index 0000000000..88d3b72fbd
--- /dev/null
+++ b/src/library/scala/util/Hashable.scala
@@ -0,0 +1,55 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+package scala.util
+
+/** A convenience trait for simplifying hashCode creation.
+ * Mix this into a class and define val hashValues = List(x1, x2, ...)
+ * and your hashCode will be derived from those values. If you define
+ * equals in terms of equalHashValues then your hashCode and equals
+ * methods will never be out of sync. Something like:
+ *
+ * override def equals(other: Any) = other match {
+ * case x: YourClass => this equalHashValues x
+ * case _ => false
+ * }
+ *
+ * @author Paul Phillips
+ */
+abstract trait Hashable extends AnyRef
+{
+ import Hashable._
+ protected def hashValues: List[Any] // in an ideal universe this would be more like List[Hashable]
+ protected def hashSeed: Int = 0
+
+ override def hashCode: Int =
+ (hashValues map calculateHashCode).foldLeft(hashSeed)((x, y) => x * 41 + y)
+
+ protected def equalHashValues(other: Any) = other match {
+ case x: Hashable => hashValues == x.hashValues
+ case _ => false
+ }
+}
+abstract trait StrictHashable extends Hashable
+{
+ protected def hashValues: List[Hashable]
+}
+
+object Hashable
+{
+ /** This implicit is for StrictHashable's benefit, so your hashValues list
+ * can contain both explicitly Hashable classes and value types.
+ */
+ implicit def anyVal2Hashable(x: AnyVal): Hashable =
+ new Hashable { protected def hashValues = List(x) }
+
+ private def calculateHashCode(x: Any) = x match {
+ case null => 0
+ case x: AnyRef => x.hashCode
+ case x => x.asInstanceOf[AnyRef].hashCode
+ }
+} \ No newline at end of file