Source file test/typeparam/metrics.go

     1  // run
     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  
     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  
    23  // Add adds another instance of some value.
    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  
    56  // Add adds another instance of some pair of values.
    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  
    94  // Add adds another instance of some triplet of values.
    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  	}
   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  // _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