mirror of
https://github.com/sjwhitworth/golearn.git
synced 2025-04-30 13:48:57 +08:00
123 lines
2.9 KiB
Go
123 lines
2.9 KiB
Go
package base
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
)
|
|
|
|
// Ponds contain a particular number of rows of
|
|
// a particular number of Attributes, all of a given type.
|
|
type Pond struct {
|
|
threadNo uint32
|
|
parent DataGrid
|
|
attributes []Attribute
|
|
size int
|
|
alloc [][]byte
|
|
maxRow int
|
|
}
|
|
|
|
func (p *Pond) String() string {
|
|
if len(p.alloc) > 1 {
|
|
return fmt.Sprintf("Pond(%d attributes\n thread: %d\n size: %d\n)", len(p.attributes), p.threadNo, p.size)
|
|
}
|
|
return fmt.Sprintf("Pond(%d attributes\n thread: %d\n size: %d\n %d \n)", len(p.attributes), p.threadNo, p.size, p.alloc[0][0:60])
|
|
}
|
|
|
|
// PondStorageRef is a reference to a particular set
|
|
// of allocated rows within a Pond
|
|
type PondStorageRef struct {
|
|
Storage []byte
|
|
Rows int
|
|
}
|
|
|
|
// RowSize returns the size of each row in bytes
|
|
func (p *Pond) RowSize() int {
|
|
return len(p.attributes) * p.size
|
|
}
|
|
|
|
// Attributes returns a slice of Attributes in this Pond
|
|
func (p *Pond) Attributes() []Attribute {
|
|
return p.attributes
|
|
}
|
|
|
|
// Storage returns a slice of PondStorageRefs which can
|
|
// be used to access the memory in this pond.
|
|
func (p *Pond) Storage() []PondStorageRef {
|
|
ret := make([]PondStorageRef, len(p.alloc))
|
|
rowSize := p.RowSize()
|
|
for i, b := range p.alloc {
|
|
ret[i] = PondStorageRef{b, len(b) / rowSize}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (p *Pond) resolveBlock(col int, row int) (int, int) {
|
|
|
|
if len(p.alloc) == 0 {
|
|
panic("No blocks to resolve")
|
|
}
|
|
|
|
// Find where in the pond the byte is
|
|
byteOffset := row*p.RowSize() + col*p.size
|
|
curOffset := 0
|
|
curBlock := 0
|
|
blockOffset := 0
|
|
for {
|
|
if curBlock >= len(p.alloc) {
|
|
panic("Don't have enough blocks to fulfill")
|
|
}
|
|
|
|
// Rows are not allowed to span blocks
|
|
blockAdd := len(p.alloc[curBlock])
|
|
blockAdd -= blockAdd % p.RowSize()
|
|
|
|
// Case 1: we need to skip this allocation
|
|
if curOffset+blockAdd < byteOffset {
|
|
curOffset += blockAdd
|
|
curBlock++
|
|
} else {
|
|
blockOffset = byteOffset - curOffset
|
|
break
|
|
}
|
|
}
|
|
|
|
return curBlock, blockOffset
|
|
}
|
|
|
|
func (p *Pond) set(col int, row int, val []byte) {
|
|
|
|
// Double-check the length
|
|
if len(val) != p.size {
|
|
panic(fmt.Sprintf("Tried to call set() with %d bytes, should be %d", len(val), p.size))
|
|
}
|
|
|
|
// Find where in the pond the byte is
|
|
curBlock, blockOffset := p.resolveBlock(col, row)
|
|
|
|
// Copy the value in
|
|
copied := copy(p.alloc[curBlock][blockOffset:], val)
|
|
if copied != p.size {
|
|
panic(fmt.Sprintf("set() terminated by only copying %d bytes into the current block (should be %d). Check EDF allocation", copied, p.size))
|
|
}
|
|
|
|
row++
|
|
if row > p.maxRow {
|
|
p.maxRow = row
|
|
}
|
|
}
|
|
|
|
func (p *Pond) get(col int, row int) []byte {
|
|
curBlock, blockOffset := p.resolveBlock(col, row)
|
|
return p.alloc[curBlock][blockOffset : blockOffset+p.size]
|
|
}
|
|
|
|
func (p *Pond) appendToRowBuf(row int, buffer *bytes.Buffer) {
|
|
for i, a := range p.attributes {
|
|
postfix := " "
|
|
if i == len(p.attributes)-1 {
|
|
postfix = ""
|
|
}
|
|
buffer.WriteString(fmt.Sprintf("%s%s", a.GetStringFromSysVal(p.get(i, row)), postfix))
|
|
}
|
|
}
|