349 lines
9.4 KiB
C++
349 lines
9.4 KiB
C++
|
/*
|
||
|
4coder_variables.cpp - Variables system
|
||
|
*/
|
||
|
|
||
|
// TOP
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): String hashing
|
||
|
|
||
|
global Arena vars_arena = {};
|
||
|
global Table_Data_u64 vars_string_to_id = {};
|
||
|
global Table_u64_Data vars_id_to_string = {};
|
||
|
global String_ID vars_string_id_counter = 0;
|
||
|
|
||
|
function void
|
||
|
_vars_init(void){
|
||
|
local_persist b32 did_init = false;
|
||
|
if (!did_init){
|
||
|
did_init = true;
|
||
|
Base_Allocator *base = get_base_allocator_system();
|
||
|
vars_arena = make_arena(base);
|
||
|
vars_string_to_id = make_table_Data_u64(base, 100);
|
||
|
vars_id_to_string = make_table_u64_Data(base, 100);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function String_ID
|
||
|
vars_save_string(String_Const_u8 string){
|
||
|
_vars_init();
|
||
|
|
||
|
String_ID result = 0;
|
||
|
String_Const_u8 string_data = make_data(string.str, string.size);
|
||
|
Table_Lookup location = table_lookup(&vars_string_to_id, string_data);
|
||
|
if (location.found_match){
|
||
|
table_read(&vars_string_to_id, location, &result);
|
||
|
}
|
||
|
else{
|
||
|
vars_string_id_counter += 1;
|
||
|
result = vars_string_id_counter;
|
||
|
string_data = push_data_copy(&vars_arena, string_data);
|
||
|
table_insert(&vars_string_to_id, string_data, result);
|
||
|
table_insert(&vars_id_to_string, result, string_data);
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function String_Const_u8
|
||
|
vars_read_string(Arena *arena, String_ID id){
|
||
|
_vars_init();
|
||
|
|
||
|
String_Const_u8 result = {};
|
||
|
Table_Lookup location = table_lookup(&vars_id_to_string, id);
|
||
|
if (location.found_match){
|
||
|
String_Const_u8 data = {};
|
||
|
table_read(&vars_id_to_string, location, &data);
|
||
|
result.str = push_array(arena, u8 , data.size);
|
||
|
block_copy(result.str, data.str, data.size);
|
||
|
result.size = data.size;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////
|
||
|
// NOTE(allen): Variable structure
|
||
|
|
||
|
global Variable vars_global_root = {};
|
||
|
global Variable vars_nil = {};
|
||
|
global Variable *vars_free_variables = 0;
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_get_root(void){
|
||
|
Variable_Handle handle = {&vars_global_root};
|
||
|
local_persist b32 first_call = true;
|
||
|
if (first_call){
|
||
|
first_call = false;
|
||
|
Variable *nil = vars_get_nil().ptr;
|
||
|
vars_global_root.parent = nil;
|
||
|
vars_global_root.next = nil;
|
||
|
vars_global_root.first = nil;
|
||
|
vars_global_root.last = nil;
|
||
|
}
|
||
|
return(handle);
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_get_nil(void){
|
||
|
Variable_Handle handle = {&vars_nil};
|
||
|
if (vars_nil.parent == 0){
|
||
|
vars_nil.parent = &vars_nil;
|
||
|
vars_nil.next = &vars_nil;
|
||
|
vars_nil.first = &vars_nil;
|
||
|
vars_nil.last = &vars_nil;
|
||
|
}
|
||
|
return(handle);
|
||
|
}
|
||
|
|
||
|
function b32
|
||
|
vars_is_nil(Variable_Handle var){
|
||
|
return(var.ptr == &vars_nil);
|
||
|
}
|
||
|
|
||
|
function b32
|
||
|
vars_is_nil(Variable* ptr) {
|
||
|
return(ptr == &vars_nil);
|
||
|
}
|
||
|
|
||
|
function b32
|
||
|
vars_match(Variable_Handle a, Variable_Handle b){
|
||
|
return(a.ptr == b.ptr);
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_first_child(Variable_Handle var){
|
||
|
Variable_Handle result = {var.ptr->first};
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_next_sibling(Variable_Handle var){
|
||
|
Variable_Handle result = {var.ptr->next};
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_parent(Variable_Handle var){
|
||
|
Variable_Handle result = {var.ptr->parent};
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function String_ID
|
||
|
vars_key_id_from_var(Variable_Handle var){
|
||
|
return(var.ptr->key);
|
||
|
}
|
||
|
|
||
|
function String_Const_u8
|
||
|
vars_key_from_var(Arena *arena, Variable_Handle var){
|
||
|
String_ID id = vars_key_id_from_var(var);
|
||
|
String_Const_u8 result = vars_read_string(arena, id);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function String_ID
|
||
|
vars_string_id_from_var(Variable_Handle var){
|
||
|
return(var.ptr->string);
|
||
|
}
|
||
|
|
||
|
function String_Const_u8
|
||
|
vars_string_from_var(Arena *arena, Variable_Handle var){
|
||
|
String_ID id = vars_string_id_from_var(var);
|
||
|
String_Const_u8 result = vars_read_string(arena, id);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function b32
|
||
|
vars_b32_from_var(Variable_Handle var){
|
||
|
String_ID val = vars_string_id_from_var(var);
|
||
|
b32 result = (val != 0 && val != vars_save_string_lit("false"));
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function u64
|
||
|
vars_u64_from_var(Application_Links *app, Variable_Handle var){
|
||
|
Scratch_Block scratch(app);
|
||
|
String_ID val = vars_string_id_from_var(var);
|
||
|
String_Const_u8 string = vars_read_string(scratch, val);
|
||
|
u64 result = 0;
|
||
|
if (string_match(string_prefix(string, 2), str8_lit("0x"))){
|
||
|
String_Const_u8 string_hex = string_skip(string, 2);
|
||
|
if (string_is_integer(string_hex, 0x10)){
|
||
|
result = string_to_integer(string_hex, 0x10);
|
||
|
}
|
||
|
}
|
||
|
else{
|
||
|
if (string_is_integer(string, 10)){
|
||
|
result = string_to_integer(string, 10);
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_read_key(Variable_Handle var, String_ID key){
|
||
|
Variable_Handle result = vars_get_nil();
|
||
|
for (Variable *node = var.ptr->first;
|
||
|
!vars_is_nil(node);
|
||
|
node = node->next){
|
||
|
if (node->key == key){
|
||
|
result.ptr = node;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_read_key(Variable_Handle var, String_Const_u8 key){
|
||
|
String_ID id = vars_save_string(key);
|
||
|
Variable_Handle result = vars_read_key(var, id);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function void
|
||
|
vars_set_string(Variable_Handle var, String_ID string){
|
||
|
if (var.ptr != &vars_nil){
|
||
|
var.ptr->string = string;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function void
|
||
|
vars_set_string(Variable_Handle var, String_Const_u8 string){
|
||
|
String_ID id = vars_save_string(string);
|
||
|
vars_set_string(var, id);
|
||
|
}
|
||
|
|
||
|
function void
|
||
|
_vars_free_variable_children(Variable *var){
|
||
|
for (Variable *node = var->first;
|
||
|
!vars_is_nil(node);
|
||
|
node = node->next){
|
||
|
_vars_free_variable_children(node);
|
||
|
}
|
||
|
|
||
|
if (!vars_is_nil(var->first)){
|
||
|
var->last->next = vars_free_variables;
|
||
|
vars_free_variables = var->first;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function void
|
||
|
vars_erase(Variable_Handle var, String_ID key){
|
||
|
if (var.ptr != &vars_nil){
|
||
|
Variable *prev = vars_get_nil().ptr;
|
||
|
Variable *node = var.ptr->first;
|
||
|
for (; vars_is_nil(node);
|
||
|
node = node->next){
|
||
|
if (node->key == key){
|
||
|
break;
|
||
|
}
|
||
|
prev = node;
|
||
|
}
|
||
|
|
||
|
if (!vars_is_nil(node)){
|
||
|
_vars_free_variable_children(node);
|
||
|
if (!vars_is_nil(prev)){
|
||
|
prev->next = node->next;
|
||
|
}
|
||
|
if (var.ptr->first == node){
|
||
|
var.ptr->first = node->next;
|
||
|
}
|
||
|
if (var.ptr->last == node){
|
||
|
var.ptr->last = prev;
|
||
|
}
|
||
|
sll_stack_push(vars_free_variables, node);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_new_variable(Variable_Handle var, String_ID key){
|
||
|
Variable_Handle handle = vars_get_nil();
|
||
|
if (var.ptr != &vars_nil){
|
||
|
Variable *prev = vars_get_nil().ptr;
|
||
|
Variable *node = var.ptr->first;
|
||
|
for (; !vars_is_nil(node);
|
||
|
node = node->next){
|
||
|
if (node->key == key){
|
||
|
break;
|
||
|
}
|
||
|
prev = node;
|
||
|
}
|
||
|
|
||
|
if (!vars_is_nil(node)){
|
||
|
handle.ptr = node;
|
||
|
_vars_free_variable_children(node);
|
||
|
}
|
||
|
else{
|
||
|
handle.ptr = vars_free_variables;
|
||
|
if (handle.ptr != 0){
|
||
|
sll_stack_pop(vars_free_variables);
|
||
|
}
|
||
|
else{
|
||
|
handle.ptr = push_array(&vars_arena, Variable, 1);
|
||
|
}
|
||
|
if (vars_is_nil(var.ptr->first)){
|
||
|
var.ptr->first = var.ptr->last = handle.ptr;
|
||
|
}
|
||
|
else{
|
||
|
var.ptr->last->next = handle.ptr;
|
||
|
var.ptr->last = handle.ptr;
|
||
|
}
|
||
|
handle.ptr->parent = var.ptr;
|
||
|
handle.ptr->next = vars_get_nil().ptr;
|
||
|
handle.ptr->key = key;
|
||
|
}
|
||
|
|
||
|
handle.ptr->string = 0;
|
||
|
handle.ptr->first = handle.ptr->last = vars_get_nil().ptr;
|
||
|
}
|
||
|
return(handle);
|
||
|
}
|
||
|
|
||
|
function Variable_Handle
|
||
|
vars_new_variable(Variable_Handle var, String_ID key, String_ID string){
|
||
|
Variable_Handle result = vars_new_variable(var, key);
|
||
|
vars_set_string(result, string);
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
function void
|
||
|
vars_clear_keys(Variable_Handle var){
|
||
|
if (var.ptr != &vars_nil){
|
||
|
_vars_free_variable_children(var.ptr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function void
|
||
|
vars_print_indented(Application_Links *app, Variable_Handle var, i32 indent){
|
||
|
Scratch_Block scratch(app);
|
||
|
local_persist char spaces[] =
|
||
|
" "
|
||
|
" "
|
||
|
" "
|
||
|
" ";
|
||
|
|
||
|
String_Const_u8 var_key = vars_key_from_var(scratch, var);
|
||
|
String_Const_u8 var_val = vars_string_from_var(scratch, var);
|
||
|
|
||
|
String_Const_u8 line = push_stringf(scratch, "%.*s%.*s: \"%.*s\"\n",
|
||
|
clamp_top(indent, sizeof(spaces)), spaces,
|
||
|
string_expand(var_key),
|
||
|
string_expand(var_val));
|
||
|
print_message(app, line);
|
||
|
|
||
|
i32 sub_indent = indent + 1;
|
||
|
for (Variable_Handle sub = vars_first_child(var);
|
||
|
!vars_is_nil(sub);
|
||
|
sub = vars_next_sibling(sub)){
|
||
|
vars_print_indented(app, sub, sub_indent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function void
|
||
|
vars_print(Application_Links *app, Variable_Handle var){
|
||
|
vars_print_indented(app, var, 0);
|
||
|
}
|
||
|
|
||
|
// BOTTOM
|
||
|
|