...
1 package lv
2
3 import "sync"
4
5
6 func NewSpace() *Space {
7 return &Space{}
8 }
9
10
11
12
13 type Space struct {
14 mtx sync.RWMutex
15 nodes map[string]*node
16 }
17
18
19
20 func (s *Space) Observe(name string, lvs LabelValues, value float64) {
21 s.nodeFor(name).observe(lvs, value)
22 }
23
24
25
26
27 func (s *Space) Add(name string, lvs LabelValues, delta float64) {
28 s.nodeFor(name).add(lvs, delta)
29 }
30
31
32
33 func (s *Space) Walk(fn func(name string, lvs LabelValues, observations []float64) bool) {
34 s.mtx.RLock()
35 defer s.mtx.RUnlock()
36 for name, node := range s.nodes {
37 f := func(lvs LabelValues, observations []float64) bool { return fn(name, lvs, observations) }
38 if !node.walk(LabelValues{}, f) {
39 return
40 }
41 }
42 }
43
44
45
46 func (s *Space) Reset() *Space {
47 s.mtx.Lock()
48 defer s.mtx.Unlock()
49 n := NewSpace()
50 n.nodes, s.nodes = s.nodes, n.nodes
51 return n
52 }
53
54 func (s *Space) nodeFor(name string) *node {
55 s.mtx.Lock()
56 defer s.mtx.Unlock()
57 if s.nodes == nil {
58 s.nodes = map[string]*node{}
59 }
60 n, ok := s.nodes[name]
61 if !ok {
62 n = &node{}
63 s.nodes[name] = n
64 }
65 return n
66 }
67
68
69
70
71 type node struct {
72 mtx sync.RWMutex
73 observations []float64
74 children map[pair]*node
75 }
76
77 type pair struct{ label, value string }
78
79 func (n *node) observe(lvs LabelValues, value float64) {
80 n.mtx.Lock()
81 defer n.mtx.Unlock()
82 if len(lvs) <= 0 {
83 n.observations = append(n.observations, value)
84 return
85 }
86 if len(lvs) < 2 {
87 panic("too few LabelValues; programmer error!")
88 }
89 head, tail := pair{lvs[0], lvs[1]}, lvs[2:]
90 if n.children == nil {
91 n.children = map[pair]*node{}
92 }
93 child, ok := n.children[head]
94 if !ok {
95 child = &node{}
96 n.children[head] = child
97 }
98 child.observe(tail, value)
99 }
100
101 func (n *node) add(lvs LabelValues, delta float64) {
102 n.mtx.Lock()
103 defer n.mtx.Unlock()
104 if len(lvs) <= 0 {
105 var value float64
106 if len(n.observations) > 0 {
107 value = last(n.observations) + delta
108 } else {
109 value = delta
110 }
111 n.observations = append(n.observations, value)
112 return
113 }
114 if len(lvs) < 2 {
115 panic("too few LabelValues; programmer error!")
116 }
117 head, tail := pair{lvs[0], lvs[1]}, lvs[2:]
118 if n.children == nil {
119 n.children = map[pair]*node{}
120 }
121 child, ok := n.children[head]
122 if !ok {
123 child = &node{}
124 n.children[head] = child
125 }
126 child.add(tail, delta)
127 }
128
129 func (n *node) walk(lvs LabelValues, fn func(LabelValues, []float64) bool) bool {
130 n.mtx.RLock()
131 defer n.mtx.RUnlock()
132 if len(n.observations) > 0 && !fn(lvs, n.observations) {
133 return false
134 }
135 for p, child := range n.children {
136 if !child.walk(append(lvs, p.label, p.value), fn) {
137 return false
138 }
139 }
140 return true
141 }
142
143 func last(a []float64) float64 {
144 return a[len(a)-1]
145 }
146
View as plain text