Files
prog8/examples/pointers/hashtable.p8

248 lines
6.8 KiB
Lua

; Doubly Linked List with Hash Table Cache
; Demonstrates advanced pointer usage with a combination of doubly linked lists and hash tables
; for efficient data storage and retrieval
; TODO fix this AI generated code
%import math
%import strings
%import textio
%zeropage basicsafe
main {
sub start() {
txt.print("Doubly Linked List with Hash Table Cache Demo\n")
txt.print("============================================\n\n")
; Initialize the data structure
cache.init()
; Add some sample data
txt.print("Adding sample data...\n")
cache.add("Alice", "Engineer", 30)
cache.add("Bob", "Designer", 25)
cache.add("Charlie", "Manager", 35)
cache.add("Diana", "Developer", 28)
cache.add("Eve", "Analyst", 32)
txt.print("\nForward traversal:\n")
cache.print_forward()
txt.print("\nBackward traversal:\n")
cache.print_backward()
txt.print("\nSearching for specific entries:\n")
txt.print("Looking for 'Charlie': ")
^^cache.Entry entry = cache.find("Charlie")
if entry!=0 {
txt.print(entry.name)
txt.print(" - ")
txt.print(entry.job)
txt.print(" (")
txt.print_ub(entry.age)
txt.print(" years old)\n")
} else {
txt.print("Not found\n")
}
txt.print("Looking for 'Frank': ")
entry = cache.find("Frank")
if entry!=0 {
txt.print("Found\n")
} else {
txt.print("Not found\n")
}
txt.print("\nRemoving 'Bob'...\n")
void cache.remove("Bob")
txt.print("Forward traversal after removal:\n")
cache.print_forward()
txt.print("\nDemonstrating hash collision handling...\n")
; Add entries that will likely collide in the hash table
cache.add("A", "First", 20)
cache.add("B", "Second", 21)
cache.add("C", "Third", 22)
txt.print("Added entries with potential hash collisions.\n")
txt.print("Forward traversal:\n")
cache.print_forward()
}
}
cache {
struct Entry {
^^Entry next ; Next entry in the list
^^Entry prev ; Previous entry in the list
^^Entry hash_next ; Next entry in the hash bucket
str name ; Name (key)
str job ; Job description
ubyte age ; Age
}
const ubyte HASH_TABLE_SIZE = 16
^^Entry[HASH_TABLE_SIZE] hash_table ; Hash table for fast lookups
^^Entry head = 0 ; Head of the doubly linked list
^^Entry tail = 0 ; Tail of the doubly linked list
uword count = 0 ; Number of entries
sub init() {
; Initialize hash table buckets to null
ubyte i
for i in 0 to HASH_TABLE_SIZE-1
hash_table[i] = 0
}
sub hash(str key) -> ubyte {
; Simple hash function
ubyte hash_value = 0
ubyte i = 0
while key[i] != 0 {
hash_value = hash_value * 31 + key[i]
i++
}
return hash_value % HASH_TABLE_SIZE
}
sub add(str name, str job, ubyte age) {
; Create new entry
^^Entry new_entry = arena.alloc(sizeof(Entry))
ubyte name_len = strings.length(name)
ubyte job_len = strings.length(job)
^^ubyte name_copy = arena.alloc(name_len + 1)
^^ubyte job_copy = arena.alloc(job_len + 1)
void strings.copy(name, name_copy)
void strings.copy(job, job_copy)
new_entry.name = name_copy
new_entry.job = job_copy
new_entry.age = age
new_entry.next = 0
new_entry.prev = 0
new_entry.hash_next = 0
; Add to the end of the doubly linked list
if head == 0 {
; First entry
head = new_entry
tail = new_entry
} else {
; Add to the end
tail.next = new_entry
new_entry.prev = tail
tail = new_entry
}
; Add to hash table
ubyte bucket = hash(name)
new_entry.hash_next = hash_table[bucket]
hash_table[bucket] = new_entry
count++
txt.print("Added: ")
txt.print(name)
txt.print("\n")
}
sub find(str name) -> ^^Entry {
; Find entry using hash table for O(1) average case
ubyte bucket = hash(name)
^^Entry current = hash_table[bucket]
while current != 0 {
if strings.compare(current.name, name) == 0
return current
current = current.hash_next
}
return 0 ; Not found
}
sub remove(str name) -> bool {
; Find the entry
^^Entry to_remove = find(name)
if to_remove == 0
return false ; Not found
; Remove from doubly linked list
if to_remove.prev != 0
to_remove.prev.next = to_remove.next
else
head = to_remove.next ; Was the head
if to_remove.next != 0
to_remove.next.prev = to_remove.prev
else
tail = to_remove.prev ; Was the tail
; Remove from hash table
ubyte bucket = hash(name)
if hash_table[bucket] == to_remove {
hash_table[bucket] = to_remove.hash_next
} else {
^^Entry current = hash_table[bucket]
while current.hash_next != 0 {
if current.hash_next == to_remove {
current.hash_next = to_remove.hash_next
break
}
current = current.hash_next
}
}
count--
txt.print("Removed: ")
txt.print(name)
txt.print("\n")
return true
}
sub print_forward() {
^^Entry current = head
while current != 0 {
txt.print("- ")
txt.print(current.name)
txt.print(" (")
txt.print(current.job)
txt.print(", ")
txt.print_ub(current.age)
txt.print(")\n")
current = current.next
}
txt.print("Total entries: ")
txt.print_uw(count)
txt.print("\n")
}
sub print_backward() {
^^Entry current = tail
while current != 0 {
txt.print("- ")
txt.print(current.name)
txt.print(" (")
txt.print(current.job)
txt.print(", ")
txt.print_ub(current.age)
txt.print(")\n")
current = current.prev
}
txt.print("Total entries: ")
txt.print_uw(count)
txt.print("\n")
}
}
arena {
; Simple arena allocator
uword buffer = memory("arena", 8000, 0)
uword next = buffer
sub alloc(ubyte size) -> uword {
defer next += size
return next
}
}