-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathslot_offsetter.go
53 lines (47 loc) · 1.76 KB
/
slot_offsetter.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
package sonic
import "github.com/talostrading/sonic/util"
// SlotOffsetter helps with offsetting a Slot's Index such that the bytes
// referred by the slot can be safely removed from a ByteBuffer's saved area.
//
// Why do we need to care about offsetting slots? Consider the following
// example, where [x, y] is a slot with Index x and Length n:
// - say we have the following slots, generated after calling
// ByteBuffer.Save(...): A:[0, 1] B:[1, 2] C:[3, 3] i.e. bytes: ABBCCC.
// - we ByteBuffer.Discard(B) and arrive at: ACCC
// - we want to ByteBuffer.Discard(C). However B was removed before C so [3, 3]
// now became [1, 3]. So C's index moved back by an offset of 2 bytes.
// - we offset C from [3, 3] to [1, 3] and then call ByteBuffer.Discard(C) which
// will give us A.
//
// SlotOffsetter does the offsetting for you. The worflow is as follows:
// - slot := ByteBuffer.Save(...)
// - slot = offsetter.Add(slot)
// - ...
// - ByteBuffer.Discard(Offset(slot))
type SlotOffsetter struct {
tree *util.FenwickTree
}
func NewSlotOffsetter(maxBytes int) *SlotOffsetter {
s := &SlotOffsetter{}
s.tree = util.NewFenwickTree(maxBytes)
return s
}
// Offset a previously Added slot such that it can be removed from the
// ByteBuffer's save area through ByteBuffer.Discard.
func (s *SlotOffsetter) Offset(slot Slot) Slot {
offset := s.tree.SumUntil(slot.Index)
s.tree.Add(slot.Index, slot.Length)
return OffsetSlot(offset, slot)
}
// Add a slot such that it can be Offset accordingly at a later time. Slots are
// generated by calling ByteBuffer.Save().
func (s *SlotOffsetter) Add(slot Slot) (Slot, error) {
slot.Index += s.tree.Sum()
if slot.Index >= s.tree.Size() {
return Slot{}, ErrNoSpaceLeftForSlot
}
return slot, nil
}
func (s *SlotOffsetter) Reset() {
s.tree.Reset()
}