77 lines
2.1 KiB
Go
77 lines
2.1 KiB
Go
package collections
|
|
|
|
import "maps"
|
|
|
|
// CopyOnWriteMap is a map that defers cloning of an inherited backing map
|
|
// until the first mutation, and supports nested scopes that share the parent's
|
|
// map for reads but get their own clone on write.
|
|
//
|
|
// The zero value is an empty map ready to use.
|
|
type CopyOnWriteMap[K comparable, V any] struct {
|
|
m map[K]V
|
|
owned bool
|
|
}
|
|
|
|
// Get returns the value for k and whether it was present.
|
|
func (c *CopyOnWriteMap[K, V]) Get(k K) (V, bool) {
|
|
v, ok := c.m[k]
|
|
return v, ok
|
|
}
|
|
|
|
// Has reports whether k is in the map.
|
|
func (c *CopyOnWriteMap[K, V]) Has(k K) bool {
|
|
_, ok := c.m[k]
|
|
return ok
|
|
}
|
|
|
|
// Set assigns v to k, cloning the inherited backing map first if necessary.
|
|
func (c *CopyOnWriteMap[K, V]) Set(k K, v V) {
|
|
c.ensureOwned()
|
|
c.m[k] = v
|
|
}
|
|
|
|
func (c *CopyOnWriteMap[K, V]) ensureOwned() {
|
|
if c.owned {
|
|
return
|
|
}
|
|
if c.m == nil {
|
|
c.m = make(map[K]V)
|
|
} else {
|
|
c.m = maps.Clone(c.m)
|
|
}
|
|
c.owned = true
|
|
}
|
|
|
|
// EnterScope returns a function that restores this map to its current state.
|
|
// While the scope is active, the map shares its current backing storage with
|
|
// the parent scope: reads see the inherited entries, and the first mutation
|
|
// transparently clones the storage so the parent's view is not modified.
|
|
func (c *CopyOnWriteMap[K, V]) EnterScope() func() {
|
|
saved := *c
|
|
c.owned = false
|
|
return func() { *c = saved }
|
|
}
|
|
|
|
type CopyOnWriteSet[K comparable] struct {
|
|
m CopyOnWriteMap[K, struct{}]
|
|
}
|
|
|
|
// Has reports whether k is in the set.
|
|
func (c *CopyOnWriteSet[K]) Has(k K) bool {
|
|
_, ok := c.m.Get(k)
|
|
return ok
|
|
}
|
|
|
|
// Set adds k to the set, cloning the inherited backing map first if necessary.
|
|
func (c *CopyOnWriteSet[K]) Add(k K) {
|
|
c.m.Set(k, struct{}{})
|
|
}
|
|
|
|
// EnterScope returns a function that restores this set to its current state.
|
|
// While the scope is active, the set shares its current backing storage with
|
|
// the parent scope: reads see the inherited entries, and the first mutation
|
|
// transparently clones the storage so the parent's view is not modified.
|
|
func (c *CopyOnWriteSet[K]) EnterScope() func() {
|
|
return c.m.EnterScope()
|
|
}
|