window-keeper util class

This commit is contained in:
John Kerl 2022-01-18 08:29:23 -05:00
parent 9a43a1dcd5
commit cd8b714dc8
3 changed files with 228 additions and 0 deletions

1
.vimrc
View file

@ -1,3 +1,4 @@
map \d :w<C-m>:!clear;echo Building ...; echo; make mlr<C-m>
map \f :w<C-m>:!clear;echo Building ...; echo; make ut<C-m>
map \r :w<C-m>:!clear;echo Building ...; echo; make ut-scan ut-mlv<C-m>
map \t :w<C-m>:!clear;go test github.com/johnkerl/miller/internal/pkg/transformers/...<C-m>

View file

@ -0,0 +1,70 @@
package utils
import (
"github.com/johnkerl/miller/internal/pkg/lib"
)
// WindowKeeper is a sliding-window container, nominally for use by mlr step,
// for holding a number of records before the current one, the current one, and
// a number of records after. The payload is interface{}, not *mlrval.Mlrmap,
// for ease of unit-testing -- as well as since nothing here inspects the
// payload, so this code could be repurposed.
type WindowKeeper struct {
numBackward int
numForward int
recordsBackward []interface{}
currentRecord interface{}
recordsForward []interface{}
}
func NewWindowKeeper(
numBackward int,
numForward int,
) *WindowKeeper {
return &WindowKeeper{
numBackward: numBackward,
numForward: numForward,
recordsBackward: make([]interface{}, numBackward),
currentRecord: nil,
recordsForward: make([]interface{}, numForward),
}
}
func (wk *WindowKeeper) IngestRecord(
inrec interface{},
) {
for i := wk.numBackward - 1; i > 0; i-- {
wk.recordsBackward[i] = wk.recordsBackward[i-1]
}
if wk.numBackward > 0 {
wk.recordsBackward[0] = wk.currentRecord
}
if wk.numForward > 0 {
wk.currentRecord = wk.recordsForward[0]
for i := 0; i < wk.numForward-1; i++ {
wk.recordsForward[i] = wk.recordsForward[i+1]
}
wk.recordsForward[wk.numForward-1] = inrec
} else {
wk.currentRecord = inrec
}
}
// GetRecord maps a user-visible indexing ..., -3, -2, -1, 0, 1, 2, 3, ...
// into this struct's zero-index array storage.
func (wk *WindowKeeper) GetRecord(
index int,
) interface{} {
if index == 0 {
return wk.currentRecord
} else if index > 0 {
lib.InternalCodingErrorIf(index > wk.numForward)
return wk.recordsForward[index-1]
} else {
index = -index
lib.InternalCodingErrorIf(index > wk.numBackward)
return wk.recordsBackward[index-1]
}
}

View file

