From bd25c61fbf986643e7d8e4081e3da4a2f09ec911 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Mon, 17 Dec 2012 20:23:03 +0000 Subject: [PATCH 01/10] New work on UDI --- .gitmodules | 3 + C/udi.c | 266 +++++++++++-------- H/utarray.h | 233 +++++++++++++++++ Makefile.in | 11 +- include/rtree_udi.h | 24 -- include/udi.h | 8 +- packages/udi | 1 + packages/udi/README | 7 - packages/udi/rtree.c | 524 ------------------------------------- packages/udi/rtree.h | 63 ----- packages/udi/rtree_udi.c | 179 ------------- packages/udi/rtree_udi_i.h | 20 -- pl/udi.yap | 6 +- 13 files changed, 409 insertions(+), 936 deletions(-) create mode 100644 H/utarray.h delete mode 100644 include/rtree_udi.h create mode 160000 packages/udi delete mode 100644 packages/udi/README delete mode 100644 packages/udi/rtree.c delete mode 100644 packages/udi/rtree.h delete mode 100644 packages/udi/rtree_udi.c delete mode 100644 packages/udi/rtree_udi_i.h diff --git a/.gitmodules b/.gitmodules index 367eac449..dc9ffa933 100644 --- a/.gitmodules +++ b/.gitmodules @@ -43,3 +43,6 @@ [submodule "packages/odbc"] path = packages/odbc url = git://yap.git.sourceforge.net/gitroot/yap/odbc +[submodule "packages/udi"] + path = packages/udi + url = https://github.com/davidvaz/yap-udi-indexers.git diff --git a/C/udi.c b/C/udi.c index 7091df6d4..7a5b04566 100644 --- a/C/udi.c +++ b/C/udi.c @@ -1,169 +1,229 @@ - +#include #include "Yap.h" +#include "YapInterface.h" #include "clause.h" #include "udi.h" +#include "utarray.h" +/* to keep a vector of udi indexers */ +UT_icd udicb_icd = {sizeof(UdiControlBlock), NULL, NULL, NULL}; +UT_array *indexing_structures; -#include "rtree_udi.h" +/* + * New user indexed predicate: + * first argument is the decl term. + * second argument is the init call with the structure + */ +void +Yap_UdiRegister(UdiControlBlock cb){ + /*TODO: check structure integrity and duplicates */ + utarray_push_back(indexing_structures, &cb); +} -/* we can have this stactic because it is written once */ -static struct udi_control_block RtreeCmd; +struct udi_p_args { + void *idxstr; //user indexing structure + UdiControlBlock control; //user indexing structure functions +}; + +/* a pointer utarray list + * This is a hack, becouse I do no know the real type of clauses*/ +UT_icd ptr_icd = {sizeof(void *), NULL, NULL, NULL }; + +#define UDI_MI 10 /****** - All the info we need to enter user indexed code: - predicate - the user control block - functions used, in case we have different schema (maybe should part of previous) + All the info we need to enter user indexed code: right now, this is just a linked list.... ******/ typedef struct udi_info { - PredEntry *p; - void *cb; - UdiControlBlock functions; + PredEntry *p; //predicate (need to identify asserts) + UT_array *clauselist; //clause list used on returns + struct udi_p_args args[UDI_MI]; //indexed args only the first UDI_MI struct udi_info *next; } *UdiInfo; +int Yap_udi_args_init(Term spec, int arity, UdiInfo blk); + /****** we now have one extra user indexed predicate. We assume these are few, so we can do with a linked list. ******/ -static int -add_udi_block(void *info, PredEntry *p, UdiControlBlock cmd) -{ - UdiInfo blk = (UdiInfo)Yap_AllocCodeSpace(sizeof(struct udi_info)); - if (!blk) - return FALSE; - blk->next = UdiControlBlocks; - UdiControlBlocks = blk; - blk->p = p; - blk->functions = cmd; - blk->cb = info; - return TRUE; -} +//static int +//add_udi_block(PredEntry *p, void *info, UdiControlBlock cmd) +//{ +// UdiInfo blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info)); +// if (!blk) +// return FALSE; +// blk->next = UdiControlBlocks; +// UdiControlBlocks = blk; +// blk->p = p; +// blk->functions = cmd; +// blk->cb = info; +// return TRUE; +//} -/****** - new user indexed predicate; - the type right now is just rtrees, but in the future we'll have more. - the second argument is the term. -******/ +/* + * New user indexed predicate: + * the first argument is the term. + */ static Int p_new_udi( USES_REGS1 ) { - Term spec = Deref(ARG2), udi_type = Deref(ARG1); - PredEntry *p; - UdiControlBlock cmd; - Atom udi_t; - void *info; + Term spec = Deref(ARG1); + + PredEntry *p; +// UdiControlBlock cmd; +// Atom udi_t; + UdiInfo blk; + int info; + + fprintf(stderr,"new pred\n"); -/* fprintf(stderr,"new pred babe\n");*/ /* get the predicate from the spec, copied from cdmgr.c */ if (IsVarTerm(spec)) { - Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1"); - return FALSE; + Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1"); + return FALSE; } else if (!IsApplTerm(spec)) { - Yap_Error(TYPE_ERROR_COMPOUND,spec,"new user index/1"); - return FALSE; + Yap_Error(TYPE_ERROR_COMPOUND,spec,"new user index/1"); + return FALSE; } else { - Functor fun = FunctorOfTerm(spec); - Term tmod = CurrentModule; + Functor fun = FunctorOfTerm(spec); + Term tmod = CurrentModule; - while (fun == FunctorModule) { - tmod = ArgOfTerm(1,spec); - if (IsVarTerm(tmod) ) { - Yap_Error(INSTANTIATION_ERROR, spec, "new user index/1"); - return FALSE; - } - if (!IsAtomTerm(tmod) ) { - Yap_Error(TYPE_ERROR_ATOM, spec, "new user index/1"); - return FALSE; - } - spec = ArgOfTerm(2, spec); - fun = FunctorOfTerm(spec); - } - p = RepPredProp(PredPropByFunc(fun, tmod)); + while (fun == FunctorModule) { + tmod = ArgOfTerm(1,spec); + if (IsVarTerm(tmod) ) { + Yap_Error(INSTANTIATION_ERROR, spec, "new user index/1"); + return FALSE; + } + if (!IsAtomTerm(tmod) ) { + Yap_Error(TYPE_ERROR_ATOM, spec, "new user index/1"); + return FALSE; + } + spec = ArgOfTerm(2, spec); + fun = FunctorOfTerm(spec); + } + p = RepPredProp(PredPropByFunc(fun, tmod)); } if (!p) - return FALSE; + return FALSE; /* boring, boring, boring! */ - if ((p->PredFlags & (DynamicPredFlag|LogUpdatePredFlag|UserCPredFlag|CArgsPredFlag|NumberDBPredFlag|AtomDBPredFlag|TestPredFlag|AsmPredFlag|CPredFlag|BinaryPredFlag)) || - (p->ModuleOfPred == PROLOG_MODULE)) { - Yap_Error(PERMISSION_ERROR_MODIFY_STATIC_PROCEDURE, spec, "udi/2"); - return FALSE; + if ((p->PredFlags + & (DynamicPredFlag|LogUpdatePredFlag|UserCPredFlag|CArgsPredFlag|NumberDBPredFlag|AtomDBPredFlag|TestPredFlag|AsmPredFlag|CPredFlag|BinaryPredFlag)) + || (p->ModuleOfPred == PROLOG_MODULE)) { + Yap_Error(PERMISSION_ERROR_MODIFY_STATIC_PROCEDURE, spec, "udi/2"); + return FALSE; } if (p->PredFlags & (DynamicPredFlag|LogUpdatePredFlag|TabledPredFlag)) { - Yap_Error(PERMISSION_ERROR_ACCESS_PRIVATE_PROCEDURE, spec, "udi/2"); - return FALSE; - } - /* just make sure we're looking at the right user type! */ - if (IsVarTerm(udi_type)) { - Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1"); - return FALSE; - } else if (!IsAtomTerm(udi_type)) { - Yap_Error(TYPE_ERROR_ATOM,spec,"new user index/1"); - return FALSE; - } - udi_t = AtomOfTerm(udi_type); - if (udi_t == AtomRTree) { - cmd = &RtreeCmd; - } else { - Yap_Error(TYPE_ERROR_ATOM,spec,"new user index/1"); - return FALSE; + Yap_Error(PERMISSION_ERROR_ACCESS_PRIVATE_PROCEDURE, spec, "udi/2"); + return FALSE; } + /* TODO: remove AtomRTree from atom list */ + /* this is the real work */ - info = cmd->init(spec, (void *)p, p->ArityOfPE); + blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info)); + if (!blk) { + Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); + return FALSE; + } + blk->next = UdiControlBlocks; + blk->clauselist = NULL; + blk->p = p; + + info = Yap_udi_args_init(spec, p->ArityOfPE, blk); if (!info) return FALSE; - /* add to table */ - if (!add_udi_block(info, p, cmd)) { - Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); - return FALSE; - } + p->PredFlags |= UDIPredFlag; return TRUE; } +/* + * Here we initialize the arguments indexing + */ +int +Yap_udi_args_init(Term spec, int arity, UdiInfo blk) +{ + int i; + Term arg; + Atom idxtype; + UdiControlBlock *p; + + fprintf(stderr,"udi init\n"); + for (i = 1; i <= arity && i <= UDI_MI ; i++) { + blk->args[i-1].idxstr = NULL; + blk->args[i-1].control = NULL; + fprintf(stderr,"%d\n",i); + arg = ArgOfTerm(i,spec); + if (IsAtomTerm(arg)) { + idxtype = AtomOfTerm(arg); + fprintf(stderr,"%p-%s %p-%s\n",idxtype, YAP_AtomName(idxtype), + AtomMinus, YAP_AtomName(AtomMinus)); + if (idxtype == AtomMinus) + continue; + p = NULL; + while ((p = (UdiControlBlock *) utarray_next(indexing_structures, p))) { + fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); + if (idxtype == (*p)->decl){ + blk->args[i-1].idxstr = NULL; + blk->args[i-1].control = *p; + } + } + if (blk->args[i-1].control == NULL){ /* not "-" and not found*/ + fprintf(stderr, "Invalid Spec (%s)\n", AtomName(idxtype)); + return FALSE; + } + } + } + return TRUE; +} + /* just pass info to user, called from cdmgr.c */ int Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) { - struct udi_info *info = UdiControlBlocks; - while (info->p != p && info) - info = info->next; - if (!info) - return FALSE; - info->cb = info->functions->insert(t, info->cb, (void *)cl); - return TRUE; + /* find our structure*/ + struct udi_info *info = UdiControlBlocks; + while (info->p != p && info) + info = info->next; + if (!info) + return FALSE; + + /* do the actual insertion */ + fprintf(stderr,"udi insert\n"); +// info->cb = info->functions->insert(t, info->cb, (void *)cl); + return TRUE; } /* index, called from absmi.c */ yamop * Yap_udi_search(PredEntry *p) { - struct udi_info *info = UdiControlBlocks; - while (info->p != p && info) - info = info->next; - if (!info) - return NULL; - return info->functions->search(info->cb); + struct udi_info *info = UdiControlBlocks; + while (info->p != p && info) + info = info->next; + if (!info) + return NULL; + return NULL; /*info->functions->search(info->cb);*/ } /* index, called from absmi.c */ void Yap_udi_abolish(PredEntry *p) { - /* tell the predicate destroy */ + /* tell the predicate destroy */ } void Yap_udi_init(void) { UdiControlBlocks = NULL; - /* to be filled in by David */ - RtreeCmd.init = RtreeUdiInit; - RtreeCmd.insert = RtreeUdiInsert; - RtreeCmd.search = RtreeUdiSearch; - RtreeCmd.destroy = RtreeUdiDestroy; - Yap_InitCPred("$udi_init", 2, p_new_udi, 0); + + /*init indexing structures array*/ + utarray_new(indexing_structures, &udicb_icd); + + Yap_InitCPred("$udi_init", 1, p_new_udi, 0); + /* TODO: decide if yap.udi should be loaded automaticaly in init.yap */ } diff --git a/H/utarray.h b/H/utarray.h new file mode 100644 index 000000000..0c1e59b5b --- /dev/null +++ b/H/utarray.h @@ -0,0 +1,233 @@ +/* +Copyright (c) 2008-2013, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* a dynamic array implementation using macros + * see http://uthash.sourceforge.net/utarray + */ +#ifndef UTARRAY_H +#define UTARRAY_H + +#define UTARRAY_VERSION 1.9.7 + +#ifdef __GNUC__ +#define _UNUSED_ __attribute__ ((__unused__)) +#else +#define _UNUSED_ +#endif + +#include /* size_t */ +#include /* memset, etc */ +#include /* exit */ + +#define oom() exit(-1) + +typedef void (ctor_f)(void *dst, const void *src); +typedef void (dtor_f)(void *elt); +typedef void (init_f)(void *elt); +typedef struct { + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; +} UT_icd; + +typedef struct { + unsigned i,n;/* i: index of next available slot, n: num slots */ + UT_icd icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ +} UT_array; + +#define utarray_init(a,_icd) do { \ + memset(a,0,sizeof(UT_array)); \ + (a)->icd=*_icd; \ +} while(0) + +#define utarray_done(a) do { \ + if ((a)->n) { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + free((a)->d); \ + } \ + (a)->n=0; \ +} while(0) + +#define utarray_new(a,_icd) do { \ + a=(UT_array*)malloc(sizeof(UT_array)); \ + utarray_init(a,_icd); \ +} while(0) + +#define utarray_free(a) do { \ + utarray_done(a); \ + free(a); \ +} while(0) + +#define utarray_reserve(a,by) do { \ + if (((a)->i+by) > ((a)->n)) { \ + while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ + if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \ + } \ +} while(0) + +#define utarray_push_back(a,p) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ + else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ +} while(0) + +#define utarray_pop_back(a) do { \ + if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ + else { (a)->i--; } \ +} while(0) + +#define utarray_extend_back(a) do { \ + utarray_reserve(a,1); \ + if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ + else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ + (a)->i++; \ +} while(0) + +#define utarray_len(a) ((a)->i) + +#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) +#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) ))) + +#define utarray_insert(a,p,j) do { \ + utarray_reserve(a,1); \ + if (j > (a)->i) break; \ + if ((j) < (a)->i) { \ + memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ + else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ + (a)->i++; \ +} while(0) + +#define utarray_inserta(a,w,j) do { \ + if (utarray_len(w) == 0) break; \ + if (j > (a)->i) break; \ + utarray_reserve(a,utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ + _utarray_eltptr(a,j), \ + ((a)->i - (j))*((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { \ + size_t _ut_i; \ + for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ + (a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ + utarray_len(w)*((a)->icd.sz)); \ + } \ + (a)->i += utarray_len(w); \ +} while(0) + +#define utarray_resize(dst,num) do { \ + size_t _ut_i; \ + if (dst->i > (size_t)(num)) { \ + if ((dst)->icd.dtor) { \ + for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ + (dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \ + } \ + } \ + } else if (dst->i < (size_t)(num)) { \ + utarray_reserve(dst,num-dst->i); \ + if ((dst)->icd.init) { \ + for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ + (dst)->icd.init(utarray_eltptr(dst,_ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \ + } \ + } \ + dst->i = num; \ +} while(0) + +#define utarray_concat(dst,src) do { \ + utarray_inserta((dst),(src),utarray_len(dst)); \ +} while(0) + +#define utarray_erase(a,pos,len) do { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < len; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \ + } \ + } \ + if ((a)->i > (pos+len)) { \ + memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ + (((a)->i)-(pos+len))*((a)->icd.sz)); \ + } \ + (a)->i -= (len); \ +} while(0) + +#define utarray_renew(a,u) do { \ + if (a) utarray_clear(a); \ + else utarray_new((a),(u)); \ +} while(0) + +#define utarray_clear(a) do { \ + if ((a)->i > 0) { \ + if ((a)->icd.dtor) { \ + size_t _ut_i; \ + for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ +} while(0) + +#define utarray_sort(a,cmp) do { \ + qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ +} while(0) + +#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) + +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) +#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) +#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) +#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd.sz) : -1) + +/* last we pre-define a few icd for common utarrays of ints and strings */ +static void utarray_str_cpy(void *dst, const void *src) { + char **_src = (char**)src, **_dst = (char**)dst; + *_dst = (*_src == NULL) ? NULL : strdup(*_src); +} +static void utarray_str_dtor(void *elt) { + char **eltc = (char**)elt; + if (*eltc) free(*eltc); +} +static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; +static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; +static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; + + +#endif /* UTARRAY_H */ diff --git a/Makefile.in b/Makefile.in index d999ed46b..8e8ecf18d 100755 --- a/Makefile.in +++ b/Makefile.in @@ -111,7 +111,6 @@ INTERFACE_HEADERS = \ $(srcdir)/include/clause_list.h \ $(srcdir)/include/dswiatoms.h \ $(srcdir)/include/udi.h \ - $(srcdir)/include/rtree_udi.h \ $(srcdir)/include/yap_structs.h \ $(srcdir)/include/YapInterface.h \ $(srcdir)/include/SWI-Prolog.h \ @@ -262,8 +261,6 @@ C_SOURCES= \ $(srcdir)/C/threads.c \ $(srcdir)/C/tracer.c $(srcdir)/C/unify.c $(srcdir)/C/userpreds.c \ $(srcdir)/C/udi.c \ - $(srcdir)/packages/udi/rtree.c \ - $(srcdir)/packages/udi/rtree_udi.c \ $(srcdir)/C/utilpreds.c $(srcdir)/C/write.c $(srcdir)/console/yap.c \ $(srcdir)/C/yap-args.c \ $(srcdir)/C/ypstdio.c \ @@ -370,7 +367,7 @@ ENGINE_OBJECTS = \ parser.o qlyr.o qlyw.o range.o \ save.o scanner.o sort.o stdpreds.o \ sysbits.o threads.o tracer.o \ - udi.o rtree.o rtree_udi.o\ + udi.o\ unify.o userpreds.o utilpreds.o \ yap-args.o write.o \ blobs.o swi.o ypstdio.o $(IOLIB_OBJECTS) @MPI_OBJS@ @@ -474,12 +471,6 @@ sysbits.o: $(srcdir)/C/sysbits.c config.h udi.o: $(srcdir)/C/udi.c config.h $(CC) -c $(C_INTERF_FLAGS) $(srcdir)/C/udi.c -o $@ -rtree.o: $(srcdir)/packages/udi/rtree.c config.h - $(CC) -c $(C_INTERF_FLAGS) $(srcdir)/packages/udi/rtree.c -o $@ - -rtree_udi.o: $(srcdir)/packages/udi/rtree_udi.c config.h - $(CC) -c $(C_INTERF_FLAGS) $(srcdir)/packages/udi/rtree_udi.c -o $@ - yap.o: $(srcdir)/console/yap.c config.h $(CC) -c $(CFLAGS) -I$(srcdir)/include $(srcdir)/console/yap.c -o $@ diff --git a/include/rtree_udi.h b/include/rtree_udi.h deleted file mode 100644 index d701212f6..000000000 --- a/include/rtree_udi.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _RTREE_UDI_ -#define _RTREE_UDI_ - -#ifndef _RTREE_ -typedef void control_t; -#endif - -/*Prolog term from :- udi(a(-,+,+)). - User defined index announce -*/ -extern control_t *RtreeUdiInit (Term spec, - void *pred, - int arity); - -/*this is called in each asserted term that was declared to udi_init*/ -extern control_t *RtreeUdiInsert (Term term, /*asserted term*/ - control_t *control, - void *clausule); /*to store in tree and return - in search*/ - -extern void *RtreeUdiSearch (control_t *control); -extern int RtreeUdiDestroy(control_t *control); - -#endif /* _RTREE_UDI_ */ diff --git a/include/udi.h b/include/udi.h index d97a9cdc9..566e90348 100644 --- a/include/udi.h +++ b/include/udi.h @@ -1,4 +1,3 @@ - /*chamada a cada index/2 controi estrutura de control, para definir a indexação, contem a rtree p.e. @@ -6,13 +5,13 @@ */ typedef void * (* Yap_UdiInit)( - Term spec, /* mode spec */ + YAP_Term spec, /* mode spec */ void *pred, /* pass predicate information */ int arity); /*chamada a cada assert*/ typedef void * -(* Yap_UdiInsert)(Term t, /* termo asserted */ +(* Yap_UdiInsert)(YAP_Term t, /* termo asserted */ void *control, /* estrutura de control*/ void *clausule); /* valor a guardar na arvore, para retornar na pesquisa */ @@ -37,9 +36,12 @@ typedef int (* Yap_UdiDestroy)(void * control); typedef struct udi_control_block { + YAP_Atom decl; //atom that triggers this indexing structure Yap_UdiInit init; Yap_UdiInsert insert; Yap_UdiSearch search; Yap_UdiDestroy destroy; } *UdiControlBlock; +/* used to register the new indexing structure */ +void Yap_UdiRegister(UdiControlBlock); diff --git a/packages/udi b/packages/udi new file mode 160000 index 000000000..10522b20e --- /dev/null +++ b/packages/udi @@ -0,0 +1 @@ +Subproject commit 10522b20e6b061d9f68a8e08e800ff0eb9814755 diff --git a/packages/udi/README b/packages/udi/README deleted file mode 100644 index f63b5294d..000000000 --- a/packages/udi/README +++ /dev/null @@ -1,7 +0,0 @@ -This directory contains support for user defined indexers, currently: - -- RTrees - -For Examples and Tests proceed as follows: - -git clone git://yap.dcc.fc.up.pt/udi-examples diff --git a/packages/udi/rtree.c b/packages/udi/rtree.c deleted file mode 100644 index 90bd5b219..000000000 --- a/packages/udi/rtree.c +++ /dev/null @@ -1,524 +0,0 @@ -#include -#include -#include -#include -#include - -#include "rtree.h" - -static node_t RTreeNewNode (void); -static void RTreeDestroyNode (node_t); -static void RTreeNodeInit (node_t); - -static int RTreeSearchNode (node_t, rect_t, SearchHitCallback, void *); -static int RTreeInsertNode (node_t, int, rect_t,void *,node_t *); - -static int RTreePickBranch (rect_t, node_t); -static int RTreeAddBranch(node_t, branch_t, node_t *); -static void RTreeSplitNode (node_t, branch_t, node_t *); - -static void RTreePickSeeds(partition_t *, node_t, node_t); -static void RTreeNodeAddBranch(rect_t *, node_t, branch_t); -static void RTreePickNext(partition_t *, node_t, node_t); - -static rect_t RTreeNodeCover(node_t); - -static double RectArea (rect_t); -static rect_t RectCombine (rect_t, rect_t); -static int RectOverlap (rect_t, rect_t); -static void RectPrint (rect_t); - -static partition_t PartitionNew (void); -static void PartitionPush (partition_t *, branch_t); -static branch_t PartitionPop (partition_t *); -static branch_t PartitionGet (partition_t *, int); - -rtree_t RTreeNew (void) -{ - rtree_t t; - t = RTreeNewNode(); - t->level = 0; /*leaf*/ - return t; -} - -void RTreeDestroy (rtree_t t) -{ - if (t) - RTreeDestroyNode (t); -} - -static node_t RTreeNewNode (void) -{ - node_t n; - - n = (node_t) malloc (sizeof(*n)); - assert(n); - RTreeNodeInit(n); - return n; -} - -static void RTreeDestroyNode (node_t node) -{ - int i; - - if (node->level == 0) /* leaf level*/ - { - for (i = 0; i < MAXCARD; i++) - if (node->branch[i].child) - ;/* allow user free data*/ - else - break; - } - else - { - for (i = 0; i < MAXCARD; i++) - if (node->branch[i].child) - RTreeDestroyNode (node->branch[i].child); - else - break; - } - free (node); -} - -static void RTreeNodeInit (node_t n) -{ - memset((void *) n,0, sizeof(*n)); - n->level = -1; -} - -int RTreeSearch (rtree_t t, rect_t s, SearchHitCallback f, void *arg) -{ - assert(t); - return RTreeSearchNode(t,s,f,arg); -} - -static int RTreeSearchNode (node_t n, rect_t s, SearchHitCallback f, void *arg) -{ - int i; - int c = 0; - - if (n->level > 0) - { - for (i = 0; i < MAXCARD; i++) - if (n->branch[i].child && - RectOverlap (s,n->branch[i].mbr)) - c += RTreeSearchNode ((node_t) n->branch[i].child, s, f, arg); - } - else - { - for (i = 0; i < MAXCARD; i++) - if (n->branch[i].child && - RectOverlap (s,n->branch[i].mbr)) - { - c ++; - if (f) - if ( !f(n->branch[i].mbr,n->branch[i].child,arg)) - return c; - } - } - return c; -} - -void RTreeInsert (rtree_t *t, rect_t r, void *data) -{ - node_t n2; - node_t new_root; - branch_t b; - assert(t && *t); - - if (RTreeInsertNode(*t, 0, r, data, &n2)) - /* deal with root split */ - { - new_root = RTreeNewNode(); - new_root->level = (*t)->level + 1; - b.mbr = RTreeNodeCover(*t); - b.child = (void *) *t; - RTreeAddBranch(new_root, b, NULL); - b.mbr = RTreeNodeCover(n2); - b.child = (void *) n2; - RTreeAddBranch(new_root, b, NULL); - *t = new_root; - } -} - -static int RTreeInsertNode (node_t n, int level, - rect_t r, void *data, - node_t *new_node) -{ - int i; - node_t n2; - branch_t b; - - assert(n && new_node); - assert(level >= 0 && level <= n->level); - - if (n->level > level) - { - i = RTreePickBranch(r,n); - if (!RTreeInsertNode((node_t) n->branch[i].child, level, - r, data,&n2)) /* not split */ - { - n->branch[i].mbr = RectCombine(r,n->branch[i].mbr); - return FALSE; - } - else /* node split */ - { - n->branch[i].mbr = RTreeNodeCover(n->branch[i].child); - b.child = n2; - b.mbr = RTreeNodeCover(n2); - return RTreeAddBranch(n, b, new_node); - } - } - else /*insert level*/ - { - b.mbr = r; - b.child = data; - return RTreeAddBranch(n, b, new_node); - } -} - -static int RTreeAddBranch(node_t n, branch_t b, node_t *new_node) -{ - int i; - - assert(n); - - if (n->count < MAXCARD) /*split not necessary*/ - { - for (i = 0; i < MAXCARD; i++) - if (n->branch[i].child == NULL) - { - n->branch[i] = b; - n->count ++; - break; - } - return FALSE; - } - else /*needs to split*/ - { - assert(new_node); - RTreeSplitNode (n, b, new_node); - return TRUE; - } -} - -static int RTreePickBranch (rect_t r, node_t n) -{ - int i; - double area; - double inc_area; - rect_t tmp; - int best_i; - double best_inc; - double best_i_area; - - best_i = 0; - best_inc = DBL_MAX; /* double Max value */ - best_i_area = DBL_MAX; - - for (i = 0; i < MAXCARD; i++) - if (n->branch[i].child) - { - area = RectArea (n->branch[i].mbr); - tmp = RectCombine (r, n->branch[i].mbr); - inc_area = RectArea (tmp) - area; - - if (inc_area < best_inc) - { - best_inc = inc_area; - best_i = i; - best_i_area = area; - } - else if (inc_area == best_inc && best_i_area > area) - { - best_inc = inc_area; - best_i = i; - best_i_area = area; - } - } - else - break; - return best_i; -} - -static void RTreeSplitNode (node_t n, branch_t b, node_t *new_node) -{ - partition_t p; - int level; - int i; - - assert(n); - assert(new_node); - - p = PartitionNew(); - - for (i = 0; i < MAXCARD; i ++) - PartitionPush(&p,n->branch[i]); - PartitionPush(&p,b); - - level = n->level; - RTreeNodeInit(n); - n->level = level; - *new_node = RTreeNewNode(); - (*new_node)->level = level; - - RTreePickSeeds(&p, n, *new_node); - - while (p.n) - if (n->count + p.n <= MINCARD) - /* first group (n) needs all entries */ - RTreeNodeAddBranch(&(p.cover[0]), n, PartitionPop(&p)); - else if ((*new_node)->count + p.n <= MINCARD) - /* second group (new_node) needs all entries */ - RTreeNodeAddBranch(&(p.cover[1]), *new_node, PartitionPop(&p)); - else - RTreePickNext(&p, n, *new_node); -} - -static void RTreePickNext(partition_t *p, node_t n1, node_t n2) -/* linear version */ -{ - branch_t b; - double area[2], inc_area[2]; - rect_t tmp; - - b = PartitionPop(p); - - area[0] = RectArea (p->cover[0]); - tmp = RectCombine (p->cover[0], b.mbr); - inc_area[0] = RectArea (tmp) - area[0]; - - area[1] = RectArea (p->cover[1]); - tmp = RectCombine (p->cover[1], b.mbr); - inc_area[1] = RectArea (tmp) - area[1]; - - if (inc_area[0] < inc_area[1] || - (inc_area[0] == inc_area[1] && area[0] < area[1])) - RTreeNodeAddBranch(&(p->cover[0]),n1,b); - else - RTreeNodeAddBranch(&(p->cover[1]),n2,b); -} - -static void RTreePickSeeds(partition_t *p, node_t n1, node_t n2) -/* puts in index 0 of each node the resulting entry, forming the two - groups - This is the linear version -*/ -{ - int dim,high, i; - int highestLow[NUMDIMS], lowestHigh[NUMDIMS]; - double width[NUMDIMS]; - int seed0, seed1; - double sep, best_sep; - - assert(p->n == MAXCARD + 1); - - for (dim = 0; dim < NUMDIMS; dim++) - { - high = dim + NUMDIMS; - highestLow[dim] = lowestHigh[dim] = 0; - for (i = 1; i < MAXCARD +1; i++) - { - if (p->buffer[i].mbr.coords[dim] > - p->buffer[highestLow[dim]].mbr.coords[dim]) - highestLow[dim] = i; - if (p->buffer[i].mbr.coords[high] < - p->buffer[lowestHigh[dim]].mbr.coords[high]) - lowestHigh[dim] = i; - } - width[dim] = p->cover_all.coords[high] - p->cover_all.coords[dim]; - assert(width[dim] >= 0); - } - - seed0 = lowestHigh[0]; - seed1 = highestLow[0]; - best_sep = 0; - for (dim = 0; dim < NUMDIMS; dim ++) - { - high = dim + NUMDIMS; - - sep = (p->buffer[highestLow[dim]].mbr.coords[dim] - - p->buffer[lowestHigh[dim]].mbr.coords[high]) / width[dim]; - if (sep > best_sep) - { - seed0 = lowestHigh[dim]; - seed1 = highestLow[dim]; - best_sep = sep; - } - } -/* assert (seed0 != seed1); */ - if (seed0 > seed1) - { - RTreeNodeAddBranch(&(p->cover[0]),n1,PartitionGet(p,seed0)); - RTreeNodeAddBranch(&(p->cover[1]),n2,PartitionGet(p,seed1)); - } - else if (seed0 < seed1) - { - RTreeNodeAddBranch(&(p->cover[0]),n1,PartitionGet(p,seed1)); - RTreeNodeAddBranch(&(p->cover[1]),n2,PartitionGet(p,seed0)); - } -} - -static void RTreeNodeAddBranch(rect_t *r, node_t n, branch_t b) -{ - int i; - - assert(n); - assert(n->count < MAXCARD); - - for (i = 0; i < MAXCARD; i++) - if (n->branch[i].child == NULL) - { - n->branch[i] = b; - n->count ++; - break; - } - *r = RectCombine(*r,b.mbr); -} - - -void RTreePrint(node_t t) -{ - int i; - - /* printf("rtree([_,_,_,_,_]).\n"); */ - printf("rtree(%p,%d,[",t,t->level); - for (i = 0; i < MAXCARD; i++) - { - if (t->branch[i].child != NULL) - { - printf("(%p,",t->branch[i].child); - RectPrint(t->branch[i].mbr); - printf(")"); - } - else - { - printf("nil"); - } - if (i < MAXCARD-1) - printf(","); - } - printf("]).\n"); - - if (t->level != 0) - for (i = 0; i < MAXCARD; i++) - if (t->branch[i].child != NULL) - RTreePrint((node_t) t->branch[i].child); - else - break; -} - -/* - * Partition related - */ - -static partition_t PartitionNew (void) -{ - partition_t p; - memset((void *) &p,0, sizeof(p)); - p.cover[0] = p.cover[1] = p.cover_all = RectInit(); - return p; -} - -static void PartitionPush (partition_t *p, branch_t b) -{ - assert(p->n < MAXCARD + 1); - p->buffer[p->n] = b; - p->n ++; - p->cover_all = RectCombine(p->cover_all,b.mbr); -} - -static branch_t PartitionPop (partition_t *p) -{ - assert(p->n > 0); - p->n --; - return p->buffer[p->n]; -} - -static branch_t PartitionGet (partition_t *p, int n) -{ - branch_t b; - assert (p->n > n); - b = p->buffer[n]; - p->buffer[n] = PartitionPop(p); - return b; -} - -/* - * Rect related - */ - -rect_t RectInit (void) -{ - rect_t r = {{DBL_MAX, DBL_MAX, DBL_MIN, DBL_MIN}}; - return (r); -} - -static double RectArea (rect_t r) -{ - int i; - double area; - - for (i = 0,area = 1; i < NUMDIMS; i++) - area *= r.coords[i+NUMDIMS] - r.coords[i]; - -/* area = (r.coords[1] - r.coords[0]) * */ -/* (r.coords[3] - r.coords[2]); */ - - return area; -} - -static rect_t RectCombine (rect_t r, rect_t s) -{ - int i; - rect_t new_rect; - - for (i = 0; i < NUMDIMS; i++) - { - new_rect.coords[i] = MIN(r.coords[i],s.coords[i]); - new_rect.coords[i+NUMDIMS] = MAX(r.coords[i+NUMDIMS],s.coords[i+NUMDIMS]); - } - - return new_rect; -} - -static int RectOverlap (rect_t r, rect_t s) -{ - int i; - - for (i = 0; i < NUMDIMS; i++) - if (r.coords[i] > s.coords[i + NUMDIMS] || - s.coords[i] > r.coords[i + NUMDIMS]) - return FALSE; - return TRUE; -} - -static rect_t RTreeNodeCover(node_t n) -{ - int i; - rect_t r = RectInit(); - - for (i = 0; i < MAXCARD; i++) - if (n->branch[i].child) - { - r = RectCombine (r, n->branch[i].mbr); - } - else - break; - - return r; -} - -static void RectPrint (rect_t r) -{ - int i; - - printf("["); - for (i = 0; i < 2*NUMDIMS; i++) - { - printf("%f",r.coords[i]); - if ( i < 2*NUMDIMS - 1) - printf(","); - } - printf("]"); -} diff --git a/packages/udi/rtree.h b/packages/udi/rtree.h deleted file mode 100644 index f05ae86e8..000000000 --- a/packages/udi/rtree.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _RTREE_ -#define _RTREE_ - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE !FALSE -#endif - -#define NUMDIMS 2 /* 2d */ - -struct Rect -{ - double coords[2*NUMDIMS]; /* x1min, y1min, ... , x1max, y1max, ...*/ -}; -typedef struct Rect rect_t; - -struct Branch -{ - rect_t mbr; - void * child; /*void * so user can store whatever he needs, in case - of non-leaf ndes it stores the child-pointer*/ -}; -typedef struct Branch branch_t; - -#define PGSIZE 196 -#define MAXCARD (int)((PGSIZE-(2*sizeof(int)))/ sizeof(struct Branch)) -#define MINCARD (MAXCARD / 2) - -struct Node -{ - int count; - int level; - branch_t branch[MAXCARD]; -}; -typedef struct Node * node_t; - -typedef node_t rtree_t; - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -/* CallBack to search function */ -typedef int (*SearchHitCallback)(rect_t r, void *data, void *arg); - -extern rtree_t RTreeNew (void); -extern void RTreeInsert (rtree_t *, rect_t, void *); -extern int RTreeSearch (rtree_t, rect_t, SearchHitCallback, void *); -extern void RTreeDestroy (rtree_t); -extern void RTreePrint(node_t); -extern rect_t RectInit (void); - -struct Partition -{ - branch_t buffer[MAXCARD+1]; - int n; - rect_t cover_all; - rect_t cover[2]; -}; -typedef struct Partition partition_t; - -#endif /* _RTREE_ */ diff --git a/packages/udi/rtree_udi.c b/packages/udi/rtree_udi.c deleted file mode 100644 index e9c092c98..000000000 --- a/packages/udi/rtree_udi.c +++ /dev/null @@ -1,179 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "Yap.h" - -#include "rtree.h" -#include "clause_list.h" -#include "rtree_udi_i.h" -#include "rtree_udi.h" - -static int YAP_IsNumberTermToFloat (Term term, YAP_Float *n) -{ - if (YAP_IsIntTerm (term) != FALSE) - { - if (n != NULL) - *n = (YAP_Float) YAP_IntOfTerm (term); - return (TRUE); - } - if (YAP_IsFloatTerm (term) != FALSE) - { - if (n != NULL) - *n = YAP_FloatOfTerm (term); - return (TRUE); - } - return (FALSE); -} - -static rect_t RectOfTerm (Term term) -{ - YAP_Term tmp; - rect_t rect; - int i; - - if (!YAP_IsPairTerm(term)) - return (RectInit()); - - for (i = 0; YAP_IsPairTerm(term) && i < 4; i++) - { - tmp = YAP_HeadOfTerm (term); - if (!YAP_IsNumberTermToFloat(tmp,&(rect.coords[i]))) - return (RectInit()); - term = YAP_TailOfTerm (term); - } - - return (rect); -} - -control_t *RtreeUdiInit (Term spec, - void * pred, - int arity){ - control_t *control; - YAP_Term arg; - int i, c; - /* YAP_Term mod; */ - - /* spec = Yap_StripModule(spec, &mod); */ - if (! YAP_IsApplTerm(spec)) - return (NULL); - - control = (control_t *) malloc (sizeof(*control)); - assert(control); - memset((void *) control,0, sizeof(*control)); - - c = 0; - for (i = 1; i <= arity; i ++) - { - arg = YAP_ArgOfTerm(i,spec); - if (YAP_IsAtomTerm(arg) - && strcmp("+",YAP_AtomName(YAP_AtomOfTerm(arg))) == 0) - { - - (*control)[c].pred = pred; - (*control)[c++].arg = i; - - } - } - -/* for (i = 0; i < NARGS; i++) - printf("%d,%p\t",(*control)[i].arg,(*control)[i].tree); - printf("\n"); */ - - return control; -} - -control_t *RtreeUdiInsert (Term term,control_t *control,void *clausule) -{ - int i; - rect_t r; - - assert(control); - - for (i = 0; i < NARGS && (*control)[i].arg != 0 ; i++) - { - r = RectOfTerm(YAP_ArgOfTerm((*control)[i].arg,term)); - if (!(*control)[i].tree) - (*control)[i].tree = RTreeNew(); - RTreeInsert(&(*control)[i].tree,r,clausule); - } - - /* printf("insert %p\n", clausule); */ - - return (control); -} - -static int callback(rect_t r, void *data, void *arg) -{ - callback_m_t x; - x = (callback_m_t) arg; - return Yap_ClauseListExtend(x->cl,data,x->pred); -} - -/*ARGS ARE AVAILABLE*/ -void *RtreeUdiSearch (control_t *control) -{ - rect_t r; - int i; - struct ClauseList clauselist; - struct CallbackM cm; - callback_m_t c; - YAP_Term Constraints; - - /*RTreePrint ((*control)[0].tree);*/ - - for (i = 0; i < NARGS && (*control)[i].arg != 0 ; i++) { - YAP_Term t = YAP_A((*control)[i].arg); - if (YAP_IsAttVar(t)) - { - fprintf(stderr,"i=%ld\n",i); - /*get the constraits rect*/ - Constraints = YAP_AttsOfVar(t); - /* Yap_DebugPlWrite(Constraints); */ - r = RectOfTerm(YAP_ArgOfTerm(2,Constraints)); - - c = &cm; - c->cl = Yap_ClauseListInit(&clauselist); - c->pred = (*control)[i].pred; - if (!c->cl) - return NULL; /*? or fail*/ - RTreeSearch((*control)[i].tree, r, callback, c); - Yap_ClauseListClose(c->cl); - - if (Yap_ClauseListCount(c->cl) == 0) - { - Yap_ClauseListDestroy(c->cl); - return Yap_FAILCODE(); - } - - if (Yap_ClauseListCount(c->cl) == 1) - { - return Yap_ClauseListToClause(c->cl); - } - - return Yap_ClauseListCode(c->cl); - } - } - return NULL; /*YAP FALLBACK*/ -} - -int RtreeUdiDestroy(control_t *control) -{ - int i; - - assert(control); - - for (i = 0; i < NARGS && (*control)[i].arg != 0; i++) - { - if ((*control)[i].tree) - RTreeDestroy((*control)[i].tree); - } - - free(control); - control = NULL; - - return TRUE; -} diff --git a/packages/udi/rtree_udi_i.h b/packages/udi/rtree_udi_i.h deleted file mode 100644 index d16aeb04e..000000000 --- a/packages/udi/rtree_udi_i.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _RTREE_UDI_I_ -#define _RTREE_UDI_I_ - -#define NARGS 5 -struct Control -{ - int arg; - void *pred; - rtree_t tree; -}; -typedef struct Control control_t[NARGS]; - -struct CallbackM -{ - clause_list_t cl; - void * pred; -}; -typedef struct CallbackM * callback_m_t; - -#endif /* _RTREE_UDI_I_ */ diff --git a/pl/udi.yap b/pl/udi.yap index a1e177174..b0da6c65b 100644 --- a/pl/udi.yap +++ b/pl/udi.yap @@ -9,7 +9,7 @@ ************************************************************************** * * * File: udi.yap * -* Last rev: 8/2/88 * +* Last rev: 17/12/2012 * * mods: * * comments: support user defined indexing * * * @@ -22,5 +22,5 @@ ******************/ udi(Pred) :- - '$udi_init'(rtree, Pred). - + writeln(('udi.yap ',Pred)), + '$udi_init'(Pred). From 8511e87e32f55a193960ab591828b4dfe176f2b0 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Mon, 17 Dec 2012 20:29:59 +0000 Subject: [PATCH 02/10] packages udi as module --- packages/udi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/udi b/packages/udi index 10522b20e..8c00c4e1e 160000 --- a/packages/udi +++ b/packages/udi @@ -1 +1 @@ -Subproject commit 10522b20e6b061d9f68a8e08e800ff0eb9814755 +Subproject commit 8c00c4e1eb0b23d4c63ee1b64265a26ceb28ac64 From 43e459b8f8a6442a11985ede5bb61c207635fd68 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Tue, 18 Dec 2012 18:26:59 +0000 Subject: [PATCH 03/10] Changes Rtree so almost working --- C/udi.c | 92 +++++++++++++++++++++++++++++++++++++++++++-------- include/udi.h | 10 +++++- packages/udi | 2 +- pl/udi.yap | 1 - 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/C/udi.c b/C/udi.c index 7a5b04566..dcba62821 100644 --- a/C/udi.c +++ b/C/udi.c @@ -2,6 +2,7 @@ #include "Yap.h" #include "YapInterface.h" #include "clause.h" +#include "clause_list.h" #include "udi.h" #include "utarray.h" @@ -78,7 +79,7 @@ p_new_udi( USES_REGS1 ) UdiInfo blk; int info; - fprintf(stderr,"new pred\n"); + //fprintf(stderr,"new pred\n"); /* get the predicate from the spec, copied from cdmgr.c */ if (IsVarTerm(spec)) { @@ -123,13 +124,18 @@ p_new_udi( USES_REGS1 ) /* this is the real work */ blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info)); + memset((void *) blk,0, sizeof(struct udi_info)); + if (!blk) { Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); return FALSE; } blk->next = UdiControlBlocks; - blk->clauselist = NULL; + utarray_new(blk->clauselist, &ptr_icd); blk->p = p; + UdiControlBlocks = blk; + + //fprintf(stderr,"PRED %p\n",p); info = Yap_udi_args_init(spec, p->ArityOfPE, blk); if (!info) @@ -150,24 +156,22 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk) Atom idxtype; UdiControlBlock *p; - fprintf(stderr,"udi init\n"); + //fprintf(stderr,"udi init\n"); + for (i = 1; i <= arity && i <= UDI_MI ; i++) { - blk->args[i-1].idxstr = NULL; - blk->args[i-1].control = NULL; - fprintf(stderr,"%d\n",i); arg = ArgOfTerm(i,spec); if (IsAtomTerm(arg)) { idxtype = AtomOfTerm(arg); - fprintf(stderr,"%p-%s %p-%s\n",idxtype, YAP_AtomName(idxtype), - AtomMinus, YAP_AtomName(AtomMinus)); +// fprintf(stderr,"%p-%s %p-%s\n",idxtype, YAP_AtomName(idxtype), +// AtomMinus, YAP_AtomName(AtomMinus)); if (idxtype == AtomMinus) continue; p = NULL; while ((p = (UdiControlBlock *) utarray_next(indexing_structures, p))) { - fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); + //fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); if (idxtype == (*p)->decl){ - blk->args[i-1].idxstr = NULL; blk->args[i-1].control = *p; + blk->args[i-1].idxstr = (*p)->init(spec, NULL, arity); } } if (blk->args[i-1].control == NULL){ /* not "-" and not found*/ @@ -183,6 +187,8 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk) int Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) { + int i; + /* find our structure*/ struct udi_info *info = UdiControlBlocks; while (info->p != p && info) @@ -191,21 +197,81 @@ Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) return FALSE; /* do the actual insertion */ - fprintf(stderr,"udi insert\n"); -// info->cb = info->functions->insert(t, info->cb, (void *)cl); + + /*insert into clauselist*/ + utarray_push_back(info->clauselist,(void *) cl); + + for (i = 0; i < UDI_MI ; i++) { + if (info->args[i].control != NULL){ +// fprintf(stderr,"call insert\n"); + info->args[i].control->insert(t,info->args[i].idxstr, (void *)cl); + // info->cb = info->functions->insert(t, info->cb, (void *)cl); + } + } return TRUE; } +struct CallbackM +{ + clause_list_t cl; + void * pred; +}; +typedef struct CallbackM * callback_m_t; + +static int callback(void *key, void *data, void *arg) +{ + callback_m_t x; + x = (callback_m_t) arg; + return Yap_ClauseListExtend(x->cl,data,x->pred); +} + /* index, called from absmi.c */ yamop * Yap_udi_search(PredEntry *p) { + int i, r = -1; + struct ClauseList clauselist; + struct CallbackM cm; + callback_m_t c; + + /* find our structure*/ struct udi_info *info = UdiControlBlocks; while (info->p != p && info) info = info->next; if (!info) return NULL; - return NULL; /*info->functions->search(info->cb);*/ + + /*TODO: handle intersection*/ + c = &cm; + c->cl = Yap_ClauseListInit(&clauselist); + c->pred = p; + for (i = 0; i < UDI_MI ; i++) { + if (info->args[i].control != NULL){ +// fprintf(stderr,"call search %d %p\n", i, (void *)c); + r = info->args[i].control->search(info->args[i].idxstr, callback,c); + /*info->functions->search(info->cb);*/ + } + } + Yap_ClauseListClose(c->cl); + + if (r >= 0) { + if (Yap_ClauseListCount(c->cl) == 0) + { + Yap_ClauseListDestroy(c->cl); + return Yap_FAILCODE(); + } + + if (Yap_ClauseListCount(c->cl) == 1) + { + return Yap_ClauseListToClause(c->cl); + } + + return Yap_ClauseListCode(c->cl); + } + else + Yap_ClauseListDestroy(c->cl); + + return NULL; } /* index, called from absmi.c */ diff --git a/include/udi.h b/include/udi.h index 566e90348..52f1978a9 100644 --- a/include/udi.h +++ b/include/udi.h @@ -15,6 +15,12 @@ typedef void * void *control, /* estrutura de control*/ void *clausule); /* valor a guardar na arvore, para retornar na pesquisa */ +/* Callback for each value found in a search */ +typedef int /* with a FALSE return should abort the search */ +(* Yap_UdiCallback) (void *key, /*index key*/ + void *clausule, /*clause*/ + void *arg); /* auxiliary to callback */ + /* chamada cada vez que um predicado indexado aparece no código Returns: NULL quando não há indexação usavel no predicado (fallback to @@ -23,7 +29,9 @@ yap indexing) TRY_RETRY_TRUST quando há resultados positivos */ typedef void * -(* Yap_UdiSearch)(void * control); +(* Yap_UdiSearch)(void * control, + Yap_UdiCallback f, /* callback on each found value*/ + void *arg); /* chamada cada vez que um predicado indexado aparece no código Returns: diff --git a/packages/udi b/packages/udi index 8c00c4e1e..5431e61ef 160000 --- a/packages/udi +++ b/packages/udi @@ -1 +1 @@ -Subproject commit 8c00c4e1eb0b23d4c63ee1b64265a26ceb28ac64 +Subproject commit 5431e61ef86b65adf62fda7d71683f4780e4e2fa diff --git a/pl/udi.yap b/pl/udi.yap index b0da6c65b..945a77110 100644 --- a/pl/udi.yap +++ b/pl/udi.yap @@ -22,5 +22,4 @@ ******************/ udi(Pred) :- - writeln(('udi.yap ',Pred)), '$udi_init'(Pred). From a655c0bb51f996af6c981c9b7be51bab07a4c8c2 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Thu, 20 Dec 2012 10:21:55 +0000 Subject: [PATCH 04/10] Rtree working as a plugin in UDI --- packages/udi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/udi b/packages/udi index 5431e61ef..13e78d741 160000 --- a/packages/udi +++ b/packages/udi @@ -1 +1 @@ -Subproject commit 5431e61ef86b65adf62fda7d71683f4780e4e2fa +Subproject commit 13e78d741400614b2b7da1fecf83a7c6ce1ecb8d From 4efa594f0a36b09ad197ec82c2427dd7c9d28f00 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Thu, 20 Dec 2012 17:13:30 +0000 Subject: [PATCH 05/10] UDI: more work --- C/udi.c | 10 ++--- include/udi.h | 122 +++++++++++++++++++++++++++++++------------------- packages/udi | 2 +- 3 files changed, 82 insertions(+), 52 deletions(-) diff --git a/C/udi.c b/C/udi.c index dcba62821..b701b0f80 100644 --- a/C/udi.c +++ b/C/udi.c @@ -68,7 +68,7 @@ int Yap_udi_args_init(Term spec, int arity, UdiInfo blk); * New user indexed predicate: * the first argument is the term. */ -static Int +static int p_new_udi( USES_REGS1 ) { Term spec = Deref(ARG1); @@ -171,7 +171,7 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk) //fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); if (idxtype == (*p)->decl){ blk->args[i-1].control = *p; - blk->args[i-1].idxstr = (*p)->init(spec, NULL, arity); + blk->args[i-1].idxstr = (*p)->init(spec, i, arity); } } if (blk->args[i-1].control == NULL){ /* not "-" and not found*/ @@ -203,8 +203,8 @@ Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) for (i = 0; i < UDI_MI ; i++) { if (info->args[i].control != NULL){ -// fprintf(stderr,"call insert\n"); - info->args[i].control->insert(t,info->args[i].idxstr, (void *)cl); + //fprintf(stderr,"call insert\n"); + info->args[i].idxstr = info->args[i].control->insert(info->args[i].idxstr, t, i + 1, (void *)cl); // info->cb = info->functions->insert(t, info->cb, (void *)cl); } } @@ -248,7 +248,7 @@ Yap_udi_search(PredEntry *p) for (i = 0; i < UDI_MI ; i++) { if (info->args[i].control != NULL){ // fprintf(stderr,"call search %d %p\n", i, (void *)c); - r = info->args[i].control->search(info->args[i].idxstr, callback,c); + r = info->args[i].control->search(info->args[i].idxstr, i + 1, callback, c); /*info->functions->search(info->cb);*/ } } diff --git a/include/udi.h b/include/udi.h index 52f1978a9..58c6a97ce 100644 --- a/include/udi.h +++ b/include/udi.h @@ -1,55 +1,85 @@ -/*chamada a cada index/2 - controi estrutura de control, para definir a indexação, contem a - rtree p.e. - retorna a estrutura de control -*/ -typedef void * -(* Yap_UdiInit)( - YAP_Term spec, /* mode spec */ - void *pred, /* pass predicate information */ - int arity); +/* + * This file is part of the YAP Prolog + * + * User Defined Indexing was developed by: + * David Vaz + * Vitor Santos Costa + * + * UDI Indexing Interface: + * + * Each new indexing mechanism should register it self by filling up a + * UdiControlBlock and calling Yap_UdiRegister(UdiControlBlock). + * + * UdiControlBlock has the main declaration that triggers the + * indexing structure as well as the pointers to the needed functions + * called at the appropriate times. + * + * For now each indexing structure only works with a single argument + * even when multiple arguments are indexed with the same struture. + * + * TODO: think of alternamive ways of support both cases, e.g. a rtree + * does not benefit from multiple rtree indexing, but a hash table do + */ -/*chamada a cada assert*/ -typedef void * -(* Yap_UdiInsert)(YAP_Term t, /* termo asserted */ - void *control, /* estrutura de control*/ - void *clausule); /* valor a guardar na arvore, para retornar na pesquisa */ +/* This is called upon udi mode spec call, and the purpose is to allow + * the indexing struture to initialize itself. + * Should return the need opaque struture to be used in future calls + * + * arg is used to track the specific call, on multiple indexing with the + * same struture + */ +typedef void * (* Yap_UdiInit) + (YAP_Term spec, + int arg, /* argument regarding this call */ + int arity); -/* Callback for each value found in a search */ -typedef int /* with a FALSE return should abort the search */ -(* Yap_UdiCallback) (void *key, /*index key*/ - void *clausule, /*clause*/ - void *arg); /* auxiliary to callback */ +/* Upon each assert the struture insert method is called to perform + * its work + */ +typedef void * (* Yap_UdiInsert) + (void *control, /* indexing structure opaque handle */ + YAP_Term term, /* asserted argument */ + int arg, /* argument regarding this call */ + void *data); /* value to return on search */ -/* chamada cada vez que um predicado indexado aparece no código - Returns: - NULL quando não há indexação usavel no predicado (fallback to -yap indexing) - FALSE - TRY_RETRY_TRUST quando há resultados positivos -*/ -typedef void * -(* Yap_UdiSearch)(void * control, - Yap_UdiCallback f, /* callback on each found value*/ - void *arg); +/* Callback for each value found in a search + * if it returns FALSE the search should be immediately aborted + */ +typedef int (* Yap_UdiCallback) + (void *key, /* index key */ + void *data, /* data */ + void *arg); /* auxiliary data to callback */ -/* chamada cada vez que um predicado indexado aparece no código - Returns: - NULL quando não há indexação usavel no predicado (fallback to -yap indexing) - FALSE - TRY_RETRY_TRUST quando há resultados positivos -*/ -typedef int -(* Yap_UdiDestroy)(void * control); +/* Called upon search + * + * If there is any search to do with this struture should return >= 0 + * corresponding to the values found + * + * returns -1 if there is nothing to search with this indexing structure + * e.g. a Variable as argument + */ +typedef int (* Yap_UdiSearch) + (void * control, /* indexing structure opaque handle */ + int arg, /* argument regarding this call */ + Yap_UdiCallback f, /* callback on each found value */ + void *args); /* auxiliary data to callback */ +/* Called upond abolish of the term + * to allow for a clean destroy of the indexing structures + */ +typedef int (* Yap_UdiDestroy) + (void * control); + +/* + * Main structure used in UDI + */ typedef struct udi_control_block { - YAP_Atom decl; //atom that triggers this indexing structure - Yap_UdiInit init; - Yap_UdiInsert insert; - Yap_UdiSearch search; + YAP_Atom decl; //atom that triggers this indexing structure + Yap_UdiInit init; + Yap_UdiInsert insert; + Yap_UdiSearch search; Yap_UdiDestroy destroy; -} *UdiControlBlock; +} * UdiControlBlock; -/* used to register the new indexing structure */ +/* Register a new indexing structure */ void Yap_UdiRegister(UdiControlBlock); diff --git a/packages/udi b/packages/udi index 13e78d741..5ee82f11a 160000 --- a/packages/udi +++ b/packages/udi @@ -1 +1 @@ -Subproject commit 13e78d741400614b2b7da1fecf83a7c6ce1ecb8d +Subproject commit 5ee82f11ac12dbd22ec8fca040bc6589cc9f7683 From e6c2fa30ee54d062c50702f302bb9274fb8109f9 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Thu, 27 Dec 2012 12:11:14 +0000 Subject: [PATCH 06/10] Added uthash to store indexed predicates info --- C/udi.c | 134 ++----- H/udi_private.h | 55 +++ H/uthash.h | 917 ++++++++++++++++++++++++++++++++++++++++++++++++ include/udi.h | 2 +- packages/udi | 2 +- 5 files changed, 1011 insertions(+), 99 deletions(-) create mode 100644 H/udi_private.h create mode 100644 H/uthash.h diff --git a/C/udi.c b/C/udi.c index b701b0f80..d725d29ec 100644 --- a/C/udi.c +++ b/C/udi.c @@ -3,17 +3,14 @@ #include "YapInterface.h" #include "clause.h" #include "clause_list.h" -#include "udi.h" -#include "utarray.h" +#include "udi_private.h" /* to keep a vector of udi indexers */ UT_icd udicb_icd = {sizeof(UdiControlBlock), NULL, NULL, NULL}; UT_array *indexing_structures; /* - * New user indexed predicate: - * first argument is the decl term. - * second argument is the init call with the structure + * New user indexed predicate (used by the public udi interface) */ void Yap_UdiRegister(UdiControlBlock cb){ @@ -21,61 +18,16 @@ Yap_UdiRegister(UdiControlBlock cb){ utarray_push_back(indexing_structures, &cb); } -struct udi_p_args { - void *idxstr; //user indexing structure - UdiControlBlock control; //user indexing structure functions -}; - -/* a pointer utarray list - * This is a hack, becouse I do no know the real type of clauses*/ -UT_icd ptr_icd = {sizeof(void *), NULL, NULL, NULL }; - -#define UDI_MI 10 - -/****** - All the info we need to enter user indexed code: - right now, this is just a linked list.... -******/ -typedef struct udi_info -{ - PredEntry *p; //predicate (need to identify asserts) - UT_array *clauselist; //clause list used on returns - struct udi_p_args args[UDI_MI]; //indexed args only the first UDI_MI - struct udi_info *next; -} *UdiInfo; - -int Yap_udi_args_init(Term spec, int arity, UdiInfo blk); - -/****** - we now have one extra user indexed predicate. We assume these - are few, so we can do with a linked list. -******/ -//static int -//add_udi_block(PredEntry *p, void *info, UdiControlBlock cmd) -//{ -// UdiInfo blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info)); -// if (!blk) -// return FALSE; -// blk->next = UdiControlBlocks; -// UdiControlBlocks = blk; -// blk->p = p; -// blk->functions = cmd; -// blk->cb = info; -// return TRUE; -//} - /* * New user indexed predicate: * the first argument is the term. */ -static int +static YAP_Int p_new_udi( USES_REGS1 ) { Term spec = Deref(ARG1); PredEntry *p; -// UdiControlBlock cmd; -// Atom udi_t; UdiInfo blk; int info; @@ -130,15 +82,14 @@ p_new_udi( USES_REGS1 ) Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); return FALSE; } - blk->next = UdiControlBlocks; utarray_new(blk->clauselist, &ptr_icd); + utarray_new(blk->args, &arg_icd); blk->p = p; - UdiControlBlocks = blk; - + HASH_ADD_UdiInfo(UdiControlBlocks, p, blk); //fprintf(stderr,"PRED %p\n",p); info = Yap_udi_args_init(spec, p->ArityOfPE, blk); - if (!info) + if (!info) /*TODO: clear blk here*/ return FALSE; p->PredFlags |= UDIPredFlag; @@ -155,10 +106,11 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk) Term arg; Atom idxtype; UdiControlBlock *p; + struct udi_p_args p_arg; //fprintf(stderr,"udi init\n"); - for (i = 1; i <= arity && i <= UDI_MI ; i++) { + for (i = 1; i <= arity; i++) { arg = ArgOfTerm(i,spec); if (IsAtomTerm(arg)) { idxtype = AtomOfTerm(arg); @@ -166,15 +118,18 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk) // AtomMinus, YAP_AtomName(AtomMinus)); if (idxtype == AtomMinus) continue; + p_arg.control = NULL; p = NULL; while ((p = (UdiControlBlock *) utarray_next(indexing_structures, p))) { //fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); if (idxtype == (*p)->decl){ - blk->args[i-1].control = *p; - blk->args[i-1].idxstr = (*p)->init(spec, i, arity); + p_arg.arg = i; + p_arg.control = *p; + p_arg.idxstr = (*p)->init(spec, i, arity); + utarray_push_back(blk->args, &p_arg); } } - if (blk->args[i-1].control == NULL){ /* not "-" and not found*/ + if (p_arg.control == NULL){ /* not "-" and not found*/ fprintf(stderr, "Invalid Spec (%s)\n", AtomName(idxtype)); return FALSE; } @@ -188,43 +143,26 @@ int Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) { int i; + UdiPArg parg; + UdiInfo info; - /* find our structure*/ - struct udi_info *info = UdiControlBlocks; - while (info->p != p && info) - info = info->next; + /* try to find our structure*/ + HASH_FIND_UdiInfo(UdiControlBlocks,p,info); if (!info) return FALSE; - /* do the actual insertion */ - - /*insert into clauselist*/ + /*insert into clauselist will be used latter*/ utarray_push_back(info->clauselist,(void *) cl); - for (i = 0; i < UDI_MI ; i++) { - if (info->args[i].control != NULL){ - //fprintf(stderr,"call insert\n"); - info->args[i].idxstr = info->args[i].control->insert(info->args[i].idxstr, t, i + 1, (void *)cl); - // info->cb = info->functions->insert(t, info->cb, (void *)cl); - } + for (i = 0; i < utarray_len(info->args) ; i++) { + parg = (UdiPArg) utarray_eltptr(info->args,i); + //fprintf(stderr,"call insert\n"); + parg->idxstr = parg->control->insert(parg->idxstr, t, parg->arg, (void *)cl); + //info->cb = info->functions->insert(t, info->cb, (void *)cl); } return TRUE; } -struct CallbackM -{ - clause_list_t cl; - void * pred; -}; -typedef struct CallbackM * callback_m_t; - -static int callback(void *key, void *data, void *arg) -{ - callback_m_t x; - x = (callback_m_t) arg; - return Yap_ClauseListExtend(x->cl,data,x->pred); -} - /* index, called from absmi.c */ yamop * Yap_udi_search(PredEntry *p) @@ -233,11 +171,11 @@ Yap_udi_search(PredEntry *p) struct ClauseList clauselist; struct CallbackM cm; callback_m_t c; + UdiPArg parg; + UdiInfo info; /* find our structure*/ - struct udi_info *info = UdiControlBlocks; - while (info->p != p && info) - info = info->next; + HASH_FIND_UdiInfo(UdiControlBlocks,p,info); if (!info) return NULL; @@ -245,12 +183,12 @@ Yap_udi_search(PredEntry *p) c = &cm; c->cl = Yap_ClauseListInit(&clauselist); c->pred = p; - for (i = 0; i < UDI_MI ; i++) { - if (info->args[i].control != NULL){ -// fprintf(stderr,"call search %d %p\n", i, (void *)c); - r = info->args[i].control->search(info->args[i].idxstr, i + 1, callback, c); - /*info->functions->search(info->cb);*/ - } + + for (i = 0; i < utarray_len(info->args) ; i++) { + parg = (UdiPArg) utarray_eltptr(info->args,i); + //fprintf(stderr,"call search %d %p\n", i, (void *)c); + r = parg->control->search(parg->idxstr, parg->arg, callback, c); + /*info->functions->search(info->cb);*/ } Yap_ClauseListClose(c->cl); @@ -281,6 +219,9 @@ Yap_udi_abolish(PredEntry *p) /* tell the predicate destroy */ } +/* + * Init Yap udi interface + */ void Yap_udi_init(void) { @@ -290,6 +231,5 @@ Yap_udi_init(void) utarray_new(indexing_structures, &udicb_icd); Yap_InitCPred("$udi_init", 1, p_new_udi, 0); - /* TODO: decide if yap.udi should be loaded automaticaly in init.yap */ + /* TODO: decide if udi.yap should be loaded automaticaly in init.yap */ } - diff --git a/H/udi_private.h b/H/udi_private.h new file mode 100644 index 000000000..237b6a9e1 --- /dev/null +++ b/H/udi_private.h @@ -0,0 +1,55 @@ +#include "udi.h" +#include "utarray.h" +#include "uthash.h" + +/* Argument Indexing */ +struct udi_p_args { + int arg; //indexed arg + void *idxstr; //user indexing structure + UdiControlBlock control; //user indexing structure functions +}; +typedef struct udi_p_args *UdiPArg; +UT_icd arg_icd = {sizeof(struct udi_p_args), NULL, NULL, NULL }; + +/* a pointer utarray list + * This is a hack, becouse I do no know the real type of clauses + * Not completely used for now + */ +UT_icd ptr_icd = {sizeof(void *), NULL, NULL, NULL }; + +/* + * All the info we need to enter user indexed code + * stored in a uthash + */ +struct udi_info +{ + PredEntry *p; //predicate (need to identify asserts) + UT_array *clauselist; //clause list used on returns + UT_array *args; //indexed args + UT_hash_handle hh; +}; +typedef struct udi_info *UdiInfo; + +/* to ease code for a UdiInfo hash table*/ +#define HASH_FIND_UdiInfo(head,find,out) \ + HASH_FIND(hh,head,find,sizeof(PredEntry *),out) +#define HASH_ADD_UdiInfo(head,p,add) \ + HASH_ADD_KEYPTR(hh,head,p,sizeof(PredEntry *),add) + +int Yap_udi_args_init(Term spec, int arity, UdiInfo blk); + +/* temporary */ +struct CallbackM +{ + clause_list_t cl; + void * pred; +}; +typedef struct CallbackM * callback_m_t; + +static inline int callback(void *key, void *data, void *arg) +{ + callback_m_t x; + x = (callback_m_t) arg; + return Yap_ClauseListExtend(x->cl,data,x->pred); +} + diff --git a/H/uthash.h b/H/uthash.h new file mode 100644 index 000000000..fe2d51b6f --- /dev/null +++ b/H/uthash.h @@ -0,0 +1,917 @@ +/* +Copyright (c) 2003-2013, Troy D. Hanson http://uthash.sourceforge.net +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while(0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while(0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on win32 */ +#ifdef _MSC_VER +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#else +#include /* uint32_t */ +#endif + +#define UTHASH_VERSION 1.9.7 + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#endif +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhe */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_bkt,_hf_hashv; \ + out=NULL; \ + if (head) { \ + HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \ + keyptr,keylen,out); \ + } \ + } \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while(0) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.next = NULL; \ + (add)->hh.key = (char*)keyptr; \ + (add)->hh.keylen = (unsigned)keylen_in; \ + if (!(head)) { \ + head = (add); \ + (head)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh,head); \ + } else { \ + (head)->hh.tbl->tail->next = (add); \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } \ + (head)->hh.tbl->num_items++; \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \ + (add)->hh.hashv, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \ + HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \ + HASH_FSCK(hh,head); \ +} while(0) + +#define HASH_TO_BKT( hashv, num_bkts, bkt ) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1)); \ +} while(0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + unsigned _hd_bkt; \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev) { \ + ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next) { \ + ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield,strlen(add->strfield),add) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + unsigned _bkt_i; \ + unsigned _count, _bkt_count; \ + char *_prev; \ + struct UT_hash_handle *_thh; \ + if (head) { \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %d, actual %d\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %d, actual %d\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + char *_hj_key=(char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = (unsigned)keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + char *_sfh_key=(char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if ((out)->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/include/udi.h b/include/udi.h index 58c6a97ce..d7df3d96f 100644 --- a/include/udi.h +++ b/include/udi.h @@ -17,7 +17,7 @@ * For now each indexing structure only works with a single argument * even when multiple arguments are indexed with the same struture. * - * TODO: think of alternamive ways of support both cases, e.g. a rtree + * TODO: think of alternative ways of support both cases, e.g. a rtree * does not benefit from multiple rtree indexing, but a hash table do */ diff --git a/packages/udi b/packages/udi index 5ee82f11a..13ae724d3 160000 --- a/packages/udi +++ b/packages/udi @@ -1 +1 @@ -Subproject commit 5ee82f11ac12dbd22ec8fca040bc6589cc9f7683 +Subproject commit 13ae724d30e4c9dd56ddde63cba4a34f1844c099 From bae26c618b3c5cb68f739920e81bcf10d0998d9b Mon Sep 17 00:00:00 2001 From: David Vaz Date: Fri, 28 Dec 2012 17:46:11 +0000 Subject: [PATCH 07/10] UDI: Added Judy1 with support for integer set intersection --- C/udi.c | 158 ++++++++++++++++++++++++++++++++++++++++-------- H/udi_private.h | 30 ++++----- 2 files changed, 148 insertions(+), 40 deletions(-) diff --git a/C/udi.c b/C/udi.c index d725d29ec..ea2303d80 100644 --- a/C/udi.c +++ b/C/udi.c @@ -1,4 +1,6 @@ #include +#include +#include #include "Yap.h" #include "YapInterface.h" #include "clause.h" @@ -82,7 +84,7 @@ p_new_udi( USES_REGS1 ) Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); return FALSE; } - utarray_new(blk->clauselist, &ptr_icd); + utarray_new(blk->clauselist, &cl_icd); utarray_new(blk->args, &arg_icd); blk->p = p; HASH_ADD_UdiInfo(UdiControlBlocks, p, blk); @@ -145,6 +147,8 @@ Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) int i; UdiPArg parg; UdiInfo info; + int index; +// yamop **x; /* try to find our structure*/ HASH_FIND_UdiInfo(UdiControlBlocks,p,info); @@ -152,64 +156,168 @@ Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) return FALSE; /*insert into clauselist will be used latter*/ - utarray_push_back(info->clauselist,(void *) cl); + utarray_push_back(info->clauselist, &cl); for (i = 0; i < utarray_len(info->args) ; i++) { parg = (UdiPArg) utarray_eltptr(info->args,i); - //fprintf(stderr,"call insert\n"); - parg->idxstr = parg->control->insert(parg->idxstr, t, parg->arg, (void *)cl); + index = utarray_len(info->clauselist); +// x = (yamop **) utarray_eltptr(info->clauselist, index); +// fprintf(stderr,"Insert (%p %p %d) %d - %p %p %p\n", +// info->clauselist,info->clauselist->d,info->clauselist->icd.sz, +// index, +// cl, *x, *((yamop **) utarray_eltptr(info->clauselist, index))); + parg->idxstr = parg->control->insert(parg->idxstr, t, + parg->arg, + (void *) index); //info->cb = info->functions->insert(t, info->cb, (void *)cl); } return TRUE; } +static inline int callback(void *key, void *data, void *arg) +{ + int r; + Pvoid_t *array = (Pvoid_t *) arg; +// fprintf(stderr,"Found %p %d",data, (int) data); + J1S(r, *array, (int) data); + if (r == JERR) + return FALSE; + J1C(r, *array, 0 , -1); +// fprintf(stderr," (%d)\n",r); + return TRUE; +} + /* index, called from absmi.c */ yamop * Yap_udi_search(PredEntry *p) { - int i, r = -1; + int i, r; struct ClauseList clauselist; - struct CallbackM cm; - callback_m_t c; +// struct CallbackM cm; +// callback_m_t c; UdiPArg parg; UdiInfo info; + Pvoid_t tmp, result; + Word_t count; + Word_t idx_r = 0L; + yamop **x; /* find our structure*/ HASH_FIND_UdiInfo(UdiControlBlocks,p,info); if (!info) return NULL; - /*TODO: handle intersection*/ - c = &cm; - c->cl = Yap_ClauseListInit(&clauselist); - c->pred = p; +// /*TODO: handle intersection*/ +// c = &cm; +// c->cl = Yap_ClauseListInit(&clauselist); +// c->pred = p; + /* + * I will start with the simplest case + * for each index create a set and intersect it with the + * next + */ + result = (Pvoid_t) NULL; + tmp = (Pvoid_t) NULL; + r = -1; for (i = 0; i < utarray_len(info->args) ; i++) { +// fprintf(stderr,"Start Search\n"); parg = (UdiPArg) utarray_eltptr(info->args,i); - //fprintf(stderr,"call search %d %p\n", i, (void *)c); - r = parg->control->search(parg->idxstr, parg->arg, callback, c); - /*info->functions->search(info->cb);*/ - } - Yap_ClauseListClose(c->cl); + r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp); - if (r >= 0) { - if (Yap_ClauseListCount(c->cl) == 0) + if (r == -1) /*this arg does not prune search*/ + continue; + + J1C(count, result, 0, -1); + + if (r == 0) { - Yap_ClauseListDestroy(c->cl); + if (count > 0) // clear previous result if it exists + J1FA(count, result); + fprintf(stderr,"Search Failed"); return Yap_FAILCODE(); } - if (Yap_ClauseListCount(c->cl) == 1) + if (r > 0 && count == 0) // first result_set { - return Yap_ClauseListToClause(c->cl); + result = tmp; + tmp = (Pvoid_t) NULL; + } + else + {/*intersection*/ + Word_t idx_tmp = 0L; + + idx_r = 0L; + J1F(count, result, idx_r);//succeeds one time at least + J1F(count, tmp, idx_tmp); //succeeds one time at least + while (count) + { + while (idx_r < idx_tmp) + { + J1U(count, result, idx_r); //does not belong + J1N(count, result, idx_r); //next + if (! count) break; //end result set + } + if(idx_r == idx_tmp) + { + J1N(count, result, idx_r); //next + if (! count) break; //end result set + J1N(count, tmp, idx_tmp); //next tmp + //if (! count) break; //end tmp set + } + else // (idx_r > idx_tmp) + { + idx_tmp = idx_r; // fast forward + J1F(count, tmp, idx_tmp); // first starting in idx_r + if (! count) break; //end tmp set + } + } + J1F(count, result, idx_r); // first starting in idx_r + //clear up the rest + while (idx_r > idx_tmp && count) //result has more setted values + { + J1U(count, result, idx_r); //does not belong + J1N(count, result, idx_r); //next + } + J1FA(count, tmp); } - return Yap_ClauseListCode(c->cl); } - else - Yap_ClauseListDestroy(c->cl); - return NULL; + + Yap_ClauseListInit(&clauselist); + idx_r = 0L; + J1F(count, result, idx_r); + while (count) + { + x = (yamop **) utarray_eltptr(info->clauselist, idx_r - 1); +// fprintf(stderr,"Clausule %d of %d: %p\n", +// idx_r, utarray_len(info->clauselist), +// *x); + Yap_ClauseListExtend( + &clauselist, + *x, + info->p); + J1N(count, result, idx_r); + } + J1FA(count,result); +// fprintf(stderr,"J1 used space %d bytes for %d clausules\n", +// count, Yap_ClauseListCount(&clauselist)); + Yap_ClauseListClose(&clauselist); + + if (Yap_ClauseListCount(&clauselist) == 0) + { + Yap_ClauseListDestroy(&clauselist); +// fprintf(stderr,"Search Not needed\n"); + return NULL; /*FAIL CODE handled before*/ + } + if (Yap_ClauseListCount(&clauselist) == 1) + { +// fprintf(stderr,"Returning 1 value\n"); + return Yap_ClauseListToClause(&clauselist); + } +// fprintf(stderr,"Returning Multiple values (%d)\n", Yap_ClauseListCount(&clauselist)); + return Yap_ClauseListCode(&clauselist); } /* index, called from absmi.c */ diff --git a/H/udi_private.h b/H/udi_private.h index 237b6a9e1..e77455ae5 100644 --- a/H/udi_private.h +++ b/H/udi_private.h @@ -15,7 +15,7 @@ UT_icd arg_icd = {sizeof(struct udi_p_args), NULL, NULL, NULL }; * This is a hack, becouse I do no know the real type of clauses * Not completely used for now */ -UT_icd ptr_icd = {sizeof(void *), NULL, NULL, NULL }; +UT_icd cl_icd = {sizeof(yamop *), NULL, NULL, NULL }; /* * All the info we need to enter user indexed code @@ -38,18 +38,18 @@ typedef struct udi_info *UdiInfo; int Yap_udi_args_init(Term spec, int arity, UdiInfo blk); -/* temporary */ -struct CallbackM -{ - clause_list_t cl; - void * pred; -}; -typedef struct CallbackM * callback_m_t; - -static inline int callback(void *key, void *data, void *arg) -{ - callback_m_t x; - x = (callback_m_t) arg; - return Yap_ClauseListExtend(x->cl,data,x->pred); -} +///* temporary */ +//struct CallbackM +//{ +// clause_list_t cl; +// void * pred; +//}; +//typedef struct CallbackM * callback_m_t; +// +//static inline int callback(void *key, void *data, void *arg) +//{ +// callback_m_t x; +// x = (callback_m_t) arg; +// return Yap_ClauseListExtend(x->cl,data,x->pred); +//} From 58962f259589d1b794d4a5a49105dc69813ae7f7 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Wed, 2 Jan 2013 11:20:54 +0000 Subject: [PATCH 08/10] UDI: some code refactor, simple code when no index intersection is needed --- C/udi.c | 338 ++++++++++++++++++++++++++---------------------- H/clause.h | 3 +- H/udi_private.h | 47 ++++--- include/udi.h | 6 +- 4 files changed, 213 insertions(+), 181 deletions(-) diff --git a/C/udi.c b/C/udi.c index ea2303d80..b91b59f3e 100644 --- a/C/udi.c +++ b/C/udi.c @@ -4,15 +4,14 @@ #include "Yap.h" #include "YapInterface.h" #include "clause.h" -#include "clause_list.h" #include "udi_private.h" -/* to keep a vector of udi indexers */ +/* to keep an array with the registered udi indexers */ UT_icd udicb_icd = {sizeof(UdiControlBlock), NULL, NULL, NULL}; UT_array *indexing_structures; /* - * New user indexed predicate (used by the public udi interface) + * Register a new user indexer */ void Yap_UdiRegister(UdiControlBlock cb){ @@ -33,8 +32,6 @@ p_new_udi( USES_REGS1 ) UdiInfo blk; int info; - //fprintf(stderr,"new pred\n"); - /* get the predicate from the spec, copied from cdmgr.c */ if (IsVarTerm(spec)) { Yap_Error(INSTANTIATION_ERROR,spec,"new user index/1"); @@ -79,59 +76,63 @@ p_new_udi( USES_REGS1 ) /* this is the real work */ blk = (UdiInfo) Yap_AllocCodeSpace(sizeof(struct udi_info)); memset((void *) blk,0, sizeof(struct udi_info)); - if (!blk) { Yap_Error(OUT_OF_HEAP_ERROR, spec, "new user index/1"); return FALSE; } - utarray_new(blk->clauselist, &cl_icd); - utarray_new(blk->args, &arg_icd); - blk->p = p; - HASH_ADD_UdiInfo(UdiControlBlocks, p, blk); - //fprintf(stderr,"PRED %p\n",p); - info = Yap_udi_args_init(spec, p->ArityOfPE, blk); - if (!info) /*TODO: clear blk here*/ - return FALSE; + /*Init UdiInfo */ + utarray_new(blk->args, &arg_icd); + utarray_new(blk->clauselist, &cl_icd); + blk->p = p; + + /*Now Init args list*/ + info = p_udi_args_init(spec, p->ArityOfPE, blk); + if (!info) + { + utarray_free(blk->args); + utarray_free(blk->clauselist); + Yap_FreeCodeSpace((char *) blk); + return FALSE; + } + + /*Push into the hash*/ + HASH_ADD_UdiInfo(UdiControlBlocks, p, blk); p->PredFlags |= UDIPredFlag; + return TRUE; } /* * Here we initialize the arguments indexing */ -int -Yap_udi_args_init(Term spec, int arity, UdiInfo blk) +YAP_Int +p_udi_args_init(Term spec, int arity, UdiInfo blk) { int i; Term arg; Atom idxtype; - UdiControlBlock *p; + UdiControlBlock *cb; struct udi_p_args p_arg; - //fprintf(stderr,"udi init\n"); - for (i = 1; i <= arity; i++) { arg = ArgOfTerm(i,spec); if (IsAtomTerm(arg)) { idxtype = AtomOfTerm(arg); -// fprintf(stderr,"%p-%s %p-%s\n",idxtype, YAP_AtomName(idxtype), -// AtomMinus, YAP_AtomName(AtomMinus)); - if (idxtype == AtomMinus) + if (idxtype == AtomMinus) //skip this argument continue; p_arg.control = NULL; - p = NULL; - while ((p = (UdiControlBlock *) utarray_next(indexing_structures, p))) { - //fprintf(stderr,"cb: %p %p-%s\n", *p, (*p)->decl, YAP_AtomName((*p)->decl)); - if (idxtype == (*p)->decl){ + cb = NULL; + while ((cb = (UdiControlBlock *) utarray_next(indexing_structures, cb))) { + if (idxtype == (*cb)->decl){ p_arg.arg = i; - p_arg.control = *p; - p_arg.idxstr = (*p)->init(spec, i, arity); + p_arg.control = *cb; + p_arg.idxstr = (*cb)->init(spec, i, arity); utarray_push_back(blk->args, &p_arg); } } - if (p_arg.control == NULL){ /* not "-" and not found*/ + if (p_arg.control == NULL){ /* not "-" and not found */ fprintf(stderr, "Invalid Spec (%s)\n", AtomName(idxtype)); return FALSE; } @@ -140,36 +141,54 @@ Yap_udi_args_init(Term spec, int arity, UdiInfo blk) return TRUE; } -/* just pass info to user, called from cdmgr.c */ +/* + * From now on this is called in several places of yap + * when the predicate has the UDIPredFlag + * and is what actually triggers the insert/search/abolish of indexing structures + */ + +/* + * Init Yap udi interface + */ +void +Yap_udi_init(void) +{ + UdiControlBlocks = NULL; + + /*init indexing structures array*/ + utarray_new(indexing_structures, &udicb_icd); + + Yap_InitCPred("$udi_init", 1, p_new_udi, 0); + /* TODO: decide if udi.yap should be loaded automaticaly in init.yap */ +} + +/* called from cdmgr.c + * + * for each assert of a udipredicate + * to pass info to user structure + */ int Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) { int i; UdiPArg parg; UdiInfo info; - int index; -// yamop **x; + YAP_Int index; - /* try to find our structure*/ + /* try to find our structure */ HASH_FIND_UdiInfo(UdiControlBlocks,p,info); if (!info) return FALSE; - /*insert into clauselist will be used latter*/ + /* insert into clauselist */ utarray_push_back(info->clauselist, &cl); for (i = 0; i < utarray_len(info->args) ; i++) { parg = (UdiPArg) utarray_eltptr(info->args,i); - index = utarray_len(info->clauselist); -// x = (yamop **) utarray_eltptr(info->clauselist, index); -// fprintf(stderr,"Insert (%p %p %d) %d - %p %p %p\n", -// info->clauselist,info->clauselist->d,info->clauselist->icd.sz, -// index, -// cl, *x, *((yamop **) utarray_eltptr(info->clauselist, index))); + index = (YAP_Int) utarray_len(info->clauselist); parg->idxstr = parg->control->insert(parg->idxstr, t, parg->arg, (void *) index); - //info->cb = info->functions->insert(t, info->cb, (void *)cl); } return TRUE; } @@ -187,136 +206,158 @@ static inline int callback(void *key, void *data, void *arg) return TRUE; } -/* index, called from absmi.c */ +/* index, called from absmi.c + * + * Returns: + * NULL (yap fallback) No usable indexing available + * + * Yap_FAILCODE() (fail) No result found + * Yap_CauseListToClause(cl) 1 solution found + * Yap_ClauseListCode(cl) 2+ solutions found + */ yamop * Yap_udi_search(PredEntry *p) { - int i, r; + int r; struct ClauseList clauselist; -// struct CallbackM cm; -// callback_m_t c; UdiPArg parg; UdiInfo info; - Pvoid_t tmp, result; - Word_t count; - Word_t idx_r = 0L; - yamop **x; /* find our structure*/ HASH_FIND_UdiInfo(UdiControlBlocks,p,info); - if (!info) + if (!info || utarray_len(info->args) == 0) return NULL; -// /*TODO: handle intersection*/ -// c = &cm; -// c->cl = Yap_ClauseListInit(&clauselist); -// c->pred = p; + if (utarray_len(info->args) == 1){ //simple case no intersection needed + struct si_callback_h c; - /* - * I will start with the simplest case - * for each index create a set and intersect it with the - * next - */ - result = (Pvoid_t) NULL; - tmp = (Pvoid_t) NULL; - r = -1; - for (i = 0; i < utarray_len(info->args) ; i++) { -// fprintf(stderr,"Start Search\n"); - parg = (UdiPArg) utarray_eltptr(info->args,i); - r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp); + c.cl = Yap_ClauseListInit(&clauselist); + c.clauselist = info->clauselist; + c.pred = info->p; + if (!c.cl) + return NULL; - if (r == -1) /*this arg does not prune search*/ - continue; + parg = (UdiPArg) utarray_eltptr(info->args,0); + r = parg->control->search(parg->idxstr, parg->arg, si_callback, (void *) &c); + Yap_ClauseListClose(c.cl); - J1C(count, result, 0, -1); + if (r == -1) { + Yap_ClauseListDestroy(c.cl); + return NULL; + } - if (r == 0) - { - if (count > 0) // clear previous result if it exists - J1FA(count, result); - fprintf(stderr,"Search Failed"); + if (Yap_ClauseListCount(c.cl) == 0) { + Yap_ClauseListDestroy(c.cl); return Yap_FAILCODE(); } + } else {//intersection needed using Judy1 + /*TODO: do more tests to this algorithm*/ + int i; + Pvoid_t tmp = (Pvoid_t) NULL; + Pvoid_t result = (Pvoid_t) NULL; + Word_t count = 0L; + Word_t idx_r = 0L; + Word_t idx_tmp = 0L; + int rc = 0; + yamop **x; - if (r > 0 && count == 0) // first result_set - { - result = tmp; - tmp = (Pvoid_t) NULL; - } - else - {/*intersection*/ - Word_t idx_tmp = 0L; - - idx_r = 0L; - J1F(count, result, idx_r);//succeeds one time at least - J1F(count, tmp, idx_tmp); //succeeds one time at least - while (count) + /* + * I will start with the simplest approach + * for each index create a set and intersect it with the + * next + * + * In the future it could pay to sort according to index type + * to improve intersection part + */ + for (i = 0; i < utarray_len(info->args) ; i++) { + parg = (UdiPArg) utarray_eltptr(info->args,i); + r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp); + if (r == -1) /*this arg does not prune search*/ + continue; + rc ++; + J1C(count, result, 0, -1); + if (r == 0) /* this arg gave 0 results -> FAIL*/ { - while (idx_r < idx_tmp) + if (count > 0) // clear previous result if they exists + J1FA(count, result); + return Yap_FAILCODE(); + } + + if (count == 0) // first result_set + { + result = tmp; + tmp = (Pvoid_t) NULL; + } + else /*intersection*/ + { + idx_tmp = 0L; + idx_r = 0L; + J1F(count, result, idx_r); //succeeds one time at least + assert(count > 0); + J1F(count, tmp, idx_tmp); //succeeds one time at least + assert(count > 0); + while (count) + { + while (idx_r < idx_tmp) + { + J1U(count, result, idx_r); //does not belong + J1N(count, result, idx_r); //next + if (! count) break; //end result set + } + if(idx_r == idx_tmp) + { + J1N(count, result, idx_r); //next + if (! count) break; //end result set + J1N(count, tmp, idx_tmp); //next tmp + //if (! count) break; //end tmp set will break while + } + else // (idx_r > idx_tmp) + { + idx_tmp = idx_r; // fast forward + J1F(count, tmp, idx_tmp); // first starting in idx_r + //if (! count) break; //end tmp set will break while + } + } + J1F(count, result, idx_r); // first starting in idx_r + //clear up the rest + while (idx_r > idx_tmp && count) //result has more setted values { J1U(count, result, idx_r); //does not belong J1N(count, result, idx_r); //next - if (! count) break; //end result set - } - if(idx_r == idx_tmp) - { - J1N(count, result, idx_r); //next - if (! count) break; //end result set - J1N(count, tmp, idx_tmp); //next tmp - //if (! count) break; //end tmp set - } - else // (idx_r > idx_tmp) - { - idx_tmp = idx_r; // fast forward - J1F(count, tmp, idx_tmp); // first starting in idx_r - if (! count) break; //end tmp set } + J1FA(count, tmp); //free tmp } - J1F(count, result, idx_r); // first starting in idx_r - //clear up the rest - while (idx_r > idx_tmp && count) //result has more setted values - { - J1U(count, result, idx_r); //does not belong - J1N(count, result, idx_r); //next - } - J1FA(count, tmp); + } + if (rc == 0) /*no search performed*/ + return NULL; + + J1C(count, result, 0, -1); + if (count == 0) { /*result set empty -> FAIL */ + J1FA(count, result); + return Yap_FAILCODE(); } + /*convert Juddy1 to clauselist*/ + Yap_ClauseListInit(&clauselist); + idx_r = 0L; + J1F(count, result, idx_r); + while (count) + { + x = (yamop **) utarray_eltptr(info->clauselist, idx_r - 1); + Yap_ClauseListExtend( + &clauselist, + *x, + info->p); + J1N(count, result, idx_r); + } + J1FA(count,result); + fprintf(stderr,"J1 used space %d bytes for %d clausules\n", + count, Yap_ClauseListCount(&clauselist)); + Yap_ClauseListClose(&clauselist); } - - Yap_ClauseListInit(&clauselist); - idx_r = 0L; - J1F(count, result, idx_r); - while (count) - { - x = (yamop **) utarray_eltptr(info->clauselist, idx_r - 1); -// fprintf(stderr,"Clausule %d of %d: %p\n", -// idx_r, utarray_len(info->clauselist), -// *x); - Yap_ClauseListExtend( - &clauselist, - *x, - info->p); - J1N(count, result, idx_r); - } - J1FA(count,result); -// fprintf(stderr,"J1 used space %d bytes for %d clausules\n", -// count, Yap_ClauseListCount(&clauselist)); - Yap_ClauseListClose(&clauselist); - - if (Yap_ClauseListCount(&clauselist) == 0) - { - Yap_ClauseListDestroy(&clauselist); -// fprintf(stderr,"Search Not needed\n"); - return NULL; /*FAIL CODE handled before*/ - } if (Yap_ClauseListCount(&clauselist) == 1) - { -// fprintf(stderr,"Returning 1 value\n"); return Yap_ClauseListToClause(&clauselist); - } -// fprintf(stderr,"Returning Multiple values (%d)\n", Yap_ClauseListCount(&clauselist)); return Yap_ClauseListCode(&clauselist); } @@ -326,18 +367,3 @@ Yap_udi_abolish(PredEntry *p) { /* tell the predicate destroy */ } - -/* - * Init Yap udi interface - */ -void -Yap_udi_init(void) -{ - UdiControlBlocks = NULL; - - /*init indexing structures array*/ - utarray_new(indexing_structures, &udicb_icd); - - Yap_InitCPred("$udi_init", 1, p_new_udi, 0); - /* TODO: decide if udi.yap should be loaded automaticaly in init.yap */ -} diff --git a/H/clause.h b/H/clause.h index 49e6da61d..d80e14002 100644 --- a/H/clause.h +++ b/H/clause.h @@ -332,8 +332,9 @@ Term STD_PROTO(Yap_LUInstance,(LogUpdClause *, UInt)); /* udi.c */ void STD_PROTO(Yap_udi_init,(void)); -yamop *STD_PROTO(Yap_udi_search,(PredEntry *)); int STD_PROTO(Yap_new_udi_clause,(PredEntry *, yamop *, Term)); +yamop *STD_PROTO(Yap_udi_search,(PredEntry *)); +void STD_PROTO(Yap_udi_abolish,(PredEntry *p)); #ifdef DEBUG void STD_PROTO(Yap_bug_location,(yamop *)); diff --git a/H/udi_private.h b/H/udi_private.h index e77455ae5..9e0bf8597 100644 --- a/H/udi_private.h +++ b/H/udi_private.h @@ -11,10 +11,7 @@ struct udi_p_args { typedef struct udi_p_args *UdiPArg; UT_icd arg_icd = {sizeof(struct udi_p_args), NULL, NULL, NULL }; -/* a pointer utarray list - * This is a hack, becouse I do no know the real type of clauses - * Not completely used for now - */ +/* clauselist */ UT_icd cl_icd = {sizeof(yamop *), NULL, NULL, NULL }; /* @@ -26,30 +23,38 @@ struct udi_info PredEntry *p; //predicate (need to identify asserts) UT_array *clauselist; //clause list used on returns UT_array *args; //indexed args - UT_hash_handle hh; + UT_hash_handle hh; //uthash handle }; typedef struct udi_info *UdiInfo; /* to ease code for a UdiInfo hash table*/ -#define HASH_FIND_UdiInfo(head,find,out) \ +#define HASH_FIND_UdiInfo(head,find,out) \ HASH_FIND(hh,head,find,sizeof(PredEntry *),out) #define HASH_ADD_UdiInfo(head,p,add) \ HASH_ADD_KEYPTR(hh,head,p,sizeof(PredEntry *),add) -int Yap_udi_args_init(Term spec, int arity, UdiInfo blk); +/* used during init */ +static YAP_Int p_new_udi( USES_REGS1 ); +static YAP_Int p_udi_args_init(Term spec, int arity, UdiInfo blk); -///* temporary */ -//struct CallbackM -//{ -// clause_list_t cl; -// void * pred; -//}; -//typedef struct CallbackM * callback_m_t; -// -//static inline int callback(void *key, void *data, void *arg) -//{ -// callback_m_t x; -// x = (callback_m_t) arg; -// return Yap_ClauseListExtend(x->cl,data,x->pred); -//} +/* + * Indexing Search and intersection Helpers + */ +/* single indexing helpers (no intersection needed just create clauselist) */ +#include "clause_list.h" +struct si_callback_h +{ + clause_list_t cl; + UT_array *clauselist; + void * pred; +}; +typedef struct si_callback_h * si_callback_h_t; + +static inline int si_callback(void *key, void *data, void *arg) +{ + si_callback_h_t c = (si_callback_h_t) arg; + yamop **cl = (yamop **) utarray_eltptr(c->clauselist, ((YAP_Int) data) - 1); + return Yap_ClauseListExtend(c->cl, *cl, c->pred); +} +/* Judy1 integer sparse set intersection */ diff --git a/include/udi.h b/include/udi.h index d7df3d96f..a7b428ec9 100644 --- a/include/udi.h +++ b/include/udi.h @@ -52,7 +52,7 @@ typedef int (* Yap_UdiCallback) /* Called upon search * - * If there is any search to do with this struture should return >= 0 + * If there is any search to do with this structure should return >= 0 * corresponding to the values found * * returns -1 if there is nothing to search with this indexing structure @@ -62,9 +62,9 @@ typedef int (* Yap_UdiSearch) (void * control, /* indexing structure opaque handle */ int arg, /* argument regarding this call */ Yap_UdiCallback f, /* callback on each found value */ - void *args); /* auxiliary data to callback */ + void *args); /* auxiliary data to callback */ -/* Called upond abolish of the term +/* Called upon abolish of the term * to allow for a clean destroy of the indexing structures */ typedef int (* Yap_UdiDestroy) From a9cacc7b33ce1f3b96b3d33865319fee65b57901 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Wed, 2 Jan 2013 12:10:11 +0000 Subject: [PATCH 09/10] Changes to autoconfigure libjudy in udi --- C/udi.c | 22 ++-- H/udi_private.h | 14 +++ config.h.in | 7 ++ configure | 317 +++++++++++++++++++++++++++++++----------------- configure.in | 19 ++- 5 files changed, 250 insertions(+), 129 deletions(-) diff --git a/C/udi.c b/C/udi.c index b91b59f3e..48fcec985 100644 --- a/C/udi.c +++ b/C/udi.c @@ -1,6 +1,5 @@ #include #include -#include #include "Yap.h" #include "YapInterface.h" #include "clause.h" @@ -193,19 +192,6 @@ Yap_new_udi_clause(PredEntry *p, yamop *cl, Term t) return TRUE; } -static inline int callback(void *key, void *data, void *arg) -{ - int r; - Pvoid_t *array = (Pvoid_t *) arg; -// fprintf(stderr,"Found %p %d",data, (int) data); - J1S(r, *array, (int) data); - if (r == JERR) - return FALSE; - J1C(r, *array, 0 , -1); -// fprintf(stderr," (%d)\n",r); - return TRUE; -} - /* index, called from absmi.c * * Returns: @@ -251,6 +237,7 @@ Yap_udi_search(PredEntry *p) return Yap_FAILCODE(); } } else {//intersection needed using Judy1 +#ifdef USE_JUDY /*TODO: do more tests to this algorithm*/ int i; Pvoid_t tmp = (Pvoid_t) NULL; @@ -271,7 +258,7 @@ Yap_udi_search(PredEntry *p) */ for (i = 0; i < utarray_len(info->args) ; i++) { parg = (UdiPArg) utarray_eltptr(info->args,i); - r = parg->control->search(parg->idxstr, parg->arg, callback, &tmp); + r = parg->control->search(parg->idxstr, parg->arg, j1_callback, &tmp); if (r == -1) /*this arg does not prune search*/ continue; rc ++; @@ -354,6 +341,11 @@ Yap_udi_search(PredEntry *p) fprintf(stderr,"J1 used space %d bytes for %d clausules\n", count, Yap_ClauseListCount(&clauselist)); Yap_ClauseListClose(&clauselist); +#else + fprintf(stderr,"Without libJudy only one argument indexed is allowed." + "Falling back to Yap Indexing\n"); + return NULL; //NO Judy Available +#endif } if (Yap_ClauseListCount(&clauselist) == 1) diff --git a/H/udi_private.h b/H/udi_private.h index 9e0bf8597..df61dc182 100644 --- a/H/udi_private.h +++ b/H/udi_private.h @@ -1,3 +1,4 @@ +#include "config.h" #include "udi.h" #include "utarray.h" #include "uthash.h" @@ -57,4 +58,17 @@ static inline int si_callback(void *key, void *data, void *arg) yamop **cl = (yamop **) utarray_eltptr(c->clauselist, ((YAP_Int) data) - 1); return Yap_ClauseListExtend(c->cl, *cl, c->pred); } + +#ifdef USE_JUDY +#include /* Judy1 integer sparse set intersection */ +static inline int j1_callback(void *key, void *data, void *arg) +{ + int r; + Pvoid_t *array = (Pvoid_t *) arg; + J1S(r, *array, (int) data); + if (r == JERR) + return FALSE; + return TRUE; +} +#endif diff --git a/config.h.in b/config.h.in index 107ec7063..d270df6ad 100755 --- a/config.h.in +++ b/config.h.in @@ -24,6 +24,8 @@ /* Should we use gmp ? */ #undef HAVE_LIBGMP +#undef HAVE_LIBJUDY + /* What MPI libraries are there? */ #define HAVE_LIBMPI 0 #define HAVE_LIBMPICH @@ -67,6 +69,7 @@ #undef HAVE_GMP_H #undef HAVE_IEEEFP_H #undef HAVE_IO_H +#undef HAVE_JUDY_H #undef HAVE_LIMITS_H #undef HAVE_LOCALE_H #undef HAVE_MACH_O_DYLD_H @@ -326,6 +329,10 @@ #define USE_GMP 1 #endif +#if HAVE_JUDY_H && HAVE_LIBJUDY +#define USE_JUDY 1 +#endif + /* Should we use MPI ? */ #if defined(HAVE_MPI_H) && (defined(HAVE_LIBMPI) || defined(HAVE_LIBMPICH)) #define HAVE_MPI 1 diff --git a/configure b/configure index 509f2e2a8..1aa51ba48 100755 --- a/configure +++ b/configure @@ -1,11 +1,9 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68. +# Generated by GNU Autoconf 2.69. # # -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -# Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -134,6 +132,31 @@ export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh @@ -167,7 +190,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi -test x\$exitcode = x0 || exit 1" +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && @@ -212,21 +236,25 @@ IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : - # We cannot yet assume a decent shell, so we have to provide a - # neutralization value for shells without unset; and this also - # works around shells that cannot unset nonexistent variables. - # Preserve -v and -x to the replacement shell. - BASH_ENV=/dev/null - ENV=/dev/null - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV - export CONFIG_SHELL - case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; - esac - exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi if test x$as_have_required = xno; then : @@ -328,6 +356,14 @@ $as_echo X"$as_dir" | } # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take @@ -449,6 +485,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). @@ -483,16 +523,16 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -504,28 +544,8 @@ else as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -829,6 +849,7 @@ enable_clpbn_bp with_gmp with_R with_python +with_judy with_minisat with_cudd enable_myddas @@ -1315,8 +1336,6 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1513,6 +1532,7 @@ Optional Packages: --with-gmp=DIR use GNU Multiple Precision in DIR --with-R=DIR interface to R language --with-python=DIR interface to R language + --with-judy=DIR UDI needs judy library --enable-minisat use minisat interface --with-cudd=DIR use CUDD package in DIR --with-java=JAVA_HOME use Java instalation in JAVA_HOME @@ -1607,9 +1627,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.68 +generated by GNU Autoconf 2.69 -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1920,7 +1940,7 @@ $as_echo "$ac_try_echo"; } >&5 test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext + test -x conftest$ac_exeext }; then : ac_retval=0 else @@ -2023,7 +2043,8 @@ int main () { static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2039,7 +2060,8 @@ int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2065,7 +2087,8 @@ int main () { static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2081,7 +2104,8 @@ int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2115,7 +2139,8 @@ int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0 +test_array [0] = 0; +return test_array [0]; ; return 0; @@ -2299,7 +2324,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2675,7 +2700,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2715,7 +2740,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2768,7 +2793,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2809,7 +2834,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue @@ -2867,7 +2892,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2911,7 +2936,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3357,8 +3382,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); @@ -3471,7 +3495,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3515,7 +3539,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3718,7 +3742,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -4068,7 +4092,7 @@ do for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in @@ -4134,7 +4158,7 @@ do for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in @@ -4695,6 +4719,21 @@ fi +# Check whether --with-judy was given. +if test "${with_judy+set}" = set; then : + withval=$with_judy; if test "$withval" = yes; then + yap_cv_judy=yes + elif test "$withval" = no; then + yap_cv_judy=no + else + yap_cv_judy=$withval + fi +else + yap_cv_judy=yes +fi + + + # Check whether --with-minisat was given. if test "${with_minisat+set}" = set; then : withval=$with_minisat; if test "$withval" = yes; then @@ -5256,7 +5295,7 @@ case $as_dir/ in #(( # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. @@ -5329,7 +5368,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5369,7 +5408,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5421,7 +5460,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_INDENT="${ac_tool_prefix}indent" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5461,7 +5500,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_INDENT="indent" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5513,7 +5552,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5553,7 +5592,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5605,7 +5644,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MPI_CC="${ac_tool_prefix}mpicc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5645,7 +5684,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MPI_CC="mpicc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5699,7 +5738,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_INSTALL_INFO="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -5740,7 +5779,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SHELL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6730,7 +6769,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_REXE="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6851,7 +6890,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PYTHON="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -6889,6 +6928,56 @@ else ENABLE_PYTHON="@# " fi +if test "$yap_cv_judy" != "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Judy1Set in -lJudy" >&5 +$as_echo_n "checking for Judy1Set in -lJudy... " >&6; } +if ${ac_cv_lib_Judy_Judy1Set+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lJudy $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char Judy1Set (); +int +main () +{ +return Judy1Set (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_Judy_Judy1Set=yes +else + ac_cv_lib_Judy_Judy1Set=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Judy_Judy1Set" >&5 +$as_echo "$ac_cv_lib_Judy_Judy1Set" >&6; } +if test "x$ac_cv_lib_Judy_Judy1Set" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBJUDY 1 +_ACEOF + + LIBS="-lJudy $LIBS" + +else + as_fn_error $? "libJudy not found, UDI will only work with one Index at a time" "$LINENO" 5 +fi + +fi + if test "$yap_cv_myddas" != "no" then @@ -9164,6 +9253,20 @@ fi done +fi +if test "$yap_cv_judy" != "no"; then + for ac_header in Judy.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "Judy.h" "ac_cv_header_Judy_h" "$ac_includes_default" +if test "x$ac_cv_header_Judy_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_JUDY_H 1 +_ACEOF + +fi + +done + fi if test "$yap_cv_myddas" != "no" then @@ -11832,16 +11935,16 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -11901,28 +12004,16 @@ else as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -11944,7 +12035,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -12006,10 +12097,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.68, +configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -12099,7 +12190,7 @@ fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' diff --git a/configure.in b/configure.in index db505b1ef..cf3dd11eb 100755 --- a/configure.in +++ b/configure.in @@ -254,8 +254,18 @@ AC_ARG_WITH(python, yap_cv_python=$withval fi, [yap_cv_python=no]) + +AC_ARG_WITH(judy, + [ --with-judy[=DIR] UDI needs judy library], + if test "$withval" = yes; then + yap_cv_judy=yes + elif test "$withval" = no; then + yap_cv_judy=no + else + yap_cv_judy=$withval + fi, + [yap_cv_judy=yes]) -dnl best test we could do. AC_ARG_WITH(minisat, [ --enable-minisat use minisat interface], if test "$withval" = yes; then @@ -870,6 +880,10 @@ else ENABLE_PYTHON="@# " fi +if test "$yap_cv_judy" != "no"; then + AC_CHECK_LIB(Judy, Judy1Set,,[AC_MSG_ERROR([libJudy not found, UDI will only work with one Index at a time])]) +fi + dnl if test "$yap_cv_cudd" != "no" dnl then dnl AC_CHECK_LIB(cudd,Cudd_Init) @@ -1707,6 +1721,9 @@ if test "$yap_cv_gmp" != "no" then AC_CHECK_HEADERS(gmp.h) fi +if test "$yap_cv_judy" != "no"; then + AC_CHECK_HEADERS(Judy.h) +fi if test "$yap_cv_myddas" != "no" then AC_CHECK_HEADERS(mysql/mysql.h) From 5c83be965abeaa8b8a330656c815330c617cee54 Mon Sep 17 00:00:00 2001 From: David Vaz Date: Mon, 7 Jan 2013 16:41:51 +0000 Subject: [PATCH 10/10] Added eclipse to ignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index f30fde5d9..14b395f06 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,8 @@ *.dylib docs/yap.info* .build + +.cproject +.project +.settings +autom4te.cache \ No newline at end of file