/*<html><pre>*/
#ifndef	V_STACK_H
#define V_STACK_H

#define	block_stack_t		bstack_t

/*
 *	Comparison procedure for vpsSort()
 */
typedef int (V_CALL *compar_proc_t)(void *param,void *p1,void *p2);

/*
 *	"Typed stacks": with operator '=' defined for base type.
 *	TODO: move here common function prototypes !
 */
#define	TYPED_STACK_DECLARE_CLASS(type_prefix,type) \
typedef struct type_prefix##_stack_s \
{ \
	unsigned	n_elem;			/* maximal number of elements */ \
	unsigned	next_elem;		/* number of added elements */ \
	type		*buf;			/* stack's storage */ \
}	type_prefix##_stack_t, *type_prefix##_stack_p;

/*
 *	Empty initializer
 */
#define	TYPED_STACK_EMPTY_INITIALIZER {0,0,NULL}

/*	We define u8_stack_t as "stack of u8_t" */
TYPED_STACK_DECLARE_CLASS(u8,u8_t)

/*	We define vp_stack_t as "stack of void_p" */
TYPED_STACK_DECLARE_CLASS(vp,void_p)

/*	======================================================================
 *	"Stack of blocks": for elements operator '=' may be undefined.
 */
typedef struct		bstack_s
{
	unsigned		n_elem;
	unsigned		next_elem;
	unsigned		element_size;
	unsigned char	*buf;				/* storage */
	unsigned char	*ptr;				/* pointer to the next place */
}	bstack_t, *bstack_p;

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
	/*	==================================================================
	 *	Methods of typed stacks
	 */
	/*	Initializes all fields of struct <type>_stack_s with zeros */
	void	V_GLOBAL	u8sInit(u8_stack_t *stack);
	void	V_GLOBAL	vpsInit(vp_stack_t *stack);
	/*	Releases stack's storage and state state of stack equal to 
	 *	state after xxaInit() */
	void	V_GLOBAL	u8sClear(u8_stack_t *stack);
	void	V_GLOBAL	vpsClear(vp_stack_t *stack);
	/*	Pushes one element */
	void	V_GLOBAL	u8sPush(u8_stack_t *stack,u8_t element);
	void	V_GLOBAL	vpsPush(vp_stack_t *stack,void_p element);
	/*	Pushes buffer of num_elements elements */
	void	V_GLOBAL	u8sPushBuffer(u8_stack_t *stack,u8_t *src,
									 unsigned num_elements);
	void	V_GLOBAL	vpsPushBuffer(vp_stack_t *stack,void_p *src,
									 unsigned num_elements);
	/*	Pops one element, return 1 on success */
	int		V_GLOBAL	u8sPop(u8_stack_t *stack,u8_t *element);
	int		V_GLOBAL	vpsPop(vp_stack_t *stack,void_p *element);
	/*	Pops buffer of num_elements, returns number of elements.
     *	NOTE !
     *	This is really NOT a 'pop' operation because it just
     *	copies 'num_elements' last pushed in 'stack' in new
     *	place 'dst' in FIFO order. For example:
     *	Push(0); Push(1); Push(2); followed by PopBuffer(2,dst);
     *  produces {1, 2} in 'dst' (also should {2,1} !).
     */
	int		V_GLOBAL	u8sPopBuffer(u8_stack_t *stack,u8_t *dst,
									 unsigned num_elements);
	int		V_GLOBAL	vpsPopBuffer(vp_stack_t *stack,void_p *dst,
									 unsigned num_elements);
	/* Sets element at pos; if storage too small, resizes it. */
	void	V_GLOBAL	u8sSet(u8_stack_t *stack,unsigned pos,
							   u8_t element);
	void	V_GLOBAL	vpsSet(vp_stack_t *stack,unsigned pos,
							   void_p element);
	/*	Concatenates two stacks as plain memory blocks (i.e. first
     *	Pop() for result  - 'dst' - will return element last
     *	Push()'ed into 'src'); 'src' unchanged.
     */
	void	V_GLOBAL	u8sConcat(u8_stack_t *dst,u8_stack_t *src);
	void	V_GLOBAL	vpsConcat(vp_stack_t *dst,vp_stack_t *src);
	/*	Resizes stack. If newsize less than stack's size of storage, than 
	 *	xxaResize() affects only TOS (stack->next_elem); otherwise new 
	 *	storage allocated and (newsize-size) zeros added beyond old TOS.
     *	Old contens of stack unchanged.
	 */
	void	V_GLOBAL	u8sResize(u8_stack_t *stack,unsigned newsize);
	void	V_GLOBAL	vpsResize(vp_stack_t *stack,unsigned newsize);
    /*	Frees unused memory */
	void	V_GLOBAL	u8sAdjust(u8_stack_t *stack);
	void	V_GLOBAL	vpsAdjust(vp_stack_t *stack);
	/*
	 *	Finds first NULL element in stack and set it to 'ptr'.
	 *	If no space (i.e. all elements are non-NULL), adds 'ptr'
	 *	at the ant of the stack.
	 *	Returns index of 'ptr' in stack.
	 */
	u32_t	V_GLOBAL	vpsStore(vp_stack_t *stack,void *ptr);
	/*
	 *	Searches for 'ptr' in stack. If 'ptr' found, stores index of
	 *	ptr in 'pos_return' and returns true; otherwise returns false.
	 */
	vboolean	V_GLOBAL	vpsFind(vp_stack_t *st,void *ptr,
		u32_t *pos_return);
	/*
	 *	Sorts pointers in stack.
	 */
	void		V_GLOBAL	vpsSort(vp_stack_t *objects,
		compar_proc_t compar,void *param);
