2024-06-02 21:29:11 +03:00
|
|
|
package gg
|
|
|
|
|
2024-06-02 23:53:43 +03:00
|
|
|
type ObjectMap map[Object] struct{}
|
|
|
|
|
2024-06-02 21:29:11 +03:00
|
|
|
// 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
|
|
|
|
|
2024-06-02 23:53:43 +03:00
|
|
|
tagMap map[Tag] ObjectMap
|
|
|
|
|
2024-06-02 21:29:11 +03:00
|
|
|
// Available nil values in the store.
|
|
|
|
freeIndexes []int
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewObjects() *Objects {
|
|
|
|
ret := &Objects{}
|
|
|
|
ret.searchMap = map[Object] int {}
|
2024-06-02 23:53:43 +03:00
|
|
|
ret.tagMap = map[Tag]ObjectMap{}
|
2024-06-02 21:29:11 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-06-02 23:53:43 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|