forked from couchbaselabs/gojsonsm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbintree.go
401 lines (341 loc) · 9.51 KB
/
bintree.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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
// Copyright 2018 Couchbase, Inc. All rights reserved.
package gojsonsm
import (
"errors"
"fmt"
"strings"
)
type BinTreeNodeType int
const (
nodeTypeLeaf BinTreeNodeType = iota
nodeTypeOr
nodeTypeAnd
nodeTypeNot
nodeTypeNeor
nodeTypeLoop
)
func binTreeNodeTypeToString(nodeType BinTreeNodeType) string {
switch nodeType {
case nodeTypeLeaf:
return "leaf"
case nodeTypeOr:
return "or"
case nodeTypeAnd:
return "and"
case nodeTypeNot:
return "not"
case nodeTypeNeor:
return "neor"
case nodeTypeLoop:
return "loop"
}
return "??ERROR??"
}
func binTreeNodeTypeHasLeft(nodeType BinTreeNodeType) bool {
return nodeType != nodeTypeLeaf
}
func binTreeNodeTypeHasRight(nodeType BinTreeNodeType) bool {
return nodeType != nodeTypeLeaf && nodeType != nodeTypeNot && nodeType != nodeTypeLoop
}
type binTreePointers struct {
ParentIdx int
Left int
Right int
}
type binTreeNode struct {
binTreePointers
NodeType BinTreeNodeType
}
func NewBinTreeNode(nodeType BinTreeNodeType, parent, left, right int) *binTreeNode {
node := &binTreeNode{
NodeType: nodeType,
}
node.ParentIdx = parent
node.Left = left
node.Right = right
return node
}
type binParserTreeNode struct {
binTreePointers
tokenType ParseTokenType
}
type binParserTree struct {
data []binParserTreeNode
}
type binTree struct {
data []binTreeNode
}
func (tree binTree) itemToString(item int) string {
var out string
idata := tree.data[item]
out += fmt.Sprintf("[%d:%d] %s\n", item, idata.ParentIdx, binTreeNodeTypeToString(idata.NodeType))
if idata.Left != 0 {
out += reindentString(tree.itemToString(idata.Left), " ") + "\n"
}
if idata.Right != 0 {
out += reindentString(tree.itemToString(idata.Right), " ") + "\n"
}
return strings.TrimRight(out, "\n")
}
func (tree binTree) String() string {
return tree.itemToString(0)
}
type binTreeStateValue int
const (
binTreeStateUnknown binTreeStateValue = iota
binTreeStateResolved
binTreeStateTrue
binTreeStateFalse
)
type binTreeState struct {
tree *binTree
data []binTreeStateValue
stallIndex int
}
func (state binTreeState) itemToString(item int) string {
var out string
idata := state.tree.data[item]
istate := state.data[item]
switch istate {
case binTreeStateUnknown:
out += fmt.Sprintf("[%d] %s\n", item, binTreeNodeTypeToString(idata.NodeType))
case binTreeStateResolved:
out += fmt.Sprintf("[%d] %s = undefined\n", item, binTreeNodeTypeToString(idata.NodeType))
case binTreeStateTrue:
out += fmt.Sprintf("[%d] %s = true\n", item, binTreeNodeTypeToString(idata.NodeType))
case binTreeStateFalse:
out += fmt.Sprintf("[%d] %s = false\n", item, binTreeNodeTypeToString(idata.NodeType))
}
if idata.Left != 0 {
out += reindentString(state.itemToString(idata.Left), " ") + "\n"
}
if idata.Right != 0 {
out += reindentString(state.itemToString(idata.Right), " ") + "\n"
}
return strings.TrimRight(out, "\n")
}
func (state binTreeState) String() string {
return state.itemToString(0)
}
func (tree *binTree) NewState() *binTreeState {
return &binTreeState{
tree: tree,
data: make([]binTreeStateValue, len(tree.data)),
}
}
func (tree *binTree) validateItem(item int, parent int) (int, error) {
idata := tree.data[item]
if idata.ParentIdx != parent {
return -1, errors.New("parent index doesnt match child")
}
switch idata.NodeType {
case nodeTypeLeaf:
// Leafs should not have any children
return item + 1, nil
case nodeTypeAnd:
case nodeTypeOr:
case nodeTypeNot:
case nodeTypeNeor:
case nodeTypeLoop:
default:
// Invalid node type
return -1, errors.New("unexpected node type")
}
if !binTreeNodeTypeHasLeft(idata.NodeType) {
// Left must not be set
if idata.Left != 0 {
return -1, errors.New("expected left to be undefined")
}
} else {
// Left must be set, and be inside the tree
if idata.Left <= 0 || idata.Left >= len(tree.data) {
return -1, errors.New("expected left to be defined, and inside the tree")
}
}
if !binTreeNodeTypeHasRight(idata.NodeType) {
// Right must not be set
if idata.Right != 0 {
return -1, errors.New("expected right to be undefined")
}
} else {
// Right must be set, and be inside the tree
if idata.Right <= 0 || idata.Right >= len(tree.data) {
return -1, errors.New("expected right to be defined, and inside the tree")
}
}
// Check the children
var err error
pos := item + 1
if binTreeNodeTypeHasLeft(idata.NodeType) {
pos, err = tree.validateItem(pos, item)
if err != nil {
return -1, err
}
}
if binTreeNodeTypeHasRight(idata.NodeType) {
pos, err = tree.validateItem(pos, item)
if err != nil {
return -1, err
}
}
return pos, nil
}
func (tree *binTree) NumNodes() int {
return len(tree.data)
}
func (tree *binTree) Validate() error {
pos, err := tree.validateItem(0, 0)
if err != nil {
return err
}
if pos != len(tree.data) {
return errors.New("tree does not encompase all nodes")
}
return nil
}
func (tree *binParserTree) NumNodes() int {
return len(tree.data)
}
func (state *binTreeState) CopyFrom(ostate *binTreeState) {
if state.tree != ostate.tree {
panic("cannot copy from different tree")
}
for i, item := range ostate.data {
state.data[i] = item
}
}
func (state *binTreeState) SetStallIndex(index int) int {
oldStallIndex := state.stallIndex
state.stallIndex = index
return oldStallIndex
}
// Resolve forces the tree to be fully resolved (including cases such as NOT)
// by doing a depth-first resolution of all unresolved nodes with `false`.
func (state *binTreeState) Resolve() {
// Skip resolving if the full tree is already resolved
if state.IsResolved(0) {
return
}
// Do depth-first resolution of the entire tree state
treeLength := len(state.data)
for i := treeLength - 1; i >= 0; i-- {
// If this bucket is not resolved, resolve it with false
if state.data[i] == binTreeStateUnknown {
state.MarkNode(i, false)
}
// Leave as soon as the root has been resolved
if state.data[0] != binTreeStateUnknown {
break
}
}
}
func (state *binTreeState) Reset() {
state.stallIndex = 0
for i := range state.data {
state.data[i] = binTreeStateUnknown
}
}
func (state *binTreeState) resetNodeRecursive(index int) {
// TODO(brett19): This is technically quite slow. It would be ideal if
// the binary tree itself marked the end of each node so we could do a
// quick loop through all the entries at once.
state.data[index] = binTreeStateUnknown
defNode := state.tree.data[index]
if binTreeNodeTypeHasLeft(defNode.NodeType) {
state.resetNodeRecursive(defNode.Left)
}
if binTreeNodeTypeHasRight(defNode.NodeType) {
state.resetNodeRecursive(defNode.Right)
}
}
func (state *binTreeState) ResetNode(index int) {
state.resetNodeRecursive(index)
}
func (state *binTreeState) resolveRecursive(index int) {
defNode := state.tree.data[index]
if binTreeNodeTypeHasLeft(defNode.NodeType) {
if state.data[defNode.Left] == binTreeStateUnknown {
state.data[defNode.Left] = binTreeStateResolved
state.resolveRecursive(defNode.Left)
}
}
if binTreeNodeTypeHasRight(defNode.NodeType) {
if state.data[defNode.Right] == binTreeStateUnknown {
state.data[defNode.Right] = binTreeStateResolved
state.resolveRecursive(defNode.Right)
}
}
}
func (state *binTreeState) checkNode(index int) {
defNode := state.tree.data[index]
if defNode.NodeType == nodeTypeLeaf {
panic("cannot check leaf")
}
if defNode.NodeType == nodeTypeOr {
if state.data[defNode.Left] == binTreeStateTrue || state.data[defNode.Right] == binTreeStateTrue {
state.MarkNode(index, true)
} else if state.data[defNode.Left] == binTreeStateFalse && state.data[defNode.Right] == binTreeStateFalse {
state.MarkNode(index, false)
}
return
} else if defNode.NodeType == nodeTypeNeor {
if state.data[defNode.Left] != binTreeStateUnknown && state.data[defNode.Right] != binTreeStateUnknown {
if state.data[defNode.Left] == binTreeStateTrue || state.data[defNode.Right] == binTreeStateTrue {
state.MarkNode(index, true)
} else {
state.MarkNode(index, false)
}
}
return
} else if defNode.NodeType == nodeTypeAnd {
if state.data[defNode.Left] == binTreeStateTrue && state.data[defNode.Right] == binTreeStateTrue {
state.MarkNode(index, true)
} else if state.data[defNode.Left] == binTreeStateFalse || state.data[defNode.Right] == binTreeStateFalse {
state.MarkNode(index, false)
}
return
} else if defNode.NodeType == nodeTypeNot {
if state.data[defNode.Left] == binTreeStateTrue {
state.MarkNode(index, false)
} else if state.data[defNode.Left] == binTreeStateFalse {
state.MarkNode(index, true)
}
return
} else if defNode.NodeType == nodeTypeLoop {
if state.data[defNode.Left] == binTreeStateTrue {
state.MarkNode(index, true)
} else if state.data[defNode.Left] == binTreeStateFalse {
state.MarkNode(index, false)
}
return
}
panic("invalid node mode")
}
func (state *binTreeState) MarkNode(index int, value bool) {
if state.data[index] != binTreeStateUnknown {
panic("cannot resolve same state node twice")
}
if value {
state.data[index] = binTreeStateTrue
} else {
state.data[index] = binTreeStateFalse
}
state.resolveRecursive(index)
// We are done if we are the root node
if index == 0 {
return
}
// If we are the marked stall index, we should stop recursing.
if index == state.stallIndex {
return
}
// Check for parent satisfaction
defNode := state.tree.data[index]
state.checkNode(defNode.ParentIdx)
}
func (state *binTreeState) IsResolved(index int) bool {
return state.data[index] != binTreeStateUnknown
}
func (state *binTreeState) IsTrue(index int) bool {
return state.data[index] == binTreeStateTrue
}