github.com/anacrolix/torrent@v1.61.0/internal/indexed/internal-table.go (about) 1 package indexed 2 3 import ( 4 "fmt" 5 "iter" 6 7 g "github.com/anacrolix/generics" 8 "github.com/anacrolix/missinggo/v2/panicif" 9 "github.com/anacrolix/torrent/internal/amortize" 10 ) 11 12 type table[R Record] struct { 13 minRecord g.Option[R] 14 set btreeSet[R] 15 // Tracks changes to the btree 16 version int 17 cmp CompareFunc[R] 18 indexes []genericRelation 19 indexTriggers []triggerFunc[R] 20 triggers []triggerFunc[R] 21 inited bool 22 } 23 24 func (me *table[R]) GetCmp() CompareFunc[R] { 25 return me.cmp 26 } 27 28 func (me *table[R]) SetMinRecord(min R) { 29 panicif.GreaterThan(me.cmp(min, me.minRecord.Value), 0) 30 me.minRecord.Set(min) 31 } 32 33 func (me *table[R]) Init(cmp func(a, b R) int) { 34 panicif.True(me.inited) 35 me.set = makeAjwernerSet(cmp) 36 me.cmp = cmp 37 me.inited = true 38 } 39 40 func (me *table[R]) runTriggers(old, new g.Option[R]) { 41 for _, t := range me.triggers { 42 t(old, new) 43 } 44 } 45 46 func (me *table[R]) OnChange(t triggerFunc[R]) { 47 me.triggers = append(me.triggers, t) 48 } 49 50 func (me *table[R]) incVersion() { 51 me.version++ 52 } 53 54 func (me *table[R]) assertIteratorVersion(it btreeIterator[R]) { 55 panicif.NotEq(me.version, it.version) 56 } 57 58 func (me *table[R]) IterFrom(start R) iter.Seq[R] { 59 if me.minRecord.Ok { 60 panicif.LessThan(me.cmp(start, me.minRecord.Value), 0) 61 } 62 return me.set.IterFrom(start) 63 } 64 65 func (me *table[R]) IterFromWhile(gte R, while func(R) bool) iter.Seq[R] { 66 return func(yield func(R) bool) { 67 for r := range me.IterFrom(gte) { 68 if !while(r) || !yield(r) { 69 return 70 } 71 } 72 } 73 } 74 75 func (me *table[R]) SelectFirstIf(gte R, filter func(r R) bool) (ret g.Option[R]) { 76 for r := range me.IterFromWhile(gte, filter) { 77 ret.Set(r) 78 break 79 } 80 return 81 } 82 83 func (me *table[R]) checkWhereGotFirst(first g.Option[R], where func(r R) bool) { 84 if !amortize.Try() { 85 return 86 } 87 var slowRet g.Option[R] 88 for r := range me.Iter { 89 if where(r) { 90 slowRet.Set(r) 91 break 92 } 93 } 94 if first.Ok != slowRet.Ok || first.Ok && me.cmp(first.Value, slowRet.Value) != 0 { 95 fmt.Printf("%#v\n", first.Value) 96 fmt.Printf("%#v\n", slowRet.Value) 97 panic("herp") 98 } 99 } 100 101 func (me *table[R]) SelectFirstWhere(gte R, where func(r R) bool) (ret g.Option[R]) { 102 for r := range me.IterFromWhile(gte, where) { 103 ret.Set(r) 104 break 105 } 106 checkWhereGotFirst(me, ret, where) 107 return 108 } 109 110 func (me *table[R]) Delete(r R) (removed bool) { 111 remK, removed := me.set.Delete(r) 112 me.Changed(g.OptionFromTuple(remK, removed), g.None[R]()) 113 return 114 } 115 116 func (me *table[R]) CreateOrReplace(r R) { 117 replaced, overwrote := me.set.Upsert(r) 118 me.Changed(g.OptionFromTuple(replaced, overwrote), g.Some(r)) 119 } 120 121 func (me *table[R]) Iter(yield func(R) bool) { 122 for r := range me.set.Iter { 123 if me.minRecord.Ok && amortize.Try() { 124 panicif.LessThan(me.cmp(r, me.minRecord.Value), 0) 125 } 126 if !yield(r) { 127 return 128 } 129 } 130 } 131 132 func (me *table[R]) Create(r R) (created bool) { 133 if me.set.Contains(r) { 134 return false 135 } 136 _, overwrote := me.set.Upsert(r) 137 panicif.True(overwrote) 138 me.Changed(g.None[R](), g.Some(r)) 139 return true 140 } 141 142 func (me *table[R]) Update(r R, updateFunc func(r R) R) (existed bool) { 143 existed = me.Contains(r) 144 if !existed { 145 return false 146 } 147 newRecord := updateFunc(r) 148 if newRecord == r { 149 return 150 } 151 replaced, overwrote := me.set.Upsert(newRecord) 152 panicif.False(overwrote) 153 panicif.NotZero(me.cmp(r, replaced)) 154 me.Changed(g.Some(r), g.Some(newRecord)) 155 return true 156 } 157 158 // Should this only return a single value ever? Should we check? 159 func (me *table[R]) Contains(r R) bool { 160 return me.set.Contains(r) 161 } 162 163 func (me *table[R]) Changed(old, new g.Option[R]) { 164 // You should not even be trying to change a table underneath iterators. We want to know about 165 // this even if nothing happens. 166 me.incVersion() 167 if !old.Ok && !new.Ok { 168 return 169 } 170 if old.Ok && new.Ok { 171 // I believe we have that Records are value-comparable. 172 if old.Value == new.Value { 173 return 174 } 175 } 176 for _, t := range me.indexTriggers { 177 t(old, new) 178 } 179 me.runTriggers(old, new) 180 } 181 182 // When you know the existing state and the destination state. Most efficient. 183 func (me *table[R]) Change(old, new g.Option[R]) { 184 if old.Ok { 185 if new.Ok { 186 // We can't guard deletion in case the compare function is partial, because we may be 187 // updating unordered fields. 188 _, deleted := me.set.Delete(old.Value) 189 panicif.False(deleted) 190 _, overwrote := me.set.Upsert(new.Value) 191 // What about deleting only if the upsert doesn't clobber here? 192 panicif.True(overwrote) 193 } else { 194 _, deleted := me.set.Delete(old.Value) 195 panicif.False(deleted) 196 } 197 } else { 198 if new.Ok { 199 _, overwrote := me.set.Upsert(new.Value) 200 panicif.True(overwrote) 201 } else { 202 return 203 } 204 } 205 me.Changed(old, new) 206 } 207 208 func (me *table[R]) GetFirst() (r R, ok bool) { 209 for r = range me.Iter { 210 ok = true 211 break 212 } 213 if amortize.Try() { 214 panicif.NotEq(g.OptionFromTuple(r, ok), me.GetGte(me.MinRecord())) 215 } 216 return 217 } 218 219 // Gets the first record greater than or equal. Hope to avoid allocation for iterator. 220 func (me *table[R]) GetGte(r R) (ret g.Option[R]) { 221 // Don't need version checking since we don't iterate. 222 for ret.Value = range me.IterFrom(r) { 223 ret.Ok = true 224 break 225 } 226 return 227 } 228 229 // Not count because that could imply more than O(1) work. 230 func (me *table[R]) Len() int { 231 return me.set.Len() 232 } 233 234 // Returns the minimal record of type R, which may not be the same as the zero value for the record. 235 // Convenient to avoid having to look up complex types for small expressions. Could be a global 236 // function. Should definitely be if this is invoked through an interface. Panics if the min record 237 // wasn't set. The concept of MinRecord might be flawed if there are conditions in the ordering of 238 // values in a record. In that case the user may have to modify "intermediate" fields in order to 239 // set a GTE record that's appropriate midway in the table. 240 func (me *table[R]) MinRecord() (_ R) { 241 return me.minRecord.Unwrap() 242 }