Answer prose round 1: pickKey names its two roots, readUnder says when it reads, levelKeys, draw and readField read on one pass, and the allocation case is named for what it reads
This commit is contained in:
@@ -246,7 +246,7 @@ func pathArm(name, head, writtenHead string, segs []string) arm {
|
|||||||
return arm{spelling: name, head: head, writtenHead: writtenHead, tail: segs, levels: levelKeys(append([]string{head}, segs...), 1)}
|
return arm{spelling: name, head: head, writtenHead: writtenHead, tail: segs, levels: levelKeys(append([]string{head}, segs...), 1)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// levelKeys keys each prefix of path, from its first from segments to the whole of it.
|
// levelKeys is the key of each prefix of path holding at least from segments, shortest first.
|
||||||
func levelKeys(path []string, from int) []pickKey {
|
func levelKeys(path []string, from int) []pickKey {
|
||||||
levels := make([]pickKey, len(path)-from+1)
|
levels := make([]pickKey, len(path)-from+1)
|
||||||
for i := range levels {
|
for i := range levels {
|
||||||
|
|||||||
+1
-1
@@ -64,7 +64,7 @@ func TestNoReferenceAllocRegression(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{"a repeat of a reference path", `{"format":"{r}","r":{"format":"{/word.w}","repeat":20,"separator":", "}}`, 25},
|
{"a repeat of a reference path", `{"format":"{r}","r":{"format":"{/word.w}","repeat":20,"separator":", "}}`, 25},
|
||||||
{"a repeat of a name", `{"format":"{r}","r":{"format":"{/word as n}{n.w}{n.w}","repeat":20,"separator":", "}}`, 162},
|
{"a repeat of a name", `{"format":"{r}","r":{"format":"{/word as n}{n.w}{n.w}","repeat":20,"separator":", "}}`, 162},
|
||||||
{"a read under a nested pick", `{"format":"{place.geo as g}{g} {g.town.zip}","place":{"format":"{geo}","geo":{"format":"{town.zip}","town":{"format":"{zip}","zip":"1"}}}}`, 10},
|
{"a read two levels under a pick", `{"format":"{place.geo as g}{g} {g.town.zip}","place":{"format":"{geo}","geo":{"format":"{town.zip}","town":{"format":"{zip}","zip":"1"}}}}`, 10},
|
||||||
} {
|
} {
|
||||||
f, err := New(WithoutShippedData(), WithDataFS(fstest.MapFS{
|
f, err := New(WithoutShippedData(), WithDataFS(fstest.MapFS{
|
||||||
"word.json": {Data: []byte(word)},
|
"word.json": {Data: []byte(word)},
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import (
|
|||||||
"github.com/larvit/fejkdata/internal/invariant"
|
"github.com/larvit/fejkdata/internal/invariant"
|
||||||
)
|
)
|
||||||
|
|
||||||
// pickKey is where a level sits in a named pick: its path from the head the name's target starts
|
// pickKey is a level's path of segments from a root keyed "": for a named read, the node its
|
||||||
// at, which is "". A fresh read keys its levels from its own head until readUnder keys them under
|
// name's target starts at; for a fresh read, the template it sits in. under moves a fresh read's
|
||||||
// the pick.
|
// key into the pick it renders in.
|
||||||
type pickKey string
|
type pickKey string
|
||||||
|
|
||||||
// under is the key of rel, a fresh read's key, in what renders at k. It never returns k itself: on
|
// under is rel, a key from a fresh read's levels, moved under k, the key of what renders. It never
|
||||||
// a render k is sc.pickAt, and a memo keeping it would move every render's scope to the heap.
|
// returns k itself: on a render k is sc.pickAt, and a memo keeping it would move every render's scope to the heap.
|
||||||
func (k pickKey) under(rel pickKey) pickKey {
|
func (k pickKey) under(rel pickKey) pickKey {
|
||||||
if k == "" {
|
if k == "" {
|
||||||
return rel
|
return rel
|
||||||
@@ -193,8 +193,8 @@ func (sc renderScope) keeps(a arm) bool {
|
|||||||
return kept
|
return kept
|
||||||
}
|
}
|
||||||
|
|
||||||
// readUnder reads a of t, which renders as part of the pick sc.pick at sc.pickAt, where a read of
|
// readUnder reads a, an arm of t, once per pick: t renders in sc.pick at sc.pickAt, and a read of
|
||||||
// the name addresses it: once per pick, by its key in the pick.
|
// the name addresses the level a starts at. It keys the value by a's key under sc.pickAt.
|
||||||
func readUnder(s *drawstate.State, t *template, sc renderScope, a arm) readValue {
|
func readUnder(s *drawstate.State, t *template, sc renderScope, a arm) readValue {
|
||||||
p, key := sc.pick, sc.pickAt.under(a.key())
|
p, key := sc.pick, sc.pickAt.under(a.key())
|
||||||
if r, done := p.memo.value[key]; done {
|
if r, done := p.memo.value[key]; done {
|
||||||
@@ -209,8 +209,8 @@ func readUnder(s *drawstate.State, t *template, sc renderScope, a arm) readValue
|
|||||||
return p.renderAt(s, leaf, pins, key, sc)
|
return p.renderAt(s, leaf, pins, key, sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw draws the path from head under p, keeping the variant drawn at each of levels, the leaf's
|
// draw draws the path from head under p, keeping the variant drawn at each of levels, whose last
|
||||||
// last, and returns the leaf and the pins its row is in.
|
// is the leaf's key, and returns the leaf and the pins its row is in.
|
||||||
func (p *namedPick) draw(s *drawstate.State, head node, steps []pathStep, levels []pickKey) (node, *pinSet) {
|
func (p *namedPick) draw(s *drawstate.State, head node, steps []pathStep, levels []pickKey) (node, *pinSet) {
|
||||||
leaf, pins := drawSteps(s, head, steps, &p.pins, &p.memo, levels)
|
leaf, pins := drawSteps(s, head, steps, &p.pins, &p.memo, levels)
|
||||||
if c, isChoice := leaf.(*choice); isChoice {
|
if c, isChoice := leaf.(*choice); isChoice {
|
||||||
|
|||||||
@@ -145,8 +145,8 @@ func expand(s *drawstate.State, t *template, sc renderScope) string {
|
|||||||
// readField renders one arm of a token. A read is kept in a name's pick when it reads the name, or
|
// readField renders one arm of a token. A read is kept in a name's pick when it reads the name, or
|
||||||
// a level that a read of the name being rendered addresses; every other read draws afresh, so
|
// a level that a read of the name being rendered addresses; every other read draws afresh, so
|
||||||
// {word} {word} draws twice and {p.a} {p.b} reads two draws of p.
|
// {word} {word} draws twice and {p.a} {p.b} reads two draws of p.
|
||||||
// A fresh read clears sc.pick. Kept, a read nested in the fresh one would key the pick's memo by
|
// A fresh read clears sc.pick: were it kept, a read nested in the fresh one would key the pick's
|
||||||
// sc.pickAt, where in the pick it renders, and share a value with a different node at that key.
|
// memo under sc.pickAt and share a value with another node at that key.
|
||||||
func readField(s *drawstate.State, t *template, sc renderScope, a arm) readValue {
|
func readField(s *drawstate.State, t *template, sc renderScope, a arm) readValue {
|
||||||
switch {
|
switch {
|
||||||
case a.kind == namedRead:
|
case a.kind == namedRead:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type renderScope struct {
|
|||||||
// base is the depth of the frame stack when the read rendering the category entered it,
|
// base is the depth of the frame stack when the read rendering the category entered it,
|
||||||
// below which no frame is the category's.
|
// below which no frame is the category's.
|
||||||
base int
|
base int
|
||||||
// pick is the named pick being rendered, nil outside one; pickAt is where in it this renders.
|
// pick is the named pick being rendered, nil outside one; pickAt is the key in it of what renders.
|
||||||
pick *namedPick
|
pick *namedPick
|
||||||
pickAt pickKey
|
pickAt pickKey
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user