Skip to content

Commit

Permalink
pathbuilder: simplify
Browse files Browse the repository at this point in the history
Signed-off-by: Vicent Marti <vmg@strn.cat>
  • Loading branch information
vmg committed Feb 11, 2025
1 parent bf96f0e commit f46418c
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 86 deletions.
84 changes: 13 additions & 71 deletions go/vt/sqlparser/pathbuilder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,103 +18,47 @@ package pathbuilder

import (
"encoding/binary"
"unsafe"
)

// ASTPathBuilder is used to build
// paths for an AST. The steps are uints.
type ASTPathBuilder struct {
path []byte
pathLen int
sizes []int
path []byte
sizes []int
}

const initialCap = 16

// NewASTPathBuilder creates a new ASTPathBuilder
func NewASTPathBuilder() *ASTPathBuilder {
return &ASTPathBuilder{
path: make([]byte, initialCap),
path: make([]byte, 0, initialCap),
}
}

// TODO: Remove this. We should only use it for testing while building confidence.
func (apb *ASTPathBuilder) sanityCheck() {
var total int
for _, size := range apb.sizes {
total += size
}
if total != apb.pathLen {
panic("path length mismatch")
}
}

// growIfNeeded expands the slice capacity if we don't have enough room for n more bytes.
func (apb *ASTPathBuilder) growIfNeeded(n int) {
needed := apb.pathLen + n
currentCap := cap(apb.path)
if needed <= currentCap {
return
}
newCap := currentCap * 2
for newCap < needed {
newCap *= 2
}
newPath := make([]byte, newCap)
copy(newPath, apb.path[:apb.pathLen])
apb.path = newPath
}

// ToPath returns the current path as a string of the used bytes.
func (apb *ASTPathBuilder) ToPath() string {
return string(apb.path[:apb.pathLen])
return unsafe.String(unsafe.SliceData(apb.path), len(apb.path))
}

// AddStep appends a single step (2 bytes) to path.
func (apb *ASTPathBuilder) AddStep(step uint16) {
apb.growIfNeeded(2)
binary.BigEndian.PutUint16(apb.path[apb.pathLen:apb.pathLen+2], step)
apb.pathLen += 2
apb.sizes = append(apb.sizes, 2)
apb.sanityCheck()
apb.sizes = append(apb.sizes, len(apb.path))
apb.path = binary.BigEndian.AppendUint16(apb.path, step)
}

// AddStepWithOffset appends a single step (2 bytes) + varint offset with value 0 to path.
func (apb *ASTPathBuilder) AddStepWithOffset(step uint16) {
// Step
apb.growIfNeeded(2)
binary.BigEndian.PutUint16(apb.path[apb.pathLen:apb.pathLen+2], step)
apb.pathLen += 2

// Offset
var buf [8]byte
bytesWritten := binary.PutVarint(buf[:], 0) // 0 offset
apb.growIfNeeded(bytesWritten)
copy(apb.path[apb.pathLen:apb.pathLen+bytesWritten], buf[:bytesWritten])
apb.pathLen += bytesWritten

apb.sizes = append(apb.sizes, 2+bytesWritten)
apb.sanityCheck()
apb.sizes = append(apb.sizes, len(apb.path))
apb.path = binary.BigEndian.AppendUint16(apb.path, step)
apb.path = binary.AppendVarint(apb.path, 0) // 0 offset
}

// ChangeOffset modifies the offset of the last step (which must have included an offset).
func (apb *ASTPathBuilder) ChangeOffset(newOffset int) {
lastIndex := len(apb.sizes) - 1
oldSize := apb.sizes[lastIndex]
offsetSize := oldSize - 2 // remove the step portion

// Move pathLen back to overwrite the old offset
apb.pathLen -= offsetSize

// Encode new offset
var buf [8]byte
bytesWritten := binary.PutVarint(buf[:], int64(newOffset))
apb.growIfNeeded(bytesWritten)
copy(apb.path[apb.pathLen:apb.pathLen+bytesWritten], buf[:bytesWritten])
apb.pathLen += bytesWritten

// Update the size
apb.sizes[lastIndex] = 2 + bytesWritten
apb.sanityCheck()
pos := apb.sizes[len(apb.sizes)-1] + 2
apb.path = binary.AppendVarint(apb.path[:pos], int64(newOffset))
}

// Pop removes the last step (including offset, if any) from the path.
Expand All @@ -123,8 +67,6 @@ func (apb *ASTPathBuilder) Pop() {
return
}
n := len(apb.sizes) - 1
lastSize := apb.sizes[n]
apb.pathLen -= lastSize
apb.path = apb.path[:apb.sizes[n]]
apb.sizes = apb.sizes[:n]
apb.sanityCheck()
}
15 changes: 0 additions & 15 deletions go/vt/sqlparser/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,6 @@ import (
// Some steps (e.g., referencing a slice) consume *additional* bytes for an index
type ASTPath string

// AddStep appends a single step (2 bytes) to path.
func AddStep(path ASTPath, step ASTStep) ASTPath {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(step))
return path + ASTPath(b)
}

func AddStepWithOffset(path ASTPath, step ASTStep, offset int) ASTPath {
var buf [10]byte
binary.BigEndian.PutUint16(buf[0:], uint16(step))
n := binary.PutVarint(buf[2:], int64(offset))

return path + ASTPath(buf[:2+n])
}

func (path ASTPath) DebugString() string {
var sb strings.Builder

Expand Down
16 changes: 16 additions & 0 deletions go/vt/sqlparser/paths_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,27 @@ limitations under the License.
package sqlparser

import (
"encoding/binary"
"testing"

"github.com/stretchr/testify/assert"
)

// AddStep appends a single step (2 bytes) to path.
func AddStep(path ASTPath, step ASTStep) ASTPath {
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(step))
return path + ASTPath(b)
}

func AddStepWithOffset(path ASTPath, step ASTStep, offset int) ASTPath {
var buf [10]byte
binary.BigEndian.PutUint16(buf[0:], uint16(step))
n := binary.PutVarint(buf[2:], int64(offset))

return path + ASTPath(buf[:2+n])
}

func TestASTPathDebugString(t *testing.T) {
// select * from t where func(1,2,x) = 10
// path to X
Expand Down

0 comments on commit f46418c

Please sign in to comment.