This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/C/globals.c
2007-02-21 16:50:51 +00:00

2220 lines
49 KiB
C

/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: non backtrackable term support *
* Last rev: 2/8/06 *
* mods: *
* comments: non-backtrackable term support *
* *
*************************************************************************/
#ifdef SCCS
static char SccsId[] = "%W% %G%";
#endif
#include "Yap.h"
#include "Yatom.h"
#include "Heap.h"
#include "yapio.h"
#include "iopreds.h"
#include "attvar.h"
/* Non-backtrackable terms will from now on be stored on arenas, a
special term on the heap. Arenas automatically contract as we add terms to
the front.
*/
#define QUEUE_ARENA 0
#define QUEUE_DELAY_ARENA 1
#define QUEUE_HEAD 2
#define QUEUE_TAIL 3
#define QUEUE_SIZE 4
#define HEAP_SIZE 0
#define HEAP_MAX 1
#define HEAP_ARENA 2
#define HEAP_DELAY_ARENA 3
#define HEAP_START 4
#define Global_MkIntegerTerm(I) MkIntegerTerm(I)
static UInt
big2arena_sz(CELL *arena_base)
{
return ((MP_INT*)(arena_base+1))->_mp_alloc + (sizeof(MP_INT) + sizeof(Functor)+sizeof(CELL))/sizeof(CELL);
}
static UInt
arena2big_sz(UInt sz)
{
return sz - (sizeof(MP_INT) + sizeof(Functor) + sizeof(CELL))/sizeof(CELL);
}
/* pointer to top of an arena */
static inline CELL *
ArenaLimit(Term arena)
{
CELL *arena_base = RepAppl(arena);
UInt sz = big2arena_sz(arena_base);
return arena_base+sz;
}
/* pointer to top of an arena */
static inline CELL *
ArenaPt(Term arena)
{
return (CELL *)RepAppl(arena);
}
static inline UInt
ArenaSz(Term arena)
{
return big2arena_sz(RepAppl(arena));
}
static Term
CreateNewArena(CELL *ptr, UInt size)
{
Term t = AbsAppl(ptr);
MP_INT *dst;
ptr[0] = (CELL)FunctorBigInt;
dst = (MP_INT *)(ptr+1);
dst->_mp_size = 0L;
dst->_mp_alloc = arena2big_sz(size);
ptr[size-1] = EndSpecials;
return t;
}
#if COROUTINING
/* pointer to top of an arena */
static inline attvar_record *
DelayArenaPt(Term arena)
{
return (attvar_record *)arena;
}
static inline UInt
DelayArenaSz(Term arena)
{
attvar_record *ptr = (attvar_record *)arena-1;
return 1+(ptr-(attvar_record *)ptr->Done);
}
static void
ResetDelayArena(Term old_delay_arena, Term *new_arenap)
{
attvar_record *min = (attvar_record *)*new_arenap;
Term base = min[-1].Done;
while (min < (attvar_record *)old_delay_arena) {
min->Value = (Term)(min-1);
min->Done = base;
RESET_VARIABLE(&min->Atts);
min++;
}
*new_arenap = old_delay_arena;
}
static Term
CreateDelayArena(attvar_record *max, attvar_record *min)
{
attvar_record *ptr = max;
while (ptr > min) {
--ptr;
ptr->Done = (CELL)min;
ptr->Value = (CELL)(ptr-1);
RESET_VARIABLE(&ptr->Atts);
}
RESET_VARIABLE(&(ptr->Value));
return (CELL)max;
}
static Term
NewDelayArena(UInt size)
{
attvar_record *max = DelayTop(), *min = max-size;
Term out;
UInt howmuch;
while ((ADDR)min < Yap_GlobalBase+1024) {
if ((howmuch = Yap_InsertInGlobal((CELL *)max, size*sizeof(attvar_record)))==0) {
Yap_Error(OUT_OF_STACK_ERROR,TermNil,"No Stack Space for Non-Backtrackable terms");
return TermNil;
}
size = howmuch/sizeof(attvar_record);
max = DelayTop(), min = max-size;
}
out = CreateDelayArena(max, min);
SetDelayTop(min);
return out;
}
static Term
GrowDelayArena(Term *arenap, UInt old_size, UInt size, UInt arity)
{
Term arena = *arenap;
UInt howmuch;
if (size == 0) {
if (old_size < 1024) {
size = old_size*2;
} else {
size = old_size+1024;
}
}
if (size < 64) {
size = 64;
}
/* just make sure we are shifted up when we expand stacks */
XREGS[arity+1] = arena;
if ((howmuch = Yap_InsertInGlobal((CELL *)arena, (size-old_size)*sizeof(attvar_record)))==0) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return TermNil;
}
size = howmuch/sizeof(attvar_record)+old_size;
arena = XREGS[arity+1];
CreateDelayArena(DelayArenaPt(arena), DelayArenaPt(arena)-size);
return arena;
}
#endif
static Term
NewArena(UInt size, UInt arity, CELL *where)
{
Term t;
UInt new_size;
if (where == NULL || where == H) {
while (H+size > ASP-1024) {
if (!Yap_gcl(size*sizeof(CELL), arity, ENV, P)) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return TermNil;
}
}
t = CreateNewArena(H, size);
H += size;
} else {
if ((new_size=Yap_InsertInGlobal(where, size*sizeof(CELL)))==0) {
Yap_Error(OUT_OF_STACK_ERROR,TermNil,"No Stack Space for Non-Backtrackable terms");
return TermNil;
}
size = new_size/sizeof(CELL);
t = CreateNewArena(where, size);
}
return t;
}
static Int
p_allocate_arena(void)
{
Term t = Deref(ARG1);
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,"allocate_arena");
return FALSE;
} else if (!IsIntegerTerm(t)) {
Yap_Error(TYPE_ERROR_INTEGER,t,"allocate_arena");
return FALSE;
}
return Yap_unify(ARG2,NewArena(IntegerOfTerm(t), 1, NULL));
}
static Int
p_default_arena_size(void)
{
return Yap_unify(ARG1,MkIntegerTerm(ArenaSz(GlobalArena)));
}
static Int
p_allocate_default_arena(void)
{
Term t = Deref(ARG1);
Term t2 = Deref(ARG2);
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,"allocate_arena");
return FALSE;
} else if (!IsIntegerTerm(t)) {
Yap_Error(TYPE_ERROR_INTEGER,t,"allocate_arena");
return FALSE;
}
if (IsVarTerm(t2)) {
Yap_Error(INSTANTIATION_ERROR,t2,"allocate_arena");
return FALSE;
} else if (!IsIntegerTerm(t)) {
Yap_Error(TYPE_ERROR_INTEGER,t2,"allocate_arena");
return FALSE;
}
GlobalArena = NewArena(IntegerOfTerm(t), 2, NULL);
#if COROUTINING
GlobalDelayArena = NewDelayArena(2);
#endif
return TRUE;
}
static int
GrowArena(Term arena, CELL *pt, UInt old_size, UInt size, UInt arity)
{
if (size == 0) {
if (old_size < 1024*1024) {
size = old_size;
} else {
size = old_size+1024*1024;
}
}
if (size < 4096) {
size = 4096;
}
if (pt == H) {
choiceptr b_ptr;
if (H+size > ASP-1024) {
XREGS[arity+1] = arena;
if (!Yap_gcl(size*sizeof(CELL), arity+1, ENV, P)) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return FALSE;
}
arena = XREGS[arity+1];
}
/* adjust possible back pointers in choice-point stack */
b_ptr = B;
while (b_ptr->cp_h == H) {
b_ptr->cp_h += size;
b_ptr = b_ptr->cp_b;
}
H += size;
} else {
XREGS[arity+1] = arena;
if ((size=Yap_InsertInGlobal(pt, size*sizeof(CELL)))==0) {
return FALSE;
}
size = size/sizeof(CELL);
arena = XREGS[arity+1];
}
CreateNewArena(ArenaPt(arena), size+old_size);
return TRUE;
}
static void
CloseArena(CELL *oldH, CELL *oldHB, CELL *oldASP, Term *oldArenaP, UInt old_size)
{
UInt new_size;
if (H == oldH)
return;
new_size = old_size - (H-RepAppl(*oldArenaP));
*oldArenaP = CreateNewArena(H, new_size);
H = oldH;
HB = oldHB;
ASP = oldASP;
}
static inline void
clean_dirty_tr(tr_fr_ptr TR0) {
if (TR != TR0) {
tr_fr_ptr pt = TR0;
do {
Term p = TrailTerm(pt++);
if (IsVarTerm(p)) {
RESET_VARIABLE(p);
} else {
/* copy downwards */
TrailTerm(TR0+1) = TrailTerm(pt);
TrailTerm(TR0) = TrailTerm(TR0+2) = p;
pt+=2;
TR0 += 3;
}
} while (pt != TR);
TR = TR0;
}
}
#if COROUTINING
static int
CopyAttVar(CELL *orig, CELL ***to_visit_ptr, CELL *res, Term *att_arenap)
{
register attvar_record *attv = (attvar_record *)orig;
register attvar_record *newv;
CELL **to_visit = *to_visit_ptr;
CELL *vt;
/* add a new attributed variable */
if (DelayArenaSz(*att_arenap) < 8)
return FALSE;
newv = DelayArenaPt(*att_arenap);
newv--;
RESET_VARIABLE(&(newv->Value));
RESET_VARIABLE(&(newv->Done));
vt = &(attv->Atts);
to_visit[0] = vt-1;
to_visit[1] = vt;
if (IsVarTerm(attv->Atts)) {
newv->Atts = (CELL)H;
to_visit[2] = H;
H++;
} else {
to_visit[2] = &(newv->Atts);
}
to_visit[3] = (CELL *)vt[-1];
*to_visit_ptr = to_visit+4;
*res = (CELL)&(newv->Done);
*att_arenap = (CELL)(newv);
return TRUE;
}
#endif
static int
copy_complex_term(register CELL *pt0, register CELL *pt0_end, CELL *ptf, CELL *HLow, Term *att_arenap)
{
CELL **to_visit0, **to_visit = (CELL **)Yap_PreAllocCodeSpace();
CELL *HB0 = HB;
tr_fr_ptr TR0 = TR;
#ifdef COROUTINING
CELL *dvars = NULL;
#endif
HB = HLow;
to_visit0 = to_visit;
loop:
while (pt0 < pt0_end) {
register CELL d0;
register CELL *ptd0;
++ pt0;
ptd0 = pt0;
d0 = *ptd0;
deref_head(d0, copy_term_unk);
copy_term_nvar:
{
if (IsPairTerm(d0)) {
CELL *ap2 = RepPair(d0);
if (ap2 >= HB && ap2 < H) {
/* If this is newer than the current term, just reuse */
*ptf++ = d0;
continue;
}
*ptf = AbsPair(H);
ptf++;
#ifdef RATIONAL_TREES
if (to_visit + 4 >= (CELL **)AuxSp) {
goto heap_overflow;
}
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = ptf;
to_visit[3] = (CELL *)*pt0;
/* fool the system into thinking we had a variable there */
*pt0 = AbsPair(H);
to_visit += 4;
#else
if (pt0 < pt0_end) {
if (to_visit + 3 >= (CELL **)AuxSp) {
goto heap_overflow;
}
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = ptf;
to_visit += 3;
}
#endif
pt0 = ap2 - 1;
pt0_end = ap2 + 1;
ptf = H;
H += 2;
if (H > ASP - 128) {
goto overflow;
}
} else if (IsApplTerm(d0)) {
register Functor f;
register CELL *ap2;
/* store the terms to visit */
ap2 = RepAppl(d0);
if (ap2 >= HB && ap2 < H) {
/* If this is newer than the current term, just reuse */
*ptf++ = d0;
continue;
}
f = (Functor)(*ap2);
if (IsExtensionFunctor(f)) {
switch((CELL)f) {
case (CELL)FunctorDBRef:
*ptf++ = d0;
break;
case (CELL)FunctorLongInt:
if (H > ASP - (128+3)) {
goto overflow;
}
*ptf++ = AbsAppl(H);
H[0] = (CELL)f;
H[1] = ap2[1];
H[2] = EndSpecials;
H += 3;
break;
case (CELL)FunctorDouble:
if (H > ASP - (128+(2+SIZEOF_DOUBLE/sizeof(CELL)))) {
goto overflow;
}
*ptf++ = AbsAppl(H);
H[0] = (CELL)f;
H[1] = ap2[1];
#if SIZEOF_DOUBLE == 2*SIZEOF_LONG_INT
H[2] = ap2[2];
H[3] = EndSpecials;
H += 4;
#else
H[2] = EndSpecials;
H += 3;
#endif
break;
default:
{
/* big int */
UInt sz = ArenaSz(d0), i;
if (H > ASP - (128+sz)) {
goto overflow;
}
*ptf++ = AbsAppl(H);
H[0] = (CELL)f;
for (i = 1; i < sz; i++) {
H[i] = ap2[i];
}
H += sz;
}
}
continue;
}
*ptf = AbsAppl(H);
ptf++;
/* store the terms to visit */
#ifdef RATIONAL_TREES
if (to_visit + 4 >= (CELL **)AuxSp) {
goto heap_overflow;
}
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = ptf;
to_visit[3] = (CELL *)*pt0;
/* fool the system into thinking we had a variable there */
*pt0 = AbsAppl(H);
to_visit += 4;
#else
if (pt0 < pt0_end) {
if (to_visit + 3 >= (CELL **)AuxSp) {
goto heap_overflow;
}
to_visit[0] = pt0;
to_visit[1] = pt0_end;
to_visit[2] = ptf;
to_visit += 3;
}
#endif
d0 = ArityOfFunctor(f);
pt0 = ap2;
pt0_end = ap2 + d0;
/* store the functor for the new term */
H[0] = (CELL)f;
ptf = H+1;
H += 1+d0;
if (H > ASP - 128) {
goto overflow;
}
} else {
/* just copy atoms or integers */
*ptf++ = d0;
}
continue;
}
derefa_body(d0, ptd0, copy_term_unk, copy_term_nvar);
if (ptd0 >= HLow && ptd0 < H) {
/* we have already found this cell */
*ptf++ = (CELL) ptd0;
} else {
#if COROUTINING
if (IsAttachedTerm((CELL)ptd0)) {
/* if unbound, call the standard copy term routine */
CELL **bp[1];
if (dvars == NULL) {
dvars = (CELL *)DelayArenaPt(*att_arenap);
}
if (ptd0 < dvars &&
ptd0 >= (CELL *)DelayArenaPt(*att_arenap)) {
*ptf++ = (CELL) ptd0;
} else {
tr_fr_ptr CurTR;
CurTR = TR;
bp[0] = to_visit;
HB = HB0;
if (!CopyAttVar(ptd0, bp, ptf, att_arenap)) {
goto delay_overflow;
}
if (H > ASP - 128) {
goto overflow;
}
to_visit = bp[0];
HB = HLow;
ptf++;
if ((ADDR)TR > Yap_TrailTop-128)
goto trail_overflow;
Bind_and_Trail(ptd0, ptf[-1]);
}
} else {
#endif
/* first time we met this term */
RESET_VARIABLE(ptf);
if ((ADDR)TR > Yap_TrailTop-128)
goto trail_overflow;
Bind_and_Trail(ptd0, (CELL)ptf);
ptf++;
#ifdef COROUTINING
}
#endif
}
}
/* Do we still have compound terms to visit */
if (to_visit > to_visit0) {
#ifdef RATIONAL_TREES
to_visit -= 4;
pt0 = to_visit[0];
pt0_end = to_visit[1];
ptf = to_visit[2];
*pt0 = (CELL)to_visit[3];
#else
to_visit -= 3;
pt0 = to_visit[0];
pt0_end = to_visit[1];
ptf = to_visit[2];
#endif
goto loop;
}
/* restore our nice, friendly, term to its original state */
HB = HB0;
clean_dirty_tr(TR0);
return 0;
overflow:
/* oops, we're in trouble */
H = HLow;
/* we've done it */
/* restore our nice, friendly, term to its original state */
HB = HB0;
#ifdef RATIONAL_TREES
while (to_visit > to_visit0) {
to_visit -= 4;
pt0 = to_visit[0];
pt0_end = to_visit[1];
ptf = to_visit[2];
*pt0 = (CELL)to_visit[3];
}
#endif
reset_trail(TR0);
return -1;
heap_overflow:
/* oops, we're in trouble */
H = HLow;
/* we've done it */
/* restore our nice, friendly, term to its original state */
HB = HB0;
#ifdef RATIONAL_TREES
while (to_visit > to_visit0) {
to_visit -= 4;
pt0 = to_visit[0];
pt0_end = to_visit[1];
ptf = to_visit[2];
*pt0 = (CELL)to_visit[3];
}
#endif
reset_trail(TR0);
return -2;
#if COROUTINING
delay_overflow:
/* oops, we're in trouble */
H = HLow;
/* we've done it */
/* restore our nice, friendly, term to its original state */
HB = HB0;
#ifdef RATIONAL_TREES
while (to_visit > to_visit0) {
to_visit -= 4;
pt0 = to_visit[0];
pt0_end = to_visit[1];
ptf = to_visit[2];
*pt0 = (CELL)to_visit[3];
}
#endif
reset_trail(TR0);
return -3;
#endif
trail_overflow:
/* oops, we're in trouble */
H = HLow;
/* we've done it */
/* restore our nice, friendly, term to its original state */
HB = HB0;
#ifdef RATIONAL_TREES
while (to_visit > to_visit0) {
to_visit -= 4;
pt0 = to_visit[0];
pt0_end = to_visit[1];
ptf = to_visit[2];
*pt0 = (CELL)to_visit[3];
}
#endif
reset_trail(TR0);
return -4;
}
static Term
CopyTermToArena(Term t, Term arena, UInt arity, Term *newarena, Term *att_arenap, Int min_grow)
{
UInt old_size = ArenaSz(arena);
CELL *oldH = H;
CELL *oldHB = HB;
CELL *oldASP = ASP;
int res;
#if COROUTINING
Term old_delay_arena;
#endif
restart:
#if COROUTINING
old_delay_arena = *att_arenap;
#endif
t = Deref(t);
if (IsVarTerm(t)) {
ASP = ArenaLimit(arena);
H = HB = ArenaPt(arena);
#if COROUTINING
if (IsAttachedTerm(t)) {
CELL *Hi;
*H = t;
Hi = H+1;
H += 2;
if ((res = copy_complex_term(Hi-2, Hi-1, Hi, Hi, att_arenap)) < 0)
goto error_handler;
CloseArena(oldH, oldHB, oldASP, newarena, old_size);
return Hi[0];
}
#endif
Term tn = MkVarTerm();
if (H > ASP - 128) {
res = -1;
goto error_handler;
}
CloseArena(oldH, oldHB, oldASP, newarena, old_size);
return tn;
} else if (IsAtomOrIntTerm(t)) {
return t;
} else if (IsPairTerm(t)) {
Term tf;
CELL *ap;
CELL *Hi;
H = HB = ArenaPt(arena);
ASP = ArenaLimit(arena);
ap = RepPair(t);
Hi = H;
tf = AbsPair(H);
H += 2;
if ((res = copy_complex_term(ap-1, ap+1, Hi, Hi, att_arenap)) < 0) {
goto error_handler;
}
CloseArena(oldH, oldHB, oldASP, newarena, old_size);
return tf;
} else {
Functor f;
Term tf;
CELL *HB0;
CELL *ap;
H = HB = ArenaPt(arena);
ASP = ArenaLimit(arena);
f = FunctorOfTerm(t);
HB0 = H;
ap = RepAppl(t);
tf = AbsAppl(H);
H[0] = (CELL)f;
if (IsExtensionFunctor(f)) {
switch((CELL)f) {
case (CELL)FunctorDBRef:
CloseArena(oldH, oldHB, oldASP, newarena, old_size);
return t;
case (CELL)FunctorLongInt:
if (H > ASP - (128+3)) {
res = -1;
goto error_handler;
}
H[1] = ap[1];
H[2] = EndSpecials;
H += 3;
break;
case (CELL)FunctorDouble:
if (H > ASP - (128+(2+SIZEOF_DOUBLE/sizeof(CELL)))) {
res = -1;
goto error_handler;
}
H[1] = ap[1];
#if SIZEOF_DOUBLE == 2*SIZEOF_LONG_INT
H[2] = ap[2];
H[3] = EndSpecials;
H += 4;
#else
H[2] = EndSpecials;
H += 3;
#endif
break;
default:
{
UInt sz = ArenaSz(t), i;
if (H > ASP - (128+sz)) {
res = -1;
goto error_handler;
}
for (i = 1; i < sz; i++) {
H[i] = ap[i];
}
H += sz;
}
}
} else {
H += 1+ArityOfFunctor(f);
if (H > ASP-128) {
res = -1;
goto error_handler;
}
if ((res = copy_complex_term(ap, ap+ArityOfFunctor(f), HB0+1, HB0, att_arenap)) < 0) {
goto error_handler;
}
}
CloseArena(oldH, oldHB, oldASP, newarena, old_size);
return tf;
}
error_handler:
H = HB;
CloseArena(oldH, oldHB, oldASP, newarena, old_size);
#if COROUTINING
if (old_delay_arena != MkIntTerm(0))
ResetDelayArena(old_delay_arena, att_arenap);
#endif
XREGS[arity+1] = t;
XREGS[arity+2] = arena;
XREGS[arity+3] = (CELL)newarena;
XREGS[arity+4] = (CELL)att_arenap;
{
CELL *old_top = ArenaLimit(*newarena);
ASP = oldASP;
H = oldH;
HB = oldHB;
switch (res) {
case -1:
/* handle arena overflow */
if (!GrowArena(arena, old_top, old_size, min_grow, arity+4)) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return 0L;
}
break;
#if COROUTINING
case -3:
/* handle delay arena overflow */
old_size = DelayArenaSz(*att_arenap);
if (!GrowDelayArena(att_arenap, old_size, 0L, arity+4)) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return 0L;
}
break;
#endif
case -4:
/* handle trail overflow */
if(!Yap_growtrail (sizeof(CELL) * 16 * 1024L, FALSE)) {
Yap_Error(OUT_OF_TRAIL_ERROR, TermNil, Yap_ErrorMessage);
return 0L;
}
break;
default: /* temporary space overflow */
if (!Yap_ExpandPreAllocCodeSpace(0,NULL)) {
Yap_Error(OUT_OF_AUXSPACE_ERROR, TermNil, Yap_ErrorMessage);
return 0L;
}
}
}
oldH = H;
oldHB = HB;
oldASP = ASP;
att_arenap = (Term *)XREGS[arity+4];
newarena = (CELL *)XREGS[arity+3];
arena = Deref(XREGS[arity+2]);
t = XREGS[arity+1];
old_size = ArenaSz(arena);
goto restart;
}
inline static GlobalEntry *
FindGlobalEntry(Atom at)
/* get predicate entry for ap/arity; create it if neccessary. */
{
Prop p0;
AtomEntry *ae = RepAtom(at);
READ_LOCK(ae->ARWLock);
p0 = ae->PropsOfAE;
while (p0) {
GlobalEntry *pe = RepGlobalProp(p0);
if ( pe->KindOfPE == GlobalProperty
#if THREADS
&& pe->owner_id == worker_id
#endif
) {
READ_UNLOCK(ae->ARWLock);
return pe;
}
p0 = pe->NextOfPE;
}
READ_UNLOCK(ae->ARWLock);
return NULL;
}
inline static GlobalEntry *
GetGlobalEntry(Atom at)
/* get predicate entry for ap/arity; create it if neccessary. */
{
Prop p0;
AtomEntry *ae = RepAtom(at);
GlobalEntry *new;
WRITE_LOCK(ae->ARWLock);
p0 = ae->PropsOfAE;
while (p0) {
GlobalEntry *pe = RepGlobalProp(p0);
if ( pe->KindOfPE == GlobalProperty
#if THREADS
&& pe->owner_id == worker_id
#endif
) {
WRITE_UNLOCK(ae->ARWLock);
return pe;
}
p0 = pe->NextOfPE;
}
new = (GlobalEntry *) Yap_AllocAtomSpace(sizeof(*new));
INIT_RWLOCK(new->GRWLock);
new->KindOfPE = GlobalProperty;
#if THREADS
new->owner_id = worker_id;
#endif
new->NextGE = GlobalVariables;
GlobalVariables = new;
new->AtomOfGE = ae;
new->NextOfPE = ae->PropsOfAE;
ae->PropsOfAE = AbsGlobalProp(new);
RESET_VARIABLE(&new->global);
WRITE_UNLOCK(ae->ARWLock);
return new;
}
static Int
p_nb_setval(void)
{
Term t = Deref(ARG1), to;
GlobalEntry *ge;
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,"nb_setval");
return (TermNil);
} else if (!IsAtomTerm(t)) {
Yap_Error(TYPE_ERROR_ATOM,t,"nb_setval");
return (FALSE);
}
ge = GetGlobalEntry(AtomOfTerm(t));
to = CopyTermToArena(ARG2, GlobalArena, 2, &GlobalArena, &GlobalDelayArena, 0);
if (to == 0L)
return FALSE;
WRITE_LOCK(ge->GRWLock);
ge->global=to;
WRITE_UNLOCK(ge->GRWLock);
return TRUE;
}
static Int
p_b_setval(void)
{
Term t = Deref(ARG1);
GlobalEntry *ge;
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,"b_setval");
return (TermNil);
} else if (!IsAtomTerm(t)) {
Yap_Error(TYPE_ERROR_ATOM,t,"b_setval");
return (FALSE);
}
ge = GetGlobalEntry(AtomOfTerm(t));
WRITE_LOCK(ge->GRWLock);
#ifdef MULTI_ASSIGNMENT_VARIABLES
/* the evil deed is to be done now */
MaBind(&ge->global, ARG2);
WRITE_UNLOCK(ge->GRWLock);
return TRUE;
#else
WRITE_UNLOCK(ge->GRWLock);
Yap_Error(SYSTEM_ERROR,t2,"update_array");
return FALSE;
#endif
}
static Int
p_nb_getval(void)
{
Term t = Deref(ARG1), to;
GlobalEntry *ge;
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,"nb_getval");
return FALSE;
} else if (!IsAtomTerm(t)) {
Yap_Error(TYPE_ERROR_ATOM,t,"nb_getval");
return FALSE;
}
ge = FindGlobalEntry(AtomOfTerm(t));
if (!ge)
return FALSE;
READ_LOCK(ge->GRWLock);
to = ge->global;
READ_UNLOCK(ge->GRWLock);
return Yap_unify(ARG2, to);
}
static Int
p_nb_delete(void)
{
Term t = Deref(ARG1);
GlobalEntry *ge, *g;
AtomEntry *ae;
Prop gp, g0;
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,"nb_delete");
return FALSE;
} else if (!IsAtomTerm(t)) {
Yap_Error(TYPE_ERROR_ATOM,t,"nb_delete");
return FALSE;
}
ge = FindGlobalEntry(AtomOfTerm(t));
if (!ge)
return FALSE;
WRITE_LOCK(ge->GRWLock);
ae = ge->AtomOfGE;
if (GlobalVariables == ge) {
GlobalVariables = ge->NextGE;
} else {
g = GlobalVariables;
while (g->NextGE != ge)
g = g->NextGE;
g->NextGE = ge->NextGE;
}
gp = AbsGlobalProp(ge);
WRITE_LOCK(ae->ARWLock);
if (ae->PropsOfAE == gp) {
ae->PropsOfAE = ge->NextOfPE;
} else {
g0 = ae->PropsOfAE;
while (g0->NextOfPE != gp)
g0 = g0->NextOfPE;
g0->NextOfPE = ge->NextOfPE;
}
WRITE_UNLOCK(ae->ARWLock);
WRITE_UNLOCK(ge->GRWLock);
Yap_FreeCodeSpace((char *)ge);
return TRUE;
}
/* a non-backtrackable queue is a term of the form $array(Arena,Start,End,Size) plus an Arena. */
static Int
p_nb_queue(void)
{
Term queue_arena, queue, ar[5], *nar;
#if COROUTINING
Term delay_queue_arena;
#endif
Term t = Deref(ARG1);
UInt arena_sz = (H-H0)/16;
if (!IsVarTerm(t)) {
if (!IsApplTerm(t)) {
return FALSE;
}
return (FunctorOfTerm(t) == FunctorNBQueue);
}
ar[QUEUE_ARENA] =
ar[QUEUE_DELAY_ARENA] =
ar[QUEUE_HEAD] =
ar[QUEUE_TAIL] =
ar[QUEUE_SIZE] =
MkIntTerm(0);
queue = Yap_MkApplTerm(FunctorNBQueue,5,ar);
if (!Yap_unify(queue,ARG1))
return FALSE;
#if COROUTINING
arena_sz = ((attvar_record *)H0- DelayTop())/16;
if (arena_sz <2)
arena_sz = 2;
if (arena_sz > 256)
arena_sz = 256;
delay_queue_arena = NewDelayArena(arena_sz);
if (delay_queue_arena == 0L) {
return FALSE;
}
nar = RepAppl(Deref(ARG1))+1;
nar[QUEUE_DELAY_ARENA] = delay_queue_arena;
#endif
if (arena_sz < 4*1024)
arena_sz = 4*1024;
queue_arena = NewArena(arena_sz,1,NULL);
if (queue_arena == 0L) {
return FALSE;
}
nar = RepAppl(Deref(ARG1))+1;
nar[QUEUE_ARENA] = queue_arena;
return TRUE;
}
static CELL *
GetQueue(Term t, char* caller)
{
t = Deref(t);
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,caller);
return NULL;
}
if (!IsApplTerm(t)) {
Yap_Error(TYPE_ERROR_COMPOUND,t,caller);
return NULL;
}
if (FunctorOfTerm(t) != FunctorNBQueue) {
Yap_Error(DOMAIN_ERROR_ARRAY_TYPE,t,caller);
return NULL;
}
return RepAppl(t)+1;
}
static Term
GetQueueArena(CELL *qd, char* caller)
{
Term t = Deref(qd[QUEUE_ARENA]);
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,caller);
return 0L;
}
if (!IsApplTerm(t)) {
Yap_Error(TYPE_ERROR_COMPOUND,t,caller);
return 0L;
}
if (FunctorOfTerm(t) != FunctorBigInt) {
Yap_Error(DOMAIN_ERROR_ARRAY_TYPE,t,caller);
return 0L;
}
return t;
}
#if COROUTINING
static void
RecoverDelayArena(Term delay_arena)
{
attvar_record *pt = DelayArenaPt(delay_arena),
*max = DelayTop();
if (max == pt-DelayArenaSz(delay_arena))
SetDelayTop(pt);
}
#endif
static void
RecoverArena(Term arena)
{
CELL *pt = ArenaPt(arena),
*max = ArenaLimit(arena);
if (max == H)
H = pt;
}
static Int
p_nb_queue_close(void)
{
Term t = Deref(ARG1);
Int out;
if (!IsVarTerm(t)) {
CELL *qp;
qp = GetQueue(t, "queue/3");
if (qp == NULL) {
return
Yap_unify(ARG3, ARG2);
}
if (qp[QUEUE_ARENA] != MkIntTerm(0))
RecoverArena(qp[QUEUE_ARENA]);
#if COROUTINING
if (qp[QUEUE_DELAY_ARENA] != MkIntTerm(0))
RecoverDelayArena(qp[QUEUE_DELAY_ARENA]);
#endif
if (qp[QUEUE_SIZE] == MkIntTerm(0)) {
return
Yap_unify(ARG3, ARG2);
}
out =
Yap_unify(ARG3, qp[QUEUE_TAIL]) &&
Yap_unify(ARG2, qp[QUEUE_HEAD]);
qp[-1] = (CELL)Yap_MkFunctor(Yap_LookupAtom("heap"),1);
qp[0] = MkIntegerTerm(0);
return out;
}
Yap_Error(INSTANTIATION_ERROR,t,"queue/3");
return FALSE;
}
static Int
p_nb_queue_enqueue(void)
{
CELL *qd = GetQueue(ARG1,"enqueue"), *oldH, *oldHB;
UInt old_sz;
Term arena, qsize, to;
UInt min_size;
if (!qd)
return FALSE;
arena = GetQueueArena(qd,"enqueue");
if (arena == 0L)
return FALSE;
if (IsPairTerm(qd[QUEUE_HEAD])) {
min_size = ArenaPt(arena)-RepPair(qd[QUEUE_HEAD]);
} else {
min_size = 0L;
}
to = CopyTermToArena(ARG2, arena, 2, qd+QUEUE_ARENA, qd+QUEUE_DELAY_ARENA, min_size);
if (to == 0L)
return FALSE;
qd = GetQueue(ARG1,"enqueue");
arena = GetQueueArena(qd,"enqueue");
/* garbage collection ? */
oldH = H;
oldHB = HB;
H = HB = ArenaPt(arena);
old_sz = ArenaSz(arena);
qsize = IntegerOfTerm(qd[QUEUE_SIZE]);
while (old_sz < 128) {
UInt gsiz = H-RepPair(qd[QUEUE_HEAD]);
H = oldH;
HB = oldHB;
if (gsiz > 1024*1024) {
gsiz = 1024*1024;
} else if (gsiz < 1024) {
gsiz = 1024;
}
ARG3 = to;
fprintf(stderr,"growing %ld cells\n",(unsigned long int)gsiz);
if (!GrowArena(arena, ArenaLimit(arena), old_sz, gsiz, 3)) {
Yap_Error(OUT_OF_STACK_ERROR, arena, Yap_ErrorMessage);
return 0L;
}
to = ARG3;
qd = RepAppl(Deref(ARG1))+1;
arena = GetQueueArena(qd,"enqueue");
oldH = H;
oldHB = HB;
H = HB = ArenaPt(arena);
old_sz = ArenaSz(arena);
}
qd[QUEUE_SIZE] = Global_MkIntegerTerm(qsize+1);
if (qsize == 0) {
qd[QUEUE_HEAD] = AbsPair(H);
} else {
*VarOfTerm(qd[QUEUE_TAIL]) = AbsPair(H);
}
*H++ = to;
RESET_VARIABLE(H);
qd[QUEUE_TAIL] = (CELL)H;
H++;
CloseArena(oldH, oldHB, ASP, qd+QUEUE_ARENA, old_sz);
return TRUE;
}
static Int
p_nb_queue_dequeue(void)
{
CELL *qd = GetQueue(ARG1,"dequeue");
UInt old_sz, qsz;
Term arena, out;
CELL *oldH, *oldHB;
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[QUEUE_SIZE]);
if (qsz == 0)
return FALSE;
arena = GetQueueArena(qd,"dequeue");
if (arena == 0L)
return FALSE;
old_sz = ArenaSz(arena);
out = HeadOfTerm(qd[QUEUE_HEAD]);
qd[QUEUE_HEAD] = TailOfTerm(qd[QUEUE_HEAD]);
/* garbage collection ? */
oldH = H;
oldHB = HB;
qd[QUEUE_SIZE] = Global_MkIntegerTerm(qsz-1);
CloseArena(oldH, oldHB, ASP, &arena, old_sz);
return Yap_unify(out, ARG2);
}
static Int
p_nb_queue_peek(void)
{
CELL *qd = GetQueue(ARG1,"queue_peek");
UInt qsz;
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[QUEUE_SIZE]);
if (qsz == 0)
return FALSE;
return Yap_unify(HeadOfTerm(qd[QUEUE_HEAD]), ARG2);
}
static Int
p_nb_queue_empty(void)
{
CELL *qd = GetQueue(ARG1,"queue_empty");
if (!qd)
return FALSE;
return (IntegerOfTerm(qd[QUEUE_SIZE]) == 0);
}
static Int
p_nb_queue_size(void)
{
CELL *qd = GetQueue(ARG1,"queue_size");
if (!qd)
return FALSE;
return Yap_unify(ARG2,qd[QUEUE_SIZE]);
}
static CELL *
GetHeap(Term t, char* caller)
{
t = Deref(t);
if (IsVarTerm(t)) {
Yap_Error(INSTANTIATION_ERROR,t,caller);
return NULL;
}
if (!IsApplTerm(t)) {
Yap_Error(TYPE_ERROR_COMPOUND,t,caller);
return NULL;
}
return RepAppl(t)+1;
}
static Term
MkZeroApplTerm(Functor f, UInt sz)
{
Term t0, tf;
CELL *pt;
if (H+(sz+1) > ASP-1024)
return TermNil;
tf = AbsAppl(H);
*H = (CELL)f;
t0 = MkIntTerm(0);
pt = H+1;
while (sz--) {
*pt++ = t0;
}
H = pt;
return tf;
}
static Int
p_nb_heap(void)
{
Term heap_arena, heap, *ar, *nar;
#if COROUTINING
Term delay_heap_arena;
#endif
UInt hsize;
Term tsize = Deref(ARG1);
UInt arena_sz = (H-H0)/16;
if (IsVarTerm(tsize)) {
Yap_Error(INSTANTIATION_ERROR,tsize,"nb_heap");
return FALSE;
} else {
if (!IsIntegerTerm(tsize)) {
Yap_Error(TYPE_ERROR_INTEGER,tsize,"nb_heap");
return FALSE;
}
hsize = IntegerOfTerm(tsize);
}
while ((heap = MkZeroApplTerm(Yap_MkFunctor(Yap_LookupAtom("heap"),2*hsize+HEAP_START+1),2*hsize+HEAP_START+1)) == TermNil) {
if (!Yap_gcl((2*hsize+HEAP_START+1)*sizeof(CELL), 2, ENV, P)) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return FALSE;
}
}
if (!Yap_unify(heap,ARG2))
return FALSE;
ar = RepAppl(heap)+1;
ar[HEAP_ARENA] =
ar[HEAP_DELAY_ARENA] =
ar[HEAP_SIZE] =
MkIntTerm(0);
ar[HEAP_MAX] = tsize;
if (arena_sz < 1024)
arena_sz = 1024;
heap_arena = NewArena(arena_sz,1,NULL);
if (heap_arena == 0L) {
return FALSE;
}
nar = RepAppl(Deref(ARG2))+1;
nar[HEAP_ARENA] = heap_arena;
#if COROUTINING
arena_sz = ((attvar_record *)H0- DelayTop())/16;
if (arena_sz <2)
arena_sz = 2;
if (arena_sz > 256)
arena_sz = 256;
delay_heap_arena = NewDelayArena(arena_sz);
if (delay_heap_arena == 0L) {
return FALSE;
}
nar = RepAppl(Deref(ARG2))+1;
nar[HEAP_DELAY_ARENA] = delay_heap_arena;
#endif
return TRUE;
}
static Int
p_nb_heap_close(void)
{
Term t = Deref(ARG1);
if (!IsVarTerm(t)) {
CELL *qp;
qp = RepAppl(t)+1;
if (qp[HEAP_ARENA] != MkIntTerm(0))
RecoverArena(qp[HEAP_ARENA]);
#if COROUTINING
if (qp[HEAP_DELAY_ARENA] != MkIntTerm(0))
RecoverDelayArena(qp[HEAP_DELAY_ARENA]);
#endif
qp[-1] = (CELL)Yap_MkFunctor(Yap_LookupAtom("heap"),1);
qp[0] = MkIntegerTerm(0);
return TRUE;
}
Yap_Error(INSTANTIATION_ERROR,t,"heap_close/1");
return FALSE;
}
static void
PushHeap(CELL *pt, UInt off)
{
while (off) {
UInt noff = (off+1)/2-1;
if (Yap_compare_terms(pt[2*off], pt[2*noff]) < 0) {
Term tk = pt[2*noff];
Term tv = pt[2*noff+1];
pt[2*noff] = pt[2*off];
pt[2*noff+1] = pt[2*off+1];
pt[2*off] = tk;
pt[2*off+1] = tv;
off = noff;
} else {
return;
}
}
}
static void
DelHeapRoot(CELL *pt, UInt sz)
{
UInt indx = 0;
Term tk, tv;
sz--;
tk = pt[2*sz];
tv = pt[2*sz+1];
while (TRUE) {
if (sz < 2*indx+3 || Yap_compare_terms(pt[4*indx+2],pt[4*indx+4]) < 0) {
if (sz < 2*indx+2 || Yap_compare_terms(tk, pt[4*indx+2]) < 0) {
pt[2*indx] = tk;
pt[2*indx+1] = tv;
return;
} else {
pt[2*indx] = pt[4*indx+2];
pt[2*indx+1] = pt[4*indx+3];
indx = 2*indx+1;
}
} else {
if (Yap_compare_terms(tk, pt[4*indx+4]) < 0) {
pt[2*indx] = tk;
pt[2*indx+1] = tv;
return;
} else {
pt[2*indx] = pt[4*indx+4];
pt[2*indx+1] = pt[4*indx+5];
indx = 2*indx+2;
}
}
}
}
static Int
p_nb_heap_add_to_heap(void)
{
CELL *qd = GetHeap(ARG1,"add_to_heap"), *oldH, *oldHB, *pt;
UInt hsize, hmsize, old_sz;
Term arena, to, key;
if (!qd)
return FALSE;
restart:
hsize = IntegerOfTerm(qd[HEAP_SIZE]);
hmsize = IntegerOfTerm(qd[HEAP_MAX]);
if (hsize == hmsize) {
CELL *top = qd+(HEAP_START+2*hmsize);
UInt extra_size;
if (hmsize >= 64*1024) {
extra_size = 64*1024;
} else {
extra_size = hmsize;
}
if ((extra_size=Yap_InsertInGlobal(top, extra_size*2*sizeof(CELL)))==0) {
Yap_Error(OUT_OF_STACK_ERROR,TermNil,"No Stack Space for Non-Backtrackable terms");
return FALSE;
}
extra_size = extra_size/(2*sizeof(CELL));
qd = GetHeap(ARG1,"add_to_heap");
hmsize += extra_size;
if (!qd)
return FALSE;
qd[-1] = (CELL)Yap_MkFunctor(Yap_LookupAtom("heap"),2*hmsize+HEAP_START)+1;
top = qd+(HEAP_START+2*(hmsize-extra_size));
while (extra_size) {
RESET_VARIABLE(top);
RESET_VARIABLE(top+1);
top+=2;
extra_size--;
}
arena = qd[HEAP_ARENA];
old_sz = ArenaSz(arena);
oldH = H;
oldHB = HB;
H = HB = ArenaPt(arena);
qd[HEAP_MAX] = Global_MkIntegerTerm(hmsize);
CloseArena(oldH, oldHB, ASP, qd+HEAP_ARENA, old_sz);
goto restart;
}
arena = qd[HEAP_ARENA];
if (arena == 0L)
return FALSE;
key = CopyTermToArena(ARG2, arena, 3, qd+HEAP_ARENA, qd+HEAP_DELAY_ARENA, 0);
arena = qd[HEAP_ARENA];
to = CopyTermToArena(ARG3, arena, 3, qd+HEAP_ARENA, qd+HEAP_DELAY_ARENA, 0);
if (key == 0 || to == 0L)
return FALSE;
qd = GetHeap(ARG1,"add_to_heap");
arena = qd[HEAP_ARENA];
/* garbage collection ? */
oldH = H;
oldHB = HB;
H = HB = ArenaPt(arena);
old_sz = ArenaSz(arena);
while (old_sz < 128) {
UInt gsiz = hsize*2;
H = oldH;
HB = oldHB;
if (gsiz > 1024*1024) {
gsiz = 1024*1024;
} else if (gsiz < 1024) {
gsiz = 1024;
}
ARG3 = to;
if (!GrowArena(arena, ArenaLimit(arena), old_sz, gsiz, 3)) {
Yap_Error(OUT_OF_STACK_ERROR, arena, Yap_ErrorMessage);
return 0L;
}
to = ARG3;
qd = RepAppl(Deref(ARG1))+1;
arena = qd[HEAP_ARENA];
oldH = H;
oldHB = HB;
H = HB = ArenaPt(arena);
old_sz = ArenaSz(arena);
}
pt = qd+HEAP_START;
pt[2*hsize] = key;
pt[2*hsize+1] = to;
PushHeap(pt, hsize);
qd[HEAP_SIZE] = Global_MkIntegerTerm(hsize+1);
CloseArena(oldH, oldHB, ASP, qd+HEAP_ARENA, old_sz);
return TRUE;
}
static Int
p_nb_heap_del(void)
{
CELL *qd = GetHeap(ARG1,"deheap");
UInt old_sz, qsz;
Term arena;
CELL *oldH, *oldHB;
Term tk, tv;
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[HEAP_SIZE]);
if (qsz == 0)
return FALSE;
arena = qd[HEAP_ARENA];
if (arena == 0L)
return FALSE;
old_sz = ArenaSz(arena);
/* garbage collection ? */
oldH = H;
oldHB = HB;
qd[HEAP_SIZE] = Global_MkIntegerTerm(qsz-1);
CloseArena(oldH, oldHB, ASP, &arena, old_sz);
tk = qd[HEAP_START];
tv = qd[HEAP_START+1];
DelHeapRoot(qd+HEAP_START, qsz);
return Yap_unify(tk, ARG2) &&
Yap_unify(tv, ARG3);
}
static Int
p_nb_heap_peek(void)
{
CELL *qd = GetHeap(ARG1,"heap_peek");
UInt qsz;
Term tk, tv;
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[HEAP_SIZE]);
if (qsz == 0)
return FALSE;
tk = qd[HEAP_START];
tv = qd[HEAP_START+1];
return Yap_unify(tk, ARG2) &&
Yap_unify(tv, ARG3);
}
static Int
p_nb_heap_empty(void)
{
CELL *qd = GetHeap(ARG1,"heap_empty");
if (!qd)
return FALSE;
return (IntegerOfTerm(qd[HEAP_SIZE]) == 0);
}
static Int
p_nb_heap_size(void)
{
CELL *qd = GetHeap(ARG1,"heap_size");
if (!qd)
return FALSE;
return Yap_unify(ARG2,qd[HEAP_SIZE]);
}
static Int
p_nb_beam(void)
{
Term beam_arena, beam, *ar, *nar;
#if COROUTINING
Term delay_beam_arena;
#endif
UInt hsize;
Term tsize = Deref(ARG1);
UInt arena_sz = (H-H0)/16;
if (IsVarTerm(tsize)) {
Yap_Error(INSTANTIATION_ERROR,tsize,"nb_beam");
return FALSE;
} else {
if (!IsIntegerTerm(tsize)) {
Yap_Error(TYPE_ERROR_INTEGER,tsize,"nb_beam");
return FALSE;
}
hsize = IntegerOfTerm(tsize);
}
while ((beam = MkZeroApplTerm(Yap_MkFunctor(Yap_LookupAtom("heap"),5*hsize+HEAP_START+1),5*hsize+HEAP_START+1)) == TermNil) {
if (!Yap_gcl((5*hsize+HEAP_START+1)*sizeof(CELL), 2, ENV, P)) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return FALSE;
}
}
if (!Yap_unify(beam,ARG2))
return FALSE;
ar = RepAppl(beam)+1;
ar[HEAP_ARENA] =
ar[HEAP_DELAY_ARENA] =
ar[HEAP_SIZE] =
MkIntTerm(0);
ar[HEAP_MAX] = tsize;
if (arena_sz < 1024)
arena_sz = 1024;
beam_arena = NewArena(arena_sz,1,NULL);
if (beam_arena == 0L) {
return FALSE;
}
nar = RepAppl(Deref(ARG2))+1;
nar[HEAP_ARENA] = beam_arena;
#if COROUTINING
arena_sz = ((attvar_record *)H0- DelayTop())/16;
if (arena_sz <2)
arena_sz = 2;
if (arena_sz > 256)
arena_sz = 256;
delay_beam_arena = NewDelayArena(arena_sz);
if (delay_beam_arena == 0L) {
return FALSE;
}
nar = RepAppl(Deref(ARG2))+1;
nar[HEAP_DELAY_ARENA] = delay_beam_arena;
#endif
return TRUE;
}
static Int
p_nb_beam_close(void)
{
return p_nb_beam_close();
}
/* we have two queues, one with
Key, IndxQueue2
the other with
Key, IndxQueue1, Val
*/
static void
PushBeam(CELL *pt, CELL *npt, UInt hsize, Term key, Term to)
{
UInt off = hsize, off2 = hsize;
Term toff, toff2;
/* push into first queue */
while (off) {
UInt noff = (off+1)/2-1;
if (Yap_compare_terms(key, pt[2*noff]) < 0) {
UInt i2 = IntegerOfTerm(pt[2*noff+1]);
pt[2*off] = pt[2*noff];
pt[2*off+1] = pt[2*noff+1];
npt[3*i2+1] = Global_MkIntegerTerm(off);
off = noff;
} else {
break;
}
}
toff = Global_MkIntegerTerm(off);
/* off says where we are in first queue */
/* push into second queue */
while (off2) {
UInt noff = (off2+1)/2-1;
if (Yap_compare_terms(key, npt[3*noff]) > 0) {
UInt i1 = IntegerOfTerm(npt[3*noff+1]);
npt[3*off2] = npt[3*noff];
npt[3*off2+1] = npt[3*noff+1];
npt[3*off2+2] = npt[3*noff+2];
pt[2*i1+1] = Global_MkIntegerTerm(off2);
off2 = noff;
} else {
break;
}
}
toff2 = Global_MkIntegerTerm(off2);
/* store elements in their rightful place */
npt[3*off2] = pt[2*off] = key;
pt[2*off+1] = toff2;
npt[3*off2+1] = toff;
npt[3*off2+2] = to;
}
static void
DelBeamMax(CELL *pt, CELL *pt2, UInt sz)
{
UInt off = IntegerOfTerm(pt2[1]);
UInt indx = 0;
Term tk, ti, tv;
sz--;
/* first, fix the reverse queue */
tk = pt2[3*sz];
ti = pt2[3*sz+1];
tv = pt2[3*sz+2];
while (TRUE) {
if (sz < 2*indx+3 || Yap_compare_terms(pt2[6*indx+3],pt2[6*indx+6]) > 0) {
if (sz < 2*indx+2 || Yap_compare_terms(tk, pt2[6*indx+3]) > 0) {
break;
} else {
UInt off = IntegerOfTerm(pt2[6*indx+4]);
pt2[3*indx] = pt2[6*indx+3];
pt2[3*indx+1] = pt2[6*indx+4];
pt2[3*indx+2] = pt2[6*indx+5];
pt[2*off+1] = Global_MkIntegerTerm(indx);
indx = 2*indx+1;
}
} else {
if (Yap_compare_terms(tk, pt2[6*indx+6]) > 0) {
break;
} else {
UInt off = IntegerOfTerm(pt2[6*indx+7]);
pt2[3*indx] = pt2[6*indx+6];
pt2[3*indx+1] = pt2[6*indx+7];
pt2[3*indx+2] = pt2[6*indx+8];
pt[2*off+1] = Global_MkIntegerTerm(indx);
indx = 2*indx+2;
}
}
}
pt[2*IntegerOfTerm(ti)+1] = Global_MkIntegerTerm(indx);
pt2[3*indx] = tk;
pt2[3*indx+1] = ti;
pt2[3*indx+2] = tv;
/* now, fix the standard queue */
if (off != sz) {
Term toff, toff2, key;
UInt off2;
key = pt[2*sz];
toff2 = pt[2*sz+1];
off2 = IntegerOfTerm(toff2);
/* off says where we are in first queue */
/* push into second queue */
while (off) {
UInt noff = (off+1)/2-1;
if (Yap_compare_terms(key, pt[2*noff]) < 0) {
UInt i1 = IntegerOfTerm(pt[2*noff+1]);
pt[2*off] = pt[2*noff];
pt[2*off+1] = pt[2*noff+1];
pt2[3*i1+1] = Global_MkIntegerTerm(off);
off = noff;
} else {
break;
}
}
toff = Global_MkIntegerTerm(off);
/* store elements in their rightful place */
pt[2*off] = key;
pt2[3*off2+1] = toff;
pt[2*off+1] = toff2;
}
}
static Term
DelBeamMin(CELL *pt, CELL *pt2, UInt sz)
{
UInt off2 = IntegerOfTerm(pt[1]);
Term ov = pt2[3*off2+2]; /* return value */
UInt indx = 0;
Term tk, tv;
sz--;
/* first, fix the standard queue */
tk = pt[2*sz];
tv = pt[2*sz+1];
while (TRUE) {
if (sz < 2*indx+3 || Yap_compare_terms(pt[4*indx+2],pt[4*indx+4]) < 0) {
if (sz < 2*indx+2 || Yap_compare_terms(tk, pt[4*indx+2]) < 0) {
break;
} else {
UInt off2 = IntegerOfTerm(pt[4*indx+3]);
pt[2*indx] = pt[4*indx+2];
pt[2*indx+1] = pt[4*indx+3];
pt2[3*off2+1] = Global_MkIntegerTerm(indx);
indx = 2*indx+1;
}
} else {
if (Yap_compare_terms(tk, pt[4*indx+4]) < 0) {
break;
} else {
UInt off2 = IntegerOfTerm(pt[4*indx+5]);
pt[2*indx] = pt[4*indx+4];
pt[2*indx+1] = pt[4*indx+5];
pt2[3*off2+1] = Global_MkIntegerTerm(indx);
indx = 2*indx+2;
}
}
}
pt[2*indx] = tk;
pt[2*indx+1] = tv;
pt2[3*IntegerOfTerm(tv)+1] = Global_MkIntegerTerm(indx);
/* now, fix the reverse queue */
if (off2 != sz) {
Term to, toff, toff2, key;
UInt off;
key = pt2[3*sz];
toff = pt2[3*sz+1];
to = pt2[3*sz+2];
off = IntegerOfTerm(toff);
/* off says where we are in first queue */
/* push into second queue */
while (off2) {
UInt noff = (off2+1)/2-1;
if (Yap_compare_terms(key, pt2[3*noff]) > 0) {
UInt i1 = IntegerOfTerm(pt2[3*noff+1]);
pt2[3*off2] = pt2[3*noff];
pt2[3*off2+1] = pt2[3*noff+1];
pt2[3*off2+2] = pt2[3*noff+2];
pt[2*i1+1] = Global_MkIntegerTerm(off2);
off2 = noff;
} else {
break;
}
}
toff2 = Global_MkIntegerTerm(off2);
/* store elements in their rightful place */
pt2[3*off2] = key;
pt[2*off+1] = toff2;
pt2[3*off2+1] = toff;
pt2[3*off2+2] = to;
}
return ov;
}
static Int
p_nb_beam_add_to_beam(void)
{
CELL *qd = GetHeap(ARG1,"add_to_beam"), *oldH, *oldHB, *pt;
UInt hsize, hmsize, old_sz;
Term arena, to, key;
if (!qd)
return FALSE;
hsize = IntegerOfTerm(qd[HEAP_SIZE]);
hmsize = IntegerOfTerm(qd[HEAP_MAX]);
key = Deref(ARG2);
if (hsize == hmsize) {
pt = qd+HEAP_START;
if (Yap_compare_terms(pt[2*hmsize],Deref(ARG2)) > 0) {
/* smaller than current max, we need to drop current max */
DelBeamMax(pt, pt+2*hmsize, hmsize);
hsize--;
} else {
return TRUE;
}
}
arena = qd[HEAP_ARENA];
if (arena == 0L)
return FALSE;
key = CopyTermToArena(ARG2, qd[HEAP_ARENA], 3, qd+HEAP_ARENA, qd+HEAP_DELAY_ARENA, 0);
arena = qd[HEAP_ARENA];
to = CopyTermToArena(ARG3, arena, 3, qd+HEAP_ARENA, qd+HEAP_DELAY_ARENA, 0);
if (key == 0 || to == 0L)
return FALSE;
qd = GetHeap(ARG1,"add_to_beam");
arena = qd[HEAP_ARENA];
/* garbage collection ? */
oldH = H;
oldHB = HB;
H = HB = ArenaPt(arena);
old_sz = ArenaSz(arena);
while (old_sz < 128) {
UInt gsiz = hsize*2;
H = oldH;
HB = oldHB;
if (gsiz > 1024*1024) {
gsiz = 1024*1024;
} else if (gsiz < 1024) {
gsiz = 1024;
}
ARG3 = to;
if (!GrowArena(arena, ArenaLimit(arena), old_sz, gsiz, 3)) {
Yap_Error(OUT_OF_STACK_ERROR, arena, Yap_ErrorMessage);
return 0L;
}
to = ARG3;
qd = RepAppl(Deref(ARG1))+1;
arena = qd[HEAP_ARENA];
oldH = H;
oldHB = HB;
H = HB = ArenaPt(arena);
old_sz = ArenaSz(arena);
}
pt = qd+HEAP_START;
PushBeam(pt, pt+2*hmsize, hsize, key, to);
qd[HEAP_SIZE] = Global_MkIntegerTerm(hsize+1);
CloseArena(oldH, oldHB, ASP, qd+HEAP_ARENA, old_sz);
return TRUE;
}
static Int
p_nb_beam_del(void)
{
CELL *qd = GetHeap(ARG1,"debeam");
UInt old_sz, qsz;
Term arena;
CELL *oldH, *oldHB;
Term tk, tv;
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[HEAP_SIZE]);
if (qsz == 0)
return FALSE;
arena = qd[HEAP_ARENA];
if (arena == 0L)
return FALSE;
old_sz = ArenaSz(arena);
/* garbage collection ? */
oldH = H;
oldHB = HB;
qd[HEAP_SIZE] = Global_MkIntegerTerm(qsz-1);
CloseArena(oldH, oldHB, ASP, &arena, old_sz);
tk = qd[HEAP_START];
tv = DelBeamMin(qd+HEAP_START, qd+(HEAP_START+2*IntegerOfTerm(qd[HEAP_MAX])), qsz);
return Yap_unify(tk, ARG2) &&
Yap_unify(tv, ARG3);
}
#ifdef DEBUG
static Int
p_nb_beam_check(void)
{
CELL *qd = GetHeap(ARG1,"debeam");
UInt qsz, qmax;
CELL *pt, *pt2;
UInt i;
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[HEAP_SIZE]);
qmax = IntegerOfTerm(qd[HEAP_MAX]);
if (qsz == 0)
return TRUE;
pt = qd+HEAP_START;
pt2 = pt+2*qmax;
for (i = 1; i < qsz; i++) {
UInt back;
if (Yap_compare_terms(pt[2*((i+1)/2-1)],pt[2*i]) > 0) {
Yap_DebugPlWrite(pt[2*((i+1)/2-1)]); fprintf(stderr,"\n");
Yap_DebugPlWrite(pt[2*i]); fprintf(stderr,"\n");
fprintf(stderr,"Error at %ld\n",(unsigned long int)i);
return FALSE;
}
back = IntegerOfTerm(pt[2*i+1]);
if (IntegerOfTerm(pt2[3*back+1]) != i) {
fprintf(stderr,"Link error at %ld\n",(unsigned long int)i);
return FALSE;
}
}
for (i = 1; i < qsz; i++) {
if (Yap_compare_terms(pt2[3*((i+1)/2-1)],pt2[3*i]) < 0) {
fprintf(stderr,"Error at sec %ld\n",(unsigned long int)i);
Yap_DebugPlWrite(pt2[3*((i+1)/2-1)]); fprintf(stderr,"\n");
Yap_DebugPlWrite(pt2[3*i]); fprintf(stderr,"\n");
return FALSE;
}
}
return TRUE;
}
#endif
static Int
p_nb_beam_keys(void)
{
CELL *qd;
UInt qsz;
CELL *pt, *ho;
UInt i;
restart:
qd = GetHeap(ARG1,"beam_keys");
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[HEAP_SIZE]);
ho = H;
pt = qd+HEAP_START;
if (qsz == 0)
return Yap_unify(ARG2, TermNil);
for (i=0; i < qsz; i++) {
if (H > ASP-1024) {
H = ho;
if (!Yap_gcl(((ASP-H)-1024)*sizeof(CELL), 2, ENV, P)) {
Yap_Error(OUT_OF_STACK_ERROR, TermNil, Yap_ErrorMessage);
return TermNil;
}
goto restart;
}
*H++ = pt[0];
*H = AbsPair(H+1);
H++;
pt += 2;
}
H[-1] = TermNil;
return Yap_unify(ARG2, AbsPair(ho));
}
static Int
p_nb_beam_peek(void)
{
CELL *qd = GetHeap(ARG1,"beam_peek"), *pt, *pt2;
UInt qsz, qbsize;
Term tk, tv;
if (!qd)
return FALSE;
qsz = IntegerOfTerm(qd[HEAP_SIZE]);
qbsize = IntegerOfTerm(qd[HEAP_MAX]);
if (qsz == 0)
return FALSE;
pt = qd+HEAP_START;
pt2 = pt+2*qbsize;
tk = pt[0];
tv = pt2[2];
return Yap_unify(tk, ARG2) &&
Yap_unify(tv, ARG3);
}
static Int
p_nb_beam_empty(void)
{
CELL *qd = GetHeap(ARG1,"beam_empty");
if (!qd)
return FALSE;
return (IntegerOfTerm(qd[HEAP_SIZE]) == 0);
}
static Int
p_nb_beam_size(void)
{
CELL *qd = GetHeap(ARG1,"beam_size");
if (!qd)
return FALSE;
return Yap_unify(ARG2,qd[HEAP_SIZE]);
}
static Int
cont_current_nb(void)
{
Int unif;
GlobalEntry *ge = (GlobalEntry *)IntegerOfTerm(EXTRA_CBACK_ARG(1,1));
unif = Yap_unify(MkAtomTerm(AbsAtom(ge->AtomOfGE)), ARG1);
ge = ge->NextGE;
if (!ge) {
if (unif)
cut_succeed();
else
cut_fail();
} else {
EXTRA_CBACK_ARG(1,1) = MkIntegerTerm((Int)ge);
return unif;
}
}
static Int
init_current_nb(void)
{ /* current_atom(?Atom) */
Term t1 = Deref(ARG1);
if (!IsVarTerm(t1)) {
if (IsAtomTerm(t1))
cut_succeed();
else
cut_fail();
}
READ_LOCK(HashChain[0].AERWLock);
EXTRA_CBACK_ARG(1,1) = MkIntegerTerm((Int)GlobalVariables);
return cont_current_nb();
}
void Yap_InitGlobals(void)
{
Term cm = CurrentModule;
Yap_InitCPred("$allocate_arena", 2, p_allocate_arena, 0);
Yap_InitCPred("$allocate_default_arena", 2, p_allocate_default_arena, 0);
Yap_InitCPred("arena_size", 1, p_default_arena_size, 0);
Yap_InitCPred("b_setval", 2, p_b_setval, SafePredFlag);
Yap_InitCPred("b_getval", 2, p_nb_getval, SafePredFlag);
Yap_InitCPred("nb_setval", 2, p_nb_setval, 0L);
Yap_InitCPred("nb_getval", 2, p_nb_getval, SafePredFlag);
Yap_InitCPred("nb_delete", 1, p_nb_delete, 0L);
Yap_InitCPredBack("$nb_current", 1, 1, init_current_nb, cont_current_nb, SafePredFlag);
CurrentModule = GLOBALS_MODULE;
Yap_InitCPred("nb_queue", 1, p_nb_queue, 0L);
Yap_InitCPred("nb_queue_close", 3, p_nb_queue_close, SafePredFlag);
Yap_InitCPred("nb_queue_enqueue", 2, p_nb_queue_enqueue, 0L);
Yap_InitCPred("nb_queue_dequeue", 2, p_nb_queue_dequeue, SafePredFlag);
Yap_InitCPred("nb_queue_peek", 2, p_nb_queue_peek, SafePredFlag);
Yap_InitCPred("nb_queue_empty", 1, p_nb_queue_empty, SafePredFlag);
Yap_InitCPred("nb_queue_size", 2, p_nb_queue_size, SafePredFlag);
Yap_InitCPred("nb_heap", 2, p_nb_heap, 0L);
Yap_InitCPred("nb_heap_close", 1, p_nb_heap_close, SafePredFlag);
Yap_InitCPred("nb_heap_add", 3, p_nb_heap_add_to_heap, 0L);
Yap_InitCPred("nb_heap_del", 3, p_nb_heap_del, SafePredFlag);
Yap_InitCPred("nb_heap_peek", 3, p_nb_heap_peek, SafePredFlag);
Yap_InitCPred("nb_heap_empty", 1, p_nb_heap_empty, SafePredFlag);
Yap_InitCPred("nb_heap_size", 2, p_nb_heap_size, SafePredFlag);
Yap_InitCPred("nb_beam", 2, p_nb_beam, 0L);
Yap_InitCPred("nb_beam_close", 1, p_nb_beam_close, SafePredFlag);
Yap_InitCPred("nb_beam_add", 3, p_nb_beam_add_to_beam, 0L);
Yap_InitCPred("nb_beam_del", 3, p_nb_beam_del, SafePredFlag);
Yap_InitCPred("nb_beam_peek", 3, p_nb_beam_peek, SafePredFlag);
Yap_InitCPred("nb_beam_empty", 1, p_nb_beam_empty, SafePredFlag);
Yap_InitCPred("nb_beam_keys", 2, p_nb_beam_keys, 0L);
#ifdef DEBUG
Yap_InitCPred("nb_beam_check", 1, p_nb_beam_check, SafePredFlag);
#endif
Yap_InitCPred("nb_beam_size", 2, p_nb_beam_size, SafePredFlag);
CurrentModule = cm;
}