Files
herolib/lib/data/tst/tst_list.v
2025-05-04 08:19:47 +03:00

217 lines
5.9 KiB
V

module tst
import freeflowuniverse.herolib.data.ourdb
// Lists all keys with a given prefix
pub fn (mut self TST) list(prefix string) ![]string {
normalized_prefix := namefix(prefix)
println('Listing keys with prefix: "${prefix}" (normalized: "${normalized_prefix}")')
mut result := []string{}
// Handle empty prefix case - will return all keys
if normalized_prefix.len == 0 {
println('Empty prefix, collecting all keys')
self.collect_all_keys(self.root_id, '', mut result)!
println('Found ${result.len} keys: ${result}')
return result
}
// Find the prefix node first
result_info := self.navigate_to_prefix(self.root_id, normalized_prefix, 0)
if !result_info.found {
println('Prefix node not found for "${normalized_prefix}"')
return result // Empty result
}
println('Found node for prefix "${normalized_prefix}" at node ${result_info.node_id}, collecting keys')
// Collect all keys from the subtree rooted at the prefix node
self.collect_keys_with_prefix(result_info.node_id, result_info.prefix, mut result)!
println('Found ${result.len} keys with prefix "${normalized_prefix}": ${result}')
return result
}
// Result struct for prefix navigation
struct PrefixSearchResult {
found bool
node_id u32
prefix string
}
// Navigate to the node corresponding to a prefix
fn (mut self TST) navigate_to_prefix(node_id u32, prefix string, pos int) PrefixSearchResult {
// Base case: no node or out of bounds
if node_id == 0 || pos >= prefix.len {
return PrefixSearchResult{
found: false
node_id: 0
prefix: ''
}
}
// Get node
node_data := self.db.get(node_id) or {
return PrefixSearchResult{
found: false
node_id: 0
prefix: ''
}
}
node := deserialize_node(node_data) or {
return PrefixSearchResult{
found: false
node_id: 0
prefix: ''
}
}
println('Navigating node ${node_id}: char=${node.character} (${node.character.ascii_str()}), pos=${pos}, prefix_char=${prefix[pos]} (${prefix[pos].ascii_str()})')
// Character comparison
if prefix[pos] < node.character {
// Go left
println('Going left')
return self.navigate_to_prefix(node.left_id, prefix, pos)
} else if prefix[pos] > node.character {
// Go right
println('Going right')
return self.navigate_to_prefix(node.right_id, prefix, pos)
} else {
// Character match
println('Character match found')
// Check if we're at the end of the prefix
if pos == prefix.len - 1 {
println('Reached end of prefix at node ${node_id}')
// Return the exact prefix string that was passed in
return PrefixSearchResult{
found: true
node_id: node_id
prefix: prefix
}
}
// Not at end of prefix, check middle child
if node.middle_id == 0 {
println('No middle child, prefix not found')
return PrefixSearchResult{
found: false
node_id: 0
prefix: ''
}
}
// Continue to middle child with next character
return self.navigate_to_prefix(node.middle_id, prefix, pos + 1)
}
}
// Collect all keys in a subtree that have a given prefix
fn (mut self TST) collect_keys_with_prefix(node_id u32, prefix string, mut result []string) ! {
if node_id == 0 {
return
}
// Get node
node_data := self.db.get(node_id) or { return }
node := deserialize_node(node_data) or { return }
println('Collecting from node ${node_id}, char=${node.character} (${node.character.ascii_str()}), prefix="${prefix}"')
// If this node is an end of string and it's not the root, we found a key
if node.is_end_of_string && node.character != 0 {
// The prefix may already contain this node's character
if prefix.len == 0 || prefix[prefix.len - 1] != node.character {
println('Found complete key: "${prefix}${node.character.ascii_str()}"')
result << prefix + node.character.ascii_str()
} else {
println('Found complete key: "${prefix}"')
result << prefix
}
}
// Recursively search all children
if node.left_id != 0 {
self.collect_keys_with_prefix(node.left_id, prefix, mut result)!
}
// For middle child, we need to add this node's character to the prefix
if node.middle_id != 0 {
mut next_prefix := prefix
if node.character != 0 { // Skip root node
// Only add the character if it's not already at the end of the prefix
if prefix.len == 0 || prefix[prefix.len - 1] != node.character {
next_prefix += node.character.ascii_str()
}
}
self.collect_keys_with_prefix(node.middle_id, next_prefix, mut result)!
}
if node.right_id != 0 {
self.collect_keys_with_prefix(node.right_id, prefix, mut result)!
}
}
// Collect all keys in the tree
fn (mut self TST) collect_all_keys(node_id u32, prefix string, mut result []string) ! {
if node_id == 0 {
return
}
// Get node
node_data := self.db.get(node_id) or { return }
node := deserialize_node(node_data) or { return }
// Calculate current path
mut current_prefix := prefix
// If this is not the root, add the character
if node.character != 0 {
current_prefix += node.character.ascii_str()
}
// If this marks the end of a key, add it to the result
if node.is_end_of_string {
println('Found key: ${current_prefix}')
if current_prefix !in result {
result << current_prefix
}
}
// Visit all children
if node.left_id != 0 {
self.collect_all_keys(node.left_id, prefix, mut result)!
}
if node.middle_id != 0 {
self.collect_all_keys(node.middle_id, current_prefix, mut result)!
}
if node.right_id != 0 {
self.collect_all_keys(node.right_id, prefix, mut result)!
}
}
// Gets all values for keys with a given prefix
pub fn (mut self TST) getall(prefix string) ![][]u8 {
normalized_prefix := namefix(prefix)
println('Getting all values with prefix: "${prefix}" (normalized: "${normalized_prefix}")')
// Get all matching keys
keys := self.list(normalized_prefix)!
// Get values for each key
mut values := [][]u8{}
for key in keys {
if value := self.get(key) {
values << value
}
}
println('Found ${values.len} values with prefix "${normalized_prefix}"')
return values
}