github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/third_party/gofrontend/libgo/go/runtime/map_test.go (about)

     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.
     4  
     5  package runtime_test
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"reflect"
    11  	"runtime"
    12  	"sort"
    13  	"strings"
    14  	"sync"
    15  	"testing"
    16  )
    17  
    18  // negative zero is a good test because:
    19  //  1) 0 and -0 are equal, yet have distinct representations.
    20  //  2) 0 is represented as all zeros, -0 isn't.
    21  // I'm not sure the language spec actually requires this behavior,
    22  // but it's what the current map implementation does.
    23  func TestNegativeZero(t *testing.T) {
    24  	m := make(map[float64]bool, 0)
    25  
    26  	m[+0.0] = true
    27  	m[math.Copysign(0.0, -1.0)] = true // should overwrite +0 entry
    28  
    29  	if len(m) != 1 {
    30  		t.Error("length wrong")
    31  	}
    32  
    33  	/* gccgo fails this test; this is not required by the spec.
    34  	for k := range m {
    35  		if math.Copysign(1.0, k) > 0 {
    36  			t.Error("wrong sign")
    37  		}
    38  	}
    39  	*/
    40  
    41  	m = make(map[float64]bool, 0)
    42  	m[math.Copysign(0.0, -1.0)] = true
    43  	m[+0.0] = true // should overwrite -0.0 entry
    44  
    45  	if len(m) != 1 {
    46  		t.Error("length wrong")
    47  	}
    48  
    49  	/* gccgo fails this test; this is not required by the spec.
    50  	for k := range m {
    51  		if math.Copysign(1.0, k) < 0 {
    52  			t.Error("wrong sign")
    53  		}
    54  	}
    55  	*/
    56  }
    57  
    58  // nan is a good test because nan != nan, and nan has
    59  // a randomized hash value.
    60  func TestNan(t *testing.T) {
    61  	m := make(map[float64]int, 0)
    62  	nan := math.NaN()
    63  	m[nan] = 1
    64  	m[nan] = 2
    65  	m[nan] = 4
    66  	if len(m) != 3 {
    67  		t.Error("length wrong")
    68  	}
    69  	s := 0
    70  	for k, v := range m {
    71  		if k == k {
    72  			t.Error("nan disappeared")
    73  		}
    74  		if (v & (v - 1)) != 0 {
    75  			t.Error("value wrong")
    76  		}
    77  		s |= v
    78  	}
    79  	if s != 7 {
    80  		t.Error("values wrong")
    81  	}
    82  }
    83  
    84  // Maps aren't actually copied on assignment.
    85  func TestAlias(t *testing.T) {
    86  	m := make(map[int]int, 0)
    87  	m[0] = 5
    88  	n := m
    89  	n[0] = 6
    90  	if m[0] != 6 {
    91  		t.Error("alias didn't work")
    92  	}
    93  }
    94  
    95  func TestGrowWithNaN(t *testing.T) {
    96  	t.Skip("fails with gccgo")
    97  	m := make(map[float64]int, 4)
    98  	nan := math.NaN()
    99  	m[nan] = 1
   100  	m[nan] = 2
   101  	m[nan] = 4
   102  	cnt := 0
   103  	s := 0
   104  	growflag := true
   105  	for k, v := range m {
   106  		if growflag {
   107  			// force a hashtable resize
   108  			for i := 0; i < 100; i++ {
   109  				m[float64(i)] = i
   110  			}
   111  			growflag = false
   112  		}
   113  		if k != k {
   114  			cnt++
   115  			s |= v
   116  		}
   117  	}
   118  	t.Log("cnt:", cnt, "s:", s)
   119  	if cnt != 3 {
   120  		t.Error("NaN keys lost during grow")
   121  	}
   122  	if s != 7 {
   123  		t.Error("NaN values lost during grow")
   124  	}
   125  }
   126  
   127  type FloatInt struct {
   128  	x float64
   129  	y int
   130  }
   131  
   132  func TestGrowWithNegativeZero(t *testing.T) {
   133  	t.Skip("fails with gccgo")
   134  	negzero := math.Copysign(0.0, -1.0)
   135  	m := make(map[FloatInt]int, 4)
   136  	m[FloatInt{0.0, 0}] = 1
   137  	m[FloatInt{0.0, 1}] = 2
   138  	m[FloatInt{0.0, 2}] = 4
   139  	m[FloatInt{0.0, 3}] = 8
   140  	growflag := true
   141  	s := 0
   142  	cnt := 0
   143  	negcnt := 0
   144  	// The first iteration should return the +0 key.
   145  	// The subsequent iterations should return the -0 key.
   146  	// I'm not really sure this is required by the spec,
   147  	// but it makes sense.
   148  	// TODO: are we allowed to get the first entry returned again???
   149  	for k, v := range m {
   150  		if v == 0 {
   151  			continue
   152  		} // ignore entries added to grow table
   153  		cnt++
   154  		if math.Copysign(1.0, k.x) < 0 {
   155  			if v&16 == 0 {
   156  				t.Error("key/value not updated together 1")
   157  			}
   158  			negcnt++
   159  			s |= v & 15
   160  		} else {
   161  			if v&16 == 16 {
   162  				t.Error("key/value not updated together 2", k, v)
   163  			}
   164  			s |= v
   165  		}
   166  		if growflag {
   167  			// force a hashtable resize
   168  			for i := 0; i < 100; i++ {
   169  				m[FloatInt{3.0, i}] = 0
   170  			}
   171  			// then change all the entries
   172  			// to negative zero
   173  			m[FloatInt{negzero, 0}] = 1 | 16
   174  			m[FloatInt{negzero, 1}] = 2 | 16
   175  			m[FloatInt{negzero, 2}] = 4 | 16
   176  			m[FloatInt{negzero, 3}] = 8 | 16
   177  			growflag = false
   178  		}
   179  	}
   180  	if s != 15 {
   181  		t.Error("entry missing", s)
   182  	}
   183  	if cnt != 4 {
   184  		t.Error("wrong number of entries returned by iterator", cnt)
   185  	}
   186  	if negcnt != 3 {
   187  		t.Error("update to negzero missed by iteration", negcnt)
   188  	}
   189  }
   190  
   191  func TestIterGrowAndDelete(t *testing.T) {
   192  	m := make(map[int]int, 4)
   193  	for i := 0; i < 100; i++ {
   194  		m[i] = i
   195  	}
   196  	growflag := true
   197  	for k := range m {
   198  		if growflag {
   199  			// grow the table
   200  			for i := 100; i < 1000; i++ {
   201  				m[i] = i
   202  			}
   203  			// delete all odd keys
   204  			for i := 1; i < 1000; i += 2 {
   205  				delete(m, i)
   206  			}
   207  			growflag = false
   208  		} else {
   209  			if k&1 == 1 {
   210  				t.Error("odd value returned")
   211  			}
   212  		}
   213  	}
   214  }
   215  
   216  // make sure old bucket arrays don't get GCd while
   217  // an iterator is still using them.
   218  func TestIterGrowWithGC(t *testing.T) {
   219  	m := make(map[int]int, 4)
   220  	for i := 0; i < 16; i++ {
   221  		m[i] = i
   222  	}
   223  	growflag := true
   224  	bitmask := 0
   225  	for k := range m {
   226  		if k < 16 {
   227  			bitmask |= 1 << uint(k)
   228  		}
   229  		if growflag {
   230  			// grow the table
   231  			for i := 100; i < 1000; i++ {
   232  				m[i] = i
   233  			}
   234  			// trigger a gc
   235  			runtime.GC()
   236  			growflag = false
   237  		}
   238  	}
   239  	if bitmask != 1<<16-1 {
   240  		t.Error("missing key", bitmask)
   241  	}
   242  }
   243  
   244  func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
   245  	if runtime.GOMAXPROCS(-1) == 1 {
   246  		if runtime.GOARCH == "s390" {
   247  			// Test uses too much address space on 31-bit S390.
   248  			defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
   249  		} else {
   250  			defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
   251  		}
   252  	}
   253  	numLoop := 10
   254  	numGrowStep := 250
   255  	numReader := 16
   256  	if testing.Short() {
   257  		numLoop, numGrowStep = 2, 500
   258  	}
   259  	for i := 0; i < numLoop; i++ {
   260  		m := make(map[int]int, 0)
   261  		for gs := 0; gs < numGrowStep; gs++ {
   262  			m[gs] = gs
   263  			var wg sync.WaitGroup
   264  			wg.Add(numReader * 2)
   265  			for nr := 0; nr < numReader; nr++ {
   266  				go func() {
   267  					defer wg.Done()
   268  					for range m {
   269  					}
   270  				}()
   271  				go func() {
   272  					defer wg.Done()
   273  					for key := 0; key < gs; key++ {
   274  						_ = m[key]
   275  					}
   276  				}()
   277  				if useReflect {
   278  					wg.Add(1)
   279  					go func() {
   280  						defer wg.Done()
   281  						mv := reflect.ValueOf(m)
   282  						keys := mv.MapKeys()
   283  						for _, k := range keys {
   284  							mv.MapIndex(k)
   285  						}
   286  					}()
   287  				}
   288  			}
   289  			wg.Wait()
   290  		}
   291  	}
   292  }
   293  
   294  func TestConcurrentReadsAfterGrowth(t *testing.T) {
   295  	testConcurrentReadsAfterGrowth(t, false)
   296  }
   297  
   298  func TestConcurrentReadsAfterGrowthReflect(t *testing.T) {
   299  	testConcurrentReadsAfterGrowth(t, true)
   300  }
   301  
   302  func TestBigItems(t *testing.T) {
   303  	var key [256]string
   304  	for i := 0; i < 256; i++ {
   305  		key[i] = "foo"
   306  	}
   307  	m := make(map[[256]string][256]string, 4)
   308  	for i := 0; i < 100; i++ {
   309  		key[37] = fmt.Sprintf("string%02d", i)
   310  		m[key] = key
   311  	}
   312  	var keys [100]string
   313  	var values [100]string
   314  	i := 0
   315  	for k, v := range m {
   316  		keys[i] = k[37]
   317  		values[i] = v[37]
   318  		i++
   319  	}
   320  	sort.Strings(keys[:])
   321  	sort.Strings(values[:])
   322  	for i := 0; i < 100; i++ {
   323  		if keys[i] != fmt.Sprintf("string%02d", i) {
   324  			t.Errorf("#%d: missing key: %v", i, keys[i])
   325  		}
   326  		if values[i] != fmt.Sprintf("string%02d", i) {
   327  			t.Errorf("#%d: missing value: %v", i, values[i])
   328  		}
   329  	}
   330  }
   331  
   332  type empty struct {
   333  }
   334  
   335  func TestEmptyKeyAndValue(t *testing.T) {
   336  	a := make(map[int]empty, 4)
   337  	b := make(map[empty]int, 4)
   338  	c := make(map[empty]empty, 4)
   339  	a[0] = empty{}
   340  	b[empty{}] = 0
   341  	b[empty{}] = 1
   342  	c[empty{}] = empty{}
   343  
   344  	if len(a) != 1 {
   345  		t.Errorf("empty value insert problem")
   346  	}
   347  	if b[empty{}] != 1 {
   348  		t.Errorf("empty key returned wrong value")
   349  	}
   350  }
   351  
   352  // Tests a map with a single bucket, with same-lengthed short keys
   353  // ("quick keys") as well as long keys.
   354  func TestSingleBucketMapStringKeys_DupLen(t *testing.T) {
   355  	testMapLookups(t, map[string]string{
   356  		"x":    "x1val",
   357  		"xx":   "x2val",
   358  		"foo":  "fooval",
   359  		"bar":  "barval", // same key length as "foo"
   360  		"xxxx": "x4val",
   361  		strings.Repeat("x", 128): "longval1",
   362  		strings.Repeat("y", 128): "longval2",
   363  	})
   364  }
   365  
   366  // Tests a map with a single bucket, with all keys having different lengths.
   367  func TestSingleBucketMapStringKeys_NoDupLen(t *testing.T) {
   368  	testMapLookups(t, map[string]string{
   369  		"x":                      "x1val",
   370  		"xx":                     "x2val",
   371  		"foo":                    "fooval",
   372  		"xxxx":                   "x4val",
   373  		"xxxxx":                  "x5val",
   374  		"xxxxxx":                 "x6val",
   375  		strings.Repeat("x", 128): "longval",
   376  	})
   377  }
   378  
   379  func testMapLookups(t *testing.T, m map[string]string) {
   380  	for k, v := range m {
   381  		if m[k] != v {
   382  			t.Fatalf("m[%q] = %q; want %q", k, m[k], v)
   383  		}
   384  	}
   385  }
   386  
   387  // Tests whether the iterator returns the right elements when
   388  // started in the middle of a grow, when the keys are NaNs.
   389  func TestMapNanGrowIterator(t *testing.T) {
   390  	m := make(map[float64]int)
   391  	nan := math.NaN()
   392  	const nBuckets = 16
   393  	// To fill nBuckets buckets takes LOAD * nBuckets keys.
   394  	nKeys := int(nBuckets * /* *runtime.HashLoad */ 6.5)
   395  
   396  	// Get map to full point with nan keys.
   397  	for i := 0; i < nKeys; i++ {
   398  		m[nan] = i
   399  	}
   400  	// Trigger grow
   401  	m[1.0] = 1
   402  	delete(m, 1.0)
   403  
   404  	// Run iterator
   405  	found := make(map[int]struct{})
   406  	for _, v := range m {
   407  		if v != -1 {
   408  			if _, repeat := found[v]; repeat {
   409  				t.Fatalf("repeat of value %d", v)
   410  			}
   411  			found[v] = struct{}{}
   412  		}
   413  		if len(found) == nKeys/2 {
   414  			// Halfway through iteration, finish grow.
   415  			for i := 0; i < nBuckets; i++ {
   416  				delete(m, 1.0)
   417  			}
   418  		}
   419  	}
   420  	if len(found) != nKeys {
   421  		t.Fatalf("missing value")
   422  	}
   423  }
   424  
   425  func TestMapIterOrder(t *testing.T) {
   426  	if runtime.Compiler == "gccgo" {
   427  		t.Skip("skipping for gccgo")
   428  	}
   429  
   430  	for _, n := range [...]int{3, 7, 9, 15} {
   431  		for i := 0; i < 1000; i++ {
   432  			// Make m be {0: true, 1: true, ..., n-1: true}.
   433  			m := make(map[int]bool)
   434  			for i := 0; i < n; i++ {
   435  				m[i] = true
   436  			}
   437  			// Check that iterating over the map produces at least two different orderings.
   438  			ord := func() []int {
   439  				var s []int
   440  				for key := range m {
   441  					s = append(s, key)
   442  				}
   443  				return s
   444  			}
   445  			first := ord()
   446  			ok := false
   447  			for try := 0; try < 100; try++ {
   448  				if !reflect.DeepEqual(first, ord()) {
   449  					ok = true
   450  					break
   451  				}
   452  			}
   453  			if !ok {
   454  				t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
   455  				break
   456  			}
   457  		}
   458  	}
   459  }
   460  
   461  // Issue 8410
   462  func TestMapSparseIterOrder(t *testing.T) {
   463  	// Run several rounds to increase the probability
   464  	// of failure. One is not enough.
   465  	if runtime.Compiler == "gccgo" {
   466  		t.Skip("skipping for gccgo")
   467  	}
   468  NextRound:
   469  	for round := 0; round < 10; round++ {
   470  		m := make(map[int]bool)
   471  		// Add 1000 items, remove 980.
   472  		for i := 0; i < 1000; i++ {
   473  			m[i] = true
   474  		}
   475  		for i := 20; i < 1000; i++ {
   476  			delete(m, i)
   477  		}
   478  
   479  		var first []int
   480  		for i := range m {
   481  			first = append(first, i)
   482  		}
   483  
   484  		// 800 chances to get a different iteration order.
   485  		// See bug 8736 for why we need so many tries.
   486  		for n := 0; n < 800; n++ {
   487  			idx := 0
   488  			for i := range m {
   489  				if i != first[idx] {
   490  					// iteration order changed.
   491  					continue NextRound
   492  				}
   493  				idx++
   494  			}
   495  		}
   496  		t.Fatalf("constant iteration order on round %d: %v", round, first)
   497  	}
   498  }
   499  
   500  func TestMapStringBytesLookup(t *testing.T) {
   501  	if runtime.Compiler == "gccgo" {
   502  		t.Skip("skipping for gccgo")
   503  	}
   504  	// Use large string keys to avoid small-allocation coalescing,
   505  	// which can cause AllocsPerRun to report lower counts than it should.
   506  	m := map[string]int{
   507  		"1000000000000000000000000000000000000000000000000": 1,
   508  		"2000000000000000000000000000000000000000000000000": 2,
   509  	}
   510  	buf := []byte("1000000000000000000000000000000000000000000000000")
   511  	if x := m[string(buf)]; x != 1 {
   512  		t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x)
   513  	}
   514  	buf[0] = '2'
   515  	if x := m[string(buf)]; x != 2 {
   516  		t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x)
   517  	}
   518  
   519  	var x int
   520  	n := testing.AllocsPerRun(100, func() {
   521  		x += m[string(buf)]
   522  	})
   523  	if n != 0 {
   524  		t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n)
   525  	}
   526  
   527  	x = 0
   528  	n = testing.AllocsPerRun(100, func() {
   529  		y, ok := m[string(buf)]
   530  		if !ok {
   531  			panic("!ok")
   532  		}
   533  		x += y
   534  	})
   535  	if n != 0 {
   536  		t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n)
   537  	}
   538  }
   539  
   540  func TestMapLargeKeyNoPointer(t *testing.T) {
   541  	const (
   542  		I = 1000
   543  		N = 64
   544  	)
   545  	type T [N]int
   546  	m := make(map[T]int)
   547  	for i := 0; i < I; i++ {
   548  		var v T
   549  		for j := 0; j < N; j++ {
   550  			v[j] = i + j
   551  		}
   552  		m[v] = i
   553  	}
   554  	runtime.GC()
   555  	for i := 0; i < I; i++ {
   556  		var v T
   557  		for j := 0; j < N; j++ {
   558  			v[j] = i + j
   559  		}
   560  		if m[v] != i {
   561  			t.Fatalf("corrupted map: want %+v, got %+v", i, m[v])
   562  		}
   563  	}
   564  }
   565  
   566  func TestMapLargeValNoPointer(t *testing.T) {
   567  	const (
   568  		I = 1000
   569  		N = 64
   570  	)
   571  	type T [N]int
   572  	m := make(map[int]T)
   573  	for i := 0; i < I; i++ {
   574  		var v T
   575  		for j := 0; j < N; j++ {
   576  			v[j] = i + j
   577  		}
   578  		m[i] = v
   579  	}
   580  	runtime.GC()
   581  	for i := 0; i < I; i++ {
   582  		var v T
   583  		for j := 0; j < N; j++ {
   584  			v[j] = i + j
   585  		}
   586  		v1 := m[i]
   587  		for j := 0; j < N; j++ {
   588  			if v1[j] != v[j] {
   589  				t.Fatalf("corrupted map: want %+v, got %+v", v, v1)
   590  			}
   591  		}
   592  	}
   593  }
   594  
   595  func benchmarkMapPop(b *testing.B, n int) {
   596  	m := map[int]int{}
   597  	for i := 0; i < b.N; i++ {
   598  		for j := 0; j < n; j++ {
   599  			m[j] = j
   600  		}
   601  		for j := 0; j < n; j++ {
   602  			// Use iterator to pop an element.
   603  			// We want this to be fast, see issue 8412.
   604  			for k := range m {
   605  				delete(m, k)
   606  				break
   607  			}
   608  		}
   609  	}
   610  }
   611  
   612  func BenchmarkMapPop100(b *testing.B)   { benchmarkMapPop(b, 100) }
   613  func BenchmarkMapPop1000(b *testing.B)  { benchmarkMapPop(b, 1000) }
   614  func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) }
   615  
   616  func TestNonEscapingMap(t *testing.T) {
   617  	t.Skip("does not work on gccgo without better escape analysis")
   618  	n := testing.AllocsPerRun(1000, func() {
   619  		m := make(map[int]int)
   620  		m[0] = 0
   621  	})
   622  	if n != 0 {
   623  		t.Fatalf("want 0 allocs, got %v", n)
   624  	}
   625  }