Source file test/typeparam/maps.go

     1  // run
     2  
     3  // Copyright 2021 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package main
     8  
     9  import (
    10  	"fmt"
    11  	"math"
    12  	"sort"
    13  )
    14  
    15  // _Equal reports whether two slices are equal: the same length and all
    16  // elements equal. All floating point NaNs are considered equal.
    17  func _SliceEqual[Elem comparable](s1, s2 []Elem) bool {
    18  	if len(s1) != len(s2) {
    19  		return false
    20  	}
    21  	for i, v1 := range s1 {
    22  		v2 := s2[i]
    23  		if v1 != v2 {
    24  			isNaN := func(f Elem) bool { return f != f }
    25  			if !isNaN(v1) || !isNaN(v2) {
    26  				return false
    27  			}
    28  		}
    29  	}
    30  	return true
    31  }
    32  
    33  // _Keys returns the keys of the map m.
    34  // The keys will be an indeterminate order.
    35  func _Keys[K comparable, V any](m map[K]V) []K {
    36  	r := make([]K, 0, len(m))
    37  	for k := range m {
    38  		r = append(r, k)
    39  	}
    40  	return r
    41  }
    42  
    43  // _Values returns the values of the map m.
    44  // The values will be in an indeterminate order.
    45  func _Values[K comparable, V any](m map[K]V) []V {
    46  	r := make([]V, 0, len(m))
    47  	for _, v := range m {
    48  		r = append(r, v)
    49  	}
    50  	return r
    51  }
    52  
    53  // _Equal reports whether two maps contain the same key/value pairs.
    54  // _Values are compared using ==.
    55  func _Equal[K, V comparable](m1, m2 map[K]V) bool {
    56  	if len(m1) != len(m2) {
    57  		return false
    58  	}
    59  	for k, v1 := range m1 {
    60  		if v2, ok := m2[k]; !ok || v1 != v2 {
    61  			return false
    62  		}
    63  	}
    64  	return true
    65  }
    66  
    67  // _Copy returns a copy of m.
    68  func _Copy[K comparable, V any](m map[K]V) map[K]V {
    69  	r := make(map[K]V, len(m))
    70  	for k, v := range m {
    71  		r[k] = v
    72  	}
    73  	return r
    74  }
    75  
    76  // _Add adds all key/value pairs in m2 to m1. _Keys in m2 that are already
    77  // present in m1 will be overwritten with the value in m2.
    78  func _Add[K comparable, V any](m1, m2 map[K]V) {
    79  	for k, v := range m2 {
    80  		m1[k] = v
    81  	}
    82  }
    83  
    84  // _Sub removes all keys in m2 from m1. _Keys in m2 that are not present
    85  // in m1 are ignored. The values in m2 are ignored.
    86  func _Sub[K comparable, V any](m1, m2 map[K]V) {
    87  	for k := range m2 {
    88  		delete(m1, k)
    89  	}
    90  }
    91  
    92  // _Intersect removes all keys from m1 that are not present in m2.
    93  // _Keys in m2 that are not in m1 are ignored. The values in m2 are ignored.
    94  func _Intersect[K comparable, V any](m1, m2 map[K]V) {
    95  	for k := range m1 {
    96  		if _, ok := m2[k]; !ok {
    97  			delete(m1, k)
    98  		}
    99  	}
   100  }
   101  
   102  // _Filter deletes any key/value pairs from m for which f returns false.
   103  func _Filter[K comparable, V any](m map[K]V, f func(K, V) bool) {
   104  	for k, v := range m {
   105  		if !f(k, v) {
   106  			delete(m, k)
   107  		}
   108  	}
   109  }
   110  
   111  // _TransformValues applies f to each value in m. The keys remain unchanged.
   112  func _TransformValues[K comparable, V any](m map[K]V, f func(V) V) {
   113  	for k, v := range m {
   114  		m[k] = f(v)
   115  	}
   116  }
   117  
   118  var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16}
   119  var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"}
   120  
   121  func TestKeys() {
   122  	want := []int{1, 2, 4, 8}
   123  
   124  	got1 := _Keys(m1)
   125  	sort.Ints(got1)
   126  	if !_SliceEqual(got1, want) {
   127  		panic(fmt.Sprintf("_Keys(%v) = %v, want %v", m1, got1, want))
   128  	}
   129  
   130  	got2 := _Keys(m2)
   131  	sort.Ints(got2)
   132  	if !_SliceEqual(got2, want) {
   133  		panic(fmt.Sprintf("_Keys(%v) = %v, want %v", m2, got2, want))
   134  	}
   135  }
   136  
   137  func TestValues() {
   138  	got1 := _Values(m1)
   139  	want1 := []int{2, 4, 8, 16}
   140  	sort.Ints(got1)
   141  	if !_SliceEqual(got1, want1) {
   142  		panic(fmt.Sprintf("_Values(%v) = %v, want %v", m1, got1, want1))
   143  	}
   144  
   145  	got2 := _Values(m2)
   146  	want2 := []string{"16", "2", "4", "8"}
   147  	sort.Strings(got2)
   148  	if !_SliceEqual(got2, want2) {
   149  		panic(fmt.Sprintf("_Values(%v) = %v, want %v", m2, got2, want2))
   150  	}
   151  }
   152  
   153  func TestEqual() {
   154  	if !_Equal(m1, m1) {
   155  		panic(fmt.Sprintf("_Equal(%v, %v) = false, want true", m1, m1))
   156  	}
   157  	if _Equal(m1, nil) {
   158  		panic(fmt.Sprintf("_Equal(%v, nil) = true, want false", m1))
   159  	}
   160  	if _Equal(nil, m1) {
   161  		panic(fmt.Sprintf("_Equal(nil, %v) = true, want false", m1))
   162  	}
   163  	if !_Equal[int, int](nil, nil) {
   164  		panic("_Equal(nil, nil) = false, want true")
   165  	}
   166  	if ms := map[int]int{1: 2}; _Equal(m1, ms) {
   167  		panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", m1, ms))
   168  	}
   169  
   170  	// Comparing NaN for equality is expected to fail.
   171  	mf := map[int]float64{1: 0, 2: math.NaN()}
   172  	if _Equal(mf, mf) {
   173  		panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", mf, mf))
   174  	}
   175  }
   176  
   177  func TestCopy() {
   178  	m2 := _Copy(m1)
   179  	if !_Equal(m1, m2) {
   180  		panic(fmt.Sprintf("_Copy(%v) = %v, want %v", m1, m2, m1))
   181  	}
   182  	m2[16] = 32
   183  	if _Equal(m1, m2) {
   184  		panic(fmt.Sprintf("_Equal(%v, %v) = true, want false", m1, m2))
   185  	}
   186  }
   187  
   188  func TestAdd() {
   189  	mc := _Copy(m1)
   190  	_Add(mc, mc)
   191  	if !_Equal(mc, m1) {
   192  		panic(fmt.Sprintf("_Add(%v, %v) = %v, want %v", m1, m1, mc, m1))
   193  	}
   194  	_Add(mc, map[int]int{16: 32})
   195  	want := map[int]int{1: 2, 2: 4, 4: 8, 8: 16, 16: 32}
   196  	if !_Equal(mc, want) {
   197  		panic(fmt.Sprintf("_Add result = %v, want %v", mc, want))
   198  	}
   199  }
   200  
   201  func TestSub() {
   202  	mc := _Copy(m1)
   203  	_Sub(mc, mc)
   204  	if len(mc) > 0 {
   205  		panic(fmt.Sprintf("_Sub(%v, %v) = %v, want empty map", m1, m1, mc))
   206  	}
   207  	mc = _Copy(m1)
   208  	_Sub(mc, map[int]int{1: 0})
   209  	want := map[int]int{2: 4, 4: 8, 8: 16}
   210  	if !_Equal(mc, want) {
   211  		panic(fmt.Sprintf("_Sub result = %v, want %v", mc, want))
   212  	}
   213  }
   214  
   215  func TestIntersect() {
   216  	mc := _Copy(m1)
   217  	_Intersect(mc, mc)
   218  	if !_Equal(mc, m1) {
   219  		panic(fmt.Sprintf("_Intersect(%v, %v) = %v, want %v", m1, m1, mc, m1))
   220  	}
   221  	_Intersect(mc, map[int]int{1: 0, 2: 0})
   222  	want := map[int]int{1: 2, 2: 4}
   223  	if !_Equal(mc, want) {
   224  		panic(fmt.Sprintf("_Intersect result = %v, want %v", mc, want))
   225  	}
   226  }
   227  
   228  func TestFilter() {
   229  	mc := _Copy(m1)
   230  	_Filter(mc, func(int, int) bool { return true })
   231  	if !_Equal(mc, m1) {
   232  		panic(fmt.Sprintf("_Filter(%v, true) = %v, want %v", m1, mc, m1))
   233  	}
   234  	_Filter(mc, func(k, v int) bool { return k < 3 })
   235  	want := map[int]int{1: 2, 2: 4}
   236  	if !_Equal(mc, want) {
   237  		panic(fmt.Sprintf("_Filter result = %v, want %v", mc, want))
   238  	}
   239  }
   240  
   241  func TestTransformValues() {
   242  	mc := _Copy(m1)
   243  	_TransformValues(mc, func(i int) int { return i / 2 })
   244  	want := map[int]int{1: 1, 2: 2, 4: 4, 8: 8}
   245  	if !_Equal(mc, want) {
   246  		panic(fmt.Sprintf("_TransformValues result = %v, want %v", mc, want))
   247  	}
   248  }
   249  
   250  func main() {
   251  	TestKeys()
   252  	TestValues()
   253  	TestEqual()
   254  	TestCopy()
   255  	TestAdd()
   256  	TestSub()
   257  	TestIntersect()
   258  	TestFilter()
   259  	TestTransformValues()
   260  }
   261  

View as plain text