std_pred_xsb_i.h

00001 /* File:      std_pred_xsb_i.h
00002 ** Author(s): Kostis F. Sagonas
00003 ** Modified by Swift 
00004 ** Contact:   xsb-contact@cs.sunysb.edu
00005 ** 
00006 ** Copyright (C) The Research Foundation of SUNY, 1986, 1993-1998
00007 ** 
00008 ** XSB is free software; you can redistribute it and/or modify it under the
00009 ** terms of the GNU Library General Public License as published by the Free
00010 ** Software Foundation; either version 2 of the License, or (at your option)
00011 ** any later version.
00012 ** 
00013 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00014 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00015 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00016 ** more details.
00017 ** 
00018 ** You should have received a copy of the GNU Library General Public License
00019 ** along with XSB; if not, write to the Free Software Foundation,
00020 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021 **
00022 ** $Id: std_pred_xsb_i.h,v 1.34 2006/06/22 18:54:10 dwarren Exp $
00023 ** 
00024 */
00025 
00026 
00027 /*----------------------------------------*/
00028 #include "xsb_config.h"
00029 #include "builtin.h"
00030 #include "sp_unify_xsb_i.h"
00031 /*----------------------------------------*/
00032 
00033 static xsbBool atom_to_list(CTXTdeclc int call_type);
00034 static xsbBool number_to_list(CTXTdeclc int call_type);
00035 
00036 /* TLS 10/01 changed functor so that it did not core dump on 
00037    functor(X,1,2) */
00038 inline static xsbBool functor_builtin(CTXTdecl)
00039 {
00040   /* r1: ?term; r2: ?functor; r3: ?arity (int)  */
00041   int  new_indicator, arity, value, disp;
00042   Psc psc;
00043   char *name;
00044   Cell functor, term;
00045   Pair sym;
00046 
00047   term = ptoc_tag(CTXTc 1);
00048   if (isnonvar(term)) {
00049     if (isconstr(term) && !isboxedfloat(term) && !isboxedinteger(term)) {
00050       psc = get_str_psc(term);
00051       name = get_name(psc);
00052       arity = get_arity(psc);
00053       return (atom_unify(CTXTc makestring(name), ptoc_tag(CTXTc 2)) &&
00054               int_unify(CTXTc makeint(arity), ptoc_tag(CTXTc 3)));
00055     } else if (islist(term))
00056       return (atom_unify(CTXTc makestring(list_dot_string), ptoc_tag(CTXTc 2)) &&
00057               int_unify(CTXTc makeint(2), ptoc_tag(CTXTc 3)));
00058     else return (unify(CTXTc term, ptoc_tag(CTXTc 2)) &&
00059                  int_unify(CTXTc makeint(0), ptoc_tag(CTXTc 3)));
00060   } else {      /* term is a variable */
00061     functor = ptoc_tag(CTXTc 2);
00062     if (isstring(functor) || isinteger(functor) || isofloat(functor) ||
00063         isboxedinteger(functor) ||
00064         (isconstr(term) && get_arity(get_str_psc(term)) == 0)) {
00065       arity = ptoc_tag(CTXTc 3);
00066       /* tls: added !isnumber conjunct */
00067       if (arity_integer(arity) && !isnumber(functor)) {
00068         value = int_val(arity);
00069         if (value == 0) return unify(CTXTc functor, term);
00070         else {
00071           if (value == 2 && isstring(functor) 
00072               && string_val(functor) == list_dot_string) {
00073             /* term is a variable and I bind it to a list. */
00074             bind_list((CPtr)term, hreg);
00075             new_heap_free(hreg);
00076             new_heap_free(hreg);
00077           } else { 
00078             /* functor always creates a psc in the current module */
00079             sym = (Pair)insert(string_val(functor), (char)value, 
00080                                (Psc)flags[CURRENT_MODULE],
00081                                &new_indicator);
00082             sreg = hreg;
00083             hreg += value+1;    /* need (arity+1) new cells */
00084             bind_cs((CPtr)term, sreg);
00085             new_heap_functor(sreg, sym->psc_ptr);
00086             for (disp=0; disp<value; disp++) {
00087               new_heap_free(sreg);
00088             }
00089           }
00090           return TRUE;  /* always succeed! */
00091         }
00092         /* TLS rearranged order of the two elses below */
00093       } else {
00094           if (isnumber(functor))
00095             return (unify(CTXTc term, functor) && 
00096                     int_unify(CTXTc makeint(0), arity));
00097           else {
00098             if (isnonvar(arity)) {
00099               if (isinteger(arity))
00100                 err_handle(CTXTc RANGE, 3, "functor", 3,
00101                        "integer in the range 0..255", arity);
00102               else 
00103                 xsb_type_error(CTXTc "integer",arity,"functor",3,3); 
00104 
00105             }
00106           else err(INSTANTIATION, 3, "functor", 3);
00107           }
00108       }
00109     }
00110       else {
00111       if (isnonvar(functor))
00112         xsb_type_error(CTXTc "atom",functor,"functor",3,2); 
00113       else err(INSTANTIATION, 2, "functor", 3);
00114       }
00115   }
00116   return TRUE;
00117 }
00118 
00119 
00120 inline static xsbBool arg_builtin(CTXTdecl)
00121 {
00122   /* r1: +index (int); r2: +term; r3: ?arg (term) */
00123   Cell index;
00124   Cell term;
00125   int disp;
00126 
00127   index = ptoc_tag(CTXTc 1);
00128   if (isinteger(index)) {
00129     if ((disp = int_val(index)) > 0) {
00130       term = ptoc_tag(CTXTc 2);
00131       if (isnonvar(term)) {
00132         if (isconstr(term) && !isboxedinteger(term) && !isboxedfloat(term)) {
00133           if (disp <= (int)get_arity(get_str_psc(term))) {
00134             return unify(CTXTc (Cell)(clref_val(term)+disp),
00135                          ptoc_tag(CTXTc 3));
00136           } 
00137           else return FALSE;    /* fail */
00138         } else if (islist(term) && (disp==1 || disp==2)) {
00139           return unify(CTXTc (Cell)(clref_val(term)+disp-1),
00140                        ptoc_tag(CTXTc 3));
00141         } else return FALSE;    /* fail */
00142       } else err(INSTANTIATION, 2, "arg", 3);
00143     } else return FALSE;        /* fail */
00144   } else {
00145     if (isnonvar(index)) xsb_type_error(CTXTc "integer",index,"arg",3,1); 
00146     else err(INSTANTIATION, 1, "arg", 3);
00147   }
00148   return TRUE;
00149 }
00150 
00151 
00152 inline static xsbBool univ_builtin(CTXTdecl)
00153 {
00154   /* r1: ?term; r2: ?list       */
00155   int i, arity;
00156   int  new_indicator;
00157   char *name;
00158   Cell list, new_list, term;
00159   CPtr head, top = 0;
00160   Pair sym;
00161 
00162   term = ptoc_tag(CTXTc 1);
00163   list = ptoc_tag(CTXTc 2);
00164   if (isnonvar(term)) { /* Usage is deconstruction of terms */
00165     new_list = makelist(hreg);
00166     if (isatomic(term) || isboxedinteger(term)) { follow(hreg++) = term; top = hreg++; }
00167     else if (isconstr(term) && (arity = (get_arity(get_str_psc(term))))) {
00168       follow(hreg++) = makestring(get_name(get_str_psc(term)));
00169       top = hreg++;
00170       for (i = 1 ; i <= arity ; i++) {
00171         follow(top) = makelist(hreg); top = hreg++;
00172         follow(top) = (Cell)(clref_val(term)+i); top = hreg++;
00173       }
00174     }
00175     else { /* term is list */
00176       follow(hreg++) = makestring(list_dot_string);
00177       top = hreg++;
00178       follow(top) = makelist(hreg); top = hreg++;
00179       follow(top) = (Cell)(clref_val(term)); top = hreg++;
00180       follow(top) = makelist(hreg); top = hreg++;
00181       follow(top) = (Cell)(clref_val(term)+1); top = hreg++;
00182     }
00183     follow(top) = makenil;
00184     return unify(CTXTc list, new_list);
00185   } else { /* usage is construction; term is known to be a variable */
00186     if (islist(list)) {
00187       head = clref_val(list);
00188       XSB_Deref(cell(head));
00189       if (isatom(cell(head))) {
00190         if (isnil(cell(head+1))) {      /* atom construction */
00191           bind_copy((CPtr)term, cell(head));
00192           return TRUE;  /* succeed */
00193         } else {
00194           xsbBool list_construction = FALSE;
00195           name = string_val(cell(head));
00196           if (!strcmp(name, ".")) { /* check for list construction */
00197             list = cell(head+1); XSB_Deref(list);
00198             if (islist(list)) {
00199               list = cell(clref_val(list)+1); XSB_Deref(list);
00200               if (islist(list)) {
00201                 list = cell(clref_val(list)+1); XSB_Deref(list);
00202                 if (isnil(list)) list_construction = TRUE;
00203               }
00204             }
00205           }
00206           if (list_construction) { /* no errors can occur */
00207             bind_list((CPtr)term, hreg);
00208             list = cell(head+1);
00209             XSB_Deref(list);
00210             bld_copy(hreg, cell(clref_val(list))); hreg++;
00211             list = cell(clref_val(list)+1);
00212             XSB_Deref(list);
00213             bld_copy(hreg, cell(clref_val(list))); hreg++;
00214           } else { /* compound term construction */
00215             sreg = hreg;
00216             bind_cs((CPtr)term, sreg); hreg = sreg; sreg++;
00217             for (arity = 0, list = cell(head+1); ;
00218                  arity++, list = cell(clref_val(list)+1)) {
00219               XSB_Deref(list); /* necessary */
00220               if (!islist(list)) break; /* really ugly */
00221               bld_copy(sreg, cell(clref_val(list))); sreg++;
00222             }
00223             if (isnil(list) && arity <= MAX_ARITY) {
00224               /* '=..'/2 always creates a psc in the current * module */
00225               sym = (Pair)insert(name, (char)arity,
00226                                  (Psc)flags[CURRENT_MODULE],
00227                                  &new_indicator);
00228               new_heap_functor(hreg, sym->psc_ptr);
00229               hreg = sreg+1;
00230             } else {
00231               hreg = hreg-1;    /* restore hreg */
00232               if (arity > MAX_ARITY)
00233                 xsb_abort("[In =..] Attempt to construct a functor with arity %d > %d",
00234                           arity, MAX_ARITY);
00235               else xsb_type_error(CTXTc "list",list,"=..",2,2);  /* X =.. [foo|Y]. */
00236               return FALSE;
00237             }
00238           }
00239         } return TRUE;
00240       }
00241       if ((isnumber(cell(head)) || isboxedinteger(cell(head))) && isnil(cell(head+1))) { /* list=[num] */
00242         bind_copy((CPtr)term, cell(head));       /* term<-num  */
00243         return TRUE;    /* succeed */
00244       }
00245       else
00246         {
00247           xsb_type_error(CTXTc "list",list,"=..",2,2);  /* X =.. X =.. [2,a,b]. */
00248           return(FALSE);
00249         }
00250     }
00251     if (isnonvar(list))
00252           xsb_type_error(CTXTc "list",list,"=..",2,2);  /* X =.. a */
00253     else err(INSTANTIATION, 2, "=..", 2);
00254   }
00255   return TRUE;
00256 }
00257 
00258 
00259 inline static xsbBool hilog_arg(CTXTdecl)
00260 {
00261   /* r1: +index (int); r2: +term; r3: ?arg (term) */
00262   Cell index, term;
00263   int disp;
00264 
00265   index = ptoc_tag(CTXTc 1);
00266   if (isinteger(index)) {
00267     if ((disp = int_val(index)) > 0) {
00268       term = ptoc_tag(CTXTc 2);
00269       if (isnonvar(term)) {
00270         if (isconstr(term)) {
00271           if (hilog_cs(term)) disp++;
00272           if (disp <= (int)get_arity(get_str_psc(term))) {
00273             return unify(CTXTc (Cell)(clref_val(term)+disp),
00274                          ptoc_tag(CTXTc 3));
00275           } return FALSE;               /* fail */
00276         } else if (islist(term) && (disp==1 || disp==2)) {
00277           return unify(CTXTc (Cell)(clref_val(term)+disp-1),
00278                        ptoc_tag(CTXTc 3));
00279         } else return FALSE;    /* fail */
00280       } else err(INSTANTIATION, 2, "hilog_arg", 3);
00281     } else return FALSE;        /* fail */
00282   } else {
00283     if (isnonvar(index))
00284       xsb_type_error(CTXTc "integer",index,"hilog_arg",3,1);
00285     else err(INSTANTIATION, 1, "hilog_arg", 3);
00286   }
00287   return TRUE;
00288 }
00289 
00290 #define INITIAL_NAMELEN 256
00291 
00292 inline static xsbBool atom_to_list(CTXTdeclc int call_type)
00293 {
00294   /* r1: ?term; r2: ?character list     */
00295   int i, len;
00296   long c;
00297   char *atomname, *atomnamelast;
00298   static char *atomnameaddr = NULL;
00299   static int atomnamelen;
00300   char tmpstr[2], *tmpstr_interned;
00301   Cell heap_addr, term, term2;
00302   Cell list, new_list;
00303   CPtr top = 0;
00304   char *call_name = (call_type == ATOM_CODES ? "atom_codes" : "atom_chars");
00305   char *elt_type = (call_type == ATOM_CODES ? "ASCII code" : "character atom");
00306 
00307   SYS_MUTEX_LOCK(MUTEX_ATOM_BUF);
00308 
00309   term = ptoc_tag(CTXTc 1);
00310   list = ptoc_tag(CTXTc 2);
00311   if (!isnonvar(term)) {        /* use is: CODES/CHARS --> ATOM */
00312     atomnameaddr = (char *)mem_alloc(INITIAL_NAMELEN,LEAK_SPACE);
00313     atomnamelen = INITIAL_NAMELEN;
00314     //    printf("Allocated namebuf: %p, %d\n",atomnameaddr,atomnamelen);
00315     atomname = atomnameaddr;
00316     atomnamelast = atomnameaddr + (atomnamelen - 1);
00317     term2 = list;       /* DON'T use heap for temp storage */
00318     do {
00319       XSB_Deref(term2);
00320       if (isnil(term2)) {
00321         *atomname++ = '\0';
00322         break;
00323       }
00324       if (islist(term2)) {
00325         heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00326         if (((call_type==ATOM_CODES) && !isinteger(heap_addr))
00327             || ((call_type==ATOM_CHARS) && !isstring(heap_addr))) {
00328           if (isnonvar(heap_addr)) {
00329             xsb_type_error(CTXTc elt_type,list,call_name,2,2); 
00330           }
00331           else err(INSTANTIATION, 2, call_name, 2);
00332           SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00333           return FALSE; /* fail */
00334         }
00335         if (isinteger(heap_addr))
00336           c = int_val(heap_addr);
00337         else /* ATOM CHARS */
00338           c = *string_val(heap_addr);
00339 
00340         if (c < 0 || c > 255) {
00341           err_handle(CTXTc RANGE, 2, call_name, 2, "ASCII code", heap_addr);
00342           SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00343           return FALSE; /* fail */
00344         }
00345         if (atomname >= atomnamelast) {
00346           atomnameaddr = (char *)mem_realloc(atomnameaddr,atomnamelen,(atomnamelen << 1),LEAK_SPACE);
00347           atomname = atomnameaddr + (atomnamelen - 1);
00348           atomnamelen = atomnamelen << 1;
00349           atomnamelast = atomnameaddr + (atomnamelen - 1);
00350           /*printf("Allocated namebuf: %p, %d\n",atomnameaddr,atomnamelen);*/
00351         }
00352         *atomname++ = (char)c;
00353         term2 = cell(clref_val(term2)+1);
00354       } else {
00355         if (isref(term2)) err(INSTANTIATION, 2, call_name, 2);
00356         else xsb_type_error(CTXTc "list",term2,call_name,2,2);  /* atom_chars(X,[1]) */
00357         SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00358         return FALSE;   /* fail */
00359       }
00360     } while (1);
00361     bind_string((CPtr)(term), (char *)string_find((char *)atomnameaddr, 1));
00362     mem_dealloc(atomnameaddr,atomnamelen,LEAK_SPACE);
00363     SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00364     return TRUE;
00365   } else {      /* use is: ATOM --> CODES/CHARS */
00366     if (isstring(term)) {
00367       atomname = string_val(term);
00368       len = strlen(atomname);
00369       if (len == 0) {
00370         if (!isnonvar(list)) {
00371           bind_nil((CPtr)(list)); 
00372           SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00373           return TRUE;
00374         }
00375         else 
00376         { SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00377           return isnil(list);
00378         }
00379       } else {
00380         /* check that there is enough space on the heap! */
00381         check_glstack_overflow(2, pcreg, 2*len*sizeof(Cell)) ;
00382         list = ptoc_tag(CTXTc 2);   /* in case it changed */
00383 
00384         new_list = makelist(hreg);
00385         for (i = 0; i < len; i++) {
00386           if (call_type==ATOM_CODES)
00387             follow(hreg++) = makeint(*(unsigned char *)atomname);
00388           else {
00389             tmpstr[0]=*atomname;
00390             tmpstr[1]='\0';
00391             tmpstr_interned=string_find(tmpstr,1);
00392             follow(hreg++) = makestring(tmpstr_interned);
00393           }
00394           atomname++;
00395           top = hreg++;
00396           follow(top) = makelist(hreg);
00397         }
00398         follow(top) = makenil;
00399         SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00400         return unify(CTXTc list, new_list);
00401       } 
00402     } else xsb_type_error(CTXTc "atom",term,call_name,2,1);  /* atom_codes(1,F) */
00403   }
00404   SYS_MUTEX_UNLOCK(MUTEX_ATOM_BUF);
00405   return TRUE;
00406 }
00407 
00408 inline static xsbBool number_to_list(CTXTdeclc int call_type)
00409 {
00410   int i, tmpval;
00411   long c;
00412   char tmpstr[2], *tmpstr_interned;
00413   char str[256];        
00414   int StringLoc = 0;
00415   Cell heap_addr, term, term2;
00416   Cell list, new_list;
00417   char hack_char;       
00418   CPtr top = 0;
00419   char *call_name =
00420     (call_type == NUMBER_CODES ?
00421      "number_codes" : (call_type == NUMBER_DIGITS?
00422                        "number_digits" : "number_chars"));
00423   char *elt_type =
00424     (call_type == NUMBER_CODES ?
00425      "integer" : (call_type == NUMBER_DIGITS? "digit" : "digit atom"));
00426 
00427 
00428   term = ptoc_tag(CTXTc 1);
00429   list = ptoc_tag(CTXTc 2);
00430   if (!isnonvar(term)) {        /* use is: CHARS/CODES --> NUMBER */
00431     term2 = list;
00432     do {
00433       XSB_Deref(term2);
00434       if (isnil(term2)) {
00435         str[StringLoc++] = '\0';
00436         break;
00437       }
00438       if (islist(term2)) {
00439         heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00440         if (((call_type==NUMBER_CODES) && (!isinteger(heap_addr)))
00441             || ((call_type==NUMBER_CHARS) && !isstring(heap_addr))
00442             || ((call_type==NUMBER_DIGITS)
00443                 && !isstring(heap_addr)
00444                 && !isinteger(heap_addr))) {
00445           if (isnonvar(heap_addr))
00446             xsb_type_error(CTXTc elt_type,list,call_name,2,2); /* number_chars(X,[a]) */
00447           else err(INSTANTIATION, 2, call_name, 2);
00448           return FALSE; /* fail */
00449         }
00450         if (call_type==NUMBER_CODES)
00451           c = int_val(heap_addr);
00452         else if ((call_type==NUMBER_DIGITS) && (isinteger(heap_addr))) {
00453           tmpval = int_val(heap_addr);
00454           if ((tmpval < 0) || (tmpval > 9)) {
00455             xsb_type_error(CTXTc elt_type,list,call_name,2,2); /* number_chars(X,[11]) */
00456           }
00457           c = (long) '0' + int_val(heap_addr);
00458         } else if (isstring(heap_addr))
00459           c = *string_val(heap_addr);
00460         else {
00461             xsb_type_error(CTXTc "integer, digit, or atom",list,call_name,2,2); /* number_chars(X,[a]) */
00462         }
00463 
00464         if (c < 0 || c > 255) {
00465           err_handle(CTXTc RANGE, 2, call_name, 2, "ASCII code", heap_addr);
00466           return FALSE; /* fail */
00467         }
00468         if (StringLoc > 200) return FALSE;
00469         str[StringLoc++] = (char)c;
00470         term2 = cell(clref_val(term2)+1);
00471       } else {
00472         if (isref(term2))
00473           err(INSTANTIATION, 2, call_name, 2);
00474         else
00475           xsb_type_error(CTXTc "list",term2,call_name,2,2);
00476         return FALSE;   /* fail */
00477       }
00478     } while (1);
00479 
00480     if (sscanf(str, "%ld%c", &c, &hack_char) == 1) {
00481       bind_int((CPtr)(term), c);
00482     } else {
00483       Float float_temp;
00484       //TODO: Refactor the below few lines of code once the "Floats are always double?" 
00485       //situation is resolved.
00486 #ifndef FAST_FLOATS
00487       if (sscanf(str, "%lf%c", &float_temp, &hack_char) == 1)
00488 #else
00489       if (sscanf(str, "%f%c", &float_temp, &hack_char) == 1)
00490 #endif
00491         {
00492           bind_boxedfloat((CPtr)(term), float_temp);
00493         }
00494       else return FALSE;        /* fail */
00495     }
00496   } else {      /* use is: NUMBER --> CHARS/CODES/DIGITS */
00497     if (isinteger(term)) {
00498       sprintf(str, "%ld", (long)int_val(term));
00499     } else {
00500       if (isofloat(term)) {
00501         sprintf(str, "%e", ofloat_val(term));
00502       } else {
00503         if (isboxedinteger(term)) {
00504           sprintf(str,"%ld",(long)boxedint_val(term));
00505         } else {
00506           xsb_type_error(CTXTc "number",term,call_name,2,1);
00507         }
00508       }
00509     }
00510     new_list = makelist(hreg);
00511     for (i=0; str[i] != '\0'; i++) {
00512       if (call_type==NUMBER_CODES)
00513         follow(hreg++) = makeint((unsigned char)str[i]);
00514       else if (call_type==NUMBER_CHARS) {
00515         tmpstr[0] = str[i];
00516         tmpstr[1] = '\0';
00517         tmpstr_interned=string_find(tmpstr,1);
00518         follow(hreg++) = makestring(tmpstr_interned);
00519       } else { /* NUMBER_DIGITS */
00520         tmpval = str[i] - '0';
00521         if (0 <= tmpval && tmpval < 10)
00522           follow(hreg++) = makeint((unsigned char)str[i] - '0');
00523         else {
00524           tmpstr[0] = str[i];
00525           tmpstr[1] = '\0';
00526           tmpstr_interned=string_find(tmpstr,1);
00527           follow(hreg++) = makestring(tmpstr_interned);
00528         }
00529       }
00530       top = hreg++;
00531       follow(top) = makelist(hreg);
00532     } follow(top) = makenil;
00533     return unify(CTXTc list, new_list);
00534   }
00535   return TRUE;
00536 }
00537 
00538 #ifdef MULTI_THREAD
00539 
00540 /* Define own qsort routine when multithreading because it has to pass
00541    the thread ID to the compare routine when comparing terms.  The
00542    standard system qsort routine, which is used when single threading,
00543    does not support such an extra parameter.
00544 */
00545 
00546 typedef int (*compfptr)(CTXTdeclc const void *, const void *) ;
00547 
00548 #define INSERT_SORT     8
00549 
00550 #define QSORT_SWAP(a,b) { Cell t = *a ; *a = *b ; *b = t ; }
00551 
00552 #define QSORT_LESS(A,B) ((*qsort_cmp)((CTXT),(A),(B)) < 0)
00553 
00554 void qsort0(CTXTdeclc compfptr qsort_cmp, CPtr low, CPtr high )
00555 {
00556 /* low is address of lowest element on array */
00557 /* high is address of rightmost element on array */
00558 
00559         if ( high - low >= INSERT_SORT )
00560         {
00561                 Cell pivot ;
00562                 CPtr l, r ;
00563                 CPtr mid = low + ( high - low ) / 2 ;
00564 
00565                 if ( QSORT_LESS(mid,low) )
00566                         QSORT_SWAP( mid, low )
00567                 if ( QSORT_LESS(high,mid) )
00568                 {       QSORT_SWAP( high, mid )
00569                         if ( QSORT_LESS(mid,low) )
00570                                 QSORT_SWAP( mid, low ) 
00571                 }
00572                 pivot = *mid ;
00573 
00574                 l = low + 1 ;
00575                 r = high - 1 ;
00576                 do
00577                 {       while( QSORT_LESS(l, &pivot) ) l++ ;
00578                         while( QSORT_LESS(&pivot, r) ) r-- ;
00579 
00580                         if( l < r )
00581                         {       QSORT_SWAP( l, r )
00582                                 l++; r--;
00583                         }
00584                         else if( l == r )
00585                         {       l++; r--;
00586                         }
00587                 } while( l <= r ) ;
00588                 qsort0(CTXTc qsort_cmp, low, r) ;
00589                 qsort0(CTXTc qsort_cmp, l, high) ;
00590         }
00591         else if( low < high )           /* insertion sort for small lists */
00592         {       CPtr p, min = low, r ;
00593                 
00594                 /* set a sentinel to speed up insert sort main loop */
00595                 for( p = low + 1 ; p <= high ; p++ )
00596                         if( QSORT_LESS( p, min ) )
00597                                 min = p ;
00598                 if( low != min )
00599                         QSORT_SWAP( low, min ) ;
00600 
00601                 for( r = low + 2 ; r <= high ; r++ )
00602                 {       Cell new_el = *r ;
00603 
00604                         for( p = r ; QSORT_LESS( &new_el, p-1 ) ; p-- )
00605                                 *p = *(p-1) ;
00606                         *p = new_el ;
00607                 }
00608         }
00609 }
00610 
00611 void mt_qsort(th_context *th, CPtr v, int len, unsigned int sz, compfptr comp)
00612 {
00613         qsort0( th, comp, v, v + len - 1 ) ;
00614 }
00615 #endif /* MULTI_THREAD */
00616 
00617 inline static xsbBool sort(CTXTdecl)
00618 {
00619   /* r1: +list of terms; r2: ?sorted list of terms */
00620   int i, len;
00621   Cell *cell_tbl;
00622   Cell heap_addr, term, term2;
00623   Cell list, new_list;
00624   CPtr top = 0;
00625 
00626   list = ptoc_tag(CTXTc 1);
00627   term2 = list; len = 0;
00628   do {
00629     XSB_Deref(term2);
00630     if (isnil(term2)) break;
00631     if (islist(term2)) {
00632       len++; term2 = cell(clref_val(term2)+1);
00633     } else {
00634       if (isref(term2)) err(INSTANTIATION, 1, "sort", 2);
00635       else xsb_type_error(CTXTc "list",list,"sort",2,1);
00636     }
00637   } while(1);
00638   check_glstack_overflow(3, pcreg, (2*len)*sizeof(Cell)) ;
00639   list = ptoc_tag(CTXTc 1); /* reset in case moved */
00640   if (len > 0) {
00641     term2 = list;
00642     cell_tbl = (Cell *)mem_alloc((len * sizeof(Cell)),LEAK_SPACE);
00643     if (!cell_tbl)
00644       xsb_abort("Cannot allocate temporary memory for sort/2");
00645     for (i=0 ; i < len ; ++i) {
00646       XSB_Deref(term2); /* Necessary for correctness.   */
00647       heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00648       cell_tbl[i] = heap_addr;
00649       term2 = cell(clref_val(term2)+1);
00650     }
00651 #ifndef MULTI_THREAD
00652     qsort(cell_tbl, len, sizeof(Cell), compare);
00653 #else
00654     mt_qsort(CTXTc cell_tbl, len, sizeof(Cell), compare);
00655 #endif
00656     new_list = makelist(hreg);
00657     follow(hreg++) = cell_tbl[0]; top = hreg++;
00658     follow(top) = makelist(hreg);
00659     for (i=1 ; i < len ; i++) {
00660       if (compare(CTXTc (void*)cell_tbl[i], (void*)cell_tbl[i-1])) {
00661         follow(hreg++) = cell_tbl[i];
00662         top = hreg++;
00663         follow(top) = makelist(hreg);
00664       }
00665     } follow(top) = makenil;
00666     mem_dealloc(cell_tbl,len * sizeof(Cell),LEAK_SPACE);
00667     term = ptoc_tag(CTXTc 2);
00668     return unify(CTXTc new_list, term);
00669   }
00670   term = ptoc_tag(CTXTc 2);
00671   return unify(CTXTc list, term);
00672 }
00673 
00674 inline static xsbBool keysort(CTXTdecl)
00675 {
00676   /* r1: +list of terms of the form Key-Value;  */
00677   /* r2: ?sorted list of terms                  */
00678   int i, len;
00679   Cell heap_addr, term, term2;
00680   Cell list, new_list;
00681   Cell *cell_tbl;
00682   CPtr top = 0;
00683 
00684   list = ptoc_tag(CTXTc 1);
00685   term2 = list; len = 0;
00686   do {
00687     XSB_Deref(term2);
00688     if (isnil(term2)) break;
00689     if (islist(term2)) {
00690       heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00691       if (isconstr(heap_addr) && 
00692           get_arity(get_str_psc(heap_addr)) == 2 &&
00693           !strcmp(get_name(get_str_psc(heap_addr)), "-")) {
00694         len++; term2 = cell(clref_val(term2)+1);
00695       } else {
00696         xsb_type_error(CTXTc "pair of the form Key-Value", (Cell)NULL,"keysort",2,1);
00697       }
00698     } else {
00699       if (isref(term2)) err(INSTANTIATION, 1, "keysort", 2);
00700       else err_handle(CTXTc TYPE, 1, "keysort", 2, "list", list);
00701       return FALSE;     /* fail */
00702     }
00703   } while(1);
00704   check_glstack_overflow(3, pcreg, (2*len)*sizeof(Cell)) ;
00705   list = ptoc_tag(CTXTc 1);  /* reset in case moved */
00706   term = ptoc_tag(CTXTc 2);
00707   if (len > 0) {
00708     term2 = list;
00709     cell_tbl = (Cell *)mem_alloc(len * sizeof(Cell),LEAK_SPACE);
00710     if (!cell_tbl)
00711       xsb_abort("Cannot allocate temporary memory for keysort/2");
00712     for (i=0 ; i < len ; ++i) {
00713       XSB_Deref(term2); /* Necessary for correctness.   */
00714       heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00715       cell_tbl[i] = heap_addr;
00716       term2 = cell(clref_val(term2)+1);
00717     }
00718 #ifndef MULTI_THREAD
00719     qsort(cell_tbl, len, sizeof(Cell), key_compare);
00720 #else
00721     mt_qsort(CTXTc cell_tbl, len, sizeof(Cell), key_compare);
00722 #endif
00723     new_list = makelist(hreg);
00724     for (i=0 ; i < len ; i++) {
00725       follow(hreg++) = cell_tbl[i];
00726       top = hreg++;
00727       follow(top) = makelist(hreg);
00728     } follow(top) = makenil;
00729     mem_dealloc(cell_tbl,len * sizeof(Cell),LEAK_SPACE);
00730     return unify(CTXTc new_list, term);
00731   }
00732   return unify(CTXTc list, term);
00733 }
00734 
00735 #ifndef MULTI_THREAD
00736 struct sort_par_spec par_spec;
00737 #endif
00738 
00739 int par_key_compare(CTXTdeclc const void * t1, const void * t2) {
00740   long ipar, cmp, ind1, ind2;
00741   Cell term1 = (Cell) t1 ;
00742   Cell term2 = (Cell) t2 ;
00743 
00744   XSB_Deref(term1);             /* term1 is not in register! */
00745   XSB_Deref(term2);             /* term2 is not in register! */
00746   if (par_spec.sort_num_pars > 0) {
00747     ipar = 0;
00748     while (ipar < par_spec.sort_num_pars) {
00749       ind1 = ind2 = par_spec.sort_par_ind[ipar];
00750       if (islist(term1)) ind1--;
00751       if (islist(term2)) ind2--;
00752       cmp = compare(CTXTc (void*)cell(clref_val(term1)+ind1),
00753                           (void*)cell(clref_val(term2)+ind2));
00754       if (cmp) {
00755         if (par_spec.sort_par_dir[ipar]) return cmp;
00756         else return -cmp;
00757       } else ipar++;
00758     }
00759     return 0;
00760   } else if (par_spec.sort_num_pars == 0) {
00761     return compare(CTXTc (void*)term1, (void*)term2);
00762   } else
00763     return -compare(CTXTc (void*)term1, (void*)term2);
00764 }
00765 
00766 inline static xsbBool parsort(CTXTdecl)
00767 {
00768   /* r1: +list of terms;                                */
00769   /* r2: +list of sort indicators: asc(I) or desc(I)    */
00770   /* r3: 1 if eliminate dupls, 0 if not                 */
00771   /* r4: ?sorted list of terms                          */
00772   int i, len;
00773   int max_ind = 0, elim_dupls;
00774   Cell heap_addr, term, term2, tmp_ind;
00775   Cell list, new_list;
00776   Cell *cell_tbl;
00777   CPtr top = 0;
00778   char ermsg[50];
00779 
00780   elim_dupls = ptoc_int(CTXTc 3);
00781 
00782   list = ptoc_tag(CTXTc 2);
00783   term2 = list; par_spec.sort_num_pars = 0;
00784 
00785   XSB_Deref(term2);
00786   if (isstring(term2) && !strcmp(string_val(term2),"asc")) par_spec.sort_num_pars = 0;
00787   else if (isstring(term2) && !strcmp(string_val(term2),"desc")) par_spec.sort_num_pars = -1;
00788   else
00789     while (TRUE) {
00790       if (isnil(term2)) break;
00791       if (islist(term2)) {
00792         heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00793         if (isconstr(heap_addr) && 
00794             get_arity(get_str_psc(heap_addr)) == 1 &&
00795             !strcmp(get_name(get_str_psc(heap_addr)),"asc")) {
00796           par_spec.sort_par_dir[par_spec.sort_num_pars] = 1;
00797         } else if (isconstr(heap_addr) && 
00798                    get_arity(get_str_psc(heap_addr)) == 1 &&
00799                    !strcmp(get_name(get_str_psc(heap_addr)),"desc")) {
00800           par_spec.sort_par_dir[par_spec.sort_num_pars] = 0;
00801         } else xsb_type_error(CTXTc "asc/1 or desc/1 term",heap_addr,"parsort",4,2);
00802         tmp_ind = cell(clref_val(heap_addr)+1); XSB_Deref(tmp_ind);
00803         if (!isinteger(tmp_ind)) xsb_type_error(CTXTc "integer arg for asc/1 or desc/1",tmp_ind,"parsort",4,2);
00804         i = int_val(tmp_ind);
00805         /* TLS: Should be range below */
00806         if (i < 1 || i > 255) err_handle(CTXTc TYPE,2,"parsort",4,"arity-sized integer",tmp_ind);
00807         par_spec.sort_par_ind[par_spec.sort_num_pars] = i;
00808         if (i > max_ind) max_ind = i;
00809         par_spec.sort_num_pars++;
00810         term2 = cell(clref_val(term2)+1);
00811         XSB_Deref(term2);
00812       } else xsb_type_error(CTXTc "list",list,"parsort",4,2);
00813     }
00814       
00815   list = ptoc_tag(CTXTc 1);
00816   term2 = list; len = 0;
00817   do {
00818     XSB_Deref(term2);
00819     if (isnil(term2)) break;
00820     if (islist(term2)) {
00821       heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00822       if (par_spec.sort_num_pars <= 0 || 
00823           (isconstr(heap_addr) && (get_arity(get_str_psc(heap_addr)) >= max_ind)) ||
00824           (islist(heap_addr) && max_ind <=2)) {
00825         len++; term2 = cell(clref_val(term2)+1);
00826       } else {
00827         sprintf(ermsg,"Term with arity at least %d", max_ind);
00828         err_handle(CTXTc TYPE, 1, "parsort", 4, ermsg, (Cell)heap_addr);
00829         return FALSE;   /* fail */
00830       }
00831     } else {
00832       if (isref(term2)) err(INSTANTIATION, 1, "parsort", 4);
00833       else err_handle(CTXTc TYPE, 1, "parsort", 4, "list", list);
00834       return FALSE;     /* fail */
00835     }
00836   } while(1);
00837 
00838   check_glstack_overflow(4, pcreg, (2*len)*sizeof(Cell)) ;
00839   list = ptoc_tag(CTXTc 1);  /* reset in case moved */
00840   term = ptoc_tag(CTXTc 4);
00841   if (len > 0) {
00842     term2 = list;
00843     cell_tbl = (Cell *)mem_alloc(len * sizeof(Cell),LEAK_SPACE);
00844     if (!cell_tbl)
00845       xsb_abort("Cannot allocate temporary memory for parsort/4");
00846     for (i=0 ; i < len ; ++i) {
00847       XSB_Deref(term2); /* Necessary for correctness.   */
00848       heap_addr = cell(clref_val(term2)); XSB_Deref(heap_addr);
00849       cell_tbl[i] = heap_addr;
00850       term2 = cell(clref_val(term2)+1);
00851     }
00852 #ifndef MULTI_THREAD
00853     qsort(cell_tbl, len, sizeof(Cell), par_key_compare);
00854 #else
00855     mt_qsort(CTXTc cell_tbl, len, sizeof(Cell), par_key_compare);
00856 #endif
00857     new_list = makelist(hreg);
00858     if (elim_dupls) {
00859       follow(hreg++) = cell_tbl[0]; top = hreg++;
00860       follow(top) = makelist(hreg);
00861       for (i=1 ; i < len ; i++) {
00862         if (compare(CTXTc (void*)cell_tbl[i], (void*)cell_tbl[i-1])) {
00863           follow(hreg++) = cell_tbl[i];
00864           top = hreg++;
00865           follow(top) = makelist(hreg);
00866         }
00867       } 
00868     } else {
00869       for (i=0 ; i < len ; i++) {
00870         follow(hreg++) = cell_tbl[i];
00871         top = hreg++;
00872         follow(top) = makelist(hreg);
00873       } 
00874     }
00875     follow(top) = makenil;
00876     mem_dealloc(cell_tbl,len * sizeof(Cell),LEAK_SPACE);
00877     return unify(CTXTc new_list, term);
00878   }
00879   return unify(CTXTc list, term);
00880 }
00881 
00882 /* Assumes that first arg is a derefed var */
00883 static inline xsbBool not_occurs_in(Cell Var, Cell Term) {
00884   XSB_Deref(Term);
00885 
00886   switch (cell_tag(Term)) {
00887   case XSB_ATTV: 
00888   case XSB_REF: 
00889   case XSB_REF1: {
00890     if (Var == Term) return FALSE; else return TRUE;
00891   }
00892   case XSB_INT:
00893   case XSB_STRING:
00894   case XSB_FLOAT: {
00895     return TRUE;
00896   }
00897   case XSB_LIST: {
00898     return (not_occurs_in(Var,Term +1) 
00899             & not_occurs_in(Var, Term + 2));
00900   }
00901   case XSB_STRUCT: {
00902     xsbBool Res = TRUE;
00903     int i;
00904     CPtr arg;
00905 
00906     for (i = 1; i <= get_arity(get_str_psc(Term)); i++) {
00907       arg = clref_val(Term) + i;
00908       //      printf("Ref before %d\n",Res);
00909       Res = Res & not_occurs_in(Var,(Cell) (clref_val(Term) +i));
00910       //      printf("Ref after %d\n",Res);
00911     }
00912     return Res;    
00913   }
00914   }
00915   return TRUE;  /* hush, little compiler */
00916 }
00917   
00918 xsbBool unify_with_occurs_check(CTXTdeclc Cell Term1, Cell Term2) { 
00919   //  printf("  Term2 %x, cs_val %x\n",Term2,cs_val(Term2));
00920   xsbBool Res = TRUE;
00921 
00922   XSB_Deref(Term1);
00923   XSB_Deref(Term2);
00924   switch (cell_tag(Term1)) {
00925   case XSB_ATTV: 
00926   case XSB_REF: 
00927   case XSB_REF1: {
00928     if (isnonvar(Term2)) {
00929       if (not_occurs_in(Term1,Term2))
00930         return unify(CTXTc Term1,Term2);
00931       else return FALSE;
00932     } else 
00933       return (int) unify(CTXTc Term1,Term2);
00934   }
00935   case XSB_INT:
00936   case XSB_STRING:
00937   case XSB_FLOAT: 
00938     return unify(CTXTc Term1,Term2);
00939   case XSB_LIST:
00940   case XSB_STRUCT: {
00941 
00942 /**********/
00943     switch (cell_tag(Term2)) {
00944     case XSB_ATTV: 
00945     case XSB_REF: 
00946     case XSB_REF1: 
00947       if (not_occurs_in(Term2,Term1))
00948         return unify(CTXTc Term1,Term2);
00949       else return FALSE;
00950     case XSB_LIST:
00951     case XSB_STRUCT: {
00952       int i;
00953       int arity = get_arity(get_str_psc(Term1)); 
00954       if (arity == get_arity(get_str_psc(Term2))) {
00955         for (i = 1; i <= arity; i++) {
00956           //      printf("  struct Res before %d\n",Res);
00957           Res = Res & unify_with_occurs_check(CTXTc (Cell) (clref_val(Term1) + i), 
00958                                               (Cell) (clref_val(Term2) + i));
00959           //      printf("  struct Res after %d\n",Res);
00960         }
00961         return Res;
00962       }
00963       else return FALSE;
00964     }
00965     }
00966 
00967 /**********/
00968 
00969   }
00970   }
00971   return TRUE;  /* hush, little compiler */
00972 }
00973   

Generated on Wed Jul 26 13:30:42 2006 for XSB by  doxygen 1.4.5