618f0181ac
* Use pointers instead of copying around ast.Node Node is a 56B struct that is constantly in the hot path. Passing nodes around by copy had a cost that started to add up. This change replaces them by pointers. Using unsafe pointer arithmetic and converting sibling/child indexes to relative offsets, it removes the need to carry around a pointer to the root of the tree. This saves 8B per Node. This space will be used to store an extra []byte slice to provide contextual error handling on all nodes, including the ones whose data is different than the raw input (for example: strings with escaped characters), while staying under the size of a cache line. * Remove conditional * Add Raw to track range in data for parsed values * Simplify reference tracking
52 lines
1020 B
Go
52 lines
1020 B
Go
package ast
|
|
|
|
type Reference int
|
|
|
|
const InvalidReference Reference = -1
|
|
|
|
func (r Reference) Valid() bool {
|
|
return r != InvalidReference
|
|
}
|
|
|
|
type Builder struct {
|
|
tree Root
|
|
lastIdx int
|
|
}
|
|
|
|
func (b *Builder) Tree() *Root {
|
|
return &b.tree
|
|
}
|
|
|
|
func (b *Builder) NodeAt(ref Reference) *Node {
|
|
return b.tree.at(ref)
|
|
}
|
|
|
|
func (b *Builder) Reset() {
|
|
b.tree.nodes = b.tree.nodes[:0]
|
|
b.lastIdx = 0
|
|
}
|
|
|
|
func (b *Builder) Push(n Node) Reference {
|
|
b.lastIdx = len(b.tree.nodes)
|
|
b.tree.nodes = append(b.tree.nodes, n)
|
|
return Reference(b.lastIdx)
|
|
}
|
|
|
|
func (b *Builder) PushAndChain(n Node) Reference {
|
|
newIdx := len(b.tree.nodes)
|
|
b.tree.nodes = append(b.tree.nodes, n)
|
|
if b.lastIdx >= 0 {
|
|
b.tree.nodes[b.lastIdx].next = newIdx - b.lastIdx
|
|
}
|
|
b.lastIdx = newIdx
|
|
return Reference(b.lastIdx)
|
|
}
|
|
|
|
func (b *Builder) AttachChild(parent Reference, child Reference) {
|
|
b.tree.nodes[parent].child = int(child) - int(parent)
|
|
}
|
|
|
|
func (b *Builder) Chain(from Reference, to Reference) {
|
|
b.tree.nodes[from].next = int(to) - int(from)
|
|
}
|