-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdb.go
123 lines (102 loc) · 2.26 KB
/
db.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
package main
type queryGenerator func(r *fileRecord, q *query)
var queryGenerators [][]queryGenerator
func init() {
singles := []queryGenerator{
0: func(r *fileRecord, q *query) { r.byName(q) },
1: func(r *fileRecord, q *query) { r.byParent(q) },
2: func(r *fileRecord, q *query) { r.byPathSuffix(q) },
3: func(r *fileRecord, q *query) { r.bySize(q) },
4: func(r *fileRecord, q *query) { r.byChecksum(q) },
}
// Use binary decrement to generate all possible subsets based on bit position
// We need (2<<N)-1 bits
counter := 0
for b := (1 << len(singles)) - 1; b > 0; b-- {
counter++
// queries will never include Checksum without Size
if (b>>4)&1 == 1 && (b>>3)&1 != 1 {
continue
}
// queries will never include PathSuffix without Parent
if (b>>2)&1 == 1 && (b>>1)&1 != 1 {
continue
}
var combo []queryGenerator
for i, x := range singles {
if (b>>i)&1 == 1 {
combo = append(combo, x)
}
}
queryGenerators = append(queryGenerators, combo)
}
}
type query struct {
Name string
Parent string
PathSuffix string
Size int64
Checksum checksum
}
func (r *fileRecord) byName(q *query) *query {
q.Name = r.FoldedName
return q
}
func (r *fileRecord) byParent(q *query) *query {
q.Parent = r.FoldedParent
return q
}
func (r *fileRecord) byPathSuffix(q *query) *query {
q = r.byParent(q)
q.PathSuffix = r.PathSuffix
return q
}
func (r *fileRecord) bySize(q *query) *query {
q.Size = r.Size()
return q
}
// If !HasChecksum, equivalent to bySize()
func (r *fileRecord) byChecksum(q *query) *query {
q = r.bySize(q)
if r.HasChecksum {
q.Checksum = r.Checksum
}
return q
}
type db struct {
m map[query]recordSet
}
func newDB() *db {
return &db{
m: make(map[query]recordSet),
}
}
func (d *db) insert(r *fileRecord) {
var rs recordSet
var ok bool
for _, generatorSet := range queryGenerators {
var q query
for _, g := range generatorSet {
g(r, &q)
}
if rs, ok = d.m[q]; !ok {
rs = make(recordSet)
}
rs[r] = struct{}{}
d.m[q] = rs
}
}
func (d *db) remove(r *fileRecord) {
for _, generatorSet := range queryGenerators {
var q query
for _, g := range generatorSet {
g(r, &q)
}
if rs, ok := d.m[q]; ok {
delete(rs, r)
}
}
}
func (d *db) query(q *query) recordSet {
return d.m[*q]
}