+
+// Size returns the sum of the line sizes.
+func (v *View) Size() int {
+ size := 0
+ for _, line := range v.lines {
+ size += v.lineSize(line)
+ }
+
+ return size
+}
+
+// mostDue returns the position of the left line of the most due sibling pair
+// whose parent is built, or -1 when there is no such pair.
+func (v *View) mostDue(tree ViewNodeReader) (int, error) {
+ best := -1
+ bestDue := 0.0
+ for n := 0; n+1 < len(v.lines); n++ {
+ left, right := v.lines[n], v.lines[n+1]
+ if left.index%2 != 0 || right.level != left.level || right.index != left.index+1 {
+ continue
+ }
+
+ last := nodeEnd(right.level, right.index) - 1
+ due := math.Ldexp(float64(v.end-last), -left.level)
+ if best >= 0 && due <= bestDue {
+ continue
+ }
+
+ built, err := tree.Built(left.level+1, left.index/2)
+ if err != nil {
+ return -1, err
+ }
+
+ if built {
+ best = n
+ bestDue = due
+ }
+ }
+
+ return best, nil
+}
+
+// lineSize returns the size of a view line.
+func (v *View) lineSize(line NodeKey) int {
+ node, built := v.nodes[line]
+ if !built {
+ return len(viewPending)
+ }
+
+ return node.Size
+}
+
+// ViewState is the saved form of a View. The limits are not part of it.
+type ViewState struct {
+ Lines [][2]int `json:"lines"`
+ Merging bool `json:"merging"`
+}
+
+// ViewNodeReader gives the built nodes of a tree.
+type ViewNodeReader interface {
+ Built(level, index int) (bool, error)
+ Node(level, index int) (Node, bool, error)
+}