Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inline and small slices for memory compaction #420

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions experimental/ast/commas.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
package ast

import (
"slices"

"github.com/bufbuild/protocompile/experimental/seq"
"github.com/bufbuild/protocompile/experimental/token"
"github.com/bufbuild/protocompile/internal/ext/slicesx"
"github.com/bufbuild/protocompile/internal/ext/unsafex"
)

// Commas is like [Slice], but it's for a comma-delimited list of some kind.
Expand Down Expand Up @@ -48,13 +48,13 @@ type withComma[T any] struct {
Comma token.ID
}

type commas[T, E any] struct {
seq.SliceInserter[T, withComma[E]]
type commas[T any, Raw unsafex.Int] struct {
seq.InserterWrapper2[T, Raw, token.ID, *slicesx.Inline[Raw], *slicesx.Inline[token.ID]]
ctx Context
}

func (c commas[T, _]) Comma(n int) token.Token {
return (*c.SliceInserter.Slice)[n].Comma.In(c.ctx)
return c.InserterWrapper2.Slice2.At(n).In(c.ctx)
}

func (c commas[T, _]) AppendComma(value T, comma token.Token) {
Expand All @@ -63,8 +63,7 @@ func (c commas[T, _]) AppendComma(value T, comma token.Token) {

func (c commas[T, _]) InsertComma(n int, value T, comma token.Token) {
c.ctx.Nodes().panicIfNotOurs(comma)
v := c.SliceInserter.Unwrap(value)
v.Comma = comma.ID()

*c.Slice = slices.Insert(*c.Slice, n, v)
e1, _ := c.InserterWrapper2.Unwrap(value)
c.InserterWrapper2.Slice1.Insert(n, e1)
c.InserterWrapper2.Slice2.Insert(n, comma.ID())
}
28 changes: 17 additions & 11 deletions experimental/ast/decl_body.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/bufbuild/protocompile/experimental/seq"
"github.com/bufbuild/protocompile/experimental/token"
"github.com/bufbuild/protocompile/internal/arena"
"github.com/bufbuild/protocompile/internal/ext/slicesx"
)

// DeclBody is the body of a [DeclBody], or the whole contents of a [File]. The
Expand All @@ -41,8 +42,8 @@ type rawDeclBody struct {
// These slices are co-indexed; they are parallelizes to save
// three bytes per decl (declKind is 1 byte, but decl is 4; if
// they're stored in AOS format, we waste 3 bytes of padding).
kinds []DeclKind
ptrs []arena.Untyped
kinds slicesx.Inline[DeclKind]
ptrs slicesx.Inline[arena.Untyped]
}

// Braces returns this body's surrounding braces, if it has any.
Expand Down Expand Up @@ -71,22 +72,27 @@ func (d DeclBody) Span() report.Span {

// Decls returns a [seq.Inserter] over the declarations in this body.
func (d DeclBody) Decls() seq.Inserter[DeclAny] {
type slice = seq.SliceInserter2[DeclAny, DeclKind, arena.Untyped]
if d.IsZero() {
return slice{}
var (
kinds *slicesx.Inline[DeclKind]
ptrs *slicesx.Inline[arena.Untyped]
)
if !d.IsZero() {
kinds = &d.raw.kinds
ptrs = &d.raw.ptrs
}

return seq.SliceInserter2[DeclAny, DeclKind, arena.Untyped]{
Slice1: &d.raw.kinds,
Slice2: &d.raw.ptrs,
Wrap: func(k DeclKind, p arena.Untyped) DeclAny {
// A single return here promotes devirtualization of both the interface
// and the funcvals within.
return seq.WrapInserter2(
kinds, ptrs,
func(k DeclKind, p arena.Untyped) DeclAny {
return rawDecl{p, k}.With(d.Context())
},
Unwrap: func(d DeclAny) (DeclKind, arena.Untyped) {
func(d DeclAny) (DeclKind, arena.Untyped) {
d.Context().Nodes().panicIfNotOurs(d)
return d.raw.kind, d.raw.ptr
},
}
)
}

func wrapDeclBody(c Context, ptr arena.Pointer[rawDeclBody]) DeclBody {
Expand Down
28 changes: 14 additions & 14 deletions experimental/ast/decl_def.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,14 @@ import (
type DeclDef struct{ declImpl[rawDeclDef] }

type rawDeclDef struct {
ty rawType // Not present for enum fields.
name rawPath

signature *rawSignature

equals token.ID
value rawExpr

options arena.Pointer[rawCompactOptions]
body arena.Pointer[rawDeclBody]
semi token.ID
ty rawType
value rawExpr
name rawPath
equals token.ID
options arena.Pointer[rawCompactOptions]
body arena.Pointer[rawDeclBody]
semi token.ID
}

// DeclDefArgs is arguments for creating a [DeclDef] with [Context.NewDeclDef].
Expand Down Expand Up @@ -198,7 +195,7 @@ func (d DeclDef) Options() CompactOptions {
//
// Setting it to a zero Options clears it.
func (d DeclDef) SetOptions(opts CompactOptions) {
d.raw.options = d.Context().Nodes().options.Compress(opts.raw)
d.raw.options = d.Context().Nodes().compactOptions.Compress(opts.raw)
}

// Body returns this definition's body, if it has one.
Expand Down Expand Up @@ -386,9 +383,12 @@ func (d DeclDef) AsOption() DefOption {
return DefOption{
Keyword: d.Keyword(),
Option: Option{
Path: d.Name(),
Equals: d.Equals(),
Value: d.Value(),
d.withContext,
&rawOption{
path: d.Name().raw,
equals: d.Equals().ID(),
value: d.Value().raw,
},
},
Semicolon: d.Semicolon(),
Decl: d,
Expand Down
22 changes: 13 additions & 9 deletions experimental/ast/decl_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ func (f File) Imports() iter.Seq2[int, DeclImport] {
type DeclSyntax struct{ declImpl[rawDeclSyntax] }

type rawDeclSyntax struct {
keyword, equals, semi token.ID
value rawExpr
options arena.Pointer[rawCompactOptions]
value rawExpr
keyword token.ID
equals token.ID
semi token.ID
options arena.Pointer[rawCompactOptions]
}

// DeclSyntaxArgs is arguments for [Context.NewDeclSyntax].
Expand Down Expand Up @@ -167,7 +169,7 @@ func (d DeclSyntax) Options() CompactOptions {
//
// Setting it to a zero Options clears it.
func (d DeclSyntax) SetOptions(opts CompactOptions) {
d.raw.options = d.Context().Nodes().options.Compress(opts.raw)
d.raw.options = d.Context().Nodes().compactOptions.Compress(opts.raw)
}

// Semicolon returns this pragma's ending semicolon.
Expand Down Expand Up @@ -254,7 +256,7 @@ func (d DeclPackage) Options() CompactOptions {
//
// Setting it to a zero Options clears it.
func (d DeclPackage) SetOptions(opts CompactOptions) {
d.raw.options = d.Context().Nodes().options.Compress(opts.raw)
d.raw.options = d.Context().Nodes().compactOptions.Compress(opts.raw)
}

// Semicolon returns this package's ending semicolon.
Expand Down Expand Up @@ -292,9 +294,11 @@ func wrapDeclPackage(c Context, ptr arena.Pointer[rawDeclPackage]) DeclPackage {
type DeclImport struct{ declImpl[rawDeclImport] }

type rawDeclImport struct {
keyword, modifier, semi token.ID
importPath rawExpr
options arena.Pointer[rawCompactOptions]
importPath rawExpr
keyword token.ID
modifier token.ID
semi token.ID
options arena.Pointer[rawCompactOptions]
}

// DeclImportArgs is arguments for [Context.NewDeclImport].
Expand Down Expand Up @@ -369,7 +373,7 @@ func (d DeclImport) Options() CompactOptions {
//
// Setting it to a zero Options clears it.
func (d DeclImport) SetOptions(opts CompactOptions) {
d.raw.options = d.Context().Nodes().options.Compress(opts.raw)
d.raw.options = d.Context().Nodes().compactOptions.Compress(opts.raw)
}

// Semicolon returns this import's ending semicolon.
Expand Down
35 changes: 22 additions & 13 deletions experimental/ast/decl_range.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/bufbuild/protocompile/experimental/seq"
"github.com/bufbuild/protocompile/experimental/token"
"github.com/bufbuild/protocompile/internal/arena"
"github.com/bufbuild/protocompile/internal/ext/slicesx"
)

// DeclRange represents an extension or reserved range declaration. They are almost identical
Expand All @@ -31,7 +32,8 @@ type DeclRange struct{ declImpl[rawDeclRange] }

type rawDeclRange struct {
keyword token.ID
args []withComma[rawExpr]
args slicesx.Inline[rawExpr]
commas slicesx.Inline[token.ID]
options arena.Pointer[rawCompactOptions]
semi token.ID
}
Expand Down Expand Up @@ -65,22 +67,29 @@ func (d DeclRange) IsReserved() bool {
// Ranges returns the sequence of expressions denoting the ranges in this
// range declaration.
func (d DeclRange) Ranges() Commas[ExprAny] {
type slice = commas[ExprAny, rawExpr]
if d.IsZero() {
return slice{}
var (
args *slicesx.Inline[rawExpr]
toks *slicesx.Inline[token.ID]
)
if !d.IsZero() {
args = &d.raw.args
toks = &d.raw.commas
}
return slice{

// A single return here promotes devirtualization of both the interface
// and the funcvals within.
return commas[ExprAny, rawExpr]{
ctx: d.Context(),
SliceInserter: seq.SliceInserter[ExprAny, withComma[rawExpr]]{
Slice: &d.raw.args,
Wrap: func(c withComma[rawExpr]) ExprAny {
return newExprAny(d.Context(), c.Value)
InserterWrapper2: seq.WrapInserter2(
args, toks,
func(e rawExpr, _ token.ID) ExprAny {
return newExprAny(d.Context(), e)
},
Unwrap: func(e ExprAny) withComma[rawExpr] {
func(e ExprAny) (rawExpr, token.ID) {
d.Context().Nodes().panicIfNotOurs(e)
return withComma[rawExpr]{Value: e.raw}
return e.raw, 0
},
},
),
}
}

Expand All @@ -97,7 +106,7 @@ func (d DeclRange) Options() CompactOptions {
//
// Setting it to a nil Options clears it.
func (d DeclRange) SetOptions(opts CompactOptions) {
d.raw.options = d.Context().Nodes().options.Compress(opts.raw)
d.raw.options = d.Context().Nodes().compactOptions.Compress(opts.raw)
}

// Semicolon returns this range's ending semicolon.
Expand Down
2 changes: 1 addition & 1 deletion experimental/ast/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type ExprAny struct {
type rawExpr = pathLike[ExprKind]

func newExprAny(c Context, e rawExpr) ExprAny {
if c == nil || (e == rawExpr{}) {
if c == nil || e.isZero() {
return ExprAny{}
}

Expand Down
35 changes: 22 additions & 13 deletions experimental/ast/expr_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/bufbuild/protocompile/experimental/report"
"github.com/bufbuild/protocompile/experimental/seq"
"github.com/bufbuild/protocompile/experimental/token"
"github.com/bufbuild/protocompile/internal/ext/slicesx"
)

// ExprArray represents an array of expressions between square brackets.
Expand All @@ -29,7 +30,8 @@ type ExprArray struct{ exprImpl[rawExprArray] }

type rawExprArray struct {
brackets token.ID
args []withComma[rawExpr]
args slicesx.Inline[rawExpr]
commas slicesx.Inline[token.ID]
}

// Brackets returns the token tree corresponding to the whole [...].
Expand All @@ -45,22 +47,29 @@ func (e ExprArray) Brackets() token.Token {

// Elements returns the sequence of expressions in this array.
func (e ExprArray) Elements() Commas[ExprAny] {
type slice = commas[ExprAny, rawExpr]
if e.IsZero() {
return slice{}
var (
args *slicesx.Inline[rawExpr]
toks *slicesx.Inline[token.ID]
)
if !e.IsZero() {
args = &e.raw.args
toks = &e.raw.commas
}
return slice{

// A single return here promotes devirtualization of both the interface
// and the funcvals within.
return commas[ExprAny, rawExpr]{
ctx: e.Context(),
SliceInserter: seq.SliceInserter[ExprAny, withComma[rawExpr]]{
Slice: &e.raw.args,
Wrap: func(c withComma[rawExpr]) ExprAny {
return newExprAny(e.Context(), c.Value)
InserterWrapper2: seq.WrapInserter2(
args, toks,
func(r rawExpr, _ token.ID) ExprAny {
return newExprAny(e.Context(), r)
},
Unwrap: func(e ExprAny) withComma[rawExpr] {
e.Context().Nodes().panicIfNotOurs(e)
return withComma[rawExpr]{Value: e.raw}
func(r ExprAny) (rawExpr, token.ID) {
e.Context().Nodes().panicIfNotOurs(r)
return r.raw, 0
},
},
),
}
}

Expand Down
Loading
Loading