segments.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package segments
  2. type Int = int64
  3. type Length = Int
  4. type Extent struct {
  5. Start, Length Int
  6. }
  7. func (e Extent) End() Int {
  8. return e.Start + e.Length
  9. }
  10. type (
  11. Callback = func(segmentIndex int, segmentBounds Extent) bool
  12. LengthIter = func() (Length, bool)
  13. ConsecutiveExtentIter = func() (Extent, bool)
  14. )
  15. // Returns true if callback returns false early, or all segments in the haystack for the needle are
  16. // found.
  17. func Scan(haystack LengthIter, needle Extent, callback Callback) bool {
  18. return ScanConsecutive(
  19. func() (Extent, bool) {
  20. l, ok := haystack()
  21. return Extent{0, l}, ok
  22. },
  23. needle,
  24. callback,
  25. )
  26. }
  27. // Returns true if callback returns false early, or all segments in the haystack for the needle are
  28. // found.
  29. func ScanConsecutive(haystack ConsecutiveExtentIter, needle Extent, callback Callback) bool {
  30. i := 0
  31. // Extents have been found in the haystack and we're waiting for the needle to end. This is kind
  32. // of for backwards compatibility for some tests that expect to have zero-length extents.
  33. startedNeedle := false
  34. for needle.Length != 0 {
  35. l, ok := haystack()
  36. if !ok {
  37. return false
  38. }
  39. e1 := Extent{
  40. Start: max(needle.Start-l.Start, 0),
  41. }
  42. e1.Length = max(min(l.Length, needle.End()-l.Start)-e1.Start, 0)
  43. needle.Start = max(0, needle.Start-l.End())
  44. needle.Length -= e1.Length + l.Start
  45. if e1.Length > 0 || (startedNeedle && needle.Length != 0) {
  46. if !callback(i, e1) {
  47. return true
  48. }
  49. startedNeedle = true
  50. }
  51. i++
  52. }
  53. return true
  54. }
  55. func LocaterFromLengthIter(li LengthIter) Locater {
  56. return func(e Extent, c Callback) bool {
  57. return Scan(li, e, c)
  58. }
  59. }
  60. type Locater func(Extent, Callback) bool