123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383 |
- /*<html><pre> -<a href="qh-set_r.htm"
- >-------------------------------</a><a name="TOP">-</a>
- qset_r.c
- implements set manipulations needed for quickhull
- see qh-set_r.htm and qset_r.h
- Be careful of strict aliasing (two pointers of different types
- that reference the same location). The last slot of a set is
- either the actual size of the set plus 1, or the NULL terminator
- of the set (i.e., setelemT).
- Only reference qh for qhmem or qhstat. Otherwise the matching code in qset.c will bring in qhT
- Copyright (c) 1993-2020 The Geometry Center.
- $Id: //main/2019/qhull/src/libqhull_r/qset_r.c#8 $$Change: 2953 $
- $DateTime: 2020/05/21 22:05:32 $$Author: bbarber $
- */
- #include "libqhull_r.h" /* for qhT and QHULL_CRTDBG */
- #include "qset_r.h"
- #include "mem_r.h"
- #include <stdio.h>
- #include <string.h>
- /*** uncomment here and qhull_ra.h
- if string.h does not define memcpy()
- #include <memory.h>
- */
- #ifndef qhDEFlibqhull
- typedef struct ridgeT ridgeT;
- typedef struct facetT facetT;
- void qh_errexit(qhT *qh, int exitcode, facetT *, ridgeT *);
- void qh_fprintf(qhT *qh, FILE *fp, int msgcode, const char *fmt, ... );
- # ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */
- # pragma warning( disable : 4127) /* conditional expression is constant */
- # pragma warning( disable : 4706) /* assignment within conditional function */
- # endif
- #endif
- /*=============== internal macros ===========================*/
- /*============ functions in alphabetical order ===================*/
- /*-<a href="qh-set_r.htm#TOC"
- >--------------------------------<a name="setaddnth">-</a>
- qh_setaddnth(qh, setp, nth, newelem )
- adds newelem as n'th element of sorted or unsorted *setp
- notes:
- *setp and newelem must be defined
- *setp may be a temp set
- nth=0 is first element
- errors if nth is out of bounds
- design:
- expand *setp if empty or full
- move tail of *setp up one
- insert newelem
- */
- void qh_setaddnth(qhT *qh, setT **setp, int nth, void *newelem) {
- int oldsize, i;
- setelemT *sizep; /* avoid strict aliasing */
- setelemT *oldp, *newp;
- if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
- qh_setlarger(qh, setp);
- sizep= SETsizeaddr_(*setp);
- }
- oldsize= sizep->i - 1;
- if (nth < 0 || nth > oldsize) {
- qh_fprintf(qh, qh->qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
- qh_setprint(qh, qh->qhmem.ferr, "", *setp);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- sizep->i++;
- oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void); /* NULL */
- newp= oldp+1;
- for (i=oldsize-nth+1; i--; ) /* move at least NULL */
- (newp--)->p= (oldp--)->p; /* may overwrite *sizep */
- newp->p= newelem;
- } /* setaddnth */
- /*-<a href="qh-set_r.htm#TOC"
- >--------------------------------<a name="setaddsorted">-</a>
- setaddsorted( setp, newelem )
- adds an newelem into sorted *setp
- notes:
- *setp and newelem must be defined
- *setp may be a temp set
- nop if newelem already in set
- design:
- find newelem's position in *setp
- insert newelem
- */
- void qh_setaddsorted(qhT *qh, setT **setp, void *newelem) {
- int newindex=0;
- void *elem, **elemp;
- FOREACHelem_(*setp) { /* could use binary search instead */
- if (elem < newelem)
- newindex++;
- else if (elem == newelem)
- return;
- else
- break;
- }
- qh_setaddnth(qh, setp, newindex, newelem);
- } /* setaddsorted */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setappend">-</a>
- qh_setappend(qh, setp, newelem )
- append newelem to *setp
- notes:
- *setp may be a temp set
- *setp and newelem may be NULL
- design:
- expand *setp if empty or full
- append newelem to *setp
- */
- void qh_setappend(qhT *qh, setT **setp, void *newelem) {
- setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */
- setelemT *endp;
- int count;
- if (!newelem)
- return;
- if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
- qh_setlarger(qh, setp);
- sizep= SETsizeaddr_(*setp);
- }
- count= (sizep->i)++ - 1;
- endp= (setelemT *)SETelemaddr_(*setp, count, void);
- (endp++)->p= newelem;
- endp->p= NULL;
- } /* setappend */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setappend_set">-</a>
- qh_setappend_set(qh, setp, setA )
- appends setA to *setp
- notes:
- *setp can not be a temp set
- *setp and setA may be NULL
- design:
- setup for copy
- expand *setp if it is too small
- append all elements of setA to *setp
- */
- void qh_setappend_set(qhT *qh, setT **setp, setT *setA) {
- int sizeA, size;
- setT *oldset;
- setelemT *sizep;
- if (!setA)
- return;
- SETreturnsize_(setA, sizeA);
- if (!*setp)
- *setp= qh_setnew(qh, sizeA);
- sizep= SETsizeaddr_(*setp);
- if (!(size= sizep->i))
- size= (*setp)->maxsize;
- else
- size--;
- if (size + sizeA > (*setp)->maxsize) {
- oldset= *setp;
- *setp= qh_setcopy(qh, oldset, sizeA);
- qh_setfree(qh, &oldset);
- sizep= SETsizeaddr_(*setp);
- }
- if (sizeA > 0) {
- sizep->i= size+sizeA+1; /* memcpy may overwrite */
- memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
- }
- } /* setappend_set */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setappend2ndlast">-</a>
- qh_setappend2ndlast(qh, setp, newelem )
- makes newelem the next to the last element in *setp
- notes:
- *setp must have at least one element
- newelem must be defined
- *setp may be a temp set
- design:
- expand *setp if empty or full
- move last element of *setp up one
- insert newelem
- */
- void qh_setappend2ndlast(qhT *qh, setT **setp, void *newelem) {
- setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */
- setelemT *endp, *lastp;
- int count;
- if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
- qh_setlarger(qh, setp);
- sizep= SETsizeaddr_(*setp);
- }
- count= (sizep->i)++ - 1;
- endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
- lastp= endp-1;
- *(endp++)= *lastp;
- endp->p= NULL; /* may overwrite *sizep */
- lastp->p= newelem;
- } /* setappend2ndlast */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setcheck">-</a>
- qh_setcheck(qh, set, typename, id )
- check set for validity
- report errors with typename and id
- design:
- checks that maxsize, actual size, and NULL terminator agree
- */
- void qh_setcheck(qhT *qh, setT *set, const char *tname, unsigned int id) {
- int maxsize, size;
- int waserr= 0;
- if (!set)
- return;
- SETreturnsize_(set, size);
- maxsize= set->maxsize;
- if (size > maxsize || !maxsize) {
- qh_fprintf(qh, qh->qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
- size, tname, id, maxsize);
- waserr= 1;
- }else if (set->e[size].p) {
- qh_fprintf(qh, qh->qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
- tname, id, size-1, maxsize);
- waserr= 1;
- }
- if (waserr) {
- qh_setprint(qh, qh->qhmem.ferr, "ERRONEOUS", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- } /* setcheck */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setcompact">-</a>
- qh_setcompact(qh, set )
- remove internal NULLs from an unsorted set
- returns:
- updated set
- notes:
- set may be NULL
- it would be faster to swap tail of set into holes, like qh_setdel
- design:
- setup pointers into set
- skip NULLs while copying elements to start of set
- update the actual size
- */
- void qh_setcompact(qhT *qh, setT *set) {
- int size;
- void **destp, **elemp, **endp, **firstp;
- if (!set)
- return;
- SETreturnsize_(set, size);
- destp= elemp= firstp= SETaddr_(set, void);
- endp= destp + size;
- while (1) {
- if (!(*destp++= *elemp++)) {
- destp--;
- if (elemp > endp)
- break;
- }
- }
- qh_settruncate(qh, set, (int)(destp-firstp)); /* WARN64 */
- } /* setcompact */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setcopy">-</a>
- qh_setcopy(qh, set, extra )
- make a copy of a sorted or unsorted set with extra slots
- returns:
- new set
- design:
- create a newset with extra slots
- copy the elements to the newset
- */
- setT *qh_setcopy(qhT *qh, setT *set, int extra) {
- setT *newset;
- int size;
- if (extra < 0)
- extra= 0;
- SETreturnsize_(set, size);
- newset= qh_setnew(qh, size+extra);
- SETsizeaddr_(newset)->i= size+1; /* memcpy may overwrite */
- memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
- return(newset);
- } /* setcopy */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setdel">-</a>
- qh_setdel(set, oldelem )
- delete oldelem from an unsorted set
- returns:
- returns oldelem if found
- returns NULL otherwise
- notes:
- set may be NULL
- oldelem must not be NULL;
- only deletes one copy of oldelem in set
- design:
- locate oldelem
- update actual size if it was full
- move the last element to the oldelem's location
- */
- void *qh_setdel(setT *set, void *oldelem) {
- setelemT *sizep;
- setelemT *elemp;
- setelemT *lastp;
- if (!set)
- return NULL;
- elemp= (setelemT *)SETaddr_(set, void);
- while (elemp->p != oldelem && elemp->p)
- elemp++;
- if (elemp->p) {
- sizep= SETsizeaddr_(set);
- if (!(sizep->i)--) /* if was a full set */
- sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
- lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
- elemp->p= lastp->p; /* may overwrite itself */
- lastp->p= NULL;
- return oldelem;
- }
- return NULL;
- } /* setdel */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setdellast">-</a>
- qh_setdellast( set )
- return last element of set or NULL
- notes:
- deletes element from set
- set may be NULL
- design:
- return NULL if empty
- if full set
- delete last element and set actual size
- else
- delete last element and update actual size
- */
- void *qh_setdellast(setT *set) {
- int setsize; /* actually, actual_size + 1 */
- int maxsize;
- setelemT *sizep;
- void *returnvalue;
- if (!set || !(set->e[0].p))
- return NULL;
- sizep= SETsizeaddr_(set);
- if ((setsize= sizep->i)) {
- returnvalue= set->e[setsize - 2].p;
- set->e[setsize - 2].p= NULL;
- sizep->i--;
- }else {
- maxsize= set->maxsize;
- returnvalue= set->e[maxsize - 1].p;
- set->e[maxsize - 1].p= NULL;
- sizep->i= maxsize;
- }
- return returnvalue;
- } /* setdellast */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setdelnth">-</a>
- qh_setdelnth(qh, set, nth )
- deletes nth element from unsorted set
- 0 is first element
- returns:
- returns the element (needs type conversion)
- notes:
- errors if nth invalid
- design:
- setup points and check nth
- delete nth element and overwrite with last element
- */
- void *qh_setdelnth(qhT *qh, setT *set, int nth) {
- void *elem;
- setelemT *sizep;
- setelemT *elemp, *lastp;
- sizep= SETsizeaddr_(set);
- if ((sizep->i--)==0) /* if was a full set */
- sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */
- if (nth < 0 || nth >= sizep->i) {
- qh_fprintf(qh, qh->qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
- qh_setprint(qh, qh->qhmem.ferr, "", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- elemp= (setelemT *)SETelemaddr_(set, nth, void); /* nth valid by QH6174 */
- lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
- elem= elemp->p;
- elemp->p= lastp->p; /* may overwrite itself */
- lastp->p= NULL;
- return elem;
- } /* setdelnth */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setdelnthsorted">-</a>
- qh_setdelnthsorted(qh, set, nth )
- deletes nth element from sorted set
- returns:
- returns the element (use type conversion)
- notes:
- errors if nth invalid
- see also:
- setnew_delnthsorted
- design:
- setup points and check nth
- copy remaining elements down one
- update actual size
- */
- void *qh_setdelnthsorted(qhT *qh, setT *set, int nth) {
- void *elem;
- setelemT *sizep;
- setelemT *newp, *oldp;
- sizep= SETsizeaddr_(set);
- if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
- qh_fprintf(qh, qh->qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
- qh_setprint(qh, qh->qhmem.ferr, "", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- newp= (setelemT *)SETelemaddr_(set, nth, void);
- elem= newp->p;
- oldp= newp+1;
- while (((newp++)->p= (oldp++)->p))
- ; /* copy remaining elements and NULL */
- if ((sizep->i--)==0) /* if was a full set */
- sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */
- return elem;
- } /* setdelnthsorted */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setdelsorted">-</a>
- qh_setdelsorted( set, oldelem )
- deletes oldelem from sorted set
- returns:
- returns oldelem if it was deleted
- notes:
- set may be NULL
- design:
- locate oldelem in set
- copy remaining elements down one
- update actual size
- */
- void *qh_setdelsorted(setT *set, void *oldelem) {
- setelemT *sizep;
- setelemT *newp, *oldp;
- if (!set)
- return NULL;
- newp= (setelemT *)SETaddr_(set, void);
- while(newp->p != oldelem && newp->p)
- newp++;
- if (newp->p) {
- oldp= newp+1;
- while (((newp++)->p= (oldp++)->p))
- ; /* copy remaining elements */
- sizep= SETsizeaddr_(set);
- if ((sizep->i--)==0) /* if was a full set */
- sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */
- return oldelem;
- }
- return NULL;
- } /* setdelsorted */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setduplicate">-</a>
- qh_setduplicate(qh, set, elemsize )
- duplicate a set of elemsize elements
- notes:
- use setcopy if retaining old elements
- design:
- create a new set
- for each elem of the old set
- create a newelem
- append newelem to newset
- */
- setT *qh_setduplicate(qhT *qh, setT *set, int elemsize) {
- void *elem, **elemp, *newElem;
- setT *newSet;
- int size;
- if (!(size= qh_setsize(qh, set)))
- return NULL;
- newSet= qh_setnew(qh, size);
- FOREACHelem_(set) {
- newElem= qh_memalloc(qh, elemsize);
- memcpy(newElem, elem, (size_t)elemsize);
- qh_setappend(qh, &newSet, newElem);
- }
- return newSet;
- } /* setduplicate */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setendpointer">-</a>
- qh_setendpointer( set )
- Returns pointer to NULL terminator of a set's elements
- set can not be NULL
- */
- void **qh_setendpointer(setT *set) {
- setelemT *sizep= SETsizeaddr_(set);
- int n= sizep->i;
- return (n ? &set->e[n-1].p : &sizep->p);
- } /* qh_setendpointer */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setequal">-</a>
- qh_setequal( setA, setB )
- returns 1 if two sorted sets are equal, otherwise returns 0
- notes:
- either set may be NULL
- design:
- check size of each set
- setup pointers
- compare elements of each set
- */
- int qh_setequal(setT *setA, setT *setB) {
- void **elemAp, **elemBp;
- int sizeA= 0, sizeB= 0;
- if (setA) {
- SETreturnsize_(setA, sizeA);
- }
- if (setB) {
- SETreturnsize_(setB, sizeB);
- }
- if (sizeA != sizeB)
- return 0;
- if (!sizeA)
- return 1;
- elemAp= SETaddr_(setA, void);
- elemBp= SETaddr_(setB, void);
- if (!memcmp((char *)elemAp, (char *)elemBp, (size_t)(sizeA * SETelemsize)))
- return 1;
- return 0;
- } /* setequal */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setequal_except">-</a>
- qh_setequal_except( setA, skipelemA, setB, skipelemB )
- returns 1 if sorted setA and setB are equal except for skipelemA & B
- returns:
- false if either skipelemA or skipelemB are missing
- notes:
- neither set may be NULL
- if skipelemB is NULL,
- can skip any one element of setB
- design:
- setup pointers
- search for skipelemA, skipelemB, and mismatches
- check results
- */
- int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
- void **elemA, **elemB;
- int skip=0;
- elemA= SETaddr_(setA, void);
- elemB= SETaddr_(setB, void);
- while (1) {
- if (*elemA == skipelemA) {
- skip++;
- elemA++;
- }
- if (skipelemB) {
- if (*elemB == skipelemB) {
- skip++;
- elemB++;
- }
- }else if (*elemA != *elemB) {
- skip++;
- if (!(skipelemB= *elemB++))
- return 0;
- }
- if (!*elemA)
- break;
- if (*elemA++ != *elemB++)
- return 0;
- }
- if (skip != 2 || *elemB)
- return 0;
- return 1;
- } /* setequal_except */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setequal_skip">-</a>
- qh_setequal_skip( setA, skipA, setB, skipB )
- returns 1 if sorted setA and setB are equal except for elements skipA & B
- returns:
- false if different size
- notes:
- neither set may be NULL
- design:
- setup pointers
- search for mismatches while skipping skipA and skipB
- */
- int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
- void **elemA, **elemB, **skipAp, **skipBp;
- elemA= SETaddr_(setA, void);
- elemB= SETaddr_(setB, void);
- skipAp= SETelemaddr_(setA, skipA, void);
- skipBp= SETelemaddr_(setB, skipB, void);
- while (1) {
- if (elemA == skipAp)
- elemA++;
- if (elemB == skipBp)
- elemB++;
- if (!*elemA)
- break;
- if (*elemA++ != *elemB++)
- return 0;
- }
- if (*elemB)
- return 0;
- return 1;
- } /* setequal_skip */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setfree">-</a>
- qh_setfree(qh, setp )
- frees the space occupied by a sorted or unsorted set
- returns:
- sets setp to NULL
- notes:
- set may be NULL
- design:
- free array
- free set
- */
- void qh_setfree(qhT *qh, setT **setp) {
- int size;
- void **freelistp; /* used if !qh_NOmem by qh_memfree_() */
- if (*setp) {
- size= (int)sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
- if (size <= qh->qhmem.LASTsize) {
- qh_memfree_(qh, *setp, size, freelistp);
- }else
- qh_memfree(qh, *setp, size);
- *setp= NULL;
- }
- } /* setfree */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setfree2">-</a>
- qh_setfree2(qh, setp, elemsize )
- frees the space occupied by a set and its elements
- notes:
- set may be NULL
- design:
- free each element
- free set
- */
- void qh_setfree2(qhT *qh, setT **setp, int elemsize) {
- void *elem, **elemp;
- FOREACHelem_(*setp)
- qh_memfree(qh, elem, elemsize);
- qh_setfree(qh, setp);
- } /* setfree2 */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setfreelong">-</a>
- qh_setfreelong(qh, setp )
- frees a set only if it's in long memory
- returns:
- sets setp to NULL if it is freed
- notes:
- set may be NULL
- design:
- if set is large
- free it
- */
- void qh_setfreelong(qhT *qh, setT **setp) {
- int size;
- if (*setp) {
- size= (int)sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
- if (size > qh->qhmem.LASTsize) {
- qh_memfree(qh, *setp, size);
- *setp= NULL;
- }
- }
- } /* setfreelong */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setin">-</a>
- qh_setin( set, setelem )
- returns 1 if setelem is in a set, 0 otherwise
- notes:
- set may be NULL or unsorted
- design:
- scans set for setelem
- */
- int qh_setin(setT *set, void *setelem) {
- void *elem, **elemp;
- FOREACHelem_(set) {
- if (elem == setelem)
- return 1;
- }
- return 0;
- } /* setin */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setindex">-</a>
- qh_setindex(set, atelem )
- returns the index of atelem in set.
- returns -1, if not in set or maxsize wrong
- notes:
- set may be NULL and may contain nulls.
- NOerrors returned (qh_pointid, QhullPoint::id)
- design:
- checks maxsize
- scans set for atelem
- */
- int qh_setindex(setT *set, void *atelem) {
- void **elem;
- int size, i;
- if (!set)
- return -1;
- SETreturnsize_(set, size);
- if (size > set->maxsize)
- return -1;
- elem= SETaddr_(set, void);
- for (i=0; i < size; i++) {
- if (*elem++ == atelem)
- return i;
- }
- return -1;
- } /* setindex */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setlarger">-</a>
- qh_setlarger(qh, oldsetp )
- returns a larger set that contains all elements of *oldsetp
- notes:
- if long memory,
- the new set is 2x larger
- if qhmem.LASTsize is between 1.5x and 2x
- the new set is qhmem.LASTsize
- otherwise use quick memory,
- the new set is 2x larger, rounded up to next qh_memsize
-
- if temp set, updates qh->qhmem.tempstack
- design:
- creates a new set
- copies the old set to the new set
- updates pointers in tempstack
- deletes the old set
- */
- void qh_setlarger(qhT *qh, setT **oldsetp) {
- int setsize= 1, newsize;
- setT *newset, *set, **setp, *oldset;
- setelemT *sizep;
- setelemT *newp, *oldp;
- if (*oldsetp) {
- oldset= *oldsetp;
- SETreturnsize_(oldset, setsize);
- qh->qhmem.cntlarger++;
- qh->qhmem.totlarger += setsize+1;
- qh_setlarger_quick(qh, setsize, &newsize);
- newset= qh_setnew(qh, newsize);
- oldp= (setelemT *)SETaddr_(oldset, void);
- newp= (setelemT *)SETaddr_(newset, void);
- memcpy((char *)newp, (char *)oldp, (size_t)(setsize+1) * SETelemsize);
- sizep= SETsizeaddr_(newset);
- sizep->i= setsize+1;
- FOREACHset_((setT *)qh->qhmem.tempstack) {
- if (set == oldset)
- *(setp-1)= newset;
- }
- qh_setfree(qh, oldsetp);
- }else
- newset= qh_setnew(qh, 3);
- *oldsetp= newset;
- } /* setlarger */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setlarger_quick">-</a>
- qh_setlarger_quick(qh, setsize, newsize )
- determine newsize for setsize
- returns True if newsize fits in quick memory
- design:
- if 2x fits into quick memory
- return True, 2x
- if x+4 does not fit into quick memory
- return False, 2x
- if x+x/3 fits into quick memory
- return True, the last quick set
- otherwise
- return False, 2x
- */
- int qh_setlarger_quick(qhT *qh, int setsize, int *newsize) {
- int lastquickset;
- *newsize= 2 * setsize;
- lastquickset= (qh->qhmem.LASTsize - (int)sizeof(setT)) / SETelemsize; /* matches size computation in qh_setnew */
- if (*newsize <= lastquickset)
- return 1;
- if (setsize + 4 > lastquickset)
- return 0;
- if (setsize + setsize/3 <= lastquickset) {
- *newsize= lastquickset;
- return 1;
- }
- return 0;
- } /* setlarger_quick */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setlast">-</a>
- qh_setlast( set )
- return last element of set or NULL (use type conversion)
- notes:
- set may be NULL
- design:
- return last element
- */
- void *qh_setlast(setT *set) {
- int size;
- if (set) {
- size= SETsizeaddr_(set)->i;
- if (!size)
- return SETelem_(set, set->maxsize - 1);
- else if (size > 1)
- return SETelem_(set, size - 2);
- }
- return NULL;
- } /* setlast */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setnew">-</a>
- qh_setnew(qh, setsize )
- creates and allocates space for a set
- notes:
- setsize means the number of elements (!including the NULL terminator)
- use qh_settemp/qh_setfreetemp if set is temporary
- design:
- allocate memory for set
- roundup memory if small set
- initialize as empty set
- */
- setT *qh_setnew(qhT *qh, int setsize) {
- setT *set;
- int sizereceived; /* used if !qh_NOmem */
- int size;
- void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
- if (!setsize)
- setsize++;
- size= (int)sizeof(setT) + setsize * SETelemsize; /* setT includes NULL terminator, see qh.LASTquickset */
- if (size>0 && size <= qh->qhmem.LASTsize) {
- qh_memalloc_(qh, size, freelistp, set, setT);
- #ifndef qh_NOmem
- sizereceived= qh->qhmem.sizetable[ qh->qhmem.indextable[size]];
- if (sizereceived > size)
- setsize += (sizereceived - size)/SETelemsize;
- #endif
- }else
- set= (setT *)qh_memalloc(qh, size);
- set->maxsize= setsize;
- set->e[setsize].i= 1;
- set->e[0].p= NULL;
- return(set);
- } /* setnew */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setnew_delnthsorted">-</a>
- qh_setnew_delnthsorted(qh, set, size, nth, prepend )
- creates a sorted set not containing nth element
- if prepend, the first prepend elements are undefined
- notes:
- set must be defined
- checks nth
- see also: setdelnthsorted
- design:
- create new set
- setup pointers and allocate room for prepend'ed entries
- append head of old set to new set
- append tail of old set to new set
- */
- setT *qh_setnew_delnthsorted(qhT *qh, setT *set, int size, int nth, int prepend) {
- setT *newset;
- void **oldp, **newp;
- int tailsize= size - nth -1, newsize;
- if (tailsize < 0) {
- qh_fprintf(qh, qh->qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
- qh_setprint(qh, qh->qhmem.ferr, "", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- newsize= size-1 + prepend;
- newset= qh_setnew(qh, newsize);
- newset->e[newset->maxsize].i= newsize+1; /* may be overwritten */
- oldp= SETaddr_(set, void);
- newp= SETaddr_(newset, void) + prepend;
- switch (nth) {
- case 0:
- break;
- case 1:
- *(newp++)= *oldp++;
- break;
- case 2:
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- break;
- case 3:
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- break;
- case 4:
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- break;
- default:
- memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
- newp += nth;
- oldp += nth;
- break;
- }
- oldp++;
- switch (tailsize) {
- case 0:
- break;
- case 1:
- *(newp++)= *oldp++;
- break;
- case 2:
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- break;
- case 3:
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- break;
- case 4:
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- *(newp++)= *oldp++;
- break;
- default:
- memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
- newp += tailsize;
- }
- *newp= NULL;
- return(newset);
- } /* setnew_delnthsorted */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setprint">-</a>
- qh_setprint(qh, fp, string, set )
- print set elements to fp with identifying string
- notes:
- never errors
- */
- void qh_setprint(qhT *qh, FILE *fp, const char* string, setT *set) {
- int size, k;
- if (!set)
- qh_fprintf(qh, fp, 9346, "%s set is null\n", string);
- else {
- SETreturnsize_(set, size);
- qh_fprintf(qh, fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
- string, set, set->maxsize, size);
- if (size > set->maxsize)
- size= set->maxsize+1;
- for (k=0; k < size; k++)
- qh_fprintf(qh, fp, 9348, " %p", set->e[k].p);
- qh_fprintf(qh, fp, 9349, "\n");
- }
- } /* setprint */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setreplace">-</a>
- qh_setreplace(qh, set, oldelem, newelem )
- replaces oldelem in set with newelem
- notes:
- errors if oldelem not in the set
- newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
- design:
- find oldelem
- replace with newelem
- */
- void qh_setreplace(qhT *qh, setT *set, void *oldelem, void *newelem) {
- void **elemp;
- elemp= SETaddr_(set, void);
- while (*elemp != oldelem && *elemp)
- elemp++;
- if (*elemp)
- *elemp= newelem;
- else {
- qh_fprintf(qh, qh->qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
- oldelem);
- qh_setprint(qh, qh->qhmem.ferr, "", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- } /* setreplace */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setsize">-</a>
- qh_setsize(qh, set )
- returns the size of a set
- notes:
- errors if set's maxsize is incorrect
- same as SETreturnsize_(set)
- same code for qh_setsize [qset_r.c] and QhullSetBase::count
- if first element is NULL, SETempty_() is True but qh_setsize may be greater than 0
- design:
- determine actual size of set from maxsize
- */
- int qh_setsize(qhT *qh, setT *set) {
- int size;
- setelemT *sizep;
- if (!set)
- return(0);
- sizep= SETsizeaddr_(set);
- if ((size= sizep->i)) {
- size--;
- if (size > set->maxsize) {
- qh_fprintf(qh, qh->qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
- size, set->maxsize);
- qh_setprint(qh, qh->qhmem.ferr, "set: ", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- }else
- size= set->maxsize;
- return size;
- } /* setsize */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="settemp">-</a>
- qh_settemp(qh, setsize )
- return a stacked, temporary set of up to setsize elements
- notes:
- use settempfree or settempfree_all to release from qh->qhmem.tempstack
- see also qh_setnew
- design:
- allocate set
- append to qh->qhmem.tempstack
- */
- setT *qh_settemp(qhT *qh, int setsize) {
- setT *newset;
- newset= qh_setnew(qh, setsize);
- qh_setappend(qh, &qh->qhmem.tempstack, newset);
- if (qh->qhmem.IStracing >= 5)
- qh_fprintf(qh, qh->qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
- newset, newset->maxsize, qh_setsize(qh, qh->qhmem.tempstack));
- return newset;
- } /* settemp */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="settempfree">-</a>
- qh_settempfree(qh, set )
- free temporary set at top of qh->qhmem.tempstack
- notes:
- nop if set is NULL
- errors if set not from previous qh_settemp
- to locate errors:
- use 'T2' to find source and then find mis-matching qh_settemp
- design:
- check top of qh->qhmem.tempstack
- free it
- */
- void qh_settempfree(qhT *qh, setT **set) {
- setT *stackedset;
- if (!*set)
- return;
- stackedset= qh_settemppop(qh);
- if (stackedset != *set) {
- qh_settemppush(qh, stackedset);
- qh_fprintf(qh, qh->qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
- *set, qh_setsize(qh, *set), qh_setsize(qh, qh->qhmem.tempstack)+1,
- stackedset, qh_setsize(qh, stackedset));
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- qh_setfree(qh, set);
- } /* settempfree */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="settempfree_all">-</a>
- qh_settempfree_all(qh)
- free all temporary sets in qh->qhmem.tempstack
- design:
- for each set in tempstack
- free set
- free qh->qhmem.tempstack
- */
- void qh_settempfree_all(qhT *qh) {
- setT *set, **setp;
- FOREACHset_(qh->qhmem.tempstack)
- qh_setfree(qh, &set);
- qh_setfree(qh, &qh->qhmem.tempstack);
- } /* settempfree_all */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="settemppop">-</a>
- qh_settemppop(qh)
- pop and return temporary set from qh->qhmem.tempstack
- notes:
- the returned set is permanent
- design:
- pop and check top of qh->qhmem.tempstack
- */
- setT *qh_settemppop(qhT *qh) {
- setT *stackedset;
- stackedset= (setT *)qh_setdellast(qh->qhmem.tempstack);
- if (!stackedset) {
- qh_fprintf(qh, qh->qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- if (qh->qhmem.IStracing >= 5)
- qh_fprintf(qh, qh->qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
- qh_setsize(qh, qh->qhmem.tempstack)+1, stackedset, qh_setsize(qh, stackedset));
- return stackedset;
- } /* settemppop */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="settemppush">-</a>
- qh_settemppush(qh, set )
- push temporary set unto qh->qhmem.tempstack (makes it temporary)
- notes:
- duplicates settemp() for tracing
- design:
- append set to tempstack
- */
- void qh_settemppush(qhT *qh, setT *set) {
- if (!set) {
- qh_fprintf(qh, qh->qhmem.ferr, 6267, "qhull error (qh_settemppush): can not push a NULL temp\n");
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- qh_setappend(qh, &qh->qhmem.tempstack, set);
- if (qh->qhmem.IStracing >= 5)
- qh_fprintf(qh, qh->qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
- qh_setsize(qh, qh->qhmem.tempstack), set, qh_setsize(qh, set));
- } /* settemppush */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="settruncate">-</a>
- qh_settruncate(qh, set, size )
- truncate set to size elements
- notes:
- set must be defined
- see:
- SETtruncate_
- design:
- check size
- update actual size of set
- */
- void qh_settruncate(qhT *qh, setT *set, int size) {
- if (size < 0 || size > set->maxsize) {
- qh_fprintf(qh, qh->qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
- qh_setprint(qh, qh->qhmem.ferr, "", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- set->e[set->maxsize].i= size+1; /* maybe overwritten */
- set->e[size].p= NULL;
- } /* settruncate */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setunique">-</a>
- qh_setunique(qh, set, elem )
- add elem to unsorted set unless it is already in set
- notes:
- returns 1 if it is appended
- design:
- if elem not in set
- append elem to set
- */
- int qh_setunique(qhT *qh, setT **set, void *elem) {
- if (!qh_setin(*set, elem)) {
- qh_setappend(qh, set, elem);
- return 1;
- }
- return 0;
- } /* setunique */
- /*-<a href="qh-set_r.htm#TOC"
- >-------------------------------<a name="setzero">-</a>
- qh_setzero(qh, set, index, size )
- zero elements from index on
- set actual size of set to size
- notes:
- set must be defined
- the set becomes an indexed set (can not use FOREACH...)
- see also:
- qh_settruncate
- design:
- check index and size
- update actual size
- zero elements starting at e[index]
- */
- void qh_setzero(qhT *qh, setT *set, int idx, int size) {
- int count;
- if (idx < 0 || idx >= size || size > set->maxsize) {
- qh_fprintf(qh, qh->qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
- qh_setprint(qh, qh->qhmem.ferr, "", set);
- qh_errexit(qh, qhmem_ERRqhull, NULL, NULL);
- }
- set->e[set->maxsize].i= size+1; /* may be overwritten */
- count= size - idx + 1; /* +1 for NULL terminator */
- memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
- } /* setzero */
|