Switch to generics (#1763)

* gradually replace list.List with slices

* gradually replace list.List with slices

* more

* more

* more
This commit is contained in:
John Kerl 2025-03-05 08:19:15 -05:00 committed by GitHub
parent 7d51030b88
commit 9963df4090
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 57 additions and 70 deletions

View file

@ -6,7 +6,6 @@
package cst
import (
"container/list"
"errors"
"fmt"
"os"
@ -37,9 +36,9 @@ func NewEmptyRoot(
udfManager: NewUDFManager(),
udsManager: NewUDSManager(),
allowUDFUDSRedefinitions: false,
unresolvedFunctionCallsites: list.New(),
unresolvedSubroutineCallsites: list.New(),
outputHandlerManagers: list.New(),
unresolvedFunctionCallsites: make([]*UDFCallsite, 0),
unresolvedSubroutineCallsites: make([]*UDSCallsite, 0),
outputHandlerManagers: make([]output.OutputHandlerManager, 0),
recordWriterOptions: recordWriterOptions,
dslInstanceType: dslInstanceType,
}
@ -364,11 +363,11 @@ func (root *RootNode) buildMainPass(ast *dsl.AST, isReplImmediate bool) error {
// This is invoked within the buildMainPass call tree whenever a function is
// called before it's defined.
func (root *RootNode) rememberUnresolvedFunctionCallsite(udfCallsite *UDFCallsite) {
root.unresolvedFunctionCallsites.PushBack(udfCallsite)
root.unresolvedFunctionCallsites = append(root.unresolvedFunctionCallsites, udfCallsite)
}
func (root *RootNode) rememberUnresolvedSubroutineCallsite(udsCallsite *UDSCallsite) {
root.unresolvedSubroutineCallsites.PushBack(udsCallsite)
root.unresolvedSubroutineCallsites = append(root.unresolvedSubroutineCallsites, udsCallsite)
}
// After-pass after buildMainPass returns, in case a function was called before
@ -381,10 +380,9 @@ func (root *RootNode) rememberUnresolvedSubroutineCallsite(udsCallsite *UDSCalls
// So, our error message should reflect all those options.
func (root *RootNode) resolveFunctionCallsites() error {
for root.unresolvedFunctionCallsites.Len() > 0 {
unresolvedFunctionCallsite := root.unresolvedFunctionCallsites.Remove(
root.unresolvedFunctionCallsites.Front(),
).(*UDFCallsite)
for len(root.unresolvedFunctionCallsites) > 0 {
unresolvedFunctionCallsite := root.unresolvedFunctionCallsites[0]
root.unresolvedFunctionCallsites = root.unresolvedFunctionCallsites[1:]
functionName := unresolvedFunctionCallsite.udf.signature.funcOrSubrName
callsiteArity := unresolvedFunctionCallsite.udf.signature.arity
@ -405,10 +403,9 @@ func (root *RootNode) resolveFunctionCallsites() error {
}
func (root *RootNode) resolveSubroutineCallsites() error {
for root.unresolvedSubroutineCallsites.Len() > 0 {
unresolvedSubroutineCallsite := root.unresolvedSubroutineCallsites.Remove(
root.unresolvedSubroutineCallsites.Front(),
).(*UDSCallsite)
for len(root.unresolvedSubroutineCallsites) > 0 {
unresolvedSubroutineCallsite := root.unresolvedSubroutineCallsites[0]
root.unresolvedSubroutineCallsites = root.unresolvedSubroutineCallsites[1:]
subroutineName := unresolvedSubroutineCallsite.uds.signature.funcOrSubrName
callsiteArity := unresolvedSubroutineCallsite.uds.signature.arity
@ -438,12 +435,11 @@ func (root *RootNode) resolveSubroutineCallsites() error {
func (root *RootNode) RegisterOutputHandlerManager(
outputHandlerManager output.OutputHandlerManager,
) {
root.outputHandlerManagers.PushBack(outputHandlerManager)
root.outputHandlerManagers = append(root.outputHandlerManagers, outputHandlerManager)
}
func (root *RootNode) ProcessEndOfStream() {
for entry := root.outputHandlerManagers.Front(); entry != nil; entry = entry.Next() {
outputHandlerManager := entry.Value.(output.OutputHandlerManager)
for _, outputHandlerManager := range root.outputHandlerManagers {
errs := outputHandlerManager.Close()
if len(errs) != 0 {
for _, err := range errs {
@ -501,8 +497,8 @@ func (root *RootNode) ExecuteREPLImmediate(state *runtime.State) (outrec *mlrval
// This is the 'and then discarded' part of that.
func (root *RootNode) ResetForREPL() {
root.replImmediateBlock = NewStatementBlockNode()
root.unresolvedFunctionCallsites = list.New()
root.unresolvedSubroutineCallsites = list.New()
root.unresolvedFunctionCallsites = make([]*UDFCallsite, 0)
root.unresolvedSubroutineCallsites = make([]*UDSCallsite, 0)
}
// This is for the REPL's context-printer command.

View file

@ -5,11 +5,10 @@
package cst
import (
"container/list"
"github.com/johnkerl/miller/v6/pkg/cli"
"github.com/johnkerl/miller/v6/pkg/dsl"
"github.com/johnkerl/miller/v6/pkg/mlrval"
"github.com/johnkerl/miller/v6/pkg/output"
"github.com/johnkerl/miller/v6/pkg/runtime"
)
@ -44,9 +43,9 @@ type RootNode struct {
udfManager *UDFManager
udsManager *UDSManager
allowUDFUDSRedefinitions bool
unresolvedFunctionCallsites *list.List
unresolvedSubroutineCallsites *list.List
outputHandlerManagers *list.List
unresolvedFunctionCallsites []*UDFCallsite
unresolvedSubroutineCallsites []*UDSCallsite
outputHandlerManagers []output.OutputHandlerManager
recordWriterOptions *cli.TWriterOptions
dslInstanceType DSLInstanceType // put, filter, repl
strictMode bool

View file

@ -26,7 +26,6 @@
package runtime
import (
"container/list"
"fmt"
"github.com/johnkerl/miller/v6/pkg/lib"
@ -68,7 +67,7 @@ func (sv *StackVariable) GetName() string {
type Stack struct {
// list of *StackFrameSet
stackFrameSets *list.List
stackFrameSets []*StackFrameSet
// Invariant: equal to the head of the stackFrameSets list. This is cached
// since all sets/gets in between frameset-push and frameset-pop will all
@ -77,9 +76,9 @@ type Stack struct {
}
func NewStack() *Stack {
stackFrameSets := list.New()
stackFrameSets := make([]*StackFrameSet, 1)
head := newStackFrameSet()
stackFrameSets.PushFront(head)
stackFrameSets[0] = head
return &Stack{
stackFrameSets: stackFrameSets,
head: head,
@ -89,13 +88,13 @@ func NewStack() *Stack {
// For when a user-defined function/subroutine is being entered
func (stack *Stack) PushStackFrameSet() {
stack.head = newStackFrameSet()
stack.stackFrameSets.PushFront(stack.head)
stack.stackFrameSets = append([]*StackFrameSet{stack.head}, stack.stackFrameSets...)
}
// For when a user-defined function/subroutine is being exited
func (stack *Stack) PopStackFrameSet() {
stack.stackFrameSets.Remove(stack.stackFrameSets.Front())
stack.head = stack.stackFrameSets.Front().Value.(*StackFrameSet)
stack.stackFrameSets = stack.stackFrameSets[1:]
stack.head = stack.stackFrameSets[0]
}
// ----------------------------------------------------------------
@ -180,9 +179,8 @@ func (stack *Stack) UnsetIndexed(
}
func (stack *Stack) Dump() {
fmt.Printf("STACK FRAMESETS (count %d):\n", stack.stackFrameSets.Len())
for entry := stack.stackFrameSets.Front(); entry != nil; entry = entry.Next() {
stackFrameSet := entry.Value.(*StackFrameSet)
fmt.Printf("STACK FRAMESETS (count %d):\n", len(stack.stackFrameSets))
for _, stackFrameSet := range stack.stackFrameSets {
stackFrameSet.dump()
}
}

View file

@ -35,7 +35,7 @@ type State struct {
// This is necessary for the stateful semantics of `=~` and "\1", "\2", etc.
// Those are avoided when the user calls `matchx`, which is newer, and
// stateless. However, `=~` exists in the Miller DSL and we must support it.
regexCapturesByFrame *list.List // list of []string
regexCapturesByFrame [][]string
Options *cli.TOptions
@ -46,8 +46,8 @@ type State struct {
func NewEmptyState(options *cli.TOptions, strictMode bool) *State {
// See lib.MakeEmptyCaptures for context.
regexCapturesByFrame := list.New()
regexCapturesByFrame.PushFront(lib.MakeEmptyCaptures())
regexCapturesByFrame := make([][]string, 1)
regexCapturesByFrame[0] = lib.MakeEmptyCaptures()
oosvars := mlrval.NewMlrmap()
return &State{
@ -72,25 +72,24 @@ func (state *State) Update(
) {
state.Inrec = inrec
state.Context = context
state.regexCapturesByFrame.Front().Value = lib.MakeEmptyCaptures()
state.regexCapturesByFrame[0] = lib.MakeEmptyCaptures()
}
func (state *State) SetRegexCaptures(
captures []string,
) {
state.regexCapturesByFrame.Front().Value = lib.CopyStringArray(captures)
state.regexCapturesByFrame[0] = lib.CopyStringArray(captures)
}
func (state *State) GetRegexCaptures() []string {
regexCaptures := state.regexCapturesByFrame.Front().Value.([]string)
regexCaptures := state.regexCapturesByFrame[0]
return lib.CopyStringArray(regexCaptures)
}
func (state *State) PushRegexCapturesFrame() {
state.regexCapturesByFrame.PushFront(lib.MakeEmptyCaptures())
state.regexCapturesByFrame = append([][]string{lib.MakeEmptyCaptures()}, state.regexCapturesByFrame...)
}
func (state *State) PopRegexCapturesFrame() {
// There is no PopFront
state.regexCapturesByFrame.Remove(state.regexCapturesByFrame.Front())
state.regexCapturesByFrame = state.regexCapturesByFrame[1:]
}

View file

@ -56,7 +56,6 @@
package regtest
import (
"container/list"
"fmt"
"os"
"path/filepath"
@ -110,8 +109,8 @@ type RegTester struct {
casePassCount int
caseFailCount int
failDirNames *list.List
failCaseNames *list.List
failDirNames []string
failCaseNames []string
firstNFailsToShow int
}
@ -132,8 +131,8 @@ func NewRegTester(
directoryFailCount: 0,
casePassCount: 0,
caseFailCount: 0,
failDirNames: list.New(),
failCaseNames: list.New(),
failDirNames: make([]string, 0),
failCaseNames: make([]string, 0),
firstNFailsToShow: firstNFailsToShow,
}
}
@ -182,13 +181,13 @@ func (regtester *RegTester) Execute(
regtester.executeSinglePath(path)
}
if regtester.failCaseNames.Len() > 0 && regtester.firstNFailsToShow > 0 {
if len(regtester.failCaseNames) > 0 && regtester.firstNFailsToShow > 0 {
fmt.Println()
fmt.Println("RERUNS OF FIRST FAILED CASE FILES:")
verbosityLevel := 3
i := 0
for e := regtester.failCaseNames.Front(); e != nil; e = e.Next() {
regtester.executeSingleCmdFile(e.Value.(string), verbosityLevel)
for _, e := range regtester.failCaseNames {
regtester.executeSingleCmdFile(e, verbosityLevel)
i++
if i >= regtester.firstNFailsToShow {
break
@ -196,11 +195,11 @@ func (regtester *RegTester) Execute(
}
}
if !regtester.plainMode && regtester.failDirNames.Len() > 0 {
if !regtester.plainMode && len(regtester.failDirNames) > 0 {
fmt.Println()
fmt.Println("FAILED CASE DIRECTORIES:")
for e := regtester.failDirNames.Front(); e != nil; e = e.Next() {
fmt.Printf(" %s/\n", e.Value.(string))
for _, e := range regtester.failDirNames {
fmt.Printf(" %s/\n", e)
}
}
@ -248,7 +247,7 @@ func (regtester *RegTester) executeSinglePath(
regtester.directoryPassCount++
} else {
regtester.directoryFailCount++
regtester.failDirNames.PushBack(path)
regtester.failDirNames = append(regtester.failDirNames, path)
}
}
return passed
@ -260,7 +259,7 @@ func (regtester *RegTester) executeSinglePath(
regtester.casePassCount++
} else {
regtester.caseFailCount++
regtester.failCaseNames.PushBack(path)
regtester.failCaseNames = append(regtester.failCaseNames, path)
}
return passed
}
@ -478,8 +477,7 @@ func (regtester *RegTester) executeSingleCmdFile(
// Copy any files requested by the test. (Most don't; some do, e.g. those
// which test the write-in-place logic of mlr -I.)
for pe := preCopySrcDestPairs.Front(); pe != nil; pe = pe.Next() {
pair := pe.Value.(stringPair)
for _, pair := range preCopySrcDestPairs {
src := pair.first
dst := pair.second
if verbosityLevel >= 3 {
@ -564,8 +562,7 @@ func (regtester *RegTester) executeSingleCmdFile(
}
}
for pe := postCompareExpectedActualPairs.Front(); pe != nil; pe = pe.Next() {
pair := pe.Value.(stringPair)
for _, pair := range postCompareExpectedActualPairs {
expectedFileName := pair.first
actualFileName := pair.second
@ -686,8 +683,7 @@ func (regtester *RegTester) executeSingleCmdFile(
// Compare any additional output files. Most test cases don't have
// these (just stdout/stderr), but some do: for example, those which
// test the tee verb/function.
for pe := postCompareExpectedActualPairs.Front(); pe != nil; pe = pe.Next() {
pair := pe.Value.(stringPair)
for _, pair := range postCompareExpectedActualPairs {
expectedFileName := pair.first
actualFileName := pair.second
ok, expectedContents, actualContents, err := regtester.compareFiles(expectedFileName, actualFileName, caseDir)
@ -725,8 +721,7 @@ func (regtester *RegTester) executeSingleCmdFile(
}
// Clean up any requested file-copies so that we're git-clean after the regression-test run.
for pe := preCopySrcDestPairs.Front(); pe != nil; pe = pe.Next() {
pair := pe.Value.(stringPair)
for _, pair := range preCopySrcDestPairs {
dst := pair.second
os.Remove(dst)
if verbosityLevel >= 3 {
@ -735,8 +730,7 @@ func (regtester *RegTester) executeSingleCmdFile(
}
// Clean up any extra output files so that we're git-clean after the regression-test run.
for pe := postCompareExpectedActualPairs.Front(); pe != nil; pe = pe.Next() {
pair := pe.Value.(stringPair)
for _, pair := range postCompareExpectedActualPairs {
actualFileName := pair.second
os.Remove(actualFileName)
if verbosityLevel >= 3 {
@ -868,12 +862,13 @@ func (regtester *RegTester) loadEnvFile(
func (regtester *RegTester) loadStringPairFile(
filename string,
caseDir string,
) (*list.List, error) {
) ([]stringPair, error) {
pairs := make([]stringPair, 0)
// If the file doesn't exist that's the normal case -- most cases do not
// have a .precopy or .postcmp file.
_, err := os.Stat(filename)
if os.IsNotExist(err) {
return list.New(), nil
return pairs, nil
}
// If the file does exist and isn't loadable, that's an error.
@ -882,7 +877,7 @@ func (regtester *RegTester) loadStringPairFile(
return nil, err
}
pairs := list.New()
pairs = make([]stringPair, 0)
lines := strings.Split(contents, "\n")
for _, line := range lines {
line = strings.TrimSuffix(line, "\r")
@ -897,7 +892,7 @@ func (regtester *RegTester) loadStringPairFile(
)
}
pair := stringPair{first: fields[0], second: fields[1]}
pairs.PushBack(pair)
pairs = append(pairs, pair)
}
return pairs, nil
}