diff --git a/bytes/bytes_test.mbt b/bytes/bytes_test.mbt index 657a6c11..88fec3c9 100644 --- a/bytes/bytes_test.mbt +++ b/bytes/bytes_test.mbt @@ -24,8 +24,12 @@ test "hash" { let b2 = Bytes::[ 65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0, 74, 0, ] + let b3 = Bytes::[128, 0, 0, 0, 0, 0, 0, 0] + let b4 = Bytes::[127, 255, 255, 255, 255, 255, 255, 255] inspect(b1.hash(), content="273427599")? inspect(b2.hash(), content="2013728637")? + inspect(b3.hash(), content="-983520567")? + inspect(b4.hash(), content="-1652773543")? inspect(b1.hash() == b1.hash(), content="true")? inspect(b2.hash() == b2.hash(), content="true")? inspect(b1.hash() == b2.hash(), content="false")? diff --git a/bytes/xxhash.mbt b/bytes/xxhash.mbt index d6713416..016eb1cf 100644 --- a/bytes/xxhash.mbt +++ b/bytes/xxhash.mbt @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// https://github.com/Cyan4973/xxHash/blob/dev/doc/xxhash_spec.md#xxh32-algorithm-description + let gPRIME1 = -1640531535 let gPRIME2 = -2048144777 diff --git a/int64/int64.mbt b/int64/int64.mbt index c0def2e3..859e8ef1 100644 --- a/int64/int64.mbt +++ b/int64/int64.mbt @@ -47,25 +47,3 @@ pub fn Int64::max_value() -> Int64 { pub fn Int64::min_value() -> Int64 { min_val } - -pub fn hash(self : Int64) -> Int { - let b = Bytes::make(8) - b[0] = self.lsr(56).to_byte() - b[1] = self.lsr(48).land(0xFFL).to_byte() - b[2] = self.lsr(40).land(0xFFL).to_byte() - b[3] = self.lsr(32).land(0xFFL).to_byte() - b[4] = self.lsr(24).land(0xFFL).to_byte() - b[5] = self.lsr(16).land(0xFFL).to_byte() - b[6] = self.lsr(8).land(0xFFL).to_byte() - b[7] = self.land(0xFFL).to_byte() - b.hash() -} - -test "int64 hash" { - @assertion.assert_eq(0L.hash(), 0L.hash())? - @assertion.assert_eq(1L.hash(), 1L.hash())? - @assertion.assert_ne(0L.hash(), 1L.hash())? - @assertion.assert_eq(0x7fffffffffffffffL.hash(), 0x7fffffffffffffffL.hash())? - @assertion.assert_ne(0x7fffffffffffffffL.hash(), 0x8000000000000000L.hash())? - @assertion.assert_eq(0x8000000000000000L.hash(), 0x8000000000000000L.hash())? -} diff --git a/int64/xxhash.mbt b/int64/xxhash.mbt new file mode 100644 index 00000000..85b0a29e --- /dev/null +++ b/int64/xxhash.mbt @@ -0,0 +1,76 @@ +// Copyright 2024 International Digital Economy Academy +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub fn slow_hash(self : Int64) -> Int { + let b = Bytes::make(8) + b[7] = self.lsr(56).to_byte() + b[6] = self.lsr(48).land(0xFFL).to_byte() + b[5] = self.lsr(40).land(0xFFL).to_byte() + b[4] = self.lsr(32).land(0xFFL).to_byte() + b[3] = self.lsr(24).land(0xFFL).to_byte() + b[2] = self.lsr(16).land(0xFFL).to_byte() + b[1] = self.lsr(8).land(0xFFL).to_byte() + b[0] = self.land(0xFFL).to_byte() + b.hash() +} + +// Not needed for 8 bytes data +// let gPRIME1 = -1640531535 + +let gPRIME2 = -2048144777 + +let gPRIME3 = -1028477379 + +let gPRIME4 = 668265263 + +let gPRIME5 = 374761393 + +// https://github.com/Cyan4973/xxHash/blob/dev/doc/xxhash_spec.md#xxh32-algorithm-description +// For a more readable version, see bytes/xxhash.mbt +pub fn hash(self : Int64) -> Int { + let mut input = self + let seed = 0 + let mut len = 8 + let mut acc = seed + gPRIME5 + len + while len > 0 { + len -= 4 + let x = acc + input.to_int() * gPRIME3 + let r = 17 + acc = x.lsl(r).lor(x.lsr(32 - r)) * gPRIME4 + input = input.lsr(32) + } + acc = acc.lxor(acc.lsr(15)) + acc *= gPRIME2 + acc = acc.lxor(acc.lsr(13)) + acc *= gPRIME3 + acc = acc.lxor(acc.lsr(16)) + acc +} + +test "hash" { + let i0 = 9_223_372_036_854_775_807L // INT64_MAX + let i1 = -9_223_372_036_854_775_808L // INT64_MIN + let i2 = gPRIME2.to_int64() + let i3 = gPRIME3.to_int64() + let i4 = gPRIME4.to_int64() + let i5 = gPRIME5.to_int64() + let i6 = 0L + inspect(i0.hash().to_string(), content=i0.slow_hash().to_string())? + inspect(i1.hash().to_string(), content=i1.slow_hash().to_string())? + inspect(i2.hash().to_string(), content=i2.slow_hash().to_string())? + inspect(i3.hash().to_string(), content=i3.slow_hash().to_string())? + inspect(i4.hash().to_string(), content=i4.slow_hash().to_string())? + inspect(i5.hash().to_string(), content=i5.slow_hash().to_string())? + inspect(i6.hash().to_string(), content=i6.slow_hash().to_string())? +}