Cleanup includes, remove stdio.h from base
This commit is contained in:
610
base.cpp
610
base.cpp
@@ -143,6 +143,7 @@ struct String{
|
|||||||
U8 *str;
|
U8 *str;
|
||||||
S64 len;
|
S64 len;
|
||||||
};
|
};
|
||||||
|
global String string_null = {(U8 *)"null", 4};
|
||||||
|
|
||||||
union Intern_String{ // Basically just String
|
union Intern_String{ // Basically just String
|
||||||
String s;
|
String s;
|
||||||
@@ -157,12 +158,6 @@ struct Allocator {
|
|||||||
Deallocate *deallocate;
|
Deallocate *deallocate;
|
||||||
};
|
};
|
||||||
|
|
||||||
global String string_null = {(U8 *)"null", 4};
|
|
||||||
#include <stdio.h>
|
|
||||||
#define STB_SPRINTF_IMPLEMENTATION
|
|
||||||
#include "stb_sprintf.h"
|
|
||||||
#define snprintf stbsp_snprintf
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Utilities
|
// Utilities
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -527,606 +522,3 @@ arena_sub(Arena *base, size_t size, String debug_name) {
|
|||||||
result.len = 0;
|
result.len = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Array
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template<class T>
|
|
||||||
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<T> 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<T> copy(Allocator *a){
|
|
||||||
Array<T> 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<T> tight_copy(Allocator *a){
|
|
||||||
Array<T> 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<T> *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<class T>
|
|
||||||
CORE_Static Array<T>
|
|
||||||
array_make(Allocator *a, S64 size = 16){
|
|
||||||
Array<T> result = {};
|
|
||||||
result.init(a, size);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "base_string.cpp"
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Defer
|
|
||||||
// http://www.gingerbill.org/article/2015/08/19/defer-in-cpp/
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template <typename F>
|
|
||||||
struct Defer_Scope {
|
|
||||||
F f;
|
|
||||||
Defer_Scope(F f) : f(f) {}
|
|
||||||
~Defer_Scope() { f(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename F>
|
|
||||||
Defer_Scope<F> defer_func(F f) {
|
|
||||||
return Defer_Scope<F>(f);
|
|
||||||
}
|
|
||||||
#define DEFER_1(x, y) x##y
|
|
||||||
#define DEFER_2(x, y) DEFER_1(x, y)
|
|
||||||
#define DEFER_3(x) DEFER_2(x, __COUNTER__)
|
|
||||||
#define defer(code) auto DEFER_3(_defer_) = defer_func([&](){code;})
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// 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<class T>
|
|
||||||
struct List_Node{
|
|
||||||
List_Node<T> *next;
|
|
||||||
List_Node<T> *prev;
|
|
||||||
int cap;
|
|
||||||
int len;
|
|
||||||
T data[];
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
struct List{
|
|
||||||
int block_size = 0;
|
|
||||||
int allocation_multiplier = 0;
|
|
||||||
List_Node<T> *first = 0;
|
|
||||||
List_Node<T> *last = 0;
|
|
||||||
List_Node<T> *first_free = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
List_Node<T> *list_allocate_node(Allocator *arena, int size){
|
|
||||||
auto node = (List_Node<T> *)allocate_size(arena, sizeof(List_Node<T>) + size*sizeof(T), false);
|
|
||||||
node->cap = size;
|
|
||||||
node->len = 0;
|
|
||||||
node->next = 0;
|
|
||||||
node->prev = 0;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void list_allocate_free_node(Allocator *arena, List<T> *list, int size){
|
|
||||||
List_Node<T> *node = list_allocate_node<T>(arena, size);
|
|
||||||
DLL_STACK_ADD(list->first_free, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void list_make_sure_there_is_room_for_item_count(Allocator *arena, List<T> *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<T> *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<T>(arena, list->block_size);
|
|
||||||
list->block_size *= list->allocation_multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(node);
|
|
||||||
DLL_QUEUE_ADD_LAST(list->first, list->last, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T *list_get(List<T> *list, int index, List_Node<T> **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<class T>
|
|
||||||
T *getp(List<T> *list, int index){
|
|
||||||
return list_get(list, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T get(List<T> *list, int index){
|
|
||||||
return *list_get(list, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void add(Allocator *arena, List<T> *list, T item){
|
|
||||||
list_make_sure_there_is_room_for_item_count(arena, list, 1);
|
|
||||||
list->last->data[list->last->len++] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T *add_size(Allocator *arena, List<T> *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<class T>
|
|
||||||
void list_free_node(List<T> *list, List_Node<T> *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<class T>
|
|
||||||
void clear(List<T> *list){
|
|
||||||
memory_zero(list, sizeof(List<T>));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
int length(List<T> *list){
|
|
||||||
int result = 0;
|
|
||||||
For_Linked_List(list->first){
|
|
||||||
result += it->len;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void free_all_nodes(List<T> *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<class T>
|
|
||||||
T ordered_remove(List<T> *list, int index){
|
|
||||||
List_Node<T> *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<class T>
|
|
||||||
T unordered_remove(List<T> *list, int index){
|
|
||||||
List_Node<T> *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<class T>
|
|
||||||
T pop(List<T> *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<class T>
|
|
||||||
T *merge(Allocator *arena, List<T> *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<class T>
|
|
||||||
struct List_Iter{
|
|
||||||
T *item;
|
|
||||||
int index;
|
|
||||||
List_Node<T> *node;
|
|
||||||
int node_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void advance(List_Iter<T> *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<class T>
|
|
||||||
List_Iter<T> iterate(List<T> *list){
|
|
||||||
List_Iter<T> result = {};
|
|
||||||
result.node = list->first;
|
|
||||||
result.index = result.node_index = -1;
|
|
||||||
advance(&result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
bool should_we_continue(List_Iter<T> *iter){
|
|
||||||
return iter->item != 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
constexpr size_t ARENA_BLOCK_SIZE = mib(1);
|
constexpr size_t ARENA_BLOCK_SIZE = mib(4);
|
||||||
constexpr size_t ARENA_ALIGNMENT = 8;
|
constexpr size_t ARENA_ALIGNMENT = 8;
|
||||||
|
|
||||||
struct Scratch_Arena : Allocator {
|
struct Scratch_Arena : Allocator {
|
||||||
581
base_data_structures.cpp
Normal file
581
base_data_structures.cpp
Normal file
@@ -0,0 +1,581 @@
|
|||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Array
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template<class T>
|
||||||
|
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<T> 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<T> copy(Allocator *a){
|
||||||
|
Array<T> 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<T> tight_copy(Allocator *a){
|
||||||
|
Array<T> 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<T> *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<class T>
|
||||||
|
CORE_Static Array<T>
|
||||||
|
array_make(Allocator *a, S64 size = 16){
|
||||||
|
Array<T> 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<class T>
|
||||||
|
struct List_Node{
|
||||||
|
List_Node<T> *next;
|
||||||
|
List_Node<T> *prev;
|
||||||
|
int cap;
|
||||||
|
int len;
|
||||||
|
T data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct List{
|
||||||
|
int block_size = 0;
|
||||||
|
int allocation_multiplier = 0;
|
||||||
|
List_Node<T> *first = 0;
|
||||||
|
List_Node<T> *last = 0;
|
||||||
|
List_Node<T> *first_free = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
List_Node<T> *list_allocate_node(Allocator *arena, int size){
|
||||||
|
auto node = (List_Node<T> *)allocate_size(arena, sizeof(List_Node<T>) + size*sizeof(T), false);
|
||||||
|
node->cap = size;
|
||||||
|
node->len = 0;
|
||||||
|
node->next = 0;
|
||||||
|
node->prev = 0;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void list_allocate_free_node(Allocator *arena, List<T> *list, int size){
|
||||||
|
List_Node<T> *node = list_allocate_node<T>(arena, size);
|
||||||
|
DLL_STACK_ADD(list->first_free, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void list_make_sure_there_is_room_for_item_count(Allocator *arena, List<T> *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<T> *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<T>(arena, list->block_size);
|
||||||
|
list->block_size *= list->allocation_multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(node);
|
||||||
|
DLL_QUEUE_ADD_LAST(list->first, list->last, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T *list_get(List<T> *list, int index, List_Node<T> **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<class T>
|
||||||
|
T *getp(List<T> *list, int index){
|
||||||
|
return list_get(list, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T get(List<T> *list, int index){
|
||||||
|
return *list_get(list, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void add(Allocator *arena, List<T> *list, T item){
|
||||||
|
list_make_sure_there_is_room_for_item_count(arena, list, 1);
|
||||||
|
list->last->data[list->last->len++] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T *add_size(Allocator *arena, List<T> *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<class T>
|
||||||
|
void list_free_node(List<T> *list, List_Node<T> *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<class T>
|
||||||
|
void clear(List<T> *list){
|
||||||
|
memory_zero(list, sizeof(List<T>));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
int length(List<T> *list){
|
||||||
|
int result = 0;
|
||||||
|
For_Linked_List(list->first){
|
||||||
|
result += it->len;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void free_all_nodes(List<T> *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<class T>
|
||||||
|
T ordered_remove(List<T> *list, int index){
|
||||||
|
List_Node<T> *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<class T>
|
||||||
|
T unordered_remove(List<T> *list, int index){
|
||||||
|
List_Node<T> *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<class T>
|
||||||
|
T pop(List<T> *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<class T>
|
||||||
|
T *merge(Allocator *arena, List<T> *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<class T>
|
||||||
|
struct List_Iter{
|
||||||
|
T *item;
|
||||||
|
int index;
|
||||||
|
List_Node<T> *node;
|
||||||
|
int node_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void advance(List_Iter<T> *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<class T>
|
||||||
|
List_Iter<T> iterate(List<T> *list){
|
||||||
|
List_Iter<T> result = {};
|
||||||
|
result.node = list->first;
|
||||||
|
result.index = result.node_index = -1;
|
||||||
|
advance(&result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool should_we_continue(List_Iter<T> *iter){
|
||||||
|
return iter->item != 0;
|
||||||
|
}
|
||||||
@@ -459,7 +459,6 @@ string_from_cstring(char *string){
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "core_arena.cpp" // @! Move this include
|
|
||||||
struct String_Replace {
|
struct String_Replace {
|
||||||
String find;
|
String find;
|
||||||
String replace;
|
String replace;
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
|
|
||||||
CORE_Static void
|
CORE_Static void
|
||||||
core_init_compiler(Core_Ctx *ctx, Arena *perm, Allocator *heap) {
|
core_init_compiler(Core_Ctx *ctx, Allocator *allocator) {
|
||||||
ctx->init_ctx_time_begin = os_time();
|
ctx->init_ctx_time_begin = os_time();
|
||||||
pctx = ctx;
|
pctx = ctx;
|
||||||
ctx->scratch = allocate_scratch_arena(perm, mib(1));
|
ctx->perm_push_only = make_push_arena(allocator);
|
||||||
ctx->perm = perm;
|
ctx->perm = &ctx->perm_push_only;
|
||||||
ctx->heap = heap;
|
ctx->scratch = allocate_scratch_arena(ctx->perm, mib(1));
|
||||||
ctx->type_map = map_make(heap, 2048);
|
ctx->heap = allocator;
|
||||||
|
ctx->type_map = map_make(ctx->heap, 2048);
|
||||||
ctx->gen = {ctx->perm};
|
ctx->gen = {ctx->perm};
|
||||||
ctx->helper_builder = {ctx->perm};
|
ctx->helper_builder = {ctx->perm};
|
||||||
ctx->scope_ids = 1;
|
ctx->scope_ids = 1;
|
||||||
bigint_allocator = ctx->perm;
|
bigint_allocator = ctx->perm;
|
||||||
arena_init(&ctx->stage_arena, "Compiler stage arena"_s);
|
arena_init(&ctx->stage_arena, "Compiler stage arena"_s);
|
||||||
|
|
||||||
ctx->tokens = array_make<Token>(heap, 4096 * 4);
|
ctx->tokens = array_make<Token>(ctx->heap, 4096 * 4);
|
||||||
ctx->interns = intern_table_make(ctx->perm, heap, 2048);
|
ctx->interns = intern_table_make(ctx->perm, ctx->heap, 2048);
|
||||||
|
|
||||||
/*#import meta
|
/*#import meta
|
||||||
for i in meta.keywords:
|
for i in meta.keywords:
|
||||||
@@ -97,9 +98,8 @@ core_init_compiler(Core_Ctx *ctx, Arena *perm, Allocator *heap) {
|
|||||||
CORE_Static void
|
CORE_Static void
|
||||||
core_bootstrap_compiler(Allocator *allocator) {
|
core_bootstrap_compiler(Allocator *allocator) {
|
||||||
Core_Ctx *ctx = allocate_struct(allocator, Core_Ctx);
|
Core_Ctx *ctx = allocate_struct(allocator, Core_Ctx);
|
||||||
|
|
||||||
assert((uintptr_t)allocator->allocate == (uintptr_t)arena_push_size);
|
assert((uintptr_t)allocator->allocate == (uintptr_t)arena_push_size);
|
||||||
core_init_compiler(ctx, (Arena *)allocator, allocator);
|
core_init_compiler(ctx, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
CORE_Static void
|
CORE_Static void
|
||||||
@@ -300,6 +300,8 @@ compile_file(Arena *arena, String filename, U32 compile_flags = COMPILE_NULL) {
|
|||||||
|
|
||||||
B32 r = os_write_file("program.c"_s, result);
|
B32 r = os_write_file("program.c"_s, result);
|
||||||
assert(r);
|
assert(r);
|
||||||
|
F64 total_compiler_time = os_time() - pctx->total_time;
|
||||||
|
log_info_no_nl("%f - ", total_compiler_time);
|
||||||
|
|
||||||
Scratch_Arena *scratch = pctx->scratch;
|
Scratch_Arena *scratch = pctx->scratch;
|
||||||
Scratch_Scope _scope(scratch);
|
Scratch_Scope _scope(scratch);
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ struct Lex_Stream{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Core_Ctx{
|
struct Core_Ctx{
|
||||||
Arena *perm; // Stores: AST, tokens, interns
|
Push_Arena perm_push_only;
|
||||||
|
Push_Arena *perm; // Stores: AST, tokens, interns
|
||||||
Allocator *heap;
|
Allocator *heap;
|
||||||
|
|
||||||
Scratch_Arena *scratch;
|
Scratch_Arena *scratch;
|
||||||
|
|||||||
@@ -258,7 +258,15 @@ For modules it's a bit different cause they should be distributed as valid.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "base.cpp"
|
#include "base.cpp"
|
||||||
|
|
||||||
|
#define STB_SPRINTF_IMPLEMENTATION
|
||||||
|
#include "stb_sprintf.h"
|
||||||
|
|
||||||
#include "base_unicode.cpp"
|
#include "base_unicode.cpp"
|
||||||
|
#include "base_arena.cpp"
|
||||||
|
#include "base_data_structures.cpp"
|
||||||
|
#include "base_string.cpp"
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
#include "os_windows.cpp"
|
#include "os_windows.cpp"
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ force_inline B32 is_numeric(Ast_Type *type){
|
|||||||
// Hash consed types
|
// Hash consed types
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
CORE_Static Ast_Type *
|
CORE_Static Ast_Type *
|
||||||
type_new(Arena *allocator, Ast_Type_Kind kind, size_t size, size_t align){
|
type_new(Allocator *allocator, Ast_Type_Kind kind, size_t size, size_t align){
|
||||||
Ast_Type *result = allocate_struct(allocator, Ast_Type, true);
|
Ast_Type *result = allocate_struct(allocator, Ast_Type, true);
|
||||||
result->kind = kind;
|
result->kind = kind;
|
||||||
result->size = size;
|
result->size = size;
|
||||||
@@ -69,7 +69,7 @@ type_new(Arena *allocator, Ast_Type_Kind kind, size_t size, size_t align){
|
|||||||
}
|
}
|
||||||
|
|
||||||
CORE_Static Ast_Type *
|
CORE_Static Ast_Type *
|
||||||
type_copy(Arena *a, Ast_Type *type){
|
type_copy(Allocator *a, Ast_Type *type){
|
||||||
// @warning: This changes type id !!!!
|
// @warning: This changes type id !!!!
|
||||||
Ast_Type *result = allocate_struct(a, Ast_Type);
|
Ast_Type *result = allocate_struct(a, Ast_Type);
|
||||||
memory_copy(result, type, sizeof(Ast_Type));
|
memory_copy(result, type, sizeof(Ast_Type));
|
||||||
@@ -324,7 +324,7 @@ typename_base(String_Builder *sb, Ast_Type *type){
|
|||||||
}
|
}
|
||||||
|
|
||||||
CORE_Static String
|
CORE_Static String
|
||||||
get_typename(Arena *a, Ast_Type *type){
|
get_typename(Allocator *a, Ast_Type *type){
|
||||||
pctx->helper_builder.addf("[");
|
pctx->helper_builder.addf("[");
|
||||||
typename_base(&pctx->helper_builder, type);
|
typename_base(&pctx->helper_builder, type);
|
||||||
pctx->helper_builder.addf("]");
|
pctx->helper_builder.addf("]");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Memory
|
// Memory
|
||||||
|
|||||||
Reference in New Issue
Block a user