/
NZ.go
244 lines (216 loc) · 4.6 KB
/
NZ.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
package rdx
import (
"fmt"
"github.com/drpcorg/chotki/protocol"
"strconv"
)
// N is an increment-only uint64 counter
// produce a text form (for REPL mostly)
func Nstring(tlv []byte) (txt string) {
return fmt.Sprintf("%d", Nnative(tlv))
}
func Ndefault() []byte { return []byte{} }
// parse a text form into a TLV value
func Nparse(txt string) (tlv []byte) {
u, err := strconv.ParseUint(txt, 10, 64)
if err != nil {
return nil
}
return Ntlv(u)
}
// convert a native golang value into TLV
func Ntlv(u uint64) (tlv []byte) {
time := ZipUint64Pair(u, 0)
return protocol.Record(Term, protocol.TinyRecord('T', time))
}
func Ntlvt(inc uint64, src uint64) []byte {
return protocol.Record(Term, protocol.TinyRecord('T', ZipUint64Pair(inc, src)))
}
// convert a TLV value to a native golang value
func Nnative(tlv []byte) (sum uint64) {
it := FIRSTIterator{TLV: tlv}
for it.Next() {
sum += it.revz
}
return
}
// merge TLV values
func Nmerge(tlvs [][]byte) (merged []byte) {
ih := ItHeap[*NIterator]{}
for _, tlv := range tlvs {
ih.Push(&NIterator{FIRSTIterator{TLV: tlv}})
}
for ih.Len() > 0 {
merged = append(merged, ih.Next()...)
}
return
}
func N2string(tlv []byte, new_val string, src uint64) (tlv_delta []byte) {
if len(new_val) == 0 {
return nil
}
it := NIterator{FIRSTIterator{TLV: tlv}}
mine := uint64(0)
for it.Next() {
if it.src == src {
mine = it.revz
break
}
}
add := false
if new_val[0] == '+' {
add = true
new_val = new_val[1:]
}
var num uint64
n, _ := fmt.Sscanf(new_val, "%d", &num)
if n < 1 {
return nil
}
if add {
mine += num
} else if num < mine {
return nil
} else if num == mine {
return nil
} else {
mine = num
}
return ZipUint64Pair(mine, 0)
}
// produce an op that turns the old value into the new one
// return nil on error, empty slice for "no changes"
func Ndelta(tlv []byte, new_val uint64, clock Clock) (tlv_delta []byte) {
it := FIRSTIterator{TLV: tlv}
max_revz := uint64(0)
mysrc := clock.Src()
old_val := uint64(0)
sum := uint64(0)
for it.Next() {
if it.revz > max_revz {
max_revz = it.revz
}
val := UnzipUint64(it.val)
if it.src == mysrc {
old_val = val
}
sum += val
}
if new_val < sum {
return nil
} else if new_val == sum {
return []byte{}
}
return Ntlv(new_val - sum + old_val)
}
// checks a TLV value for validity (format violations)
func Nvalid(tlv []byte) bool {
return true //todo
}
func Ndiff(tlv []byte, vvdiff VV) []byte {
return tlv //fixme
}
func Nmine(tlv []byte, src uint64) uint64 {
it := NIterator{FIRSTIterator{TLV: tlv}}
for it.Next() {
if it.src == src {
return it.revz
}
}
return 0
}
type NIterator struct {
FIRSTIterator
}
func (a *NIterator) Merge(b SortedIterator) int {
bb := b.(*NIterator)
if a.src == bb.src {
if a.revz < bb.revz {
return MergeB
} else {
return MergeA
}
} else if a.src < bb.src {
return MergeAB
} else {
return MergeBA
}
}
func (a *NIterator) Value() []byte {
return a.one
}
// Z is a two-way int64 counter
// produce a text form (for REPL mostly)
func Zstring(tlv []byte) (txt string) {
return fmt.Sprintf("%d", Znative(tlv))
}
// parse a text form into a TLV value
func Zparse(txt string) (tlv []byte) {
i, err := strconv.ParseInt(txt, 10, 64)
if err != nil {
return nil
}
return Ztlv(i)
}
// convert a native golang value into TLV
func Ztlv(i int64) (tlv []byte) {
return protocol.Record('I',
protocol.TinyRecord('T', ZipIntUint64Pair(0, 0)),
ZipInt64(i),
)
}
// convert a TLV value to a native golang value
func Znative(tlv []byte) (sum int64) {
rest := tlv
for len(rest) > 0 {
var one []byte
one, rest = protocol.Take('I', rest)
_, body := protocol.Take('T', one)
inc := UnzipInt64(body)
sum += inc
}
return
}
// merge TLV values
func Zmerge(tlvs [][]byte) (merged []byte) {
ih := ItHeap[*ZIterator]{}
for _, tlv := range tlvs {
ih.Push(&ZIterator{FIRSTIterator{TLV: tlv}})
}
for ih.Len() > 0 {
merged = append(merged, ih.Next()...)
}
return
}
// produce an op that turns the old value into the new one
func Zdelta(tlv []byte, new_val int64, clock Clock) (tlv_delta []byte) {
sum := Znative(tlv)
if new_val == sum {
return []byte{}
}
return Ztlv(new_val - sum)
}
// checks a TLV value for validity (format violations)
func Zvalid(tlv []byte) bool {
return true //todo
}
func Zdiff(tlv []byte, vvdiff VV) []byte {
return nil //fixme
}
type ZIterator struct {
FIRSTIterator
}
func (a *ZIterator) Merge(b SortedIterator) int {
bb := b.(*ZIterator)
if a.src == bb.src {
if a.revz < bb.revz {
return MergeB
} else {
return MergeA
}
} else if a.src < bb.src {
return MergeAB
} else {
return MergeBA
}
}