view list.c @ 130:147dfc703161

Add String method to List
author Mike Pavone <pavone@retrodev.com>
date Fri, 05 Nov 2010 02:42:45 +0000
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;
}