mirror of
https://github.com/bloeys/nterm.git
synced 2025-12-29 14:38:19 +00:00
Ring buffer iterator
This commit is contained in:
2
main.go
2
main.go
@ -284,6 +284,8 @@ func (p *program) MainUpdate() {
|
|||||||
var newPosNewLines int64
|
var newPosNewLines int64
|
||||||
w, _ := p.GridSize()
|
w, _ := p.GridSize()
|
||||||
if mouseWheelYNorm < 0 {
|
if mouseWheelYNorm < 0 {
|
||||||
|
// @TODO This is wrong because it deals with data as a normal array while its a ring buffer
|
||||||
|
|
||||||
newPosNewLines, _ = find_n_lines_index(p.textBuf.Data, p.scrollPos, p.scrollSpd*mouseWheelYNorm-1, int64(w))
|
newPosNewLines, _ = find_n_lines_index(p.textBuf.Data, p.scrollPos, p.scrollSpd*mouseWheelYNorm-1, int64(w))
|
||||||
} else {
|
} else {
|
||||||
newPosNewLines, _ = find_n_lines_index(p.textBuf.Data, p.scrollPos, p.scrollSpd*mouseWheelYNorm, int64(w))
|
newPosNewLines, _ = find_n_lines_index(p.textBuf.Data, p.scrollPos, p.scrollSpd*mouseWheelYNorm, int64(w))
|
||||||
|
|||||||
120
ring/ring.go
120
ring/ring.go
@ -96,6 +96,8 @@ func clamp[T constraints.Ordered](x, min, max T) T {
|
|||||||
// If Start+Len>Cap then the first slice contains the data from Start till Cap, and the second slice contains data from Zero till Start+Len-Cap (basically the remaining elements to reach Len in total)
|
// If Start+Len>Cap then the first slice contains the data from Start till Cap, and the second slice contains data from Zero till Start+Len-Cap (basically the remaining elements to reach Len in total)
|
||||||
//
|
//
|
||||||
// This function does NOT copy. Any changes on the returned slices will reflect on the buffer Data
|
// This function does NOT copy. Any changes on the returned slices will reflect on the buffer Data
|
||||||
|
//
|
||||||
|
// Note: Views become invalid when a write/insert is done on the buffer
|
||||||
func (b *Buffer[T]) Views() (v1, v2 []T) {
|
func (b *Buffer[T]) Views() (v1, v2 []T) {
|
||||||
|
|
||||||
if b.Start+b.Len <= b.Cap {
|
if b.Start+b.Len <= b.Cap {
|
||||||
@ -107,6 +109,17 @@ func (b *Buffer[T]) Views() (v1, v2 []T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Buffer[T]) Iterator() Iterator[T] {
|
||||||
|
|
||||||
|
v1, v2 := b.Views()
|
||||||
|
return Iterator[T]{
|
||||||
|
V1: v1,
|
||||||
|
V2: v2,
|
||||||
|
Curr: 0,
|
||||||
|
InV1: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewBuffer[T any](capacity uint64) *Buffer[T] {
|
func NewBuffer[T any](capacity uint64) *Buffer[T] {
|
||||||
|
|
||||||
return &Buffer[T]{
|
return &Buffer[T]{
|
||||||
@ -116,3 +129,110 @@ func NewBuffer[T any](capacity uint64) *Buffer[T] {
|
|||||||
Cap: int64(capacity),
|
Cap: int64(capacity),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterator provides a way of iterating and indexing values of a ring buffer as if it was a flat array
|
||||||
|
// without having to deal with wrapping and so on.
|
||||||
|
//
|
||||||
|
// Indices used are all relative to 'Buffer.Start'
|
||||||
|
type Iterator[T any] struct {
|
||||||
|
V1 []T
|
||||||
|
V2 []T
|
||||||
|
|
||||||
|
// Curr is the index of the element that will be returned on Next()
|
||||||
|
Curr int64
|
||||||
|
InV1 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the value at Iterator.Curr and done=false
|
||||||
|
//
|
||||||
|
// If there are no more values to return the default value is returned for v and done=true
|
||||||
|
func (it *Iterator[T]) Next() (v T, done bool) {
|
||||||
|
|
||||||
|
if it.InV1 {
|
||||||
|
|
||||||
|
v = it.V1[it.Curr]
|
||||||
|
|
||||||
|
it.Curr++
|
||||||
|
if it.Curr >= int64(len(it.V1)) {
|
||||||
|
it.Curr = 0
|
||||||
|
it.InV1 = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if it.Curr >= int64(len(it.V2)) {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
v = it.V2[it.Curr]
|
||||||
|
it.Curr++
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the value at Iterator.Curr-1 and done=false
|
||||||
|
//
|
||||||
|
// If there are no more values to return the default value is returned for v and done=true
|
||||||
|
func (it *Iterator[T]) Prev() (v T, done bool) {
|
||||||
|
|
||||||
|
if it.InV1 {
|
||||||
|
|
||||||
|
if it.Curr <= 0 {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Curr--
|
||||||
|
v = it.V1[it.Curr]
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Curr--
|
||||||
|
if it.Curr < 0 {
|
||||||
|
it.InV1 = true
|
||||||
|
it.Curr = int64(len(it.V1))
|
||||||
|
return it.Prev()
|
||||||
|
}
|
||||||
|
|
||||||
|
v = it.V2[it.Curr]
|
||||||
|
|
||||||
|
return v, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GotoStart adjusts the iterator such that the following Next() call returns the value at index=0
|
||||||
|
// and the next Prev() call returns done=true
|
||||||
|
func (it *Iterator[T]) GotoStart() {
|
||||||
|
it.Curr = 0
|
||||||
|
it.InV1 = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GotoIndex goes to the index n relative to Buffer.Start
|
||||||
|
func (it *Iterator[T]) GotoIndex(n int64) {
|
||||||
|
|
||||||
|
if n <= 0 {
|
||||||
|
it.GotoStart()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
v1Len := int64(len(it.V1))
|
||||||
|
if n < v1Len {
|
||||||
|
it.Curr = n
|
||||||
|
it.InV1 = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n -= v1Len
|
||||||
|
if n < int64(len(it.V2)) {
|
||||||
|
it.Curr = n
|
||||||
|
it.InV1 = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
it.GotoEnd()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GotoEnd adjusts the iterator such that the following Prev() call returns the value at index=Len-1
|
||||||
|
// and the following Next() call returns done=true
|
||||||
|
func (it *Iterator[T]) GotoEnd() {
|
||||||
|
it.Curr = int64(len(it.V2))
|
||||||
|
it.InV1 = false
|
||||||
|
}
|
||||||
|
|||||||
@ -89,6 +89,95 @@ func TestRing(t *testing.T) {
|
|||||||
CheckArr(t, []int{5, 6, 8, 8}, b2.Data)
|
CheckArr(t, []int{5, 6, 8, 8}, b2.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIterator(t *testing.T) {
|
||||||
|
|
||||||
|
// Only v1 set
|
||||||
|
b := ring.NewBuffer[int](4)
|
||||||
|
b.Write(1, 2)
|
||||||
|
|
||||||
|
got := []int{}
|
||||||
|
ans := []int{1, 2}
|
||||||
|
it := b.Iterator()
|
||||||
|
for v, done := it.Next(); !done; v, done = it.Next() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{2, 1}
|
||||||
|
for v, done := it.Prev(); !done; v, done = it.Prev() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{1, 2}
|
||||||
|
it.GotoStart()
|
||||||
|
for v, done := it.Next(); !done; v, done = it.Next() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
// V1 and v2 set
|
||||||
|
b.Write(3, 4, 5, 6)
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{3, 4, 5, 6}
|
||||||
|
it = b.Iterator()
|
||||||
|
for v, done := it.Next(); !done; v, done = it.Next() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
it.GotoEnd()
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{6, 5, 4, 3}
|
||||||
|
for v, done := it.Prev(); !done; v, done = it.Prev() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
// GotoIndex
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{5, 6}
|
||||||
|
it.GotoIndex(2)
|
||||||
|
for v, done := it.Next(); !done; v, done = it.Next() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{4, 3}
|
||||||
|
it.GotoIndex(2)
|
||||||
|
for v, done := it.Prev(); !done; v, done = it.Prev() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{}
|
||||||
|
it.GotoIndex(-100)
|
||||||
|
for v, done := it.Prev(); !done; v, done = it.Prev() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{6, 5, 4, 3}
|
||||||
|
it.GotoIndex(100)
|
||||||
|
for v, done := it.Prev(); !done; v, done = it.Prev() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
|
||||||
|
got = []int{}
|
||||||
|
ans = []int{}
|
||||||
|
it.GotoIndex(100)
|
||||||
|
for v, done := it.Next(); !done; v, done = it.Next() {
|
||||||
|
got = append(got, v)
|
||||||
|
}
|
||||||
|
CheckArr(t, ans, got)
|
||||||
|
}
|
||||||
|
|
||||||
func Check[T comparable](t *testing.T, expected, got T) {
|
func Check[T comparable](t *testing.T, expected, got T) {
|
||||||
if got != expected {
|
if got != expected {
|
||||||
t.Fatalf("Expected %v but got %v\n", expected, got)
|
t.Fatalf("Expected %v but got %v\n", expected, got)
|
||||||
|
|||||||
Reference in New Issue
Block a user