github.com/sunvim/utils@v0.1.0/radix/radix.go (about) 1 package radix 2 3 import ( 4 "sort" 5 "strings" 6 ) 7 8 // WalkFn is used when walking the tree. Takes a 9 // key and value, returning if iteration should 10 // be terminated. 11 type WalkFn func(s string, v interface{}) bool 12 13 // leafNode is used to represent a value 14 type leafNode struct { 15 key string 16 val interface{} 17 } 18 19 // edge is used to represent an edge node 20 type edge struct { 21 label byte 22 node *node 23 } 24 25 type node struct { 26 // leaf is used to store possible leaf 27 leaf *leafNode 28 29 // prefix is the common prefix we ignore 30 prefix string 31 32 // Edges should be stored in-order for iteration. 33 // We avoid a fully materialized slice to save memory, 34 // since in most cases we expect to be sparse 35 edges edges 36 } 37 38 func (n *node) isLeaf() bool { 39 return n.leaf != nil 40 } 41 42 func (n *node) addEdge(e edge) { 43 n.edges = append(n.edges, e) 44 n.edges.Sort() 45 } 46 47 func (n *node) updateEdge(label byte, node *node) { 48 num := len(n.edges) 49 idx := sort.Search(num, func(i int) bool { 50 return n.edges[i].label >= label 51 }) 52 if idx < num && n.edges[idx].label == label { 53 n.edges[idx].node = node 54 return 55 } 56 panic("replacing missing edge") 57 } 58 59 func (n *node) getEdge(label byte) *node { 60 num := len(n.edges) 61 idx := sort.Search(num, func(i int) bool { 62 return n.edges[i].label >= label 63 }) 64 if idx < num && n.edges[idx].label == label { 65 return n.edges[idx].node 66 } 67 return nil 68 } 69 70 func (n *node) delEdge(label byte) { 71 num := len(n.edges) 72 idx := sort.Search(num, func(i int) bool { 73 return n.edges[i].label >= label 74 }) 75 if idx < num && n.edges[idx].label == label { 76 copy(n.edges[idx:], n.edges[idx+1:]) 77 n.edges[len(n.edges)-1] = edge{} 78 n.edges = n.edges[:len(n.edges)-1] 79 } 80 } 81 82 type edges []edge 83 84 func (e edges) Len() int { 85 return len(e) 86 } 87 88 func (e edges) Less(i, j int) bool { 89 return e[i].label < e[j].label 90 } 91 92 func (e edges) Swap(i, j int) { 93 e[i], e[j] = e[j], e[i] 94 } 95 96 func (e edges) Sort() { 97 sort.Sort(e) 98 } 99 100 // Tree implements a radix tree. This can be treated as a 101 // Dictionary abstract data type. The main advantage over 102 // a standard hash map is prefix-based lookups and 103 // ordered iteration, 104 type Tree struct { 105 root *node 106 size int 107 } 108 109 // New returns an empty Tree 110 func New() *Tree { 111 return NewFromMap(nil) 112 } 113 114 // NewFromMap returns a new tree containing the keys 115 // from an existing map 116 func NewFromMap(m map[string]interface{}) *Tree { 117 t := &Tree{root: &node{}} 118 for k, v := range m { 119 t.Insert(k, v) 120 } 121 return t 122 } 123 124 // Len is used to return the number of elements in the tree 125 func (t *Tree) Len() int { 126 return t.size 127 } 128 129 // longestPrefix finds the length of the shared prefix 130 // of two strings 131 func longestPrefix(k1, k2 string) int { 132 max := len(k1) 133 if l := len(k2); l < max { 134 max = l 135 } 136 var i int 137 for i = 0; i < max; i++ { 138 if k1[i] != k2[i] { 139 break 140 } 141 } 142 return i 143 } 144 145 // Insert is used to add a newentry or update 146 // an existing entry. Returns if updated. 147 func (t *Tree) Insert(s string, v interface{}) (interface{}, bool) { 148 var parent *node 149 n := t.root 150 search := s 151 for { 152 // Handle key exhaution 153 if len(search) == 0 { 154 if n.isLeaf() { 155 old := n.leaf.val 156 n.leaf.val = v 157 return old, true 158 } 159 160 n.leaf = &leafNode{ 161 key: s, 162 val: v, 163 } 164 t.size++ 165 return nil, false 166 } 167 168 // Look for the edge 169 parent = n 170 n = n.getEdge(search[0]) 171 172 // No edge, create one 173 if n == nil { 174 e := edge{ 175 label: search[0], 176 node: &node{ 177 leaf: &leafNode{ 178 key: s, 179 val: v, 180 }, 181 prefix: search, 182 }, 183 } 184 parent.addEdge(e) 185 t.size++ 186 return nil, false 187 } 188 189 // Determine longest prefix of the search key on match 190 commonPrefix := longestPrefix(search, n.prefix) 191 if commonPrefix == len(n.prefix) { 192 search = search[commonPrefix:] 193 continue 194 } 195 196 // Split the node 197 t.size++ 198 child := &node{ 199 prefix: search[:commonPrefix], 200 } 201 parent.updateEdge(search[0], child) 202 203 // Restore the existing node 204 child.addEdge(edge{ 205 label: n.prefix[commonPrefix], 206 node: n, 207 }) 208 n.prefix = n.prefix[commonPrefix:] 209 210 // Create a new leaf node 211 leaf := &leafNode{ 212 key: s, 213 val: v, 214 } 215 216 // If the new key is a subset, add to to this node 217 search = search[commonPrefix:] 218 if len(search) == 0 { 219 child.leaf = leaf 220 return nil, false 221 } 222 223 // Create a new edge for the node 224 child.addEdge(edge{ 225 label: search[0], 226 node: &node{ 227 leaf: leaf, 228 prefix: search, 229 }, 230 }) 231 return nil, false 232 } 233 } 234 235 // Delete is used to delete a key, returning the previous 236 // value and if it was deleted 237 func (t *Tree) Delete(s string) (interface{}, bool) { 238 var parent *node 239 var label byte 240 n := t.root 241 search := s 242 for { 243 // Check for key exhaution 244 if len(search) == 0 { 245 if !n.isLeaf() { 246 break 247 } 248 goto DELETE 249 } 250 251 // Look for an edge 252 parent = n 253 label = search[0] 254 n = n.getEdge(label) 255 if n == nil { 256 break 257 } 258 259 // Consume the search prefix 260 if strings.HasPrefix(search, n.prefix) { 261 search = search[len(n.prefix):] 262 } else { 263 break 264 } 265 } 266 return nil, false 267 268 DELETE: 269 // Delete the leaf 270 leaf := n.leaf 271 n.leaf = nil 272 t.size-- 273 274 // Check if we should delete this node from the parent 275 if parent != nil && len(n.edges) == 0 { 276 parent.delEdge(label) 277 } 278 279 // Check if we should merge this node 280 if n != t.root && len(n.edges) == 1 { 281 n.mergeChild() 282 } 283 284 // Check if we should merge the parent's other child 285 if parent != nil && parent != t.root && len(parent.edges) == 1 && !parent.isLeaf() { 286 parent.mergeChild() 287 } 288 289 return leaf.val, true 290 } 291 292 // DeletePrefix is used to delete the subtree under a prefix 293 // Returns how many nodes were deleted 294 // Use this to delete large subtrees efficiently 295 func (t *Tree) DeletePrefix(s string) int { 296 return t.deletePrefix(nil, t.root, s) 297 } 298 299 // delete does a recursive deletion 300 func (t *Tree) deletePrefix(parent, n *node, prefix string) int { 301 // Check for key exhaustion 302 if len(prefix) == 0 { 303 // Remove the leaf node 304 subTreeSize := 0 305 //recursively walk from all edges of the node to be deleted 306 recursiveWalk(n, func(s string, v interface{}) bool { 307 subTreeSize++ 308 return false 309 }) 310 if n.isLeaf() { 311 n.leaf = nil 312 } 313 n.edges = nil // deletes the entire subtree 314 315 // Check if we should merge the parent's other child 316 if parent != nil && parent != t.root && len(parent.edges) == 1 && !parent.isLeaf() { 317 parent.mergeChild() 318 } 319 t.size -= subTreeSize 320 return subTreeSize 321 } 322 323 // Look for an edge 324 label := prefix[0] 325 child := n.getEdge(label) 326 if child == nil || (!strings.HasPrefix(child.prefix, prefix) && !strings.HasPrefix(prefix, child.prefix)) { 327 return 0 328 } 329 330 // Consume the search prefix 331 if len(child.prefix) > len(prefix) { 332 prefix = prefix[len(prefix):] 333 } else { 334 prefix = prefix[len(child.prefix):] 335 } 336 return t.deletePrefix(n, child, prefix) 337 } 338 339 func (n *node) mergeChild() { 340 e := n.edges[0] 341 child := e.node 342 n.prefix = n.prefix + child.prefix 343 n.leaf = child.leaf 344 n.edges = child.edges 345 } 346 347 // Get is used to lookup a specific key, returning 348 // the value and if it was found 349 func (t *Tree) Get(s string) (interface{}, bool) { 350 n := t.root 351 search := s 352 for { 353 // Check for key exhaution 354 if len(search) == 0 { 355 if n.isLeaf() { 356 return n.leaf.val, true 357 } 358 break 359 } 360 361 // Look for an edge 362 n = n.getEdge(search[0]) 363 if n == nil { 364 break 365 } 366 367 // Consume the search prefix 368 if strings.HasPrefix(search, n.prefix) { 369 search = search[len(n.prefix):] 370 } else { 371 break 372 } 373 } 374 return nil, false 375 } 376 377 // LongestPrefix is like Get, but instead of an 378 // exact match, it will return the longest prefix match. 379 func (t *Tree) LongestPrefix(s string) (string, interface{}, bool) { 380 var last *leafNode 381 n := t.root 382 search := s 383 for { 384 // Look for a leaf node 385 if n.isLeaf() { 386 last = n.leaf 387 } 388 389 // Check for key exhaution 390 if len(search) == 0 { 391 break 392 } 393 394 // Look for an edge 395 n = n.getEdge(search[0]) 396 if n == nil { 397 break 398 } 399 400 // Consume the search prefix 401 if strings.HasPrefix(search, n.prefix) { 402 search = search[len(n.prefix):] 403 } else { 404 break 405 } 406 } 407 if last != nil { 408 return last.key, last.val, true 409 } 410 return "", nil, false 411 } 412 413 // Minimum is used to return the minimum value in the tree 414 func (t *Tree) Minimum() (string, interface{}, bool) { 415 n := t.root 416 for { 417 if n.isLeaf() { 418 return n.leaf.key, n.leaf.val, true 419 } 420 if len(n.edges) > 0 { 421 n = n.edges[0].node 422 } else { 423 break 424 } 425 } 426 return "", nil, false 427 } 428 429 // Maximum is used to return the maximum value in the tree 430 func (t *Tree) Maximum() (string, interface{}, bool) { 431 n := t.root 432 for { 433 if num := len(n.edges); num > 0 { 434 n = n.edges[num-1].node 435 continue 436 } 437 if n.isLeaf() { 438 return n.leaf.key, n.leaf.val, true 439 } 440 break 441 } 442 return "", nil, false 443 } 444 445 // Walk is used to walk the tree 446 func (t *Tree) Walk(fn WalkFn) { 447 recursiveWalk(t.root, fn) 448 } 449 450 // WalkPrefix is used to walk the tree under a prefix 451 func (t *Tree) WalkPrefix(prefix string, fn WalkFn) { 452 n := t.root 453 search := prefix 454 for { 455 // Check for key exhaution 456 if len(search) == 0 { 457 recursiveWalk(n, fn) 458 return 459 } 460 461 // Look for an edge 462 n = n.getEdge(search[0]) 463 if n == nil { 464 break 465 } 466 467 // Consume the search prefix 468 if strings.HasPrefix(search, n.prefix) { 469 search = search[len(n.prefix):] 470 471 } else if strings.HasPrefix(n.prefix, search) { 472 // Child may be under our search prefix 473 recursiveWalk(n, fn) 474 return 475 } else { 476 break 477 } 478 } 479 480 } 481 482 // WalkPath is used to walk the tree, but only visiting nodes 483 // from the root down to a given leaf. Where WalkPrefix walks 484 // all the entries *under* the given prefix, this walks the 485 // entries *above* the given prefix. 486 func (t *Tree) WalkPath(path string, fn WalkFn) { 487 n := t.root 488 search := path 489 for { 490 // Visit the leaf values if any 491 if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { 492 return 493 } 494 495 // Check for key exhaution 496 if len(search) == 0 { 497 return 498 } 499 500 // Look for an edge 501 n = n.getEdge(search[0]) 502 if n == nil { 503 return 504 } 505 506 // Consume the search prefix 507 if strings.HasPrefix(search, n.prefix) { 508 search = search[len(n.prefix):] 509 } else { 510 break 511 } 512 } 513 } 514 515 // recursiveWalk is used to do a pre-order walk of a node 516 // recursively. Returns true if the walk should be aborted 517 func recursiveWalk(n *node, fn WalkFn) bool { 518 // Visit the leaf values if any 519 if n.leaf != nil && fn(n.leaf.key, n.leaf.val) { 520 return true 521 } 522 523 // Recurse on the children 524 for _, e := range n.edges { 525 if recursiveWalk(e.node, fn) { 526 return true 527 } 528 } 529 return false 530 } 531 532 // ToMap is used to walk the tree and convert it into a map 533 func (t *Tree) ToMap() map[string]interface{} { 534 out := make(map[string]interface{}, t.size) 535 t.Walk(func(k string, v interface{}) bool { 536 out[k] = v 537 return false 538 }) 539 return out 540 } 541 542 func (t *Tree) Save(file string) error { 543 return nil 544 } 545 546 func (t *Tree) Load(file string) error { 547 return nil 548 }