Skip to content
Permalink
Browse files

Revert recent commits.

This reverts commit 9b6f51d.
This reverts commit b591910.
  • Loading branch information
paulp committed May 9, 2012
1 parent d459104 commit 1cd498f9091504b42030d4b81c6f659bc386115f
@@ -203,6 +203,67 @@ private static boolean equalsNumChar(java.lang.Number xn, java.lang.Character yc
}
}

/** 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
* verisons 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();
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();
@@ -233,39 +233,12 @@ object ScalaRunTime {
//
// Note that these are the implementations called by ##, so they
// must not call ## themselves.
//
// 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.

@inline def hash(x: Any): Int = x match {
case null => 0
case x: Long => hash(x)
case x: Double => hash(x)
case x: Float => hash(x)
case x: java.lang.Number => hash(x)
case _ => x.hashCode
}

@@ -293,6 +266,7 @@ object ScalaRunTime {
val high = (lv >>> 32).toInt
low ^ (high + lowSign)
}
@inline 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.
@@ -1,23 +1,23 @@
// This only tests direct access to the methods in ScalaRunTime,
// This only tests direct access to the methods in BoxesRunTime,
// not the whole scheme.
object Test
{
import java.{ lang => jl }
import scala.runtime.ScalaRunTime.{ hash }
import scala.runtime.BoxesRunTime.{ hashFromNumber, hashFromObject }

def allSame[T](xs: List[T]) = assert(xs.distinct.size == 1, "failed: " + xs)

def mkNumbers(x: Int): List[Number] =
List(x.toByte, x.toShort, x, x.toLong, x.toFloat, x.toDouble)

def testLDF(x: Long) = allSame(List[Number](x, x.toDouble, x.toFloat) map hash)
def testLDF(x: Long) = allSame(List[Number](x, x.toDouble, x.toFloat) map hashFromNumber)

def main(args: Array[String]): Unit = {
List(Byte.MinValue, -1, 0, 1, Byte.MaxValue) foreach { n =>
val hashes = mkNumbers(n) map hash
val hashes = mkNumbers(n) map hashFromNumber
allSame(hashes)
if (n >= 0) {
val charCode = hash(n.toChar: Character)
val charCode = hashFromObject(n.toChar: Character)
assert(charCode == hashes.head)
}
}
@@ -9,15 +9,7 @@ object Test {

val x = (BigInt(1) << 64).toDouble
val y: Any = x
val f: Float = x.toFloat
val jn: java.lang.Number = x
val jf: java.lang.Float = x.toFloat
val jd: java.lang.Double = x

assert(x.## == y.##, ((x, y)))
assert(x.## == f.##, ((x, f)))
assert(x.## == jn.##, ((x, jn)))
assert(x.## == jf.##, ((x, jf)))
assert(x.## == jd.##, ((x, jd)))
}
}

0 comments on commit 1cd498f

Please sign in to comment.
You can’t perform that action at this time.