This commit is contained in:
2025-01-31 15:39:44 +03:00
parent 27cb6cb0c6
commit 74ab68d05f
185 changed files with 2321 additions and 972 deletions

View File

@@ -1,7 +1,7 @@
module radixtree
fn test_basic_operations() ! {
mut rt := new(path:'/tmp/radixtree_test',reset:true)!
mut rt := new(path: '/tmp/radixtree_test', reset: true)!
// Test insert and search
rt.insert('test', 'value1'.bytes())!
@@ -20,15 +20,15 @@ fn test_basic_operations() ! {
// Test delete
rt.delete('test')!
mut ok:=false
mut ok := false
if _ := rt.search('test') {
ok=true
ok = true
}
assert ok
}
fn test_prefix_matching() ! {
mut rt := new(path:'/tmp/radixtree_test_prefix')!
mut rt := new(path: '/tmp/radixtree_test_prefix')!
// Insert keys with common prefixes
rt.insert('team', 'value1'.bytes())!
@@ -47,7 +47,7 @@ fn test_prefix_matching() ! {
// Delete middle key and verify others still work
rt.delete('test')!
if _ := rt.search('test') {
assert false, 'Expected error after deletion'
}
@@ -60,7 +60,7 @@ fn test_prefix_matching() ! {
}
fn test_edge_cases() ! {
mut rt := new(path:'/tmp/radixtree_test_edge')!
mut rt := new(path: '/tmp/radixtree_test_edge')!
// Test empty key
rt.insert('', 'empty'.bytes())!
@@ -89,7 +89,7 @@ fn test_edge_cases() ! {
}
fn test_multiple_operations() ! {
mut rt := new(path:'/tmp/radixtree_test_multiple')!
mut rt := new(path: '/tmp/radixtree_test_multiple')!
// Insert multiple keys
keys := ['abc', 'abcd', 'abcde', 'bcd', 'bcde']
@@ -110,7 +110,7 @@ fn test_multiple_operations() ! {
// Verify remaining keys
remaining := ['abc', 'abcde', 'bcd']
expected := ['value1', 'value3', 'value4']
for i, key in remaining {
value := rt.search(key)!
assert value.bytestr() == expected[i]

View File

@@ -6,39 +6,38 @@ import freeflowuniverse.herolib.data.ourdb
struct Node {
mut:
key_segment string // The segment of the key stored at this node
value []u8 // Value stored at this node (empty if not a leaf)
children []NodeRef // References to child nodes
is_leaf bool // Whether this node is a leaf node
value []u8 // Value stored at this node (empty if not a leaf)
children []NodeRef // References to child nodes
is_leaf bool // Whether this node is a leaf node
}
// Reference to a node in the database
struct NodeRef {
mut:
key_part string // The key segment for this child
node_id u32 // Database ID of the node
node_id u32 // Database ID of the node
}
// RadixTree represents a radix tree data structure
pub struct RadixTree {
mut:
db &ourdb.OurDB // Database for persistent storage
root_id u32 // Database ID of the root node
root_id u32 // Database ID of the root node
}
pub struct NewArgs {
pub mut:
path string
path string
reset bool
}
// Creates a new radix tree with the specified database path
pub fn new(args NewArgs) !&RadixTree {
mut db := ourdb.new(
path: args.path
record_size_max: 1024 * 4 // 4KB max record size
path: args.path
record_size_max: 1024 * 4 // 4KB max record size
incremental_mode: true
reset:args.reset
reset: args.reset
)!
mut root_id := u32(0)
@@ -47,11 +46,11 @@ pub fn new(args NewArgs) !&RadixTree {
println('Debug: Creating new root node')
root := Node{
key_segment: ''
value: []u8{}
children: []NodeRef{}
is_leaf: false
value: []u8{}
children: []NodeRef{}
is_leaf: false
}
root_id = db.set(data: serialize_node(root))!
root_id = db.set(data: serialize_node(root))!
println('Debug: Created root node with ID ${root_id}')
assert root_id == 0
} else {
@@ -62,7 +61,7 @@ pub fn new(args NewArgs) !&RadixTree {
}
return &RadixTree{
db: &db
db: &db
root_id: root_id
}
}
@@ -83,7 +82,7 @@ pub fn (mut rt RadixTree) insert(key string, value []u8) ! {
for offset < key.len {
mut node := deserialize_node(rt.db.get(current_id)!)!
// Find matching child
mut matched_child := -1
for i, child in node.children {
@@ -98,33 +97,33 @@ pub fn (mut rt RadixTree) insert(key string, value []u8) ! {
key_part := key[offset..]
new_node := Node{
key_segment: key_part
value: value
children: []NodeRef{}
is_leaf: true
value: value
children: []NodeRef{}
is_leaf: true
}
println('Debug: Creating new leaf node with key_part "${key_part}"')
new_id := rt.db.set(data: serialize_node(new_node))!
println('Debug: Created node ID ${new_id}')
// Create new child reference and update parent node
println('Debug: Updating parent node ${current_id} to add child reference')
// Get fresh copy of parent node
mut parent_node := deserialize_node(rt.db.get(current_id)!)!
println('Debug: Parent node initially has ${parent_node.children.len} children')
// Add new child reference
parent_node.children << NodeRef{
key_part: key_part
node_id: new_id
node_id: new_id
}
println('Debug: Added child reference, now has ${parent_node.children.len} children')
// Update parent node in DB
println('Debug: Serializing parent node with ${parent_node.children.len} children')
parent_data := serialize_node(parent_node)
println('Debug: Parent data size: ${parent_data.len} bytes')
// First verify we can deserialize the data correctly
println('Debug: Verifying serialization...')
if test_node := deserialize_node(parent_data) {
@@ -133,17 +132,17 @@ pub fn (mut rt RadixTree) insert(key string, value []u8) ! {
println('Debug: ERROR - Failed to deserialize test data')
return error('Serialization verification failed')
}
// Set with explicit ID to update existing node
println('Debug: Writing to DB...')
rt.db.set(id: current_id, data: parent_data)!
// Verify by reading back and comparing
println('Debug: Reading back for verification...')
verify_data := rt.db.get(current_id)!
verify_node := deserialize_node(verify_data)!
println('Debug: Verification - node has ${verify_node.children.len} children')
if verify_node.children.len == 0 {
println('Debug: ERROR - Node update verification failed!')
println('Debug: Original node children: ${node.children.len}')
@@ -159,24 +158,24 @@ pub fn (mut rt RadixTree) insert(key string, value []u8) ! {
child := node.children[matched_child]
common_prefix := get_common_prefix(key[offset..], child.key_part)
if common_prefix.len < child.key_part.len {
// Split existing node
mut child_node := deserialize_node(rt.db.get(child.node_id)!)!
// Create new intermediate node
mut new_node := Node{
key_segment: child.key_part[common_prefix.len..]
value: child_node.value
children: child_node.children
is_leaf: child_node.is_leaf
value: child_node.value
children: child_node.children
is_leaf: child_node.is_leaf
}
new_id := rt.db.set(data: serialize_node(new_node))!
// Update current node
node.children[matched_child] = NodeRef{
key_part: common_prefix
node_id: new_id
node_id: new_id
}
rt.db.set(id: current_id, data: serialize_node(node))!
}
@@ -211,7 +210,7 @@ pub fn (mut rt RadixTree) search(key string) ![]u8 {
for offset < key.len {
node := deserialize_node(rt.db.get(current_id)!)!
mut found := false
for child in node.children {
if key[offset..].starts_with(child.key_part) {
@@ -245,7 +244,7 @@ pub fn (mut rt RadixTree) delete(key string) ! {
// Find the node to delete
for offset < key.len {
node := deserialize_node(rt.db.get(current_id)!)!
mut found := false
for child in node.children {
if key[offset..].starts_with(child.key_part) {
@@ -279,7 +278,7 @@ pub fn (mut rt RadixTree) delete(key string) ! {
mut last_node := deserialize_node(rt.db.get(path.last().node_id)!)!
last_node.is_leaf = false
last_node.value = []u8{}
// If node has no children, remove it from parent
if last_node.children.len == 0 {
if path.len > 1 {

View File

@@ -50,7 +50,7 @@ pub fn (mut rt RadixTree) debug_db() ! {
// Prints the tree structure starting from a given node ID
pub fn (mut rt RadixTree) print_tree_from_node(node_id u32, indent string) ! {
node := rt.get_node_by_id(node_id)!
mut node_info := '${indent}Node(id: ${node_id})'
node_info += '\n${indent} key_segment: "${node.key_segment}"'
node_info += '\n${indent} is_leaf: ${node.is_leaf}'
@@ -61,7 +61,9 @@ pub fn (mut rt RadixTree) print_tree_from_node(node_id u32, indent string) ! {
if node.children.len > 0 {
node_info += ' ['
for i, child in node.children {
if i > 0 { node_info += ', ' }
if i > 0 {
node_info += ', '
}
node_info += '${child.node_id}:${child.key_part}'
}
node_info += ']'
@@ -90,7 +92,7 @@ pub fn (mut rt RadixTree) print_tree() ! {
// Gets detailed information about a specific node
pub fn (mut rt RadixTree) get_node_info(id u32) !string {
node := rt.get_node_by_id(id)!
mut info := 'Node Details:\n'
info += '=============\n'
info += 'ID: ${id}\n'
@@ -106,6 +108,6 @@ pub fn (mut rt RadixTree) get_node_info(id u32) !string {
info += '- ID: ${child.node_id}, Key Part: "${child.key_part}"\n'
}
}
return info
}

View File

@@ -2,57 +2,55 @@ module radixtree
import freeflowuniverse.herolib.data.encoder
const (
version = u8(1) // Current binary format version
)
const version = u8(1) // Current binary format version
// Serializes a node to bytes for storage
fn serialize_node(node Node) []u8 {
mut e := encoder.new()
// Add version byte
e.add_u8(version)
// Add key segment
e.add_string(node.key_segment)
// Add value as []u8
e.add_u16(u16(node.value.len))
e.data << node.value
// Add children
e.add_u16(u16(node.children.len))
for child in node.children {
e.add_string(child.key_part)
e.add_u32(child.node_id)
}
// Add leaf flag
e.add_u8(if node.is_leaf { u8(1) } else { u8(0) })
return e.data
}
// Deserializes bytes to a node
fn deserialize_node(data []u8) !Node {
mut d := encoder.decoder_new(data)
// Read and verify version
version_byte := d.get_u8()
if version_byte != version {
return error('Invalid version byte: expected ${version}, got ${version_byte}')
}
// Read key segment
key_segment := d.get_string()
// Read value as []u8
value_len := d.get_u16()
mut value := []u8{len: int(value_len)}
for i in 0..int(value_len) {
for i in 0 .. int(value_len) {
value[i] = d.get_u8()
}
// Read children
children_len := d.get_u16()
mut children := []NodeRef{cap: int(children_len)}
@@ -61,17 +59,17 @@ fn deserialize_node(data []u8) !Node {
node_id := d.get_u32()
children << NodeRef{
key_part: key_part
node_id: node_id
node_id: node_id
}
}
// Read leaf flag
is_leaf := d.get_u8() == 1
return Node{
key_segment: key_segment
value: value
children: children
is_leaf: is_leaf
value: value
children: children
is_leaf: is_leaf
}
}

View File

@@ -4,35 +4,35 @@ fn test_serialize_deserialize() {
// Create a test node with children
node := Node{
key_segment: 'test'
value: 'hello world'.bytes()
children: [
value: 'hello world'.bytes()
children: [
NodeRef{
key_part: 'child1'
node_id: 1
node_id: 1
},
NodeRef{
key_part: 'child2'
node_id: 2
}
node_id: 2
},
]
is_leaf: true
is_leaf: true
}
// Serialize
data := serialize_node(node)
// Verify version byte
assert data[0] == version
// Deserialize
decoded := deserialize_node(data)!
// Verify all fields match
assert decoded.key_segment == node.key_segment
assert decoded.value == node.value
assert decoded.is_leaf == node.is_leaf
assert decoded.children.len == node.children.len
// Verify children
assert decoded.children[0].key_part == node.children[0].key_part
assert decoded.children[0].node_id == node.children[0].node_id
@@ -44,14 +44,14 @@ fn test_empty_node() {
// Test node with empty values
node := Node{
key_segment: ''
value: []u8{}
children: []NodeRef{}
is_leaf: false
value: []u8{}
children: []NodeRef{}
is_leaf: false
}
data := serialize_node(node)
decoded := deserialize_node(data)!
assert decoded.key_segment == node.key_segment
assert decoded.value == node.value
assert decoded.children == node.children
@@ -62,27 +62,27 @@ fn test_large_values() {
// Create large test data
mut large_value := []u8{len: 1000, init: u8(index & 0xFF)}
mut children := []NodeRef{cap: 100}
for i in 0..100 {
for i in 0 .. 100 {
children << NodeRef{
key_part: 'child${i}'
node_id: u32(i)
node_id: u32(i)
}
}
node := Node{
key_segment: 'large_test'
value: large_value
children: children
is_leaf: true
value: large_value
children: children
is_leaf: true
}
data := serialize_node(node)
decoded := deserialize_node(data)!
assert decoded.key_segment == node.key_segment
assert decoded.value == node.value
assert decoded.children.len == node.children.len
// Verify some random children
assert decoded.children[0] == node.children[0]
assert decoded.children[50] == node.children[50]
@@ -92,15 +92,15 @@ fn test_large_values() {
fn test_invalid_version() {
node := Node{
key_segment: 'test'
value: []u8{}
children: []NodeRef{}
is_leaf: false
value: []u8{}
children: []NodeRef{}
is_leaf: false
}
mut data := serialize_node(node)
// Corrupt version byte
data[0] = 255
// Should return error for version mismatch
if result := deserialize_node(data) {
assert false, 'Expected error for invalid version byte'