package maps
import (
"internal/abi"
"internal/goarch"
"internal/race"
"internal/runtime/sys"
"unsafe"
)
func (m *Map ) getWithoutKeySmallFastStr (typ *abi .SwissMapType , key string ) unsafe .Pointer {
g := groupReference {
data : m .dirPtr ,
}
ctrls := *g .ctrls ()
slotKey := g .key (typ , 0 )
slotSize := typ .SlotSize
if len (key ) > 64 {
j := abi .SwissMapGroupSlots
for i := range abi .SwissMapGroupSlots {
if ctrls &(1 <<7 ) == 0 && longStringQuickEqualityTest (key , *(*string )(slotKey )) {
if j < abi .SwissMapGroupSlots {
goto dohash
}
j = i
}
slotKey = unsafe .Pointer (uintptr (slotKey ) + slotSize )
ctrls >>= 8
}
if j == abi .SwissMapGroupSlots {
return nil
}
slotKey = g .key (typ , uintptr (j ))
if key == *(*string )(slotKey ) {
return unsafe .Pointer (uintptr (slotKey ) + 2 *goarch .PtrSize )
}
return nil
}
dohash :
hash := typ .Hasher (abi .NoEscape (unsafe .Pointer (&key )), m .seed )
h2 := uint8 (h2 (hash ))
ctrls = *g .ctrls ()
slotKey = g .key (typ , 0 )
for range abi .SwissMapGroupSlots {
if uint8 (ctrls ) == h2 && key == *(*string )(slotKey ) {
return unsafe .Pointer (uintptr (slotKey ) + 2 *goarch .PtrSize )
}
slotKey = unsafe .Pointer (uintptr (slotKey ) + slotSize )
ctrls >>= 8
}
return nil
}
func longStringQuickEqualityTest(a , b string ) bool {
if len (a ) != len (b ) {
return false
}
x , y := stringPtr (a ), stringPtr (b )
if *(*[8 ]byte )(x ) != *(*[8 ]byte )(y ) {
return false
}
x = unsafe .Pointer (uintptr (x ) + uintptr (len (a )) - 8 )
y = unsafe .Pointer (uintptr (y ) + uintptr (len (a )) - 8 )
if *(*[8 ]byte )(x ) != *(*[8 ]byte )(y ) {
return false
}
return true
}
func stringPtr(s string ) unsafe .Pointer {
type stringStruct struct {
ptr unsafe .Pointer
len int
}
return (*stringStruct )(unsafe .Pointer (&s )).ptr
}
func runtime_mapaccess1_faststr(typ *abi .SwissMapType , m *Map , key string ) unsafe .Pointer {
if race .Enabled && m != nil {
callerpc := sys .GetCallerPC ()
pc := abi .FuncPCABIInternal (runtime_mapaccess1 )
race .ReadPC (unsafe .Pointer (m ), callerpc , pc )
}
if m == nil || m .Used () == 0 {
return unsafe .Pointer (&zeroVal [0 ])
}
if m .writing != 0 {
fatal ("concurrent map read and map write" )
return nil
}
if m .dirLen <= 0 {
elem := m .getWithoutKeySmallFastStr (typ , key )
if elem == nil {
return unsafe .Pointer (&zeroVal [0 ])
}
return elem
}
k := key
hash := typ .Hasher (abi .NoEscape (unsafe .Pointer (&k )), m .seed )
idx := m .directoryIndex (hash )
t := m .directoryAt (idx )
seq := makeProbeSeq (h1 (hash ), t .groups .lengthMask )
for ; ; seq = seq .next () {
g := t .groups .group (typ , seq .offset )
match := g .ctrls ().matchH2 (h2 (hash ))
for match != 0 {
i := match .first ()
slotKey := g .key (typ , i )
if key == *(*string )(slotKey ) {
slotElem := unsafe .Pointer (uintptr (slotKey ) + 2 *goarch .PtrSize )
return slotElem
}
match = match .removeFirst ()
}
match = g .ctrls ().matchEmpty ()
if match != 0 {
return unsafe .Pointer (&zeroVal [0 ])
}
}
}
func runtime_mapaccess2_faststr(typ *abi .SwissMapType , m *Map , key string ) (unsafe .Pointer , bool ) {
if race .Enabled && m != nil {
callerpc := sys .GetCallerPC ()
pc := abi .FuncPCABIInternal (runtime_mapaccess1 )
race .ReadPC (unsafe .Pointer (m ), callerpc , pc )
}
if m == nil || m .Used () == 0 {
return unsafe .Pointer (&zeroVal [0 ]), false
}
if m .writing != 0 {
fatal ("concurrent map read and map write" )
return nil , false
}
if m .dirLen <= 0 {
elem := m .getWithoutKeySmallFastStr (typ , key )
if elem == nil {
return unsafe .Pointer (&zeroVal [0 ]), false
}
return elem , true
}
k := key
hash := typ .Hasher (abi .NoEscape (unsafe .Pointer (&k )), m .seed )
idx := m .directoryIndex (hash )
t := m .directoryAt (idx )
seq := makeProbeSeq (h1 (hash ), t .groups .lengthMask )
for ; ; seq = seq .next () {
g := t .groups .group (typ , seq .offset )
match := g .ctrls ().matchH2 (h2 (hash ))
for match != 0 {
i := match .first ()
slotKey := g .key (typ , i )
if key == *(*string )(slotKey ) {
slotElem := unsafe .Pointer (uintptr (slotKey ) + 2 *goarch .PtrSize )
return slotElem , true
}
match = match .removeFirst ()
}
match = g .ctrls ().matchEmpty ()
if match != 0 {
return unsafe .Pointer (&zeroVal [0 ]), false
}
}
}
func (m *Map ) putSlotSmallFastStr (typ *abi .SwissMapType , hash uintptr , key string ) unsafe .Pointer {
g := groupReference {
data : m .dirPtr ,
}
match := g .ctrls ().matchH2 (h2 (hash ))
for match != 0 {
i := match .first ()
slotKey := g .key (typ , i )
if key == *(*string )(slotKey ) {
*(*string )(slotKey ) = key
slotElem := g .elem (typ , i )
return slotElem
}
match = match .removeFirst ()
}
match = g .ctrls ().matchEmptyOrDeleted ()
if match == 0 {
fatal ("small map with no empty slot (concurrent map writes?)" )
}
i := match .first ()
slotKey := g .key (typ , i )
*(*string )(slotKey ) = key
slotElem := g .elem (typ , i )
g .ctrls ().set (i , ctrl (h2 (hash )))
m .used ++
return slotElem
}
func runtime_mapassign_faststr(typ *abi .SwissMapType , m *Map , key string ) unsafe .Pointer {
if m == nil {
panic (errNilAssign )
}
if race .Enabled {
callerpc := sys .GetCallerPC ()
pc := abi .FuncPCABIInternal (runtime_mapassign )
race .WritePC (unsafe .Pointer (m ), callerpc , pc )
}
if m .writing != 0 {
fatal ("concurrent map writes" )
}
k := key
hash := typ .Hasher (abi .NoEscape (unsafe .Pointer (&k )), m .seed )
m .writing ^= 1
if m .dirPtr == nil {
m .growToSmall (typ )
}
if m .dirLen == 0 {
if m .used < abi .SwissMapGroupSlots {
elem := m .putSlotSmallFastStr (typ , hash , key )
if m .writing == 0 {
fatal ("concurrent map writes" )
}
m .writing ^= 1
return elem
}
m .growToTable (typ )
}
var slotElem unsafe .Pointer
outer :
for {
idx := m .directoryIndex (hash )
t := m .directoryAt (idx )
seq := makeProbeSeq (h1 (hash ), t .groups .lengthMask )
var firstDeletedGroup groupReference
var firstDeletedSlot uintptr
for ; ; seq = seq .next () {
g := t .groups .group (typ , seq .offset )
match := g .ctrls ().matchH2 (h2 (hash ))
for match != 0 {
i := match .first ()
slotKey := g .key (typ , i )
if key == *(*string )(slotKey ) {
*(*string )(slotKey ) = key
slotElem = g .elem (typ , i )
t .checkInvariants (typ , m )
break outer
}
match = match .removeFirst ()
}
match = g .ctrls ().matchEmptyOrDeleted ()
if match == 0 {
continue
}
i := match .first ()
if g .ctrls ().get (i ) == ctrlDeleted {
if firstDeletedGroup .data == nil {
firstDeletedGroup = g
firstDeletedSlot = i
}
continue
}
if firstDeletedGroup .data != nil {
g = firstDeletedGroup
i = firstDeletedSlot
t .growthLeft ++
}
if t .growthLeft > 0 {
slotKey := g .key (typ , i )
*(*string )(slotKey ) = key
slotElem = g .elem (typ , i )
g .ctrls ().set (i , ctrl (h2 (hash )))
t .growthLeft --
t .used ++
m .used ++
t .checkInvariants (typ , m )
break outer
}
t .rehash (typ , m )
continue outer
}
}
if m .writing == 0 {
fatal ("concurrent map writes" )
}
m .writing ^= 1
return slotElem
}
func runtime_mapdelete_faststr(typ *abi .SwissMapType , m *Map , key string ) {
if race .Enabled {
callerpc := sys .GetCallerPC ()
pc := abi .FuncPCABIInternal (runtime_mapassign )
race .WritePC (unsafe .Pointer (m ), callerpc , pc )
}
if m == nil || m .Used () == 0 {
return
}
m .Delete (typ , abi .NoEscape (unsafe .Pointer (&key )))
}
The pages are generated with Golds v0.7.3-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .