Key the survey by a pin set's rows spelled as a string
This commit is contained in:
@@ -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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user