mirror of
https://github.com/sjwhitworth/golearn.git
synced 2025-04-26 13:49:14 +08:00
321 lines
7.6 KiB
Go
321 lines
7.6 KiB
Go
package base
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
)
|
|
|
|
// InstancesViews hide or re-order Attributes and rows from
|
|
// a given DataGrid to make it appear that they've been deleted.
|
|
type InstancesView struct {
|
|
src FixedDataGrid
|
|
attrs []AttributeSpec
|
|
rows map[int]int
|
|
classAttrs map[Attribute]bool
|
|
maskRows bool
|
|
}
|
|
|
|
func (v *InstancesView) addClassAttrsFromSrc(src FixedDataGrid) {
|
|
for _, a := range src.AllClassAttributes() {
|
|
matched := true
|
|
if v.attrs != nil {
|
|
matched = false
|
|
for _, b := range v.attrs {
|
|
if b.attr.Equals(a) {
|
|
matched = true
|
|
}
|
|
}
|
|
}
|
|
if matched {
|
|
v.classAttrs[a] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
func (v *InstancesView) resolveRow(origRow int) int {
|
|
if v.rows != nil {
|
|
if newRow, ok := v.rows[origRow]; !ok {
|
|
if v.maskRows {
|
|
return -1
|
|
}
|
|
} else {
|
|
return newRow
|
|
}
|
|
}
|
|
|
|
return origRow
|
|
|
|
}
|
|
|
|
// NewInstancesViewFromRows creates a new InstancesView from a source
|
|
// FixedDataGrid and row -> row mapping. The key of the rows map is the
|
|
// row as it exists within this mapping: for example an entry like 5 -> 1
|
|
// means that row 1 in src will appear at row 5 in the Instancesview.
|
|
//
|
|
// Rows are not masked in this implementation, meaning that all rows which
|
|
// are left unspecified appear as normal.
|
|
func NewInstancesViewFromRows(src FixedDataGrid, rows map[int]int) *InstancesView {
|
|
ret := &InstancesView{
|
|
src,
|
|
nil,
|
|
rows,
|
|
make(map[Attribute]bool),
|
|
false,
|
|
}
|
|
|
|
ret.addClassAttrsFromSrc(src)
|
|
return ret
|
|
}
|
|
|
|
// NewInstancesViewFromVisible creates a new InstancesView from a source
|
|
// FixedDataGrid, a slice of row numbers and a slice of Attributes.
|
|
//
|
|
// Only the rows specified will appear in this InstancesView, and they will
|
|
// appear in the same order they appear within the rows array.
|
|
//
|
|
// Only the Attributes specified will appear in this InstancesView. Retrieving
|
|
// Attribute specifications from this InstancesView will maintain their order.
|
|
func NewInstancesViewFromVisible(src FixedDataGrid, rows []int, attrs []Attribute) *InstancesView {
|
|
ret := &InstancesView{
|
|
src,
|
|
ResolveAttributes(src, attrs),
|
|
make(map[int]int),
|
|
make(map[Attribute]bool),
|
|
true,
|
|
}
|
|
|
|
for i, a := range rows {
|
|
ret.rows[i] = a
|
|
}
|
|
|
|
ret.addClassAttrsFromSrc(src)
|
|
return ret
|
|
}
|
|
|
|
// NewInstancesViewFromAttrs creates a new InstancesView from a source
|
|
// FixedDataGrid and a slice of Attributes.
|
|
//
|
|
// Only the Attributes specified will appear in this InstancesView.
|
|
func NewInstancesViewFromAttrs(src FixedDataGrid, attrs []Attribute) *InstancesView {
|
|
ret := &InstancesView{
|
|
src,
|
|
ResolveAttributes(src, attrs),
|
|
nil,
|
|
make(map[Attribute]bool),
|
|
false,
|
|
}
|
|
|
|
ret.addClassAttrsFromSrc(src)
|
|
return ret
|
|
}
|
|
|
|
// GetAttribute returns an Attribute specification matching an Attribute
|
|
// if it has not been filtered.
|
|
//
|
|
// The AttributeSpecs returned are the same as those returned by the
|
|
// source FixedDataGrid.
|
|
func (v *InstancesView) GetAttribute(a Attribute) (AttributeSpec, error) {
|
|
if a == nil {
|
|
return AttributeSpec{}, fmt.Errorf("Attribute can't be nil")
|
|
}
|
|
// Pass-through on nil
|
|
if v.attrs == nil {
|
|
return v.src.GetAttribute(a)
|
|
}
|
|
// Otherwise
|
|
for _, r := range v.attrs {
|
|
// If the attribute matches...
|
|
if r.GetAttribute().Equals(a) {
|
|
return r, nil
|
|
}
|
|
}
|
|
return AttributeSpec{}, fmt.Errorf("Requested Attribute has been filtered")
|
|
}
|
|
|
|
// AllAttributes returns every Attribute which hasn't been filtered.
|
|
func (v *InstancesView) AllAttributes() []Attribute {
|
|
|
|
if v.attrs == nil {
|
|
return v.src.AllAttributes()
|
|
}
|
|
|
|
ret := make([]Attribute, len(v.attrs))
|
|
|
|
for i, a := range v.attrs {
|
|
ret[i] = a.GetAttribute()
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
// AddClassAttribute adds the given Attribute to the set of defined
|
|
// class Attributes, if it hasn't been filtered.
|
|
func (v *InstancesView) AddClassAttribute(a Attribute) error {
|
|
// Check that this Attribute is defined
|
|
matched := false
|
|
for _, r := range v.AllAttributes() {
|
|
if r.Equals(a) {
|
|
matched = true
|
|
}
|
|
}
|
|
if !matched {
|
|
return fmt.Errorf("Attribute has been filtered")
|
|
}
|
|
|
|
v.classAttrs[a] = true
|
|
return nil
|
|
}
|
|
|
|
// RemoveClassAttribute removes the given Attribute from the set of
|
|
// class Attributes.
|
|
func (v *InstancesView) RemoveClassAttribute(a Attribute) error {
|
|
v.classAttrs[a] = false
|
|
return nil
|
|
}
|
|
|
|
// AllClassAttributes returns all the Attributes currently defined
|
|
// as being class Attributes.
|
|
func (v *InstancesView) AllClassAttributes() []Attribute {
|
|
ret := make([]Attribute, 0)
|
|
for a := range v.classAttrs {
|
|
if v.classAttrs[a] {
|
|
ret = append(ret, a)
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// Get returns a sequence of bytes stored under a given Attribute
|
|
// on a given row.
|
|
//
|
|
// IMPORTANT: The AttributeSpec is unverified, meaning it's possible
|
|
// to return values from Attributes filtered by this InstancesView
|
|
// if the underlying AttributeSpec is known.
|
|
func (v *InstancesView) Get(as AttributeSpec, row int) []byte {
|
|
// Change the row if necessary
|
|
row = v.resolveRow(row)
|
|
if row == -1 {
|
|
panic("Out of range")
|
|
}
|
|
return v.src.Get(as, row)
|
|
}
|
|
|
|
// MapOverRows, see DenseInstances.MapOverRows.
|
|
//
|
|
// IMPORTANT: MapOverRows is not guaranteed to be ordered, but this one
|
|
// especially so.
|
|
func (v *InstancesView) MapOverRows(as []AttributeSpec, rowFunc func([][]byte, int) (bool, error)) error {
|
|
if v.maskRows {
|
|
rowBuf := make([][]byte, len(as))
|
|
for r := range v.rows {
|
|
row := v.rows[r]
|
|
for i, a := range as {
|
|
rowBuf[i] = v.src.Get(a, row)
|
|
}
|
|
ok, err := rowFunc(rowBuf, r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
break
|
|
}
|
|
}
|
|
return nil
|
|
} else {
|
|
return v.src.MapOverRows(as, rowFunc)
|
|
}
|
|
}
|
|
|
|
// Size Returns the number of Attributes and rows this InstancesView
|
|
// contains.
|
|
func (v *InstancesView) Size() (int, int) {
|
|
// Get the original size
|
|
hSize, vSize := v.src.Size()
|
|
// Adjust to the number of defined Attributes
|
|
if v.attrs != nil {
|
|
hSize = len(v.attrs)
|
|
}
|
|
// Adjust to the number of defined rows
|
|
if v.rows != nil {
|
|
if v.maskRows {
|
|
vSize = len(v.rows)
|
|
} else if len(v.rows) > vSize {
|
|
vSize = len(v.rows)
|
|
}
|
|
}
|
|
return hSize, vSize
|
|
}
|
|
|
|
// String returns a human-readable summary of this InstancesView.
|
|
func (v *InstancesView) String() string {
|
|
var buffer bytes.Buffer
|
|
maxRows := 30
|
|
|
|
// Get all Attribute information
|
|
as := ResolveAllAttributes(v)
|
|
|
|
// Print header
|
|
cols, rows := v.Size()
|
|
buffer.WriteString("InstancesView with ")
|
|
buffer.WriteString(fmt.Sprintf("%d row(s) ", rows))
|
|
buffer.WriteString(fmt.Sprintf("%d attribute(s)\n", cols))
|
|
if v.attrs != nil {
|
|
buffer.WriteString(fmt.Sprintf("With defined Attribute view\n"))
|
|
}
|
|
if v.rows != nil {
|
|
buffer.WriteString(fmt.Sprintf("With defined Row view\n"))
|
|
}
|
|
if v.maskRows {
|
|
buffer.WriteString("Row masking on.\n")
|
|
}
|
|
buffer.WriteString(fmt.Sprintf("Attributes:\n"))
|
|
|
|
for _, a := range as {
|
|
prefix := "\t"
|
|
if v.classAttrs[a.attr] {
|
|
prefix = "*\t"
|
|
}
|
|
buffer.WriteString(fmt.Sprintf("%s%s\n", prefix, a.attr))
|
|
}
|
|
|
|
// Print data
|
|
if rows < maxRows {
|
|
maxRows = rows
|
|
}
|
|
buffer.WriteString("Data:")
|
|
for i := 0; i < maxRows; i++ {
|
|
buffer.WriteString("\t")
|
|
for _, a := range as {
|
|
val := v.Get(a, i)
|
|
buffer.WriteString(fmt.Sprintf("%s ", a.attr.GetStringFromSysVal(val)))
|
|
}
|
|
buffer.WriteString("\n")
|
|
}
|
|
|
|
missingRows := rows - maxRows
|
|
if missingRows != 0 {
|
|
buffer.WriteString(fmt.Sprintf("\t...\n%d row(s) undisplayed", missingRows))
|
|
} else {
|
|
buffer.WriteString("All rows displayed")
|
|
}
|
|
|
|
return buffer.String()
|
|
}
|
|
|
|
// RowString returns a string representation of a given row.
|
|
func (v *InstancesView) RowString(row int) string {
|
|
var buffer bytes.Buffer
|
|
as := ResolveAllAttributes(v)
|
|
first := true
|
|
for _, a := range as {
|
|
val := v.Get(a, row)
|
|
prefix := " "
|
|
if first {
|
|
prefix = ""
|
|
first = false
|
|
}
|
|
buffer.WriteString(fmt.Sprintf("%s%s", prefix, a.attr.GetStringFromSysVal(val)))
|
|
}
|
|
return buffer.String()
|
|
}
|