scala.runtime.Statics Maven / Gradle / Ivy
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.runtime;
/** Not for public consumption. Usage by the runtime only.
*/
public final class Statics {
public static int mix(int hash, int data) {
int h = mixLast(hash, data);
h = Integer.rotateLeft(h, 13);
return h * 5 + 0xe6546b64;
}
public static int mixLast(int hash, int data) {
int k = data;
k *= 0xcc9e2d51;
k = Integer.rotateLeft(k, 15);
k *= 0x1b873593;
return hash ^ k;
}
public static int finalizeHash(int hash, int length) {
return avalanche(hash ^ length);
}
/** Force all bits of the hash to avalanche. Used for finalizing the hash. */
public static int avalanche(int h) {
h ^= h >>> 16;
h *= 0x85ebca6b;
h ^= h >>> 13;
h *= 0xc2b2ae35;
h ^= h >>> 16;
return h;
}
public static int longHash(long lv) {
int iv = (int)lv;
if (iv == lv)
return iv;
return java.lang.Long.hashCode(lv);
}
public static int doubleHash(double dv) {
int iv = (int)dv;
if (iv == dv)
return iv;
long lv = (long)dv;
if (lv == dv)
return java.lang.Long.hashCode(lv);
float fv = (float)dv;
if (fv == dv)
return java.lang.Float.hashCode(fv);
return java.lang.Double.hashCode(dv);
}
public static int floatHash(float fv) {
int iv = (int)fv;
if (iv == fv)
return iv;
long lv = (long)fv;
if (lv == fv)
return java.lang.Long.hashCode(lv);
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;
if (x instanceof java.lang.Number) {
return anyHashNumber((java.lang.Number) x);
}
return x.hashCode();
}
private static int anyHashNumber(Number x) {
if (x instanceof java.lang.Long)
return longHash(((java.lang.Long)x).longValue());
if (x instanceof java.lang.Double)
return doubleHash(((java.lang.Double)x).doubleValue());
if (x instanceof java.lang.Float)
return floatHash(((java.lang.Float)x).floatValue());
return x.hashCode();
}
}