Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b1a487c
chore:Initializing project structure and node files
Bhuviiiii-prog Mar 19, 2026
058b2e5
feat:insert+utility functions
aivillio Mar 19, 2026
3577de9
Feat: Add Search/lookup function and remove insert.go
Bhuviiiii-prog Mar 20, 2026
68dbdbe
chore: fixed bug 'variable size keys index out of bounds error'
aivillio Mar 20, 2026
94bf757
Merge branch 'artDev' of github.com:Bhuviiiii-prog/radFS into dev
aivillio Mar 20, 2026
db64be6
feat:added sorting to addchild
aivillio Mar 20, 2026
3f86edc
chore: put insert and search in different files
aivillio Mar 20, 2026
72a7ead
Chore:Delete insert_test.go and added comments for search function
Bhuviiiii-prog Mar 20, 2026
f1c491b
feat: now can update values and fixed duplicate key bug in addchild
aivillio Mar 21, 2026
e5b9dde
chore: merged changes from bhuvigna
aivillio Mar 21, 2026
dfd6c14
feature: added grow, updated findchild , added num_children feild for…
aivillio Mar 24, 2026
0352d08
chore :the tree now handles the case when prefix is longer than maxp…
aivillio Mar 27, 2026
278149a
feat: removed the use of sentinal value and stores the leaf inside in…
aivillio Mar 28, 2026
34e0389
chore :week4 log
aivillio Mar 28, 2026
d85da6a
Update docs/weekly/angelo/week_4.md
aivillio Mar 28, 2026
5c3fb51
Update docs/weekly/angelo/week_4.md
aivillio Mar 28, 2026
ab066c6
chore: added deep copy to prevent to make new_node and current node i…
aivillio Mar 31, 2026
277c89c
chore:forgot to add deepcopy func from utilty
aivillio Mar 31, 2026
b423a0c
chore : made addchild and fetchleaf compatible with multiple node types
aivillio Mar 31, 2026
05e0e14
Update internal/art/insert.go
aivillio Mar 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions cmd/radFS/arttest/main.go
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)
}
8 changes: 8 additions & 0 deletions docs/weekly/angelo/week_4.md
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
23 changes: 23 additions & 0 deletions internal/art/art.go
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
}
114 changes: 114 additions & 0 deletions internal/art/insert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
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)
leafKey := leaf.leaf.key
start := depth + p + 1
if start >= len(leafKey) {
n.innerNode.meta.prefix = []byte{}
} else {
end := start + maxprefixlen
if end > len(leafKey) {
end = len(leafKey)
}
n.innerNode.meta.prefix = deepcopy(leafKey[start:end])
}
}

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

}

}
18 changes: 18 additions & 0 deletions internal/art/leaf.go
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
}
41 changes: 41 additions & 0 deletions internal/art/node.go
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
}
15 changes: 15 additions & 0 deletions internal/art/node16.go
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}
}
16 changes: 16 additions & 0 deletions internal/art/node256.go
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}
}
15 changes: 15 additions & 0 deletions internal/art/node4.go
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}

}
15 changes: 15 additions & 0 deletions internal/art/node48.go
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}
}
73 changes: 73 additions & 0 deletions internal/art/print_tree.go
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)
}
}
}
}
Loading