/*****
 NAME
 	cstack.m - source code for CStack class
 VERSION
 	$Id$
 CHANGELOG
 	$Log$
 */

#include <coconut/cstack.h>
#include <coconut/csystem.h>
#include <coconut/ptext.h>

#define	UNITSIZE	16
#define	TMP_CALCNUM(n)	((u_int) ((n + UNITSIZE) / UNITSIZE))
#define	CALCNUM(n)	(TMP_CALCNUM(n) * UNITSIZE)

@implementation CStack

- init
{
	return [self initStack: sizeof(void *)] ;
}

- initStack: (size_t) elmsize
{
	current_num = 0 ; 
	elm_size = elmsize ;
	this_array = g_array_new(FALSE, FALSE, CALCNUM(0)) ;
	[CSystem checkPtr: this_array] ;
	return [super init] ;
}

- (void) dealloc
{
	g_array_free(this_array, TRUE) ;
	return [super dealloc] ;
}

- (u_int) count
{
	return current_num ;
}

- clear
{
	g_array_set_size(this_array, 0) ;
	current_num = 0 ;
	return nil ;
}

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

	bottom = this_array->data ;
	if(bottom){
		top = bottom + elm_size * (current_num - 1) ;
		for( ; top>=bottom ; top -= elm_size){
			result = (*func)(top, p1, p2) ;
			if(result)
				return result ;
		}
	}
	return NULL ;
}

- push: (const void *) p
{
	byte *		data ;
	if(current_num >= this_array->len)
		 g_array_set_size(this_array, CALCNUM(current_num+1));
	data = (byte *) this_array->data ;
	[CSystem checkPtr: data] ;
	memmove(data + elm_size * current_num, p, elm_size) ;
	current_num++ ;
	return nil ;
}

- (const void *) pop
{
	byte *		data ;
	u_int		newlen ;

	if(current_num > 0){
		data = (byte *) this_array->data ;
		data += elm_size * (current_num-1) ;

		/* keep the content pointed by "data" */
		newlen = CALCNUM(current_num) ;
		if(newlen < this_array->len)
			g_array_set_size(this_array, newlen);
		current_num-- ;
		return data ;
	} else
		return NULL ;
}

- (const void *) peek: (u_int) idx
{
	byte * 	data ;
	if(current_num > idx){
		data = (byte *) this_array->data ;
		data += elm_size * idx ;
		return data ;
	} else
		return NULL ;
}

- (const void *) peekTop
{
	byte * 	data ;
	if(current_num > 0){
		data = (byte *) this_array->data ;
		data += elm_size * (current_num-1) ;
		return data ;
	} else
		return NULL ;
}

- print: (id <PIndentStream>) stream
{
	byte *	bottom ;
	byte *	top ;

	[stream putPtr: "(stack\n"] ;
	  bottom = this_array->data ;
	  if(bottom){
		top = bottom + elm_size * (current_num - 1) ;
		for( ; top>=bottom ; top -= elm_size)
			[((id) top) print: stream] ;
	  }
	[stream putPtr: ")\n"] ;
	return nil ;
}

@end

