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;
|
||||
S64 len;
|
||||
};
|
||||
global String string_null = {(U8 *)"null", 4};
|
||||
|
||||
union Intern_String{ // Basically just String
|
||||
String s;
|
||||
@@ -157,12 +158,6 @@ struct Allocator {
|
||||
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
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -527,606 +522,3 @@ arena_sub(Arena *base, size_t size, String debug_name) {
|
||||
result.len = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user