github.com/josephvusich/fdf@v0.0.0-20230522095411-9326dd32e33f/db.go (about) 1 package main 2 3 type queryGenerator func(r *fileRecord, q *query) 4 5 var queryGenerators [][]queryGenerator 6 7 func init() { 8 singles := []queryGenerator{ 9 0: func(r *fileRecord, q *query) { r.byName(q) }, 10 1: func(r *fileRecord, q *query) { r.byParent(q) }, 11 2: func(r *fileRecord, q *query) { r.byPathSuffix(q) }, 12 3: func(r *fileRecord, q *query) { r.bySize(q) }, 13 4: func(r *fileRecord, q *query) { r.byChecksum(q) }, 14 } 15 16 // Use binary decrement to generate all possible subsets based on bit position 17 // We need (2<<N)-1 bits 18 counter := 0 19 for b := (1 << len(singles)) - 1; b > 0; b-- { 20 counter++ 21 22 // queries will never include Checksum without Size 23 if (b>>4)&1 == 1 && (b>>3)&1 != 1 { 24 continue 25 } 26 27 // queries will never include PathSuffix without Parent 28 if (b>>2)&1 == 1 && (b>>1)&1 != 1 { 29 continue 30 } 31 32 var combo []queryGenerator 33 for i, x := range singles { 34 if (b>>i)&1 == 1 { 35 combo = append(combo, x) 36 } 37 } 38 queryGenerators = append(queryGenerators, combo) 39 } 40 } 41 42 type query struct { 43 Name string 44 Parent string 45 PathSuffix string 46 Size int64 47 Checksum checksum 48 } 49 50 func (r *fileRecord) byName(q *query) *query { 51 q.Name = r.FoldedName 52 return q 53 } 54 55 func (r *fileRecord) byParent(q *query) *query { 56 q.Parent = r.FoldedParent 57 return q 58 } 59 60 func (r *fileRecord) byPathSuffix(q *query) *query { 61 q = r.byParent(q) 62 q.PathSuffix = r.PathSuffix 63 return q 64 } 65 66 func (r *fileRecord) bySize(q *query) *query { 67 q.Size = r.Size() 68 return q 69 } 70 71 // If !HasChecksum, equivalent to bySize() 72 func (r *fileRecord) byChecksum(q *query) *query { 73 q = r.bySize(q) 74 if r.HasChecksum { 75 q.Checksum = r.Checksum 76 } 77 return q 78 } 79 80 type db struct { 81 m map[query]recordSet 82 } 83 84 func newDB() *db { 85 return &db{ 86 m: make(map[query]recordSet), 87 } 88 } 89 90 func (d *db) insert(r *fileRecord) { 91 var rs recordSet 92 var ok bool 93 94 for _, generatorSet := range queryGenerators { 95 var q query 96 for _, g := range generatorSet { 97 g(r, &q) 98 } 99 100 if rs, ok = d.m[q]; !ok { 101 rs = make(recordSet) 102 } 103 rs[r] = struct{}{} 104 d.m[q] = rs 105 } 106 } 107 108 func (d *db) remove(r *fileRecord) { 109 for _, generatorSet := range queryGenerators { 110 var q query 111 for _, g := range generatorSet { 112 g(r, &q) 113 } 114 115 if rs, ok := d.m[q]; ok { 116 delete(rs, r) 117 } 118 } 119 } 120 121 func (d *db) query(q *query) recordSet { 122 return d.m[*q] 123 }