This commit is contained in:
Josh Deprez 2021-09-23 15:32:57 +10:00
parent 8dc7583884
commit f4a6a1a249

View file

@ -1,28 +1,55 @@
package engine package engine
import (
"bytes"
"encoding/gob"
)
var _ interface { var _ interface {
Registrar Registrar
Scanner Scanner
gob.GobDecoder
gob.GobEncoder
} = &Container{} } = &Container{}
func init() {
gob.Register(&Container{})
}
// Container contains many components, in order. // Container contains many components, in order.
type Container struct { type Container struct {
Items []interface{} items []interface{}
free map[int]struct{} free map[int]struct{}
reverse map[interface{}]int reverse map[interface{}]int
} }
func MakeContainer(items ...interface{}) *Container { func MakeContainer(items ...interface{}) *Container {
c := &Container{Items: items} c := &Container{items: items}
c.Prepare(nil) c.Prepare(nil)
return c return c
} }
func (c *Container) GobDecode(in []byte) error {
dec := gob.NewDecoder(bytes.NewReader(in))
if err := dec.Decode(&c.items); err != nil {
return err
}
c.free, c.reverse = nil, nil
return c.Prepare(nil)
}
func (c *Container) GobEncode() ([]byte, error) {
var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(c.items); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func (c *Container) Prepare(*Game) error { func (c *Container) Prepare(*Game) error {
if c.reverse == nil { if c.reverse == nil {
c.reverse = make(map[interface{}]int, len(c.Items)) c.reverse = make(map[interface{}]int, len(c.items))
for i, x := range c.Items { for i, x := range c.items {
c.reverse[x] = i c.reverse[x] = i
} }
} }
@ -34,7 +61,7 @@ func (c *Container) Prepare(*Game) error {
// Scan visits every component in the container. // Scan visits every component in the container.
func (c *Container) Scan(visit func(interface{}) error) error { func (c *Container) Scan(visit func(interface{}) error) error {
for _, x := range c.Items { for _, x := range c.items {
if err := visit(x); err != nil { if err := visit(x); err != nil {
return err return err
} }
@ -43,38 +70,38 @@ func (c *Container) Scan(visit func(interface{}) error) error {
} }
// Len returns the number of items in the container. // Len returns the number of items in the container.
func (c *Container) Len() int { return len(c.Items) } func (c *Container) Len() int { return len(c.items) }
// Swap swaps two items in the container. // Swap swaps two items in the container.
func (c *Container) Swap(i, j int) { func (c *Container) Swap(i, j int) {
if i == j { if i == j {
return return
} }
ifree := c.Items[i] == nil ifree := c.items[i] == nil
jfree := c.Items[j] == nil jfree := c.items[j] == nil
switch { switch {
case ifree && jfree: case ifree && jfree:
return return
case ifree: case ifree:
c.Items[i] = c.Items[j] c.items[i] = c.items[j]
c.reverse[c.Items[i]] = i c.reverse[c.items[i]] = i
c.free[j] = struct{}{} c.free[j] = struct{}{}
delete(c.free, i) delete(c.free, i)
case jfree: case jfree:
c.Items[j] = c.Items[i] c.items[j] = c.items[i]
c.reverse[c.Items[j]] = j c.reverse[c.items[j]] = j
c.free[i] = struct{}{} c.free[i] = struct{}{}
delete(c.free, j) delete(c.free, j)
default: default:
c.Items[i], c.Items[j] = c.Items[j], c.Items[i] c.items[i], c.items[j] = c.items[j], c.items[i]
c.reverse[c.Items[i]] = i c.reverse[c.items[i]] = i
c.reverse[c.Items[j]] = j c.reverse[c.items[j]] = j
} }
} }
func (c Container) String() string { return "Container" } func (c Container) String() string { return "Container" }
// Register records component in the slice, if parent is this container. It // Register records component into the slice, if parent is this container. It
// writes the component to an arbitrary free index in the slice, or appends if // writes the component to an arbitrary free index in the slice, or appends if
// there are none free. // there are none free.
func (c *Container) Register(component, parent interface{}) error { func (c *Container) Register(component, parent interface{}) error {
@ -82,13 +109,13 @@ func (c *Container) Register(component, parent interface{}) error {
return nil return nil
} }
if len(c.free) == 0 { if len(c.free) == 0 {
c.reverse[component] = len(c.Items) c.reverse[component] = len(c.items)
c.Items = append(c.Items, component) c.items = append(c.items, component)
return nil return nil
} }
for i := range c.free { for i := range c.free {
c.reverse[component] = i c.reverse[component] = i
c.Items[i] = component c.items[i] = component
delete(c.free, i) delete(c.free, i)
return nil return nil
} }
@ -100,24 +127,24 @@ func (c *Container) Register(component, parent interface{}) error {
// is compacted. // is compacted.
func (c *Container) Unregister(component interface{}) { func (c *Container) Unregister(component interface{}) {
if i, found := c.reverse[component]; found { if i, found := c.reverse[component]; found {
c.Items[i] = nil c.items[i] = nil
c.free[i] = struct{}{} c.free[i] = struct{}{}
delete(c.reverse, i) delete(c.reverse, i)
} }
if len(c.free) > len(c.Items)/2 { if len(c.free) > len(c.items)/2 {
c.compact() c.compact()
} }
} }
func (c *Container) compact() { func (c *Container) compact() {
i := 0 i := 0
for _, x := range c.Items { for _, x := range c.items {
if x != nil { if x != nil {
c.Items[i] = x c.items[i] = x
c.reverse[x] = i c.reverse[x] = i
i++ i++
} }
} }
c.Items = c.Items[:i] c.items = c.items[:i]
c.free = make(map[int]struct{}) c.free = make(map[int]struct{})
} }