mirror of
https://github.com/golang/go
synced 2024-11-18 02:04:45 -07:00
reflect: add MakeMapWithSize for creating maps with size hint
Providing size hint when creating a map allows avoiding re-allocating underlying data structure if we know how many elements are going to be inserted. This can be used for example during decoding maps in gob. Fixes #19599 Change-Id: I108035fec29391215d2261a73eaed1310b46bab1 Reviewed-on: https://go-review.googlesource.com/38335 Reviewed-by: Rob Pike <r@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
be5a201e2a
commit
6c5a819a5e
@ -5850,6 +5850,24 @@ func TestMapAlloc(t *testing.T) {
|
||||
if allocs > 0.5 {
|
||||
t.Errorf("allocs per map assignment: want 0 got %f", allocs)
|
||||
}
|
||||
|
||||
const size = 1000
|
||||
tmp := 0
|
||||
val := ValueOf(&tmp).Elem()
|
||||
allocs = testing.AllocsPerRun(100, func() {
|
||||
mv := MakeMapWithSize(TypeOf(map[int]int{}), size)
|
||||
// Only adding half of the capacity to not trigger re-allocations due too many overloaded buckets.
|
||||
for i := 0; i < size/2; i++ {
|
||||
val.SetInt(int64(i))
|
||||
mv.SetMapIndex(val, val)
|
||||
}
|
||||
})
|
||||
if allocs > 10 {
|
||||
t.Errorf("allocs per map assignment: want at most 10 got %f", allocs)
|
||||
}
|
||||
// Empirical testing shows that with capacity hint single run will trigger 3 allocations and without 91. I set
|
||||
// the threshold to 10, to not make it overly brittle if something changes in the initial allocation of the
|
||||
// map, but to still catch a regression where we keep re-allocating in the hashmap as new entries are added.
|
||||
}
|
||||
|
||||
func TestChanAlloc(t *testing.T) {
|
||||
|
@ -2077,12 +2077,17 @@ func MakeChan(typ Type, buffer int) Value {
|
||||
return Value{typ.common(), ch, flag(Chan)}
|
||||
}
|
||||
|
||||
// MakeMap creates a new map of the specified type.
|
||||
// MakeMap creates a new map with the specified type.
|
||||
func MakeMap(typ Type) Value {
|
||||
return MakeMapWithSize(typ, 0)
|
||||
}
|
||||
|
||||
// MakeMapWithSize creates a new map with the specified type and initial capacity.
|
||||
func MakeMapWithSize(typ Type, cap int) Value {
|
||||
if typ.Kind() != Map {
|
||||
panic("reflect.MakeMap of non-map type")
|
||||
panic("reflect.MakeMapWithSize of non-map type")
|
||||
}
|
||||
m := makemap(typ.(*rtype))
|
||||
m := makemap(typ.(*rtype), cap)
|
||||
return Value{typ.common(), m, flag(Map)}
|
||||
}
|
||||
|
||||
@ -2477,7 +2482,7 @@ func chanrecv(ch unsafe.Pointer, nb bool, val unsafe.Pointer) (selected, receive
|
||||
func chansend(ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
|
||||
|
||||
func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
|
||||
func makemap(t *rtype) (m unsafe.Pointer)
|
||||
func makemap(t *rtype, cap int) (m unsafe.Pointer)
|
||||
|
||||
//go:noescape
|
||||
func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
|
||||
|
@ -1139,8 +1139,8 @@ func ismapkey(t *_type) bool {
|
||||
// Reflect stubs. Called from ../reflect/asm_*.s
|
||||
|
||||
//go:linkname reflect_makemap reflect.makemap
|
||||
func reflect_makemap(t *maptype) *hmap {
|
||||
return makemap(t, 0, nil, nil)
|
||||
func reflect_makemap(t *maptype, cap int) *hmap {
|
||||
return makemap(t, int64(cap), nil, nil)
|
||||
}
|
||||
|
||||
//go:linkname reflect_mapaccess reflect.mapaccess
|
||||
|
Loading…
Reference in New Issue
Block a user