From f85a6749de6502d4138b4f6013286088c330d74f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Tue, 9 Jun 2009 15:11:27 +0000 Subject: A couple findbugs inspired bugfixes, and a new ... A couple findbugs inspired bugfixes, and a new trait scala.util.Hashable, now used by GenericRange. --- src/compiler/scala/tools/nsc/Global.scala | 2 +- src/library/scala/Range.scala | 10 +++++- src/library/scala/util/Hashable.scala | 55 +++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 src/library/scala/util/Hashable.scala (limited to 'src') 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 /**

* GenericRange 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 -- cgit v1.2.3