// Copyright 2022 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. // The persistent package defines various persistent data structures; // that is, data structures that can be efficiently copied and modified // in sublinear time. package persistent import ( "math/rand" "sync/atomic" ) // Implementation details: // * Each value is reference counted by nodes which hold it. // * Each node is reference counted by its parent nodes. // * Each map is considered a top-level parent node from reference counting perspective. // * Each change does always effectivelly produce a new top level node. // // Functions which operate directly with nodes do have a notation in form of // `foo(arg1:+n1, arg2:+n2) (ret1:+n3)`. // Each argument is followed by a delta change to its reference counter. // In case if no change is expected, the delta will be `-0`. // Map is an associative mapping from keys to values, both represented as // interface{}. Key comparison and iteration order is defined by a // client-provided function that implements a strict weak order. // // Maps can be Cloned in constant time. // Get, Store, and Delete operations are done on average in logarithmic time. // Maps can be Updated in O(m log(n/m)) time for maps of size n and m, where m < n. // // Values are reference counted, and a client-supplied release function // is called when a value is no longer referenced by a map or any clone. // // Internally the implementation is based on a randomized persistent treap: // https://en.wikipedia.org/wiki/Treap. type Map struct { less func(a, b interface{}) bool root *mapNode } type mapNode struct { key interface{} value *refValue weight uint64 refCount int32 left, right *mapNode } type refValue struct { refCount int32 value interface{} release func(key, value interface{}) } func newNodeWithRef(key, value interface{}, release func(key, value interface{})) *mapNode { return &mapNode{ key: key, value: &refValue{ value: value, release: release, refCount: 1, }, refCount: 1, weight: rand.Uint64(), } } func (node *mapNode) shallowCloneWithRef() *mapNode { atomic.AddInt32(&node.value.refCount, 1) return &mapNode{ key: node.key, value: node.value, weight: node.weight, refCount: 1, } } func (node *mapNode) incref() *mapNode { if node != nil { atomic.AddInt32(&node.refCount, 1) } return node } func (node *mapNode) decref() { if node == nil { return } if atomic.AddInt32(&node.refCount, -1) == 0 { if atomic.AddInt32(&node.value.refCount, -1) == 0 { if node.value.release != nil { node.value.release(node.key, node.value.value) } node.value.value = nil node.value.release = nil } node.left.decref() node.right.decref() } } // NewMap returns a new map whose keys are ordered by the given comparison // function (a strict weak order). It is the responsibility of the caller to // Destroy it at later time. func NewMap(less func(a, b interface{}) bool) *Map { return &Map{ less: less, } } // Clone returns a copy of the given map. It is a responsibility of the caller // to Destroy it at later time. func (pm *Map) Clone() *Map { return &Map{ less: pm.less, root: pm.root.incref(), } } // Destroy destroys the map. // // After Destroy, the Map should not be used again. func (pm *Map) Destroy() { // The implementation of these two functions is the same, // but their intent is different. pm.Clear() } // Clear removes all entries from the map. func (pm *Map) Clear() { pm.root.decref() pm.root = nil } // Range calls f sequentially in ascending key order for all entries in the map. func (pm *Map) Range(f func(key, value interface{})) { pm.root.forEach(f) } func (node *mapNode) forEach(f func(key, value interface{})) { if node == nil { return } node.left.forEach(f) f(node.key, node.value.value) node.right.forEach(f) } // Get returns the map value associated with the specified key, or nil if no entry // is present. The ok result indicates whether an entry was found in the map. func (pm *Map) Get(key interface{}) (interface{}, bool) { node := pm.root for node != nil { if pm.less(key, node.key) { node = node.left } else if pm.less(node.key, key) { node = node.right } else { return node.value.value, true } } return nil, false } // SetAll updates the map with key/value pairs from the other map, overwriting existing keys. // It is equivalent to calling Set for each entry in the other map but is more efficient. // Both maps must have the same comparison function, otherwise behavior is undefined. func (pm *Map) SetAll(other *Map) { root := pm.root pm.root = union(root, other.root, pm.less, true) root.decref() } // Set updates the value associated with the specified key. // If release is non-nil, it will be called with entry's key and value once the // key is no longer contained in the map or any clone. func (pm *Map) Set(key, value interface{}, release func(key, value interface{})) { first := pm.root second := newNodeWithRef(key, value, release) pm.root = union(first, second, pm.less, true) first.decref() second.decref() } // union returns a new tree which is a union of first and second one. // If overwrite is set to true, second one would override a value for any duplicate keys. // // union(first:-0, second:-0) (result:+1) // Union borrows both subtrees without affecting their refcount and returns a // new reference that the caller is expected to call decref. func union(first, second *mapNode, less func(a, b interface{}) bool, overwrite bool) *mapNode { if first == nil { return second.incref() } if second == nil { return first.incref() } if first.weight < second.weight { second, first, overwrite = first, second, !overwrite } left, mid, right := split(second, first.key, less, false) var result *mapNode if overwrite && mid != nil { result = mid.shallowCloneWithRef() } else { result = first.shallowCloneWithRef() } result.weight = first.weight result.left = union(first.left, left, less, overwrite) result.right = union(first.right, right, less, overwrite) left.decref() mid.decref() right.decref() return result } // split the tree midway by the key into three different ones. // Return three new trees: left with all nodes with smaller than key, mid with // the node matching the key, right with all nodes larger than key. // If there are no nodes in one of trees, return nil instead of it. // If requireMid is set (such as during deletion), then all return arguments // are nil if mid is not found. // // split(n:-0) (left:+1, mid:+1, right:+1) // Split borrows n without affecting its refcount, and returns three // new references that that caller is expected to call decref. func split(n *mapNode, key interface{}, less func(a, b interface{}) bool, requireMid bool) (left, mid, right *mapNode) { if n == nil { return nil, nil, nil } if less(n.key, key) { left, mid, right := split(n.right, key, less, requireMid) if requireMid && mid == nil { return nil, nil, nil } newN := n.shallowCloneWithRef() newN.left = n.left.incref() newN.right = left return newN, mid, right } else if less(key, n.key) { left, mid, right := split(n.left, key, less, requireMid) if requireMid && mid == nil { return nil, nil, nil } newN := n.shallowCloneWithRef() newN.left = right newN.right = n.right.incref() return left, mid, newN } mid = n.shallowCloneWithRef() return n.left.incref(), mid, n.right.incref() } // Delete deletes the value for a key. func (pm *Map) Delete(key interface{}) { root := pm.root left, mid, right := split(root, key, pm.less, true) if mid == nil { return } pm.root = merge(left, right) left.decref() mid.decref() right.decref() root.decref() } // merge two trees while preserving the weight invariant. // All nodes in left must have smaller keys than any node in right. // // merge(left:-0, right:-0) (result:+1) // Merge borrows its arguments without affecting their refcount // and returns a new reference that the caller is expected to call decref. func merge(left, right *mapNode) *mapNode { switch { case left == nil: return right.incref() case right == nil: return left.incref() case left.weight > right.weight: root := left.shallowCloneWithRef() root.left = left.left.incref() root.right = merge(left.right, right) return root default: root := right.shallowCloneWithRef() root.left = merge(left, right.left) root.right = right.right.incref() return root } }