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

commonMain.com.goncalossilva.murmurhash.MurmurHash3.kt Maven / Gradle / Ivy

Go to download

A Kotlin Multiplatform implementation of the SymSpell Spell Checking algorithm.

There is a newer version: 3.1.0
Show newest version
package com.goncalossilva.murmurhash

// Copied from https://github.com/goncalossilva/kotlinx-murmurhash
public class MurmurHash3(private val seed: UInt = 0u) {
	public fun hash32x86(key: ByteArray): UInt {
		var h = seed
		val len = key.size
		val nblocks = len / 4

		for (i in 0 until nblocks * 4 step 4) {
			val k = key.getLittleEndianUInt(i)

			h = h xor k.mix(R1_32, C1_32, C2_32)
			h = h.rotateLeft(R2_32)
			h = h * M_32 + N_32
		}

		val index = nblocks * 4
		val rem = len - index
		var k = 0u
		if (rem == 3) {
			k = k xor (key.getUInt(index + 2) shl 16)
		}
		if (rem >= 2) {
			k = k xor (key.getUInt(index + 1) shl 8)
		}
		if (rem >= 1) {
			k = k xor key.getUInt(index)
			h = h xor k.mix(R1_32, C1_32, C2_32)
		}

		h = h xor len.toUInt()

		h = h.fmix()

		return h
	}

	public fun hash128x86(key: ByteArray): Array {
		var h1 = seed
		var h2 = seed
		var h3 = seed
		var h4 = seed
		val len = key.size
		val nblocks = len / 16

		for (i in 0 until nblocks * 16 step 16) {
			val k1 = key.getLittleEndianUInt(i)
			val k2 = key.getLittleEndianUInt(i + 4)
			val k3 = key.getLittleEndianUInt(i + 8)
			val k4 = key.getLittleEndianUInt(i + 12)

			h1 = h1 xor k1.mix(R1_128x86, C1_128x86, C2_128x86)
			h1 = h1.rotateLeft(R5_128x86)
			h1 += h2
			h1 = h1 * M_128x86 + N1_128x86

			h2 = h2 xor k2.mix(R2_128x86, C2_128x86, C3_128x86)
			h2 = h2.rotateLeft(R3_128x86)
			h2 += h3
			h2 = h2 * M_128x86 + N2_128x86

			h3 = h3 xor k3.mix(R3_128x86, C3_128x86, C4_128x86)
			h3 = h3.rotateLeft(R1_128x86)
			h3 += h4
			h3 = h3 * M_128x86 + N3_128x86

			h4 = h4 xor k4.mix(R4_128x86, C4_128x86, C1_128x86)
			h4 = h4.rotateLeft(R6_128x86)
			h4 += h1
			h4 = h4 * M_128x86 + N4_128x86
		}

		val index = nblocks * 16
		val rem = len - index
		var k1 = 0u
		var k2 = 0u
		var k3 = 0u
		var k4 = 0u
		if (rem == 15) {
			k4 = k4 xor (key.getUInt(index + 14) shl 16)
		}
		if (rem >= 14) {
			k4 = k4 xor (key.getUInt(index + 13) shl 8)
		}
		if (rem >= 13) {
			k4 = k4 xor key.getUInt(index + 12)
			h4 = h4 xor k4.mix(R4_128x86, C4_128x86, C1_128x86)
		}
		if (rem >= 12) {
			k3 = k3 xor (key.getUInt(index + 11) shl 24)
		}
		if (rem >= 11) {
			k3 = k3 xor (key.getUInt(index + 10) shl 16)
		}
		if (rem >= 10) {
			k3 = k3 xor (key.getUInt(index + 9) shl 8)
		}
		if (rem >= 9) {
			k3 = k3 xor key.getUInt(index + 8)
			h3 = h3 xor k3.mix(R3_128x86, C3_128x86, C4_128x86)
		}
		if (rem >= 8) {
			k2 = k2 xor (key.getUInt(index + 7) shl 24)
		}
		if (rem >= 7) {
			k2 = k2 xor (key.getUInt(index + 6) shl 16)
		}
		if (rem >= 6) {
			k2 = k2 xor (key.getUInt(index + 5) shl 8)
		}
		if (rem >= 5) {
			k2 = k2 xor key.getUInt(index + 4)
			h2 = h2 xor k2.mix(R2_128x86, C2_128x86, C3_128x86)
		}
		if (rem >= 4) {
			k1 = k1 xor (key.getUInt(index + 3) shl 24)
		}
		if (rem >= 3) {
			k1 = k1 xor (key.getUInt(index + 2) shl 16)
		}
		if (rem >= 2) {
			k1 = k1 xor (key.getUInt(index + 1) shl 8)
		}
		if (rem >= 1) {
			k1 = k1 xor key.getUInt(index)
			h1 = h1 xor k1.mix(R1_128x86, C1_128x86, C2_128x86)
		}

		h1 = h1 xor len.toUInt()
		h2 = h2 xor len.toUInt()
		h3 = h3 xor len.toUInt()
		h4 = h4 xor len.toUInt()

		h1 += h2
		h1 += h3
		h1 += h4
		h2 += h1
		h3 += h1
		h4 += h1

		h1 = h1.fmix()
		h2 = h2.fmix()
		h3 = h3.fmix()
		h4 = h4.fmix()

		h1 += h2
		h1 += h3
		h1 += h4
		h2 += h1
		h3 += h1
		h4 += h1

		return arrayOf(h1, h2, h3, h4)
	}

