//----------------------------------------------------------------------------- // Array //----------------------------------------------------------------------------- template struct Array{ Allocator *allocator; T *data; S64 cap; S64 len; T *push_empty(S64 count = 1){ grow(count); T *result = data + len; len += count; return result; } T *push_empty_zero(S64 count = 1){ T *result = push_empty(count); memory_zero(result, count*sizeof(T)); return result; } void grow(S64 required_size){ if(cap == 0){ S64 new_cap = max(required_size*2, (S64)16); data = allocate_array(allocator, T, new_cap); cap = new_cap; } else if(len + required_size > cap){ U64 new_cap = max(cap * 2, len+required_size+1); T *new_data = allocate_array(allocator, T, new_cap); memory_copy(new_data, data, cap*sizeof(T)); deallocate(allocator, data); data = new_data; cap = new_cap; } } S64 get_index(T *item){ assert((data <= item) && ((data + len) > item)); size_t offset = item - data; return (S64)offset; } void add(Array items){ For(items){ add(it); } } void add(T item){ grow(1); data[len++] = item; } S64 addi(T item){ S64 result = len; grow(1); data[len++] = item; return result; } void unordered_remove(T *item){ assert(len > 0); assert((data <= item) && ((data + len) > item)); *item = data[--len]; } void init(Allocator *a, S64 size = 16){ allocator = a; data = allocate_array(a, T, size); cap = size; } Array copy(Allocator *a){ Array result = {}; result.len = len; result.cap = len*2; result.allocator = a; result.data = allocate_array(a, T, result.cap); memory_copy(result.data, data, sizeof(T)*result.len); return result; } Array tight_copy(Allocator *a){ Array result = {}; result.len = len; result.cap = len; result.allocator = 0; result.data = allocate_array(a, T, len); memory_copy(result.data, data, sizeof(T)*len); return result; } force_inline B32 is_last(T *item){ return item == last(); } force_inline B32 is_first(T *item){ return item == begin(); } force_inline void clear(){ len = 0; } force_inline T pop() { return data[--len]; } force_inline T *last() { return data + len - 1; } force_inline T *begin() { return data; } force_inline T *end () { return data + len; } force_inline T &operator[](S64 i){ assert(i >= 0 && i < cap); return data[i]; } struct Array_Iter{ Array *array; S64 i; T *item; force_inline void next(){ i+=1; item = &array->data[i]; } force_inline B32 is_valid(){ return i < array->len; } }; force_inline Array_Iter iter(){ return {this, 0, begin()};} #define For_It_Named(array, it) for(auto it = (array).iter(); it.is_valid(); it.next()) #define For_It(array) For_It_Named(array, it) }; template CORE_Static Array array_make(Allocator *a, S64 size = 16){ Array result = {}; result.init(a, size); return result; } //----------------------------------------------------------------------------- // Map //----------------------------------------------------------------------------- struct Map_Key_Value{ int occupied; U64 key; void *value; }; struct Map{ Allocator *allocator; Map_Key_Value *data; S64 len; S64 cap; }; CORE_Static void map_insert(Map *map, U64 key, void *val); CORE_Static void map_grow(Map *map, S64 new_size){ new_size = max((S64)16, new_size); assert(new_size > map->cap); assert(is_pow2(new_size)); assert(map->allocator); Map new_map = {}; new_map.data = allocate_array(map->allocator, Map_Key_Value, new_size); new_map.cap = new_size; new_map.allocator = map->allocator; for(S64 i = 0; i < map->cap; i++){ if(map->data[i].occupied){ map_insert(&new_map, map->data[i].key, map->data[i].value); } } if(map->data) deallocate(map->allocator, map->data); *map = new_map; } CORE_Static Map map_make(Allocator *a, S64 size){ Map result = {a}; map_grow(&result, size); return result; } CORE_Static void map_insert(Map *map, U64 key, void *val){ assert(val); assert(key); // if(key == 0) key+=1; if((2*map->len) + 1 > map->cap){ map_grow(map, 2*map->cap); } U64 hash = hash_u64(key); U64 index = wrap_around_pow2(hash, map->cap); U64 i = index; for(;;){ if(map->data[i].occupied == false){ map->len++; map->data[i].occupied = true; map->data[i].key = key; map->data[i].value = val; return; } else if(map->data[i].key == key){ map->data[i].value = val; return; } i = wrap_around_pow2(i+1, map->cap); if(i == map->cap){ return; } } } CORE_Static Map_Key_Value * map_base_get(Map *map, U64 key){ if(map->len == 0) return 0; assert(key); U64 hash = hash_u64(key); U64 index = wrap_around_pow2(hash, map->cap); U64 i = index; for(;;){ if(map->data[i].key == key){ return map->data + i; } else if(map->data[i].key == 0){ return 0; } i = wrap_around_pow2(i+1, map->cap); if(i == map->cap){ return 0; } } } CORE_Static void * map_get(Map *map, U64 key){ Map_Key_Value *result = map_base_get(map, key); if(result && result->occupied) return result->value; return 0; } CORE_Static void * map_remove(Map *map, U64 key){ Map_Key_Value *kv = map_base_get(map, key); if(kv){ kv->occupied = false; return kv->value; } return 0; } CORE_Static void * map_get(Map *map, void *pointer){ return map_get(map, (U64)pointer); } CORE_Static void * map_get(Map *map, Intern_String string){ return map_get(map, hash_string(string.s)); } CORE_Static void map_insert(Map *map, void *key, void *value){ map_insert(map, (U64)key, value); } CORE_Static void map_insert(Map *map, Intern_String key, void *value){ map_insert(map, hash_string(key.s), value); } //----------------------------------------------------------------------------- // String intern //----------------------------------------------------------------------------- struct Intern_Table{ Allocator *string_allocator; Map map; U8 *first_keyword; U8 *last_keyword; }; CORE_Static Intern_Table intern_table_make(Allocator *string_allocator, Allocator *map_allocator, S64 initial_size = 32){ Intern_Table result = {}; result.map = map_make(map_allocator, initial_size); result.string_allocator = string_allocator; return result; } CORE_Static Intern_String intern_string(Intern_Table *t, String string){ assert(t->string_allocator); U64 hash = hash_string(string); U8 *slot = (U8 *)map_get(&t->map, hash); if(slot){ // @todo: Is this a cast bug: *(slot-sizeof(S64))? slot is u8 so truncates? Intern_String result = {{slot, *(slot-sizeof(S64))}}; return result; } S64 *len_address = (S64 *)allocate_size(t->string_allocator, string.len+1+sizeof(S64), false); *len_address = string.len; U8 *string_address = (U8 *)(len_address + 1); memory_copy(string_address, string.str, string.len); string_address[string.len] = 0; map_insert(&t->map, hash, string_address); Intern_String result = {{string_address, *len_address}}; return result; } //----------------------------------------------------------------------------- // Array List // @todo(krzosa): If even one item got removed from block // the block should go on free list //----------------------------------------------------------------------------- const int LIST_DEFAULT_BLOCK_SIZE = 32; const int LIST_DEFAULT_ALLOCATION_MUL = 2; template struct List_Node{ List_Node *next; List_Node *prev; int cap; int len; T data[]; }; template struct List{ int block_size = 0; int allocation_multiplier = 0; List_Node *first = 0; List_Node *last = 0; List_Node *first_free = 0; }; template List_Node *list_allocate_node(Allocator *arena, int size){ auto node = (List_Node *)allocate_size(arena, sizeof(List_Node) + size*sizeof(T), false); node->cap = size; node->len = 0; node->next = 0; node->prev = 0; return node; } template void list_allocate_free_node(Allocator *arena, List *list, int size){ List_Node *node = list_allocate_node(arena, size); DLL_STACK_ADD(list->first_free, node); } template void list_make_sure_there_is_room_for_item_count(Allocator *arena, List *list, int item_count){ if(list->last == 0 || list->last->len + item_count > list->last->cap){ // Not enough space we need to get a new block List_Node *node = 0; // Iterate the free list to check if we have a block of required size there For_Linked_List(list->first_free){ if(it->cap >= item_count){ DLL_STACK_REMOVE(list->first_free, it); node = it; node->len = 0; break; } } // We don't have a block on the free list need to allocate if(!node){ // Set default values if not initialized if(!list->allocation_multiplier) list->allocation_multiplier = LIST_DEFAULT_ALLOCATION_MUL; if(!list->block_size) list->block_size = LIST_DEFAULT_BLOCK_SIZE; if(item_count > list->block_size) list->block_size = item_count*2; node = list_allocate_node(arena, list->block_size); list->block_size *= list->allocation_multiplier; } assert(node); DLL_QUEUE_ADD_LAST(list->first, list->last, node); } } template T *list_get(List *list, int index, List_Node **node = 0, int *in_block_index = 0){ if(list){ int i = 0; For_Linked_List(list->first){ int lookup_i = index - i; if(lookup_i < it->len) { if(node) *node = it; if(in_block_index) *in_block_index = lookup_i; return it->data + lookup_i; } i += it->len; } } return 0; } template T *getp(List *list, int index){ return list_get(list, index); } template T get(List *list, int index){ return *list_get(list, index); } template void add(Allocator *arena, List *list, T item){ list_make_sure_there_is_room_for_item_count(arena, list, 1); list->last->data[list->last->len++] = item; } template T *add_size(Allocator *arena, List *list, int count = 1, int zero_memory = 0){ list_make_sure_there_is_room_for_item_count(arena, list, count); T *result = list->last->data + list->last->len; list->last->len += count; if(zero_memory){ memory_zero(result, sizeof(T)*count); } return result; } template void list_free_node(List *list, List_Node *node){ #if 1 // Make sure it's actually in list list bool found = false; For_Linked_List(list->first){ if(it == node){ found = true; break; } } assert(found); #endif DLL_QUEUE_REMOVE(list->first, list->last, node); DLL_STACK_ADD(list->first_free, node); } template void clear(List *list){ memory_zero(list, sizeof(List)); } template int length(List *list){ int result = 0; For_Linked_List(list->first){ result += it->len; } return result; } template void free_all_nodes(List *list){ assert(!list->last->next); assert(!list->first->prev); list->last->next = list->first_free; if(list->first_free) list->first_free->prev = list->last; list->first_free = list->first; list->last = list->first = 0; } template T ordered_remove(List *list, int index){ List_Node *node; int in_block_index; T *data = list_get(list, index, &node, &in_block_index); assert_message(data, "Trying to unordered_remove element that's outside of the List"); if(!data) return {}; T result = *data; // Check if we need to deallocate the block if(node->len == 1) { list_free_node(list, node); return result; } // We need to move part of the block to fill the new empty spot int right_count = (--node->len) - in_block_index; memory_copy(data, data+1, sizeof(T)*right_count); return result; } template T unordered_remove(List *list, int index){ List_Node *node; T *data = list_get(list, index, &node); assert_message(data, "Trying to unordered_remove element that's outside of the List"); if(!data) return {}; assert(node->len); assert(node->cap); // Swap T result = *data; *data = node->data[node->len - 1]; node->len -= 1; if(node->len == 0){ list_free_node(list, node); } return result; } template T pop(List *list){ assert(list->last != 0); assert(list->last->len > 0); T result = list->last->data[--list->last->len]; if(list->last->len == 0){ list_free_node(list, list->last); } return result; } template T *merge(Allocator *arena, List *list){ int len = length(list); T *result = allocate_size(arena, T, len, false); int i = 0; For_Linked_List(list->first){ memory_copy(result + i, it->data, it->len*sizeof(T)); i += it->len; } return result; } template struct List_Iter{ T *item; int index; List_Node *node; int node_index; }; template void advance(List_Iter *iter){ if(!iter->node) return; if(iter->node_index + 1 >= iter->node->len){ iter->node = iter->node->next; iter->node_index = -1; iter->item = 0; } if(iter->node){ iter->node_index += 1; iter->index += 1; iter->item = iter->node->data + iter->node_index; } } template List_Iter iterate(List *list){ List_Iter result = {}; result.node = list->first; result.index = result.node_index = -1; advance(&result); return result; } template bool should_we_continue(List_Iter *iter){ return iter->item != 0; }