gg/objects.go

124 lines
2.3 KiB
Go

package gg
type ObjectMap map[Object] struct{}
// The structure to store objects
// with O(1) add, remove and search operations.
type Objects struct {
// The place to store all the objects.
store []Object
// Find index by Object.
searchMap map[Object] int
tagMap map[Tag] ObjectMap
// Available nil values in the store.
freeIndexes []int
}
func NewObjects() *Objects {
ret := &Objects{}
ret.searchMap = map[Object] int {}
ret.tagMap = map[Tag]ObjectMap{}
return ret
}
func (objects *Objects) has(object Object) bool {
_, ok := objects.searchMap[object]
return ok
}
func (objects *Objects) add(object Object) bool {
if objects.has(object) {
return false
}
if len(objects.freeIndexes) > 0 {
freeIndex := objects.freeIndexes[0]
objects.freeIndexes = objects.freeIndexes[1:]
objects.store[freeIndex] = object
objects.searchMap[object] = freeIndex
} else {
objects.store = append(objects.store, object)
objects.searchMap[object] = len(objects.store)-1
}
return true
}
func (objects *Objects) remove(object Object) bool {
objectIndex, ok := objects.searchMap[object]
if !ok {
return false
}
objects.store[objectIndex] = nil
objects.freeIndexes = append(
objects.freeIndexes,
objectIndex,
)
return true
}
func (objects *Objects) FindByTags(
t Tag, rest ...Tag,
) []Object {
tagMap := objects.tagMap
objectMap := tagMap[t]
retMap := map[Object]struct{}{}
for object := range objectMap {
retMap[object] = struct{}{}
}
for _, tag := range rest {
m, ok := tagMap[tag]
if !ok {
continue
}
for object := range m {
_, ok := m[object]
if !ok {
delete(retMap, object)
}
}
}
ret := []Object{}
for object := range retMap {
ret = append(ret, object)
}
return ret
}
func (objects *Objects) updateObjects(c Context){
for _, object := range objects.store {
if object == nil {
continue
}
object.OnUpdate(c)
}
}
func (objects *Objects) updateTags(c Context) {
tagMap := objects.tagMap
updateMap := make(map[Tag]ObjectMap, len(tagMap))
for _, object := range objects.store {
tags := object.GetTags(c)
for tag := range tags {
tm, ok := updateMap[tag]
if ok {
tm[object] = struct{}{}
} else {
updateMap[tag] = ObjectMap{
object: struct{}{},
}
}
}
}
objects.tagMap = updateMap
}