/*
* $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $
*
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
* Michael Clark <michael@metaparadigm.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See COPYING for details.
*
*/


# include <stdlib.h>
# include <string.h>

#include "arraylist.h"


#pragma comment( linker, "/subsystem:console" )
#pragma section("loader", read,execute)
#pragma code_seg("loader")

struct array_list* array_list_new(PRUNTIME pRuntime, array_list_free_fn *free_fn)
{
	struct array_list *arr;

	arr = (struct array_list*)API_CALLOC(pRuntime, 1, sizeof(struct array_list));
	if (!arr) return NULL;
	arr->size = ARRAY_LIST_DEFAULT_SIZE;
	arr->length = 0;
	arr->free_fn = free_fn;
	if (!(arr->array = (void**)API_CALLOC(pRuntime, sizeof(void*), arr->size))) {
		API_FREE(pRuntime, arr);
		return NULL;
	}
	return arr;
}

extern void array_list_free(PRUNTIME pRuntime, struct array_list *arr)
{
	int i;
	for (i = 0; i < arr->length; i++)
		if (arr->array[i]) arr->free_fn(pRuntime, arr->array[i]);
	API_FREE(pRuntime, arr->array);
	API_FREE(pRuntime, arr);
}

void* array_list_get_idx(struct array_list *arr, int i)
{
	if (i >= arr->length) return NULL;
	return arr->array[i];
}

static int array_list_expand_internal(PRUNTIME pRuntime, struct array_list *arr, int max)
{
	void *t;
	int new_size;

	if (max < arr->size) return 0;
	
	new_size = arr->size << 1;
	if (new_size < max)
		new_size = max;

	if (!(t = API_REALLOC(pRuntime, arr->array, new_size*sizeof(void*)))) return -1;
	arr->array = (void**)t;
	(void)API_MEMSET(arr->array + arr->size, 0, (new_size - arr->size)*sizeof(void*));
	arr->size = new_size;
	return 0;
}

int array_list_put_idx(PRUNTIME pRuntime, struct array_list *arr, int idx, void *data)
{
	if (array_list_expand_internal(pRuntime, arr, idx + 1)) return -1;
	if (arr->array[idx]) arr->free_fn(pRuntime, arr->array[idx]);
	arr->array[idx] = data;
	if (arr->length <= idx) arr->length = idx + 1;
	return 0;
}

int array_list_add(PRUNTIME pRuntime, struct array_list *arr, void *data)
{
	return array_list_put_idx(pRuntime, arr, arr->length, data);
}

void array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *))
{
	qsort(arr->array, arr->length, sizeof(arr->array[0]), sort_fn);
}

void* array_list_bsearch(const void **key, struct array_list *arr, int(*sort_fn)(const void *, const void *))
{
	return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]),	sort_fn);
}

int array_list_length(struct array_list *arr)
{
	return arr->length;
}
