/*****
 NAME
	carray.m - source codee for CArray class
 VERSION
	$Id$
 CHANGELOG
	$Log$
 */

#include <coconut/carray.h>
#include <coconut/csystem.h>
#include <coconut/cerror.h>
#include <coconut/ptext.h>

#define	PTR(P, IDX)		&(((byte *) P)[elm_size * (IDX)])

@implementation CArray

- init
{
	return [self initArray: sizeof(void *) dealloc: NULL] ;
}

- initArray: (size_t) elmsize dealloc: (dealloc_func_t) defunc 
{
	elm_size = elmsize ;
	array_body = g_array_new(FALSE, FALSE, elmsize) ;
	[CSystem checkPtr: array_body] ;
	dealloc_func = defunc ; 
	return [super init] ;
}

- p_clear
{
	byte *	p ;
	byte *	endp ;
	p = array_body->data ; endp = p + elm_size * array_body->len ;
	if(dealloc_func){
		for( ; p<endp ; p += elm_size)
			(*dealloc_func)(p) ;
	}
	g_array_free(array_body, TRUE) ;
	return nil ;
}

- (void) dealloc
{
	[self p_clear] ;
	[super dealloc] ;
}

- (u_int) count
{
	return array_body->len ;
}

- clear
{
	[self p_clear] ;
	array_body = g_array_new(FALSE, FALSE, elm_size) ;
	[CSystem checkPtr: array_body] ;
	return nil ;
}

- (const void *) foreach: (foreach_func_t) func with: (void *) p1
    with: (void *) p2
{
	byte *		p ;
	byte *		endp ;
	const void *	result ;

	p = array_body->data ; endp = p + elm_size * array_body->len ;
	for( ; p<endp ; p += elm_size){
		if((result = (*func)(p, p1, p2)) != NULL)
			return result ;	
	}
	return NULL ;
}

- append: (const void *) data
{
	g_array_append_vals(array_body, data, 1) ;
	return nil ;
}

- prepend: (const void *) data
{
	g_array_prepend_vals(array_body, data, 1) ;
	return nil ;
}

- (id <PError>) setItem: (const void *) data to: (u_int) idx 
{
	guint	len = array_body->len ;
	byte *	p ;

	if(idx < len){
		p = PTR(array_body->data, idx) ;
		memmove(p, data, elm_size) ;
		return nil ;
	} else
		return [CError illegal_range] ;
}

- (const void *) item: (u_int) idx 
{
	guint	len = array_body->len ;
	return idx<len ? PTR(array_body->data, idx) : NULL ;
}

- (const void *) first
{
	return array_body->len > 0 ? array_body->data : NULL ;
}

- (const void *) last
{
	guint	len = array_body->len ;
	return len>0 ? PTR(array_body->data, len-1) : NULL ;
}

- (const void *) search: (u_int *) idx compareFunc: (compare_func_t) cmp
    by: (const void *) obj 
{
	byte *		p ;
	byte *		endp ;
	u_int		i ;

	p = array_body->data ; endp = p + elm_size * array_body->len ;
	for(i=0 ; p<endp ; p += elm_size, i++){
		if((*cmp)(p, obj) == 0){
			*idx = i ;
			return p ;
		}
	}
	return NULL ;
}

- (id <PError>) removeItem: (u_int) idx
{
	id <PError>	result ;
	if(idx < array_body->len){
		g_array_remove_index(array_body, idx) ;
		result = nil ;
	} else
		result = [CError not_exist] ;
	return result ;
}

@end

