]> Sergey Matveev's repositories - btrtrc.git/blob - segments/index.go
Improve segment handling for discontiguous extents
[btrtrc.git] / segments / index.go
1 package segments
2
3 import (
4         g "github.com/anacrolix/generics"
5         "sort"
6 )
7
8 func NewIndex(segments LengthIter) (ret Index) {
9         var start Length
10         for l, ok := segments(); ok; l, ok = segments() {
11                 ret.segments = append(ret.segments, Extent{start, l})
12                 start += l
13         }
14         return
15 }
16
17 type Index struct {
18         segments []Extent
19 }
20
21 func NewIndexFromSegments(segments []Extent) Index {
22         return Index{segments}
23 }
24
25 func (me Index) iterSegments() func() (Extent, bool) {
26         var lastEnd g.Option[Int]
27         return func() (ret Extent, ok bool) {
28                 if len(me.segments) == 0 {
29                         return
30                 }
31                 cur := me.segments[0]
32                 me.segments = me.segments[1:]
33                 ret.Start = cur.Start - lastEnd.UnwrapOr(cur.Start)
34                 ret.Length = cur.Length
35                 lastEnd.Set(cur.End())
36                 ok = true
37                 return
38         }
39 }
40
41 // Returns true if the callback returns false early, or extents are found in the index for all parts
42 // of the given extent.
43 func (me Index) Locate(e Extent, output Callback) bool {
44         first := sort.Search(len(me.segments), func(i int) bool {
45                 _e := me.segments[i]
46                 return _e.End() > e.Start
47         })
48         if first == len(me.segments) {
49                 return e.Length == 0
50         }
51         e.Start -= me.segments[first].Start
52         // The extent is before the first segment.
53         if e.Start < 0 {
54                 e.Length += e.Start
55                 e.Start = 0
56         }
57         me.segments = me.segments[first:]
58         return ScanConsecutive(me.iterSegments(), e, func(i int, e Extent) bool {
59                 return output(i+first, e)
60         })
61 }