brunel/fastmap/fastmap.go

156 lines
3.0 KiB
Go

package fastmap
import (
"fmt"
"strings"
"slices"
"github.com/goccy/go-json"
)
type Fastmap[K comparable, V any] struct {
idx map[K]int
store []fastmapValue[K, V]
}
type fastmapValue[K comparable, V any] struct {
Key K
Value V
}
func New[K comparable, V any]() *Fastmap[K, V] {
return &Fastmap[K, V]{
idx: make(map[K]int),
store: make([]fastmapValue[K, V], 0),
}
}
func (m *Fastmap[K, V]) Set(key K, value V) {
if _, ok := m.idx[key]; ok {
m.store[m.idx[key]].Value = value
return
}
m.idx[key] = len(m.store)
m.store = append(m.store, fastmapValue[K, V]{Key: key, Value: value})
}
func (m *Fastmap[K, V]) Get(key K) (value V, ok bool) {
idx, ok := m.idx[key]
if !ok {
return
}
return m.store[idx].Value, true
}
func (m *Fastmap[K, V]) Delete(key K) {
idx, ok := m.idx[key]
if !ok {
return
}
delete(m.idx, key)
m.store[idx] = m.store[len(m.store)-1]
m.store = m.store[:len(m.store)-1]
}
func (m *Fastmap[K, V]) Has(key K) bool {
_, ok := m.idx[key]
return ok
}
func (m *Fastmap[K, V]) Len() int {
return len(m.idx)
}
func (m *Fastmap[K, V]) GetPage(pageNum int, pageSize int) *Fastmap[K, V] {
start := pageSize * pageNum
end := start + pageSize
if end > len(m.store) {
end = len(m.store)
}
returnVal := New[K, V]()
for i := start; i < end; i++ {
returnVal.Set(m.store[i].Key, m.store[i].Value)
}
return returnVal
}
func (m *Fastmap[K, V]) Clear() {
m.idx = make(map[K]int)
m.store = make([]fastmapValue[K, V], 0)
}
func (m *Fastmap[K, V]) Iter(fn func(key K, value V) bool) {
for _, v := range m.store {
if !fn(v.Key, v.Value) {
break
}
}
}
func (m *Fastmap[K, V]) StableSortByKey() {
slices.SortStableFunc(m.store, func(a, b fastmapValue[K, V]) int {
aKey := fmt.Sprint(a.Key)
bKey := fmt.Sprint(b.Key)
return strings.Compare(aKey, bKey)
})
// Update the index map after sorting
for i, v := range m.store {
m.idx[v.Key] = i
}
}
func (m *Fastmap[K, V]) MarshalText() ([]byte, error) {
var builder strings.Builder
for _, v := range m.store {
builder.WriteString(fmt.Sprintf("%v:%v\n", v.Key, v.Value))
}
return []byte(builder.String()), nil
}
func (m *Fastmap[K, V]) UnmarshalText(text []byte) error {
m.Clear()
lines := strings.Split(string(text), "\n")
for _, line := range lines {
if line == "" {
continue
}
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid format: %s", line)
}
var key K
var value V
if _, err := fmt.Sscan(parts[0], &key); err != nil {
return fmt.Errorf("error parsing key: %v", err)
}
if _, err := fmt.Sscan(parts[1], &value); err != nil {
return fmt.Errorf("error parsing value: %v", err)
}
m.Set(key, value)
}
return nil
}
func (m *Fastmap[K, V]) MarshalJSON() ([]byte, error) {
temp := make(map[K]V)
for _, v := range m.store {
temp[v.Key] = v.Value
}
return json.Marshal(temp)
}
func (m *Fastmap[K, V]) UnmarshalJSON(data []byte) error {
temp := make(map[K]V)
if err := json.Unmarshal(data, &temp); err != nil {
return err
}
m.Clear()
for k, v := range temp {
m.Set(k, v)
}
return nil
}