#ifdef	STACK_NO_MACRO
	/*	Returns number of added elements */
	unsigned	V_GLOBAL	u8sCount(u8_stack_t *stack);
	unsigned	V_GLOBAL	vpsCount(vp_stack_t *stack);
	/*	Returns element at pos (NO CHECKS PERFORMED !) */
	u8_t	V_GLOBAL	u8sGet(u8_stack_t *stack,unsigned pos);
	void_p	V_GLOBAL	vpsGet(vp_stack_t *stack,unsigned pos);
	/*	Returns stack's storage. Don't duplicate it because it can be 
	 *	invalidated in any call of Push/Set/Resize functions.
	 */
	u8_p	V_GLOBAL	u8sGetStorage(u8_stack_t *stack);
	void_pp	V_GLOBAL	vpsGetStorage(vp_stack_t *stack);
#else	/* !STACK_NO_MACRO */
#define	u8sCount(stack)					(stack)->next_elem
#define	vpsCount(stack)					(stack)->next_elem

#define u8sGet(stack,pos)					(stack)->buf[(pos)]
#define vpsGet(stack,pos)					(stack)->buf[(pos)]

#define u8sGetStorage(stack)				(stack)->buf
#define vpsGetStorage(stack)				(stack)->buf
#endif	/* !STACK_NO_MACRO */
	/*	==================================================================
	 *	Methods of "Stack of blocks"
	 */
	/* Same sense */
	void	V_GLOBAL	stackInit(bstack_t *stack,unsigned element_size);
	/* Same sense */
	void	V_GLOBAL	stackClear(bstack_t *stack);
	/* Pushes element_size bytes from element */
	void	V_GLOBAL	stackPush(bstack_t *stack,void *element);
	/* Pushes (element_size * num_elements) bytes from buffer */
	void	V_GLOBAL	stackPushBuffer(bstack_t *stack,void *src,
										unsigned num_elements);
	/* Pops element_size bytes to element */
	int		V_GLOBAL	stackPop(bstack_t *stack,void *element);
	/* Pops (element_size * num_elements) bytes to dst */
	int		V_GLOBAL	stackPopBuffer(bstack_t *stack,void *dst,
									   unsigned num_elements);
	/* Copies element_size bytes from element to the position of 
	 * element #pos; if stack too small, resizes it */
	void	V_GLOBAL	stackSet(bstack_t *stack,unsigned pos,
							   void *element);
	/* Same sense */
	void	V_GLOBAL	stackConcat(bstack_t *dst,bstack_t *src);
	void	V_GLOBAL	stackResize(bstack_t *stack,unsigned newsize);
	void	V_GLOBAL	stackAdjust(bstack_t *stack);
#ifdef	STACK_NO_MACRO
	/* Same sense */
	unsigned	V_GLOBAL	stackCount(bstack_t *stack);
	/* Copies element_size bytes from position of element #pos to dst */
	void	V_GLOBAL	stackGet(bstack_t *stack,void *dst,unsigned pos);
	/* Same sense; differs only in return type */
	void_p	V_GLOBAL	stackGetStorage(bstack_t *stack);
#else	/* STACK_NO_MACRO undefined - code will be inlined */
#define	stackCount(stack)					(stack)->next_elem
#define stackGet(stack,dst,pos)\
		memCopy(dst,(u8_p)(stack)->buf+(pos)*(stack)->element_size,\
			(stack)->element_size);
#define stackGetStorage(stack)				(stack)->buf
#endif	/* STACK_NO_MACRO */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif	/* V_STACK_H */
/*</pre></html>*/
/*EOF*/
