gods/maps/sparse.go
2023-10-28 14:26:50 +03:00

179 lines
2.9 KiB
Go

package maps
import (
"slices"
"cmp"
"fmt"
)
// The package implements sparse array structure.
// You can make sparse matrices by assigning
// the value type to another sparse array.
// The sparse array type.
// Does not sort by default on setting so by
// default is not ordered for the Chan, Keys, KeyChan, Slice methods.
// Its made for the optimization sakes because
// initially the package was made for the gox (2D game engine) package use
// to provide dynamic layering.
// See *Sparse[K, V].ShouldSort method to change it.
type mSparse[K cmp.Ordered, V any] struct {
store map[K] V
def V
keys []K
}
// Return the new with the default implementation storing the values from the
// map inside the structure. Is fast on creation and reading, but
// slow on inserting and deleting. Takes only one or zero maps as input.
// Panics otherwise.
func NewSparse[K cmp.Ordered, V any](
defval V,
values ...map[K] V,
) Map[K, V] {
var (
store map[K] V
keys []K
vs map[K] V
)
if len(values) > 1 {
panic("too many arguments")
} else if len(values) == 1 {
vs = values[0]
}
if vs == nil {
store = map[K] V{}
keys = []K{}
} else {
store = make(map[K] V, len(vs))
keys = make([]K, len(vs))
i := 0
for k, v := range vs {
keys[i] = k
store[k] = v
i++
}
slices.Sort(keys)
}
ret := &mSparse[K, V]{
store: store,
def: defval,
keys: keys,
}
return ret
}
func (s *mSparse[K, V]) Size() int {
return len(s.keys)
}
func (s *mSparse[K, V]) Clear() {
s.store = map[K]V{}
s.keys = []K{}
}
func (s *mSparse[K, V]) Has(key K) bool {
_, ok := s.store[key]
return ok
}
func (s *mSparse[K, V]) Get(key K) (V) {
val, ok := s.store[key]
if !ok {
val = s.def
}
return val
}
func (s *mSparse[K, V]) Got(key K) (V, bool) {
v, ok := s.store[key]
if !ok {
v = s.def
}
return v, ok
}
func (s *mSparse[K, V]) Set(k K, v V) {
_, ok := s.store[k]
if !ok {
s.keys = append(s.keys, k)
s.sort()
}
s.store[k] = v
}
func (s *mSparse[K, V]) Empty() bool {
return len(s.keys) == 0
}
func (s *mSparse[K, V]) Del(k K) {
delete(s.store, k)
// To know if the loop was run.
idx := -1
for i, v := range s.keys {
if v == k {
idx = i
break
}
}
if idx != -1 {
// Removing the key.
s.keys = append(s.keys[:idx], s.keys[idx+1:]...)
}
}
func (s *mSparse[K, V]) Chan(
) chan V {
keys := s.keys
store := s.store
ret := make(chan V)
go func() {
for _, k := range keys {
ret <- store[k]
}
close(ret)
}()
return ret
}
func (s *mSparse[K, V]) KeyChan() chan K {
ret := make(chan K)
go func() {
for _, k := range s.keys {
ret <- k
}
close(ret)
}()
return ret
}
func (s *mSparse[K, V]) Keys() []K {
return s.keys
}
func (s *mSparse[K, V]) Values() []V {
ret := []V{}
for v := range s.Chan() {
ret = append(ret, v)
}
return ret
}
func (s *mSparse[K, V]) String() string {
return fmt.Sprintf("%#v", s.store)
}
func (s *mSparse[K, V]) sort() {
slices.Sort(s.keys)
}