-
Notifications
You must be signed in to change notification settings - Fork 11
/
buffer.go
95 lines (82 loc) · 1.99 KB
/
buffer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package quantiles
import (
"fmt"
"sort"
)
// byValue implements sort.Interface based on the value field.
type byValue []bufEntry
func (a byValue) Len() int { return len(a) }
func (a byValue) Less(i, j int) bool { return a[i].value < a[j].value }
func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
// bufEntry ...
type bufEntry struct {
value float64
weight float64
}
type buffer struct {
vec byValue
maxSize int64
curSize int64
}
func newBuffer(blockSize, maxElements int64) (*buffer, error) {
maxSize := blockSize << 1
if maxSize > maxElements {
maxSize = maxElements
}
if maxSize <= 0 {
return nil, fmt.Errorf("Invalid buffer specification: (%v, %v)", blockSize, maxElements)
}
return &buffer{
maxSize: maxSize,
curSize: 0,
vec: make([]bufEntry, maxSize),
}, nil
}
func (buf *buffer) clone() *buffer {
newBuffer := &buffer{
maxSize: buf.maxSize,
curSize: buf.curSize,
vec: make([]bufEntry, buf.maxSize),
}
for i, e := range buf.vec {
newBuffer.vec[i] = e
}
return newBuffer
}
func (buf *buffer) push(value, weight float64) error {
//QCHECK magic
if buf.isFull() {
return fmt.Errorf("Buffer already full: %v", buf.maxSize)
}
if weight > 0 {
buf.vec[buf.curSize] = bufEntry{value, weight}
buf.curSize++
}
return nil
}
// generateEntryList returns a sorted vector view of the base buffer and clears the buffer.
// Callers should minimize how often this is called, ideally only right after
// the buffer becomes full.
func (buf *buffer) generateEntryList() []bufEntry {
sort.Sort(buf.vec[:buf.curSize])
ret := buf.vec[:buf.curSize]
buf.vec = make([]bufEntry, buf.maxSize)
if buf.curSize == 0 {
return ret
}
buf.curSize = 0
numEntries := 0
for i := 1; i < len(ret); i++ {
if ret[i].value != ret[i-1].value {
numEntries++
ret[numEntries] = ret[i]
} else {
ret[numEntries].weight += ret[i].weight
}
}
return ret[:numEntries+1]
}
// isFull ...
func (buf *buffer) isFull() bool {
return buf.curSize >= buf.maxSize
}