1
2
3
4
5
6
7
8
9 package main
10
11 import (
12 "fmt"
13 "sort"
14 "sync"
15 )
16
17
18 type _Metric1[T comparable] struct {
19 mu sync.Mutex
20 m map[T]int
21 }
22
23
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
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
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
51 type _Metric2[T1, T2 comparable] struct {
52 mu sync.Mutex
53 m map[key2[T1, T2]]int
54 }
55
56
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
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
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
89 type _Metric3[T1, T2, T3 comparable] struct {
90 mu sync.Mutex
91 m map[key3[T1, T2, T3]]int
92 }
93
94
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
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
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 }
128 m1.Add("a")
129 m1.Add("a")
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]{}
138 m2.Add(1, 1)
139 m2.Add(2, 2)
140 m2.Add(3, 3)
141 m2.Add(3, 3)
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
171
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
189
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