Files
llgo/internal/runtime/z_map.go

129 lines
3.2 KiB
Go
Raw Normal View History

2024-05-01 07:26:51 +08:00
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed 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 runtime
2024-06-13 22:58:04 +08:00
import (
"unsafe"
"github.com/goplus/llgo/internal/abi"
)
2024-05-01 07:26:51 +08:00
// Map represents a Go map.
type Map = hmap
2024-06-14 21:57:34 +08:00
type MapType = abi.MapType
2024-05-01 07:26:51 +08:00
// MakeSmallMap creates a new small map.
func MakeSmallMap() *Map {
return makemap_small()
}
2024-06-13 22:58:04 +08:00
2024-06-14 21:57:34 +08:00
// MakeMap creates a new map.
func MakeMap(t *MapType, hint int, at *Map) *Map {
return makemap(t, hint, at)
}
// MapAssign finds a key in map m and returns the elem address to assign.
func MapAssign(t *MapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
2024-06-13 22:58:04 +08:00
return mapassign(t, m, key)
}
2024-06-14 21:57:34 +08:00
func isReflexive(key *Type) bool {
return true // TODO(xsw): false for float/complex type
}
func hashOf(t *Type) func(key unsafe.Pointer, hash0 uintptr) uintptr {
if t.TFlag&abi.TFlagRegularMemory != 0 {
switch t.Size_ {
case 4:
return memhash32
case 8:
return memhash64
}
return func(key unsafe.Pointer, hash0 uintptr) uintptr {
return memhash(key, hash0, t.Size_)
}
}
switch t.Kind() {
case abi.Float32:
return f32hash
case abi.Float64:
return f64hash
case abi.Complex64:
return c64hash
case abi.Complex128:
return c128hash
case abi.String:
return strhash
case abi.Interface:
i := (*interfacetype)(unsafe.Pointer(t))
if len(i.Methods) == 0 {
return nilinterhash
}
return interhash
}
return func(key unsafe.Pointer, hash0 uintptr) uintptr {
return typehash(t, key, hash0)
}
}
// MapOf creates a new map type.
func MapOf(key, elem *Type) *MapType {
var flags uint32
keySlot, elemSlot := key, elem
ptrTy := Basic(abi.UnsafePointer)
if keySlot.Size_ > 128 {
keySlot = ptrTy
flags |= 1
}
if elemSlot.Size_ > 128 {
elemSlot = ptrTy
flags |= 2
}
if isReflexive(key) {
flags |= 4
}
tophashTy := ArrayOf(bucketCnt, Basic(abi.Uint8))
keysTy := ArrayOf(bucketCnt, keySlot)
elemsTy := ArrayOf(bucketCnt, elemSlot)
tophash := StructField("tophash", tophashTy, 0, "", false)
keys := StructField("keys", keysTy, tophashTy.Size_, "", false)
elems := StructField("elems", elemsTy, keys.Offset+keysTy.Size_, "", false)
overflow := StructField("overflow", ptrTy, elems.Offset+elemsTy.Size_, "", false)
bucket := Struct("", overflow.Offset+ptrTy.Size_, tophash, keys, elems, overflow)
ret := &abi.MapType{
Type: abi.Type{
Size_: unsafe.Sizeof(uintptr(0)),
Hash: uint32(abi.Map),
Kind_: uint8(abi.Map),
},
Key: key,
Elem: elem,
Bucket: bucket,
Hasher: hashOf(key),
KeySize: uint8(keySlot.Size_), // size of key slot
ValueSize: uint8(elemSlot.Size_), // size of elem slot
BucketSize: uint16(bucket.Size_), // size of bucket
Flags: flags,
}
return ret
}