81 lines
1.9 KiB
Plaintext
81 lines
1.9 KiB
Plaintext
import "@std/mem"
|
|
import "@std/arraylist"
|
|
import "@std/hashmap"
|
|
import "@std/testing"
|
|
|
|
StringId :: alias usize
|
|
|
|
StringPool :: struct {
|
|
ids hashmap.StringHashMap(StringId) # string → id
|
|
strings arraylist.ArrayList([]u8) # id → owned string
|
|
allocator mem.Allocator
|
|
}
|
|
|
|
init func(allocator mem.Allocator) StringPool {
|
|
return StringPool{
|
|
ids = hashmap.init(allocator),
|
|
strings = arraylist.init(allocator),
|
|
allocator = allocator,
|
|
}
|
|
}
|
|
|
|
deinit func(pool @mut StringPool) void {
|
|
hashmap.deinit(&pool.ids)
|
|
for pool.strings.items |str| {
|
|
mem.free(pool.allocator, str)
|
|
}
|
|
arraylist.deinit(&pool.strings)
|
|
}
|
|
|
|
intern func(pool @mut StringPool, str []u8) StringId ! mem.AllocError {
|
|
if hashmap.get(&pool.ids, str) |id| return id
|
|
|
|
id :: pool.strings.items.len
|
|
owned_str []mut u8 :: try mem.alloc(u8, pool.allocator, str.len)
|
|
errdefer mem.free(pool.allocator, owned_str)
|
|
memcopy!(owned_str, str)
|
|
|
|
try arraylist.append(&pool.strings, owned_str)
|
|
errdefer _ = arraylist.pop(&pool.strings)
|
|
|
|
hashmap.put(&pool.ids, owned_str, id) catch |err| {
|
|
match err {
|
|
.key_exists: unreachable
|
|
else: return err
|
|
}
|
|
}
|
|
|
|
return id
|
|
}
|
|
|
|
get_str func(pool @StringPool, id StringId) ?[]u8 {
|
|
if (id >= pool.strings.items.len) return null
|
|
return pool.strings.items[id]
|
|
}
|
|
|
|
get_id func(pool @StringPool, str []u8) ?StringId {
|
|
return hashmap.get(&pool.ids, str)
|
|
}
|
|
|
|
handles_intern test {
|
|
pool StringPool = init(mem.c_allocator)
|
|
defer deinit(&pool)
|
|
|
|
input [5]mut u8 = ['h', 'e', 'l', 'l', 'o']
|
|
id :: try intern(&pool, input[..])
|
|
duplicate :: try intern(&pool, "hello")
|
|
input[0] = 'j'
|
|
|
|
same_id :: get_id(&pool, "hello")
|
|
mutated_id :: get_id(&pool, input[..])
|
|
hello_str :: get_str(&pool, id)
|
|
invalid_str :: get_str(&pool, id + 1)
|
|
|
|
try testing.expect_equal(0, id)
|
|
try testing.expect_equal(id, duplicate)
|
|
try testing.expect_equal(id, same_id?)
|
|
try testing.expect_equal(null, mutated_id)
|
|
try testing.expect_equal(null, invalid_str)
|
|
try testing.expect_equal("hello", hello_str?)
|
|
}
|