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.
19 // negative zero is a good test because:
20 // 1) 0 and -0 are equal, yet have distinct representations.
21 // 2) 0 is represented as all zeros, -0 isn't.
22 // I'm not sure the language spec actually requires this behavior,
23 // but it's what the current map implementation does.
24 func TestNegativeZero(t
*testing
.T
) {
25 m
:= make(map[float64]bool, 0)
28 m
[math
.Copysign(0.0, -1.0)] = true // should overwrite +0 entry
31 t
.Error("length wrong")
35 if math
.Copysign(1.0, k
) > 0 {
40 m
= make(map[float64]bool, 0)
41 m
[math
.Copysign(0.0, -1.0)] = true
42 m
[+0.0] = true // should overwrite -0.0 entry
45 t
.Error("length wrong")
49 if math
.Copysign(1.0, k
) < 0 {
55 // nan is a good test because nan != nan, and nan has
56 // a randomized hash value.
57 func TestNan(t
*testing
.T
) {
58 m
:= make(map[float64]int, 0)
64 t
.Error("length wrong")
69 t
.Error("nan disappeared")
71 if (v
& (v
- 1)) != 0 {
72 t
.Error("value wrong")
77 t
.Error("values wrong")
81 // Maps aren't actually copied on assignment.
82 func TestAlias(t
*testing
.T
) {
83 m
:= make(map[int]int, 0)
88 t
.Error("alias didn't work")
92 func TestGrowWithNaN(t
*testing
.T
) {
93 m
:= make(map[float64]int, 4)
101 for k
, v
:= range m
{
103 // force a hashtable resize
104 for i
:= 0; i
< 100; i
++ {
115 t
.Error("NaN keys lost during grow")
118 t
.Error("NaN values lost during grow")
122 type FloatInt
struct {
127 func TestGrowWithNegativeZero(t
*testing
.T
) {
128 negzero
:= math
.Copysign(0.0, -1.0)
129 m
:= make(map[FloatInt
]int, 4)
130 m
[FloatInt
{0.0, 0}] = 1
131 m
[FloatInt
{0.0, 1}] = 2
132 m
[FloatInt
{0.0, 2}] = 4
133 m
[FloatInt
{0.0, 3}] = 8
138 // The first iteration should return the +0 key.
139 // The subsequent iterations should return the -0 key.
140 // I'm not really sure this is required by the spec,
141 // but it makes sense.
142 // TODO: are we allowed to get the first entry returned again???
143 for k
, v
:= range m
{
146 } // ignore entries added to grow table
148 if math
.Copysign(1.0, k
.x
) < 0 {
150 t
.Error("key/value not updated together 1")
156 t
.Error("key/value not updated together 2", k
, v
)
161 // force a hashtable resize
162 for i
:= 0; i
< 100; i
++ {
163 m
[FloatInt
{3.0, i
}] = 0
165 // then change all the entries
167 m
[FloatInt
{negzero
, 0}] = 1 |
16
168 m
[FloatInt
{negzero
, 1}] = 2 |
16
169 m
[FloatInt
{negzero
, 2}] = 4 |
16
170 m
[FloatInt
{negzero
, 3}] = 8 |
16
175 t
.Error("entry missing", s
)
178 t
.Error("wrong number of entries returned by iterator", cnt
)
181 t
.Error("update to negzero missed by iteration", negcnt
)
185 func TestIterGrowAndDelete(t
*testing
.T
) {
186 m
:= make(map[int]int, 4)
187 for i
:= 0; i
< 100; i
++ {
194 for i
:= 100; i
< 1000; i
++ {
197 // delete all odd keys
198 for i
:= 1; i
< 1000; i
+= 2 {
204 t
.Error("odd value returned")
210 // make sure old bucket arrays don't get GCd while
211 // an iterator is still using them.
212 func TestIterGrowWithGC(t
*testing
.T
) {
213 m
:= make(map[int]int, 4)
214 for i
:= 0; i
< 16; i
++ {
221 bitmask |
= 1 << uint(k
)
225 for i
:= 100; i
< 1000; i
++ {
233 if bitmask
!= 1<<16-1 {
234 t
.Error("missing key", bitmask
)
238 func testConcurrentReadsAfterGrowth(t
*testing
.T
, useReflect
bool) {
240 if runtime
.GOMAXPROCS(-1) == 1 {
241 if runtime
.GOARCH
== "s390" {
242 // Test uses too much address space on 31-bit S390.
243 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(8))
245 defer runtime
.GOMAXPROCS(runtime
.GOMAXPROCS(16))
252 numLoop
, numGrowStep
= 2, 100
254 for i
:= 0; i
< numLoop
; i
++ {
255 m
:= make(map[int]int, 0)
256 for gs
:= 0; gs
< numGrowStep
; gs
++ {
258 var wg sync
.WaitGroup
259 wg
.Add(numReader
* 2)
260 for nr
:= 0; nr
< numReader
; nr
++ {
268 for key
:= 0; key
< gs
; key
++ {
276 mv
:= reflect
.ValueOf(m
)
278 for _
, k
:= range keys
{
289 func TestConcurrentReadsAfterGrowth(t
*testing
.T
) {
290 testConcurrentReadsAfterGrowth(t
, false)
293 func TestConcurrentReadsAfterGrowthReflect(t
*testing
.T
) {
294 testConcurrentReadsAfterGrowth(t
, true)
297 func TestBigItems(t
*testing
.T
) {
299 for i
:= 0; i
< 256; i
++ {
302 m
:= make(map[[256]string][256]string, 4)
303 for i
:= 0; i
< 100; i
++ {
304 key
[37] = fmt
.Sprintf("string%02d", i
)
308 var values
[100]string
310 for k
, v
:= range m
{
315 sort
.Strings(keys
[:])
316 sort
.Strings(values
[:])
317 for i
:= 0; i
< 100; i
++ {
318 if keys
[i
] != fmt
.Sprintf("string%02d", i
) {
319 t
.Errorf("#%d: missing key: %v", i
, keys
[i
])
321 if values
[i
] != fmt
.Sprintf("string%02d", i
) {
322 t
.Errorf("#%d: missing value: %v", i
, values
[i
])
327 func TestMapHugeZero(t
*testing
.T
) {
332 t
.Errorf("map value not zero")
336 t
.Errorf("map value should be missing")
339 t
.Errorf("map value not zero")
346 func TestEmptyKeyAndValue(t
*testing
.T
) {
347 a
:= make(map[int]empty
, 4)
348 b
:= make(map[empty
]int, 4)
349 c
:= make(map[empty
]empty
, 4)
356 t
.Errorf("empty value insert problem")
359 t
.Errorf("empty key returned wrong value")
363 // Tests a map with a single bucket, with same-lengthed short keys
364 // ("quick keys") as well as long keys.
365 func TestSingleBucketMapStringKeys_DupLen(t
*testing
.T
) {
366 testMapLookups(t
, map[string]string{
370 "bar": "barval", // same key length as "foo"
372 strings
.Repeat("x", 128): "longval1",
373 strings
.Repeat("y", 128): "longval2",
377 // Tests a map with a single bucket, with all keys having different lengths.
378 func TestSingleBucketMapStringKeys_NoDupLen(t
*testing
.T
) {
379 testMapLookups(t
, map[string]string{
386 strings
.Repeat("x", 128): "longval",
390 func testMapLookups(t
*testing
.T
, m
map[string]string) {
391 for k
, v
:= range m
{
393 t
.Fatalf("m[%q] = %q; want %q", k
, m
[k
], v
)
398 // Tests whether the iterator returns the right elements when
399 // started in the middle of a grow, when the keys are NaNs.
400 func TestMapNanGrowIterator(t
*testing
.T
) {
401 m
:= make(map[float64]int)
404 // To fill nBuckets buckets takes LOAD * nBuckets keys.
405 nKeys
:= int(nBuckets
* *runtime
.HashLoad
)
407 // Get map to full point with nan keys.
408 for i
:= 0; i
< nKeys
; i
++ {
416 found
:= make(map[int]struct{})
417 for _
, v
:= range m
{
419 if _
, repeat
:= found
[v
]; repeat
{
420 t
.Fatalf("repeat of value %d", v
)
422 found
[v
] = struct{}{}
424 if len(found
) == nKeys
/2 {
425 // Halfway through iteration, finish grow.
426 for i
:= 0; i
< nBuckets
; i
++ {
431 if len(found
) != nKeys
{
432 t
.Fatalf("missing value")
436 func TestMapIterOrder(t
*testing
.T
) {
437 for _
, n
:= range [...]int{3, 7, 9, 15} {
438 for i
:= 0; i
< 1000; i
++ {
439 // Make m be {0: true, 1: true, ..., n-1: true}.
440 m
:= make(map[int]bool)
441 for i
:= 0; i
< n
; i
++ {
444 // Check that iterating over the map produces at least two different orderings.
445 ord
:= func() []int {
454 for try
:= 0; try
< 100; try
++ {
455 if !reflect
.DeepEqual(first
, ord()) {
461 t
.Errorf("Map with n=%d elements had consistent iteration order: %v", n
, first
)
469 func TestMapSparseIterOrder(t
*testing
.T
) {
470 // Run several rounds to increase the probability
471 // of failure. One is not enough.
473 for round
:= 0; round
< 10; round
++ {
474 m
:= make(map[int]bool)
475 // Add 1000 items, remove 980.
476 for i
:= 0; i
< 1000; i
++ {
479 for i
:= 20; i
< 1000; i
++ {
485 first
= append(first
, i
)
488 // 800 chances to get a different iteration order.
489 // See bug 8736 for why we need so many tries.
490 for n
:= 0; n
< 800; n
++ {
494 // iteration order changed.
500 t
.Fatalf("constant iteration order on round %d: %v", round
, first
)
504 func TestMapStringBytesLookup(t
*testing
.T
) {
505 // Use large string keys to avoid small-allocation coalescing,
506 // which can cause AllocsPerRun to report lower counts than it should.
508 "1000000000000000000000000000000000000000000000000": 1,
509 "2000000000000000000000000000000000000000000000000": 2,
511 buf
:= []byte("1000000000000000000000000000000000000000000000000")
512 if x
:= m
[string(buf
)]; x
!= 1 {
513 t
.Errorf(`m[string([]byte("1"))] = %d, want 1`, x
)
516 if x
:= m
[string(buf
)]; x
!= 2 {
517 t
.Errorf(`m[string([]byte("2"))] = %d, want 2`, x
)
520 t
.Skip("does not work on gccgo without better escape analysis")
523 n
:= testing
.AllocsPerRun(100, func() {
527 t
.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n
)
531 n
= testing
.AllocsPerRun(100, func() {
532 y
, ok
:= m
[string(buf
)]
539 t
.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n
)
543 func TestMapLargeKeyNoPointer(t
*testing
.T
) {
550 for i
:= 0; i
< I
; i
++ {
552 for j
:= 0; j
< N
; j
++ {
558 for i
:= 0; i
< I
; i
++ {
560 for j
:= 0; j
< N
; j
++ {
564 t
.Fatalf("corrupted map: want %+v, got %+v", i
, m
[v
])
569 func TestMapLargeValNoPointer(t
*testing
.T
) {
576 for i
:= 0; i
< I
; i
++ {
578 for j
:= 0; j
< N
; j
++ {
584 for i
:= 0; i
< I
; i
++ {
586 for j
:= 0; j
< N
; j
++ {
590 for j
:= 0; j
< N
; j
++ {
592 t
.Fatalf("corrupted map: want %+v, got %+v", v
, v1
)
598 // Test that making a map with a large or invalid hint
599 // doesn't panic. (Issue 19926).
600 func TestIgnoreBogusMapHint(t
*testing
.T
) {
601 for _
, hint
:= range []int64{-1, 1 << 62} {
602 _
= make(map[int]int, hint
)
606 var mapSink
map[int]int
608 var mapBucketTests
= [...]struct {
609 n
int // n is the number of map elements
610 noescape
int // number of expected buckets for non-escaping map
611 escape
int // number of expected buckets for escaping map
624 func TestMapBuckets(t
*testing
.T
) {
625 // Test that maps of different sizes have the right number of buckets.
626 // Non-escaping maps with small buckets (like map[int]int) never
627 // have a nil bucket pointer due to starting with preallocated buckets
628 // on the stack. Escaping maps start with a non-nil bucket pointer if
629 // hint size is above bucketCnt and thereby have more than one bucket.
630 // These tests depend on bucketCnt and loadFactor* in hashmap.go.
631 t
.Run("mapliteral", func(t
*testing
.T
) {
632 for _
, tt
:= range mapBucketTests
{
633 localMap
:= map[int]int{}
634 // Skip test on gccgo until escape analysis is
636 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
637 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
639 for i
:= 0; i
< tt
.n
; i
++ {
642 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
643 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
645 escapingMap
:= map[int]int{}
646 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
647 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
649 for i
:= 0; i
< tt
.n
; i
++ {
652 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
653 t
.Errorf("escape n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
655 mapSink
= escapingMap
658 t
.Run("nohint", func(t
*testing
.T
) {
659 for _
, tt
:= range mapBucketTests
{
660 localMap
:= make(map[int]int)
661 // Skip test on gccgo until escape analysis is
663 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
664 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
666 for i
:= 0; i
< tt
.n
; i
++ {
669 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
670 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
672 escapingMap
:= make(map[int]int)
673 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
674 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
676 for i
:= 0; i
< tt
.n
; i
++ {
679 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
680 t
.Errorf("escape: n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
682 mapSink
= escapingMap
685 t
.Run("makemap", func(t
*testing
.T
) {
686 for _
, tt
:= range mapBucketTests
{
687 localMap
:= make(map[int]int, tt
.n
)
688 // Skip test on gccgo until escape analysis is
690 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
691 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
693 for i
:= 0; i
< tt
.n
; i
++ {
696 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
697 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
699 escapingMap
:= make(map[int]int, tt
.n
)
700 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
701 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
703 for i
:= 0; i
< tt
.n
; i
++ {
706 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
707 t
.Errorf("escape: n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
709 mapSink
= escapingMap
712 t
.Run("makemap64", func(t
*testing
.T
) {
713 for _
, tt
:= range mapBucketTests
{
714 localMap
:= make(map[int]int, int64(tt
.n
))
715 // Skip test on gccgo until escape analysis is
717 if runtime
.MapBucketsPointerIsNil(localMap
) && runtime
.Compiler
!= "gccgo" {
718 t
.Errorf("no escape: buckets pointer is nil for non-escaping map")
720 for i
:= 0; i
< tt
.n
; i
++ {
723 if got
:= runtime
.MapBucketsCount(localMap
); got
!= tt
.noescape
{
724 t
.Errorf("no escape: n=%d want %d buckets, got %d", tt
.n
, tt
.noescape
, got
)
726 escapingMap
:= make(map[int]int, tt
.n
)
727 if count
:= runtime
.MapBucketsCount(escapingMap
); count
> 1 && runtime
.MapBucketsPointerIsNil(escapingMap
) {
728 t
.Errorf("escape: buckets pointer is nil for n=%d buckets", count
)
730 for i
:= 0; i
< tt
.n
; i
++ {
733 if got
:= runtime
.MapBucketsCount(escapingMap
); got
!= tt
.escape
{
734 t
.Errorf("escape: n=%d want %d buckets, got %d", tt
.n
, tt
.escape
, got
)
736 mapSink
= escapingMap
742 func benchmarkMapPop(b
*testing
.B
, n
int) {
744 for i
:= 0; i
< b
.N
; i
++ {
745 for j
:= 0; j
< n
; j
++ {
748 for j
:= 0; j
< n
; j
++ {
749 // Use iterator to pop an element.
750 // We want this to be fast, see issue 8412.
759 func BenchmarkMapPop100(b
*testing
.B
) { benchmarkMapPop(b
, 100) }
760 func BenchmarkMapPop1000(b
*testing
.B
) { benchmarkMapPop(b
, 1000) }
761 func BenchmarkMapPop10000(b
*testing
.B
) { benchmarkMapPop(b
, 10000) }
763 var testNonEscapingMapVariable
int = 8
765 func TestNonEscapingMap(t
*testing
.T
) {
766 t
.Skip("does not work on gccgo without better escape analysis")
767 n
:= testing
.AllocsPerRun(1000, func() {
772 t
.Fatalf("mapliteral: want 0 allocs, got %v", n
)
774 n
= testing
.AllocsPerRun(1000, func() {
775 m
:= make(map[int]int)
779 t
.Fatalf("no hint: want 0 allocs, got %v", n
)
781 n
= testing
.AllocsPerRun(1000, func() {
782 m
:= make(map[int]int, 8)
786 t
.Fatalf("with small hint: want 0 allocs, got %v", n
)
788 n
= testing
.AllocsPerRun(1000, func() {
789 m
:= make(map[int]int, testNonEscapingMapVariable
)
793 t
.Fatalf("with variable hint: want 0 allocs, got %v", n
)
798 func benchmarkMapAssignInt32(b
*testing
.B
, n
int) {
799 a
:= make(map[int32]int)
800 for i
:= 0; i
< b
.N
; i
++ {
801 a
[int32(i
&(n
-1))] = i
805 func benchmarkMapDeleteInt32(b
*testing
.B
, n
int) {
806 a
:= make(map[int32]int, n
)
808 for i
:= 0; i
< b
.N
; i
++ {
811 for j
:= i
; j
< i
+n
; j
++ {
820 func benchmarkMapAssignInt64(b
*testing
.B
, n
int) {
821 a
:= make(map[int64]int)
822 for i
:= 0; i
< b
.N
; i
++ {
823 a
[int64(i
&(n
-1))] = i
827 func benchmarkMapDeleteInt64(b
*testing
.B
, n
int) {
828 a
:= make(map[int64]int, n
)
830 for i
:= 0; i
< b
.N
; i
++ {
833 for j
:= i
; j
< i
+n
; j
++ {
842 func benchmarkMapAssignStr(b
*testing
.B
, n
int) {
843 k
:= make([]string, n
)
844 for i
:= 0; i
< len(k
); i
++ {
845 k
[i
] = strconv
.Itoa(i
)
848 a
:= make(map[string]int)
849 for i
:= 0; i
< b
.N
; i
++ {
854 func benchmarkMapDeleteStr(b
*testing
.B
, n
int) {
855 i2s
:= make([]string, n
)
856 for i
:= 0; i
< n
; i
++ {
857 i2s
[i
] = strconv
.Itoa(i
)
859 a
:= make(map[string]int, n
)
862 for i
:= 0; i
< b
.N
; i
++ {
865 for j
:= 0; j
< n
; j
++ {
875 func runWith(f
func(*testing
.B
, int), v
...int) func(*testing
.B
) {
876 return func(b
*testing
.B
) {
877 for _
, n
:= range v
{
878 b
.Run(strconv
.Itoa(n
), func(b
*testing
.B
) { f(b
, n
) })
883 func BenchmarkMapAssign(b
*testing
.B
) {
884 b
.Run("Int32", runWith(benchmarkMapAssignInt32
, 1<<8, 1<<16))
885 b
.Run("Int64", runWith(benchmarkMapAssignInt64
, 1<<8, 1<<16))
886 b
.Run("Str", runWith(benchmarkMapAssignStr
, 1<<8, 1<<16))
889 func BenchmarkMapDelete(b
*testing
.B
) {
890 b
.Run("Int32", runWith(benchmarkMapDeleteInt32
, 100, 1000, 10000))
891 b
.Run("Int64", runWith(benchmarkMapDeleteInt64
, 100, 1000, 10000))
892 b
.Run("Str", runWith(benchmarkMapDeleteStr
, 100, 1000, 10000))