view list.c @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -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;
}