564 lines
12 KiB
C
564 lines
12 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: arith1.c *
|
|
* Last rev: *
|
|
* mods: *
|
|
* comments: bignum support through gmp *
|
|
* *
|
|
*************************************************************************/
|
|
#ifdef SCCS
|
|
static char SccsId[] = "%W% %G%";
|
|
#endif
|
|
|
|
#include "Yap.h"
|
|
#include "Yatom.h"
|
|
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#include "YapHeap.h"
|
|
|
|
#ifdef USE_GMP
|
|
|
|
#include "eval.h"
|
|
#include "alloc.h"
|
|
|
|
Term
|
|
Yap_MkBigIntTerm(MP_INT *big)
|
|
{
|
|
CACHE_REGS
|
|
Int nlimbs;
|
|
MP_INT *dst = (MP_INT *)(H+2);
|
|
CELL *ret = H;
|
|
Int bytes;
|
|
|
|
if (mpz_fits_slong_p(big)) {
|
|
long int out = mpz_get_si(big);
|
|
return MkIntegerTerm((Int)out);
|
|
}
|
|
// bytes = big->_mp_alloc * sizeof(mp_limb_t);
|
|
// nlimbs = ALIGN_YAPTYPE(bytes,CELL)/CellSize;
|
|
// this works, but it shouldn't need to do this...
|
|
nlimbs = big->_mp_alloc;
|
|
bytes = nlimbs*sizeof(CELL);
|
|
if (nlimbs > (ASP-ret)-1024) {
|
|
return TermNil;
|
|
}
|
|
H[0] = (CELL)FunctorBigInt;
|
|
H[1] = BIG_INT;
|
|
|
|
dst->_mp_size = big->_mp_size;
|
|
dst->_mp_alloc = nlimbs*(CellSize/sizeof(mp_limb_t));
|
|
memmove((void *)(dst+1), (const void *)(big->_mp_d), bytes);
|
|
H = (CELL *)(dst+1)+nlimbs;
|
|
H[0] = EndSpecials;
|
|
H++;
|
|
return AbsAppl(ret);
|
|
}
|
|
|
|
|
|
MP_INT *
|
|
Yap_BigIntOfTerm(Term t)
|
|
{
|
|
MP_INT *new = (MP_INT *)(RepAppl(t)+2);
|
|
|
|
new->_mp_d = (mp_limb_t *)(new+1);
|
|
return(new);
|
|
}
|
|
|
|
Term
|
|
Yap_MkBigRatTerm(MP_RAT *big)
|
|
{
|
|
CACHE_REGS
|
|
Int nlimbs;
|
|
MP_INT *dst = (MP_INT *)(H+2);
|
|
MP_INT *num = mpq_numref(big);
|
|
MP_INT *den = mpq_denref(big);
|
|
MP_RAT *rat;
|
|
CELL *ret = H;
|
|
|
|
if (mpz_cmp_si(den, 1) == 0)
|
|
return Yap_MkBigIntTerm(num);
|
|
if ((num->_mp_alloc+den->_mp_alloc)*(sizeof(mp_limb_t)/CellSize) > (ASP-ret)-1024) {
|
|
return TermNil;
|
|
}
|
|
H[0] = (CELL)FunctorBigInt;
|
|
H[1] = BIG_RATIONAL;
|
|
dst->_mp_size = 0;
|
|
rat = (MP_RAT *)(dst+1);
|
|
rat->_mp_num._mp_size = num->_mp_size;
|
|
rat->_mp_num._mp_alloc = num->_mp_alloc;
|
|
nlimbs = (num->_mp_alloc)*(sizeof(mp_limb_t)/CellSize);
|
|
memmove((void *)(rat+1), (const void *)(num->_mp_d), nlimbs*CellSize);
|
|
rat->_mp_den._mp_size = den->_mp_size;
|
|
rat->_mp_den._mp_alloc = den->_mp_alloc;
|
|
H = (CELL *)(rat+1)+nlimbs;
|
|
nlimbs = (den->_mp_alloc)*(sizeof(mp_limb_t)/CellSize);
|
|
memmove((void *)(H), (const void *)(den->_mp_d), nlimbs*CellSize);
|
|
H += nlimbs;
|
|
dst->_mp_alloc = (H-(CELL *)(dst+1));
|
|
H[0] = EndSpecials;
|
|
H++;
|
|
return AbsAppl(ret);
|
|
}
|
|
|
|
MP_RAT *
|
|
Yap_BigRatOfTerm(Term t)
|
|
{
|
|
MP_RAT *new = (MP_RAT *)(RepAppl(t)+2+sizeof(MP_INT)/sizeof(CELL));
|
|
mp_limb_t *nt;
|
|
|
|
nt = new->_mp_num._mp_d = (mp_limb_t *)(new+1);
|
|
nt += new->_mp_num._mp_alloc;
|
|
new->_mp_den._mp_d = nt;
|
|
return new;
|
|
}
|
|
|
|
Term
|
|
Yap_RatTermToApplTerm(Term t)
|
|
{
|
|
Term ts[2];
|
|
MP_RAT *rat = Yap_BigRatOfTerm(t);
|
|
|
|
ts[0] = Yap_MkBigIntTerm(mpq_numref(rat));
|
|
ts[1] = Yap_MkBigIntTerm(mpq_denref(rat));
|
|
return Yap_MkApplTerm(FunctorRDiv,2,ts);
|
|
}
|
|
|
|
#endif
|
|
|
|
Term
|
|
Yap_AllocExternalDataInStack(CELL tag, size_t bytes)
|
|
{
|
|
CACHE_REGS
|
|
Int nlimbs;
|
|
MP_INT *dst = (MP_INT *)(H+2);
|
|
CELL *ret = H;
|
|
|
|
nlimbs = ALIGN_YAPTYPE(bytes,CELL)/CellSize;
|
|
if (nlimbs > (ASP-ret)-1024) {
|
|
return TermNil;
|
|
}
|
|
H[0] = (CELL)FunctorBigInt;
|
|
H[1] = tag;
|
|
dst->_mp_size = 0;
|
|
dst->_mp_alloc = nlimbs;
|
|
H = (CELL *)(dst+1)+nlimbs;
|
|
H[0] = EndSpecials;
|
|
H++;
|
|
if (tag != EXTERNAL_BLOB) {
|
|
TrailTerm(TR) = AbsPair(ret);
|
|
TR++;
|
|
}
|
|
return AbsAppl(ret);
|
|
}
|
|
|
|
int Yap_CleanOpaqueVariable(CELL *pt)
|
|
{
|
|
CELL blob_info, blob_tag;
|
|
MP_INT *blobp;
|
|
#ifdef DEBUG
|
|
/* sanity checking */
|
|
if (pt[0] != (CELL)FunctorBigInt) {
|
|
Yap_Error(SYSTEM_ERROR, TermNil, "CleanOpaqueVariable bad call");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
blob_tag = pt[1];
|
|
if (blob_tag < USER_BLOB_START ||
|
|
blob_tag >= USER_BLOB_END) {
|
|
Yap_Error(SYSTEM_ERROR, AbsAppl(pt), "clean opaque: bad blob with tag " UInt_FORMAT ,blob_tag);
|
|
return FALSE;
|
|
}
|
|
blob_info = blob_tag - USER_BLOB_START;
|
|
if (!GLOBAL_OpaqueHandlers)
|
|
return FALSE;
|
|
blobp = (MP_INT *)(pt+2);
|
|
if (!GLOBAL_OpaqueHandlers[blob_info].fail_handler)
|
|
return TRUE;
|
|
return (GLOBAL_OpaqueHandlers[blob_info].fail_handler)((void *)(blobp+1));
|
|
}
|
|
|
|
Opaque_CallOnWrite
|
|
Yap_blob_write_handler_from_slot(Int slot)
|
|
{
|
|
CACHE_REGS
|
|
CELL blob_info, blob_tag;
|
|
Term t = Yap_GetFromSlot(slot PASS_REGS);
|
|
CELL *pt = RepAppl(t);
|
|
|
|
#ifdef DEBUG
|
|
/* sanity checking */
|
|
if (pt[0] != (CELL)FunctorBigInt) {
|
|
Yap_Error(SYSTEM_ERROR, TermNil, "CleanOpaqueVariable bad call");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
blob_tag = pt[1];
|
|
if (blob_tag < USER_BLOB_START ||
|
|
blob_tag >= USER_BLOB_END) {
|
|
Yap_Error(SYSTEM_ERROR, AbsAppl(pt), "clean opaque: bad blob with tag " UInt_FORMAT ,blob_tag);
|
|
return FALSE;
|
|
}
|
|
blob_info = blob_tag - USER_BLOB_START;
|
|
if (!GLOBAL_OpaqueHandlers) {
|
|
return NULL;
|
|
}
|
|
return GLOBAL_OpaqueHandlers[blob_info].write_handler;
|
|
}
|
|
|
|
Opaque_CallOnGCMark
|
|
Yap_blob_gc_mark_handler(Term t)
|
|
{
|
|
CELL blob_info, blob_tag;
|
|
CELL *pt = RepAppl(t);
|
|
|
|
#ifdef DEBUG
|
|
/* sanity checking */
|
|
if (pt[0] != (CELL)FunctorBigInt) {
|
|
Yap_Error(SYSTEM_ERROR, TermNil, "CleanOpaqueVariable bad call");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
blob_tag = pt[1];
|
|
if (blob_tag < USER_BLOB_START ||
|
|
blob_tag >= USER_BLOB_END) {
|
|
return NULL;
|
|
}
|
|
blob_info = blob_tag - USER_BLOB_START;
|
|
if (!GLOBAL_OpaqueHandlers)
|
|
return NULL;
|
|
return GLOBAL_OpaqueHandlers[blob_info].gc_mark_handler;
|
|
}
|
|
|
|
Opaque_CallOnGCRelocate
|
|
Yap_blob_gc_relocate_handler(Term t)
|
|
{
|
|
CELL blob_info, blob_tag;
|
|
CELL *pt = RepAppl(t);
|
|
|
|
#ifdef DEBUG
|
|
/* sanity checking */
|
|
if (pt[0] != (CELL)FunctorBigInt) {
|
|
Yap_Error(SYSTEM_ERROR, TermNil, "CleanOpaqueVariable bad call");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
blob_tag = pt[1];
|
|
if (blob_tag < USER_BLOB_START ||
|
|
blob_tag >= USER_BLOB_END) {
|
|
Yap_Error(SYSTEM_ERROR, AbsAppl(pt), "clean opaque: bad blob with tag " UInt_FORMAT ,blob_tag);
|
|
return FALSE;
|
|
}
|
|
blob_info = blob_tag - USER_BLOB_START;
|
|
if (!GLOBAL_OpaqueHandlers)
|
|
return NULL;
|
|
return GLOBAL_OpaqueHandlers[blob_info].gc_relocate_handler;
|
|
}
|
|
|
|
extern Int Yap_blob_tag_from_slot(Int slot)
|
|
{
|
|
CACHE_REGS
|
|
Term t = Yap_GetFromSlot(slot PASS_REGS);
|
|
CELL *pt = RepAppl(t);
|
|
|
|
#ifdef DEBUG
|
|
/* sanity checking */
|
|
if (pt[0] != (CELL)FunctorBigInt) {
|
|
Yap_Error(SYSTEM_ERROR, TermNil, "CleanOpaqueVariable bad call");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
return pt[1];
|
|
}
|
|
|
|
void *
|
|
Yap_blob_info_from_slot(Int slot)
|
|
{
|
|
CACHE_REGS
|
|
MP_INT *blobp;
|
|
Term t = Yap_GetFromSlot(slot PASS_REGS);
|
|
CELL *pt = RepAppl(t);
|
|
|
|
#ifdef DEBUG
|
|
/* sanity checking */
|
|
if (pt[0] != (CELL)FunctorBigInt) {
|
|
Yap_Error(SYSTEM_ERROR, TermNil, "CleanOpaqueVariable bad call");
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
if (!GLOBAL_OpaqueHandlers)
|
|
return FALSE;
|
|
blobp = (MP_INT *)(pt+2);
|
|
return (void *)(blobp+1);
|
|
}
|
|
|
|
Term
|
|
Yap_MkULLIntTerm(YAP_ULONG_LONG n)
|
|
{
|
|
#if __GNUC__ && USE_GMP
|
|
mpz_t new;
|
|
char tmp[256];
|
|
Term t;
|
|
|
|
#ifdef _WIN32
|
|
snprintf(tmp,256,"%I64u",n);
|
|
#elif HAVE_SNPRINTF
|
|
snprintf(tmp,256,"%llu",n);
|
|
#else
|
|
sprintf(tmp,"%llu",n);
|
|
#endif
|
|
/* try to scan it as a bignum */
|
|
mpz_init_set_str (new, tmp, 10);
|
|
if (mpz_fits_slong_p(new)) {
|
|
return MkIntegerTerm(mpz_get_si(new));
|
|
}
|
|
t = Yap_MkBigIntTerm(new);
|
|
mpz_clear(new);
|
|
return t;
|
|
#else
|
|
return MkIntegerTerm(n);
|
|
#endif
|
|
}
|
|
|
|
static Int
|
|
p_is_bignum( USES_REGS1 )
|
|
{
|
|
#ifdef USE_GMP
|
|
Term t = Deref(ARG1);
|
|
return(
|
|
IsNonVarTerm(t) &&
|
|
IsApplTerm(t) &&
|
|
FunctorOfTerm(t) == FunctorBigInt &&
|
|
RepAppl(t)[1] == BIG_INT
|
|
);
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
static Int
|
|
p_has_bignums( USES_REGS1 )
|
|
{
|
|
#ifdef USE_GMP
|
|
return TRUE;
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
static Int
|
|
p_is_rational( USES_REGS1 )
|
|
{
|
|
Term t = Deref(ARG1);
|
|
if (IsVarTerm(t))
|
|
return FALSE;
|
|
if (IsIntTerm(t))
|
|
return TRUE;
|
|
if (IsApplTerm(t)) {
|
|
Functor f = FunctorOfTerm(t);
|
|
CELL *pt;
|
|
|
|
if (f == FunctorLongInt)
|
|
return TRUE;
|
|
if (f != FunctorBigInt)
|
|
return FALSE;
|
|
pt = RepAppl(t);
|
|
return ( pt[1] == BIG_RATIONAL || pt[1] == BIG_INT );
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static Int
|
|
p_rational( USES_REGS1 )
|
|
{
|
|
#ifdef USE_GMP
|
|
Term t = Deref(ARG1);
|
|
Functor f;
|
|
CELL *pt;
|
|
MP_RAT *rat;
|
|
Term t1, t2;
|
|
|
|
if (IsVarTerm(t))
|
|
return FALSE;
|
|
if (!IsApplTerm(t))
|
|
return FALSE;
|
|
f = FunctorOfTerm(t);
|
|
if (f != FunctorBigInt)
|
|
return FALSE;
|
|
pt = RepAppl(t);
|
|
if (pt[1] != BIG_RATIONAL)
|
|
return FALSE;
|
|
rat = Yap_BigRatOfTerm(t);
|
|
while ((t1 = Yap_MkBigIntTerm(mpq_numref(rat))) == TermNil ||
|
|
(t2 = Yap_MkBigIntTerm(mpq_denref(rat))) == TermNil) {
|
|
UInt size =
|
|
(mpq_numref(rat)->_mp_alloc)*(sizeof(mp_limb_t)/CellSize) +
|
|
(mpq_denref(rat)->_mp_alloc)*(sizeof(mp_limb_t)/CellSize);
|
|
if (!Yap_gcl(size, 3, ENV, P)) {
|
|
Yap_Error(OUT_OF_STACK_ERROR, t, LOCAL_ErrorMessage);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return
|
|
Yap_unify(ARG2, t1) &&
|
|
Yap_unify(ARG3, t2);
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
Yap_IsStringTerm(Term t)
|
|
{
|
|
CELL fl;
|
|
if (IsVarTerm(t))
|
|
return FALSE;
|
|
if (!IsApplTerm(t))
|
|
return FALSE;
|
|
if (FunctorOfTerm(t) != FunctorBigInt)
|
|
return FALSE;
|
|
|
|
fl = RepAppl(t)[1];
|
|
return fl == BLOB_STRING || fl == BLOB_WIDE_STRING;
|
|
}
|
|
|
|
int
|
|
Yap_IsWideStringTerm(Term t)
|
|
{
|
|
CELL fl;
|
|
if (IsVarTerm(t))
|
|
return FALSE;
|
|
if (!IsApplTerm(t))
|
|
return FALSE;
|
|
if (FunctorOfTerm(t) != FunctorBigInt)
|
|
return FALSE;
|
|
|
|
fl = RepAppl(t)[1];
|
|
return fl == BLOB_WIDE_STRING;
|
|
}
|
|
|
|
Term
|
|
Yap_MkBlobStringTerm(const char *s, size_t len)
|
|
{
|
|
CACHE_REGS
|
|
CELL *ret = H;
|
|
size_t sz;
|
|
MP_INT *dst = (MP_INT *)(H+2);
|
|
blob_string_t *sp;
|
|
size_t siz;
|
|
char *dest;
|
|
|
|
sz = strlen(s);
|
|
if (len > 0 && sz > len) sz = len;
|
|
if (len/sizeof(CELL) > (ASP-ret)-1024) {
|
|
return TermNil;
|
|
}
|
|
H[0] = (CELL)FunctorBigInt;
|
|
H[1] = BLOB_STRING;
|
|
siz = ALIGN_YAPTYPE((len+1+sizeof(blob_string_t)),CELL);
|
|
dst->_mp_size = 0L;
|
|
dst->_mp_alloc = siz/sizeof(mp_limb_t);
|
|
sp = (blob_string_t *)(dst+1);
|
|
sp->len = sz;
|
|
dest = (char *)(sp+1);
|
|
strncpy(dest, s, sz);
|
|
dest[sz] = '\0';
|
|
H += (siz + 2*sizeof(CELL)+sizeof(MP_INT)+sizeof(Functor))/sizeof(CELL);
|
|
H[-1] = EndSpecials;
|
|
return AbsAppl(ret);
|
|
}
|
|
|
|
Term
|
|
Yap_MkBlobWideStringTerm(const wchar_t *s, size_t len)
|
|
{
|
|
CACHE_REGS
|
|
CELL *ret = H;
|
|
size_t sz;
|
|
MP_INT *dst = (MP_INT *)(H+2);
|
|
blob_string_t *sp = (blob_string_t *)(dst+1);
|
|
size_t siz, i = 0;
|
|
|
|
H[0] = (CELL)FunctorBigInt;
|
|
dst->_mp_size = 0L;
|
|
sz = wcslen(s);
|
|
if (len > 0 && sz > len) {
|
|
sz = len;
|
|
}
|
|
if ((len/sizeof(CELL)) > (ASP-ret)-1024) {
|
|
return TermNil;
|
|
}
|
|
while (i < sz) {
|
|
if (s[i++] >= 255) break;
|
|
}
|
|
if (i == sz) {
|
|
/* we have a standard ascii string */
|
|
char *target;
|
|
size_t i = 0;
|
|
|
|
H[1] = BLOB_STRING;
|
|
siz = ALIGN_YAPTYPE((sz+1+sizeof(blob_string_t)),CELL);
|
|
dst->_mp_alloc = siz/sizeof(mp_limb_t);
|
|
sp->len = sz;
|
|
target = (char *)(sp+1);
|
|
for (i = 0 ; i < sz; i++) {
|
|
target[i] = s[i];
|
|
}
|
|
target[sz] = '\0';
|
|
H += (siz+2*sizeof(CELL)+sizeof(MP_INT)+sizeof(Functor))/sizeof(CELL);
|
|
} else {
|
|
wchar_t * target;
|
|
|
|
H[1] = BLOB_WIDE_STRING;
|
|
siz = ALIGN_YAPTYPE((sz+1)*sizeof(wchar_t)+sizeof(blob_string_t),CELL);
|
|
dst->_mp_alloc = siz/sizeof(mp_limb_t);
|
|
sp->len = sz;
|
|
target = (wchar_t *)(sp+1);
|
|
wcsncpy(target, s, sz);
|
|
target[sz] = '\0';
|
|
H += (siz + 2*sizeof(CELL)+sizeof(MP_INT)+sizeof(Functor))/sizeof(CELL);
|
|
}
|
|
H[-1] = EndSpecials;
|
|
return AbsAppl(ret);
|
|
}
|
|
|
|
char *
|
|
Yap_BlobStringOfTerm(Term t)
|
|
{
|
|
blob_string_t *new = (blob_string_t *)(RepAppl(t)+2+sizeof(MP_INT)/sizeof(CELL));
|
|
return (char *)(new+1);
|
|
}
|
|
|
|
wchar_t *
|
|
Yap_BlobWideStringOfTerm(Term t)
|
|
{
|
|
blob_string_t *new = (blob_string_t *)(RepAppl(t)+2+sizeof(MP_INT)/sizeof(CELL));
|
|
return (wchar_t *)(new+1);
|
|
}
|
|
|
|
char *
|
|
Yap_BlobStringOfTermAndLength(Term t, size_t *sp)
|
|
{
|
|
blob_string_t *new = (blob_string_t *)(RepAppl(t)+2+sizeof(MP_INT)/sizeof(CELL));
|
|
*sp = new->len;
|
|
return (char *)(new+1);
|
|
}
|
|
|
|
void
|
|
Yap_InitBigNums(void)
|
|
{
|
|
Yap_InitCPred("$has_bignums", 0, p_has_bignums, SafePredFlag);
|
|
Yap_InitCPred("$bignum", 1, p_is_bignum, SafePredFlag);
|
|
Yap_InitCPred("rational", 3, p_rational, 0);
|
|
Yap_InitCPred("rational", 1, p_is_rational, SafePredFlag);
|
|
}
|