sing-box/common/linkedhashmap/map.go

171 lines
3.6 KiB
Go

package linkedhashmap
import (
"bytes"
"github.com/goccy/go-json"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/x/list"
)
type Map[K comparable, V any] struct {
raw list.List[mapEntry[K, V]]
rawMap map[K]*list.Element[mapEntry[K, V]]
}
func (m *Map[K, V]) init() {
if m.rawMap == nil {
m.rawMap = make(map[K]*list.Element[mapEntry[K, V]])
}
}
func (m *Map[K, V]) MarshalJSON() ([]byte, error) {
buffer := new(bytes.Buffer)
buffer.WriteString("{")
for item := m.raw.Front(); item != nil; {
entry := item.Value
err := json.NewEncoder(buffer).Encode(entry.Key)
if err != nil {
return nil, err
}
buffer.WriteString(": ")
err = json.NewEncoder(buffer).Encode(entry.Value)
if err != nil {
return nil, err
}
item = item.Next()
if item != nil {
buffer.WriteString(", ")
}
}
buffer.WriteString("}")
return buffer.Bytes(), nil
}
func (m *Map[K, V]) UnmarshalJSON(content []byte) error {
decoder := json.NewDecoder(bytes.NewReader(content))
m.Clear()
m.init()
objectStart, err := decoder.Token()
if err != nil {
return err
} else if objectStart != json.Delim('{') {
return E.New("expected json object start, but starts with ", objectStart)
}
for decoder.More() {
var entryKey K
err = decoder.Decode(&entryKey)
if err != nil {
return err
}
var entryValue V
err = decoder.Decode(&entryValue)
if err != nil {
return err
}
m.rawMap[entryKey] = m.raw.PushBack(mapEntry[K, V]{Key: entryKey, Value: entryValue})
}
objectEnd, err := decoder.Token()
if err != nil {
return err
} else if objectEnd != json.Delim('}') {
return E.New("expected json object end, but ends with ", objectEnd)
}
return nil
}
type mapEntry[K comparable, V any] struct {
Key K
Value V
}
func (m *Map[K, V]) Size() int {
return m.raw.Size()
}
func (m *Map[K, V]) IsEmpty() bool {
return m.raw.IsEmpty()
}
func (m *Map[K, V]) ContainsKey(key K) bool {
m.init()
_, loaded := m.rawMap[key]
return loaded
}
func (m *Map[K, V]) Get(key K) (V, bool) {
m.init()
value, loaded := m.rawMap[key]
return value.Value.Value, loaded
}
func (m *Map[K, V]) Put(key K, value V) V {
m.init()
entry, loaded := m.rawMap[key]
if loaded {
oldValue := entry.Value.Value
entry.Value.Value = value
return oldValue
}
entry = m.raw.PushBack(mapEntry[K, V]{Key: key, Value: value})
m.rawMap[key] = entry
return common.DefaultValue[V]()
}
func (m *Map[K, V]) PutAll(other *Map[K, V]) {
for item := other.raw.Front(); item != nil; item = item.Next() {
m.Put(item.Value.Key, item.Value.Value)
}
}
func (m *Map[K, V]) Remove(key K) bool {
m.init()
entry, loaded := m.rawMap[key]
if !loaded {
return false
}
m.raw.Remove(entry)
delete(m.rawMap, key)
return true
}
func (m *Map[K, V]) RemoveAll(keys []K) {
m.init()
for _, key := range keys {
entry, loaded := m.rawMap[key]
if !loaded {
continue
}
m.raw.Remove(entry)
delete(m.rawMap, key)
}
}
func (m *Map[K, V]) AsMap() map[K]V {
result := make(map[K]V, m.raw.Len())
for item := m.raw.Front(); item != nil; item = item.Next() {
result[item.Value.Key] = item.Value.Value
}
return result
}
func (m *Map[K, V]) Keys() []K {
result := make([]K, 0, m.raw.Len())
for item := m.raw.Front(); item != nil; item = item.Next() {
result = append(result, item.Value.Key)
}
return result
}
func (m *Map[K, V]) Values() []V {
result := make([]V, 0, m.raw.Len())
for item := m.raw.Front(); item != nil; item = item.Next() {
result = append(result, item.Value.Value)
}
return result
}
func (m *Map[K, V]) Clear() {
*m = Map[K, V]{}
}