-
Notifications
You must be signed in to change notification settings - Fork 4
Addchild and fetchchild node compatiblity +grow working #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 19 commits
b1a487c
058b2e5
3577de9
68dbdbe
94bf757
db64be6
3f86edc
72a7ead
f1c491b
e5b9dde
dfd6c14
0352d08
278149a
34e0389
d85da6a
5c3fb51
ab066c6
277c89c
b423a0c
05e0e14
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/acmpesuecc/radFS/internal/art" | ||
| ) | ||
|
|
||
| func main() { | ||
| tree := &art.Tree{} | ||
|
|
||
| for i := 0; i < 50; i++ { | ||
| key := []byte("ca" + string(byte(i+97))) | ||
| tree.Insert(key, fmt.Sprintf("val%d", i)) | ||
| } | ||
| art.PrintTree(tree.Root(), 0, 0) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| ## Angelo's Progress | ||
| * implemented the insert function | ||
| * implemented update function in addchild | ||
|
|
||
|
|
||
| ## What's next? | ||
| * implement grow to transition to larger nodes | ||
| * fix the bugs in insert |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package art | ||
|
|
||
| // TODO: Public API (Tree struct, Insert, Search, Delete) | ||
|
|
||
| type Tree struct { | ||
| root *Node | ||
| } | ||
|
|
||
| func (t *Tree) Root() *Node { | ||
| return t.root | ||
| } | ||
|
|
||
| func (t *Tree) Insert(key []byte, value string) { | ||
| t.root = insert(t.root, value, key, 0) | ||
| } | ||
|
|
||
| func (t *Tree) Search(key []byte) (string, bool) { | ||
| leaf := search(t.root, key, 0) // start from root and depth 0 | ||
| if leaf != nil && isleaf(leaf) { | ||
| return leaf.leaf.values, true //Node->innerleaf->values | ||
| } | ||
| return "", false | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| package art | ||
|
|
||
| func insert(n *Node, value string, key []byte, depth int) *Node { | ||
|
|
||
| if n == nil { | ||
| return newleaf(value, key) | ||
| } | ||
| if isleaf(n) { | ||
| new_node := newNode4() | ||
| oldkey := n.leaf.key | ||
| i := depth | ||
|
|
||
| for i < len(oldkey) && i < len(key) && oldkey[i] == key[i] { | ||
| prefix_index := i - depth | ||
| if prefix_index < maxprefixlen { | ||
| new_node.innerNode.meta.prefix[prefix_index] = key[i] // stores only the till max prefix | ||
|
|
||
| } | ||
|
|
||
| i++ | ||
| } | ||
|
|
||
| new_node.innerNode.meta.prefixlen = i - depth // stores full prefix len even after maxprefixlen | ||
| depth = i | ||
| if depth == len(key) { | ||
| new_node.innerNode.leaf = newleaf(value, key) | ||
|
|
||
| } else { | ||
| new_node = addchild(new_node, key[depth], newleaf(value, key)) | ||
|
|
||
| } | ||
| if depth == len(oldkey) { | ||
| new_node.innerNode.leaf = n | ||
|
|
||
| } else { | ||
| new_node = addchild(new_node, oldkey[depth], n) | ||
|
|
||
| } | ||
|
|
||
| return new_node | ||
|
|
||
| } | ||
| p := checkprefix(n, key, depth) | ||
|
|
||
| if p != n.innerNode.meta.prefixlen { | ||
|
|
||
| new_node := newNode4() | ||
| if p+depth == len(key) { | ||
| new_node.innerNode.leaf = newleaf(value, key) | ||
|
|
||
| } else { | ||
| new_node = addchild(new_node, key[depth+p], newleaf(value, key)) | ||
|
|
||
| } | ||
| leaf := fetchleaf(n) // either its an actual leaf or innernode leaf | ||
| oldkey := leaf.leaf.key | ||
|
|
||
| var oldkeybyte byte | ||
| if p < maxprefixlen { | ||
| oldkeybyte = n.innerNode.meta.prefix[p] | ||
| } else { | ||
| oldkeybyte = oldkey[depth+p] | ||
| } | ||
|
|
||
| new_node = addchild(new_node, oldkeybyte, n) | ||
|
|
||
| new_node.innerNode.meta.prefixlen = p | ||
| if p < maxprefixlen { | ||
| new_node.innerNode.meta.prefix = deepcopy(n.innerNode.meta.prefix[:p]) | ||
|
|
||
| } else { | ||
| new_node.innerNode.meta.prefix = deepcopy(n.innerNode.meta.prefix[:maxprefixlen]) | ||
| } | ||
|
|
||
| oldprefixlen := n.innerNode.meta.prefixlen | ||
| n.innerNode.meta.prefixlen = oldprefixlen - (p + 1) | ||
| if oldprefixlen < maxprefixlen { | ||
| n.innerNode.meta.prefix = deepcopy(n.innerNode.meta.prefix[p+1 : oldprefixlen]) | ||
|
|
||
| } else { | ||
| leaf := fetchleaf(n) | ||
| n.innerNode.meta.prefix = deepcopy(leaf.leaf.key[depth+p+1 : depth+p+1+maxprefixlen]) | ||
| } | ||
|
|
||
| return new_node | ||
| } | ||
|
|
||
| depth += n.innerNode.meta.prefixlen | ||
| if depth == len(key) { | ||
| n.innerNode.leaf = newleaf(value, key) | ||
| return n | ||
| } | ||
| next, pos := findchild(key[depth], n) | ||
| if next != nil { | ||
| n.innerNode.children[pos] = insert(next, value, key, depth+1) | ||
| return n | ||
|
|
||
| } else { | ||
| n = addchild(n, key[depth], newleaf(value, key)) | ||
| return n | ||
|
|
||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package art | ||
|
|
||
| // TODO: Leaf node structure for storing values | ||
|
|
||
| type leaf struct { | ||
| key []byte | ||
| values string | ||
| } | ||
|
|
||
| func newleaf(value string, key []byte) *Node { | ||
| return &Node{ | ||
| leaf: &leaf{key: key, values: value}, | ||
| } | ||
|
|
||
| } | ||
| func isleaf(n *Node) bool { | ||
| return n.leaf != nil | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package art | ||
|
|
||
| // TODO: Interfaces and shared node header (meta) | ||
|
|
||
| type NodeType int | ||
|
|
||
| const ( | ||
| Node4 NodeType = iota | ||
| Node16 | ||
| Node48 | ||
| Node256 | ||
| ) | ||
| const ( | ||
| Node4max = 4 | ||
| Node16Max = 16 | ||
| Node48Max = 48 | ||
| Node256Max = 256 | ||
|
|
||
| maxprefixlen = 8 | ||
| ) | ||
|
|
||
| type Node struct { | ||
| innerNode *innerNode | ||
| leaf *leaf | ||
| } | ||
|
|
||
| type innerNode struct { | ||
| nodeType NodeType | ||
| keys []byte | ||
| children []*Node | ||
| leaf *Node | ||
|
|
||
| num_children int | ||
|
|
||
| meta meta | ||
| } | ||
|
|
||
| type meta struct { | ||
| prefix []byte | ||
| prefixlen int | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package art | ||
|
|
||
| // TODO: Node16 implementation | ||
| func newNode16() *Node { | ||
| in := &innerNode{ | ||
| nodeType: Node16, | ||
| keys: make([]byte, Node16Max), | ||
| children: make([]*Node, Node16Max), | ||
| num_children: 0, | ||
| meta: meta{ | ||
| prefix: make([]byte, maxprefixlen), | ||
| }, | ||
| } | ||
| return &Node{innerNode: in} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package art | ||
|
|
||
| // TODO: Node256 implementation (direct map) | ||
|
|
||
| func newNode256() *Node { | ||
| in := &innerNode{ | ||
| nodeType: Node256, | ||
| children: make([]*Node, Node256Max), | ||
| num_children: 0, | ||
|
|
||
| meta: meta{ | ||
| prefix: make([]byte, maxprefixlen), | ||
| }, | ||
| } | ||
| return &Node{innerNode: in} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package art | ||
|
|
||
| func newNode4() *Node { | ||
| in := &innerNode{ | ||
| nodeType: Node4, | ||
| keys: make([]byte, Node4max), | ||
| children: make([]*Node, Node4max), | ||
| num_children: 0, | ||
| meta: meta{ | ||
| prefix: make([]byte, maxprefixlen), | ||
| }, | ||
| } | ||
| return &Node{innerNode: in} | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package art | ||
|
|
||
| // TODO: Node48 implementation (indirection layer) | ||
| func newNode48() *Node { | ||
| in := &innerNode{ | ||
| nodeType: Node48, | ||
| keys: make([]byte, Node256Max), | ||
| children: make([]*Node, Node48Max), | ||
| num_children: 0, | ||
| meta: meta{ | ||
| prefix: make([]byte, maxprefixlen), | ||
| }, | ||
| } | ||
| return &Node{innerNode: in} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| package art | ||
|
|
||
| import "fmt" | ||
|
|
||
| func PrintTree(n *Node, level int, depth int) { | ||
| if n == nil { | ||
| return | ||
| } | ||
|
|
||
| indent := "" | ||
| for i := 0; i < level; i++ { | ||
| indent += " " | ||
| } | ||
|
|
||
| if isleaf(n) { | ||
| fmt.Println(indent + "Leaf: " + string(n.leaf.key)) | ||
| return | ||
| } | ||
|
|
||
| in := n.innerNode | ||
|
|
||
| prefixlen := in.meta.prefixlen | ||
| prefix := "" | ||
| if prefixlen <= maxprefixlen { | ||
| prefix = string(in.meta.prefix[:prefixlen]) | ||
|
|
||
| } else { | ||
| leaf := fetchleaf(n) | ||
| prefix = string(leaf.leaf.key[depth : depth+prefixlen]) | ||
| } | ||
|
|
||
| fmt.Println(indent+"Node(prefix=\""+prefix+"\", prefixLen=", prefixlen, ")") | ||
|
|
||
| if in.leaf != nil { | ||
| fmt.Printf("%s [Internal Leaf]: %s\n", indent, string(in.leaf.leaf.key)) | ||
| } | ||
| // Print children | ||
|
|
||
| newDepth := depth + prefixlen | ||
|
|
||
| switch in.nodeType { | ||
| case Node4, Node16: | ||
| for i := 0; i < in.num_children; i++ { | ||
| key := in.keys[i] | ||
| child := in.children[i] | ||
|
|
||
| fmt.Printf("%s Edge('%c' | %d):\t", indent, key, key) | ||
| PrintTree(child, level+1, newDepth+1) | ||
| } | ||
|
|
||
| case Node48: | ||
| for b := 0; b < 256; b++ { | ||
| idx := in.keys[b] | ||
|
|
||
| if idx != 0 { | ||
|
|
||
| child := in.children[idx-1] | ||
|
|
||
| fmt.Printf("%s Edge('%c' | %d):\t", indent, byte(b), b) | ||
| PrintTree(child, level+1, newDepth+1) | ||
| } | ||
| } | ||
|
|
||
| case Node256: | ||
| for b := 0; b < 256; b++ { | ||
| child := in.children[b] | ||
| if child != nil { | ||
| fmt.Printf("%s Edge('%c' | %d):\t", indent, byte(b), b) | ||
| PrintTree(child, level+1, newDepth+1) | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package art | ||
|
|
||
| func search(n *Node, key []byte, depth int) *Node { | ||
| // Base case: nil node means we've reached a dead end. | ||
| // Key does not exist in this path of the tree. | ||
| if n == nil { | ||
| return nil | ||
| } | ||
|
|
||
| // Reached a leaf node, do a full key comparison. | ||
| // Necessary because path compression may have skipped bytes. | ||
| if isleaf(n) { | ||
| if string(n.leaf.key) == string(key) { | ||
| return n | ||
| } | ||
| return nil | ||
|
Comment on lines
+12
to
+16
|
||
| } | ||
|
|
||
| // Check if the compressed prefix at this node matches the search key. | ||
| // If any byte mismatches, the entire subtree is irrelevant. | ||
| if n.innerNode.meta.prefixlen > 0 { | ||
| p := checkprefix(n, key, depth) | ||
| if p != n.innerNode.meta.prefixlen { | ||
| return nil | ||
| } | ||
| depth += n.innerNode.meta.prefixlen | ||
| } | ||
|
|
||
| // Get the next byte to branch on at current depth. | ||
| // Returns 0 (terminator) if key is exhausted. | ||
| k := key[depth] | ||
|
|
||
| // Find the child corresponding to byte k and recurse deeper. | ||
| // Return nil if no child exists for this byte. | ||
| next, _ := findchild(k, n) | ||
| if next != nil { | ||
| return search(next, key, depth+1) | ||
|
Comment on lines
+29
to
+37
|
||
| } | ||
|
|
||
| return nil | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.