#include        "depend.h"
#include        "genint.h"
#include        "int.h"
#include	"process.h"
#include	"intproto.h"

/* Memory management routines */

#ifndef NO_PROTOTYPES
static void compandtake(word, word *, word *, word *, bool);
static void sinsert(word);
#else
static void compandtake();
static void sinsert();
#endif


int compactify_allowed=1;
#define space 400 /* words */


void request(app, ah, am)
word app, *ah, *am;
{
    word t2, t4, t5;
    bool wascompactified, found;

    if (app >= MAXAPPT) errsignal(RTEMEMOV);
    wascompactified = FALSE;

    if( compactify_allowed && thisp->force_compactification ){
         compactify();
         thisp->force_compactification=FALSE;
         wascompactified=TRUE;
    }

    if (thisp->freeitem != 0)           /* reserve dictionary item */
    {
        *ah = thisp->freeitem;
        thisp->freeitem = M[ *ah ];
    }
    else
    {
        *ah = thisp->lastitem-2;
        if (*ah <= thisp->lastused + space)     /* cannot take free item */
        {
            if( compactify_allowed )
                if( !wascompactified ) compactify(),wascompactified=TRUE;
                else ;
            else
                thisp->force_compactification=TRUE;
            *ah = thisp->lastitem-2;
            if (*ah <= thisp->lastused) errsignal(RTEMEMOV);
        }

        thisp->lastitem = *ah;
        M[ *ah+1 ] = 0;                 /* clear mark */
    }                                   /* now we have a free dict. item */


    if (app == 2 && thisp->headk2 != 0)    /* special case app=2 */
    {
        *am = thisp->headk2;
        thisp->headk2 = M[ *am+SHORTLINK ];
    }
    else
    {
        word t1 = thisp->headk;
        found = FALSE;
        t4 = 0;
        while (t1 != thisp->lower && !found)
        {
            t2 = M[ t1 ];
            if (t2 == app) found = TRUE;
            else
                if (t2-app >= 2) found = TRUE;
                else
                {
                    t4 = t1;
                    t1 = M[ t1+LONGLINK ];
                }
        }
        if( found ) {
            t5 = M[ t1+SHORTLINK ];
            if (t5 != 0) M[ t5+LONGLINK ] = M[ t1+LONGLINK ];
            else t5 = M[ t1+LONGLINK ];
            if (t4 == 0) thisp->headk = t5;  else M[ t4+LONGLINK ] = t5;
            *am = t1;
            if (t2 > app)           /* at least two extra words */
            {
                t5 = t1+app;
                M[ t5 ] = t2-app;
                sinsert(t5);
            }
        }
        else
        if ( thisp->lastitem - thisp->lastused > app + space )
        {
            *am = thisp->lastused+1;
            thisp->lastused += app;
        }
        else
        {
            M[ *ah ] = thisp->freeitem;        /* return dictionary item */
            thisp->freeitem = *ah;
            if( compactify_allowed )
                if( !wascompactified ) compactify();
                else ;
            else
                thisp->force_compactification=TRUE;
            *ah = thisp->lastitem-2;           /* reserve dictionary item */
            thisp->lastitem = *ah;
            M[ *ah+1 ] = 0;                    /* clear mark */
            if ( thisp->lastitem - thisp->lastused > app ) {
                *am = thisp->lastused+1;
                thisp->lastused += app;
            }
            else
                errsignal(RTEMEMOV);
        }
    }

    M[ *am ] = app;
    for (t2 = *am+1;  t2 < *am+app;  t2++ ) M[ t2 ] = 0;
    M[ *ah ] = *am;

}


static void sinsert(am)                        /* Dispose of a memory item. */
word am;
{
    word t1, t2, t3, t4;

    t1 = M[ am ];                       /* appetite */
    if (t1 == 2)                        /* a special list should be used */
    {
        M[ am+SHORTLINK ] = thisp->headk2;
        thisp->headk2 = am;
    }
    else
    {
        t2 = thisp->headk;
        t4 = 0;
        while (TRUE)                    /* look for a proper place */
        {
            t3 = M[ t2 ];               /* appetite */
            if (t1 == t3)               /* an entry with matching appetite */
            {
                M[ am+SHORTLINK ] = M[ t2+SHORTLINK ];
                M[ t2+SHORTLINK ] = am;
                break;
            }
            else
                if (t1 < t3)
                {
                    M[ am+LONGLINK ] = t2;
                    M[ am+SHORTLINK ] = 0;
                    if (t4 == 0) thisp->headk = am;
                    else M[ t4+LONGLINK ] = am;
                    break;
                }
                else
                {
                    t4 = t2;
                    t2 = M[ t2+LONGLINK ];
                }
        }
    }
}


void disp(virt)                         /* Simple kill. */
virtaddr *virt;
{
    word t1, t2;

    t1 = M[ virt->addr+1 ];
    if (t1 == virt->mark)		/* not none */
    {
        t1++;                           /* advance mark */
        t2 = M[ virt->addr ];           /* am */
        M[ virt->addr+1 ] = t1;
        if (t1 != MAXMARKER)            /* mark still usable */
        {
            M[ virt->addr ] = thisp->freeitem;
            thisp->freeitem = virt->addr;
        }                               /* now dictionary item is released */
        if (t2+M[ t2 ]-1 == thisp->lastused)   /* on the boundary */
            thisp->lastused = t2-1;
        else sinsert(t2);
    }
} /* end disp */


word memavail()				/* Compute available memory size */
{
    word t1, t2, avail;

    avail = thisp->lastitem-thisp->lastused-1;	/* contiguos memory */
    t1 = thisp->headk2;			/* go through killed 2 list */
    while (t1 != 0)
    {
    	avail += 2;
    	t1 = M[ t1+SHORTLINK ];
    }
    t1 = thisp->headk;
    while (t1 != thisp->lower)		/* go through killed object list */
    {
    	t2 = t1;
    	while (t2 != 0)
	{
	    avail += M[ t2 ];
	    t2 = M[ t2+SHORTLINK ];
	}
	t1 = M[ t1+LONGLINK ];
    }
    t1 = thisp->freeitem;		/* go through free item list */
    while (t1 != 0)
    {
    	avail += 2;
    	t1 = M[ t1 ];
    }
    return(avail);
} /* end memavail */