	public fun hash128x64(key: ByteArray): Array {
		var h1 = seed.toULong()
		var h2 = seed.toULong()
		val len = key.size
		val nblocks = len / 16

		for (i in 0 until nblocks * 16 step 16) {
			val k1 = key.getLittleEndianLong(i)
			val k2 = key.getLittleEndianLong(i + 8)

			h1 = h1 xor k1.mix(R1_128x64, C1_128x64, C2_128x64)
			h1 = h1.rotateLeft(R2_128x64)
			h1 += h2
			h1 = h1 * M_128x64 + N1_128x64

			h2 = h2 xor k2.mix(R3_128x64, C2_128x64, C1_128x64)
			h2 = h2.rotateLeft(R1_128x64)
			h2 += h1
			h2 = h2 * M_128x64 + N2_128x64
		}

		val index = nblocks * 16
		val rem = len - index
		var k1 = 0uL
		var k2 = 0uL
		if (rem == 15) {
			k2 = k2 xor (key.getULong(index + 14) shl 48)
		}
		if (rem >= 14) {
			k2 = k2 xor (key.getULong(index + 13) shl 40)
		}
		if (rem >= 13) {
			k2 = k2 xor (key.getULong(index + 12) shl 32)
		}
		if (rem >= 12) {
			k2 = k2 xor (key.getULong(index + 11) shl 24)
		}
		if (rem >= 11) {
			k2 = k2 xor (key.getULong(index + 10) shl 16)
		}
		if (rem >= 10) {
			k2 = k2 xor (key.getULong(index + 9) shl 8)
		}
		if (rem >= 9) {
			k2 = k2 xor key.getULong(index + 8)
			h2 = h2 xor k2.mix(R3_128x64, C2_128x64, C1_128x64)
		}
		if (rem >= 8) {
			k1 = k1 xor (key.getULong(index + 7) shl 56)
		}
		if (rem >= 7) {
			k1 = k1 xor (key.getULong(index + 6) shl 48)
		}
		if (rem >= 6) {
			k1 = k1 xor (key.getULong(index + 5) shl 40)
		}
		if (rem >= 5) {
			k1 = k1 xor (key.getULong(index + 4) shl 32)
		}
		if (rem >= 4) {
			k1 = k1 xor (key.getULong(index + 3) shl 24)
		}
		if (rem >= 3) {
			k1 = k1 xor (key.getULong(index + 2) shl 16)
		}
		if (rem >= 2) {
			k1 = k1 xor (key.getULong(index + 1) shl 8)
		}
		if (rem >= 1) {
			k1 = k1 xor key.getULong(index)
			h1 = h1 xor k1.mix(R1_128x64, C1_128x64, C2_128x64)
		}

		h1 = h1 xor len.toULong()
		h2 = h2 xor len.toULong()

		h1 += h2
		h2 += h1

		h1 = h1.fmix()
		h2 = h2.fmix()

		h1 += h2
		h2 += h1

		return arrayOf(h1, h2)
	}

