Xor16 (final long[] keys, final int offset, final int length) { final int arrayLength = getArrayLength(length); final int blockLength = arrayLength / HASHES; final long[] reverseOrder = new long[length]; final byte[] reverseH = new byte[length]; int reverseOrderPos; // constant seed - reproducible JARs (initial seed just a random number) long seed = 1354212L; do { seed = mix(seed); byte[] t2count = new byte[arrayLength]; long[] t2 = new long[arrayLength]; for (int i = offset; i < length; i++) { long k = keys[i]; for (int hi = 0; hi < HASHES; hi++) { int h = getHash(blockLength, k, seed, hi); t2[h] ^= k; if (t2count[h] > 120) { throw new IllegalArgumentException(); } t2count[h]++; } } int[] alone = new int[arrayLength]; int alonePos = 0; reverseOrderPos = 0; for (int nextAloneCheck = 0; nextAloneCheck < arrayLength; ) { while (nextAloneCheck < arrayLength) { if (t2count[nextAloneCheck] == 1) { alone[alonePos++] = nextAloneCheck; } nextAloneCheck++; } while (alonePos > 0) { int i = alone[--alonePos]; if (t2count[i] == 0) { continue; } long k = t2[i]; byte found = -1; for (int hi = 0; hi < HASHES; hi++) { int h = getHash(blockLength, k, seed, hi); int newCount = --t2count[h]; if (newCount == 0) { found = (byte)hi; } else { if (newCount == 1) { alone[alonePos++] = h; } t2[h] ^= k; } } reverseOrder[reverseOrderPos] = k; reverseH[reverseOrderPos] = found; reverseOrderPos++; } } } while (reverseOrderPos != length); short[] fingerprints = new short[arrayLength]; for (int i = reverseOrderPos - 1; i >= 0; i--) { long k = reverseOrder[i]; int found = reverseH[i]; int change = -1; long hash = hash64(k, seed); int xor = fingerprint(hash); for (int hi = 0; hi < HASHES; hi++) { int h = getHash(blockLength, k, seed, hi); if (found == hi) { change = h; } else { xor ^= fingerprints[h]; } } fingerprints[change] = (short)xor; } return new Xor16(fingerprints, blockLength, seed); }