@@ -5,4 +5,4 @@ this is a non-cryptographic hash optimized for short strings. | |||
adapted from CodeDweller/mishmash.h/cpp | |||
https://code.microneil.com/madscientist/CodeDweller/src/branch/master | |||
to use: use the Mishmash function. If you're in need of a second hash (or could be) keep the second value returned, that's the accumulator. Mishmash will take that in a second call, along with your string, to create a second hash. | |||
to use: use the Mishmash function. If you're in need of a second hash use Engine instead, which will return the accumulator. You can use the MishmashAccumulator function to mishmash your accumulator, and could also feed that accumulator back into Mishmash to double hash. |
@@ -39,39 +39,49 @@ func slct(n uint64) uint32 { | |||
} | |||
func Engine(buffer []byte, length int, accumulator uint64) uint64 { | |||
// exported for ease of use - Mishmash below returns | |||
// both the mishmash AND accumulator | |||
for i := 0; i < length; i++ { | |||
b := buffer[i] | |||
accumulator += uint64(slct(accumulator)) + uint64(b) | |||
accumulator *= uint64(slct(uint64(b))) | |||
accumulator += accumulator >> 32 | |||
} | |||
return accumulator | |||
} | |||
func Mishmash(buffer []byte, nums ...uint64) (uint32, uint64) { | |||
// returns mishmashHash, accumulator | |||
func Mishmash(buffer []byte, nums ...uint64) uint32 { | |||
// nums is a seed/accumulator | |||
var accumulator uint64 | |||
if 0 == len(nums) { | |||
// seeding with 0 by default - could be changed | |||
accumulator = Engine(buffer, len(buffer), 0) | |||
} else { | |||
accumulator = Engine(buffer, len(buffer), nums[0]) | |||
} | |||
return uint32(accumulator & 0x00000000ffffffff), accumulator | |||
return uint32(accumulator & 0x00000000ffffffff) | |||
} | |||
func MishmashAccumulator(accumulator uint64) uint32 { | |||
// use when collecting accumulators for second hash | |||
return uint32(accumulator & 0x00000000ffffffff) | |||
} | |||
// example below shows calling Mishmash on "hello world" | |||
// and then collecting the hash and accumulator. Given | |||
// and then collecting the hash. Given | |||
// a collision we simply call Mishmash again, giving it | |||
// the accumulator this time, and get a second hash. | |||
// the first hash as a seed this time and get a second hash. | |||
/* | |||
func main() { | |||
buf := []byte("Hello world") | |||
hash, accumulator := Mishmash(buf) | |||
fmt.Println(uint32(hash & 0x00000000ffffffff)) | |||
secondHash, accumulator := Mishmash(buf, accumulator) | |||
fmt.Println(uint32(secondHash & 0x00000000ffffffff)) | |||
// grab the accumulator if necessary | |||
accum := Engine(buf, len(buf), 0) | |||
// grab the hash - decode accumulator into hash | |||
hash := MishmashAccumulator(accum) | |||
fmt.Printf("%08x\n", hash) | |||
// now get second hash - seed with accumulator | |||
secondHash := Mishmash(buf, accum) | |||
fmt.Printf("%08x\n", secondHash) | |||
// you can also get a simple hash | |||
simpleMishmash := Mishmash(buf) | |||
fmt.Printf("%08x\n", simpleMishmash) | |||
} | |||
*/ |
@@ -7,9 +7,7 @@ import ( | |||
func TestMishmash(t *testing.T) { | |||
want := "9d923077" | |||
hash, _ := Mishmash([]byte("google.com")) | |||
got := fmt.Sprintf("%08x", hash) | |||
if want != got { | |||
if got := fmt.Sprintf("%08x", Mishmash([]byte("google.com"))); want != got { | |||
t.Error("Parse() = got", got, "want", want) | |||
} else { | |||
fmt.Println("TestMishmash Passed") | |||
@@ -17,14 +15,31 @@ func TestMishmash(t *testing.T) { | |||
} | |||
func TestSecondHash(t *testing.T) { | |||
want := "65df1304" | |||
_, accum := Mishmash([]byte("google.com")) | |||
hash, accum := Mishmash([]byte("google.com"), accum) | |||
got := fmt.Sprintf("%08x", hash) | |||
if want != got { | |||
want := "3fbdb348" | |||
hash := Mishmash([]byte("google.com")) | |||
if got := fmt.Sprintf("%08x", Mishmash([]byte("google.com"), uint64(hash))); want != got { | |||
t.Error("Parse() = got", got, "want", want) | |||
} else { | |||
fmt.Println("TestSecondHash Passed") | |||
} | |||
} | |||
func TestSeedOne(t *testing.T) { | |||
want := "cebf5691" | |||
if got := fmt.Sprintf("%08x", Mishmash([]byte("google.com"), uint64(1))); want != got { | |||
t.Error("Parse() = got", got, "want", want) | |||
} else { | |||
fmt.Println("TestSeedOne Passed") | |||
} | |||
} | |||
func TestEngineAndAccumulator(t *testing.T) { | |||
want := "65df1304" | |||
test := []byte("google.com") | |||
accum := Engine(test, len(test), 0) | |||
if got := fmt.Sprintf("%08x", Mishmash(test, accum)); want != got { | |||
t.Error("Parse() = got", got, "want", want) | |||
} else { | |||
fmt.Println("TestEngineAndAccumulator Passed") | |||
} | |||
} |