	private fun ByteArray.getLittleEndianUInt(index: Int): UInt {
		return this.getUInt(index) or
				(this.getUInt(index + 1) shl 8) or
				(this.getUInt(index + 2) shl 16) or
				(this.getUInt(index + 3) shl 24)
	}

	private fun ByteArray.getLittleEndianLong(index: Int): ULong {
		return this.getULong(index) or
				(this.getULong(index + 1) shl 8) or
				(this.getULong(index + 2) shl 16) or
				(this.getULong(index + 3) shl 24) or
				(this.getULong(index + 4) shl 32) or
				(this.getULong(index + 5) shl 40) or
				(this.getULong(index + 6) shl 48) or
				(this.getULong(index + 7) shl 56)
	}

	private fun UInt.mix(r: Int, c1: UInt, c2: UInt): UInt {
		var k = this
		k *= c1
		k = k.rotateLeft(r)
		k *= c2
		return k
	}

	private fun ULong.mix(r: Int, c1: ULong, c2: ULong): ULong {
		var k = this
		k *= c1
		k = k.rotateLeft(r)
		k *= c2
		return k
	}

	private fun UInt.fmix(): UInt {
		var h = this
		h = h xor (h shr 16)
		h *= 0x85ebca6bu
		h = h xor (h shr 13)
		h *= 0xc2b2ae35u
		h = h xor (h shr 16)
		return h
	}

	private fun ULong.fmix(): ULong {
		var h = this
		h = h xor (h shr 33)
		h *= 0xff51afd7ed558ccduL
		h = h xor (h shr 33)
		h *= 0xc4ceb9fe1a85ec53uL
		h = h xor (h shr 33)
		return h
	}

	private fun ByteArray.getUInt(index: Int) = get(index).toUByte().toUInt()

	private fun ByteArray.getULong(index: Int) = get(index).toUByte().toULong()

	private companion object {
		private const val C1_32: UInt = 0xcc9e2d51u
		private const val C2_32: UInt = 0x1b873593u

		private const val R1_32: Int = 15
		private const val R2_32: Int = 13

		private const val M_32: UInt = 5u
		private const val N_32: UInt = 0xe6546b64u

		private const val C1_128x86: UInt = 0x239b961bu
		private const val C2_128x86: UInt = 0xab0e9789u
		private const val C3_128x86: UInt = 0x38b34ae5u
		private const val C4_128x86: UInt = 0xa1e38b93u

		private const val R1_128x86: Int = 15
		private const val R2_128x86: Int = 16
		private const val R3_128x86: Int = 17
		private const val R4_128x86: Int = 18
		private const val R5_128x86: Int = 19
		private const val R6_128x86: Int = 13

		private const val M_128x86: UInt = 5u
		private const val N1_128x86: UInt = 0x561ccd1bu
		private const val N2_128x86: UInt = 0x0bcaa747u
		private const val N3_128x86: UInt = 0x96cd1c35u
		private const val N4_128x86: UInt = 0x32ac3b17u

		private const val C1_128x64: ULong = 0x87c37b91114253d5uL
		private const val C2_128x64: ULong = 0x4cf5ad432745937fuL

		private const val R1_128x64: Int = 31
		private const val R2_128x64: Int = 27
		private const val R3_128x64: Int = 33

		private const val M_128x64: ULong = 5u
		private const val N1_128x64: ULong = 0x52dce729u
		private const val N2_128x64: ULong = 0x38495ab5u
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy