-
Notifications
You must be signed in to change notification settings - Fork 4
handles words>maxprefixlen #36
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 all commits
b1a487c
058b2e5
3577de9
68dbdbe
94bf757
db64be6
3f86edc
72a7ead
f1c491b
e5b9dde
dfd6c14
0352d08
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,15 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "github.com/acmpesuecc/radFS/internal/art" | ||
| ) | ||
|
|
||
| func main() { | ||
| tree := &art.Tree{} | ||
|
|
||
| tree.Insert([]byte("abbbbbbbc"), "first") | ||
| tree.Insert([]byte("abbbbbbbcb"), "second") | ||
| tree.Insert([]byte("abbbbbbbcbc"), "second") | ||
|
|
||
| art.PrintTree(tree.Root(), 0) | ||
| } |
| 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,86 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package art | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import "fmt" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("depth:", depth) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("oldkey[depth:]:", string(oldkey[depth:])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("key[depth:]:", string(key[depth:])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for i < len(oldkey) && i < len(key) && oldkey[i] == key[i] { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prefix_index := i - depth | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if prefix_index < maxprefixlen { //index goes till 7 so prefix index<8 and not ==8 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_node = addchild(new_node, keycheck(key, depth), newleaf(value, key)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_node = addchild(new_node, keycheck(oldkey, depth), n) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("depth:", depth) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("oldkey[depth:]:", string(oldkey[depth:])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("key[depth:]:", string(key[depth:])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println(" ") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fmt.Println("prefix", string(new_node.innerNode.meta.prefix)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return new_node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| p := checkprefix(n, key, depth) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if p != n.innerNode.meta.prefixlen { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_node := newNode4() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_node = addchild(new_node, keycheck(key, depth+p), newleaf(value, key)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if p < maxprefixlen { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_node = addchild(new_node, n.innerNode.meta.prefix[p], n) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| leaf := fetchleaf(n) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_node = addchild(new_node, keycheck(leaf.leaf.key, depth+p), n) // the logic is teh leaf will contain the full key with the same prefix | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new_node.innerNode.meta.prefixlen = p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if p < maxprefixlen { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| copy(new_node.innerNode.meta.prefix, n.innerNode.meta.prefix[:p]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| copy(new_node.innerNode.meta.prefix, n.innerNode.meta.prefix[:maxprefixlen]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| oldprefixlen := n.innerNode.meta.prefixlen | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| n.innerNode.meta.prefixlen = n.innerNode.meta.prefixlen - (p + 1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(n.innerNode.meta.prefix[p+1:oldprefixlen]) < maxprefixlen { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| copy(n.innerNode.meta.prefix, n.innerNode.meta.prefix[p+1:oldprefixlen]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| copy(n.innerNode.meta.prefix, n.innerNode.meta.prefix[p+1:maxprefixlen]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+63
to
+68
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| n.innerNode.meta.prefixlen = n.innerNode.meta.prefixlen - (p + 1) | |
| if len(n.innerNode.meta.prefix[p+1:oldprefixlen]) < maxprefixlen { | |
| copy(n.innerNode.meta.prefix, n.innerNode.meta.prefix[p+1:oldprefixlen]) | |
| } else { | |
| copy(n.innerNode.meta.prefix, n.innerNode.meta.prefix[p+1:maxprefixlen]) | |
| remaining := oldprefixlen - (p + 1) | |
| if remaining < 0 { | |
| remaining = 0 | |
| } | |
| n.innerNode.meta.prefixlen = remaining | |
| if remaining > 0 { | |
| fill := remaining | |
| if fill > maxprefixlen { | |
| fill = maxprefixlen | |
| } | |
| if oldprefixlen <= maxprefixlen { | |
| // All logical prefix bytes are stored in meta.prefix; shift the remaining bytes down. | |
| start := p + 1 | |
| if start > maxprefixlen { | |
| start = maxprefixlen | |
| } | |
| end := start + fill | |
| if end > maxprefixlen { | |
| end = maxprefixlen | |
| } | |
| copy(n.innerNode.meta.prefix[:fill], n.innerNode.meta.prefix[start:end]) | |
| } else { | |
| // Logical prefix exceeds maxprefixlen; rebuild remaining prefix bytes from the leaf key. | |
| leaf := fetchleaf(n) | |
| keyStart := depth + p + 1 | |
| keyEnd := keyStart + fill | |
| if keyEnd > len(leaf.leaf.key) { | |
| keyEnd = len(leaf.leaf.key) | |
| } | |
| if keyStart < keyEnd { | |
| copy(n.innerNode.meta.prefix[:], leaf.leaf.key[keyStart:keyEnd]) | |
| } | |
| } |
| 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,38 @@ | ||
| 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 | ||
| 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,42 @@ | ||||||||||||||||||||||||||
| package art | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import "fmt" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| func PrintTree(n *Node, level 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) | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| fmt.Println(indent+"Node(prefix=\""+prefix+"\", prefixLen=", prefixlen, ")") | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Print children | ||||||||||||||||||||||||||
| for i := 0; i < len(in.keys); i++ { | ||||||||||||||||||||||||||
| if in.children[i] != nil { | ||||||||||||||||||||||||||
| fmt.Printf("%s Edge('%c' | %d):\t", indent, in.keys[i], in.keys[i]) | ||||||||||||||||||||||||||
|
Comment on lines
+35
to
+37
|
||||||||||||||||||||||||||
| for i := 0; i < len(in.keys); i++ { | |
| if in.children[i] != nil { | |
| fmt.Printf("%s Edge('%c' | %d):\t", indent, in.keys[i], in.keys[i]) | |
| for i := 0; i < len(in.children); i++ { | |
| if in.children[i] != nil { | |
| var edgeKey byte | |
| if in.keys != nil && i < len(in.keys) { | |
| edgeKey = in.keys[i] | |
| } else { | |
| edgeKey = byte(i) | |
| } | |
| fmt.Printf("%s Edge('%c' | %d):\t", indent, edgeKey, edgeKey) |
| 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. | ||||||
|
||||||
| // Returns 0 (terminator) if key is exhausted. | |
| // Returns 1 (terminator) if key is exhausted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are multiple
fmt.Printlndebug prints ininsert(e.g., printing depth/keys/prefix). This will spam stdout for every insert and makes the package unusable as a library component. Please remove these prints or gate them behind an explicit debug logger/flag.