/* File:      dynamic_stack.h
** Author(s): Ernie Johnson
** Contact:   xsb-contact@cs.sunysb.edu
** 
** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
** 
** XSB is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
** 
** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
** more details.
** 
** You should have received a copy of the GNU Library General Public License
** along with XSB; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** $Id: dynamic_stack.h,v 1.2 2000/06/26 15:53:26 ejohnson Exp $
** 
*/


#ifndef DYNAMIC_STACK

#define DYNAMIC_STACK


/*-------------------------------------------------------------------------*/

/* Dynamic Stack Structure
   ----------------------- */
typedef struct {
  struct {
    void *top;		   /* next available frame */
    void *base;		   /* stack bottom */
    void *ceiling;	   /* off-end pointer for determining fullness */
  } stack;
  struct {
    size_t frame;	   /* size of a frame */
    size_t stackinit;	   /* initial size of stack in number of frames */
    size_t stackcur;	   /* current size of stack in number of frames */
  } size;
  char *name;
} DynamicStack;

#define DynStk_Top(DS)		( (DS).stack.top )
#define DynStk_Base(DS)		( (DS).stack.base )
#define DynStk_Ceiling(DS)	( (DS).stack.ceiling )
#define DynStk_FrameSize(DS)	( (DS).size.frame )
#define DynStk_InitSize(DS)	( (DS).size.stackinit )
#define DynStk_CurSize(DS)	( (DS).size.stackcur )
#define DynStk_Name(DS)		( (DS).name )

#define DynStk_NumFrames(DS)	\
   (((char *)DynStk_Top(DS) - (char *)DynStk_Base(DS)) / DynStk_FrameSize(DS))


/* Top-of-Stack Manipulations
   -------------------------- */
#define DynStk_NextFrame(DS)	\
   (void *)((char *)DynStk_Top(DS) + DynStk_FrameSize(DS))
#define DynStk_PrevFrame(DS)	\
   (void *)((char *)DynStk_Top(DS) - DynStk_FrameSize(DS))


/* Stack Maintenance
   ----------------- */
extern void dsPrint(DynamicStack, char *);
extern void dsInit(DynamicStack *, size_t, size_t, char *);
extern void dsExpand(DynamicStack *, int);
extern void dsShrink(DynamicStack *);

#define DynStk_Init(DS,NumElements,FrameType,Desc)	\
   dsInit(DS,NumElements,sizeof(FrameType),Desc)

#define DynStk_ResetTOS(DS)	DynStk_Top(DS) = DynStk_Base(DS)
#define DynStk_IsEmpty(DS)	( DynStk_Top(DS) == DynStk_Base(DS) )
#define DynStk_IsFull(DS)	( DynStk_Top(DS) >= DynStk_Ceiling(DS) )

#define DynStk_WillOverflow(DS,NFrames)				\
   ( (char *)DynStk_Top(DS) + NFrames * DynStk_FrameSize(DS)	\
     > (char *)DynStk_Ceiling(DS) )


#define DynStk_ExpandIfFull(DS) {		\
   if ( DynStk_IsFull(DS) )			\
     dsExpand(&(DS),1);				\
 }

#define DynStk_ExpandIfOverflow(DS,N) {		\
   if ( DynStk_WillOverflow(DS,N) )		\
     dsExpand(&(DS),N);				\
 }


/*
 * In the following macros, "Frame" is assigned a pointer to either
 * the next or the current frame on the stack.
 */

/* Operations With Bounds Checking
   ------------------------------- */
#define DynStk_Push(DS,Frame) {			\
   DynStk_ExpandIfFull(DS);			\
   DynStk_BlindPush(DS,Frame);			\
 }

#define DynStk_Pop(DS,Frame) {			\
   if ( ! DynStk_IsEmpty(DS) )			\
     DynStk_BlindPop(DS,Frame)			\
   else						\
     Frame = NULL;				\
 }

#define DynStk_Peek(DS,Frame) {			\
   if ( ! DynStk_IsEmpty(DS) )			\
     DynStk_BlindPeek(DS,Frame);		\
   else						\
     Frame = NULL;				\
 }


/* Operations Without Bounds Checking
   ---------------------------------- */
#define DynStk_BlindPush(DS,Frame) {		\
   Frame = DynStk_Top(DS);			\
   DynStk_Top(DS) = DynStk_NextFrame(DS);	\
 }

#define DynStk_BlindPop(DS,Frame) {		\
   DynStk_Top(DS) = DynStk_PrevFrame(DS);	\
   Frame = DynStk_Top(DS);			\
 }

#define DynStk_BlindPeek(DS,Frame)		\
   Frame = DynStk_PrevFrame(DS)

/*-------------------------------------------------------------------------*/


#endif
