Files
monibuca/pkg/util/collection.go
2025-01-14 18:56:58 +08:00

185 lines
3.2 KiB
Go

package util
import (
"slices"
"sync"
)
type Collection[K comparable, T interface{ GetKey() K }] struct {
L *sync.RWMutex
Items []T
m map[K]T
Length int
addListeners []func(T)
removeListeners []func(T)
}
func (c *Collection[K, T]) OnAdd(listener func(T)) {
c.addListeners = append(c.addListeners, listener)
}
func (c *Collection[K, T]) OnRemove(listener func(T)) {
c.removeListeners = append(c.removeListeners, listener)
}
func (c *Collection[K, T]) Add(item T) {
if c.L != nil {
c.L.Lock()
defer c.L.Unlock()
}
c.Items = append(c.Items, item)
if c.Length > 100 || c.m != nil {
if c.m == nil {
c.m = make(map[K]T)
for _, v := range c.Items {
c.m[v.GetKey()] = v
}
}
c.m[item.GetKey()] = item
}
c.Length++
for _, listener := range c.addListeners {
listener(item)
}
}
func (c *Collection[K, T]) AddUnique(item T) (ok bool) {
if _, ok = c.Get(item.GetKey()); !ok {
c.Add(item)
}
return !ok
}
func (c *Collection[K, T]) Set(item T) (added bool) {
key := item.GetKey()
if c.m != nil {
c.m[key] = item
}
for i := range c.Items {
if c.Items[i].GetKey() == key {
c.Items[i] = item
return false
}
}
c.Add(item)
return true
}
func (c *Collection[K, T]) Range(f func(T) bool) {
if c.L != nil {
c.L.RLock()
defer c.L.RUnlock()
}
for _, item := range c.Items {
if !f(item) {
break
}
}
}
func (c *Collection[K, T]) Remove(item T) bool {
return c.RemoveByKey(item.GetKey())
}
func (c *Collection[K, T]) RemoveByKey(key K) bool {
if c.L != nil {
c.L.Lock()
defer c.L.Unlock()
}
delete(c.m, key)
for i := range c.Length {
if c.Items[i].GetKey() == key {
item := c.Items[i]
c.Items = slices.Delete(c.Items, i, i+1)
c.Length--
for _, listener := range c.removeListeners {
listener(item)
}
return true
}
}
return false
}
// func (c *Collection[K, T]) GetOrCreate(key K) (item T, find bool) {
// if c.L != nil {
// c.L.Lock()
// defer c.L.Unlock()
// }
// if c.m != nil {
// item, find = c.m[key]
// return item, find
// }
// for _, item = range c.Items {
// if item.GetKey() == key {
// return item, true
// }
// }
// item = reflect.New(reflect.TypeOf(item).Elem()).Interface().(T)
// return
// }
func (c *Collection[K, T]) Has(key K) bool {
_, ok := c.Get(key)
return ok
}
func (c *Collection[K, T]) Get(key K) (item T, ok bool) {
if c.L != nil {
c.L.RLock()
defer c.L.RUnlock()
}
if c.m != nil {
item, ok = c.m[key]
return
}
for _, item := range c.Items {
if item.GetKey() == key {
return item, true
}
}
return
}
func (c *Collection[K, T]) Find(f func(T) bool) (item T, ok bool) {
if c.L != nil {
c.L.RLock()
defer c.L.RUnlock()
}
for _, item := range c.Items {
if f(item) {
return item, true
}
}
return
}
func (c *Collection[K, T]) Search(f func(T) bool) func(yield func(item T) bool) {
if c.L != nil {
c.L.RLock()
defer c.L.RUnlock()
}
return func(yield func(item T) bool) {
for _, item := range c.Items {
if f(item) {
if !yield(item) {
break
}
}
}
}
}
func (c *Collection[K, T]) GetKey() K {
return c.Items[0].GetKey()
}
func (c *Collection[K, T]) Clear() {
if c.L != nil {
c.L.Lock()
defer c.L.Unlock()
}
c.Items = nil
c.m = nil
c.Length = 0
}