Mercurial > repos > rhope
view list.c @ 121:1af91ceaaf49
Fixed memory leak when an output is only attached to a single null input
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 28 Oct 2010 21:04:12 -0400 |
parents | 76568becd6d6 |
children |
line wrap: on
line source
#include "structs.h" #include "datum.h" #include "interp.h" #include <stdlib.h> #include <string.h> datum * create_list(program * prog) { short i; datum * dat = new_datum(BUILTIN_TYPE_LIST, 1, sizeof(list_data) + sizeof(datum *)*7, prog); dat->c.generic.len = 8; ((list_data *)dat->c.generic.data)->num_entries = 0; return dat; } int vis_list_new(datum ** inputlist, queue_entry * worker_entry) { inputlist[0] = create_list(worker_entry->instance->def->program); return 0; } int vis_list_append(datum ** inputlist, queue_entry * worker_entry) { int ref_count, new_entry_count; list_data * list, * new_list; datum * output; int i; VIS_EnterCriticalSection(inputlist[0]->lock); ref_count = inputlist[0]->ref_count; VIS_LeaveCriticalSection(inputlist[0]->lock); list = ((list_data *)inputlist[0]->c.generic.data); DEBUGPRINTF("append: generic.len = %d, list->num_entries = %d, ref_count = %d\n", inputlist[0]->c.generic.len, list->num_entries, ref_count); if(ref_count == 1) { if(inputlist[0]->c.generic.len > list->num_entries) { DEBUGPUTS("Fast append\n"); list->entries[list->num_entries] = inputlist[1]; //No need to add_ref because we're consuming the ref we wer passed ++(list->num_entries); } else { DEBUGPUTS("malloc append\n"); new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size new_list = malloc((new_entry_count -1) * sizeof(datum *) + sizeof(list_data)); new_list->num_entries = list->num_entries+1; inputlist[0]->c.generic.len = new_entry_count; memcpy(new_list->entries, list->entries, list->num_entries * sizeof(datum *)); new_list->entries[list->num_entries] = inputlist[1]; inputlist[0]->c.generic.data = new_list; VIS_FREE(list, "List object"); } } else { DEBUGPUTS("datum copy append\n"); if(inputlist[0]->c.generic.len > list->num_entries) new_entry_count = inputlist[0]->c.generic.len; else new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data)); new_list = output->c.generic.data; new_list->num_entries = list->num_entries+1; output->c.generic.len = new_entry_count; for(i = 0; i < list->num_entries; ++i) new_list->entries[i] = add_ref(list->entries[i]); new_list->entries[list->num_entries] = inputlist[1]; release_ref(inputlist[0]); inputlist[0] = output; } DEBUGPRINTF("append: generic.len = %d, list->num_entries = %d\n", inputlist[0]->c.generic.len, ((list_data *)inputlist[0]->c.generic.data)->num_entries); return 0; } int vis_list_swap(datum ** inputlist, queue_entry * worker_entry) { //TODO: Throw error if indices out of bounds list_data * list; datum * temp; inputlist[0] = copy_datum(inputlist[0], 0); list = ((list_data *)inputlist[0]->c.generic.data); temp = list->entries[inputlist[1]->c.integers.num_a]; list->entries[inputlist[1]->c.integers.num_a] = list->entries[inputlist[2]->c.integers.num_a]; list->entries[inputlist[2]->c.integers.num_a] = temp; release_ref(inputlist[1]); release_ref(inputlist[2]); return 0; } int vis_list_index(datum ** inputlist, queue_entry * worker_entry) { //TODO: Throw error if indices out of bounds list_data * list = ((list_data *)inputlist[0]->c.generic.data); datum * output; DEBUGPRINTF("index: generic.len = %d, list->num_entries = %d, requested index: %d\n", inputlist[0]->c.generic.len, list->num_entries, inputlist[1]->c.integers.num_a); DEBUGPRINTF("list->entries[%d] = %X\n", inputlist[1]->c.integers.num_a, list->entries[inputlist[1]->c.integers.num_a]); if(inputlist[1]->c.integers.num_a < list->num_entries && list->entries[inputlist[1]->c.integers.num_a]) { output = add_ref(list->entries[inputlist[1]->c.integers.num_a]); release_ref(inputlist[1]); inputlist[1] = NULL; } else { output = NULL; inputlist[1] = new_datum(BUILTIN_TYPE_YESNO, 2, 0, worker_entry->instance->def->program); inputlist[1]->c.integers.num_a = 0; } release_ref(inputlist[0]); inputlist[0] = output; return 0; } int vis_list_insert(datum ** inputlist, queue_entry * worker_entry) { int ref_count, new_entry_count; list_data * list, * new_list; datum * output; int i; VIS_EnterCriticalSection(inputlist[0]->lock); ref_count = inputlist[0]->ref_count; VIS_LeaveCriticalSection(inputlist[0]->lock); list = ((list_data *)inputlist[0]->c.generic.data); if(ref_count == 1) { if(inputlist[0]->c.generic.len > list->num_entries) { memmove(list->entries + inputlist[1]->c.integers.num_a + 1, list->entries + inputlist[1]->c.integers.num_a, sizeof(datum *) * (list->num_entries-inputlist[1]->c.integers.num_a)); list->entries[inputlist[1]->c.integers.num_a] = inputlist[2]; //No need to add_ref because we're consuming the ref we wer passed ++(list->num_entries); } else { new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size new_list = malloc((new_entry_count -1) * sizeof(datum *) + sizeof(list_data)); new_list->num_entries = list->num_entries+1; inputlist[0]->c.generic.len = new_entry_count; memcpy(new_list->entries, list->entries, list->num_entries * sizeof(datum *)); new_list->entries[list->num_entries] = inputlist[1]; inputlist[0]->c.generic.data = new_list; VIS_FREE(list, "List object"); } } else { new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data)); new_list = output->c.generic.data; new_list->num_entries = list->num_entries+1; output->c.generic.len = new_entry_count; for(i = 0; i < inputlist[1]->c.integers.num_a; ++i) new_list->entries[i] = add_ref(list->entries[i]); for(i = inputlist[1]->c.integers.num_a; i < list->num_entries; ++i) new_list->entries[i+1] = add_ref(list->entries[i]); release_ref(inputlist[0]); new_list->entries[list->num_entries] = inputlist[2]; inputlist[0] = output; } release_ref(inputlist[1]); return 0; } int vis_list_remove(datum ** inputlist, queue_entry * worker_entry) { int ref_count, new_entry_count; list_data * list, * new_list; int i; datum * output; VIS_EnterCriticalSection(inputlist[0]->lock); ref_count = inputlist[0]->ref_count; VIS_LeaveCriticalSection(inputlist[0]->lock); list = ((list_data *)inputlist[0]->c.generic.data); if(ref_count == 1) { release_ref(list->entries[inputlist[1]->c.integers.num_a]); memmove(list->entries + inputlist[1]->c.integers.num_a, list->entries + inputlist[1]->c.integers.num_a + 1, sizeof(datum *) * (list->num_entries-(inputlist[1]->c.integers.num_a+1))); --(list->num_entries); } else { new_entry_count = list->num_entries + (list->num_entries > 1);//grow by half current size output = new_datum_comp(inputlist[0]->company, 1, (new_entry_count -1) * sizeof(datum *) + sizeof(list_data)); new_list = output->c.generic.data; new_list->num_entries = list->num_entries+1; output->c.generic.len = new_entry_count; for(i = 0; i < inputlist[1]->c.integers.num_a; ++i) new_list->entries[i] = add_ref(list->entries[i]); for(i = inputlist[1]->c.integers.num_a+1; i < list->num_entries; ++i) new_list->entries[i-1] = add_ref(list->entries[i]); release_ref(inputlist[0]); inputlist[0] = output; } release_ref(inputlist[1]); return 0; } int vis_list_set(datum ** inputlist, queue_entry * worker_entry) { int new_num_entries, new_generic_len, i; list_data * list; DEBUGPUTS("vis_list_set\n"); if(((list_data *)inputlist[0]->c.generic.data)->num_entries <= inputlist[1]->c.integers.num_a) { new_num_entries = inputlist[1]->c.integers.num_a + 1; new_generic_len = (new_num_entries + (new_num_entries>>1)-1)*sizeof(datum*) + sizeof(list_data); } else { new_num_entries = ((list_data *)inputlist[0]->c.generic.data)->num_entries; new_generic_len = 0; } DEBUGPRINTF("new_generic_len: %d, new num_entries: %d\n", new_generic_len, new_num_entries); inputlist[0] = copy_datum(inputlist[0], new_generic_len); if(new_generic_len) { inputlist[0]->c.generic.len = (new_num_entries + (new_num_entries>>1)); } DEBUGPUTS("Datum copy done\n"); list = ((list_data *)inputlist[0]->c.generic.data); DEBUGPUTS("before Null fill loop\n"); for(i = list->num_entries; i < new_num_entries; ++i) list->entries[i] = NULL; DEBUGPUTS("Before existing entry release_ref\n"); if(inputlist[1]->c.integers.num_a < list->num_entries) release_ref(list->entries[inputlist[1]->c.integers.num_a]); DEBUGPRINTF("Setting index %d to %X\n", inputlist[1]->c.integers.num_a, inputlist[2]); list->entries[inputlist[1]->c.integers.num_a] = inputlist[2]; release_ref(inputlist[1]); list->num_entries = new_num_entries; DEBUGPUTS("vis_list_set done\n"); return 0; } int vis_list_length(datum ** inputlist, queue_entry * worker_entry) { datum * output; list_data * list = ((list_data *)inputlist[0]->c.generic.data); output = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program); output->c.integers.num_a = list->num_entries; release_ref(inputlist[0]); inputlist[0] = output; return 0; } int vis_list_first(datum ** inputlist, queue_entry * worker_entry) { int i; list_data * list = inputlist[0]->c.generic.data; if(!list->num_entries) { inputlist[1] = inputlist[0]; inputlist[0] = NULL; } else { i = 0; while(!list->entries[i] && i < list->num_entries) ++i; release_ref(inputlist[0]); inputlist[0] = new_datum(BUILTIN_TYPE_WHOLE, 2, 0, worker_entry->instance->def->program); inputlist[0]->c.integers.num_a = i; inputlist[1] = NULL; } return 0; } int vis_list_next(datum ** inputlist, queue_entry * worker_entry) { int i; list_data * list = inputlist[0]->c.generic.data; i = inputlist[1]->c.integers.num_a + 1; while(i < list->num_entries && !list->entries[i]) ++i; if(i < list->num_entries) { release_ref(inputlist[0]); inputlist[0] = copy_datum(inputlist[1], 0); inputlist[1] = NULL; inputlist[0]->c.integers.num_a = i; } else { release_ref(inputlist[1]); inputlist[1] = inputlist[0]; inputlist[0] = NULL; } return 0; }