Revert "src/runtime: first darft of map growth code"
This reverts commit 7e05efa274
.
Этот коммит содержится в:
родитель
dcd8ee63a8
коммит
1dcdd5f2d2
2 изменённых файлов: 28 добавлений и 156 удалений
|
@ -10,13 +10,6 @@ import (
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// constants for hashmap algorithms; must match src/runtime/hashmap.go
|
|
||||||
const (
|
|
||||||
hashmapAlgorithmBinary = iota
|
|
||||||
hashmapAlgorithmString
|
|
||||||
hashmapAlgorithmInterface
|
|
||||||
)
|
|
||||||
|
|
||||||
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
|
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
|
||||||
// initializing an appropriately sized object.
|
// initializing an appropriately sized object.
|
||||||
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||||
|
@ -24,27 +17,22 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||||
keyType := mapType.Key().Underlying()
|
keyType := mapType.Key().Underlying()
|
||||||
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
|
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
|
||||||
var llvmKeyType llvm.Type
|
var llvmKeyType llvm.Type
|
||||||
var alg uint64 // must match values in src/runtime/hashmap.go
|
|
||||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||||
// String keys.
|
// String keys.
|
||||||
llvmKeyType = b.getLLVMType(keyType)
|
llvmKeyType = b.getLLVMType(keyType)
|
||||||
alg = hashmapAlgorithmString
|
|
||||||
} else if hashmapIsBinaryKey(keyType) {
|
} else if hashmapIsBinaryKey(keyType) {
|
||||||
// Trivially comparable keys.
|
// Trivially comparable keys.
|
||||||
llvmKeyType = b.getLLVMType(keyType)
|
llvmKeyType = b.getLLVMType(keyType)
|
||||||
alg = hashmapAlgorithmBinary
|
|
||||||
} else {
|
} else {
|
||||||
// All other keys. Implemented as map[interface{}]valueType for ease of
|
// All other keys. Implemented as map[interface{}]valueType for ease of
|
||||||
// implementation.
|
// implementation.
|
||||||
llvmKeyType = b.getLLVMRuntimeType("_interface")
|
llvmKeyType = b.getLLVMRuntimeType("_interface")
|
||||||
alg = hashmapAlgorithmInterface
|
|
||||||
}
|
}
|
||||||
keySize := b.targetData.TypeAllocSize(llvmKeyType)
|
keySize := b.targetData.TypeAllocSize(llvmKeyType)
|
||||||
valueSize := b.targetData.TypeAllocSize(llvmValueType)
|
valueSize := b.targetData.TypeAllocSize(llvmValueType)
|
||||||
llvmKeySize := llvm.ConstInt(b.ctx.Int8Type(), keySize, false)
|
llvmKeySize := llvm.ConstInt(b.ctx.Int8Type(), keySize, false)
|
||||||
llvmValueSize := llvm.ConstInt(b.ctx.Int8Type(), valueSize, false)
|
llvmValueSize := llvm.ConstInt(b.ctx.Int8Type(), valueSize, false)
|
||||||
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
||||||
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
|
|
||||||
if expr.Reserve != nil {
|
if expr.Reserve != nil {
|
||||||
sizeHint = b.getValue(expr.Reserve)
|
sizeHint = b.getValue(expr.Reserve)
|
||||||
var err error
|
var err error
|
||||||
|
@ -53,7 +41,7 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
|
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint}, "")
|
||||||
return hashmap, nil
|
return hashmap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,23 +12,14 @@ import (
|
||||||
|
|
||||||
// The underlying hashmap structure for Go.
|
// The underlying hashmap structure for Go.
|
||||||
type hashmap struct {
|
type hashmap struct {
|
||||||
|
next *hashmap // hashmap after evacuate (for iterators)
|
||||||
buckets unsafe.Pointer // pointer to array of buckets
|
buckets unsafe.Pointer // pointer to array of buckets
|
||||||
count uintptr
|
count uintptr
|
||||||
keySize uint8 // maybe this can store the key type as well? E.g. keysize == 5 means string?
|
keySize uint8 // maybe this can store the key type as well? E.g. keysize == 5 means string?
|
||||||
valueSize uint8
|
valueSize uint8
|
||||||
bucketBits uint8
|
bucketBits uint8
|
||||||
keyEqual func(x, y unsafe.Pointer, n uintptr) bool
|
|
||||||
keyHash func(key unsafe.Pointer, size uintptr) uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type hashmapAlgorithm uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
hashmapAlgorithmBinary hashmapAlgorithm = iota
|
|
||||||
hashmapAlgorithmString
|
|
||||||
hashmapAlgorithmInterface
|
|
||||||
)
|
|
||||||
|
|
||||||
// A hashmap bucket. A bucket is a container of 8 key/value pairs: first the
|
// A hashmap bucket. A bucket is a container of 8 key/value pairs: first the
|
||||||
// following two entries, then the 8 keys, then the 8 values. This somewhat odd
|
// following two entries, then the 8 keys, then the 8 values. This somewhat odd
|
||||||
// ordering is to make sure the keys and values are well aligned when one of
|
// ordering is to make sure the keys and values are well aligned when one of
|
||||||
|
@ -41,8 +32,6 @@ type hashmapBucket struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type hashmapIterator struct {
|
type hashmapIterator struct {
|
||||||
buckets unsafe.Pointer
|
|
||||||
numBuckets uintptr
|
|
||||||
bucketNumber uintptr
|
bucketNumber uintptr
|
||||||
bucket *hashmapBucket
|
bucket *hashmapBucket
|
||||||
bucketIndex uint8
|
bucketIndex uint8
|
||||||
|
@ -59,7 +48,7 @@ func hashmapTopHash(hash uint32) uint8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new hashmap with the given keySize and valueSize.
|
// Create a new hashmap with the given keySize and valueSize.
|
||||||
func hashmapMake(keySize, valueSize uint8, sizeHint uintptr, alg uint8) *hashmap {
|
func hashmapMake(keySize, valueSize uint8, sizeHint uintptr) *hashmap {
|
||||||
numBuckets := sizeHint / 8
|
numBuckets := sizeHint / 8
|
||||||
bucketBits := uint8(0)
|
bucketBits := uint8(0)
|
||||||
for numBuckets != 0 {
|
for numBuckets != 0 {
|
||||||
|
@ -68,58 +57,14 @@ func hashmapMake(keySize, valueSize uint8, sizeHint uintptr, alg uint8) *hashmap
|
||||||
}
|
}
|
||||||
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(keySize)*8 + uintptr(valueSize)*8
|
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(keySize)*8 + uintptr(valueSize)*8
|
||||||
buckets := alloc(bucketBufSize*(1<<bucketBits), nil)
|
buckets := alloc(bucketBufSize*(1<<bucketBits), nil)
|
||||||
|
|
||||||
keyHash := hashmapKeyHashAlg(hashmapAlgorithm(alg))
|
|
||||||
keyEqual := hashmapKeyEqualAlg(hashmapAlgorithm(alg))
|
|
||||||
|
|
||||||
return &hashmap{
|
return &hashmap{
|
||||||
buckets: buckets,
|
buckets: buckets,
|
||||||
keySize: keySize,
|
keySize: keySize,
|
||||||
valueSize: valueSize,
|
valueSize: valueSize,
|
||||||
bucketBits: bucketBits,
|
bucketBits: bucketBits,
|
||||||
keyEqual: keyEqual,
|
|
||||||
keyHash: keyHash,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapKeyEqualAlg(alg hashmapAlgorithm) func(x, y unsafe.Pointer, n uintptr) bool {
|
|
||||||
switch alg {
|
|
||||||
case hashmapAlgorithmBinary:
|
|
||||||
return memequal
|
|
||||||
case hashmapAlgorithmString:
|
|
||||||
return hashmapStringEqual
|
|
||||||
case hashmapAlgorithmInterface:
|
|
||||||
return hashmapInterfaceEqual
|
|
||||||
default:
|
|
||||||
panic("unknown hashmap equal algorithm")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashmapKeyHashAlg(alg hashmapAlgorithm) func(key unsafe.Pointer, n uintptr) uint32 {
|
|
||||||
switch alg {
|
|
||||||
case hashmapAlgorithmBinary:
|
|
||||||
return hash32
|
|
||||||
case hashmapAlgorithmString:
|
|
||||||
return hashmapStringPtrHash
|
|
||||||
case hashmapAlgorithmInterface:
|
|
||||||
return hashmapInterfacePtrHash
|
|
||||||
default:
|
|
||||||
panic("unknown hashmap hash algorithm")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashmapShouldGrow(m *hashmap) bool {
|
|
||||||
if m.bucketBits == 32 {
|
|
||||||
// can't grow any more
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// "maximum" number of elements is 0.75 * buckets * elements per bucket
|
|
||||||
max := uintptr((3 * ((1 << m.bucketBits) * 8)) / 4)
|
|
||||||
|
|
||||||
return m.count > max
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the number of entries in this hashmap, called from the len builtin.
|
// Return the number of entries in this hashmap, called from the len builtin.
|
||||||
// A nil hashmap is defined as having length 0.
|
// A nil hashmap is defined as having length 0.
|
||||||
//go:inline
|
//go:inline
|
||||||
|
@ -138,7 +83,7 @@ func hashmapLenUnsafePointer(p unsafe.Pointer) int {
|
||||||
|
|
||||||
// Set a specified key to a given value. Grow the map if necessary.
|
// Set a specified key to a given value. Grow the map if necessary.
|
||||||
//go:nobounds
|
//go:nobounds
|
||||||
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32) {
|
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
||||||
tophash := hashmapTopHash(hash)
|
tophash := hashmapTopHash(hash)
|
||||||
|
|
||||||
if m.buckets == nil {
|
if m.buckets == nil {
|
||||||
|
@ -147,10 +92,6 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if hashmapShouldGrow(m) {
|
|
||||||
hashmapGrow(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
numBuckets := uintptr(1) << m.bucketBits
|
numBuckets := uintptr(1) << m.bucketBits
|
||||||
bucketNumber := (uintptr(hash) & (numBuckets - 1))
|
bucketNumber := (uintptr(hash) & (numBuckets - 1))
|
||||||
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
||||||
|
@ -177,7 +118,7 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
|
||||||
}
|
}
|
||||||
if bucket.tophash[i] == tophash {
|
if bucket.tophash[i] == tophash {
|
||||||
// Could be an existing key that's the same.
|
// Could be an existing key that's the same.
|
||||||
if m.keyEqual(key, slotKey, uintptr(m.keySize)) {
|
if keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||||
// found same key, replace it
|
// found same key, replace it
|
||||||
memcpy(slotValue, value, uintptr(m.valueSize))
|
memcpy(slotValue, value, uintptr(m.valueSize))
|
||||||
return
|
return
|
||||||
|
@ -217,35 +158,9 @@ func hashmapInsertIntoNewBucket(m *hashmap, key, value unsafe.Pointer, tophash u
|
||||||
return bucket
|
return bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapGrow(m *hashmap) {
|
|
||||||
|
|
||||||
// clone map as empty
|
|
||||||
n := *m
|
|
||||||
n.count = 0
|
|
||||||
|
|
||||||
// allocate our new buckets twice as big
|
|
||||||
n.bucketBits = m.bucketBits + 1
|
|
||||||
numBuckets := uintptr(1) << n.bucketBits
|
|
||||||
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
|
||||||
n.buckets = alloc(bucketBufSize*numBuckets, nil)
|
|
||||||
|
|
||||||
// use a hashmap iterator to go through the old map
|
|
||||||
var it hashmapIterator
|
|
||||||
|
|
||||||
var key = alloc(uintptr(m.keySize), nil)
|
|
||||||
var value = alloc(uintptr(m.valueSize), nil)
|
|
||||||
|
|
||||||
for hashmapNext(m, &it, key, value) {
|
|
||||||
h := m.keyHash(key, uintptr(m.keySize))
|
|
||||||
hashmapSet(&n, key, value, h)
|
|
||||||
}
|
|
||||||
|
|
||||||
*m = n
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the value of a specified key, or zero the value if not found.
|
// Get the value of a specified key, or zero the value if not found.
|
||||||
//go:nobounds
|
//go:nobounds
|
||||||
func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash uint32) bool {
|
func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) bool {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
// Getting a value out of a nil map is valid. From the spec:
|
// Getting a value out of a nil map is valid. From the spec:
|
||||||
// > if the map is nil or does not contain such an entry, a[x] is the
|
// > if the map is nil or does not contain such an entry, a[x] is the
|
||||||
|
@ -274,7 +189,7 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
|
||||||
slotValue := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotValueOffset)
|
slotValue := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotValueOffset)
|
||||||
if bucket.tophash[i] == tophash {
|
if bucket.tophash[i] == tophash {
|
||||||
// This could be the key we're looking for.
|
// This could be the key we're looking for.
|
||||||
if m.keyEqual(key, slotKey, uintptr(m.keySize)) {
|
if keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||||
// Found the key, copy it.
|
// Found the key, copy it.
|
||||||
memcpy(value, slotValue, uintptr(m.valueSize))
|
memcpy(value, slotValue, uintptr(m.valueSize))
|
||||||
return true
|
return true
|
||||||
|
@ -292,7 +207,7 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
|
||||||
// Delete a given key from the map. No-op when the key does not exist in the
|
// Delete a given key from the map. No-op when the key does not exist in the
|
||||||
// map.
|
// map.
|
||||||
//go:nobounds
|
//go:nobounds
|
||||||
func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
|
func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
// The delete builtin is defined even when the map is nil. From the spec:
|
// The delete builtin is defined even when the map is nil. From the spec:
|
||||||
// > If the map m is nil or the element m[k] does not exist, delete is a
|
// > If the map m is nil or the element m[k] does not exist, delete is a
|
||||||
|
@ -318,7 +233,7 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
|
||||||
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset)
|
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset)
|
||||||
if bucket.tophash[i] == tophash {
|
if bucket.tophash[i] == tophash {
|
||||||
// This could be the key we're looking for.
|
// This could be the key we're looking for.
|
||||||
if m.keyEqual(key, slotKey, uintptr(m.keySize)) {
|
if keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||||
// Found the key, delete it.
|
// Found the key, delete it.
|
||||||
bucket.tophash[i] = 0
|
bucket.tophash[i] = 0
|
||||||
m.count--
|
m.count--
|
||||||
|
@ -334,16 +249,13 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
|
||||||
//go:nobounds
|
//go:nobounds
|
||||||
func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) bool {
|
func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) bool {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
// From the spec: If the map is nil, the number of iterations is 0.
|
// Iterating over a nil slice appears to be allowed by the Go spec:
|
||||||
|
// https://groups.google.com/g/golang-nuts/c/gVgVLQU1FFE?pli=1
|
||||||
|
// https://play.golang.org/p/S8jxAMytKDB
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if it.buckets == nil {
|
numBuckets := uintptr(1) << m.bucketBits
|
||||||
// initialize iterator
|
|
||||||
it.buckets = m.buckets
|
|
||||||
it.numBuckets = uintptr(1) << m.bucketBits
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if it.bucketIndex >= 8 {
|
if it.bucketIndex >= 8 {
|
||||||
// end of bucket, move to the next in the chain
|
// end of bucket, move to the next in the chain
|
||||||
|
@ -351,12 +263,12 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||||
it.bucket = it.bucket.next
|
it.bucket = it.bucket.next
|
||||||
}
|
}
|
||||||
if it.bucket == nil {
|
if it.bucket == nil {
|
||||||
if it.bucketNumber >= it.numBuckets {
|
if it.bucketNumber >= numBuckets {
|
||||||
// went through all buckets
|
// went through all buckets
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
||||||
bucketAddr := uintptr(it.buckets) + bucketSize*it.bucketNumber
|
bucketAddr := uintptr(m.buckets) + bucketSize*it.bucketNumber
|
||||||
it.bucket = (*hashmapBucket)(unsafe.Pointer(bucketAddr))
|
it.bucket = (*hashmapBucket)(unsafe.Pointer(bucketAddr))
|
||||||
it.bucketNumber++ // next bucket
|
it.bucketNumber++ // next bucket
|
||||||
}
|
}
|
||||||
|
@ -369,29 +281,11 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||||
bucketAddr := uintptr(unsafe.Pointer(it.bucket))
|
bucketAddr := uintptr(unsafe.Pointer(it.bucket))
|
||||||
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(it.bucketIndex)
|
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(it.bucketIndex)
|
||||||
slotKey := unsafe.Pointer(bucketAddr + slotKeyOffset)
|
slotKey := unsafe.Pointer(bucketAddr + slotKeyOffset)
|
||||||
|
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(it.bucketIndex)
|
||||||
|
slotValue := unsafe.Pointer(bucketAddr + slotValueOffset)
|
||||||
memcpy(key, slotKey, uintptr(m.keySize))
|
memcpy(key, slotKey, uintptr(m.keySize))
|
||||||
|
memcpy(value, slotValue, uintptr(m.valueSize))
|
||||||
if it.buckets == m.buckets {
|
it.bucketIndex++
|
||||||
// Our view of the buckets is the same as the parent map.
|
|
||||||
// Just copy the value we have
|
|
||||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(it.bucketIndex)
|
|
||||||
slotValue := unsafe.Pointer(bucketAddr + slotValueOffset)
|
|
||||||
memcpy(value, slotValue, uintptr(m.valueSize))
|
|
||||||
it.bucketIndex++
|
|
||||||
} else {
|
|
||||||
it.bucketIndex++
|
|
||||||
|
|
||||||
// Our view of the buckets doesn't match the parent map.
|
|
||||||
// Look up the key in the new buckets and return that value if it exists
|
|
||||||
hash := m.keyHash(key, uintptr(m.keySize))
|
|
||||||
ok := hashmapGet(m, key, value, uintptr(m.valueSize), hash)
|
|
||||||
if !ok {
|
|
||||||
// doesn't exist in parent map; try next key
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// All good.
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -402,7 +296,7 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||||
func hashmapBinarySet(m *hashmap, key, value unsafe.Pointer) {
|
func hashmapBinarySet(m *hashmap, key, value unsafe.Pointer) {
|
||||||
// TODO: detect nil map here and throw a better panic message?
|
// TODO: detect nil map here and throw a better panic message?
|
||||||
hash := hash32(key, uintptr(m.keySize))
|
hash := hash32(key, uintptr(m.keySize))
|
||||||
hashmapSet(m, key, value, hash)
|
hashmapSet(m, key, value, hash, memequal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapBinaryGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr) bool {
|
func hashmapBinaryGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr) bool {
|
||||||
|
@ -411,7 +305,7 @@ func hashmapBinaryGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
hash := hash32(key, uintptr(m.keySize))
|
hash := hash32(key, uintptr(m.keySize))
|
||||||
return hashmapGet(m, key, value, valueSize, hash)
|
return hashmapGet(m, key, value, valueSize, hash, memequal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapBinaryDelete(m *hashmap, key unsafe.Pointer) {
|
func hashmapBinaryDelete(m *hashmap, key unsafe.Pointer) {
|
||||||
|
@ -419,7 +313,7 @@ func hashmapBinaryDelete(m *hashmap, key unsafe.Pointer) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hash := hash32(key, uintptr(m.keySize))
|
hash := hash32(key, uintptr(m.keySize))
|
||||||
hashmapDelete(m, key, hash)
|
hashmapDelete(m, key, hash, memequal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hashmap with string keys (a common case).
|
// Hashmap with string keys (a common case).
|
||||||
|
@ -433,24 +327,19 @@ func hashmapStringHash(s string) uint32 {
|
||||||
return hash32(unsafe.Pointer(_s.ptr), uintptr(_s.length))
|
return hash32(unsafe.Pointer(_s.ptr), uintptr(_s.length))
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapStringPtrHash(sptr unsafe.Pointer, size uintptr) uint32 {
|
|
||||||
_s := *(*_string)(sptr)
|
|
||||||
return hash32(unsafe.Pointer(_s.ptr), uintptr(_s.length))
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashmapStringSet(m *hashmap, key string, value unsafe.Pointer) {
|
func hashmapStringSet(m *hashmap, key string, value unsafe.Pointer) {
|
||||||
hash := hashmapStringHash(key)
|
hash := hashmapStringHash(key)
|
||||||
hashmapSet(m, unsafe.Pointer(&key), value, hash)
|
hashmapSet(m, unsafe.Pointer(&key), value, hash, hashmapStringEqual)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapStringGet(m *hashmap, key string, value unsafe.Pointer, valueSize uintptr) bool {
|
func hashmapStringGet(m *hashmap, key string, value unsafe.Pointer, valueSize uintptr) bool {
|
||||||
hash := hashmapStringHash(key)
|
hash := hashmapStringHash(key)
|
||||||
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash)
|
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash, hashmapStringEqual)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapStringDelete(m *hashmap, key string) {
|
func hashmapStringDelete(m *hashmap, key string) {
|
||||||
hash := hashmapStringHash(key)
|
hash := hashmapStringHash(key)
|
||||||
hashmapDelete(m, unsafe.Pointer(&key), hash)
|
hashmapDelete(m, unsafe.Pointer(&key), hash, hashmapStringEqual)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hashmap with interface keys (for everything else).
|
// Hashmap with interface keys (for everything else).
|
||||||
|
@ -538,26 +427,21 @@ func hashmapInterfaceHash(itf interface{}) uint32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapInterfacePtrHash(iptr unsafe.Pointer, size uintptr) uint32 {
|
|
||||||
_i := *(*_interface)(iptr)
|
|
||||||
return hashmapInterfaceHash(_i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashmapInterfaceEqual(x, y unsafe.Pointer, n uintptr) bool {
|
func hashmapInterfaceEqual(x, y unsafe.Pointer, n uintptr) bool {
|
||||||
return *(*interface{})(x) == *(*interface{})(y)
|
return *(*interface{})(x) == *(*interface{})(y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapInterfaceSet(m *hashmap, key interface{}, value unsafe.Pointer) {
|
func hashmapInterfaceSet(m *hashmap, key interface{}, value unsafe.Pointer) {
|
||||||
hash := hashmapInterfaceHash(key)
|
hash := hashmapInterfaceHash(key)
|
||||||
hashmapSet(m, unsafe.Pointer(&key), value, hash)
|
hashmapSet(m, unsafe.Pointer(&key), value, hash, hashmapInterfaceEqual)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapInterfaceGet(m *hashmap, key interface{}, value unsafe.Pointer, valueSize uintptr) bool {
|
func hashmapInterfaceGet(m *hashmap, key interface{}, value unsafe.Pointer, valueSize uintptr) bool {
|
||||||
hash := hashmapInterfaceHash(key)
|
hash := hashmapInterfaceHash(key)
|
||||||
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash)
|
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash, hashmapInterfaceEqual)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hashmapInterfaceDelete(m *hashmap, key interface{}) {
|
func hashmapInterfaceDelete(m *hashmap, key interface{}) {
|
||||||
hash := hashmapInterfaceHash(key)
|
hash := hashmapInterfaceHash(key)
|
||||||
hashmapDelete(m, unsafe.Pointer(&key), hash)
|
hashmapDelete(m, unsafe.Pointer(&key), hash, hashmapInterfaceEqual)
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче