milvus/pkg/util/cache/hash.go
jaime c9d0c157ec
Move some modules from internal to public package (#22572)
Signed-off-by: jaime <yun.zhang@zilliz.com>
2023-04-06 19:14:32 +08:00

141 lines
3.1 KiB
Go

// Licensed to the LF AI & Data foundation under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
package cache
import (
"math"
"reflect"
)
// Hash is an interface implemented by cache keys to
// override default hash function.
type Hash interface {
Sum64() uint64
}
// sum calculates hash value of the given key.
func sum(k interface{}) uint64 {
switch h := k.(type) {
case Hash:
return h.Sum64()
case int:
return hashU64(uint64(h))
case int8:
return hashU32(uint32(h))
case int16:
return hashU32(uint32(h))
case int32:
return hashU32(uint32(h))
case int64:
return hashU64(uint64(h))
case uint:
return hashU64(uint64(h))
case uint8:
return hashU32(uint32(h))
case uint16:
return hashU32(uint32(h))
case uint32:
return hashU32(h)
case uint64:
return hashU64(h)
case uintptr:
return hashU64(uint64(h))
case float32:
return hashU32(math.Float32bits(h))
case float64:
return hashU64(math.Float64bits(h))
case bool:
if h {
return 1
}
return 0
case string:
return hashString(h)
}
// TODO: complex64 and complex128
if h, ok := hashPointer(k); ok {
return h
}
// TODO: use gob to encode k to bytes then hash.
return 0
}
const (
fnvOffset uint64 = 14695981039346656037
fnvPrime uint64 = 1099511628211
)
func hashU64(v uint64) uint64 {
// Inline code from hash/fnv to reduce memory allocations
h := fnvOffset
// for i := uint(0); i < 64; i += 8 {
// h ^= (v >> i) & 0xFF
// h *= fnvPrime
// }
h ^= (v >> 0) & 0xFF
h *= fnvPrime
h ^= (v >> 8) & 0xFF
h *= fnvPrime
h ^= (v >> 16) & 0xFF
h *= fnvPrime
h ^= (v >> 24) & 0xFF
h *= fnvPrime
h ^= (v >> 32) & 0xFF
h *= fnvPrime
h ^= (v >> 40) & 0xFF
h *= fnvPrime
h ^= (v >> 48) & 0xFF
h *= fnvPrime
h ^= (v >> 56) & 0xFF
h *= fnvPrime
return h
}
func hashU32(v uint32) uint64 {
h := fnvOffset
h ^= uint64(v>>0) & 0xFF
h *= fnvPrime
h ^= uint64(v>>8) & 0xFF
h *= fnvPrime
h ^= uint64(v>>16) & 0xFF
h *= fnvPrime
h ^= uint64(v>>24) & 0xFF
h *= fnvPrime
return h
}
// hashString calculates hash value using FNV-1a algorithm.
func hashString(data string) uint64 {
// Inline code from hash/fnv to reduce memory allocations
h := fnvOffset
for _, b := range data {
h ^= uint64(b)
h *= fnvPrime
}
return h
}
func hashPointer(k interface{}) (uint64, bool) {
v := reflect.ValueOf(k)
switch v.Kind() {
case reflect.Ptr, reflect.UnsafePointer, reflect.Func, reflect.Slice, reflect.Map, reflect.Chan:
return hashU64(uint64(v.Pointer())), true
default:
return 0, false
}
}