88 lines
1.9 KiB
Odin
88 lines
1.9 KiB
Odin
// String interning thingy
|
|
|
|
package name
|
|
|
|
import "core:mem"
|
|
import "core:strings"
|
|
import "core:sync"
|
|
|
|
// When enabled name globals will be initialized automatically
|
|
NAME_STATIC_INIT :: #config(NAME_STATIC_INIT, true)
|
|
MAX_STATIC_NAMES :: #config(MAX_STATIC_NAMES, 1024)
|
|
|
|
Name :: distinct u32
|
|
|
|
NONE :: Name(0)
|
|
|
|
Container :: struct {
|
|
lock: sync.Atomic_RW_Mutex,
|
|
names_lookup: map[string]Name,
|
|
names_allocator: mem.Dynamic_Arena,
|
|
names_array: [dynamic]string,
|
|
}
|
|
|
|
@(private = "file")
|
|
global_container: ^Container
|
|
|
|
setup_global_container :: proc(cnt: ^Container) {
|
|
global_container = cnt
|
|
}
|
|
|
|
init :: proc(cnt: ^Container) {
|
|
mem.dynamic_arena_init(&cnt.names_allocator)
|
|
assert(len(cnt.names_array) == 0)
|
|
|
|
append(&cnt.names_array, "None")
|
|
}
|
|
|
|
destroy :: proc() {
|
|
assert(global_container != nil)
|
|
|
|
delete(global_container.names_array)
|
|
delete(global_container.names_lookup)
|
|
mem.dynamic_arena_destroy(&global_container.names_allocator)
|
|
global_container = nil
|
|
}
|
|
|
|
when NAME_STATIC_INIT {
|
|
@(private = "file")
|
|
static_container: Container
|
|
|
|
@(init)
|
|
init_static :: proc() {
|
|
init(&static_container)
|
|
setup_global_container(&static_container)
|
|
}
|
|
|
|
@(fini)
|
|
fini_static :: proc() {
|
|
destroy()
|
|
}
|
|
}
|
|
|
|
from_string :: proc(str: string) -> Name {
|
|
sync.atomic_rw_mutex_guard(&global_container.lock)
|
|
existing, ok := global_container.names_lookup[str]
|
|
if ok {
|
|
return existing
|
|
} else {
|
|
new_str := strings.clone(
|
|
str,
|
|
mem.dynamic_arena_allocator(&global_container.names_allocator),
|
|
)
|
|
idx := u32(len(global_container.names_array))
|
|
append(&global_container.names_array, new_str)
|
|
global_container.names_lookup[str] = Name(idx)
|
|
return Name(idx)
|
|
}
|
|
}
|
|
|
|
to_string :: proc(name: Name) -> string {
|
|
sync.atomic_rw_mutex_shared_guard(&global_container.lock)
|
|
return global_container.names_array[name]
|
|
}
|
|
|
|
to_cstring :: proc(name: Name) -> cstring {
|
|
return strings.unsafe_string_to_cstring(to_string(name))
|
|
}
|