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