1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
20 func TestHmapSize(t
*testing
.T
) {
21 // The structure of hmap is defined in runtime/map.go
22 // and in cmd/compile/internal/gc/reflect.go and must be in sync.
23 // The size of hmap should be 48 bytes on 64 bit and 28 bytes on 32 bit platforms.
24 var hmapSize
= uintptr(8 + 5*goarch
.PtrSize
)
25 if runtime
.RuntimeHmapSize
!= hmapSize
{
26 t
.Errorf("sizeof(runtime.hmap{})==%d, want %d", runtime
.RuntimeHmapSize
, hmapSize
)
31 // negative zero is a good test because:
32 // 1) 0 and -0 are equal, yet have distinct representations.
33 // 2) 0 is represented as all zeros, -0 isn't.
34 // I'm not sure the language spec actually requires this behavior,
35 // but it's what the current map implementation does.
36 func TestNegativeZero(t
*testing
.T
) {
37 m
:= make(map[float64]bool, 0)
40 m
[math
.Copysign(0.0, -1.0)] = true // should overwrite +0 entry
43 t
.Error("length wrong")
47 if math
.Copysign(1.0, k
) > 0 {
52 m
= make(map[float64]bool, 0)
53 m
[math
.Copysign(0.0, -1.0)] = true
54 m
[+0.0] = true // should overwrite -0.0 entry
57 t
.Error("length wrong")
61 if math
.Copysign(1.0, k
) < 0 {
67 func testMapNan(t
*testing
.T
, m
map[float64]int) {
69 t
.Error("length wrong")
74 t
.Error("nan disappeared")
76 if (v
& (v
- 1)) != 0 {
77 t
.Error("value wrong")
82 t
.Error("values wrong")
86 // nan is a good test because nan != nan, and nan has
87 // a randomized hash value.
88 func TestMapAssignmentNan(t
*testing
.T
) {
89 m
:= make(map[float64]int, 0)
99 // nan is a good test because nan != nan, and nan has
100 // a randomized hash value.
101 func TestMapOperatorAssignmentNan(t
*testing
.T
) {
102 m
:= make(map[float64]int, 0)
105 // Test assignment operations.
112 func TestMapOperatorAssignment(t
*testing
.T
) {
113 m
:= make(map[int]int, 0)
115 // "m[k] op= x" is rewritten into "m[k] = m[k] op x"
116 // differently when op is / or % than when it isn't.
117 // Simple test to make sure they all work as expected.
123 const want
= (12345 + 67890) / 123 % 456
124 if got
:= m
[0]; got
!= want
{
125 t
.Errorf("got %d, want %d", got
, want
)
131 func TestMapAppendAssignment(t
*testing
.T
) {
132 m
:= make(map[int][]int, 0)
135 m
[0] = append(m
[0], 12345)
136 m
[0] = append(m
[0], 67890)
137 sinkAppend
, m
[0] = !sinkAppend
, append(m
[0], 123, 456)
138 a
:= []int{7, 8, 9, 0}
139 m
[0] = append(m
[0], a
...)
141 want
:= []int{12345, 67890, 123, 456, 7, 8, 9, 0}
142 if got
:= m
[0]; !reflect
.DeepEqual(got
, want
) {
143 t
.Errorf("got %v, want %v", got
, want
)
147 // Maps aren't actually copied on assignment.
148 func TestAlias(t
*testing
.T
) {
149 m
:= make(map[int]int, 0)
154 t
.Error("alias didn't work")
158 func TestGrowWithNaN(t
*testing
.T
) {
159 m
:= make(map[float64]int, 4)
162 // Use both assignment and assignment operations as they may
163 // behave differently.
171 for k
, v
:= range m
{
173 // force a hashtable resize
174 for i
:= 0; i
< 50; i
++ {
177 for i
:= 50; i
< 100; i
++ {
188 t
.Error("NaN keys lost during grow")
191 t
.Error("NaN values lost during grow")
195 type FloatInt
struct {
200 func TestGrowWithNegativeZero(t
*testing
.T
) {
201 negzero
:= math
.Copysign(0.0, -1.0)
202 m
:= make(map[FloatInt
]int, 4)
203 m
[FloatInt
{0.0, 0}] = 1
204 m
[FloatInt
{0.0, 1}] += 2
205 m
[FloatInt
{0.0, 2}] += 4
206 m
[FloatInt
{0.0, 3}] = 8
211 // The first iteration should return the +0 key.
212 // The subsequent iterations should return the -0 key.
213 // I'm not really sure this is required by the spec,
214 // but it makes sense.
215 // TODO: are we allowed to get the first entry returned again???
216 for k
, v
:= range m
{
219 } // ignore entries added to grow table
221 if math
.Copysign(1.0, k
.x
) < 0 {
223 t
.Error("key/value not updated together 1")
229 t
.Error("key/value not updated together 2", k
, v
)
234 // force a hashtable resize
235 for i
:= 0; i
< 100; i
++ {
236 m
[FloatInt
{3.0, i
}] = 0
238 // then change all the entries
240 m
[FloatInt
{negzero
, 0}] = 1 |
16
241 m
[FloatInt
{negzero
, 1}] = 2 |
16
242 m
[FloatInt
{negzero
, 2}] = 4 |
16
243 m
[FloatInt
{negzero
, 3}] = 8 |
16
248 t
.Error("entry missing", s
)
251 t
.Error("wrong number of entries returned by iterator", cnt
)
254 t
.Error("update to negzero missed by iteration", negcnt
)
258 func TestIterGrowAndDelete(t
*testing
.T
) {
259 m
:= make(map[int]int, 4)
260 for i
:= 0; i
< 100; i
++ {
267 for i
:= 100; i
< 1000; i
++ {
270 // delete all odd keys
271 for i
:= 1; i
< 1000; i
+= 2 {
277 t
.Error("odd value returned")
283 // make sure old bucket arrays don't get GCd while
284 // an iterator is still using them.
285 func TestIterGrowWithGC(t
*testing
.T
) {
286 m
:= make(map[int]int, 4)
287 for i
:= 0; i
< 8; i
++ {
290 for i
:= 8; i
< 16; i
++ {
297 bitmask |
= 1 << uint(k
)
301 for i
:= 100; i
< 1000; i
++ {
309 if bitmask
!= 1<<16-1 {
310 t
.Error("missing key", bitmask
)
314 func testConcurrentReadsAfterGrowth(t
*testing
.T
, useReflect
bool) {
316 if runtime
.GOMAXPROCS(-1) == 1 {
317 if runtime
.GOARCH
== "s390" {
318 // Test uses too much address space on 31-bit S390.
319 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(8))
321 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(16))
328 numLoop
, numGrowStep
= 2, 100
330 for i
:= 0; i
< numLoop
; i
++ {
331 m
:= make(map[int]int, 0)
332 for gs
:= 0; gs
< numGrowStep
; gs
++ {
334 var wg sync
.WaitGroup
335 wg
.Add(numReader
* 2)
336 for nr
:= 0; nr
< numReader
; nr
++ {
344 for key
:= 0; key
< gs
; key
++ {
352 mv
:= reflect
.ValueOf(m
)
354 for _
, k
:= range keys
{
365 func TestConcurrentReadsAfterGrowth(t
*testing
.T
) {
366 testConcurrentReadsAfterGrowth(t
, false)
369 func TestConcurrentReadsAfterGrowthReflect(t
*testing
.T
) {
370 testConcurrentReadsAfterGrowth(t
, true)
373 func TestBigItems(t
*testing
.T
) {
375 for i
:= 0; i
< 256; i
++ {
378 m
:= make(map[[256]string][256]string, 4)
379 for i
:= 0; i
< 100; i
++ {
380 key
[37] = fmt
.Sprintf("string%02d", i
)
384 var values
[100]string
386 for k
, v
:= range m
{
391 sort
.Strings(keys
[:])
392 sort
.Strings(values
[:])
393 for i
:= 0; i
< 100; i
++ {
394 if keys
[i
] != fmt
.Sprintf("string%02d", i
) {
395 t
.Errorf("#%d: missing key: %v", i
, keys
[i
])
397 if values
[i
] != fmt
.Sprintf("string%02d", i
) {
398 t
.Errorf("#%d: missing value: %v", i
, values
[i
])
403 func TestMapHugeZero(t
*testing
.T
) {
408 t
.Errorf("map value not zero")
412 t
.Errorf("map value should be missing")
415 t
.Errorf("map value not zero")
422 func TestEmptyKeyAndValue(t
*testing
.T
) {
423 a
:= make(map[int]empty
, 4)
424 b
:= make(map[empty
]int, 4)
425 c
:= make(map[empty
]empty
, 4)
432 t
.Errorf("empty value insert problem")
435 t
.Errorf("empty key returned wrong value")
439 // Tests a map with a single bucket, with same-lengthed short keys
440 // ("quick keys") as well as long keys.
441 func TestSingleBucketMapStringKeys_DupLen(t
*testing
.T
) {
442 testMapLookups(t
, map[string]string{
446 "bar": "barval", // same key length as "foo"
448 strings
.Repeat("x", 128): "longval1",
449 strings
.Repeat("y", 128): "longval2",
453 // Tests a map with a single bucket, with all keys having different lengths.
454 func TestSingleBucketMapStringKeys_NoDupLen(t
*testing
.T
) {
455 testMapLookups(t
, map[string]string{
462 strings
.Repeat("x", 128): "longval",
466 func testMapLookups(t
*testing
.T
, m
map[string]string) {
467 for k
, v
:= range m
{
469 t
.Fatalf("m[%q] = %q; want %q", k
, m
[k
], v
)
474 // Tests whether the iterator returns the right elements when
475 // started in the middle of a grow, when the keys are NaNs.
476 func TestMapNanGrowIterator(t
*testing
.T
) {
477 m
:= make(map[float64]int)
480 // To fill nBuckets buckets takes LOAD * nBuckets keys.
481 nKeys
:= int(nBuckets
* runtime
.HashLoad
)
483 // Get map to full point with nan keys.
484 for i
:= 0; i
< nKeys
; i
++ {
492 found
:= make(map[int]struct{})
493 for _
, v
:= range m
{
495 if _
, repeat
:= found
[v
]; repeat
{
496 t
.Fatalf("repeat of value %d", v
)
498 found
[v
] = struct{}{}
500 if len(found
) == nKeys
/2 {
501 // Halfway through iteration, finish grow.
502 for i
:= 0; i
< nBuckets
; i
++ {
507 if len(found
) != nKeys
{
508 t
.Fatalf("missing value")
512 func TestMapIterOrder(t
*testing
.T
) {
513 for _
, n
:= range [...]int{3, 7, 9, 15} {
514 for i
:= 0; i
< 1000; i
++ {
515 // Make m be {0: true, 1: true, ..., n-1: true}.
516 m
:= make(map[int]bool)
517 for i
:= 0; i
< n
; i
++ {
520 // Check that iterating over the map produces at least two different orderings.
521 ord
:= func() []int {
530 for try
:= 0; try
< 100; try
++ {
531 if !reflect
.DeepEqual(first
, ord()) {
537 t
.Errorf("Map with n=%d elements had consistent iteration order: %v", n
, first
)
545 func TestMapSparseIterOrder(t
*testing
.T
) {
546 // Run several rounds to increase the probability
547 // of failure. One is not enough.
549 for round
:= 0; round
< 10; round
++ {
550 m
:= make(map[int]bool)
551 // Add 1000 items, remove 980.
552 for i
:= 0; i
< 1000; i
++ {
555 for i
:= 20; i
< 1000; i
++ {
561 first
= append(first
, i
)
564 // 800 chances to get a different iteration order.
565 // See bug 8736 for why we need so many tries.
566 for n
:= 0; n
< 800; n
++ {
570 // iteration order changed.
576 t
.Fatalf("constant iteration order on round %d: %v", round
, first
)
580 func TestMapStringBytesLookup(t
*testing
.T
) {
581 // Use large string keys to avoid small-allocation coalescing,
582 // which can cause AllocsPerRun to report lower counts than it should.
584 "1000000000000000000000000000000000000000000000000": 1,
585 "2000000000000000000000000000000000000000000000000": 2,
587 buf
:= []byte("1000000000000000000000000000000000000000000000000")
588 if x
:= m
[string(buf
)]; x
!= 1 {
589 t
.Errorf(`m[string([]byte("1"))] = %d, want 1`, x
)
592 if x
:= m
[string(buf
)]; x
!= 2 {
593 t
.Errorf(`m[string([]byte("2"))] = %d, want 2`, x
)
596 t
.Skip("does not work on gccgo without better escape analysis")
599 n
:= testing
.AllocsPerRun(100, func() {
603 t
.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n
)
607 n
= testing
.AllocsPerRun(100, func() {
608 y
, ok
:= m
[string(buf
)]
615 t
.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n
)
619 func TestMapLargeKeyNoPointer(t
*testing
.T
) {
626 for i
:= 0; i
< I
; i
++ {
628 for j
:= 0; j
< N
; j
++ {
634 for i
:= 0; i
< I
; i
++ {
636 for j
:= 0; j
< N
; j
++ {
640 t
.Fatalf("corrupted map: want %+v, got %+v", i
, m
[v
])
645 func TestMapLargeValNoPointer(t
*testing
.T
) {
652 for i
:= 0; i
< I
; i
++ {
654 for j
:= 0; j
< N
; j
++ {
660 for i
:= 0; i
< I
; i
++ {
662 for j
:= 0; j
< N
; j
++ {
666 for j
:= 0; j
< N
; j
++ {
668 t
.Fatalf("corrupted map: want %+v, got %+v", v
, v1
)
674 // Test that making a map with a large or invalid hint
675 // doesn't panic. (Issue 19926).
676 func TestIgnoreBogusMapHint(t
*testing
.T
) {
677 for _
, hint
:= range []int64{-1, 1 << 62} {
678 _
= make(map[int]int, hint
)
682 var mapSink
map[int]int
684 var mapBucketTests
= [...]struct {
685 n
int // n is the number of map elements
686 noescape
int // number of expected buckets for non-escaping map
687 escape
int // number of expected buckets for escaping map
700 func TestMapBuckets(t
*testing
.T
) {
701 // Test that maps of different sizes have the right number of buckets.
702 // Non-escaping maps with small buckets (like map[int]int) never
703 // have a nil bucket pointer due to starting with preallocated buckets
704 // on the stack. Escaping maps start with a non-nil bucket pointer if
705 // hint size is above bucketCnt and thereby have more than one bucket.
706 // These tests depend on bucketCnt and loadFactor* in map.go.
707 t
.Run("mapliteral", func(t
*testing
.T
) {
708 for _
, tt
:= range mapBucketTests
{
709 localMap
:= map[int]int{}
710 // Skip test on gccgo until escape analysis is
712 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
713 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
715 for i
:= 0; i
< tt
.n
; i
++ {
718 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
719 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
721 escapingMap
:= map[int]int{}
722 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
723 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
725 for i
:= 0; i
< tt
.n
; i
++ {
728 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
729 t
.Errorf("escape n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
731 mapSink
= escapingMap
734 t
.Run("nohint", func(t
*testing
.T
) {
735 for _
, tt
:= range mapBucketTests
{
736 localMap
:= make(map[int]int)
737 // Skip test on gccgo until escape analysis is
739 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
740 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
742 for i
:= 0; i
< tt
.n
; i
++ {
745 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
746 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
748 escapingMap
:= make(map[int]int)
749 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
750 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
752 for i
:= 0; i
< tt
.n
; i
++ {
755 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
756 t
.Errorf("escape: n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
758 mapSink
= escapingMap
761 t
.Run("makemap", func(t
*testing
.T
) {
762 for _
, tt
:= range mapBucketTests
{
763 localMap
:= make(map[int]int, tt
.n
)
764 // Skip test on gccgo until escape analysis is
766 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
767 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
769 for i
:= 0; i
< tt
.n
; i
++ {
772 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
773 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
775 escapingMap
:= make(map[int]int, tt
.n
)
776 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
777 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
779 for i
:= 0; i
< tt
.n
; i
++ {
782 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
783 t
.Errorf("escape: n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
785 mapSink
= escapingMap
788 t
.Run("makemap64", func(t
*testing
.T
) {
789 for _
, tt
:= range mapBucketTests
{
790 localMap
:= make(map[int]int, int64(tt
.n
))
791 // Skip test on gccgo until escape analysis is
793 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
794 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
796 for i
:= 0; i
< tt
.n
; i
++ {
799 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
800 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
802 escapingMap
:= make(map[int]int, tt
.n
)
803 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
804 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
806 for i
:= 0; i
< tt
.n
; i
++ {
809 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
810 t
.Errorf("escape: n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
812 mapSink
= escapingMap
818 func benchmarkMapPop(b
*testing
.B
, n
int) {
820 for i
:= 0; i
< b
.N
; i
++ {
821 for j
:= 0; j
< n
; j
++ {
824 for j
:= 0; j
< n
; j
++ {
825 // Use iterator to pop an element.
826 // We want this to be fast, see issue 8412.
835 func BenchmarkMapPop100(b
*testing
.B
) { benchmarkMapPop(b
, 100) }
836 func BenchmarkMapPop1000(b
*testing
.B
) { benchmarkMapPop(b
, 1000) }
837 func BenchmarkMapPop10000(b
*testing
.B
) { benchmarkMapPop(b
, 10000) }
839 var testNonEscapingMapVariable
int = 8
841 func TestNonEscapingMap(t
*testing
.T
) {
842 t
.Skip("does not work on gccgo without better escape analysis")
843 n
:= testing
.AllocsPerRun(1000, func() {
848 t
.Fatalf("mapliteral: want 0 allocs, got %v", n
)
850 n
= testing
.AllocsPerRun(1000, func() {
851 m
:= make(map[int]int)
855 t
.Fatalf("no hint: want 0 allocs, got %v", n
)
857 n
= testing
.AllocsPerRun(1000, func() {
858 m
:= make(map[int]int, 8)
862 t
.Fatalf("with small hint: want 0 allocs, got %v", n
)
864 n
= testing
.AllocsPerRun(1000, func() {
865 m
:= make(map[int]int, testNonEscapingMapVariable
)
869 t
.Fatalf("with variable hint: want 0 allocs, got %v", n
)
874 func benchmarkMapAssignInt32(b
*testing
.B
, n
int) {
875 a
:= make(map[int32]int)
876 for i
:= 0; i
< b
.N
; i
++ {
877 a
[int32(i
&(n
-1))] = i
881 func benchmarkMapOperatorAssignInt32(b
*testing
.B
, n
int) {
882 a
:= make(map[int32]int)
883 for i
:= 0; i
< b
.N
; i
++ {
884 a
[int32(i
&(n
-1))] += i
888 func benchmarkMapAppendAssignInt32(b
*testing
.B
, n
int) {
889 a
:= make(map[int32][]int)
892 for i
:= 0; i
< b
.N
; i
++ {
893 key
:= int32(i
& (n
- 1))
894 a
[key
] = append(a
[key
], i
)
898 func benchmarkMapDeleteInt32(b
*testing
.B
, n
int) {
899 a
:= make(map[int32]int, n
)
901 for i
:= 0; i
< b
.N
; i
++ {
904 for j
:= i
; j
< i
+n
; j
++ {
913 func benchmarkMapAssignInt64(b
*testing
.B
, n
int) {
914 a
:= make(map[int64]int)
915 for i
:= 0; i
< b
.N
; i
++ {
916 a
[int64(i
&(n
-1))] = i
920 func benchmarkMapOperatorAssignInt64(b
*testing
.B
, n
int) {
921 a
:= make(map[int64]int)
922 for i
:= 0; i
< b
.N
; i
++ {
923 a
[int64(i
&(n
-1))] += i
927 func benchmarkMapAppendAssignInt64(b
*testing
.B
, n
int) {
928 a
:= make(map[int64][]int)
931 for i
:= 0; i
< b
.N
; i
++ {
932 key
:= int64(i
& (n
- 1))
933 a
[key
] = append(a
[key
], i
)
937 func benchmarkMapDeleteInt64(b
*testing
.B
, n
int) {
938 a
:= make(map[int64]int, n
)
940 for i
:= 0; i
< b
.N
; i
++ {
943 for j
:= i
; j
< i
+n
; j
++ {
952 func benchmarkMapAssignStr(b
*testing
.B
, n
int) {
953 k
:= make([]string, n
)
954 for i
:= 0; i
< len(k
); i
++ {
955 k
[i
] = strconv
.Itoa(i
)
958 a
:= make(map[string]int)
959 for i
:= 0; i
< b
.N
; i
++ {
964 func benchmarkMapOperatorAssignStr(b
*testing
.B
, n
int) {
965 k
:= make([]string, n
)
966 for i
:= 0; i
< len(k
); i
++ {
967 k
[i
] = strconv
.Itoa(i
)
970 a
:= make(map[string]string)
971 for i
:= 0; i
< b
.N
; i
++ {
977 func benchmarkMapAppendAssignStr(b
*testing
.B
, n
int) {
978 k
:= make([]string, n
)
979 for i
:= 0; i
< len(k
); i
++ {
980 k
[i
] = strconv
.Itoa(i
)
982 a
:= make(map[string][]string)
985 for i
:= 0; i
< b
.N
; i
++ {
987 a
[key
] = append(a
[key
], key
)
991 func benchmarkMapDeleteStr(b
*testing
.B
, n
int) {
992 i2s
:= make([]string, n
)
993 for i
:= 0; i
< n
; i
++ {
994 i2s
[i
] = strconv
.Itoa(i
)
996 a
:= make(map[string]int, n
)
999 for i
:= 0; i
< b
.N
; i
++ {
1002 for j
:= 0; j
< n
; j
++ {
1012 func benchmarkMapDeletePointer(b
*testing
.B
, n
int) {
1013 i2p
:= make([]*int, n
)
1014 for i
:= 0; i
< n
; i
++ {
1017 a
:= make(map[*int]int, n
)
1020 for i
:= 0; i
< b
.N
; i
++ {
1023 for j
:= 0; j
< n
; j
++ {
1033 func runWith(f
func(*testing
.B
, int), v
...int) func(*testing
.B
) {
1034 return func(b
*testing
.B
) {
1035 for _
, n
:= range v
{
1036 b
.Run(strconv
.Itoa(n
), func(b
*testing
.B
) { f(b
, n
) })
1041 func BenchmarkMapAssign(b
*testing
.B
) {
1042 b
.Run("Int32", runWith(benchmarkMapAssignInt32
, 1<<8, 1<<16))
1043 b
.Run("Int64", runWith(benchmarkMapAssignInt64
, 1<<8, 1<<16))
1044 b
.Run("Str", runWith(benchmarkMapAssignStr
, 1<<8, 1<<16))
1047 func BenchmarkMapOperatorAssign(b
*testing
.B
) {
1048 b
.Run("Int32", runWith(benchmarkMapOperatorAssignInt32
, 1<<8, 1<<16))
1049 b
.Run("Int64", runWith(benchmarkMapOperatorAssignInt64
, 1<<8, 1<<16))
1050 b
.Run("Str", runWith(benchmarkMapOperatorAssignStr
, 1<<8, 1<<16))
1053 func BenchmarkMapAppendAssign(b
*testing
.B
) {
1054 b
.Run("Int32", runWith(benchmarkMapAppendAssignInt32
, 1<<8, 1<<16))
1055 b
.Run("Int64", runWith(benchmarkMapAppendAssignInt64
, 1<<8, 1<<16))
1056 b
.Run("Str", runWith(benchmarkMapAppendAssignStr
, 1<<8, 1<<16))
1059 func BenchmarkMapDelete(b
*testing
.B
) {
1060 b
.Run("Int32", runWith(benchmarkMapDeleteInt32
, 100, 1000, 10000))
1061 b
.Run("Int64", runWith(benchmarkMapDeleteInt64
, 100, 1000, 10000))
1062 b
.Run("Str", runWith(benchmarkMapDeleteStr
, 100, 1000, 10000))
1063 b
.Run("Pointer", runWith(benchmarkMapDeletePointer
, 100, 1000, 10000))
1066 func TestDeferDeleteSlow(t
*testing
.T
) {
1067 ks
:= []complex128
{0, 1, 2, 3}
1069 m
:= make(map[any
]int)
1070 for i
, k
:= range ks
{
1073 if len(m
) != len(ks
) {
1074 t
.Errorf("want %d elements, got %d", len(ks
), len(m
))
1078 for _
, k
:= range ks
{
1083 t
.Errorf("want 0 elements, got %d", len(m
))
1087 // TestIncrementAfterDeleteValueInt and other test Issue 25936.
1088 // Value types int, int32, int64 are affected. Value type string
1089 // works as expected.
1090 func TestIncrementAfterDeleteValueInt(t
*testing
.T
) {
1094 m
:= make(map[int]int)
1098 if n2
:= m
[key2
]; n2
!= 1 {
1099 t
.Errorf("incremented 0 to %d", n2
)
1103 func TestIncrementAfterDeleteValueInt32(t
*testing
.T
) {
1107 m
:= make(map[int]int32)
1111 if n2
:= m
[key2
]; n2
!= 1 {
1112 t
.Errorf("incremented 0 to %d", n2
)
1116 func TestIncrementAfterDeleteValueInt64(t
*testing
.T
) {
1120 m
:= make(map[int]int64)
1124 if n2
:= m
[key2
]; n2
!= 1 {
1125 t
.Errorf("incremented 0 to %d", n2
)
1129 func TestIncrementAfterDeleteKeyStringValueInt(t
*testing
.T
) {
1133 m
:= make(map[string]int)
1137 if n2
:= m
[key2
]; n2
!= 1 {
1138 t
.Errorf("incremented 0 to %d", n2
)
1142 func TestIncrementAfterDeleteKeyValueString(t
*testing
.T
) {
1146 m
:= make(map[string]string)
1150 if n2
:= m
[key2
]; n2
!= "1" {
1151 t
.Errorf("appended '1' to empty (nil) string, got %s", n2
)
1155 // TestIncrementAfterBulkClearKeyStringValueInt tests that map bulk
1156 // deletion (mapclear) still works as expected. Note that it was not
1157 // affected by Issue 25936.
1158 func TestIncrementAfterBulkClearKeyStringValueInt(t
*testing
.T
) {
1162 m
:= make(map[string]int)
1168 if n2
:= m
[key2
]; n2
!= 1 {
1169 t
.Errorf("incremented 0 to %d", n2
)
1173 func TestMapTombstones(t
*testing
.T
) {
1177 for i
:= 0; i
< N
; i
++ {
1180 runtime
.MapTombstoneCheck(m
)
1181 // Delete half of the entries.
1182 for i
:= 0; i
< N
; i
+= 2 {
1185 runtime
.MapTombstoneCheck(m
)
1186 // Add new entries to fill in holes.
1187 for i
:= N
; i
< 3*N
/2; i
++ {
1190 runtime
.MapTombstoneCheck(m
)
1191 // Delete everything.
1192 for i
:= 0; i
< 3*N
/2; i
++ {
1195 runtime
.MapTombstoneCheck(m
)
1200 func (c canString
) String() string {
1201 return fmt
.Sprintf("%d", int(c
))
1204 func TestMapInterfaceKey(t
*testing
.T
) {
1205 // Test all the special cases in runtime.typehash.
1206 type GrabBag
struct {
1220 // Put a bunch of data in m, so that a bad hash is likely to
1221 // lead to a bad bucket, which will lead to a missed lookup.
1222 for i
:= 0; i
< 1000; i
++ {
1225 m
[GrabBag
{f32
: 1.0}] = true
1226 if !m
[GrabBag
{f32
: 1.0}] {
1227 panic("f32 not found")
1229 m
[GrabBag
{f64
: 1.0}] = true
1230 if !m
[GrabBag
{f64
: 1.0}] {
1231 panic("f64 not found")
1233 m
[GrabBag
{c64
: 1.0i
}] = true
1234 if !m
[GrabBag
{c64
: 1.0i
}] {
1235 panic("c64 not found")
1237 m
[GrabBag
{c128
: 1.0i
}] = true
1238 if !m
[GrabBag
{c128
: 1.0i
}] {
1239 panic("c128 not found")
1241 m
[GrabBag
{s
: "foo"}] = true
1242 if !m
[GrabBag
{s
: "foo"}] {
1243 panic("string not found")
1245 m
[GrabBag
{i0
: "foo"}] = true
1246 if !m
[GrabBag
{i0
: "foo"}] {
1247 panic("interface{} not found")
1249 m
[GrabBag
{i1
: canString(5)}] = true
1250 if !m
[GrabBag
{i1
: canString(5)}] {
1251 panic("interface{String() string} not found")
1253 m
[GrabBag
{a
: [4]string{"foo", "bar", "baz", "bop"}}] = true
1254 if !m
[GrabBag
{a
: [4]string{"foo", "bar", "baz", "bop"}}] {
1255 panic("array not found")