rs6000: Fix wrong RTL patterns for vector merge high/low word on LE
[official-gcc.git] / libgo / go / runtime / map_test.go
blob2da4643dff7c6a910e44b7c6acf4fba550faff94
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.
5 package runtime_test
7 import (
8 "fmt"
9 "internal/goarch"
10 "math"
11 "reflect"
12 "runtime"
13 "sort"
14 "strconv"
15 "strings"
16 "sync"
17 "testing"
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)
39 m[+0.0] = true
40 m[math.Copysign(0.0, -1.0)] = true // should overwrite +0 entry
42 if len(m) != 1 {
43 t.Error("length wrong")
46 for k := range m {
47 if math.Copysign(1.0, k) > 0 {
48 t.Error("wrong sign")
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
56 if len(m) != 1 {
57 t.Error("length wrong")
60 for k := range m {
61 if math.Copysign(1.0, k) < 0 {
62 t.Error("wrong sign")
67 func testMapNan(t *testing.T, m map[float64]int) {
68 if len(m) != 3 {
69 t.Error("length wrong")
71 s := 0
72 for k, v := range m {
73 if k == k {
74 t.Error("nan disappeared")
76 if (v & (v - 1)) != 0 {
77 t.Error("value wrong")
79 s |= v
81 if s != 7 {
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)
90 nan := math.NaN()
92 // Test assignment.
93 m[nan] = 1
94 m[nan] = 2
95 m[nan] = 4
96 testMapNan(t, m)
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)
103 nan := math.NaN()
105 // Test assignment operations.
106 m[nan] += 1
107 m[nan] += 2
108 m[nan] += 4
109 testMapNan(t, m)
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.
118 m[0] = 12345
119 m[0] += 67890
120 m[0] /= 123
121 m[0] %= 456
123 const want = (12345 + 67890) / 123 % 456
124 if got := m[0]; got != want {
125 t.Errorf("got %d, want %d", got, want)
129 var sinkAppend bool
131 func TestMapAppendAssignment(t *testing.T) {
132 m := make(map[int][]int, 0)
134 m[0] = nil
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)
150 m[0] = 5
151 n := m
152 n[0] = 6
153 if m[0] != 6 {
154 t.Error("alias didn't work")
158 func TestGrowWithNaN(t *testing.T) {
159 m := make(map[float64]int, 4)
160 nan := math.NaN()
162 // Use both assignment and assignment operations as they may
163 // behave differently.
164 m[nan] = 1
165 m[nan] = 2
166 m[nan] += 4
168 cnt := 0
169 s := 0
170 growflag := true
171 for k, v := range m {
172 if growflag {
173 // force a hashtable resize
174 for i := 0; i < 50; i++ {
175 m[float64(i)] = i
177 for i := 50; i < 100; i++ {
178 m[float64(i)] += i
180 growflag = false
182 if k != k {
183 cnt++
184 s |= v
187 if cnt != 3 {
188 t.Error("NaN keys lost during grow")
190 if s != 7 {
191 t.Error("NaN values lost during grow")
195 type FloatInt struct {
196 x float64
197 y int
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
207 growflag := true
208 s := 0
209 cnt := 0
210 negcnt := 0
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 {
217 if v == 0 {
218 continue
219 } // ignore entries added to grow table
220 cnt++
221 if math.Copysign(1.0, k.x) < 0 {
222 if v&16 == 0 {
223 t.Error("key/value not updated together 1")
225 negcnt++
226 s |= v & 15
227 } else {
228 if v&16 == 16 {
229 t.Error("key/value not updated together 2", k, v)
231 s |= v
233 if growflag {
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
239 // to negative zero
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
244 growflag = false
247 if s != 15 {
248 t.Error("entry missing", s)
250 if cnt != 4 {
251 t.Error("wrong number of entries returned by iterator", cnt)
253 if negcnt != 3 {
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++ {
261 m[i] = i
263 growflag := true
264 for k := range m {
265 if growflag {
266 // grow the table
267 for i := 100; i < 1000; i++ {
268 m[i] = i
270 // delete all odd keys
271 for i := 1; i < 1000; i += 2 {
272 delete(m, i)
274 growflag = false
275 } else {
276 if k&1 == 1 {
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++ {
288 m[i] = i
290 for i := 8; i < 16; i++ {
291 m[i] += i
293 growflag := true
294 bitmask := 0
295 for k := range m {
296 if k < 16 {
297 bitmask |= 1 << uint(k)
299 if growflag {
300 // grow the table
301 for i := 100; i < 1000; i++ {
302 m[i] = i
304 // trigger a gc
305 runtime.GC()
306 growflag = false
309 if bitmask != 1<<16-1 {
310 t.Error("missing key", bitmask)
314 func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
315 t.Parallel()
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))
320 } else {
321 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
324 numLoop := 10
325 numGrowStep := 250
326 numReader := 16
327 if testing.Short() {
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++ {
333 m[gs] = gs
334 var wg sync.WaitGroup
335 wg.Add(numReader * 2)
336 for nr := 0; nr < numReader; nr++ {
337 go func() {
338 defer wg.Done()
339 for range m {
342 go func() {
343 defer wg.Done()
344 for key := 0; key < gs; key++ {
345 _ = m[key]
348 if useReflect {
349 wg.Add(1)
350 go func() {
351 defer wg.Done()
352 mv := reflect.ValueOf(m)
353 keys := mv.MapKeys()
354 for _, k := range keys {
355 mv.MapIndex(k)
360 wg.Wait()
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) {
374 var key [256]string
375 for i := 0; i < 256; i++ {
376 key[i] = "foo"
378 m := make(map[[256]string][256]string, 4)
379 for i := 0; i < 100; i++ {
380 key[37] = fmt.Sprintf("string%02d", i)
381 m[key] = key
383 var keys [100]string
384 var values [100]string
385 i := 0
386 for k, v := range m {
387 keys[i] = k[37]
388 values[i] = v[37]
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) {
404 type T [4000]byte
405 m := map[int]T{}
406 x := m[0]
407 if x != (T{}) {
408 t.Errorf("map value not zero")
410 y, ok := m[0]
411 if ok {
412 t.Errorf("map value should be missing")
414 if y != (T{}) {
415 t.Errorf("map value not zero")
419 type empty struct {
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)
426 a[0] = empty{}
427 b[empty{}] = 0
428 b[empty{}] = 1
429 c[empty{}] = empty{}
431 if len(a) != 1 {
432 t.Errorf("empty value insert problem")
434 if b[empty{}] != 1 {
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{
443 "x": "x1val",
444 "xx": "x2val",
445 "foo": "fooval",
446 "bar": "barval", // same key length as "foo"
447 "xxxx": "x4val",
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{
456 "x": "x1val",
457 "xx": "x2val",
458 "foo": "fooval",
459 "xxxx": "x4val",
460 "xxxxx": "x5val",
461 "xxxxxx": "x6val",
462 strings.Repeat("x", 128): "longval",
466 func testMapLookups(t *testing.T, m map[string]string) {
467 for k, v := range m {
468 if m[k] != v {
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)
478 nan := math.NaN()
479 const nBuckets = 16
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++ {
485 m[nan] = i
487 // Trigger grow
488 m[1.0] = 1
489 delete(m, 1.0)
491 // Run iterator
492 found := make(map[int]struct{})
493 for _, v := range m {
494 if v != -1 {
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++ {
503 delete(m, 1.0)
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++ {
518 m[i] = true
520 // Check that iterating over the map produces at least two different orderings.
521 ord := func() []int {
522 var s []int
523 for key := range m {
524 s = append(s, key)
526 return s
528 first := ord()
529 ok := false
530 for try := 0; try < 100; try++ {
531 if !reflect.DeepEqual(first, ord()) {
532 ok = true
533 break
536 if !ok {
537 t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
538 break
544 // Issue 8410
545 func TestMapSparseIterOrder(t *testing.T) {
546 // Run several rounds to increase the probability
547 // of failure. One is not enough.
548 NextRound:
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++ {
553 m[i] = true
555 for i := 20; i < 1000; i++ {
556 delete(m, i)
559 var first []int
560 for i := range m {
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++ {
567 idx := 0
568 for i := range m {
569 if i != first[idx] {
570 // iteration order changed.
571 continue NextRound
573 idx++
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.
583 m := map[string]int{
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)
591 buf[0] = '2'
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")
598 var x int
599 n := testing.AllocsPerRun(100, func() {
600 x += m[string(buf)]
602 if n != 0 {
603 t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n)
606 x = 0
607 n = testing.AllocsPerRun(100, func() {
608 y, ok := m[string(buf)]
609 if !ok {
610 panic("!ok")
612 x += y
614 if n != 0 {
615 t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n)
619 func TestMapLargeKeyNoPointer(t *testing.T) {
620 const (
621 I = 1000
622 N = 64
624 type T [N]int
625 m := make(map[T]int)
626 for i := 0; i < I; i++ {
627 var v T
628 for j := 0; j < N; j++ {
629 v[j] = i + j
631 m[v] = i
633 runtime.GC()
634 for i := 0; i < I; i++ {
635 var v T
636 for j := 0; j < N; j++ {
637 v[j] = i + j
639 if m[v] != i {
640 t.Fatalf("corrupted map: want %+v, got %+v", i, m[v])
645 func TestMapLargeValNoPointer(t *testing.T) {
646 const (
647 I = 1000
648 N = 64
650 type T [N]int
651 m := make(map[int]T)
652 for i := 0; i < I; i++ {
653 var v T
654 for j := 0; j < N; j++ {
655 v[j] = i + j
657 m[i] = v
659 runtime.GC()
660 for i := 0; i < I; i++ {
661 var v T
662 for j := 0; j < N; j++ {
663 v[j] = i + j
665 v1 := m[i]
666 for j := 0; j < N; j++ {
667 if v1[j] != v[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
689 {-(1 << 30), 1, 1},
690 {-1, 1, 1},
691 {0, 1, 1},
692 {1, 1, 1},
693 {8, 1, 1},
694 {9, 2, 2},
695 {13, 2, 2},
696 {14, 4, 4},
697 {26, 4, 4},
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
711 // turned on.
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++ {
716 localMap[i] = 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++ {
726 escapingMap[i] = 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
738 // turned on.
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++ {
743 localMap[i] = 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++ {
753 escapingMap[i] = 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
765 // turned on.
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++ {
770 localMap[i] = 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++ {
780 escapingMap[i] = 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
792 // turned on.
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++ {
797 localMap[i] = 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++ {
807 escapingMap[i] = 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) {
819 m := map[int]int{}
820 for i := 0; i < b.N; i++ {
821 for j := 0; j < n; j++ {
822 m[j] = 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.
827 for k := range m {
828 delete(m, k)
829 break
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() {
844 m := map[int]int{}
845 m[0] = 0
847 if n != 0 {
848 t.Fatalf("mapliteral: want 0 allocs, got %v", n)
850 n = testing.AllocsPerRun(1000, func() {
851 m := make(map[int]int)
852 m[0] = 0
854 if n != 0 {
855 t.Fatalf("no hint: want 0 allocs, got %v", n)
857 n = testing.AllocsPerRun(1000, func() {
858 m := make(map[int]int, 8)
859 m[0] = 0
861 if n != 0 {
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)
866 m[0] = 0
868 if n != 0 {
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)
890 b.ReportAllocs()
891 b.ResetTimer()
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)
900 b.ResetTimer()
901 for i := 0; i < b.N; i++ {
902 if len(a) == 0 {
903 b.StopTimer()
904 for j := i; j < i+n; j++ {
905 a[int32(j)] = j
907 b.StartTimer()
909 delete(a, int32(i))
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)
929 b.ReportAllocs()
930 b.ResetTimer()
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)
939 b.ResetTimer()
940 for i := 0; i < b.N; i++ {
941 if len(a) == 0 {
942 b.StopTimer()
943 for j := i; j < i+n; j++ {
944 a[int64(j)] = j
946 b.StartTimer()
948 delete(a, int64(i))
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)
957 b.ResetTimer()
958 a := make(map[string]int)
959 for i := 0; i < b.N; i++ {
960 a[k[i&(n-1)]] = 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)
969 b.ResetTimer()
970 a := make(map[string]string)
971 for i := 0; i < b.N; i++ {
972 key := k[i&(n-1)]
973 a[key] += key
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)
983 b.ReportAllocs()
984 b.ResetTimer()
985 for i := 0; i < b.N; i++ {
986 key := k[i&(n-1)]
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)
997 b.ResetTimer()
998 k := 0
999 for i := 0; i < b.N; i++ {
1000 if len(a) == 0 {
1001 b.StopTimer()
1002 for j := 0; j < n; j++ {
1003 a[i2s[j]] = j
1005 k = i
1006 b.StartTimer()
1008 delete(a, i2s[i-k])
1012 func benchmarkMapDeletePointer(b *testing.B, n int) {
1013 i2p := make([]*int, n)
1014 for i := 0; i < n; i++ {
1015 i2p[i] = new(int)
1017 a := make(map[*int]int, n)
1018 b.ResetTimer()
1019 k := 0
1020 for i := 0; i < b.N; i++ {
1021 if len(a) == 0 {
1022 b.StopTimer()
1023 for j := 0; j < n; j++ {
1024 a[i2p[j]] = j
1026 k = i
1027 b.StartTimer()
1029 delete(a, i2p[i-k])
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 {
1071 m[k] = i
1073 if len(m) != len(ks) {
1074 t.Errorf("want %d elements, got %d", len(ks), len(m))
1077 func() {
1078 for _, k := range ks {
1079 defer delete(m, k)
1082 if len(m) != 0 {
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) {
1091 const key1 = 12
1092 const key2 = 13
1094 m := make(map[int]int)
1095 m[key1] = 99
1096 delete(m, key1)
1097 m[key2]++
1098 if n2 := m[key2]; n2 != 1 {
1099 t.Errorf("incremented 0 to %d", n2)
1103 func TestIncrementAfterDeleteValueInt32(t *testing.T) {
1104 const key1 = 12
1105 const key2 = 13
1107 m := make(map[int]int32)
1108 m[key1] = 99
1109 delete(m, key1)
1110 m[key2]++
1111 if n2 := m[key2]; n2 != 1 {
1112 t.Errorf("incremented 0 to %d", n2)
1116 func TestIncrementAfterDeleteValueInt64(t *testing.T) {
1117 const key1 = 12
1118 const key2 = 13
1120 m := make(map[int]int64)
1121 m[key1] = 99
1122 delete(m, key1)
1123 m[key2]++
1124 if n2 := m[key2]; n2 != 1 {
1125 t.Errorf("incremented 0 to %d", n2)
1129 func TestIncrementAfterDeleteKeyStringValueInt(t *testing.T) {
1130 const key1 = ""
1131 const key2 = "x"
1133 m := make(map[string]int)
1134 m[key1] = 99
1135 delete(m, key1)
1136 m[key2] += 1
1137 if n2 := m[key2]; n2 != 1 {
1138 t.Errorf("incremented 0 to %d", n2)
1142 func TestIncrementAfterDeleteKeyValueString(t *testing.T) {
1143 const key1 = ""
1144 const key2 = "x"
1146 m := make(map[string]string)
1147 m[key1] = "99"
1148 delete(m, key1)
1149 m[key2] += "1"
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) {
1159 const key1 = ""
1160 const key2 = "x"
1162 m := make(map[string]int)
1163 m[key1] = 99
1164 for k := range m {
1165 delete(m, k)
1167 m[key2]++
1168 if n2 := m[key2]; n2 != 1 {
1169 t.Errorf("incremented 0 to %d", n2)
1173 func TestMapTombstones(t *testing.T) {
1174 m := map[int]int{}
1175 const N = 10000
1176 // Fill a map.
1177 for i := 0; i < N; i++ {
1178 m[i] = i
1180 runtime.MapTombstoneCheck(m)
1181 // Delete half of the entries.
1182 for i := 0; i < N; i += 2 {
1183 delete(m, i)
1185 runtime.MapTombstoneCheck(m)
1186 // Add new entries to fill in holes.
1187 for i := N; i < 3*N/2; i++ {
1188 m[i] = i
1190 runtime.MapTombstoneCheck(m)
1191 // Delete everything.
1192 for i := 0; i < 3*N/2; i++ {
1193 delete(m, i)
1195 runtime.MapTombstoneCheck(m)
1198 type canString int
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 {
1207 f32 float32
1208 f64 float64
1209 c64 complex64
1210 c128 complex128
1211 s string
1212 i0 any
1213 i1 interface {
1214 String() string
1216 a [4]string
1219 m := map[any]bool{}
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++ {
1223 m[i] = true
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")