buf2d/buffer.go

147 lines
3.1 KiB
Go
Raw Permalink Normal View History

2020-10-01 13:14:36 +02:00
package buf2d
import (
"strings"
)
2022-03-31 12:37:35 +02:00
// Buffer is a 2-dimensional buffer
type Buffer[T any] struct {
data [][]T
2022-05-04 18:02:42 +02:00
x, y int
2022-03-31 12:37:35 +02:00
width int
height int
parent *Buffer[T]
StringFunc func(T) string
2020-10-01 13:14:36 +02:00
}
// NewBuffer makes a new buffer with the given dimensions
2022-03-31 12:37:35 +02:00
func NewBuffer[T any](width, height int, defaultValue T) *Buffer[T] {
b := make([][]T, height)
2020-10-01 13:37:58 +02:00
for y := range b {
2022-03-31 12:37:35 +02:00
b[y] = make([]T, width)
2020-10-01 13:37:58 +02:00
for x := range b[y] {
2022-03-31 12:37:35 +02:00
b[y][x] = defaultValue
2020-10-01 13:14:36 +02:00
}
}
2022-03-31 12:37:35 +02:00
return &Buffer[T]{
2022-05-04 18:02:42 +02:00
x: 0, y: 0,
2022-03-31 12:37:35 +02:00
data: b,
width: width,
height: height,
parent: nil,
StringFunc: MakeDefaultStringFunc[T](),
2020-10-01 13:14:36 +02:00
}
}
2022-05-04 18:02:42 +02:00
func (b *Buffer[T]) limX(x int) int {
2020-10-01 15:54:08 +02:00
return limit(x, 0, b.width-1)
}
2022-05-04 18:02:42 +02:00
func (b *Buffer[T]) limY(y int) int {
2020-10-01 15:54:08 +02:00
return limit(y, 0, b.height-1)
}
2022-03-31 12:37:35 +02:00
// Set sets the value at position (x,y) to c
func (b *Buffer[T]) Set(x, y int, v T) {
if b.width > 0 && b.height > 0 {
2022-05-04 18:02:42 +02:00
b.data[b.limY(y)][b.limX(x)] = v
}
2020-10-01 13:14:36 +02:00
}
2022-03-31 12:37:35 +02:00
// Get returns the value at position (x,y)
func (b *Buffer[T]) Get(x, y int) T {
2020-10-01 13:37:58 +02:00
return b.data[y][x]
2020-10-01 13:14:36 +02:00
}
2020-10-01 13:56:05 +02:00
// Size returns width and height of b
2022-03-31 12:37:35 +02:00
func (b *Buffer[T]) Size() (w, h int) {
2020-10-01 13:14:36 +02:00
return b.width, b.height
}
2020-10-01 13:56:05 +02:00
// Width returns the width of b
2022-03-31 12:37:35 +02:00
func (b *Buffer[T]) Width() int {
2020-10-01 13:14:36 +02:00
return b.width
}
2020-10-01 13:56:05 +02:00
// Height returns the height of b
2022-03-31 12:37:35 +02:00
func (b *Buffer[T]) Height() int {
2020-10-01 13:14:36 +02:00
return b.height
}
2022-05-04 18:06:24 +02:00
// Offset returns the offset of b relative to its parent buffer.
// Offset returns zeros if b has no parent
func (b *Buffer[T]) Offset() (x, y int) {
return b.x, b.y
}
2022-05-04 18:02:42 +02:00
// OffsetX returns the horizontal offset of b relative to its parent buffer.
// OffsetX returns 0 if b has no parent
func (b *Buffer[T]) OffsetX() int {
return b.x
}
// OffsetY returns the vertical offset of b relative to its parent buffer.
// OffsetY returns 0 if b has no parent
func (b *Buffer[T]) OffsetY() int {
return b.y
}
// ForEachLine calls f for each line in b
2022-04-02 11:33:59 +02:00
func (b *Buffer[T]) ForEachLine(f func(line int, content []T)) {
for line, content := range b.data {
f(line, content)
}
}
2022-05-04 18:02:42 +02:00
// ForEach calls f for every value in b
2022-03-31 12:37:35 +02:00
func (b *Buffer[T]) ForEach(f func(x, y int, v T)) {
2020-10-01 13:37:58 +02:00
for y, col := range b.data {
for x, v := range col {
f(x, y, v)
2020-10-01 13:14:36 +02:00
}
}
}
2022-03-31 12:37:35 +02:00
func (b *Buffer[T]) String() string {
2020-10-01 13:14:36 +02:00
s := new(strings.Builder)
2020-10-01 13:37:58 +02:00
for ci, col := range b.data {
for _, v := range col {
2022-03-31 12:37:35 +02:00
s.WriteString(b.StringFunc(v))
2020-10-01 13:14:36 +02:00
}
2020-10-01 13:37:58 +02:00
if ci != len(b.data)-1 {
2020-10-01 13:14:36 +02:00
s.WriteRune('\n')
}
}
return s.String()
}
// Sub returns a buffer which is completely contained in this buffer
// Modifying the main buffer or the sub buffer will modify the other one as well
// This method can be used recursively
// If the given dimensions don't fit in the parent buffer, it will be truncated
2022-03-31 12:37:35 +02:00
func (b *Buffer[T]) Sub(x, y, w, h int) *Buffer[T] {
2020-10-01 13:14:36 +02:00
// sanitize inputs
x = limit(x, 0, b.width-1)
y = limit(y, 0, b.height-1)
2022-04-02 17:33:52 +02:00
w = limit(w, 0, b.width-x)
h = limit(h, 0, b.height-y)
2020-10-01 13:14:36 +02:00
// make slice references
2022-03-31 12:37:35 +02:00
data := make([][]T, h)
2020-10-01 13:56:05 +02:00
for dy := 0; dy < h; dy++ {
col := b.data[y+dy]
2020-10-01 13:37:58 +02:00
data[dy] = col[x : x+w]
2020-10-01 13:14:36 +02:00
}
// make buffer
2022-03-31 12:37:35 +02:00
return &Buffer[T]{
2022-05-04 18:02:42 +02:00
x: x, y: y,
2022-03-31 12:37:35 +02:00
data: data,
width: w,
height: h,
parent: b,
StringFunc: b.StringFunc,
2020-10-01 13:14:36 +02:00
}
}