# Source file test/typeparam/metrics.go

```     1  // run
2
4  // Use of this source code is governed by a BSD-style
6
7  // Package metrics provides tracking arbitrary metrics composed of
8  // values of comparable types.
9  package main
10
11  import (
12  	"fmt"
13  	"sort"
14  	"sync"
15  )
16
17  // _Metric1 tracks metrics of values of some type.
18  type _Metric1[T comparable] struct {
19  	mu sync.Mutex
20  	m  map[T]int
21  }
22
24  func (m *_Metric1[T]) Add(v T) {
25  	m.mu.Lock()
26  	defer m.mu.Unlock()
27  	if m.m == nil {
28  		m.m = make(map[T]int)
29  	}
30  	m.m[v]++
31  }
32
33  // Count returns the number of instances we've seen of v.
34  func (m *_Metric1[T]) Count(v T) int {
35  	m.mu.Lock()
36  	defer m.mu.Unlock()
37  	return m.m[v]
38  }
39
40  // Metrics returns all the values we've seen, in an indeterminate order.
41  func (m *_Metric1[T]) Metrics() []T {
42  	return _Keys(m.m)
43  }
44
45  type key2[T1, T2 comparable] struct {
46  	f1 T1
47  	f2 T2
48  }
49
50  // _Metric2 tracks metrics of pairs of values.
51  type _Metric2[T1, T2 comparable] struct {
52  	mu sync.Mutex
53  	m  map[key2[T1, T2]]int
54  }
55
57  func (m *_Metric2[T1, T2]) Add(v1 T1, v2 T2) {
58  	m.mu.Lock()
59  	defer m.mu.Unlock()
60  	if m.m == nil {
61  		m.m = make(map[key2[T1, T2]]int)
62  	}
63  	m.m[key2[T1, T2]{v1, v2}]++
64  }
65
66  // Count returns the number of instances we've seen of v1/v2.
67  func (m *_Metric2[T1, T2]) Count(v1 T1, v2 T2) int {
68  	m.mu.Lock()
69  	defer m.mu.Unlock()
70  	return m.m[key2[T1, T2]{v1, v2}]
71  }
72
73  // Metrics returns all the values we've seen, in an indeterminate order.
74  func (m *_Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) {
75  	for _, k := range _Keys(m.m) {
76  		r1 = append(r1, k.f1)
77  		r2 = append(r2, k.f2)
78  	}
79  	return r1, r2
80  }
81
82  type key3[T1, T2, T3 comparable] struct {
83  	f1 T1
84  	f2 T2
85  	f3 T3
86  }
87
88  // _Metric3 tracks metrics of triplets of values.
89  type _Metric3[T1, T2, T3 comparable] struct {
90  	mu sync.Mutex
91  	m  map[key3[T1, T2, T3]]int
92  }
93
95  func (m *_Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
96  	m.mu.Lock()
97  	defer m.mu.Unlock()
98  	if m.m == nil {
99  		m.m = make(map[key3[T1, T2, T3]]int)
100  	}
101  	m.m[key3[T1, T2, T3]{v1, v2, v3}]++
102  }
103
104  // Count returns the number of instances we've seen of v1/v2/v3.
105  func (m *_Metric3[T1, T2, T3]) Count(v1 T1, v2 T2, v3 T3) int {
106  	m.mu.Lock()
107  	defer m.mu.Unlock()
108  	return m.m[key3[T1, T2, T3]{v1, v2, v3}]
109  }
110
111  // Metrics returns all the values we've seen, in an indeterminate order.
112  func (m *_Metric3[T1, T2, T3]) Metrics() (r1 []T1, r2 []T2, r3 []T3) {
113  	for k := range m.m {
114  		r1 = append(r1, k.f1)
115  		r2 = append(r2, k.f2)
116  		r3 = append(r3, k.f3)
117  	}
118  	return r1, r2, r3
119  }
120
121  type S struct{ a, b, c string }
122
123  func TestMetrics() {
124  	m1 := _Metric1[string]{}
125  	if got := m1.Count("a"); got != 0 {
126  		panic(fmt.Sprintf("Count(%q) = %d, want 0", "a", got))
127  	}
130  	if got := m1.Count("a"); got != 2 {
131  		panic(fmt.Sprintf("Count(%q) = %d, want 2", "a", got))
132  	}
133  	if got, want := m1.Metrics(), []string{"a"}; !_SlicesEqual(got, want) {
134  		panic(fmt.Sprintf("Metrics = %v, want %v", got, want))
135  	}
136
137  	m2 := _Metric2[int, float64]{}
142  	k1, k2 := m2.Metrics()
143
144  	sort.Ints(k1)
145  	w1 := []int{1, 2, 3}
146  	if !_SlicesEqual(k1, w1) {
147  		panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k1, w1))
148  	}
149
150  	sort.Float64s(k2)
151  	w2 := []float64{1, 2, 3}
152  	if !_SlicesEqual(k2, w2) {
153  		panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k2, w2))
154  	}
155
156  	m3 := _Metric3[string, S, S]{}
157  	m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
158  	m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
159  	m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
160  	m3.Add("b", S{"d", "e", "f"}, S{"g", "h", "i"})
161  	if got := m3.Count("a", S{"d", "e", "f"}, S{"g", "h", "i"}); got != 3 {
162  		panic(fmt.Sprintf("Count(%v, %v, %v) = %d, want 3", "a", S{"d", "e", "f"}, S{"g", "h", "i"}, got))
163  	}
164  }
165
166  func main() {
167  	TestMetrics()
168  }
169
170  // _Equal reports whether two slices are equal: the same length and all
171  // elements equal. All floating point NaNs are considered equal.
172  func _SlicesEqual[Elem comparable](s1, s2 []Elem) bool {
173  	if len(s1) != len(s2) {
174  		return false
175  	}
176  	for i, v1 := range s1 {
177  		v2 := s2[i]
178  		if v1 != v2 {
179  			isNaN := func(f Elem) bool { return f != f }
180  			if !isNaN(v1) || !isNaN(v2) {
181  				return false
182  			}
183  		}
184  	}
185  	return true
186  }
187
188  // _Keys returns the keys of the map m.
189  // The keys will be an indeterminate order.
190  func _Keys[K comparable, V any](m map[K]V) []K {
191  	r := make([]K, 0, len(m))
192  	for k := range m {
193  		r = append(r, k)
194  	}
195  	return r
196  }
197
```

View as plain text