123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- package iradix
- import (
- "bytes"
- "sort"
- )
- // WalkFn is used when walking the tree. Takes a
- // key and value, returning if iteration should
- // be terminated.
- type WalkFn func(k []byte, v interface{}) bool
- // leafNode is used to represent a value
- type leafNode struct {
- mutateCh chan struct{}
- key []byte
- val interface{}
- }
- // edge is used to represent an edge node
- type edge struct {
- label byte
- node *Node
- }
- // Node is an immutable node in the radix tree
- type Node struct {
- // mutateCh is closed if this node is modified
- mutateCh chan struct{}
- // leaf is used to store possible leaf
- leaf *leafNode
- // prefix is the common prefix we ignore
- prefix []byte
- // Edges should be stored in-order for iteration.
- // We avoid a fully materialized slice to save memory,
- // since in most cases we expect to be sparse
- edges edges
- }
- func (n *Node) isLeaf() bool {
- return n.leaf != nil
- }
- func (n *Node) addEdge(e edge) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= e.label
- })
- n.edges = append(n.edges, e)
- if idx != num {
- copy(n.edges[idx+1:], n.edges[idx:num])
- n.edges[idx] = e
- }
- }
- func (n *Node) replaceEdge(e edge) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= e.label
- })
- if idx < num && n.edges[idx].label == e.label {
- n.edges[idx].node = e.node
- return
- }
- panic("replacing missing edge")
- }
- func (n *Node) getEdge(label byte) (int, *Node) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= label
- })
- if idx < num && n.edges[idx].label == label {
- return idx, n.edges[idx].node
- }
- return -1, nil
- }
- func (n *Node) delEdge(label byte) {
- num := len(n.edges)
- idx := sort.Search(num, func(i int) bool {
- return n.edges[i].label >= label
- })
- if idx < num && n.edges[idx].label == label {
- copy(n.edges[idx:], n.edges[idx+1:])
- n.edges[len(n.edges)-1] = edge{}
- n.edges = n.edges[:len(n.edges)-1]
- }
- }
- func (n *Node) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) {
- search := k
- watch := n.mutateCh
- for {
- // Check for key exhaustion
- if len(search) == 0 {
- if n.isLeaf() {
- return n.leaf.mutateCh, n.leaf.val, true
- }
- break
- }
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- break
- }
- // Update to the finest granularity as the search makes progress
- watch = n.mutateCh
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
- } else {
- break
- }
- }
- return watch, nil, false
- }
- func (n *Node) Get(k []byte) (interface{}, bool) {
- _, val, ok := n.GetWatch(k)
- return val, ok
- }
- // LongestPrefix is like Get, but instead of an
- // exact match, it will return the longest prefix match.
- func (n *Node) LongestPrefix(k []byte) ([]byte, interface{}, bool) {
- var last *leafNode
- search := k
- for {
- // Look for a leaf node
- if n.isLeaf() {
- last = n.leaf
- }
- // Check for key exhaution
- if len(search) == 0 {
- break
- }
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- break
- }
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
- } else {
- break
- }
- }
- if last != nil {
- return last.key, last.val, true
- }
- return nil, nil, false
- }
- // Minimum is used to return the minimum value in the tree
- func (n *Node) Minimum() ([]byte, interface{}, bool) {
- for {
- if n.isLeaf() {
- return n.leaf.key, n.leaf.val, true
- }
- if len(n.edges) > 0 {
- n = n.edges[0].node
- } else {
- break
- }
- }
- return nil, nil, false
- }
- // Maximum is used to return the maximum value in the tree
- func (n *Node) Maximum() ([]byte, interface{}, bool) {
- for {
- if num := len(n.edges); num > 0 {
- n = n.edges[num-1].node
- continue
- }
- if n.isLeaf() {
- return n.leaf.key, n.leaf.val, true
- } else {
- break
- }
- }
- return nil, nil, false
- }
- // Iterator is used to return an iterator at
- // the given node to walk the tree
- func (n *Node) Iterator() *Iterator {
- return &Iterator{node: n}
- }
- // rawIterator is used to return a raw iterator at the given node to walk the
- // tree.
- func (n *Node) rawIterator() *rawIterator {
- iter := &rawIterator{node: n}
- iter.Next()
- return iter
- }
- // Walk is used to walk the tree
- func (n *Node) Walk(fn WalkFn) {
- recursiveWalk(n, fn)
- }
- // WalkPrefix is used to walk the tree under a prefix
- func (n *Node) WalkPrefix(prefix []byte, fn WalkFn) {
- search := prefix
- for {
- // Check for key exhaution
- if len(search) == 0 {
- recursiveWalk(n, fn)
- return
- }
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- break
- }
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
- } else if bytes.HasPrefix(n.prefix, search) {
- // Child may be under our search prefix
- recursiveWalk(n, fn)
- return
- } else {
- break
- }
- }
- }
- // WalkPath is used to walk the tree, but only visiting nodes
- // from the root down to a given leaf. Where WalkPrefix walks
- // all the entries *under* the given prefix, this walks the
- // entries *above* the given prefix.
- func (n *Node) WalkPath(path []byte, fn WalkFn) {
- search := path
- for {
- // Visit the leaf values if any
- if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
- return
- }
- // Check for key exhaution
- if len(search) == 0 {
- return
- }
- // Look for an edge
- _, n = n.getEdge(search[0])
- if n == nil {
- return
- }
- // Consume the search prefix
- if bytes.HasPrefix(search, n.prefix) {
- search = search[len(n.prefix):]
- } else {
- break
- }
- }
- }
- // recursiveWalk is used to do a pre-order walk of a node
- // recursively. Returns true if the walk should be aborted
- func recursiveWalk(n *Node, fn WalkFn) bool {
- // Visit the leaf values if any
- if n.leaf != nil && fn(n.leaf.key, n.leaf.val) {
- return true
- }
- // Recurse on the children
- for _, e := range n.edges {
- if recursiveWalk(e.node, fn) {
- return true
- }
- }
- return false
- }
|