mirror of https://github.com/golang/go.git
298 lines
8.4 KiB
Go
298 lines
8.4 KiB
Go
// 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
|
|
}
|
|
}
|