1// run -gcflags=-G=3 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 7package main 8 9import ( 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. 17func _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. 35func _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. 45func _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 ==. 55func _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. 68func _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. 78func _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. 86func _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. 94func _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. 103func _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. 112func _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 118var m1 = map[int]int{1: 2, 2: 4, 4: 8, 8: 16} 119var m2 = map[int]string{1: "2", 2: "4", 4: "8", 8: "16"} 120 121func 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 137func 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 153func 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 177func 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 188func 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 201func 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 215func 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 228func 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 241func 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 250func main() { 251 TestKeys() 252 TestValues() 253 TestEqual() 254 TestCopy() 255 TestAdd() 256 TestSub() 257 TestIntersect() 258 TestFilter() 259 TestTransformValues() 260} 261