// ORDERED MAP FROM STRING TO GENERIC VALUE TYPE // // Quite like types.OrderedMap but only with string keys. See orderedMap.go for // more information. package lib type OrderedMap[V any] struct { FieldCount int64 Head *orderedMapEntry[V] Tail *orderedMapEntry[V] keysToEntries map[string]*orderedMapEntry[V] } type orderedMapEntry[V any] struct { Key string Value V Prev *orderedMapEntry[V] Next *orderedMapEntry[V] } func NewOrderedMap[V any]() *OrderedMap[V] { return &OrderedMap[V]{ FieldCount: 0, Head: nil, Tail: nil, keysToEntries: make(map[string]*orderedMapEntry[V]), } } // Value-copy is up to the caller -- PutReference and PutCopy // are in the public OrderedMap API. func newOrderedMapEntry[V any](key *string, value V) *orderedMapEntry[V] { return &orderedMapEntry[V]{ *key, value, nil, nil, } } func (omap *OrderedMap[V]) IsEmpty() bool { return omap.FieldCount == 0 } func (omap *OrderedMap[V]) Has(key string) bool { return omap.findEntry(&key) != nil } func (omap *OrderedMap[V]) findEntry(key *string) *orderedMapEntry[V] { if omap.keysToEntries != nil { return omap.keysToEntries[*key] } for pe := omap.Head; pe != nil; pe = pe.Next { if pe.Key == *key { return pe } } return nil } func (omap *OrderedMap[V]) Put(key string, value V) { pe := omap.findEntry(&key) if pe == nil { pe = newOrderedMapEntry(&key, value) if omap.Head == nil { omap.Head = pe omap.Tail = pe } else { pe.Prev = omap.Tail pe.Next = nil omap.Tail.Next = pe omap.Tail = pe } if omap.keysToEntries != nil { omap.keysToEntries[key] = pe } omap.FieldCount++ } else { pe.Value = value } } func (omap *OrderedMap[V]) Get(key string) V { pe := omap.findEntry(&key) if pe == nil { var zero V return zero } return pe.Value } // The Get is sufficient for pointer values -- the caller can check if the // return value is nil. For int/string values (which are non-nullable) we have // this method. func (omap *OrderedMap[V]) GetWithCheck(key string) (V, bool) { pe := omap.findEntry(&key) if pe == nil { var zero V return zero, false } return pe.Value, true } // Returns true if it was found and removed func (omap *OrderedMap[V]) Remove(key string) bool { pe := omap.findEntry(&key) if pe == nil { return false } omap.unlink(pe) return true } func (omap *OrderedMap[V]) unlink(pe *orderedMapEntry[V]) { if pe == omap.Head { if pe == omap.Tail { omap.Head = nil omap.Tail = nil } else { omap.Head = pe.Next pe.Next.Prev = nil } } else { pe.Prev.Next = pe.Next if pe == omap.Tail { omap.Tail = pe.Prev } else { pe.Next.Prev = pe.Prev } } if omap.keysToEntries != nil { delete(omap.keysToEntries, pe.Key) } omap.FieldCount-- }