runtime: factor duplicate hashmap snippts to functions
Этот коммит содержится в:
родитель
cb9c6f0074
коммит
a3afd4e8ac
1 изменённых файлов: 56 добавлений и 51 удалений
|
@ -153,6 +153,39 @@ func hashmapLenUnsafePointer(m unsafe.Pointer) int {
|
||||||
return hashmapLen((*hashmap)(m))
|
return hashmapLen((*hashmap)(m))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func hashmapBucketSize(m *hashmap) uintptr {
|
||||||
|
return unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func hashmapBucketAddr(m *hashmap, buckets unsafe.Pointer, n uintptr) *hashmapBucket {
|
||||||
|
bucketSize := hashmapBucketSize(m)
|
||||||
|
bucket := (*hashmapBucket)(unsafe.Add(buckets, bucketSize*n))
|
||||||
|
return bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func hashmapBucketAddrForHash(m *hashmap, hash uint32) *hashmapBucket {
|
||||||
|
numBuckets := uintptr(1) << m.bucketBits
|
||||||
|
bucketNumber := (uintptr(hash) & (numBuckets - 1))
|
||||||
|
return hashmapBucketAddr(m, m.buckets, bucketNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func hashmapSlotKey(m *hashmap, bucket *hashmapBucket, slot uint8) unsafe.Pointer {
|
||||||
|
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(slot)
|
||||||
|
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset)
|
||||||
|
return slotKey
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func hashmapSlotValue(m *hashmap, bucket *hashmapBucket, slot uint8) unsafe.Pointer {
|
||||||
|
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(slot)
|
||||||
|
slotValue := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotValueOffset)
|
||||||
|
return slotValue
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -164,11 +197,7 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
|
||||||
}
|
}
|
||||||
|
|
||||||
tophash := hashmapTopHash(hash)
|
tophash := hashmapTopHash(hash)
|
||||||
|
bucket := hashmapBucketAddrForHash(m, hash)
|
||||||
numBuckets := uintptr(1) << m.bucketBits
|
|
||||||
bucketNumber := (uintptr(hash) & (numBuckets - 1))
|
|
||||||
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
|
|
||||||
bucket := (*hashmapBucket)(unsafe.Add(m.buckets, bucketSize*bucketNumber))
|
|
||||||
var lastBucket *hashmapBucket
|
var lastBucket *hashmapBucket
|
||||||
|
|
||||||
// See whether the key already exists somewhere.
|
// See whether the key already exists somewhere.
|
||||||
|
@ -176,11 +205,9 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
|
||||||
var emptySlotValue unsafe.Pointer
|
var emptySlotValue unsafe.Pointer
|
||||||
var emptySlotTophash *byte
|
var emptySlotTophash *byte
|
||||||
for bucket != nil {
|
for bucket != nil {
|
||||||
for i := uintptr(0); i < 8; i++ {
|
for i := uint8(0); i < 8; i++ {
|
||||||
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i)
|
slotKey := hashmapSlotKey(m, bucket, i)
|
||||||
slotKey := unsafe.Add(unsafe.Pointer(bucket), slotKeyOffset)
|
slotValue := hashmapSlotValue(m, bucket, i)
|
||||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i)
|
|
||||||
slotValue := unsafe.Add(unsafe.Pointer(bucket), slotValueOffset)
|
|
||||||
if bucket.tophash[i] == 0 && emptySlotKey == nil {
|
if bucket.tophash[i] == 0 && emptySlotKey == nil {
|
||||||
// Found an empty slot, store it for if we couldn't find an
|
// Found an empty slot, store it for if we couldn't find an
|
||||||
// existing slot.
|
// existing slot.
|
||||||
|
@ -219,17 +246,16 @@ func hashmapSetUnsafePointer(m unsafe.Pointer, key unsafe.Pointer, value unsafe.
|
||||||
// hashmapInsertIntoNewBucket creates a new bucket, inserts the given key and
|
// hashmapInsertIntoNewBucket creates a new bucket, inserts the given key and
|
||||||
// value into the bucket, and returns a pointer to this bucket.
|
// value into the bucket, and returns a pointer to this bucket.
|
||||||
func hashmapInsertIntoNewBucket(m *hashmap, key, value unsafe.Pointer, tophash uint8) *hashmapBucket {
|
func hashmapInsertIntoNewBucket(m *hashmap, key, value unsafe.Pointer, tophash uint8) *hashmapBucket {
|
||||||
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
|
bucketBufSize := hashmapBucketSize(m)
|
||||||
bucketBuf := alloc(bucketBufSize, nil)
|
bucketBuf := alloc(bucketBufSize, nil)
|
||||||
|
bucket := (*hashmapBucket)(bucketBuf)
|
||||||
|
|
||||||
// Insert into the first slot, which is empty as it has just been allocated.
|
// Insert into the first slot, which is empty as it has just been allocated.
|
||||||
slotKeyOffset := unsafe.Sizeof(hashmapBucket{})
|
slotKey := hashmapSlotKey(m, bucket, 0)
|
||||||
slotKey := unsafe.Add(bucketBuf, slotKeyOffset)
|
slotValue := hashmapSlotValue(m, bucket, 0)
|
||||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8
|
|
||||||
slotValue := unsafe.Add(bucketBuf, slotValueOffset)
|
|
||||||
m.count++
|
m.count++
|
||||||
memcpy(slotKey, key, m.keySize)
|
memcpy(slotKey, key, m.keySize)
|
||||||
memcpy(slotValue, value, m.valueSize)
|
memcpy(slotValue, value, m.valueSize)
|
||||||
bucket := (*hashmapBucket)(bucketBuf)
|
|
||||||
bucket.tophash[0] = tophash
|
bucket.tophash[0] = tophash
|
||||||
return bucket
|
return bucket
|
||||||
}
|
}
|
||||||
|
@ -243,7 +269,7 @@ func hashmapGrow(m *hashmap) {
|
||||||
// allocate our new buckets twice as big
|
// allocate our new buckets twice as big
|
||||||
n.bucketBits = m.bucketBits + 1
|
n.bucketBits = m.bucketBits + 1
|
||||||
numBuckets := uintptr(1) << n.bucketBits
|
numBuckets := uintptr(1) << n.bucketBits
|
||||||
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
|
bucketBufSize := hashmapBucketSize(m)
|
||||||
n.buckets = alloc(bucketBufSize*numBuckets, nil)
|
n.buckets = alloc(bucketBufSize*numBuckets, nil)
|
||||||
|
|
||||||
// use a hashmap iterator to go through the old map
|
// use a hashmap iterator to go through the old map
|
||||||
|
@ -271,24 +297,15 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
|
||||||
memzero(value, uintptr(valueSize))
|
memzero(value, uintptr(valueSize))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
numBuckets := uintptr(1) << m.bucketBits
|
|
||||||
bucketNumber := (uintptr(hash) & (numBuckets - 1))
|
|
||||||
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
|
|
||||||
bucket := (*hashmapBucket)(unsafe.Add(m.buckets, bucketSize*bucketNumber))
|
|
||||||
|
|
||||||
tophash := uint8(hash >> 24)
|
tophash := hashmapTopHash(hash)
|
||||||
if tophash < 1 {
|
bucket := hashmapBucketAddrForHash(m, hash)
|
||||||
// 0 means empty slot, so make it bigger.
|
|
||||||
tophash += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find the key.
|
// Try to find the key.
|
||||||
for bucket != nil {
|
for bucket != nil {
|
||||||
for i := uintptr(0); i < 8; i++ {
|
for i := uint8(0); i < 8; i++ {
|
||||||
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i)
|
slotKey := hashmapSlotKey(m, bucket, i)
|
||||||
slotKey := unsafe.Add(unsafe.Pointer(bucket), slotKeyOffset)
|
slotValue := hashmapSlotValue(m, bucket, i)
|
||||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i)
|
|
||||||
slotValue := unsafe.Add(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, m.keySize) {
|
if m.keyEqual(key, slotKey, m.keySize) {
|
||||||
|
@ -321,22 +338,14 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
|
||||||
// > no-op.
|
// > no-op.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
numBuckets := uintptr(1) << m.bucketBits
|
|
||||||
bucketNumber := (uintptr(hash) & (numBuckets - 1))
|
|
||||||
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
|
|
||||||
bucket := (*hashmapBucket)(unsafe.Add(m.buckets, bucketSize*bucketNumber))
|
|
||||||
|
|
||||||
tophash := uint8(hash >> 24)
|
tophash := hashmapTopHash(hash)
|
||||||
if tophash < 1 {
|
bucket := hashmapBucketAddrForHash(m, hash)
|
||||||
// 0 means empty slot, so make it bigger.
|
|
||||||
tophash += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find the key.
|
// Try to find the key.
|
||||||
for bucket != nil {
|
for bucket != nil {
|
||||||
for i := uintptr(0); i < 8; i++ {
|
for i := uint8(0); i < 8; i++ {
|
||||||
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(i)
|
slotKey := hashmapSlotKey(m, bucket, i)
|
||||||
slotKey := unsafe.Add(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, m.keySize) {
|
if m.keyEqual(key, slotKey, m.keySize) {
|
||||||
|
@ -344,8 +353,7 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
|
||||||
bucket.tophash[i] = 0
|
bucket.tophash[i] = 0
|
||||||
// Zero out the key and value so garbage collector doesn't pin the allocations.
|
// Zero out the key and value so garbage collector doesn't pin the allocations.
|
||||||
memzero(slotKey, m.keySize)
|
memzero(slotKey, m.keySize)
|
||||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(i)
|
slotValue := hashmapSlotValue(m, bucket, i)
|
||||||
slotValue := unsafe.Add(unsafe.Pointer(bucket), slotValueOffset)
|
|
||||||
memzero(slotValue, m.valueSize)
|
memzero(slotValue, m.valueSize)
|
||||||
m.count--
|
m.count--
|
||||||
return
|
return
|
||||||
|
@ -382,8 +390,7 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||||
// went through all buckets
|
// went through all buckets
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
bucketSize := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*8
|
it.bucket = hashmapBucketAddr(m, it.buckets, it.bucketNumber)
|
||||||
it.bucket = (*hashmapBucket)(unsafe.Add(it.buckets, bucketSize*it.bucketNumber))
|
|
||||||
it.bucketNumber++ // next bucket
|
it.bucketNumber++ // next bucket
|
||||||
}
|
}
|
||||||
if it.bucket.tophash[it.bucketIndex] == 0 {
|
if it.bucket.tophash[it.bucketIndex] == 0 {
|
||||||
|
@ -392,15 +399,13 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*uintptr(it.bucketIndex)
|
slotKey := hashmapSlotKey(m, it.bucket, it.bucketIndex)
|
||||||
slotKey := unsafe.Add(unsafe.Pointer(it.bucket), slotKeyOffset)
|
|
||||||
memcpy(key, slotKey, m.keySize)
|
memcpy(key, slotKey, m.keySize)
|
||||||
|
|
||||||
if it.buckets == m.buckets {
|
if it.buckets == m.buckets {
|
||||||
// Our view of the buckets is the same as the parent map.
|
// Our view of the buckets is the same as the parent map.
|
||||||
// Just copy the value we have
|
// Just copy the value we have
|
||||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + m.keySize*8 + m.valueSize*uintptr(it.bucketIndex)
|
slotValue := hashmapSlotValue(m, it.bucket, it.bucketIndex)
|
||||||
slotValue := unsafe.Add(unsafe.Pointer(it.bucket), slotValueOffset)
|
|
||||||
memcpy(value, slotValue, m.valueSize)
|
memcpy(value, slotValue, m.valueSize)
|
||||||
it.bucketIndex++
|
it.bucketIndex++
|
||||||
} else {
|
} else {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче