Move out the ArrayList
This commit is contained in:
348
main.cpp
348
main.cpp
@@ -765,354 +765,6 @@ UI_SIGNAL_CALLBACK(scene_callback) {
|
||||
scene = (Scene)(((int)scene + 1) % Scene_Count);
|
||||
}
|
||||
|
||||
const int ARRAY_LIST_DEFAULT_CAP = 32;
|
||||
const int ARRAY_LIST_DEFAULT_ALLOCATION_MUL = 2;
|
||||
template<class T> struct Array_List_Iter;
|
||||
|
||||
template<class T>
|
||||
struct Array_Node{
|
||||
Array_Node<T> *next;
|
||||
Array_Node<T> *prev;
|
||||
int cap;
|
||||
int len;
|
||||
T data[];
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Array_List{
|
||||
int block_size = 0;
|
||||
int allocation_multiplier = 0;
|
||||
Array_Node<T> *first = 0;
|
||||
Array_Node<T> *last = 0;
|
||||
Array_Node<T> *first_free = 0;
|
||||
|
||||
// Iterator method
|
||||
Array_List_Iter<T> iter();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct Array_List_Iter{
|
||||
T *item;
|
||||
int index;
|
||||
Array_Node<T> *node;
|
||||
int node_index;
|
||||
|
||||
// Methods
|
||||
void next();
|
||||
force_inline B32 is_valid();
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void Array_List_Iter<T>::next(){
|
||||
if(node_index + 1 >= node->len){
|
||||
node = node->next;
|
||||
node_index = -1;
|
||||
item = 0;
|
||||
}
|
||||
|
||||
if(node){
|
||||
node_index += 1;
|
||||
index += 1;
|
||||
item = node->data + node_index;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
B32 Array_List_Iter<T>::is_valid(){
|
||||
return item != 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Array_List_Iter<T> Array_List<T>::iter(){
|
||||
Array_List_Iter<T> result = {};
|
||||
result.node = this->first;
|
||||
result.index = result.node_index = -1;
|
||||
result.next();
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Array_Node<T> *array_allocate_node(Arena *arena, int size){
|
||||
auto node = (Array_Node<T> *)arena_push_size(arena, sizeof(Array_Node<T>) + size*sizeof(T));
|
||||
node->cap = size;
|
||||
node->len = 0;
|
||||
return node;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void array_alloc_free_node(Arena *arena, Array_List<T> *array, int size){
|
||||
Array_Node<T> *node = array_allocate_node<T>(arena, size);
|
||||
DLLFreeListAdd(array->first_free, node);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void make_sure_there_is_room_for_item_count(Arena *arena, Array_List<T> *array, int item_count){
|
||||
if(array->last == 0 || array->last->len + item_count > array->last->cap){
|
||||
// Not enough space we need to get a new block
|
||||
Array_Node<T> *node = 0;
|
||||
|
||||
// Iterate the free list to check if we have a block of required size there
|
||||
For_List(array->first_free){
|
||||
if(it->cap >= item_count){
|
||||
DLLFreeListRemove(array->first_free, it);
|
||||
node = it;
|
||||
node->len = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have a block on the free list need to allocate
|
||||
if(!node){
|
||||
if(!array->allocation_multiplier) array->allocation_multiplier = ARRAY_LIST_DEFAULT_ALLOCATION_MUL;
|
||||
if(!array->block_size) array->block_size = ARRAY_LIST_DEFAULT_CAP;
|
||||
if(item_count > array->block_size)
|
||||
array->block_size = item_count*2;
|
||||
node = array_allocate_node<T>(arena, array->block_size);
|
||||
array->block_size *= array->allocation_multiplier;
|
||||
}
|
||||
|
||||
assert(node);
|
||||
DLLQueueAddLast(array->first, array->last, node);
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *array_get(Array_List<T> *array, int index){
|
||||
int i = 0;
|
||||
For_List(array->first){
|
||||
int lookup_i = index - i;
|
||||
if(lookup_i < it->len) {
|
||||
return it->data + lookup_i;
|
||||
}
|
||||
i += it->cap;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void array_add(Arena *arena, Array_List<T> *array, T item){
|
||||
make_sure_there_is_room_for_item_count(arena, array, 1);
|
||||
array->last->data[array->last->len++] = item;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *array_alloc(Arena *arena, Array_List<T> *array, int count){
|
||||
make_sure_there_is_room_for_item_count(arena, array, count);
|
||||
T *result = array->last->data;
|
||||
array->last->len += count;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void array_free_node(Array_List<T> *array, Array_Node<T> *node){
|
||||
|
||||
#if 1
|
||||
// Make sure it's actually in array list
|
||||
B32 found = false;
|
||||
For_List(array->first){
|
||||
if(it == node){
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(found);
|
||||
#endif
|
||||
|
||||
DLLQueueRemove(array->first, array->last, node);
|
||||
DLLFreeListAdd(array->first_free, node);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void array_free_all_nodes(Array_List<T> *array){
|
||||
assert(!array->last->next);
|
||||
assert(!array->first->prev);
|
||||
array->last->next = array->first_free;
|
||||
if(array->first_free) array->first_free->prev = array->last;
|
||||
array->first_free = array->first;
|
||||
array->last = array->first = 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T array_ordered_remove(Array_List<T> *array, int index){
|
||||
Array_Node<T> *node = 0;
|
||||
int i = 0;
|
||||
T *item = 0;
|
||||
|
||||
// Get node from array
|
||||
For_List(array->first){
|
||||
int lookup_i = index - i;
|
||||
if(lookup_i < it->len) {
|
||||
node = it;
|
||||
i = lookup_i;
|
||||
item = it->data + lookup_i;
|
||||
break;
|
||||
}
|
||||
i += it->cap;
|
||||
}
|
||||
|
||||
assert(node);
|
||||
assert(item);
|
||||
T result = *item;
|
||||
|
||||
// Check if we need to deallocate the block
|
||||
if(node->len == 1) {
|
||||
array_free_node(array, node);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// We need to move part of the block to fill the new empty spot
|
||||
int right_count = (--node->len) - i;
|
||||
memory_copy(item, item+1, sizeof(T)*right_count);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T array_unordered_remove(Array_List<T> *array, int index){
|
||||
auto last = array->last;
|
||||
assert(last);
|
||||
assert(last->data);
|
||||
assert(last->len != 0);
|
||||
T *indexed_value = array_get(array, index);
|
||||
T *last_value = last->data + (last->len-1);
|
||||
|
||||
T temp = *indexed_value;
|
||||
*indexed_value = *last_value;
|
||||
*last_value = temp;
|
||||
|
||||
return array_pop(array);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T array_pop(Array_List<T> *array){
|
||||
assert(array->last != 0);
|
||||
assert(array->last->len > 0);
|
||||
T result = array->last->data[--array->last->len];
|
||||
if(array->last->len == 0){
|
||||
array_free_node(array, array->last);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void array_print(Array_List<int> *array){
|
||||
log_info("\nNodes: ");
|
||||
for(Array_Node<int> *it = array->first; it; it=it->next){
|
||||
log_info("%d", it->cap);
|
||||
if(it->next) log_info("->");
|
||||
}
|
||||
|
||||
log_info("\nFree: ");
|
||||
for(Array_Node<int> *it = array->first_free; it; it=it->next){
|
||||
log_info("%d", it->cap);
|
||||
if(it->next) log_info("->");
|
||||
}
|
||||
|
||||
log_info("\nNodes_Reverse: ");
|
||||
for(Array_Node<int> *it = array->last; it; it=it->prev){
|
||||
log_info("%d", it->cap);
|
||||
if(it->prev) log_info("<-");
|
||||
}
|
||||
|
||||
//
|
||||
// Make sure going backwards yields same results as going forward
|
||||
//
|
||||
Scratch scratch;
|
||||
Array<Array_Node<int> *> nodes = {scratch};
|
||||
for(Array_Node<int> *it = array->first; it; it=it->next){
|
||||
nodes.add(it);
|
||||
}
|
||||
|
||||
S32 array_i = nodes.len;
|
||||
for(Array_Node<int> *it = array->last; it; it=it->prev){
|
||||
Array_Node<int> *node_from_array = nodes.data[--array_i];
|
||||
assert(it == node_from_array);
|
||||
}
|
||||
|
||||
//
|
||||
// Same test but for free list
|
||||
//
|
||||
nodes.clear();
|
||||
Array_Node<int> *last = 0;
|
||||
for(auto it = array->first_free; it; it=it->next){
|
||||
nodes.add(it);
|
||||
if(!it->next) last = it;
|
||||
}
|
||||
|
||||
array_i = nodes.len;
|
||||
for(Array_Node<int> *it = last; it; it=it->prev){
|
||||
Array_Node<int> *node_from_array = nodes.data[--array_i];
|
||||
assert(it == node_from_array);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function void
|
||||
test_array_list(){
|
||||
Scratch scratch;
|
||||
log_info("\nArray_List:%d Array_Node:%d Array:%d", (int)sizeof(Array_List<int>), (int)sizeof(Array_Node<int>), (int)sizeof(Array<int>));
|
||||
|
||||
{
|
||||
Array_List<int> array{32,1};
|
||||
for(int i = 0; i < 33; i++){
|
||||
array_add(scratch, &array, i);
|
||||
}
|
||||
assert(array_pop(&array) == 32);
|
||||
assert(array_pop(&array) == 31);
|
||||
array_add(scratch, &array, 31);
|
||||
array_add(scratch, &array, 32);
|
||||
assert(array_pop(&array) == 32);
|
||||
assert(array_pop(&array) == 31);
|
||||
|
||||
array_add(scratch, &array, 31);
|
||||
array_add(scratch, &array, 32);
|
||||
|
||||
array_unordered_remove(&array, 31);
|
||||
array_unordered_remove(&array, 31);
|
||||
|
||||
assert(array_pop(&array) == 30);
|
||||
assert(array_pop(&array) == 29);
|
||||
array_add(scratch, &array, 29);
|
||||
array_add(scratch, &array, 30);
|
||||
array_add(scratch, &array, 31);
|
||||
array_add(scratch, &array, 32);
|
||||
array_ordered_remove(&array, 32);
|
||||
array_ordered_remove(&array, 0);
|
||||
array_ordered_remove(&array, 16);
|
||||
array_ordered_remove(&array, 29);
|
||||
array_print(&array);
|
||||
}
|
||||
|
||||
{
|
||||
Array_List<int> array;
|
||||
for(int i = 0; i < 100000; i++){
|
||||
array_add(scratch, &array, i);
|
||||
}
|
||||
|
||||
For_It(array){
|
||||
assert(it.index == *it.item);
|
||||
}
|
||||
|
||||
assert(*array_get(&array, 22) == 22);
|
||||
assert(*array_get(&array, 65) == 65);
|
||||
assert(*array_get(&array, 200) == 200);
|
||||
|
||||
array_print(&array);
|
||||
array_free_node(&array, array.last->prev);
|
||||
array_free_node(&array, array.last->prev);
|
||||
array_free_node(&array, array.last->prev);
|
||||
array_free_node(&array, array.last->prev);
|
||||
array_free_node(&array, array.last->prev->prev);
|
||||
array_print(&array);
|
||||
|
||||
for(int i = 0; i < 10000; i++){
|
||||
array_add(scratch, &array, i);
|
||||
}
|
||||
|
||||
array_print(&array);
|
||||
}
|
||||
// __debugbreak();
|
||||
}
|
||||
|
||||
FILE *global_file;
|
||||
function void
|
||||
windows_log(Log_Kind kind, String string, char *file, int line){
|
||||
|
||||
Reference in New Issue
Block a user