mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-07 20:43:40 +00:00
compiler,runtime: implement maps for arbitrary keys
This implementation simply casts types without special support to an interface, to make the implementation simpler and possibly reducing the code size too. It will likely be slower than the canonical Go implementation though (which builds special compare and hash functions at compile time).
This commit is contained in:
committed by
Ron Evans
parent
440dc8ed4e
commit
0d34f933eb
+40
-5
@@ -14,8 +14,20 @@ import (
|
||||
// initializing an appropriately sized object.
|
||||
func (c *Compiler) emitMakeMap(frame *Frame, expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
mapType := expr.Type().Underlying().(*types.Map)
|
||||
llvmKeyType := c.getLLVMType(mapType.Key().Underlying())
|
||||
keyType := mapType.Key().Underlying()
|
||||
llvmValueType := c.getLLVMType(mapType.Elem().Underlying())
|
||||
var llvmKeyType llvm.Type
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// String keys.
|
||||
llvmKeyType = c.getLLVMType(keyType)
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
// Trivially comparable keys.
|
||||
llvmKeyType = c.getLLVMType(keyType)
|
||||
} else {
|
||||
// All other keys. Implemented as map[interface{}]valueType for ease of
|
||||
// implementation.
|
||||
llvmKeyType = c.getLLVMRuntimeType("_interface")
|
||||
}
|
||||
keySize := c.targetData.TypeAllocSize(llvmKeyType)
|
||||
valueSize := c.targetData.TypeAllocSize(llvmValueType)
|
||||
llvmKeySize := llvm.ConstInt(c.ctx.Int8Type(), keySize, false)
|
||||
@@ -43,6 +55,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
|
||||
|
||||
// Do the lookup. How it is done depends on the key type.
|
||||
var commaOkValue llvm.Value
|
||||
keyType = keyType.Underlying()
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// key is a string
|
||||
params := []llvm.Value{m, key, mapValuePtr}
|
||||
@@ -58,8 +71,14 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
|
||||
commaOkValue = c.createRuntimeCall("hashmapBinaryGet", params, "")
|
||||
c.emitLifetimeEnd(mapKeyPtr, mapKeySize)
|
||||
} else {
|
||||
// Not trivially comparable using memcmp.
|
||||
return llvm.Value{}, c.makeError(pos, "only strings, bools, ints, pointers or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
||||
// Not trivially comparable using memcmp. Make it an interface instead.
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface now.
|
||||
itfKey = c.parseMakeInterface(key, keyType, pos)
|
||||
}
|
||||
params := []llvm.Value{m, itfKey, mapValuePtr}
|
||||
commaOkValue = c.createRuntimeCall("hashmapInterfaceGet", params, "")
|
||||
}
|
||||
|
||||
// Load the resulting value from the hashmap. The value is set to the zero
|
||||
@@ -93,7 +112,14 @@ func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, p
|
||||
c.createRuntimeCall("hashmapBinarySet", params, "")
|
||||
c.emitLifetimeEnd(keyPtr, keySize)
|
||||
} else {
|
||||
c.addError(pos, "only strings, bools, ints, pointers or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
||||
// Key is not trivially comparable, so compare it as an interface instead.
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface first.
|
||||
itfKey = c.parseMakeInterface(key, keyType, pos)
|
||||
}
|
||||
params := []llvm.Value{m, itfKey, valuePtr}
|
||||
c.createRuntimeCall("hashmapInterfaceSet", params, "")
|
||||
}
|
||||
c.emitLifetimeEnd(valuePtr, valueSize)
|
||||
}
|
||||
@@ -113,7 +139,16 @@ func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value, pos toke
|
||||
c.emitLifetimeEnd(keyPtr, keySize)
|
||||
return nil
|
||||
} else {
|
||||
return c.makeError(pos, "only strings, bools, ints, pointers or structs of bools/ints are supported as map keys, but got: "+keyType.String())
|
||||
// Key is not trivially comparable, so compare it as an interface
|
||||
// instead.
|
||||
itfKey := key
|
||||
if _, ok := keyType.(*types.Interface); !ok {
|
||||
// Not already an interface, so convert it to an interface first.
|
||||
itfKey = c.parseMakeInterface(key, keyType, pos)
|
||||
}
|
||||
params := []llvm.Value{m, itfKey}
|
||||
c.createRuntimeCall("hashmapInterfaceDelete", params, "")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user