reflect: add Cap and Len support for map and chan

Этот коммит содержится в:
cornelk 2020-05-11 20:55:20 +03:00 коммит произвёл Ayke
родитель 7e64bc8f77
коммит 2c71f08922
2 изменённых файлов: 34 добавлений и 8 удалений

Просмотреть файл

@ -304,29 +304,48 @@ func (v Value) Slice(i, j int) Value {
panic("unimplemented: (reflect.Value).Slice()")
}
//go:linkname maplen runtime.hashmapLenUnsafePointer
func maplen(p unsafe.Pointer) int
//go:linkname chanlen runtime.chanLenUnsafePointer
func chanlen(p unsafe.Pointer) int
// Len returns the length of this value for slices, strings, arrays, channels,
// and maps. For oter types, it panics.
// and maps. For other types, it panics.
func (v Value) Len() int {
t := v.Type()
switch t.Kind() {
case Array:
return v.Type().Len()
case Chan:
return chanlen(v.value)
case Map:
return maplen(v.value)
case Slice:
return int((*SliceHeader)(v.value).Len)
case String:
return int((*StringHeader)(v.value).Len)
case Array:
return v.Type().Len()
default: // Chan, Map
panic("unimplemented: (reflect.Value).Len()")
default:
panic(&ValueError{"Len"})
}
}
//go:linkname chancap runtime.chanCapUnsafePointer
func chancap(p unsafe.Pointer) int
// Cap returns the capacity of this value for arrays, channels and slices.
// For other types, it panics.
func (v Value) Cap() int {
t := v.Type()
switch t.Kind() {
case Array:
return v.Type().Len()
case Chan:
return chancap(v.value)
case Slice:
return int((*SliceHeader)(v.value).Cap)
default: // Array, Chan
panic("unimplemented: (reflect.Value).Cap()")
default:
panic(&ValueError{"Cap"})
}
}

Просмотреть файл

@ -1,7 +1,7 @@
package runtime
// This is a hashmap implementation for the map[T]T type.
// It is very rougly based on the implementation of the Go hashmap:
// It is very roughly based on the implementation of the Go hashmap:
//
// https://golang.org/src/runtime/map.go
@ -80,6 +80,7 @@ func hashmapMake(keySize, valueSize uint8, sizeHint uintptr) *hashmap {
// Return the number of entries in this hashmap, called from the len builtin.
// A nil hashmap is defined as having length 0.
//go:inline
func hashmapLen(m *hashmap) int {
if m == nil {
return 0
@ -87,6 +88,12 @@ func hashmapLen(m *hashmap) int {
return int(m.count)
}
// wrapper for use in reflect
func hashmapLenUnsafePointer(p unsafe.Pointer) int {
m := (*hashmap)(p)
return hashmapLen(m)
}
// Set a specified key to a given value. Grow the map if necessary.
//go:nobounds
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {