1
0
mirror of https://github.com/sjwhitworth/golearn.git synced 2025-04-30 13:48:57 +08:00
golearn/base/pond.go
2014-08-03 23:09:18 +01:00

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))
}
}