@ -0,0 +1,157 @@
package utils
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test00(t *testing.T) {
wk := NewWindowKeeper(0, 0)
wk.IngestRecord("a")
assert.Equal(t, "a", wk.GetRecord(0).(string))
wk.IngestRecord("b")
assert.Equal(t, "b", wk.GetRecord(0).(string))
}
func Test10(t *testing.T) {
wk := NewWindowKeeper(1, 0)
wk.IngestRecord("a")
assert.Equal(t, "a", wk.GetRecord(0).(string))
assert.Equal(t, nil, wk.GetRecord(-1))
wk.IngestRecord("b")
assert.Equal(t, "b", wk.GetRecord(0).(string))
assert.Equal(t, "a", wk.GetRecord(-1).(string))
wk.IngestRecord("c")
assert.Equal(t, "c", wk.GetRecord(0).(string))
assert.Equal(t, "b", wk.GetRecord(-1).(string))
}
func Test20(t *testing.T) {
wk := NewWindowKeeper(2, 0)
wk.IngestRecord("a")
assert.Equal(t, "a", wk.GetRecord(0).(string))
assert.Equal(t, nil, wk.GetRecord(-1))
assert.Equal(t, nil, wk.GetRecord(-2))
wk.IngestRecord("b")
assert.Equal(t, "b", wk.GetRecord(0).(string))
assert.Equal(t, "a", wk.GetRecord(-1).(string))
assert.Equal(t, nil, wk.GetRecord(-2))
wk.IngestRecord("c")
assert.Equal(t, "c", wk.GetRecord(0).(string))
assert.Equal(t, "b", wk.GetRecord(-1).(string))
assert.Equal(t, "a", wk.GetRecord(-2).(string))
wk.IngestRecord("d")
assert.Equal(t, "d", wk.GetRecord(0).(string))
assert.Equal(t, "c", wk.GetRecord(-1).(string))
assert.Equal(t, "b", wk.GetRecord(-2).(string))
}
func Test01(t *testing.T) {
wk := NewWindowKeeper(0, 1)
wk.IngestRecord("a")
assert.Equal(t, "a", wk.GetRecord(1).(string))
assert.Equal(t, nil, wk.GetRecord(0))
wk.IngestRecord("b")
assert.Equal(t, "b", wk.GetRecord(1).(string))
assert.Equal(t, "a", wk.GetRecord(0).(string))
wk.IngestRecord("c")
assert.Equal(t, "c", wk.GetRecord(1).(string))
assert.Equal(t, "b", wk.GetRecord(0).(string))
}
func Test02(t *testing.T) {
wk := NewWindowKeeper(0, 2)
wk.IngestRecord("a")
assert.Equal(t, "a", wk.GetRecord(2).(string))
assert.Equal(t, nil, wk.GetRecord(1))
assert.Equal(t, nil, wk.GetRecord(0))
wk.IngestRecord("b")
assert.Equal(t, "b", wk.GetRecord(2).(string))
assert.Equal(t, "a", wk.GetRecord(1).(string))
assert.Equal(t, nil, wk.GetRecord(0))
wk.IngestRecord("c")
assert.Equal(t, "c", wk.GetRecord(2).(string))
assert.Equal(t, "b", wk.GetRecord(1).(string))
assert.Equal(t, "a", wk.GetRecord(0).(string))
wk.IngestRecord("d")
assert.Equal(t, "d", wk.GetRecord(2).(string))
assert.Equal(t, "c", wk.GetRecord(1).(string))
assert.Equal(t, "b", wk.GetRecord(0).(string))
}
func Test32(t *testing.T) {
wk := NewWindowKeeper(3, 2)
wk.IngestRecord("a")
assert.Equal(t, "a", wk.GetRecord(2).(string))
assert.Equal(t, nil, wk.GetRecord(1))
assert.Equal(t, nil, wk.GetRecord(0))
assert.Equal(t, nil, wk.GetRecord(-1))
assert.Equal(t, nil, wk.GetRecord(-2))
assert.Equal(t, nil, wk.GetRecord(-3))
wk.IngestRecord("b")
assert.Equal(t, "b", wk.GetRecord(2).(string))
assert.Equal(t, "a", wk.GetRecord(1).(string))
assert.Equal(t, nil, wk.GetRecord(0))
assert.Equal(t, nil, wk.GetRecord(-1))
assert.Equal(t, nil, wk.GetRecord(-2))
assert.Equal(t, nil, wk.GetRecord(-3))
wk.IngestRecord("c")
assert.Equal(t, "c", wk.GetRecord(2).(string))
assert.Equal(t, "b", wk.GetRecord(1).(string))
assert.Equal(t, "a", wk.GetRecord(0).(string))
assert.Equal(t, nil, wk.GetRecord(-1))
assert.Equal(t, nil, wk.GetRecord(-2))
assert.Equal(t, nil, wk.GetRecord(-3))
wk.IngestRecord("d")
assert.Equal(t, "d", wk.GetRecord(2).(string))
assert.Equal(t, "c", wk.GetRecord(1).(string))
assert.Equal(t, "b", wk.GetRecord(0).(string))
assert.Equal(t, "a", wk.GetRecord(-1).(string))
assert.Equal(t, nil, wk.GetRecord(-2))
assert.Equal(t, nil, wk.GetRecord(-3))
wk.IngestRecord("e")
assert.Equal(t, "e", wk.GetRecord(2).(string))
assert.Equal(t, "d", wk.GetRecord(1).(string))
assert.Equal(t, "c", wk.GetRecord(0).(string))
assert.Equal(t, "b", wk.GetRecord(-1).(string))
assert.Equal(t, "a", wk.GetRecord(-2).(string))
assert.Equal(t, nil, wk.GetRecord(-3))
wk.IngestRecord("f")
assert.Equal(t, "f", wk.GetRecord(2).(string))
assert.Equal(t, "e", wk.GetRecord(1).(string))
assert.Equal(t, "d", wk.GetRecord(0).(string))
assert.Equal(t, "c", wk.GetRecord(-1).(string))
assert.Equal(t, "b", wk.GetRecord(-2).(string))
assert.Equal(t, "a", wk.GetRecord(-3).(string))
wk.IngestRecord("g")
assert.Equal(t, "g", wk.GetRecord(2).(string))
assert.Equal(t, "f", wk.GetRecord(1).(string))
assert.Equal(t, "e", wk.GetRecord(0).(string))
assert.Equal(t, "d", wk.GetRecord(-1).(string))
assert.Equal(t, "c", wk.GetRecord(-2).(string))
assert.Equal(t, "b", wk.GetRecord(-3).(string))
}