Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
3 changed files with 26 additions and 47 deletions
Showing only changes of commit 4772fa7df3 - Show all commits
+13
View File
@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"maps" "maps"
"sort" "sort"
"strings"
) )
type tablePin struct { type tablePin struct {
@@ -85,6 +86,18 @@ func (p *pinSet) each(fn func(t *table, r int)) {
} }
} }
// key spells the pinned rows, so two sets pinning the same rows share one.
func (p *pinSet) key() string {
var pins []tablePin
p.each(func(t *table, r int) { pins = append(pins, tablePin{t, r}) })
sort.Slice(pins, func(i, j int) bool { return pins[i].t.path < pins[j].t.path })
var b strings.Builder
for _, q := range pins {
fmt.Fprintf(&b, "%q%d", q.t.path, q.row)
}
return b.String()
}
// clash is the table whose pinned row keeps row r of t out: t itself pinned to another row, or the // clash is the table whose pinned row keeps row r of t out: t itself pinned to another row, or the
// nearest ancestor pinned to a row r is not inside; nil where none does. // nearest ancestor pinned to a row r is not inside; nil where none does.
func (p *pinSet) clash(t *table, r int) *table { func (p *pinSet) clash(t *table, r int) *table {
+13 -43
View File
@@ -8,10 +8,9 @@ import (
// readSurvey gathers, at load, the references one render reads, by draw group, for check to compare. // readSurvey gathers, at load, the references one render reads, by draw group, for check to compare.
type readSurvey struct { type readSurvey struct {
reads []pathRead reads []pathRead
read map[readKey]bool read map[readKey]bool
seen map[nodeVisit]bool seen map[nodeVisit]bool
pinIDs map[pinsLink]pinsID
} }
// surveyAt is where a survey stands: the draw group its reads draw in, how the render's root reached it, the // surveyAt is where a survey stands: the draw group its reads draw in, how the render's root reached it, the
@@ -39,28 +38,19 @@ type nodeVisit struct {
n node n node
group string group string
wholeTable *table wholeTable *table
pins pinsID pins string
wholePins pinsID wholePins string
} }
type readKey struct { type readKey struct {
group string group string
path string path string
pins pinsID pins string
wholePins pinsID wholePins string
}
// pinsID names a pin set within one walk: two sets pinning the same rows share one.
type pinsID int
// pinsLink is a set's last pin, in path order, and the id of the set before it.
type pinsLink struct {
prev pinsID
pin tablePin
} }
func newReadSurvey() *readSurvey { func newReadSurvey() *readSurvey {
return &readSurvey{read: map[readKey]bool{}, seen: map[nodeVisit]bool{}, pinIDs: map[pinsLink]pinsID{}} return &readSurvey{read: map[readKey]bool{}, seen: map[nodeVisit]bool{}}
} }
func surveyRender(t *template) *readSurvey { func surveyRender(t *template) *readSurvey {
@@ -79,27 +69,10 @@ func surveyColumns(t *template, columns []string) *readSurvey {
return s return s
} }
func (s *readSurvey) pinsID(p *pinSet) pinsID {
var pins []tablePin
p.each(func(t *table, r int) { pins = append(pins, tablePin{t, r}) })
sort.Slice(pins, func(i, j int) bool { return pins[i].t.path < pins[j].t.path })
id := pinsID(0)
for _, q := range pins {
l := pinsLink{id, q}
next, ok := s.pinIDs[l]
if !ok {
next = pinsID(len(s.pinIDs) + 1)
s.pinIDs[l] = next
}
id = next
}
return id
}
// walk follows what rendering n renders. A repeat renders over draws of its own, so the walk stops // walk follows what rendering n renders. A repeat renders over draws of its own, so the walk stops
// there. // there.
func (s *readSurvey) walk(n node, at surveyAt) { func (s *readSurvey) walk(n node, at surveyAt) {
v := nodeVisit{n, at.group, at.wholeTable, s.pinsID(&at.pins), s.pinsID(&at.wholePins)} v := nodeVisit{n, at.group, at.wholeTable, at.pins.key(), at.wholePins.key()}
if s.seen[v] { if s.seen[v] {
return return
} }
@@ -144,7 +117,7 @@ func (s *readSurvey) edge(from node, e renderEdge, at surveyAt) {
if e.readsRef() { if e.readsRef() {
a := e.read a := e.read
tr := tableReadOf(from.(*template).head(a.head), a, e.to) tr := tableReadOf(from.(*template).head(a.head), a, e.to)
if k := (readKey{at.group, a.path, s.pinsID(&at.pins), s.pinsID(&at.wholePins)}); !s.read[k] { if k := (readKey{at.group, a.path, at.pins.key(), at.wholePins.key()}); !s.read[k] {
s.read[k] = true s.read[k] = true
s.reads = append(s.reads, pathRead{at, a, tr}) s.reads = append(s.reads, pathRead{at, a, tr})
} }
@@ -301,8 +274,8 @@ func checkFamilyPair(a, b pathRead) error {
return nil return nil
} }
// replayPairs replays every two reads that can render together into one draws, the earlier // replayPairs replays, of every two reads that can render together, the later into the
// read first. Pairs find every conflict a full replay would: clash judges a row against one // earlier's pins. Pairs find every conflict a full replay would: clash judges a row against one
// pinned table, and the read that pinned it holds that pin itself, since a read's pins carry // pinned table, and the read that pinned it holds that pin itself, since a read's pins carry
// its rows' ancestors, so the pair of those two reads clashes the same way. // its rows' ancestors, so the pair of those two reads clashes the same way.
func replayPairs(reads []pathRead) error { func replayPairs(reads []pathRead) error {
@@ -314,10 +287,7 @@ func replayPairs(reads []pathRead) error {
if o.tr == nil || o.at.group != r.at.group || alternatives(r.at, o.at) { if o.tr == nil || o.at.group != r.at.group || alternatives(r.at, o.at) {
continue continue
} }
var d pinSet d := r.tr.pins.clone()
if err := r.tr.replay(&d); err != nil {
return conflict(r, err)
}
if err := o.tr.replay(&d); err != nil { if err := o.tr.replay(&d); err != nil {
return conflict(o, err) return conflict(o, err)
} }
-4
View File
@@ -31,10 +31,6 @@ on 2026-09-29 a third time (Navigation 7.0, Locality 5.6, Shape 6.3, Self-suffic
This round, in order: This round, in order:
- Key the survey's visits and reads by a pin set's rows spelled as a string, and delete
`pinsID`, `pinsLink` and `readSurvey.pinIDs`: five seats stalled on the interning.
Start `replayPairs`' pin set as a clone of the earlier read's pins, deleting the
replay into an empty set, which cannot fail since `pinRow` built those pins.
- Move `checkOwnFamily` into `readsurvey.go` beside `checkFamilies`, and - Move `checkOwnFamily` into `readsurvey.go` beside `checkFamilies`, and
`checkNestedDrawGroup` into `node.go` beside `drawGroupOf`, the compile step calling `checkNestedDrawGroup` into `node.go` beside `drawGroupOf`, the compile step calling
it; delete `checkColumnDraws` for `surveyColumns(…).check()` at its caller. Both it; delete `checkColumnDraws` for `surveyColumns(…).check()` at its caller. Both