ringbuffer

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Dec 28, 2024 License: MIT Imports: 1 Imported by: 0

README

Super simple fixed length FIFO ring buffer in Go.

Documentation

Overview

Package provides fixed length FIFO ring buffer functionality.

You can use a generic data structure with methods, which is forced to use slices due to Go language limitations (no generic array lengths):

b := ringbuffer.New[int](5)
b.Push(1)
b.Push(2)
v1, _ := b.Pop()
v2, _ := b.Pop()
fmt.Printf("%d %d\n", v1, v2)

Or you can use generic functions with your own state variables. Here you can use plain arrays and integer types of arbitrary size:

var buf [5]int
var read int8
var write int8

ringbuffer.Push(buf[:], read, &write, 1)
ringbuffer.Push(buf[:], read, &write, 2)
v1, _ := ringbuffer.Pop(buf[:], &read, write)
v2, _ := ringbuffer.Pop(buf[:], &read, write)
fmt.Printf("%d %d\n", v1, v2)

The logic is the simplest implementation straight from wikipedia: https://en.wikipedia.org/wiki/Circular_buffer. In short: there are read and write pointers as integer indices and a buffer of capacity+1 space. An extra element is reserved to distinguish between full/empty state. When using plain generic functions with smaller integer types, be aware of integer overflows. No care taken to prevent these.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Cap

func Cap[T any](slice []T) int

How many elements a buffer can store?

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	var buf [10]int
	fmt.Printf("%d\n", ringbuffer.Cap(buf[:]))
}
Output:

9

func Len

func Len[T any, U constraints.Integer](slice []T, read, write U) int

How many elements are currently stored in the buffer?

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	var buf [10]int
	var read int8
	var write int8

	l1 := ringbuffer.Len(buf[:], read, write)
	ringbuffer.Push(buf[:], read, &write, 1)
	l2 := ringbuffer.Len(buf[:], read, write)
	fmt.Printf("%d %d\n", l1, l2)
}
Output:

0 1

func Pop

func Pop[T any, U constraints.Integer](slice []T, read *U, write U) (T, bool)

Try to pop an element from the buffer.

Returns the popped element and true on success. Returns default value and false if there were no elements in the buffer.

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	var buf [5]int
	var read int8
	var write int8

	ringbuffer.Push(buf[:], read, &write, 1)
	ringbuffer.Push(buf[:], read, &write, 2)
	v1, _ := ringbuffer.Pop(buf[:], &read, write)
	v2, _ := ringbuffer.Pop(buf[:], &read, write)
	fmt.Printf("%d %d\n", v1, v2)
}
Output:

1 2

func Push

func Push[T any, U constraints.Integer](slice []T, read U, write *U, v T) bool

Push a new element to the buffer.

Returns true on success. Returns false if there is no free space and push failed.

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	var buf [5]int
	var read int8
	var write int8

	ringbuffer.Push(buf[:], read, &write, 1)
	ringbuffer.Push(buf[:], read, &write, 2)
	v1, _ := ringbuffer.Pop(buf[:], &read, write)
	v2, _ := ringbuffer.Pop(buf[:], &read, write)
	fmt.Printf("%d %d\n", v1, v2)
}
Output:

1 2

Types

type RingBuffer

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

Fixed length FIFO ring buffer.

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	// Using ringbuffer structure alone without the "New" function is fairly useless, but it's valid.
	var buf ringbuffer.RingBuffer[int]
	fmt.Printf("cap: %d, len: %d, pushed: %v\n", buf.Cap(), buf.Len(), buf.Push(5))
}
Output:

cap: 0, len: 0, pushed: false

func New

func New[T any](capacity int) RingBuffer[T]

Create a new buffer which can store capacity elements. The buffer is fixed in length and will not grow. It is a FIFO buffer.

Implementation detail: the buffer is implemented as two integer pointers and a slice of capacity+1 elements. One extra element is reserved to avoid ambiguous state where read and write pointers point to the same location and it might mean full or empty buffer. A bit of extra space wasted is traded for logical simplicity.

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	b := ringbuffer.New[int](5)
	b.Push(1)
	b.Push(2)
	v1, _ := b.Pop()
	v2, _ := b.Pop()
	fmt.Printf("%d %d\n", v1, v2)
}
Output:

1 2

func (RingBuffer[T]) Cap

func (b RingBuffer[T]) Cap() int

How many elements a buffer can store?

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	b := ringbuffer.New[int](5)
	fmt.Printf("%d\n", b.Cap())
}
Output:

5

func (RingBuffer[T]) Len

func (b RingBuffer[T]) Len() int

How many elements are currently stored in the buffer?

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	b := ringbuffer.New[int](5)
	l1 := b.Len()
	b.Push(1)
	l2 := b.Len()
	fmt.Printf("%d %d\n", l1, l2)
}
Output:

0 1

func (*RingBuffer[T]) Pop

func (b *RingBuffer[T]) Pop() (T, bool)

Try to pop an element from the buffer.

Returns the popped element and true on success. Returns default value and false if there were no elements in the buffer.

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	b := ringbuffer.New[int](5)
	b.Push(1)
	b.Push(2)
	v1, _ := b.Pop()
	v2, _ := b.Pop()
	fmt.Printf("%d %d\n", v1, v2)
}
Output:

1 2

func (*RingBuffer[T]) Push

func (b *RingBuffer[T]) Push(v T) bool

Push a new element to the buffer.

Returns true on success. Returns false if there is no free space and push failed.

Example
package main

import (
	"fmt"
	"github.com/nsf/ringbuffer"
)

func main() {
	b := ringbuffer.New[int](5)
	b.Push(1)
	b.Push(2)
	v1, _ := b.Pop()
	v2, _ := b.Pop()
	fmt.Printf("%d %d\n", v1, v2)
}
Output:

1 2

Jump to

Keyboard shortcuts

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