All Downloads are FREE. Search and download functionalities are using the official Maven repository.

squidpony.squidmath.CrossHash Maven / Gradle / Ivy

Go to download

SquidLib platform-independent logic and utility code. Please refer to https://github.com/SquidPony/SquidLib .

There is a newer version: 3.0.6
Show newest version
package squidpony.squidmath;

import squidpony.annotation.Beta;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import static squidpony.squidmath.NumberTools.doubleToMixedIntBits;
import static squidpony.squidmath.NumberTools.floatToIntBits;

/**
 * Simple hashing functions that we can rely on staying the same cross-platform.
 * The static methods of this class (not its inner classes) use a custom algorithm
 * designed for speed and general-purpose usability, but not cryptographic security;
 * this algorithm is sometimes referred to as Hive, and several other algorithms are
 * available in static inner classes, some of which have different goals, such as
 * reduced likelihood of successfully reversing a hash, or just providing another
 * choice. The hashes this returns are always 0 when given null to hash. Arrays with
 * identical elements of identical types will hash identically. Arrays with identical
 * numerical values but different types will sometimes hash differently. This class
 * always provides 64-bit hashes via hash64() and 32-bit hashes via hash(), and some
 * of the algorithms here may provide a hash32() method that matches older behavior
 * and uses only 32-bit math. The hash64() and hash() methods, at least in Wisp and
 * Mist, use 64-bit math even when producing 32-bit hashes, for GWT reasons. GWT
 * doesn't have the same behavior as desktop and Android applications when using ints
 * because it treats doubles mostly like ints, sometimes, due to it using JavaScript.
 * If we use mainly longs, though, GWT emulates the longs with a more complex
 * technique behind-the-scenes, that behaves the same on the web as it does on
 * desktop or on a phone. Since CrossHash is supposed to be stable cross-platform,
 * this is the way we need to go, despite it being slightly slower.
 * 
* There are several static inner classes in CrossHash: Lightning, Falcon, and Mist, * each providing different hashing properties, as well as the inner IHasher interface and a * compatibility version of Wisp as a subclass. Older versions of SquidLib encouraged using a * subclass because the non-nested-class methods used a lousy implementation of the FNV-1a algorithm, * which was roughly 10x slower than the current methods in CrossHash and had poor correlation * properties. In the current version, you probably will be fine with the default functions in * CrossHash, using the Wisp algorithm. If you need a salt to alter the hash function, * using one of a large family of such functions instead of a single function like Wisp, then Mist * is a good choice. Lightning is mostly superseded by Wisp, but it can have better behavior on some * collections regarding collisions; Falcon is meant to be a faster version of Lightning. *
* IHasher values are provided as static fields, and use Wisp to hash a specific type or fall * back to Object.hashCode if given an object with the wrong type. IHasher values are optional * parts of OrderedMap, OrderedSet, Arrangement, and the various classes that use Arrangement * like K2 and K2V1, and allow arrays to be used as keys in those collections while keeping * hashing by value instead of the normal hashing by reference for arrays. You probably won't * ever need to make a class that implements IHasher yourself; for some cases you may want to * look at the {@link Hashers} class for additional functions. *
* The inner classes provide alternate, faster hashing algorithms. Lightning, Wisp, and Falcon * have no theoretical basis or grounds in any reason other than empirical testing for why they * do what they do, and this seems to be in line with many widely-used hashes (see: The Art of * Hashing, http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx ). That said, Wisp * performs very well, ahead of Arrays.hashCode (10.5 ms instead of 15 ms) for over a million * hashes of 16-element long arrays, not including overhead for generating them, while SipHash and * FNV-1a take approximately 80 ms and 135-155 ms, respectively, for the same data). Lightning and * Falcon perform less-well, with Lightning taking 17 ms instead of 15 ms for Arrays.hashCode, and * Falcon taking about 12.3 ms but slowing down somewhat if a 32-bit hash is requested from long * data. All of these have good, low, collision rates on Strings and long arrays. Sketch is only * slightly slower than Wisp, but offers little to no advantage over it yet. *
* Mist is a variant on Wisp with 128 bits for a salt-like modifier as a member variable, which can * make 2 to the 128 individual hashing functions from one set of code, and uses 64 bits for some other * hashes (only calls to hash() with data that doesn't involve long or double arrays). Mist has some * minor resemblance to a cryptographic hash, but is not recommended it for that usage. It is, * however ideal for situations that show up often in game development where end users may be able * to see and possibly alter some information that you don't want changed (i.e. save data stored on * a device or in the browser's LocalStorage). If you want a way to verify the data is what you * think it is, you can store a hash, using one of the many-possible hash functions this can * produce, somewhere else and verify that the saved data has the hash it did last time; if the * exact hashing function isn't known (or exact functions aren't known) by a tampering user, * then it is unlikely they can make the hash match even if they can edit it. Mist is slightly slower * than Wisp, at about 18 ms for Mist for the same data instead of Wisp's 10.5, but should never be * worse than twice as slow as Arrays.hashCode, and is still about three times faster than the similar * SipHash that SquidLib previously had here. *
* All of the hashes used here have about the same rate of collisions on identical data * (testing used Arrays.hashCode, all the hashes in here now, and the now-removed SipHash), with * any fluctuation within some small margin of error. Wisp (typically via the non-nested methods * in CrossHash) and Mist are the two most likely algorithms you might use here. *
* To help find patterns in hash output in a visual way, you can hash an x,y point, take the bottom 24 bits, * and use that as an RGB color for the pixel at that x,y point. On a 512x512 grid of points, the patterns * in Arrays.hashCode and the former default CrossHash algorithm (FNV-1a) are evident, and Sip (implementing * SipHash) did approximately as well as Lightning, with no clear patterns visible (Sip has been removed from * SquidLib because it needs a lot of code and is slower than all of the current hashes). The idea is from * a technical report on visual uses for hashing (PDF). *
    *
  • {@link java.util.Arrays#hashCode(int[])}: http://i.imgur.com/S4Gh1sX.png
  • *
  • {@link CrossHash#hash(int[])}: http://i.imgur.com/x8SDqvL.png
  • *
  • (Former) CrossHash.Sip.hash(int[]): http://i.imgur.com/keSpIwm.png
  • *
  • {@link CrossHash.Lightning#hash(int[])}: http://i.imgur.com/afGJ9cA.png
  • *
*
* Note: This class was formerly called StableHash, but since that refers to a specific * category of hashing algorithm that this is not, and since the goal is to be cross- * platform, the name was changed to CrossHash. * Note 2: FNV-1a was removed from SquidLib on July 25, 2017, and replaced as default with Wisp; Wisp * was later replaced as default by Hive, and in June 2019 Hive was replaced by Water. Wisp was used * because at the time SquidLib preferred 64-bit math when math needed to be the same across platforms; * math on longs behaves the same on GWT as on desktop, despite being slower. Hive passed an older version * of SMHasher, a testing suite for hashes, where Wisp does not (it fails just like Arrays.hashCode() * does). Hive uses a cross-platform subset of the possible 32-bit math operations when producing 32-bit * hashes of data that doesn't involve longs or doubles, and this should speed up the CrossHash.Hive.hash() * methods a lot on GWT, but it slows down 32-bit output on desktop-class JVMs. Water became the default * when newer versions of SMHasher showed that Hive wasn't as high-quality as it had appeared, and the * recently-debuted wyhash by Wang Yi, a variation on a hash called MUM, opened some possibilities for * structures that are simple but also very fast. Water is modeled after wyhash and uses the same constants * in its hash64() methods, but avoids the 128-bit multiplication that wyhash uses. Because both wyhash and * Water operate on 4 items at a time, they tend to be very fast on desktop platforms, but Water probably * won't be amazing at GWT performance. *
* Created by Tommy Ettinger on 1/16/2016. * @author Tommy Ettinger */ public class CrossHash { public static long hash64(final CharSequence data) { return Water.hash64(data); } public static long hash64(final boolean[] data) { return Water.hash64(data); } public static long hash64(final byte[] data) { return Water.hash64(data); } public static long hash64(final short[] data) { return Water.hash64(data); } public static long hash64(final int[] data) { return Water.hash64(data); } public static long hash64(final long[] data) { return Water.hash64(data); } public static long hash64(final char[] data) { return Water.hash64(data); } public static long hash64(final float[] data) { return Water.hash64(data); } public static long hash64(final double[] data) { return Water.hash64(data); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 64-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end) { return Water.hash64(data, start, end); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 64-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end) { return Water.hash64(data, start, end); } public static long hash64(final char[][] data) { return Water.hash64(data); } public static long hash64(final int[][] data) { return Water.hash64(data); } public static long hash64(final long[][] data) { return Water.hash64(data); } public static long hash64(final CharSequence[] data) { return Water.hash64(data); } public static long hash64(final CharSequence[]... data) { return Water.hash64(data); } public static long hash64(final Iterable data) { return Water.hash64(data); } public static long hash64(final List data) { return Water.hash64(data); } public static long hash64(final Object[] data) { return Water.hash64(data); } public static long hash64(final Object data) { return Water.hash64(data); } public static int hash(final CharSequence data) { return Water.hash(data); } public static int hash(final boolean[] data) { return Water.hash(data); } public static int hash(final byte[] data) { return Water.hash(data); } public static int hash(final short[] data) { return Water.hash(data); } public static int hash(final int[] data) { return Water.hash(data); } public static int hash(final long[] data) { return Water.hash(data); } public static int hash(final char[] data) { return Water.hash(data); } public static int hash(final float[] data) { return Water.hash(data); } public static int hash(final double[] data) { return Water.hash(data); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end) { return Water.hash(data, start, end); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end) { return Water.hash(data, start, end); } public static int hash(final char[][] data) { return Water.hash(data); } public static int hash(final int[][] data) { return Water.hash(data); } public static int hash(final long[][] data) { return Water.hash(data); } public static int hash(final CharSequence[] data) { return Water.hash(data); } public static int hash(final CharSequence[]... data) { return Water.hash(data); } public static int hash(final Iterable data) { return Water.hash(data); } public static int hash(final List data) { return Water.hash(data); } public static int hash(final Object[] data) { return Water.hash(data); } public static int hash(final Object data) { return Water.hash(data); } /** * An interface that can be used to move the logic for the hashCode() and equals() methods from a class' methods to * an implementation of IHasher that certain collections in SquidLib can use. Primarily useful when the key type is * an array, which normally doesn't work as expected in Java hash-based collections, but can if the right collection * and IHasher are used. See also {@link Hashers} for additional implementations, some of which need dependencies on * things the rest of CrossHash doesn't, like a case-insensitive String hasher/equator that uses RegExodus to handle * CharSequence comparison on GWT. */ public interface IHasher extends Serializable { /** * If data is a type that this IHasher can specifically hash, this method should use that specific hash; in * other situations, it should simply delegate to calling {@link Object#hashCode()} on data. The body of an * implementation of this method can be very small; for an IHasher that is meant for byte arrays, the body could * be: {@code return (data instanceof byte[]) ? CrossHash.Lightning.hash((byte[]) data) : data.hashCode();} * * @param data the Object to hash; this method should take any type but often has special behavior for one type * @return a 32-bit int hash code of data */ int hash(final Object data); /** * Not all types you might want to use an IHasher on meaningfully implement .equals(), such as array types; in * these situations the areEqual method helps quickly check for equality by potentially having special logic for * the type this is meant to check. The body of implementations for this method can be fairly small; for byte * arrays, it looks like: {@code return left == right * || ((left instanceof byte[] && right instanceof byte[]) * ? Arrays.equals((byte[]) left, (byte[]) right) * : Objects.equals(left, right));} , but for multidimensional arrays you should use the * {@link #equalityHelper(Object[], Object[], IHasher)} method with an IHasher for the inner arrays that are 1D * or otherwise already-hash-able, as can be seen in the body of the implementation for 2D char arrays, where * charHasher is an existing IHasher that handles 1D arrays: * {@code return left == right * || ((left instanceof char[][] && right instanceof char[][]) * ? equalityHelper((char[][]) left, (char[][]) right, charHasher) * : Objects.equals(left, right));} * * @param left allowed to be null; most implementations will have special behavior for one type * @param right allowed to be null; most implementations will have special behavior for one type * @return true if left is equal to right (preferably by value, but reference equality may sometimes be needed) */ boolean areEqual(final Object left, final Object right); } /** * Not a general-purpose method; meant to ease implementation of {@link IHasher#areEqual(Object, Object)} * methods when the type being compared is a multi-dimensional array (which normally requires the heavyweight method * {@link Arrays#deepEquals(Object[], Object[])} or doing more work yourself; this reduces the work needed to * implement fixed-depth equality). As mentioned in the docs for {@link IHasher#areEqual(Object, Object)}, example * code that hashes 2D char arrays can be done using an IHasher for 1D char arrays called charHasher: * {@code return left == right * || ((left instanceof char[][] && right instanceof char[][]) * ? equalityHelper((char[][]) left, (char[][]) right, charHasher) * : Objects.equals(left, right));} * * @param left an array of some kind of Object, usually an array, that the given IHasher can compare * @param right an array of some kind of Object, usually an array, that the given IHasher can compare * @param inner an IHasher to compare items in left with items in right * @return true if the contents of left and right are equal by the given IHasher, otherwise false */ public static boolean equalityHelper(Object[] left, Object[] right, IHasher inner) { if (left == right) return true; if (left == null || right == null || left.length != right.length) return false; for (int i = 0; i < left.length; i++) { if (!inner.areEqual(left[i], right[i])) return false; } return true; } private static class BooleanHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; BooleanHasher() { } @Override public int hash(final Object data) { return (data instanceof boolean[]) ? CrossHash.hash((boolean[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof boolean[] && right instanceof boolean[]) ? Arrays.equals((boolean[]) left, (boolean[]) right) : Objects.equals(left, right)); } } public static final IHasher booleanHasher = new BooleanHasher(); private static class ByteHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; ByteHasher() { } @Override public int hash(final Object data) { return (data instanceof byte[]) ? CrossHash.hash((byte[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof byte[] && right instanceof byte[]) ? Arrays.equals((byte[]) left, (byte[]) right) : Objects.equals(left, right)); } } public static final IHasher byteHasher = new ByteHasher(); private static class ShortHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; ShortHasher() { } @Override public int hash(final Object data) { return (data instanceof short[]) ? CrossHash.hash((short[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof short[] && right instanceof short[]) ? Arrays.equals((short[]) left, (short[]) right) : Objects.equals(left, right)); } } public static final IHasher shortHasher = new ShortHasher(); private static class CharHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; CharHasher() { } @Override public int hash(final Object data) { return (data instanceof char[]) ? CrossHash.hash((char[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof char[] && right instanceof char[]) ? Arrays.equals((char[]) left, (char[]) right) : Objects.equals(left, right)); } } public static final IHasher charHasher = new CharHasher(); private static class IntHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; IntHasher() { } @Override public int hash(final Object data) { return (data instanceof int[]) ? CrossHash.hash((int[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return (left instanceof int[] && right instanceof int[]) ? Arrays.equals((int[]) left, (int[]) right) : Objects.equals(left, right); } } public static final IHasher intHasher = new IntHasher(); private static class LongHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; LongHasher() { } @Override public int hash(final Object data) { return (data instanceof long[]) ? CrossHash.hash((long[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return (left instanceof long[] && right instanceof long[]) ? Arrays.equals((long[]) left, (long[]) right) : Objects.equals(left, right); } } public static final IHasher longHasher = new LongHasher(); private static class FloatHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; FloatHasher() { } @Override public int hash(final Object data) { return (data instanceof float[]) ? CrossHash.hash((float[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof float[] && right instanceof float[]) ? Arrays.equals((float[]) left, (float[]) right) : Objects.equals(left, right)); } } public static final IHasher floatHasher = new FloatHasher(); private static class DoubleHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; DoubleHasher() { } @Override public int hash(final Object data) { return (data instanceof double[]) ? CrossHash.hash((double[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof double[] && right instanceof double[]) ? Arrays.equals((double[]) left, (double[]) right) : Objects.equals(left, right)); } } public static final IHasher doubleHasher = new DoubleHasher(); private static class Char2DHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; Char2DHasher() { } @Override public int hash(final Object data) { return (data instanceof char[][]) ? CrossHash.hash((char[][]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof char[][] && right instanceof char[][]) ? equalityHelper((char[][]) left, (char[][]) right, charHasher) : Objects.equals(left, right)); } } public static final IHasher char2DHasher = new Char2DHasher(); private static class Int2DHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; Int2DHasher() { } @Override public int hash(final Object data) { return (data instanceof int[][]) ? CrossHash.hash((int[][]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof int[][] && right instanceof int[][]) ? equalityHelper((int[][]) left, (int[][]) right, intHasher) : Objects.equals(left, right)); } } public static final IHasher int2DHasher = new Int2DHasher(); private static class Long2DHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; Long2DHasher() { } @Override public int hash(final Object data) { return (data instanceof long[][]) ? CrossHash.hash((long[][]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof long[][] && right instanceof long[][]) ? equalityHelper((long[][]) left, (long[][]) right, longHasher) : Objects.equals(left, right)); } } public static final IHasher long2DHasher = new Long2DHasher(); private static class StringHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; StringHasher() { } @Override public int hash(final Object data) { return (data instanceof CharSequence) ? CrossHash.hash((CharSequence) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return Objects.equals(left, right); } } public static final IHasher stringHasher = new StringHasher(); private static class StringArrayHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; StringArrayHasher() { } @Override public int hash(final Object data) { return (data instanceof CharSequence[]) ? CrossHash.hash((CharSequence[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof CharSequence[] && right instanceof CharSequence[]) ? equalityHelper((CharSequence[]) left, (CharSequence[]) right, stringHasher) : Objects.equals(left, right)); } } /** * Though the name suggests this only hashes String arrays, it can actually hash any CharSequence array as well. */ public static final IHasher stringArrayHasher = new StringArrayHasher(); private static class ObjectArrayHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; ObjectArrayHasher() { } @Override public int hash(final Object data) { return (data instanceof Object[]) ? CrossHash.hash((Object[]) data) : data.hashCode(); } @Override public boolean areEqual(Object left, Object right) { return left == right || ((left instanceof Object[] && right instanceof Object[]) && Arrays.equals((Object[]) left, (Object[]) right) || Objects.equals(left, right)); } } public static final IHasher objectArrayHasher = new ObjectArrayHasher(); private static class DefaultHasher implements IHasher, Serializable { private static final long serialVersionUID = 5L; DefaultHasher() { } @Override public int hash(final Object data) { if(data == null) return 0; final int x = data.hashCode() * 0x9E375; return x ^ x >>> 16; } @Override public boolean areEqual(final Object left, final Object right) { return (left == right) || (left != null && left.equals(right)); } } public static final IHasher defaultHasher = new DefaultHasher(); private static class MildHasher implements IHasher, Serializable { private static final long serialVersionUID = 4L; MildHasher() { } @Override public int hash(final Object data) { return data != null ? data.hashCode() : 0; } @Override public boolean areEqual(final Object left, final Object right) { return (left == right) || (left != null && left.equals(right)); } } /** * The most basic IHasher type; effectively delegates to {@link Objects#hashCode(Object)} and * {@link Objects#equals(Object, Object)}. Might not scramble the bits of a hash well enough to have good * performance in a hash table lke {@link OrderedMap} or {@link UnorderedSet}, unless the objects being hashed have * good hashCode() implementations already. */ public static final IHasher mildHasher = new MildHasher(); private static class IdentityHasher implements IHasher, Serializable { private static final long serialVersionUID = 4L; IdentityHasher() { } @Override public int hash(Object data) { return System.identityHashCode(data); } @Override public boolean areEqual(Object left, Object right) { return left == right; } } public static final IHasher identityHasher = new IdentityHasher(); private static class GeneralHasher implements IHasher, Serializable { private static final long serialVersionUID = 3L; GeneralHasher() { } @Override public int hash(final Object data) { return CrossHash.hash(data); } @Override public boolean areEqual(Object left, Object right) { if(left == right) return true; Class l = left.getClass(), r = right.getClass(); if(l == r) { if(l.isArray()) { if(left instanceof int[]) return Arrays.equals((int[]) left, (int[]) right); else if(left instanceof long[]) return Arrays.equals((long[]) left, (long[]) right); else if(left instanceof char[]) return Arrays.equals((char[]) left, (char[]) right); else if(left instanceof double[]) return Arrays.equals((double[]) left, (double[]) right); else if(left instanceof boolean[]) return Arrays.equals((boolean[]) left, (boolean[]) right); else if(left instanceof byte[]) return Arrays.equals((byte[]) left, (byte[]) right); else if(left instanceof float[]) return Arrays.equals((float[]) left, (float[]) right); else if(left instanceof short[]) return Arrays.equals((short[]) left, (short[]) right); else if(left instanceof char[][]) return equalityHelper((char[][]) left, (char[][]) right, charHasher); else if(left instanceof int[][]) return equalityHelper((int[][]) left, (int[][]) right, intHasher); else if(left instanceof long[][]) return equalityHelper((long[][]) left, (long[][]) right, longHasher); else if(left instanceof CharSequence[]) return equalityHelper((CharSequence[]) left, (CharSequence[]) right, stringHasher); else if(left instanceof Object[]) return Arrays.equals((Object[]) left, (Object[]) right); } return Objects.equals(left, right); } return false; } } /** * This IHasher is the one you should use if you aren't totally certain what types will go in an OrderedMap's keys * or an OrderedSet's items, since it can handle mixes of elements. */ public static final IHasher generalHasher = new GeneralHasher(); /** * A quick, simple hashing function that seems to have good results. Like LightRNG, it stores a state that * it updates independently of the output, and this starts at a large prime. At each step, it takes the * current item in the array being hashed, adds a large non-prime used in LightRNG's generation function * (it's 2 to the 64, times the golden ratio phi, and truncated to a signed long), multiplies by a prime * called the "state multiplier", adds the result to the state and stores it, multiplies the value of the * state by another prime called the "output multiplier", then XORs the current result with that value * before moving onto the next item in the array. A finalization step XORs the result with a complex value * made by adding the state (left over from the previous step) to what was the output multiplier, adding * the last known value for result to the phi-related constant from LightRNG, multiplying that pair, adding * the initial state (which turns out to be unusually good for this, despite no particularly special numeric * qualities other than being a probable prime) and then bitwise-rotating it left by a seemingly-random * number drawn from the highest 6 bits of the state. *
* This all can be done very quickly; a million hashes of a million different 16-element long arrays can be * computed in under 18-20 ms (in the benchmark, some amount of that is overhead from generating a new * array with LongPeriodRNG, since the benchmark uses that RNG's state for data, and the default * Arrays.hashCode implementation is only somewhat faster at under 16 ms). After several tries and tweaks * to the constants this uses, it also gets remarkably few hash collisions. On the same 0x100000, or * 1048576, RNG states for data, Lightning gets 110 collisions, the JDK Arrays.hashCode method gets 129 * collisions, Sip (implementing SipHash) gets 145 collisions, and CrossHash (using the FNV-1a algorithm) * gets 135 collisions. Dispersion is not perfect, but * at many bit sizes Lightning continues to have less collisions (it disperses better than the other hashes * with several quantities of bits, at least on this test data). Lightning also does relatively well, though * it isn't clearly ahead of the rest all the time, when hashing Strings, especially ones that use a larger * set of letters, it seems (FakeLanguageGen was used to make test data, and languages that used more * characters in their alphabet seemed to hash better with this than competing hashes for some reason). *
* There is certainly room for improvement with the specific numbers chosen; earlier versions used the * state multiplier "Neely's number", which is a probable prime made by taking the radix-29 number * "HARGNALLINSCLOPIOPEEPIO" (a reference to a very unusual TV show), truncating to 64 bits, and rotating * right by 42 bits. This version uses "Neely's number" for an initial state and during finalization, and * uses a different probable prime as the state multiplier, made with a similar process; it starts with the * radix-36 number "EDSGERWDIJKSTRA", then does the same process but rotates right by 37 bits to obtain a * different prime. This tweak seems to help with hash collisions. Extensive trial and error was used to * find the current output multiplier, which has no real relationship to anything else but has exactly 32 of * 64 bits set to 1, has 1 in the least and most significant bit indices (meaning it is negative and odd), * and other than that seems to have better results on most inputs for mystifying reasons. Earlier versions * applied a Gray code step to alter the output instead of a multiplier that heavily overflows to obfuscate * state, but that had a predictable pattern for most of the inputs tried, which seemed less-than-ideal for * a hash. Vitally, Lightning avoids predictable collisions that Arrays.hashCode has, like * {@code Arrays.hashCode(new long[]{0})==Arrays.hashCode(new long[]{-1})}. *
* The output multiplier is 0xC6BC279692B5CC83L, the state multiplier is 0xD0E89D2D311E289FL, the number * added to the state (from LightRNG and code derived from FastUtil, but obtained from the golden ratio * phi) is 0x9E3779B97F4A7C15L, and the starting state ("Neely's Number") is 0x632BE59BD9B4E019L. *
* To help find patterns in hash output in a visual way, you can hash an x,y point, take the bottom 24 bits, * and use that as an RGB color for the pixel at that x,y point. On a 512x512 grid of points, the patterns * in Arrays.hashCode and the default CrossHash algorithm (FNV-1a) are evident, and Sip (implementing * SipHash) does approximately as well as Lightning, with no clear patterns visible (Sip has been removed * from SquidLib because it needs a lot of code and is slower than Mist). The * idea is from a technical report on visual uses for hashing, * http://www.clockandflame.com/media/Goulburn06.pdf . *
    *
  • {@link java.util.Arrays#hashCode(int[])}: http://i.imgur.com/S4Gh1sX.png
  • *
  • {@link CrossHash#hash(int[])}: http://i.imgur.com/x8SDqvL.png
  • *
  • (Former) CrossHash.Sip.hash(int[]): http://i.imgur.com/keSpIwm.png
  • *
  • {@link CrossHash.Lightning#hash(int[])}: http://i.imgur.com/afGJ9cA.png
  • *
*/ // tested output multipliers // 0x DA1A459BD9B4C619L // 0x DC1A459879B5C619L // 0x DC1A479829B5E639L // 0x DC1A479C29B5C639L // 0x EA1C479692B5C639L // 0x CA1C479692B5C635L // this gets 105 collisions, low // 0x CABC479692B5C635L // 0x DC1A479C29B5C647L // 0x DC1A479C29B5C725L // 0x CABC279692B5CB21L // 0x C6BC279692B5CC83L // this gets 100 collisions, lowest // 0x C6BC279692B4D8A5L // 0x C6BC279692B4D345L // 0x C6EC273692B4A4B9L // 0x C6A3256B52D5B463L // 0x C6A3256B52D5B463L // 0x C6A3256D52D5B4C9L // 0x D8A3256D52D5B619L // 0x D96E6AC724658947L // 0x D96E6AC724658C2DL // 0x CCABF9E32FD684F9L // 0x C314163FAF912A01L // 0x C3246007A332C12AL // 0x CA1C479692B5C6ABL // 0x C6B5275692B5CC83 // untested so far @SuppressWarnings("NumericOverflow") public static final class Lightning { public static long hash64(final boolean[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] ? 0x9E3779B97F4A7C94L : 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final byte[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final short[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final char[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final int[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final long[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final float[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (floatToIntBits(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final double[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (NumberTools.doubleToMixedIntBits(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 64-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = start; i < end && i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 64-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = start; i < end && i < data.length; i += step) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final CharSequence data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length(); i++) { result ^= (z += (data.charAt(i) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final char[][] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final long[][] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final CharSequence[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final Iterable data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (CharSequence datum : data) { result ^= (z += (hash64(datum) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final CharSequence[]... data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static long hash64(final Object[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; Object o; for (int i = 0; i < data.length; i++) { o = data[i]; result ^= (z += ((o == null ? 0 : o.hashCode()) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return result ^ Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58)); } public static int hash(final boolean[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] ? 0x9E3779B97F4A7C94L : 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final byte[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final short[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final char[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final int[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final long[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final float[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (floatToIntBits(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final double[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (NumberTools.doubleToMixedIntBits(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = start; i < end && i < data.length; i++) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = start; i < end && i < data.length; i += step) { result ^= (z += (data[i] + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final CharSequence data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length(); i++) { result ^= (z += (data.charAt(i) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final char[][] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final long[][] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final CharSequence[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final Iterable data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (CharSequence datum : data) { result ^= (z += (hash64(datum) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final CharSequence[]... data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; for (int i = 0; i < data.length; i++) { result ^= (z += (hash64(data[i]) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } public static int hash(final Object[] data) { if (data == null) return 0; long z = 0x632BE59BD9B4E019L, result = 1L; Object o; for (int i = 0; i < data.length; i++) { o = data[i]; result ^= (z += ((o == null ? 0 : o.hashCode()) + 0x9E3779B97F4A7C15L) * 0xD0E89D2D311E289FL) * 0xC6BC279692B5CC83L; } return (int) ((result ^= Long.rotateLeft((z * 0xC6BC279692B5CC83L ^ result * 0x9E3779B97F4A7C15L) + 0x632BE59BD9B4E019L, (int) (z >>> 58))) ^ (result >>> 32)); } } // Nice ints, all probable primes except the last one, for 32-bit hashing // 0x62E2AC0D 0x632BE5AB 0x85157AF5 0x9E3779B9 /** * The fastest hash in CrossHash, with middling quality. Uses a finely-tuned mix of very few operations for each * element, plus a minimal and simple finalization step, and as such obtains superior speed on the standard * benchmark SquidLib uses for hashes (hashing one million 16-element long arrays, remaining the best in both 32-bit * and 64-bit versions). Specifically, Wisp takes 9.478 ms to generate a million 64-bit hashes on a recent laptop * with an i7-6700HQ processor (removing the time the control takes to generate the million arrays). For comparison, * the JDK's Arrays.hashCode method takes 13.642 ms on the same workload, though it produces 32-bit hashes. Wisp * performs almost exactly as well producing 32-bit hashes as it does 64-bit hashes, where Hive slows down * significantly on some input types. This also passes visual tests where an earlier version of Wisp did not. * Collision rates are slightly worse than other CrossHash classes, but are better than the JDK's * Arrays.hashCode method, that is, acceptably low when given varied-enough inputs. On certain kinds of similar * inputs, Wisp will struggle with a higher collision rate. For example, when hashing Strings that contain only * several spaces, then some combination of digits 0-5, then more spaces, Wisp does very badly, worse than * {@link String#hashCode()} (which also does badly, though not as badly), while other hashes here do fine (such as * Water, which is the default for {@link CrossHash#hash(CharSequence)}). *
* This version replaces an older version of Wisp that had serious quality issues and wasn't quite as fast. Since * the only reason one would use the older version was speed without regard for quality, and it was marked as Beta, * a faster version makes sense to replace the slower one, rather than add yet another nested class in CrossHash. *
* Wisp is no longer considered Beta-quality, but even though it is rather fast, it has some cases where categories * of input cause frequent collisions. {@link Water} is about 20% slower but doesn't have such categories of * pathologically bad inputs, and passes tests that Wisp fails badly on. Because the hash-based collections in * SquidLib need a pretty good hash function to work at their best (they use linear-probing with open addressing, * which struggles when hashes are bad), 20% loss of speed during hashing to avoid slower * lookups/insertions/deletions from {@link OrderedMap}, {@link OrderedSet}, {@link UnorderedMap}, * {@link UnorderedSet}, {@link Arrangement}, and others is probably worth it; if you really need speed then Wisp is * right here. */ public static final class Wisp { public static long hash64(final boolean[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * (data[i] ? 0xC6BC279692B5CC83L : 0xAEF17502108EF2D9L)); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final byte[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final short[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final char[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final int[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final long[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final float[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * floatToIntBits(data[i])); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final double[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(data[i])); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final CharSequence data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length(); for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data.charAt(i)); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 64-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 64-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i += step) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final char[][] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final int[][] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final long[][] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final CharSequence[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final CharSequence[]... data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final Iterable data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; for (CharSequence datum : data) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(datum)); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final List data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.size(); for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data.get(i))); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final Object[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * ((o = data[i]) == null ? -1L : o.hashCode())); } return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static long hash64(final Object data) { if (data == null) return 0L; long a = 0x632BE59BD9B4E019L ^ 0x8329C6EB9E6AD3E3L * data.hashCode(), result = 0x9E3779B97F4A7C94L + a; return result * (a | 1L) ^ (result << 37 | result >>> 27); } public static int hash32(final boolean[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * (data[i] ? 0x789ABCDE : 0x62E2AC0D)); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final byte[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * data[i]); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final short[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * data[i]); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final char[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * data[i]); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final int[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * data[i]); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final long[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)((a += (result << 37 | result >>> 27)) ^ (a >>> 32)); } public static int hash32(final float[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * floatToIntBits(data[i])); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final double[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; double t; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * ((long) (-0xD0E8.9D2D311E289Fp-25 * (t = data[i]) + t * -0x1.39b4dce80194cp9))); } return (int)((result = (result * (a | 1L) ^ (result << 37 | result >>> 27))) ^ (result >>> 32)); } public static int hash32(final CharSequence data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length(); for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * data.charAt(i)); } return result * (a | 1) ^ (result >>> 11 | result << 21); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * Uses 32-bit math on most platforms, but will give different results on GWT due to it using double values that * only somewhat act like int values. * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash32(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result += (a ^= 0x85157AF5 * data[i]); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final char[][] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * hash32(data[i])); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final int[][] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * hash32(data[i])); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final long[][] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * hash32(data[i])); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final CharSequence[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * hash32(data[i])); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final CharSequence[]... data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * hash32(data[i])); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final Iterable data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; for (CharSequence datum : data) { result += (a ^= 0x85157AF5 * hash32(datum)); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final List data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.size(); for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * hash32(data.get(i))); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final Object[] data) { if (data == null) return 0; int result = 0x9E3779B9, a = 0x632BE5AB; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result += (a ^= 0x85157AF5 * ((o = data[i]) == null ? -1 : o.hashCode())); } return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash32(final Object data) { if (data == null) return 0; int a = 0x632BE5AB ^ 0x85157AF5 * data.hashCode(), result = 0x9E3779B9 + a; return result * (a | 1) ^ (result >>> 11 | result << 21); } public static int hash(final boolean[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * (data[i] ? 0xC6BC279692B5CC83L : 0xAEF17502108EF2D9L)); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final byte[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final short[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final char[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final int[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final long[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final float[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * floatToIntBits(data[i])); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final double[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(data[i])); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final CharSequence data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length(); for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data.charAt(i)); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i+= step) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final char[][] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final int[][] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final long[][] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final CharSequence[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final CharSequence[]... data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final Iterable data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; for (CharSequence datum : data) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(datum)); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final List data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.size(); for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data.get(i))); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final Object[] data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L, a = 0x632BE59BD9B4E019L; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * ((o = data[i]) == null ? -1 : o.hashCode())); } return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } public static int hash(final Object data) { if (data == null) return 0; long a = 0x632BE59BD9B4E019L ^ 0x8329C6EB9E6AD3E3L * data.hashCode(), result = 0x9E3779B97F4A7C94L + a; return (int)(result * (a | 1L) ^ (result << 37 | result >>> 27)); } } /** * A whole cluster of Wisp-like hash functions that sacrifice a small degree of speed, but can be built with up * to 128 bits of salt values that help to obscure what hashing function is actually being used. This class is * similar to the older Storm variety, but is somewhat faster and has many more possible salt "states" when using * the constructors that take two longs or a CharSequence. There isn't really any reason to use Storm, so Mist has * now replaced Storm entirely. Code that used Storm should be able to just change any usage of "Storm" to "Mist". *
* The salt fields are not serialized, so it is important that the same salt will be given by the * program when the same hash results are wanted for some inputs. *
* A group of 48 static, final, pre-initialized Mist members are present in this class, 24 with the * name of a letter in the Greek alphabet (this uses the convention on Wikipedia, * https://en.wikipedia.org/wiki/Greek_alphabet#Letters , where lambda is spelled with a 'b') and 24 with the same * name followed by an underscore, such as {@link #alpha_}. The whole group of 48 pre-initialized members are also * present in a static array called {@code predefined}. These can be useful when, for example, you want to get * multiple hashes of a single array or String as part of cuckoo hashing or similar techniques that need multiple * hashes for the same inputs. */ @Beta public static final class Mist implements Serializable { private static final long serialVersionUID = -1275284837479983271L; private transient final long $l1, $l2; public Mist() { this(0x1234567876543210L, 0xEDCBA98789ABCDEFL); } public Mist(final CharSequence alteration) { this(CrossHash.hash64(alteration), Lightning.hash64(alteration)); } private static int permute(final long state) { int s = (int)state ^ 0xD0E89D2D; s = (s >>> 19 | s << 13); s ^= state >>> (5 + (state >>> 59)); return ((s *= 277803737) >>> 22) ^ s; } @SuppressWarnings("NumericOverflow") public Mist(final long alteration) { long l1, l2; l1 = alteration + permute(alteration); l1 = (l1 ^ (l1 >>> 30)) * 0xBF58476D1CE4E5B9L; l1 = (l1 ^ (l1 >>> 27)) * 0x94D049BB133111EBL; $l1 = l1 ^ l1 >>> 31; l2 = alteration + 6 * 0x9E3779B97F4A7C15L; l2 = (l2 ^ (l2 >>> 30)) * 0xBF58476D1CE4E5B9L; l2 = (l2 ^ (l2 >>> 27)) * 0x94D049BB133111EBL; $l2 = l2 ^ l2 >>> 31; } @SuppressWarnings("NumericOverflow") public Mist(final long alteration1, long alteration2) { final int i1 = permute(alteration1); $l1 = alteration1 + i1; $l2 = alteration2 + permute(alteration2 + i1); } /** * Makes a new Mist with all of the salt values altered based on the previous salt values. * This will make a different, incompatible Mist object that will give different results than the original. * Meant for use in Cuckoo Hashing, which can need the hash function to be updated or changed. * An alternative is to select a different Mist object from {@link #predefined}, or to simply * construct a new Mist with a different parameter or set of parameters. */ @SuppressWarnings("NumericOverflow") public Mist randomize() { long l1, l2; l1 = $l2 + permute($l2 + 3 * 0x9E3779B97F4A7C15L); l1 = (l1 ^ (l1 >>> 30)) * 0xBF58476D1CE4E5B9L; l1 = (l1 ^ (l1 >>> 27)) * 0x94D049BB133111EBL; l1 ^= l1 >>> 31; l2 = permute(l1 + 5 * 0x9E3779B97F4A7C15L) + 6 * 0x9E3779B97F4A7C15L; l2 = (l2 ^ (l2 >>> 30)) * 0xBF58476D1CE4E5B9L; l2 = (l2 ^ (l2 >>> 27)) * 0x94D049BB133111EBL; l2 ^= l2 >>> 31; return new Mist(l1, l2); } public static final Mist alpha = new Mist("alpha"), beta = new Mist("beta"), gamma = new Mist("gamma"), delta = new Mist("delta"), epsilon = new Mist("epsilon"), zeta = new Mist("zeta"), eta = new Mist("eta"), theta = new Mist("theta"), iota = new Mist("iota"), kappa = new Mist("kappa"), lambda = new Mist("lambda"), mu = new Mist("mu"), nu = new Mist("nu"), xi = new Mist("xi"), omicron = new Mist("omicron"), pi = new Mist("pi"), rho = new Mist("rho"), sigma = new Mist("sigma"), tau = new Mist("tau"), upsilon = new Mist("upsilon"), phi = new Mist("phi"), chi = new Mist("chi"), psi = new Mist("psi"), omega = new Mist("omega"), alpha_ = new Mist("ALPHA"), beta_ = new Mist("BETA"), gamma_ = new Mist("GAMMA"), delta_ = new Mist("DELTA"), epsilon_ = new Mist("EPSILON"), zeta_ = new Mist("ZETA"), eta_ = new Mist("ETA"), theta_ = new Mist("THETA"), iota_ = new Mist("IOTA"), kappa_ = new Mist("KAPPA"), lambda_ = new Mist("LAMBDA"), mu_ = new Mist("MU"), nu_ = new Mist("NU"), xi_ = new Mist("XI"), omicron_ = new Mist("OMICRON"), pi_ = new Mist("PI"), rho_ = new Mist("RHO"), sigma_ = new Mist("SIGMA"), tau_ = new Mist("TAU"), upsilon_ = new Mist("UPSILON"), phi_ = new Mist("PHI"), chi_ = new Mist("CHI"), psi_ = new Mist("PSI"), omega_ = new Mist("OMEGA"); /** * Has a length of 48, which may be relevant if automatically choosing a predefined hash functor. */ public static final Mist[] predefined = new Mist[]{alpha, beta, gamma, delta, epsilon, zeta, eta, theta, iota, kappa, lambda, mu, nu, xi, omicron, pi, rho, sigma, tau, upsilon, phi, chi, psi, omega, alpha_, beta_, gamma_, delta_, epsilon_, zeta_, eta_, theta_, iota_, kappa_, lambda_, mu_, nu_, xi_, omicron_, pi_, rho_, sigma_, tau_, upsilon_, phi_, chi_, psi_, omega_}; public long hash64(final boolean[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * (data[i] ? 0x9E3779B97F4A7C15L : 0x789ABCDEFEDCBA98L)) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final byte[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final short[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final char[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final int[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final long[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final float[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * floatToIntBits(data[i])) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final double[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(data[i])) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 64-bit hash code for the requested section of data */ public long hash64(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = start; i < end && i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 64-bit hash code for the requested section of data */ public long hash64(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = start; i < end && i < len; i += step) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final CharSequence data) { if (data == null) return 0; final int len = data.length(); long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data.charAt(i)) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final char[][] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final long[][] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final CharSequence[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final Iterable data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (CharSequence datum : data) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(datum)) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final CharSequence[]... data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final Object[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; Object o; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * ((o = data[i]) == null ? -1 : o.hashCode())) ^ $l2 * a + $l1; } return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public long hash64(final Object data) { if (data == null) return 0; final long a = 0x632BE59BD9B4E019L ^ 0x8329C6EB9E6AD3E3L * data.hashCode(), result = 0x9E3779B97F4A7C94L + $l2 + (a ^ $l2 * a + $l1); return result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27); } public int hash(final boolean[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * (data[i] ? 0x9E3779B97F4A7C15L : 0x789ABCDEFEDCBA98L)) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final byte[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final short[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final char[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final int[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final long[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final float[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * floatToIntBits(data[i])) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final double[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * NumberTools.doubleToMixedIntBits(data[i])) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public int hash(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = start; i < end && i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public int hash(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = start; i < end && i < len; i += step) { result += (a ^= 0x8329C6EB9E6AD3E3L * data[i]) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final CharSequence data) { if (data == null) return 0; final int len = data.length(); long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * data.charAt(i)) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final char[][] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final long[][] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final CharSequence[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final Iterable data) { if (data == null) return 0; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (CharSequence datum : data) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(datum)) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final CharSequence[]... data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * hash64(data[i])) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final Object[] data) { if (data == null) return 0; final int len = data.length; long result = 0x9E3779B97F4A7C94L + $l2, a = 0x632BE59BD9B4E019L; Object o; for (int i = 0; i < len; i++) { result += (a ^= 0x8329C6EB9E6AD3E3L * ((o = data[i]) == null ? -1 : o.hashCode())) ^ $l2 * a + $l1; } return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } public int hash(final Object data) { if (data == null) return 0; final long a = 0x632BE59BD9B4E019L ^ 0x8329C6EB9E6AD3E3L * data.hashCode(), result = 0x9E3779B97F4A7C94L + $l2 + (a ^ $l2 * a + $l1); return (int)(result * (a * $l1 | 1L) ^ (result << 37 | result >>> 27)); } } /** * A mid-quality hashing function that has been tested with SMHasher and has passed all of it when running on * {@code byte[]} data, not larger items like {@code char[]} or {@code long[]}. The code to hash bytes is identical * in {@link Hive}, but Hive has better behavior on chars, ints, longs, and so on. You should prefer Hive, which is * now the default algorithm for {@link CrossHash#hash(CharSequence)} (as well as all overloads of hash() and * hash64() ), in place of Jolt unless you can tolerate mediocre quality when hashing ints, longs, objects, etc. * (better than Wisp, though) but do want closer speed to Wisp than Hive offers on those types. *
* Its design is similar to Lightning or Wisp, but it doesn't use bitwise rotations and runs what would otherwise be * the output through MurmurHash3's finalization step (its {@code fmix64()} function) at the very end. Parts of the * code here are inspired by the design of {@link LinnormRNG}, particularly its determine() method since both use an * XLCG as a processing step. */ @Beta public static final class Jolt { public static long hash64(final CharSequence data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length(); for (int i = 0; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final boolean[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += ((data[i] ? 0xFF51AFD7ED558CCDL : 0xC4CEB9FE1A85EC53L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final byte[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final short[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final int[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final long[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final char[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final float[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (floatToIntBits(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final double[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (NumberTools.doubleToLongBits(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i += step) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i += step) { result ^= (z += (data.charAt(i) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final char[][] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final int[][] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final long[][] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final CharSequence[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final CharSequence[]... data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final Iterable data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; for (CharSequence datum : data) { result ^= (z += (hash64(datum) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final List data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.size(); for (int i = 0; i < len; i++) { result ^= (z += (hash64(data.get(i)) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final Object[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result ^= (z += (((o = data[i]) == null ? -1L : o.hashCode()) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final Object data) { if (data == null) return 0L; long result = data.hashCode(); result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static int hash(final CharSequence data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length(); for (int i = 0; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final boolean[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += ((data[i] ? 0xFF51AFD7ED558CCDL : 0xC4CEB9FE1A85EC53L) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final byte[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final short[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final int[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final long[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final char[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final float[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (floatToIntBits(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final double[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (NumberTools.doubleToLongBits(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i += step) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i += step) { result ^= (z += (data.charAt(i) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final char[][] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final int[][] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final long[][] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final CharSequence[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final CharSequence[][] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final Iterable data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; for (CharSequence datum : data) { result ^= (z += (hash64(datum) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final List data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.size(); for (int i = 0; i < len; i++) { result ^= (z += (hash64(data.get(i)) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final Object[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result ^= (z += (((o = data[i]) == null ? -1 : o.hashCode()) ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } public static int hash(final Object data) { if (data == null) return 0; long result = data.hashCode(); result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (int) (result ^ result >>> 33); } } /** * A reasonably-fast hashing function that passes some of SMHasher's quality tests, but neither critically fails nor * overwhelmingly succeeds the full SMHasher test battery. This is the default used by methods in the * outer class like {@link CrossHash#hash(int[])}, which should be the same as {@link CrossHash.Hive#hash(int[])}; * you should prefer using the outer class since this inner class is only here for reference. It may be replaced by * {@link Water} in the future; Water is drastically faster on int array inputs and does pass all of SMHasher, but * has minimal optimization for GWT. *
* This mixes three different algorithms: the main one is used whenever inputs or outputs are 64-bit (so, all hash64() * overloads and {@link Hive#hash(long[])} for long and double), a modification of the main one to perform better on * GWT (only used on hash() overloads, and only when inputs are individually 32-bit or less), and * {@link CrossHash.Jolt}'s algorithm for hash64() on boolean and byte data. *
* Speed-wise, the main algorithm is about 20% slower than Wisp, but in hash tables it doesn't have clear failure * cases like Wisp does on some inputs (such as fixed-length Strings with identical prefixes). If collisions are * expensive or profiling shows that Wisp's algorithm is colliding at a high rate, you should probably use the * normal IHasher and CrossHash.hash() methods, since those will use Hive. The modified algorithm for GWT is a * little slower than the main algorithm in the C++ implementation that was used to check SMHasher quality, but it * may perform similarly to the main algorithm in Java on desktop platforms. Since it avoids creating longs or doing * any math on them, it should be at least 3x faster than the main algorithm on GWT (a GWT long is internally * represented by 3 JS numbers, so barring special optimizations it takes at least 3x as many math operations to use * longs there). *
* Its design uses two states like {@link Lightning} or {@link Wisp}, updating them differently from each other, and * bitwise-rotates one at each step. It combines the states (xorshifting one state, multiplying it by a huge * constant, and adding that to the other state) and then runs that through MurmurHash3's finalization function (its * {@code fmix64()} function; the main algorithm elides one xorshift at the end that proved unnecessary). Parts of * the code here are inspired by the design of {@link DiverRNG}, particularly its determine() method since both * use an XLCG (XOR Linear Congruential Generator, as PractRand calls it) as a processing step. *
* The name comes from the song I was listening to when I finally got the tests to pass ("Slave The Hive" by High On * Fire) and from the wide assortment of code that I had to employ to achieve a SMHasher successful run (which * turned out to be not-so-successful). * @see CrossHash Prefer using the hash() and hash64() methods in the outer class to this inner one; this inner * class is only here for compatibility and can be removed by minifiers if you don't use it */ @Beta public static final class Hive { public static long hash64(final CharSequence data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length(); for (int i = 0; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final boolean[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ? 0xFF51AFD7ED558CCDL : 0xC4CEB9FE1A85EC53L)); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final byte[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0x9E3779B97F4A7C15L) * 0xC6BC279692B5CC83L); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result ^= result >>> 25 ^ z ^ z >>> 29; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static long hash64(final short[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final int[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final long[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final char[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final float[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (floatToIntBits(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final double[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (NumberTools.doubleToLongBits(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result ^= (z += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i += step) { result ^= (z += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i += step) { result ^= (z += (data.charAt(i) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final char[][] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final int[][] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final long[][] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final CharSequence[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final CharSequence[]... data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final Iterable data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; for (CharSequence datum : data) { result ^= (z += (hash64(datum) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final List data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.size(); for (int i = 0; i < len; i++) { result ^= (z += (hash64(data.get(i)) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final Object[] data) { if (data == null) return 0L; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result ^= (z += (((o = data[i]) == null ? -1L : o.hashCode()) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static long hash64(final Object data) { if (data == null) return 0L; long result = data.hashCode() * 0xFF51AFD7ED558CCDL; result = (result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L; return (result ^ result >>> 33); } public static int hash(final CharSequence data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length(); for (int i = 0; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final boolean[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ? 0x6F51AFDB : 0xC3564E95)); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final byte[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final short[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final int[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final long[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return (int)((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static int hash(final char[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (data[i] ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final float[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (floatToIntBits(data[i]) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final double[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (NumberTools.doubleToLongBits(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return (int)((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result ^= (z += (data[i] ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i++) { result ^= (z += (data.charAt(i) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i += step) { result ^= (z += (data[i] ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i += step) { result ^= (z += (data.charAt(i) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final char[][] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final int[][] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final long[][] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash64(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return (int)((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static int hash(final CharSequence[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final CharSequence[]... data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (z += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final Iterable data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; for (CharSequence datum : data) { result ^= (z += (hash(datum) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final List data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.size(); for (int i = 0; i < len; i++) { result ^= (z += (hash(data.get(i)) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final Object[] data) { if (data == null) return 0; int result = 0x1A976FDF, z = 0x60642E25; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result ^= (z += (((o = data[i]) == null ? -1 : o.hashCode()) ^ 0xC3564E95) * 0x9E375); z ^= (result = (result << 20 | result >>> 12)); } result += (z ^ z >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final Object data) { if (data == null) return 0; final int h = data.hashCode() * 0x9E375; return h ^ (h >>> 16); } } /** * Pretty fast, but not GWT-optimized for 32-bit input and output like Hive. */ @Beta public static final class Sirocco { public static long hash64(final CharSequence data) { if (data == null) return 0L; final int len = data.length(); long a = len; for (int i = 0; i < len; i++) { a += (data.charAt(i) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final boolean[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (data[i] ? 0x517CC1B727220A95L : 0x9308E0BEACFD0A39L) ^ (a << 17 | a >>> 47) ^ 0xD1B54A32D192ED03L; } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final byte[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (data[i] ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final short[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (data[i] ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final int[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (data[i] ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final long[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (data[i] ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final char[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (data[i] ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final float[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (floatToIntBits(data[i]) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final double[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (NumberTools.doubleToLongBits(data[i]) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0L; final int len = end < data.length ? end : data.length; long a = len - start; for (int i = start; i < len; i++) { a += (data[i] ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0L; final int len = end < data.length() ? end : data.length(); long a = len - start; for (int i = start; i < len; i++) { a += (data.charAt(i) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0L; final int len = end < data.length ? end : data.length; long a = len - start; for (int i = start; i < len; i += step) { a += (data[i] ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0L; final int len = end < data.length() ? end : data.length(); long a = len - start; for (int i = start; i < len; i += step) { a += (data.charAt(i) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final char[][] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (hash64(data[i]) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final int[][] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (hash64(data[i]) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final long[][] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (hash64(data[i]) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final CharSequence[] data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (hash64(data[i]) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final CharSequence[]... data) { if (data == null) return 0L; final int len = data.length; long a = len; for (int i = 0; i < len; i++) { a += (hash64(data[i]) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final Iterable data) { if (data == null) return 0L; long a = 0xD1B54A32D192ED03L; for (CharSequence datum : data) { a += (hash64(datum) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final List data) { if (data == null) return 0L; final int len = data.size(); long a = len; for (int i = 0; i < len; i++) { a += (hash64(data.get(i)) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final Object[] data) { if (data == null) return 0L; final int len = data.length; long a = len; Object o; for (int i = 0; i < len; i++) { a += (((o = data[i]) == null ? -1L : o.hashCode()) ^ 0xDB4F0B9175AE2165L) * 0xD1B54A32D192ED03L; a = (a << 17 | a >>> 47); } a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static long hash64(final Object data) { if (data == null) return 0L; long a = data.hashCode(); a = (a ^ (a << 41 | a >>> 23) ^ (a << 17 | a >>> 47)) * 0xAEF17502108EF2D9L; a = (a ^ a >>> 43 ^ a >>> 31 ^ a >>> 23) * 0xDB4F0B9175AE2165L; return a ^ a >>> 28; } public static int hash(final CharSequence data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length(); for (int i = 0; i < len; i++) { result ^= (run += (data.charAt(i) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final boolean[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (data[i] ? 0x6F51AFDB : 0xC3564E95)); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final byte[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (data[i] ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final short[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (data[i] ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final int[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (data[i] ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final long[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, run = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result = (run += (data[i] ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL) ^ (result << 54 | result >>> 10); } result += (run ^ run >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return (int) ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static int hash(final char[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (data[i] ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final float[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (floatToIntBits(data[i]) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final double[] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, run = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (NumberTools.doubleToLongBits(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (run ^ run >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return (int) ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i++) { result ^= (run += (data[i] ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i++) { result ^= (run += (data.charAt(i) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = end < data.length ? end : data.length; for (int i = start; i < len; i += step) { result ^= (run += (data[i] ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } /** * Hashes only a subsection of the given data, starting at start (inclusive), ending before end (exclusive), and * moving between chars in increments of step (which is always greater than 0). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @param step how many elements to advance after using one element from data; must be greater than 0 * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end, final int step) { if (data == null || start >= end || step <= 0) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = end < data.length() ? end : data.length(); for (int i = start; i < len; i += step) { result ^= (run += (data.charAt(i) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final char[][] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final int[][] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final long[][] data) { if (data == null) return 0; long result = 0x1A976FDF6BF60B8EL, run = 0x60642E2A34326F15L; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (hash64(data[i]) ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL); result = (result << 54 | result >>> 10); } result += (run ^ run >>> 26) * 0x632BE59BD9B4E019L; result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL; return (int) ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L); } public static int hash(final CharSequence[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final CharSequence[]... data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; for (int i = 0; i < len; i++) { result ^= (run += (hash(data[i]) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final Iterable data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; for (CharSequence datum : data) { result ^= (run += (hash(datum) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final List data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.size(); for (int i = 0; i < len; i++) { result ^= (run += (hash(data.get(i)) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final Object[] data) { if (data == null) return 0; int result = 0x1A976FDF, run = 0x60642E25; final int len = data.length; Object o; for (int i = 0; i < len; i++) { result ^= (run += (((o = data[i]) == null ? -1L : o.hashCode()) ^ 0xC3564E95) * 0x9E375); run ^= (result = (result << 20 | result >>> 12)); } result += (run ^ run >>> 15 ^ 0xAE932BD5) * 0x632B9; result = (result ^ result >>> 15) * 0xFF51D; result = (result ^ result >>> 15) * 0xC4CEB; return result ^ result >>> 15; } public static int hash(final Object data) { if (data == null) return 0; final int h = data.hashCode() * 0x9E375; return h ^ (h >>> 16); } } /** * A fairly fast hashing algorithm in general, Water performs especially well on large arrays, and passes SMHasher's * newest and most stringent version of tests. The int-hashing {@link #hash(int[])} method is almost twice as fast * as {@link CrossHash#hash(int[])} and faster than {@link Arrays#hashCode(int[])}. Based on * wyhash, specifically * the waterhash variant. This version passes SMHasher for * both the 32-bit output hash() methods and the 64-bit output hash64() methods (which use the slightly tweaked * wheathash variant in the waterhash Git repo, or woothash for hashing long arrays). While an earlier version * passed rurban/smhasher, it failed demerphq/smhasher (Yves' more stringent fork), so some minor tweaks allowed the * latest code to pass Yves' test. Uses 64-bit math, so it won't be as fast on GWT. Currently, the methods that hash * types other than int arrays aren't as fast as the int array hash, but they are usually faster than the default * Hive implementation, and unlike Hive, these pass SMHasher. *
* These hash functions are so fast because they operate in bulk on 4 items at a time, such as 4 ints (which is the * optimal case), 4 bytes, or 4 longs (which uses a different algorithm). This bulk operation usually entails 3 * multiplications and some other, cheaper operations per 4 items hashed. For long arrays, it requires many more * multiplications, but modern CPUs can pipeline the operations on unrelated longs to run in parallel on one core. * If any items are left over after the bulk segment, Water uses the least effort possible to hash the remaining 1, * 2, or 3 items left. Most of these operations use the method {@link #mum(long, long)}, which helps take two inputs * and multiply them once, getting a more-random result after another small step. The long array code uses * {@link #wow(long, long)} (similar to mum upside-down), which mixes up its arguments with each other before * multplying. It finishes with either code similar to mum() for 32-bit output hash() methods, or a somewhat more * rigorous method for 64-bit output hash64() methods (still similar to mum). */ @SuppressWarnings("NumericOverflow") public static final class Water { /** * Big constant 0. */ public static final long b0 = 0xA0761D6478BD642FL; /** * Big constant 1. */ public static final long b1 = 0xE7037ED1A0B428DBL; /** * Big constant 2. */ public static final long b2 = 0x8EBC6AF09C88C6E3L; /** * Big constant 3. */ public static final long b3 = 0x589965CC75374CC3L; /** * Big constant 4. */ public static final long b4 = 0x1D8E4E27C47D124FL; /** * Big constant 5. */ public static final long b5 = 0xEB44ACCAB455D165L; /** * Takes two arguments that are technically longs, and should be very different, and uses them to get a result * that is technically a long and mixes the bits of the inputs. The arguments and result are only technically * longs because their lower 32 bits matter much more than their upper 32, and giving just any long won't work. *
* This is very similar to wyhash's mum function, but doesn't use 128-bit math because it expects that its * arguments are only relevant in their lower 32 bits (allowing their product to fit in 64 bits). * @param a a long that should probably only hold an int's worth of data * @param b a long that should probably only hold an int's worth of data * @return a sort-of randomized output dependent on both inputs */ public static long mum(final long a, final long b) { final long n = a * b; return n - (n >>> 32); } /** * A slower but higher-quality variant on {@link #mum(long, long)} that can take two arbitrary longs (with any * of their 64 bits containing relevant data) instead of mum's 32-bit sections of its inputs, and outputs a * 64-bit result that can have any of its bits used. *
* This was changed so it distributes bits from both inputs a little better on July 6, 2019. * @param a any long * @param b any long * @return a sort-of randomized output dependent on both inputs */ public static long wow(final long a, final long b) { final long n = (a ^ (b << 39 | b >>> 25)) * (b ^ (a << 39 | a >>> 25)); return n ^ (n >>> 32); } public static long hash64(final boolean[] data) { if (data == null) return 0; long seed = 9069147967908697017L;//seed = b1 ^ b1 >>> 29 ^ b1 >>> 43 ^ b1 << 7 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum((data[i-3] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b1, (data[i-2] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b2) + seed, mum((data[i-1] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b3, (data[i] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (data[len-1] ? 0x9E37L : 0x7F4AL), b3 ^ (data[len-1] ? 0x79B9L : 0x7C15L)); break; case 2: seed = mum(seed ^ (data[len-2] ? 0x9E3779B9L : 0x7F4A7C15L), b0 ^ (data[len-1] ? 0x9E3779B9L : 0x7F4A7C15L)); break; case 3: seed = mum(seed ^ (data[len-3] ? 0x9E3779B9L : 0x7F4A7C15L), b2 ^ (data[len-2] ? 0x9E3779B9L : 0x7F4A7C15L)) ^ mum(seed ^ (data[len-1] ? 0x9E3779B9 : 0x7F4A7C15), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final byte[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b2, b1 ^ data[len-1]); break; case 2: seed = mum(seed ^ b3, data[len-2] ^ data[len-1] << 8 ^ b4); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 8, b2 ^ data[len-1]); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final short[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data[len-1]); break; case 2: seed = mum(seed ^ data[len-2], b3 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 16, b1 ^ data[len-1]); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final char[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data[len-1]); break; case 2: seed = mum(seed ^ data[len-2], b3 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 16, b1 ^ data[len-1]); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final CharSequence data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length(); for (int i = 3; i < len; i+=4) { seed = mum( mum(data.charAt(i-3) ^ b1, data.charAt(i-2) ^ b2) + seed, mum(data.charAt(i-1) ^ b3, data.charAt(i ) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data.charAt(len-1)); break; case 2: seed = mum(seed ^ data.charAt(len-2), b3 ^ data.charAt(len-1)); break; case 3: seed = mum(seed ^ data.charAt(len-3) ^ data.charAt(len-2) << 16, b1 ^ data.charAt(len-1)); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final int[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (data[len-1] >>> 16), b3 ^ (data[len-1] & 0xFFFFL)); break; case 2: seed = mum(seed ^ data[len-2], b0 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3], b2 ^ data[len-2]) ^ mum(seed ^ data[len-1], b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final int[] data, final int length) { if (data == null) return 0; long seed = 9069147967908697017L; for (int i = 3; i < length; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (length & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (data[length-1] >>> 16), b3 ^ (data[length-1] & 0xFFFFL)); break; case 2: seed = mum(seed ^ data[length-2], b0 ^ data[length-1]); break; case 3: seed = mum(seed ^ data[length-3], b2 ^ data[length-2]) ^ mum(seed ^ data[length-1], b4); break; } seed = (seed ^ seed << 16) * (length ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final long[] data) { if (data == null) return 0; long seed = 0x1E98AE18CA351B28L,// seed = b0 ^ b0 >>> 23 ^ b0 >>> 48 ^ b0 << 7 ^ b0 << 53, a = seed ^ b4, b = (seed << 17 | seed >>> 47) ^ b3, c = (seed << 31 | seed >>> 33) ^ b2, d = (seed << 47 | seed >>> 17) ^ b1; final int len = data.length; for (int i = 3; i < len; i+=4) { a = (data[i-3] ^ a) * b1; a = (a << 23 | a >>> 41) * b3; b = (data[i-2] ^ b) * b2; b = (b << 25 | b >>> 39) * b4; c = (data[i-1] ^ c) * b3; c = (c << 29 | c >>> 35) * b5; d = (data[i ] ^ d) * b4; d = (d << 31 | d >>> 33) * b1; seed += a + b + c + d; } seed += b5; switch (len & 3) { case 1: seed = wow(seed, b1 ^ data[len-1]); break; case 2: seed = wow(seed + data[len-2], b2 + data[len-1]); break; case 3: seed = wow(seed + data[len-3], b2 + data[len-2]) ^ wow(seed + data[len-1], seed ^ b3); break; } seed = (seed ^ seed << 16) * (len ^ b0 ^ seed >>> 32); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final float[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(floatToIntBits(data[i-3]) ^ b1, floatToIntBits(data[i-2]) ^ b2) + seed, mum(floatToIntBits(data[i-1]) ^ b3, floatToIntBits(data[i]) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (floatToIntBits(data[len-1]) >>> 16), b3 ^ (floatToIntBits(data[len-1]) & 0xFFFFL)); break; case 2: seed = mum(seed ^ floatToIntBits(data[len-2]), b0 ^ floatToIntBits(data[len-1])); break; case 3: seed = mum(seed ^ floatToIntBits(data[len-3]), b2 ^ floatToIntBits(data[len-2])) ^ mum(seed ^ floatToIntBits(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final double[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(doubleToMixedIntBits(data[i-3]) ^ b1, doubleToMixedIntBits(data[i-2]) ^ b2) + seed, mum(doubleToMixedIntBits(data[i-1]) ^ b3, doubleToMixedIntBits(data[i]) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (doubleToMixedIntBits(data[len-1]) >>> 16), b3 ^ (doubleToMixedIntBits(data[len-1]) & 0xFFFFL)); break; case 2: seed = mum(seed ^ doubleToMixedIntBits(data[len-2]), b0 ^ doubleToMixedIntBits(data[len-1])); break; case 3: seed = mum(seed ^ doubleToMixedIntBits(data[len-3]), b2 ^ doubleToMixedIntBits(data[len-2])) ^ mum(seed ^ doubleToMixedIntBits(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; long seed = 9069147967908697017L; final int len = Math.min(end, data.length); for (int i = start + 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len - start & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data[len-1]); break; case 2: seed = mum(seed ^ data[len-2], b3 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 16, b1 ^ data[len-1]); break; } return (int) mum(seed ^ seed << 16, len - start ^ b0); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static long hash64(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0; long seed = 9069147967908697017L; final int len = Math.min(end, data.length()); for (int i = start + 3; i < len; i+=4) { seed = mum( mum(data.charAt(i-3) ^ b1, data.charAt(i-2) ^ b2) + seed, mum(data.charAt(i-1) ^ b3, data.charAt(i) ^ b4)); } switch (len - start & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data.charAt(len-1)); break; case 2: seed = mum(seed ^ data.charAt(len-2), b3 ^ data.charAt(len-1)); break; case 3: seed = mum(seed ^ data.charAt(len-3) ^ data.charAt(len-2) << 16, b1 ^ data.charAt(len-1)); break; } return (int) mum(seed ^ seed << 16, len - start ^ b0); } public static long hash64(final char[][] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final int[][] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final long[][] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final CharSequence[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final CharSequence[]... data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final Iterable data) { if (data == null) return 0; long seed = 9069147967908697017L; final Iterator it = data.iterator(); int len = 0; while (it.hasNext()) { ++len; seed = mum( mum(hash(it.next()) ^ b1, (it.hasNext() ? hash(it.next()) ^ b2 ^ ++len : b2)) + seed, mum((it.hasNext() ? hash(it.next()) ^ b3 ^ ++len : b3), (it.hasNext() ? hash(it.next()) ^ b4 ^ ++len : b4))); } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final List data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.size(); for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data.get(i-3)) ^ b1, hash(data.get(i-2)) ^ b2) + seed, mum(hash(data.get(i-1)) ^ b3, hash(data.get(i )) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data.get(len-1))) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data.get(len-2)), b0 ^ hash(data.get(len-1))); break; case 3: seed = mum(seed ^ hash(data.get(len-3)), b2 ^ hash(data.get(len-2))) ^ mum(seed ^ hash(data.get(len-1)), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final Object[] data) { if (data == null) return 0; long seed = 9069147967908697017L; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } seed = (seed ^ seed << 16) * (len ^ b0); return seed - (seed >>> 31) + (seed << 33); } public static long hash64(final Object data) { if (data == null) return 0; final long h = data.hashCode() * 0x9E3779B97F4A7C15L; return h - (h >>> 31) + (h << 33); } public static int hash(final boolean[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum((data[i-3] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b1, (data[i-2] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b2) + seed, mum((data[i-1] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b3, (data[i] ? 0x9E3779B9L : 0x7F4A7C15L) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (data[len-1] ? 0x9E37L : 0x7F4AL), b3 ^ (data[len-1] ? 0x79B9L : 0x7C15L)); break; case 2: seed = mum(seed ^ (data[len-2] ? 0x9E3779B9L : 0x7F4A7C15L), b0 ^ (data[len-1] ? 0x9E3779B9L : 0x7F4A7C15L)); break; case 3: seed = mum(seed ^ (data[len-3] ? 0x9E3779B9L : 0x7F4A7C15L), b2 ^ (data[len-2] ? 0x9E3779B9L : 0x7F4A7C15L)) ^ mum(seed ^ (data[len-1] ? 0x9E3779B9 : 0x7F4A7C15), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final byte[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b2, b1 ^ data[len-1]); break; case 2: seed = mum(seed ^ b3, data[len-2] ^ data[len-1] << 8 ^ b4); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 8, b2 ^ data[len-1]); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final short[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data[len-1]); break; case 2: seed = mum(seed ^ data[len-2], b3 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 16, b1 ^ data[len-1]); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final char[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data[len-1]); break; case 2: seed = mum(seed ^ data[len-2], b3 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 16, b1 ^ data[len-1]); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final CharSequence data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length(); for (int i = 3; i < len; i+=4) { seed = mum( mum(data.charAt(i-3) ^ b1, data.charAt(i-2) ^ b2) + seed, mum(data.charAt(i-1) ^ b3, data.charAt(i ) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data.charAt(len-1)); break; case 2: seed = mum(seed ^ data.charAt(len-2), b3 ^ data.charAt(len-1)); break; case 3: seed = mum(seed ^ data.charAt(len-3) ^ data.charAt(len-2) << 16, b1 ^ data.charAt(len-1)); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final int[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (data[len-1] >>> 16), b3 ^ (data[len-1] & 0xFFFFL)); break; case 2: seed = mum(seed ^ data[len-2], b0 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3], b2 ^ data[len-2]) ^ mum(seed ^ data[len-1], b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final int[] data, final int length) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; for (int i = 3; i < length; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (length & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (data[length-1] >>> 16), b3 ^ (data[length-1] & 0xFFFFL)); break; case 2: seed = mum(seed ^ data[length-2], b0 ^ data[length-1]); break; case 3: seed = mum(seed ^ data[length-3], b2 ^ data[length-2]) ^ mum(seed ^ data[length-1], b4); break; } return (int) mum(seed ^ seed << 16, length ^ b0); } public static int hash(final long[] data) { if (data == null) return 0; long seed = 0x1E98AE18CA351B28L,// seed = b0 ^ b0 >>> 23 ^ b0 >>> 48 ^ b0 << 7 ^ b0 << 53, a = seed ^ b4, b = (seed << 17 | seed >>> 47) ^ b3, c = (seed << 31 | seed >>> 33) ^ b2, d = (seed << 47 | seed >>> 17) ^ b1; final int len = data.length; for (int i = 3; i < len; i+=4) { a = (data[i-3] ^ a) * b1; a = (a << 23 | a >>> 41) * b3; b = (data[i-2] ^ b) * b2; b = (b << 25 | b >>> 39) * b4; c = (data[i-1] ^ c) * b3; c = (c << 29 | c >>> 35) * b5; d = (data[i ] ^ d) * b4; d = (d << 31 | d >>> 33) * b1; seed += a + b + c + d; } seed += b5; switch (len & 3) { case 1: seed = wow(seed, b1 ^ data[len-1]); break; case 2: seed = wow(seed + data[len-2], b2 + data[len-1]); break; case 3: seed = wow(seed + data[len-3], b2 + data[len-2]) ^ wow(seed + data[len-1], seed ^ b3); break; } seed = (seed ^ seed << 16) * (len ^ b0 ^ seed >>> 32); return (int)(seed - (seed >>> 32)); } public static int hash(final float[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(floatToIntBits(data[i-3]) ^ b1, floatToIntBits(data[i-2]) ^ b2) + seed, mum(floatToIntBits(data[i-1]) ^ b3, floatToIntBits(data[i]) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (floatToIntBits(data[len-1]) >>> 16), b3 ^ (floatToIntBits(data[len-1]) & 0xFFFFL)); break; case 2: seed = mum(seed ^ floatToIntBits(data[len-2]), b0 ^ floatToIntBits(data[len-1])); break; case 3: seed = mum(seed ^ floatToIntBits(data[len-3]), b2 ^ floatToIntBits(data[len-2])) ^ mum(seed ^ floatToIntBits(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final double[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(doubleToMixedIntBits(data[i-3]) ^ b1, doubleToMixedIntBits(data[i-2]) ^ b2) + seed, mum(doubleToMixedIntBits(data[i-1]) ^ b3, doubleToMixedIntBits(data[i]) ^ b4)); } switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ (doubleToMixedIntBits(data[len-1]) >>> 16), b3 ^ (doubleToMixedIntBits(data[len-1]) & 0xFFFFL)); break; case 2: seed = mum(seed ^ doubleToMixedIntBits(data[len-2]), b0 ^ doubleToMixedIntBits(data[len-1])); break; case 3: seed = mum(seed ^ doubleToMixedIntBits(data[len-3]), b2 ^ doubleToMixedIntBits(data[len-2])) ^ mum(seed ^ doubleToMixedIntBits(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the char array to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final char[] data, final int start, final int end) { if (data == null || start >= end) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = Math.min(end, data.length); for (int i = start + 3; i < len; i+=4) { seed = mum( mum(data[i-3] ^ b1, data[i-2] ^ b2) + seed, mum(data[i-1] ^ b3, data[i] ^ b4)); } switch (len - start & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data[len-1]); break; case 2: seed = mum(seed ^ data[len-2], b3 ^ data[len-1]); break; case 3: seed = mum(seed ^ data[len-3] ^ data[len-2] << 16, b1 ^ data[len-1]); break; } return (int) mum(seed ^ seed << 16, len - start ^ b0); } /** * Hashes only a subsection of the given data, starting at start (inclusive) and ending before end (exclusive). * * @param data the String or other CharSequence to hash * @param start the start of the section to hash (inclusive) * @param end the end of the section to hash (exclusive) * @return a 32-bit hash code for the requested section of data */ public static int hash(final CharSequence data, final int start, final int end) { if (data == null || start >= end) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = Math.min(end, data.length()); for (int i = start + 3; i < len; i+=4) { seed = mum( mum(data.charAt(i-3) ^ b1, data.charAt(i-2) ^ b2) + seed, mum(data.charAt(i-1) ^ b3, data.charAt(i) ^ b4)); } switch (len - start & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^ b3, b4 ^ data.charAt(len-1)); break; case 2: seed = mum(seed ^ data.charAt(len-2), b3 ^ data.charAt(len-1)); break; case 3: seed = mum(seed ^ data.charAt(len-3) ^ data.charAt(len-2) << 16, b1 ^ data.charAt(len-1)); break; } return (int) mum(seed ^ seed << 16, len - start ^ b0); } public static int hash(final char[][] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final int[][] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final long[][] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final CharSequence[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final CharSequence[]... data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final Iterable data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final Iterator it = data.iterator(); int len = 0; while (it.hasNext()) { ++len; seed = mum( mum(hash(it.next()) ^ b1, (it.hasNext() ? hash(it.next()) ^ b2 ^ ++len : b2)) + seed, mum((it.hasNext() ? hash(it.next()) ^ b3 ^ ++len : b3), (it.hasNext() ? hash(it.next()) ^ b4 ^ ++len : b4))); } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final List data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.size(); for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data.get(i-3)) ^ b1, hash(data.get(i-2)) ^ b2) + seed, mum(hash(data.get(i-1)) ^ b3, hash(data.get(i )) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data.get(len-1))) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data.get(len-2)), b0 ^ hash(data.get(len-1))); break; case 3: seed = mum(seed ^ hash(data.get(len-3)), b2 ^ hash(data.get(len-2))) ^ mum(seed ^ hash(data.get(len-1)), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final Object[] data) { if (data == null) return 0; long seed = -260224914646652572L;//b1 ^ b1 >>> 41 ^ b1 << 53; final int len = data.length; for (int i = 3; i < len; i+=4) { seed = mum( mum(hash(data[i-3]) ^ b1, hash(data[i-2]) ^ b2) + seed, mum(hash(data[i-1]) ^ b3, hash(data[i ]) ^ b4)); } int t; switch (len & 3) { case 0: seed = mum(b1 ^ seed, b4 + seed); break; case 1: seed = mum(seed ^((t = hash(data[len-1])) >>> 16), b3 ^ (t & 0xFFFFL)); break; case 2: seed = mum(seed ^ hash(data[len-2]), b0 ^ hash(data[len-1])); break; case 3: seed = mum(seed ^ hash(data[len-3]), b2 ^ hash(data[len-2])) ^ mum(seed ^ hash(data[len-1]), b4); break; } return (int) mum(seed ^ seed << 16, len ^ b0); } public static int hash(final Object data) { if (data == null) return 0; final int h = data.hashCode() * 0x9E375; return h ^ (h >>> 16); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy