tailbuf

package
v0.48.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 12, 2024 License: MIT Imports: 1 Imported by: 0

Documentation

Overview

Package tailbuf contains a tail buffer Buf of fixed size that provides a window on the tail of the items written via Buf.Write. Start with tailbuf.New to create a Buf.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SliceNominal

func SliceNominal[T any](b *Buf[T], start, end int) []T

SliceNominal returns a slice into the nominal buffer, using the standard [inclusive:exclusive] slicing mechanics.

Boundary checking is relaxed. If the buffer is empty, the returned slice is empty. Otherwise, if the requested range is completely outside the bounds of the tail window, the returned slice is empty; if the range overlaps with the tail window, the returned slice contains the overlapping items. If strict boundary checking is important to you, use Buf.InBounds to check the start and end indices.

SliceNominal is approximately functionality equivalent to reslicing the result of Buf.Tail, but it may avoid wasteful copying (and has relaxed bounds checking).

buf := tailbuf.New[int](3).WriteAll(1, 2, 3)
a := buf.Tail()[0:2]
b := buf.SliceNominal(0, 2)
assert.Equal(t, a, b)

If start < 0, zero is used. SliceNominal panics if end is less than start.

func SliceTail

func SliceTail[T any](b *Buf[T], start, end int) []T

SliceTail returns a slice of the tail window, using the standard [inclusive:exclusive] slicing mechanics, but with permissive bounds checking. The slice is freshly allocated, so the caller is free to mutate it.

A call to SliceTail is equivalent to reslicing the result of Buf.Tail, but it may avoid unnecessary copying, depending on the state of Buf.

buf := tailbuf.New[int](3).WriteAll(1, 2, 3)
a := buf.Tail()[0:2]
b := buf.SliceTail(0, 2)
fmt.Println("a:", a, "b:", b)
// Output: a: [1 2] b: [1 2]

If Buf is empty, the returned slice is empty. Otherwise, if the requested range is completely outside the bounds of the tail window, the returned slice is empty; if the range overlaps with the tail window, the returned slice contains the overlapping items. If strict boundary checking is important, use Buf.InBounds to check the start and end indices.

SliceTail panics if start is negative or end is less than start.

See also: SliceNominal, Buf.Tail, Buf.Bounds, Buf.InBounds.

Types

type Buf

type Buf[T any] struct {
	// contains filtered or unexported fields
}

Buf is an append-only fixed-size circular buffer that provides a window on the tail of items written to the buffer. The zero value is technically usable, but not very useful. Instead, invoke tailbuf.New to create a Buf. Buf is not safe for concurrent use.

Note the terms "nominal buffer" and "tail window" (or just "window"). The nominal buffer is the complete list of items written to Buf via the Buf.Write or Buf.WriteAll methods. However, Buf drops the oldest items as it fills (which is the entire point of this package): the tail window is the subset of the nominal buffer that is currently available. Some of Buf's methods take arguments that are indices into the nominal buffer, for example SliceNominal.

func New

func New[T any](capacity int) *Buf[T]

New returns a new Buf with the specified capacity. It panics if capacity is less than 1.

func (*Buf[T]) Apply

func (b *Buf[T]) Apply(fn func(item T) T) *Buf[T]

Apply applies fn to each item in the tail window, in oldest-to-newest order. If Buf is empty, fn is not invoked. The buffer is returned for chaining.

buf := tailbuf.New[string](3)
buf.WriteAll("a", "b  ", "   c  ")
buf.Apply(strings.TrimSpace).Apply(strings.ToUpper)
fmt.Println(buf.Tail())
// Output: [A B C]

Using Apply is cheaper than getting the slice via Buf.Tail and applying fn manually, as it avoids the possible allocation of a new slice by Buf.Tail.

For more control, or to handle errors, use Buf.Do.

func (*Buf[T]) Back

func (b *Buf[T]) Back() T

Back returns the oldest item in the tail window. If Buf is empty, the zero value of T is returned.

func (*Buf[T]) Bounds

func (b *Buf[T]) Bounds() (start, end int)

Bounds returns the start and end indices of the tail window vs the nominal buffer. If the buffer is empty, start and end are both 0. The returned values are the same as Buf.Offset and Buf.Written.

func (*Buf[T]) Capacity

func (b *Buf[T]) Capacity() int

Capacity returns the capacity of Buf, which is the fixed size specified when the buffer was created.

