index.go 1.4 KB

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