minTopHash = 4 // minimum tophash for a normal filled cell.
// flags
- indirectKey = 1 // storing pointers to keys
- indirectValue = 2 // storing pointers to values
- iterator = 4 // there may be an iterator using buckets
- oldIterator = 8 // there may be an iterator using oldbuckets
+ iterator = 1 // there may be an iterator using buckets
+ oldIterator = 2 // there may be an iterator using oldbuckets
// sentinel bucket ID for iterator checks
noCheck = 1<<(8*ptrSize) - 1
type hmap struct {
// Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
// ../reflect/type.go. Don't change this structure without also changing that code!
- count int // # live cells == size of map. Must be first (used by len() builtin)
- flags uint32
- hash0 uint32 // hash seed
- B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
- keysize uint8 // key size in bytes
- valuesize uint8 // value size in bytes
- bucketsize uint16 // bucket size in bytes
+ count int // # live cells == size of map. Must be first (used by len() builtin)
+ flags uint32
+ hash0 uint32 // hash seed
+ B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
gothrow("runtime.makemap: unsupported map key type")
}
- flags := uint32(0)
-
- // figure out how big we have to make everything
- keysize := uintptr(t.key.size)
- if keysize > maxKeySize {
- flags |= indirectKey
- keysize = ptrSize
- }
- valuesize := uintptr(t.elem.size)
- if valuesize > maxValueSize {
- flags |= indirectValue
- valuesize = ptrSize
+ // check compiler's and reflect's math
+ if t.key.size > maxKeySize && (t.indirectkey == 0 || t.keysize != uint8(ptrSize)) ||
+ t.key.size <= maxKeySize && (t.indirectkey == 1 || t.keysize != uint8(t.key.size)) {
+ gothrow("key size wrong")
}
- bucketsize := dataOffset + bucketCnt*(keysize+valuesize)
- if bucketsize != uintptr(t.bucket.size) {
- gothrow("bucketsize wrong")
+ if t.elem.size > maxValueSize && (t.indirectvalue == 0 || t.valuesize != uint8(ptrSize)) ||
+ t.elem.size <= maxValueSize && (t.indirectvalue == 1 || t.valuesize != uint8(t.elem.size)) {
+ gothrow("value size wrong")
}
// invariants we depend on. We should probably check these at compile time
h := (*hmap)(newobject(t.hmap))
h.count = 0
h.B = B
- h.flags = flags
- h.keysize = uint8(keysize)
- h.valuesize = uint8(valuesize)
- h.bucketsize = uint16(bucketsize)
+ h.flags = 0
h.hash0 = fastrand2()
h.buckets = buckets
h.oldbuckets = nil
}
hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
if b.tophash[i] != top {
continue
}
- k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
- if h.flags&indirectKey != 0 {
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ if t.indirectkey != 0 {
k = *((*unsafe.Pointer)(k))
}
if goeq(t.key.alg, key, k, uintptr(t.key.size)) {
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
- if h.flags&indirectValue != 0 {
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ if t.indirectvalue != 0 {
v = *((*unsafe.Pointer)(v))
}
return v
}
hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(h.bucketsize)))
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
if b.tophash[i] != top {
continue
}
- k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
- if h.flags&indirectKey != 0 {
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ if t.indirectkey != 0 {
k = *((*unsafe.Pointer)(k))
}
if goeq(t.key.alg, key, k, uintptr(t.key.size)) {
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
- if h.flags&indirectValue != 0 {
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ if t.indirectvalue != 0 {
v = *((*unsafe.Pointer)(v))
}
return v, true
}
hash := goalg(t.key.alg).hash(key, uintptr(t.key.size), uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(h.bucketsize)))
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
if b.tophash[i] != top {
continue
}
- k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
- if h.flags&indirectKey != 0 {
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ if t.indirectkey != 0 {
k = *((*unsafe.Pointer)(k))
}
if goeq(t.key.alg, key, k, uintptr(t.key.size)) {
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
- if h.flags&indirectValue != 0 {
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ if t.indirectvalue != 0 {
v = *((*unsafe.Pointer)(v))
}
return k, v
if h.oldbuckets != nil {
growWork(t, h, bucket)
}
- b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(h.bucketsize)))
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
top := uint8(hash >> (ptrSize*8 - 8))
if top < minTopHash {
top += minTopHash
if b.tophash[i] != top {
if b.tophash[i] == empty && inserti == nil {
inserti = &b.tophash[i]
- insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
- insertv = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
+ insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
+ insertv = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
}
continue
}
- k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
k2 := k
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
k2 = *((*unsafe.Pointer)(k2))
}
if !goeq(t.key.alg, key, k2, uintptr(t.key.size)) {
}
// already have a mapping for key. Update it.
memmove(k2, key, uintptr(t.key.size))
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+i*uintptr(h.valuesize))
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
v2 := v
- if h.flags&indirectValue != 0 {
+ if t.indirectvalue != 0 {
v2 = *((*unsafe.Pointer)(v2))
}
memmove(v2, val, uintptr(t.elem.size))
b.overflow = newb
inserti = &newb.tophash[0]
insertk = add(unsafe.Pointer(newb), dataOffset)
- insertv = add(insertk, bucketCnt*uintptr(h.keysize))
+ insertv = add(insertk, bucketCnt*uintptr(t.keysize))
}
// store new key/value at insert position
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
if checkgc {
memstats.next_gc = memstats.heap_alloc
}
*(*unsafe.Pointer)(insertk) = kmem
insertk = kmem
}
- if h.flags&indirectValue != 0 {
+ if t.indirectvalue != 0 {
if checkgc {
memstats.next_gc = memstats.heap_alloc
}
if h.oldbuckets != nil {
growWork(t, h, bucket)
}
- b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(h.bucketsize)))
+ b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
top := uint8(hash >> (ptrSize*8 - 8))
if top < minTopHash {
top += minTopHash
if b.tophash[i] != top {
continue
}
- k := add(unsafe.Pointer(b), dataOffset+i*uintptr(h.keysize))
+ k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
k2 := k
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
k2 = *((*unsafe.Pointer)(k2))
}
if !goeq(t.key.alg, key, k2, uintptr(t.key.size)) {
continue
}
- memclr(k, uintptr(h.keysize))
- v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(h.keysize) + i*uintptr(h.valuesize))
- memclr(v, uintptr(h.valuesize))
+ memclr(k, uintptr(t.keysize))
+ v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize))
+ memclr(v, uintptr(t.valuesize))
b.tophash[i] = empty
h.count--
return
// bucket hasn't been evacuated) then we need to iterate through the old
// bucket and only return the ones that will be migrated to this bucket.
oldbucket := bucket & (uintptr(1)<<(it.B-1) - 1)
- b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(h.bucketsize)))
+ b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
if !evacuated(b) {
checkBucket = bucket
} else {
- b = (*bmap)(add(it.buckets, bucket*uintptr(h.bucketsize)))
+ b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
checkBucket = noCheck
}
} else {
- b = (*bmap)(add(it.buckets, bucket*uintptr(h.bucketsize)))
+ b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize)))
checkBucket = noCheck
}
bucket++
}
for ; i < bucketCnt; i++ {
offi := (i + uintptr(it.offset)) & (bucketCnt - 1)
- k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(h.keysize))
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(h.keysize)+offi*uintptr(h.valuesize))
+ k := add(unsafe.Pointer(b), dataOffset+offi*uintptr(t.keysize))
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+offi*uintptr(t.valuesize))
if b.tophash[offi] != empty && b.tophash[offi] != evacuatedEmpty {
if checkBucket != noCheck {
// Special case: iterator was started during a grow and the
// to the other new bucket (each oldbucket expands to two
// buckets during a grow).
k2 := k
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
k2 = *((*unsafe.Pointer)(k2))
}
if goeq(t.key.alg, k2, k2, uintptr(t.key.size)) {
}
if b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY {
// this is the golden data, we can return it.
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
k = *((*unsafe.Pointer)(k))
}
it.key = k
- if h.flags&indirectValue != 0 {
+ if t.indirectvalue != 0 {
v = *((*unsafe.Pointer)(v))
}
it.value = v
// The hash table has grown since the iterator was started.
// The golden data for this key is now somewhere else.
k2 := k
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
k2 = *((*unsafe.Pointer)(k2))
}
if goeq(t.key.alg, k2, k2, uintptr(t.key.size)) {
// us because when key!=key we can't look it up
// successfully in the current table.
it.key = k2
- if h.flags&indirectValue != 0 {
+ if t.indirectvalue != 0 {
v = *((*unsafe.Pointer)(v))
}
it.value = v
}
func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
- b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(h.bucketsize)))
+ b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
newbit := uintptr(1) << (h.B - 1)
if !evacuated(b) {
// TODO: reuse overflow buckets instead of using new ones, if there
// is no iterator using the old buckets. (If !oldIterator.)
- x := (*bmap)(add(h.buckets, oldbucket*uintptr(h.bucketsize)))
- y := (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(h.bucketsize)))
+ x := (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
+ y := (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
xi := 0
yi := 0
xk := add(unsafe.Pointer(x), dataOffset)
yk := add(unsafe.Pointer(y), dataOffset)
- xv := add(xk, bucketCnt*uintptr(h.keysize))
- yv := add(yk, bucketCnt*uintptr(h.keysize))
+ xv := add(xk, bucketCnt*uintptr(t.keysize))
+ yv := add(yk, bucketCnt*uintptr(t.keysize))
for ; b != nil; b = b.overflow {
k := add(unsafe.Pointer(b), dataOffset)
- v := add(k, bucketCnt*uintptr(h.keysize))
- for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(h.keysize)), add(v, uintptr(h.valuesize)) {
+ v := add(k, bucketCnt*uintptr(t.keysize))
+ for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) {
top := b.tophash[i]
if top == empty {
b.tophash[i] = evacuatedEmpty
gothrow("bad map state")
}
k2 := k
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
k2 = *((*unsafe.Pointer)(k2))
}
// Compute hash to make our evacuation decision (whether we need
x = newx
xi = 0
xk = add(unsafe.Pointer(x), dataOffset)
- xv = add(xk, bucketCnt*uintptr(h.keysize))
+ xv = add(xk, bucketCnt*uintptr(t.keysize))
}
x.tophash[xi] = top
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
*(*unsafe.Pointer)(xk) = k2 // copy pointer
} else {
memmove(xk, k, uintptr(t.key.size)) // copy value
}
- if h.flags&indirectValue != 0 {
+ if t.indirectvalue != 0 {
*(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v)
} else {
memmove(xv, v, uintptr(t.elem.size))
}
xi++
- xk = add(xk, uintptr(h.keysize))
- xv = add(xv, uintptr(h.valuesize))
+ xk = add(xk, uintptr(t.keysize))
+ xv = add(xv, uintptr(t.valuesize))
} else {
b.tophash[i] = evacuatedY
if yi == bucketCnt {
y = newy
yi = 0
yk = add(unsafe.Pointer(y), dataOffset)
- yv = add(yk, bucketCnt*uintptr(h.keysize))
+ yv = add(yk, bucketCnt*uintptr(t.keysize))
}
y.tophash[yi] = top
- if h.flags&indirectKey != 0 {
+ if t.indirectkey != 0 {
*(*unsafe.Pointer)(yk) = k2
} else {
memmove(yk, k, uintptr(t.key.size))
}
- if h.flags&indirectValue != 0 {
+ if t.indirectvalue != 0 {
*(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v)
} else {
memmove(yv, v, uintptr(t.elem.size))
}
yi++
- yk = add(yk, uintptr(h.keysize))
- yv = add(yv, uintptr(h.valuesize))
+ yk = add(yk, uintptr(t.keysize))
+ yv = add(yv, uintptr(t.valuesize))
}
}
}
// Unlink the overflow buckets & clear key/value to help GC.
if h.flags&oldIterator == 0 {
- b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(h.bucketsize)))
+ b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
b.overflow = nil
- memclr(add(unsafe.Pointer(b), dataOffset), uintptr(h.bucketsize)-dataOffset)
+ memclr(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
}
}
} else {
hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
if k != key {
continue
}
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(h.valuesize))
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
}
b = b.overflow
if b == nil {
} else {
hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
if k != key {
continue
}
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(h.valuesize)), true
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)), true
}
b = b.overflow
if b == nil {
} else {
hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
if k != key {
continue
}
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(h.valuesize))
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
}
b = b.overflow
if b == nil {
} else {
hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b = (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+ b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
if k != key {
continue
}
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(h.valuesize)), true
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)), true
}
b = b.overflow
if b == nil {
if key.len < 32 {
// short key, doing lots of comparisons is ok
for i := uintptr(0); i < bucketCnt; i++ {
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
continue
}
if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize))
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize))
}
}
return unsafe.Pointer(t.elem.zero)
// long key, try not to do more comparisons than necessary
keymaybe := uintptr(bucketCnt)
for i := uintptr(0); i < bucketCnt; i++ {
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
continue
}
if k.str == key.str {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize))
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize))
}
// check first 4 bytes
// TODO: on amd64/386 at least, make this compile to one 4-byte comparison instead of
if keymaybe != bucketCnt {
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*ptrSize))
if gomemeq(k.str, key.str, uintptr(key.len)) {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(h.valuesize))
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(t.valuesize))
}
}
return unsafe.Pointer(t.elem.zero)
dohash:
hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
}
for {
for i := uintptr(0); i < bucketCnt; i++ {
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t != top {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x != top {
continue
}
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
continue
}
if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize))
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize))
}
}
b = b.overflow
if key.len < 32 {
// short key, doing lots of comparisons is ok
for i := uintptr(0); i < bucketCnt; i++ {
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
continue
}
if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize)), true
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true
}
}
return unsafe.Pointer(t.elem.zero), false
// long key, try not to do more comparisons than necessary
keymaybe := uintptr(bucketCnt)
for i := uintptr(0); i < bucketCnt; i++ {
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t == empty {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x == empty {
continue
}
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
continue
}
if k.str == key.str {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize)), true
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true
}
// check first 4 bytes
if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) {
if keymaybe != bucketCnt {
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*ptrSize))
if gomemeq(k.str, key.str, uintptr(key.len)) {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(h.valuesize)), true
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(t.valuesize)), true
}
}
return unsafe.Pointer(t.elem.zero), false
dohash:
hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
- b := (*bmap)(add(h.buckets, (hash&m)*uintptr(h.bucketsize)))
+ b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(h.bucketsize)))
+ oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
}
for {
for i := uintptr(0); i < bucketCnt; i++ {
- t := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
- if t != top {
+ x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check
+ if x != top {
continue
}
k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize))
continue
}
if k.str == key.str || gomemeq(k.str, key.str, uintptr(key.len)) {
- return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(h.valuesize)), true
+ return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true
}
}
b = b.overflow