aboutsummaryrefslogtreecommitdiff
path: root/test/typeparam/metrics.go
diff options
context:
space:
mode:
authorDan Scales <danscales@google.com>2021-03-14 13:46:23 -0700
committerDan Scales <danscales@google.com>2021-03-15 20:29:11 +0000
commit96aecdcb36ad5240a9858f7f7d77ace30f2deaaa (patch)
treecf3c49cf8575bfe24eb7fae5b66220f274e6ba95 /test/typeparam/metrics.go
parentc2360956389a30a27407fb857fd4916f20f8dc01 (diff)
downloadgo-96aecdcb36ad5240a9858f7f7d77ace30f2deaaa.tar.gz
go-96aecdcb36ad5240a9858f7f7d77ace30f2deaaa.zip
cmd/compile: fix case where func-valued field of a generic type is called
Added test example orderedmap.go (binary search tree) that requires this fix (calling function compare in _Map). Also added new tests slices.go and metrics.go that just work. Change-Id: Ifa5f42ab6eee9aa54c40f0eca19e00a87f8f608a Reviewed-on: https://go-review.googlesource.com/c/go/+/301829 Trust: Dan Scales <danscales@google.com> Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'test/typeparam/metrics.go')
-rw-r--r--test/typeparam/metrics.go196
1 files changed, 196 insertions, 0 deletions
diff --git a/test/typeparam/metrics.go b/test/typeparam/metrics.go
new file mode 100644
index 0000000000..8a39d9945d
--- /dev/null
+++ b/test/typeparam/metrics.go
@@ -0,0 +1,196 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package metrics provides tracking arbitrary metrics composed of
+// values of comparable types.
+package main
+
+import (
+ "fmt"
+ "sort"
+ "sync"
+)
+
+// _Metric1 tracks metrics of values of some type.
+type _Metric1[T comparable] struct {
+ mu sync.Mutex
+ m map[T]int
+}
+
+// Add adds another instance of some value.
+func (m *_Metric1[T]) Add(v T) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.m == nil {
+ m.m = make(map[T]int)
+ }
+ m.m[v]++
+}
+
+// Count returns the number of instances we've seen of v.
+func (m *_Metric1[T]) Count(v T) int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.m[v]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *_Metric1[T]) Metrics() []T {
+ return _Keys(m.m)
+}
+
+type key2[T1, T2 comparable] struct {
+ f1 T1
+ f2 T2
+}
+
+// _Metric2 tracks metrics of pairs of values.
+type _Metric2[T1, T2 comparable] struct {
+ mu sync.Mutex
+ m map[key2[T1, T2]]int
+}
+
+// Add adds another instance of some pair of values.
+func (m *_Metric2[T1, T2]) Add(v1 T1, v2 T2) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.m == nil {
+ m.m = make(map[key2[T1, T2]]int)
+ }
+ m.m[key2[T1, T2]{v1, v2}]++
+}
+
+// Count returns the number of instances we've seen of v1/v2.
+func (m *_Metric2[T1, T2]) Count(v1 T1, v2 T2) int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.m[key2[T1, T2]{v1, v2}]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *_Metric2[T1, T2]) Metrics() (r1 []T1, r2 []T2) {
+ for _, k := range _Keys(m.m) {
+ r1 = append(r1, k.f1)
+ r2 = append(r2, k.f2)
+ }
+ return r1, r2
+}
+
+type key3[T1, T2, T3 comparable] struct {
+ f1 T1
+ f2 T2
+ f3 T3
+}
+
+// _Metric3 tracks metrics of triplets of values.
+type _Metric3[T1, T2, T3 comparable] struct {
+ mu sync.Mutex
+ m map[key3[T1, T2, T3]]int
+}
+
+// Add adds another instance of some triplet of values.
+func (m *_Metric3[T1, T2, T3]) Add(v1 T1, v2 T2, v3 T3) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.m == nil {
+ m.m = make(map[key3[T1, T2, T3]]int)
+ }
+ m.m[key3[T1, T2, T3]{v1, v2, v3}]++
+}
+
+// Count returns the number of instances we've seen of v1/v2/v3.
+func (m *_Metric3[T1, T2, T3]) Count(v1 T1, v2 T2, v3 T3) int {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.m[key3[T1, T2, T3]{v1, v2, v3}]
+}
+
+// Metrics returns all the values we've seen, in an indeterminate order.
+func (m *_Metric3[T1, T2, T3]) Metrics() (r1 []T1, r2 []T2, r3 []T3) {
+ for k := range m.m {
+ r1 = append(r1, k.f1)
+ r2 = append(r2, k.f2)
+ r3 = append(r3, k.f3)
+ }
+ return r1, r2, r3
+}
+
+type S struct{ a, b, c string }
+
+func TestMetrics() {
+ m1 := _Metric1[string]{}
+ if got := m1.Count("a"); got != 0 {
+ panic(fmt.Sprintf("Count(%q) = %d, want 0", "a", got))
+ }
+ m1.Add("a")
+ m1.Add("a")
+ if got := m1.Count("a"); got != 2 {
+ panic(fmt.Sprintf("Count(%q) = %d, want 2", "a", got))
+ }
+ if got, want := m1.Metrics(), []string{"a"}; !_SlicesEqual(got, want) {
+ panic(fmt.Sprintf("Metrics = %v, want %v", got, want))
+ }
+
+ m2 := _Metric2[int, float64]{}
+ m2.Add(1, 1)
+ m2.Add(2, 2)
+ m2.Add(3, 3)
+ m2.Add(3, 3)
+ k1, k2 := m2.Metrics()
+
+ sort.Ints(k1)
+ w1 := []int{1, 2, 3}
+ if !_SlicesEqual(k1, w1) {
+ panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k1, w1))
+ }
+
+ sort.Float64s(k2)
+ w2 := []float64{1, 2, 3}
+ if !_SlicesEqual(k2, w2) {
+ panic(fmt.Sprintf("_Metric2.Metrics first slice = %v, want %v", k2, w2))
+ }
+
+ m3 := _Metric3[string, S, S]{}
+ m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+ m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+ m3.Add("a", S{"d", "e", "f"}, S{"g", "h", "i"})
+ m3.Add("b", S{"d", "e", "f"}, S{"g", "h", "i"})
+ if got := m3.Count("a", S{"d", "e", "f"}, S{"g", "h", "i"}); got != 3 {
+ panic(fmt.Sprintf("Count(%v, %v, %v) = %d, want 3", "a", S{"d", "e", "f"}, S{"g", "h", "i"}, got))
+ }
+}
+
+func main() {
+ TestMetrics()
+}
+
+// _Equal reports whether two slices are equal: the same length and all
+// elements equal. All floating point NaNs are considered equal.
+func _SlicesEqual[Elem comparable](s1, s2 []Elem) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i, v1 := range s1 {
+ v2 := s2[i]
+ if v1 != v2 {
+ isNaN := func(f Elem) bool { return f != f }
+ if !isNaN(v1) || !isNaN(v2) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// _Keys returns the keys of the map m.
+// The keys will be an indeterminate order.
+func _Keys[K comparable, V any](m map[K]V) []K {
+ r := make([]K, 0, len(m))
+ for k := range m {
+ r = append(r, k)
+ }
+ return r
+}