|
|
@@ -0,0 +1,111 @@
|
|
|
+// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
+// SPDX-License-Identifier: BSD-3-Clause
|
|
|
+
|
|
|
+// Package mapx contains extra map types and functions.
|
|
|
+package mapx
|
|
|
+
|
|
|
+import (
|
|
|
+ "iter"
|
|
|
+ "slices"
|
|
|
+)
|
|
|
+
|
|
|
+// OrderedMap is a map that maintains the order of its keys.
|
|
|
+//
|
|
|
+// It is meant for maps that only grow or that are small;
|
|
|
+// is it not optimized for deleting keys.
|
|
|
+//
|
|
|
+// The zero value is ready to use.
|
|
|
+//
|
|
|
+// Locking-wise, it has the same rules as a regular Go map:
|
|
|
+// concurrent reads are safe, but not writes.
|
|
|
+type OrderedMap[K comparable, V any] struct {
|
|
|
+ // m is the underlying map.
|
|
|
+ m map[K]V
|
|
|
+
|
|
|
+ // keys is the order of keys in the map.
|
|
|
+ keys []K
|
|
|
+}
|
|
|
+
|
|
|
+func (m *OrderedMap[K, V]) init() {
|
|
|
+ if m.m == nil {
|
|
|
+ m.m = make(map[K]V)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Set sets the value for the given key in the map.
|
|
|
+//
|
|
|
+// If the key already exists, it updates the value and keeps the order.
|
|
|
+func (m *OrderedMap[K, V]) Set(key K, value V) {
|
|
|
+ m.init()
|
|
|
+ len0 := len(m.keys)
|
|
|
+ m.m[key] = value
|
|
|
+ if len(m.m) > len0 {
|
|
|
+ // New key (not an update)
|
|
|
+ m.keys = append(m.keys, key)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Get returns the value for the given key in the map.
|
|
|
+// If the key does not exist, it returns the zero value for V.
|
|
|
+func (m *OrderedMap[K, V]) Get(key K) V {
|
|
|
+ return m.m[key]
|
|
|
+}
|
|
|
+
|
|
|
+// GetOk returns the value for the given key in the map
|
|
|
+// and whether it was present in the map.
|
|
|
+func (m *OrderedMap[K, V]) GetOk(key K) (_ V, ok bool) {
|
|
|
+ v, ok := m.m[key]
|
|
|
+ return v, ok
|
|
|
+}
|
|
|
+
|
|
|
+// Contains reports whether the map contains the given key.
|
|
|
+func (m *OrderedMap[K, V]) Contains(key K) bool {
|
|
|
+ _, ok := m.m[key]
|
|
|
+ return ok
|
|
|
+}
|
|
|
+
|
|
|
+// Delete removes the key from the map.
|
|
|
+//
|
|
|
+// The cost is O(n) in the number of keys in the map.
|
|
|
+func (m *OrderedMap[K, V]) Delete(key K) {
|
|
|
+ len0 := len(m.m)
|
|
|
+ delete(m.m, key)
|
|
|
+ if len(m.m) == len0 {
|
|
|
+ // Wasn't present; no need to adjust keys.
|
|
|
+ return
|
|
|
+ }
|
|
|
+ was := m.keys
|
|
|
+ m.keys = m.keys[:0]
|
|
|
+ for _, k := range was {
|
|
|
+ if k != key {
|
|
|
+ m.keys = append(m.keys, k)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// All yields all the keys and values, in the order they were inserted.
|
|
|
+func (m *OrderedMap[K, V]) All() iter.Seq2[K, V] {
|
|
|
+ return func(yield func(K, V) bool) {
|
|
|
+ for _, k := range m.keys {
|
|
|
+ if !yield(k, m.m[k]) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Keys yields the map keys, in the order they were inserted.
|
|
|
+func (m *OrderedMap[K, V]) Keys() iter.Seq[K] {
|
|
|
+ return slices.Values(m.keys)
|
|
|
+}
|
|
|
+
|
|
|
+// Values yields the map values, in the order they were inserted.
|
|
|
+func (m *OrderedMap[K, V]) Values() iter.Seq[V] {
|
|
|
+ return func(yield func(V) bool) {
|
|
|
+ for _, k := range m.keys {
|
|
|
+ if !yield(m.m[k]) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|