| // Copyright 2026 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package sgutil | |
| import "iter" | |
| type InsertMap[K comparable, V any] struct { | |
| m map[K]uint32 // Maps keys to their insertion index in the values slice. | |
| v []V // Stores values in their insertion order. | |
| k []K // Lazy slice of keys in insertion order, for iterators. | |
| } | |
| // Put inserts or updates a key-value pair in the map. | |
| // If the key already exists, its value is updated while its insertion order | |
| // remains unchanged. Returns the old value if there is one, | |
| // and a boolean indicating whether an update occurred. | |
| func (im *InsertMap[K, V]) Put(key K, val V) (old V, updated bool) { | |
| if im.m == nil { | |
| im.m = make(map[K]uint32) | |
| } | |
| var index uint32 | |
| index, updated = im.m[key] | |
| if updated { | |
| // Key already exists; update its value in-place in the values slice. | |
| old = im.v[index] | |
| im.v[index] = val | |
| return | |
| } | |
| // Keep the keys slice synchronized if it has already been initialized. | |
| if len(im.v) > 0 && len(im.k) == len(im.v) { | |
| im.k = append(im.k, key) | |
| } | |
| // Record the new key's insertion index and append the value. | |
| im.m[key] = uint32(len(im.v)) | |
| im.v = append(im.v, val) | |
| return | |
| } | |
| // updateKeys synchronizes the lazy keys slice (im.k) with the values slice (im.v). | |
| // It populates im.k with keys at their respective insertion indices using | |
| // the mapping stored in im.m. | |
| func (im *InsertMap[K, V]) updateKeys() { | |
| if len(im.k) == len(im.v) { | |
| return | |
| } | |
| im.k = make([]K, len(im.v)) | |
| for k, i := range im.m { | |
| im.k[i] = k | |
| } | |
| } | |
| // Contains reports whether the map contains the specified key. | |
| func (im *InsertMap[K, V]) Contains(key K) bool { | |
| if im.m == nil { | |
| return false | |
| } | |
| _, ok := im.m[key] | |
| return ok | |
| } | |
| // Get returns the value associated with the specified key. | |
| // If the key does not exist, the zero value of type V is returned. | |
| func (im *InsertMap[K, V]) Get(key K) V { | |
| if im.m != nil { | |
| index, ok := im.m[key] | |
| if ok { | |
| return im.v[index] | |
| } | |
| } | |
| var v V | |
| return v | |
| } | |
| // GetOk returns the value associated with the specified key and | |
| // a boolean indicating whether the key exists in the map. | |
| // If the key is not in the map, the zero value is returned along with false. | |
| func (im *InsertMap[K, V]) GetOk(key K) (V, bool) { | |
| if im.m != nil { | |
| index, ok := im.m[key] | |
| if ok { | |
| return im.v[index], true | |
| } | |
| } | |
| var v V | |
| return v, false | |
| } | |
| // Compare compares two keys based on their insertion order. | |
| // It returns: | |
| // - -1 if 'a' was inserted before 'b' | |
| // - 1 if 'a' was inserted after 'b' | |
| // - 0 if 'a' and 'b' are equal, or if neither key exists in the map. | |
| // | |
| // If only one of the keys exists in the map, the existing key is considered | |
| // to be "before" (less than) the non-existing key, returning -1 if 'a' exists, | |
| // and 1 if 'b' exists. | |
| func (im *InsertMap[K, V]) Compare(a, b K) int { | |
| if im.m == nil { | |
| return 0 | |
| } | |
| ai, aok := im.m[a] | |
| bi, bok := im.m[b] | |
| if aok != bok { | |
| if aok { | |
| return -1 | |
| } | |
| return 1 | |
| } | |
| if !aok { | |
| return 0 | |
| } | |
| if ai < bi { | |
| return -1 | |
| } | |
| if ai > bi { | |
| return 1 | |
| } | |
| return 0 | |
| } | |
| // All returns an iterator over the key-value pairs of the map in insertion order. | |
| func (im *InsertMap[K, V]) All() iter.Seq2[K, V] { | |
| return func(yield func(K, V) bool) { | |
| im.updateKeys() | |
| for i, k := range im.k { | |
| if !yield(k, im.v[i]) { | |
| return | |
| } | |
| } | |
| } | |
| } | |
| // Keys returns an iterator over the keys of the map in insertion order. | |
| func (im *InsertMap[K, V]) Keys() iter.Seq[K] { | |
| return func(yield func(K) bool) { | |
| im.updateKeys() | |
| for _, k := range im.k { | |
| if !yield(k) { | |
| return | |
| } | |
| } | |
| } | |
| } | |
| // Values returns an iterator over the values of the map in insertion order. | |
| func (im *InsertMap[K, V]) Values() iter.Seq[V] { | |
| return func(yield func(V) bool) { | |
| for _, v := range im.v { | |
| if !yield(v) { | |
| return | |
| } | |
| } | |
| } | |
| } |