func (*Buf[T]) Clear

func (b *Buf[T]) Clear() *Buf[T]

Clear removes all items from the buffer, zeroing all values. This is similar to Buf.Reset, but note that the value returned by Buf.Written is unchanged. The buffer is returned for chaining.

See also: Buf.Reset.

func (*Buf[T]) Do

func (b *Buf[T]) Do(ctx context.Context, fn func(ctx context.Context, item T, index, offset int) (T, error)) error

Do applies fn to each item in the tail window, in oldest-to-newest order, replacing each item with the value returned by successful invocation of fn. If fn returns an error, the item is not replaced. Execution is halted if any invocation of fn returns an error, and that error is returned to the caller. Thus a partial application of fn may occur.

If Buf is empty, fn is not invoked.

The index arg to fn is the index of the item in the tail window. You can use the offset arg to compute the index of the item in the nominal buffer.

nominalIndex := index + offset

REVISIT: Should index be the tailIndex instead?

The context is not checked for cancellation between iterations. The context should be checked in fn if desired.

func (*Buf[T]) DropBack

func (b *Buf[T]) DropBack()

DropBack removes the oldest item in the tail window. See also: Buf.PopBack.

func (*Buf[T]) DropBackN

func (b *Buf[T]) DropBackN(n int)

DropBackN removes the oldest n items from the tail, zeroing out the items.

func (*Buf[T]) Front

func (b *Buf[T]) Front() T

Front returns the newest item in the tail window. If Buf is empty, the zero value of T is returned.

func (*Buf[T]) InBounds

func (b *Buf[T]) InBounds(i int) bool

InBounds returns true if the index i of the nominal buffer is within the bounds of the tail window. That is to say, InBounds returns true if the ith item written to the buffer is still in the tail window.

func (*Buf[T]) Len

func (b *Buf[T]) Len() int

Len returns the number of items currently in the buffer.

func (*Buf[T]) Offset

func (b *Buf[T]) Offset() int

Offset returns the offset of the current window vs the nominal complete list of items written to the buffer. It is effectively the count of items that have slipped out of the tail window. If the buffer is empty, the returned offset is 0.

func (*Buf[T]) PopBack

func (b *Buf[T]) PopBack() T

PopBack removes and returns the oldest item in the tail window. If the buffer is empty, the zero value of T is returned.

func (*Buf[T]) PopBackN

func (b *Buf[T]) PopBackN(n int) []T

PopBackN removes and returns the oldest n items in the tail window. Any removed items are zeroed out from the buffer's internal window. On return, the slice (which is always freshly allocated) contains the removed items, in oldest-to-newest order, and Buf.Len is reduced by n. If n is greater than the number of items in the tail window, all items in the tail window are removed and returned.

func (*Buf[T]) PopFront

func (b *Buf[T]) PopFront() T

PopFront removes and returns the newest item in the tail window.

func (*Buf[T]) PopFrontN

func (b *Buf[T]) PopFrontN(n int) []T

PopFrontN removes and returns the newest n items in the tail window. Any removed items are zeroed out from the buffer's internal window. On return, the slice (which is always freshly allocated) contains the removed items, in oldest-to-newest order, and Buf.Len is reduced by n. If n is greater than the number of items in the tail window, all items in the tail window are removed and returned.

func (*Buf[T]) Reset

func (b *Buf[T]) Reset() *Buf[T]

Reset resets the buffer to its initial state, including the value returned by Buf.Written. The buffer is returned for chaining. Any items in the buffer are zeroed out.

See also: Buf.Clear.

func (*Buf[T]) Tail

func (b *Buf[T]) Tail() []T

Tail returns a slice containing the items currently in the buffer, in oldest-to-newest order. If possible, the returned slice shares the buffer's internal window, but a fresh slice is allocated if necessary. Thus you should copy the returned slice before modifying it, or instead use SliceTail.

func (*Buf[T]) Write

func (b *Buf[T]) Write(t T) *Buf[T]

Write appends t to the buffer. If the buffer fills, the oldest item is overwritten. The buffer is returned for chaining.

func (*Buf[T]) WriteAll

func (b *Buf[T]) WriteAll(a ...T) *Buf[T]

WriteAll appends items to the buffer. If the buffer fills, the oldest items are overwritten. The buffer is returned for chaining.

func (*Buf[T]) Written

func (b *Buf[T]) Written() int

Written returns the total number of items written to the buffer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL