1 /*<html><pre>  -<a                             href="qh-set.htm"
2   >-------------------------------</a><a name="TOP">-</a>
3 
4    qset.c
5    implements set manipulations needed for quickhull
6 
7    see qh-set.htm and qset.h
8 
9    Be careful of strict aliasing (two pointers of different types
10    that reference the same location).  The last slot of a set is
11    either the actual size of the set plus 1, or the NULL terminator
12    of the set (i.e., setelemT).
13 
14    Copyright (c) 1993-2015 The Geometry Center.
15    $Id: //main/2015/qhull/src/libqhull/qset.c#3 $$Change: 2062 $
16    $DateTime: 2016/01/17 13:13:18 $$Author: bbarber $
17 */
18 
19 #include "user.h" /* for QHULL_CRTDBG */
20 #include "qset.h"
21 #include "mem.h"
22 #include <stdio.h>
23 #include <string.h>
24 /*** uncomment here and qhull_a.h
25      if string.h does not define memcpy()
26 #include <memory.h>
27 */
28 
29 #ifndef qhDEFlibqhull
30 typedef struct ridgeT ridgeT;
31 typedef struct facetT facetT;
32 void    qh_errexit(int exitcode, facetT *, ridgeT *);
33 void    qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... );
34 #  ifdef _MSC_VER  /* Microsoft Visual C++ -- warning level 4 */
35 #  pragma warning( disable : 4127)  /* conditional expression is constant */
36 #  pragma warning( disable : 4706)  /* assignment within conditional function */
37 #  endif
38 #endif
39 
40 /*=============== internal macros ===========================*/
41 
42 /*============ functions in alphabetical order ===================*/
43 
44 /*-<a                             href="qh-set.htm#TOC"
45   >--------------------------------<a name="setaddnth">-</a>
46 
47   qh_setaddnth( setp, nth, newelem)
48     adds newelem as n'th element of sorted or unsorted *setp
49 
50   notes:
51     *setp and newelem must be defined
52     *setp may be a temp set
53     nth=0 is first element
54     errors if nth is out of bounds
55 
56   design:
57     expand *setp if empty or full
58     move tail of *setp up one
59     insert newelem
60 */
qh_setaddnth(setT ** setp,int nth,void * newelem)61 void qh_setaddnth(setT **setp, int nth, void *newelem) {
62   int oldsize, i;
63   setelemT *sizep;          /* avoid strict aliasing */
64   setelemT *oldp, *newp;
65 
66   if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
67     qh_setlarger(setp);
68     sizep= SETsizeaddr_(*setp);
69   }
70   oldsize= sizep->i - 1;
71   if (nth < 0 || nth > oldsize) {
72     qh_fprintf(qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth);
73     qh_setprint(qhmem.ferr, "", *setp);
74     qh_errexit(qhmem_ERRqhull, NULL, NULL);
75   }
76   sizep->i++;
77   oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void);   /* NULL */
78   newp= oldp+1;
79   for (i=oldsize-nth+1; i--; )  /* move at least NULL  */
80     (newp--)->p= (oldp--)->p;       /* may overwrite *sizep */
81   newp->p= newelem;
82 } /* setaddnth */
83 
84 
85 /*-<a                              href="qh-set.htm#TOC"
86   >--------------------------------<a name="setaddsorted">-</a>
87 
88   setaddsorted( setp, newelem )
89     adds an newelem into sorted *setp
90 
91   notes:
92     *setp and newelem must be defined
93     *setp may be a temp set
94     nop if newelem already in set
95 
96   design:
97     find newelem's position in *setp
98     insert newelem
99 */
qh_setaddsorted(setT ** setp,void * newelem)100 void qh_setaddsorted(setT **setp, void *newelem) {
101   int newindex=0;
102   void *elem, **elemp;
103 
104   FOREACHelem_(*setp) {          /* could use binary search instead */
105     if (elem < newelem)
106       newindex++;
107     else if (elem == newelem)
108       return;
109     else
110       break;
111   }
112   qh_setaddnth(setp, newindex, newelem);
113 } /* setaddsorted */
114 
115 
116 /*-<a                             href="qh-set.htm#TOC"
117   >-------------------------------<a name="setappend">-</a>
118 
119   qh_setappend( setp, newelem)
120     append newelem to *setp
121 
122   notes:
123     *setp may be a temp set
124     *setp and newelem may be NULL
125 
126   design:
127     expand *setp if empty or full
128     append newelem to *setp
129 
130 */
qh_setappend(setT ** setp,void * newelem)131 void qh_setappend(setT **setp, void *newelem) {
132   setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
133   setelemT *endp;
134   int count;
135 
136   if (!newelem)
137     return;
138   if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
139     qh_setlarger(setp);
140     sizep= SETsizeaddr_(*setp);
141   }
142   count= (sizep->i)++ - 1;
143   endp= (setelemT *)SETelemaddr_(*setp, count, void);
144   (endp++)->p= newelem;
145   endp->p= NULL;
146 } /* setappend */
147 
148 /*-<a                             href="qh-set.htm#TOC"
149   >-------------------------------<a name="setappend_set">-</a>
150 
151   qh_setappend_set( setp, setA)
152     appends setA to *setp
153 
154   notes:
155     *setp can not be a temp set
156     *setp and setA may be NULL
157 
158   design:
159     setup for copy
160     expand *setp if it is too small
161     append all elements of setA to *setp
162 */
qh_setappend_set(setT ** setp,setT * setA)163 void qh_setappend_set(setT **setp, setT *setA) {
164   int sizeA, size;
165   setT *oldset;
166   setelemT *sizep;
167 
168   if (!setA)
169     return;
170   SETreturnsize_(setA, sizeA);
171   if (!*setp)
172     *setp= qh_setnew(sizeA);
173   sizep= SETsizeaddr_(*setp);
174   if (!(size= sizep->i))
175     size= (*setp)->maxsize;
176   else
177     size--;
178   if (size + sizeA > (*setp)->maxsize) {
179     oldset= *setp;
180     *setp= qh_setcopy(oldset, sizeA);
181     qh_setfree(&oldset);
182     sizep= SETsizeaddr_(*setp);
183   }
184   if (sizeA > 0) {
185     sizep->i= size+sizeA+1;   /* memcpy may overwrite */
186     memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize);
187   }
188 } /* setappend_set */
189 
190 
191 /*-<a                             href="qh-set.htm#TOC"
192   >-------------------------------<a name="setappend2ndlast">-</a>
193 
194   qh_setappend2ndlast( setp, newelem )
195     makes newelem the next to the last element in *setp
196 
197   notes:
198     *setp must have at least one element
199     newelem must be defined
200     *setp may be a temp set
201 
202   design:
203     expand *setp if empty or full
204     move last element of *setp up one
205     insert newelem
206 */
qh_setappend2ndlast(setT ** setp,void * newelem)207 void qh_setappend2ndlast(setT **setp, void *newelem) {
208     setelemT *sizep;  /* Avoid strict aliasing.  Writing to *endp may overwrite *sizep */
209     setelemT *endp, *lastp;
210     int count;
211 
212     if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) {
213         qh_setlarger(setp);
214         sizep= SETsizeaddr_(*setp);
215     }
216     count= (sizep->i)++ - 1;
217     endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */
218     lastp= endp-1;
219     *(endp++)= *lastp;
220     endp->p= NULL;    /* may overwrite *sizep */
221     lastp->p= newelem;
222 } /* setappend2ndlast */
223 
224 /*-<a                             href="qh-set.htm#TOC"
225   >-------------------------------<a name="setcheck">-</a>
226 
227   qh_setcheck( set, typename, id )
228     check set for validity
229     report errors with typename and id
230 
231   design:
232     checks that maxsize, actual size, and NULL terminator agree
233 */
qh_setcheck(setT * set,const char * tname,unsigned id)234 void qh_setcheck(setT *set, const char *tname, unsigned id) {
235   int maxsize, size;
236   int waserr= 0;
237 
238   if (!set)
239     return;
240   SETreturnsize_(set, size);
241   maxsize= set->maxsize;
242   if (size > maxsize || !maxsize) {
243     qh_fprintf(qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n",
244              size, tname, id, maxsize);
245     waserr= 1;
246   }else if (set->e[size].p) {
247     qh_fprintf(qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n",
248              tname, id, size-1, maxsize);
249     waserr= 1;
250   }
251   if (waserr) {
252     qh_setprint(qhmem.ferr, "ERRONEOUS", set);
253     qh_errexit(qhmem_ERRqhull, NULL, NULL);
254   }
255 } /* setcheck */
256 
257 
258 /*-<a                             href="qh-set.htm#TOC"
259   >-------------------------------<a name="setcompact">-</a>
260 
261   qh_setcompact( set )
262     remove internal NULLs from an unsorted set
263 
264   returns:
265     updated set
266 
267   notes:
268     set may be NULL
269     it would be faster to swap tail of set into holes, like qh_setdel
270 
271   design:
272     setup pointers into set
273     skip NULLs while copying elements to start of set
274     update the actual size
275 */
qh_setcompact(setT * set)276 void qh_setcompact(setT *set) {
277   int size;
278   void **destp, **elemp, **endp, **firstp;
279 
280   if (!set)
281     return;
282   SETreturnsize_(set, size);
283   destp= elemp= firstp= SETaddr_(set, void);
284   endp= destp + size;
285   while (1) {
286     if (!(*destp++ = *elemp++)) {
287       destp--;
288       if (elemp > endp)
289         break;
290     }
291   }
292   qh_settruncate(set, (int)(destp-firstp));   /* WARN64 */
293 } /* setcompact */
294 
295 
296 /*-<a                             href="qh-set.htm#TOC"
297   >-------------------------------<a name="setcopy">-</a>
298 
299   qh_setcopy( set, extra )
300     make a copy of a sorted or unsorted set with extra slots
301 
302   returns:
303     new set
304 
305   design:
306     create a newset with extra slots
307     copy the elements to the newset
308 
309 */
qh_setcopy(setT * set,int extra)310 setT *qh_setcopy(setT *set, int extra) {
311   setT *newset;
312   int size;
313 
314   if (extra < 0)
315     extra= 0;
316   SETreturnsize_(set, size);
317   newset= qh_setnew(size+extra);
318   SETsizeaddr_(newset)->i= size+1;    /* memcpy may overwrite */
319   memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize);
320   return(newset);
321 } /* setcopy */
322 
323 
324 /*-<a                             href="qh-set.htm#TOC"
325   >-------------------------------<a name="setdel">-</a>
326 
327   qh_setdel( set, oldelem )
328     delete oldelem from an unsorted set
329 
330   returns:
331     returns oldelem if found
332     returns NULL otherwise
333 
334   notes:
335     set may be NULL
336     oldelem must not be NULL;
337     only deletes one copy of oldelem in set
338 
339   design:
340     locate oldelem
341     update actual size if it was full
342     move the last element to the oldelem's location
343 */
qh_setdel(setT * set,void * oldelem)344 void *qh_setdel(setT *set, void *oldelem) {
345   setelemT *sizep;
346   setelemT *elemp;
347   setelemT *lastp;
348 
349   if (!set)
350     return NULL;
351   elemp= (setelemT *)SETaddr_(set, void);
352   while (elemp->p != oldelem && elemp->p)
353     elemp++;
354   if (elemp->p) {
355     sizep= SETsizeaddr_(set);
356     if (!(sizep->i)--)         /*  if was a full set */
357       sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
358     lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
359     elemp->p= lastp->p;      /* may overwrite itself */
360     lastp->p= NULL;
361     return oldelem;
362   }
363   return NULL;
364 } /* setdel */
365 
366 
367 /*-<a                             href="qh-set.htm#TOC"
368   >-------------------------------<a name="setdellast">-</a>
369 
370   qh_setdellast( set)
371     return last element of set or NULL
372 
373   notes:
374     deletes element from set
375     set may be NULL
376 
377   design:
378     return NULL if empty
379     if full set
380       delete last element and set actual size
381     else
382       delete last element and update actual size
383 */
qh_setdellast(setT * set)384 void *qh_setdellast(setT *set) {
385   int setsize;  /* actually, actual_size + 1 */
386   int maxsize;
387   setelemT *sizep;
388   void *returnvalue;
389 
390   if (!set || !(set->e[0].p))
391     return NULL;
392   sizep= SETsizeaddr_(set);
393   if ((setsize= sizep->i)) {
394     returnvalue= set->e[setsize - 2].p;
395     set->e[setsize - 2].p= NULL;
396     sizep->i--;
397   }else {
398     maxsize= set->maxsize;
399     returnvalue= set->e[maxsize - 1].p;
400     set->e[maxsize - 1].p= NULL;
401     sizep->i= maxsize;
402   }
403   return returnvalue;
404 } /* setdellast */
405 
406 
407 /*-<a                             href="qh-set.htm#TOC"
408   >-------------------------------<a name="setdelnth">-</a>
409 
410   qh_setdelnth( set, nth )
411     deletes nth element from unsorted set
412     0 is first element
413 
414   returns:
415     returns the element (needs type conversion)
416 
417   notes:
418     errors if nth invalid
419 
420   design:
421     setup points and check nth
422     delete nth element and overwrite with last element
423 */
qh_setdelnth(setT * set,int nth)424 void *qh_setdelnth(setT *set, int nth) {
425   void *elem;
426   setelemT *sizep;
427   setelemT *elemp, *lastp;
428 
429   sizep= SETsizeaddr_(set);
430   if ((sizep->i--)==0)         /*  if was a full set */
431       sizep->i= set->maxsize;  /*     *sizep= (maxsize-1)+ 1 */
432   if (nth < 0 || nth >= sizep->i) {
433     qh_fprintf(qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth);
434     qh_setprint(qhmem.ferr, "", set);
435     qh_errexit(qhmem_ERRqhull, NULL, NULL);
436   }
437   elemp= (setelemT *)SETelemaddr_(set, nth, void); /* nth valid by QH6174 */
438   lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void);
439   elem= elemp->p;
440   elemp->p= lastp->p;      /* may overwrite itself */
441   lastp->p= NULL;
442   return elem;
443 } /* setdelnth */
444 
445 /*-<a                             href="qh-set.htm#TOC"
446   >-------------------------------<a name="setdelnthsorted">-</a>
447 
448   qh_setdelnthsorted( set, nth )
449     deletes nth element from sorted set
450 
451   returns:
452     returns the element (use type conversion)
453 
454   notes:
455     errors if nth invalid
456 
457   see also:
458     setnew_delnthsorted
459 
460   design:
461     setup points and check nth
462     copy remaining elements down one
463     update actual size
464 */
qh_setdelnthsorted(setT * set,int nth)465 void *qh_setdelnthsorted(setT *set, int nth) {
466   void *elem;
467   setelemT *sizep;
468   setelemT *newp, *oldp;
469 
470   sizep= SETsizeaddr_(set);
471   if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) {
472     qh_fprintf(qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth);
473     qh_setprint(qhmem.ferr, "", set);
474     qh_errexit(qhmem_ERRqhull, NULL, NULL);
475   }
476   newp= (setelemT *)SETelemaddr_(set, nth, void);
477   elem= newp->p;
478   oldp= newp+1;
479   while (((newp++)->p= (oldp++)->p))
480     ; /* copy remaining elements and NULL */
481   if ((sizep->i--)==0)         /*  if was a full set */
482     sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
483   return elem;
484 } /* setdelnthsorted */
485 
486 
487 /*-<a                             href="qh-set.htm#TOC"
488   >-------------------------------<a name="setdelsorted">-</a>
489 
490   qh_setdelsorted( set, oldelem )
491     deletes oldelem from sorted set
492 
493   returns:
494     returns oldelem if it was deleted
495 
496   notes:
497     set may be NULL
498 
499   design:
500     locate oldelem in set
501     copy remaining elements down one
502     update actual size
503 */
qh_setdelsorted(setT * set,void * oldelem)504 void *qh_setdelsorted(setT *set, void *oldelem) {
505   setelemT *sizep;
506   setelemT *newp, *oldp;
507 
508   if (!set)
509     return NULL;
510   newp= (setelemT *)SETaddr_(set, void);
511   while(newp->p != oldelem && newp->p)
512     newp++;
513   if (newp->p) {
514     oldp= newp+1;
515     while (((newp++)->p= (oldp++)->p))
516       ; /* copy remaining elements */
517     sizep= SETsizeaddr_(set);
518     if ((sizep->i--)==0)    /*  if was a full set */
519       sizep->i= set->maxsize;  /*     *sizep= (max size-1)+ 1 */
520     return oldelem;
521   }
522   return NULL;
523 } /* setdelsorted */
524 
525 
526 /*-<a                             href="qh-set.htm#TOC"
527   >-------------------------------<a name="setduplicate">-</a>
528 
529   qh_setduplicate( set, elemsize )
530     duplicate a set of elemsize elements
531 
532   notes:
533     use setcopy if retaining old elements
534 
535   design:
536     create a new set
537     for each elem of the old set
538       create a newelem
539       append newelem to newset
540 */
qh_setduplicate(setT * set,int elemsize)541 setT *qh_setduplicate(setT *set, int elemsize) {
542   void          *elem, **elemp, *newElem;
543   setT          *newSet;
544   int           size;
545 
546   if (!(size= qh_setsize(set)))
547     return NULL;
548   newSet= qh_setnew(size);
549   FOREACHelem_(set) {
550     newElem= qh_memalloc(elemsize);
551     memcpy(newElem, elem, (size_t)elemsize);
552     qh_setappend(&newSet, newElem);
553   }
554   return newSet;
555 } /* setduplicate */
556 
557 
558 /*-<a                             href="qh-set.htm#TOC"
559   >-------------------------------<a name="setendpointer">-</a>
560 
561   qh_setendpointer( set )
562     Returns pointer to NULL terminator of a set's elements
563     set can not be NULL
564 
565 */
qh_setendpointer(setT * set)566 void **qh_setendpointer(setT *set) {
567 
568   setelemT *sizep= SETsizeaddr_(set);
569   int n= sizep->i;
570   return (n ? &set->e[n-1].p : &sizep->p);
571 } /* qh_setendpointer */
572 
573 /*-<a                             href="qh-set.htm#TOC"
574   >-------------------------------<a name="setequal">-</a>
575 
576   qh_setequal( setA, setB )
577     returns 1 if two sorted sets are equal, otherwise returns 0
578 
579   notes:
580     either set may be NULL
581 
582   design:
583     check size of each set
584     setup pointers
585     compare elements of each set
586 */
qh_setequal(setT * setA,setT * setB)587 int qh_setequal(setT *setA, setT *setB) {
588   void **elemAp, **elemBp;
589   int sizeA= 0, sizeB= 0;
590 
591   if (setA) {
592     SETreturnsize_(setA, sizeA);
593   }
594   if (setB) {
595     SETreturnsize_(setB, sizeB);
596   }
597   if (sizeA != sizeB)
598     return 0;
599   if (!sizeA)
600     return 1;
601   elemAp= SETaddr_(setA, void);
602   elemBp= SETaddr_(setB, void);
603   if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize))
604     return 1;
605   return 0;
606 } /* setequal */
607 
608 
609 /*-<a                             href="qh-set.htm#TOC"
610   >-------------------------------<a name="setequal_except">-</a>
611 
612   qh_setequal_except( setA, skipelemA, setB, skipelemB )
613     returns 1 if sorted setA and setB are equal except for skipelemA & B
614 
615   returns:
616     false if either skipelemA or skipelemB are missing
617 
618   notes:
619     neither set may be NULL
620 
621     if skipelemB is NULL,
622       can skip any one element of setB
623 
624   design:
625     setup pointers
626     search for skipelemA, skipelemB, and mismatches
627     check results
628 */
qh_setequal_except(setT * setA,void * skipelemA,setT * setB,void * skipelemB)629 int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) {
630   void **elemA, **elemB;
631   int skip=0;
632 
633   elemA= SETaddr_(setA, void);
634   elemB= SETaddr_(setB, void);
635   while (1) {
636     if (*elemA == skipelemA) {
637       skip++;
638       elemA++;
639     }
640     if (skipelemB) {
641       if (*elemB == skipelemB) {
642         skip++;
643         elemB++;
644       }
645     }else if (*elemA != *elemB) {
646       skip++;
647       if (!(skipelemB= *elemB++))
648         return 0;
649     }
650     if (!*elemA)
651       break;
652     if (*elemA++ != *elemB++)
653       return 0;
654   }
655   if (skip != 2 || *elemB)
656     return 0;
657   return 1;
658 } /* setequal_except */
659 
660 
661 /*-<a                             href="qh-set.htm#TOC"
662   >-------------------------------<a name="setequal_skip">-</a>
663 
664   qh_setequal_skip( setA, skipA, setB, skipB )
665     returns 1 if sorted setA and setB are equal except for elements skipA & B
666 
667   returns:
668     false if different size
669 
670   notes:
671     neither set may be NULL
672 
673   design:
674     setup pointers
675     search for mismatches while skipping skipA and skipB
676 */
qh_setequal_skip(setT * setA,int skipA,setT * setB,int skipB)677 int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) {
678   void **elemA, **elemB, **skipAp, **skipBp;
679 
680   elemA= SETaddr_(setA, void);
681   elemB= SETaddr_(setB, void);
682   skipAp= SETelemaddr_(setA, skipA, void);
683   skipBp= SETelemaddr_(setB, skipB, void);
684   while (1) {
685     if (elemA == skipAp)
686       elemA++;
687     if (elemB == skipBp)
688       elemB++;
689     if (!*elemA)
690       break;
691     if (*elemA++ != *elemB++)
692       return 0;
693   }
694   if (*elemB)
695     return 0;
696   return 1;
697 } /* setequal_skip */
698 
699 
700 /*-<a                             href="qh-set.htm#TOC"
701   >-------------------------------<a name="setfree">-</a>
702 
703   qh_setfree( setp )
704     frees the space occupied by a sorted or unsorted set
705 
706   returns:
707     sets setp to NULL
708 
709   notes:
710     set may be NULL
711 
712   design:
713     free array
714     free set
715 */
qh_setfree(setT ** setp)716 void qh_setfree(setT **setp) {
717   int size;
718   void **freelistp;  /* used if !qh_NOmem by qh_memfree_() */
719 
720   if (*setp) {
721     size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
722     if (size <= qhmem.LASTsize) {
723       qh_memfree_(*setp, size, freelistp);
724     }else
725       qh_memfree(*setp, size);
726     *setp= NULL;
727   }
728 } /* setfree */
729 
730 
731 /*-<a                             href="qh-set.htm#TOC"
732   >-------------------------------<a name="setfree2">-</a>
733 
734   qh_setfree2( setp, elemsize )
735     frees the space occupied by a set and its elements
736 
737   notes:
738     set may be NULL
739 
740   design:
741     free each element
742     free set
743 */
qh_setfree2(setT ** setp,int elemsize)744 void qh_setfree2(setT **setp, int elemsize) {
745   void          *elem, **elemp;
746 
747   FOREACHelem_(*setp)
748     qh_memfree(elem, elemsize);
749   qh_setfree(setp);
750 } /* setfree2 */
751 
752 
753 
754 /*-<a                             href="qh-set.htm#TOC"
755   >-------------------------------<a name="setfreelong">-</a>
756 
757   qh_setfreelong( setp )
758     frees a set only if it's in long memory
759 
760   returns:
761     sets setp to NULL if it is freed
762 
763   notes:
764     set may be NULL
765 
766   design:
767     if set is large
768       free it
769 */
qh_setfreelong(setT ** setp)770 void qh_setfreelong(setT **setp) {
771   int size;
772 
773   if (*setp) {
774     size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize;
775     if (size > qhmem.LASTsize) {
776       qh_memfree(*setp, size);
777       *setp= NULL;
778     }
779   }
780 } /* setfreelong */
781 
782 
783 /*-<a                             href="qh-set.htm#TOC"
784   >-------------------------------<a name="setin">-</a>
785 
786   qh_setin( set, setelem )
787     returns 1 if setelem is in a set, 0 otherwise
788 
789   notes:
790     set may be NULL or unsorted
791 
792   design:
793     scans set for setelem
794 */
qh_setin(setT * set,void * setelem)795 int qh_setin(setT *set, void *setelem) {
796   void *elem, **elemp;
797 
798   FOREACHelem_(set) {
799     if (elem == setelem)
800       return 1;
801   }
802   return 0;
803 } /* setin */
804 
805 
806 /*-<a                             href="qh-set.htm#TOC"
807   >-------------------------------<a name="setindex">-</a>
808 
809   qh_setindex( set, atelem )
810     returns the index of atelem in set.
811     returns -1, if not in set or maxsize wrong
812 
813   notes:
814     set may be NULL and may contain nulls.
815     NOerrors returned (qh_pointid, QhullPoint::id)
816 
817   design:
818     checks maxsize
819     scans set for atelem
820 */
qh_setindex(setT * set,void * atelem)821 int qh_setindex(setT *set, void *atelem) {
822   void **elem;
823   int size, i;
824 
825   if (!set)
826     return -1;
827   SETreturnsize_(set, size);
828   if (size > set->maxsize)
829     return -1;
830   elem= SETaddr_(set, void);
831   for (i=0; i < size; i++) {
832     if (*elem++ == atelem)
833       return i;
834   }
835   return -1;
836 } /* setindex */
837 
838 
839 /*-<a                             href="qh-set.htm#TOC"
840   >-------------------------------<a name="setlarger">-</a>
841 
842   qh_setlarger( oldsetp )
843     returns a larger set that contains all elements of *oldsetp
844 
845   notes:
846     the set is at least twice as large
847     if temp set, updates qhmem.tempstack
848 
849   design:
850     creates a new set
851     copies the old set to the new set
852     updates pointers in tempstack
853     deletes the old set
854 */
qh_setlarger(setT ** oldsetp)855 void qh_setlarger(setT **oldsetp) {
856   int size= 1;
857   setT *newset, *set, **setp, *oldset;
858   setelemT *sizep;
859   setelemT *newp, *oldp;
860 
861   if (*oldsetp) {
862     oldset= *oldsetp;
863     SETreturnsize_(oldset, size);
864     qhmem.cntlarger++;
865     qhmem.totlarger += size+1;
866     newset= qh_setnew(2 * size);
867     oldp= (setelemT *)SETaddr_(oldset, void);
868     newp= (setelemT *)SETaddr_(newset, void);
869     memcpy((char *)newp, (char *)oldp, (size_t)(size+1) * SETelemsize);
870     sizep= SETsizeaddr_(newset);
871     sizep->i= size+1;
872     FOREACHset_((setT *)qhmem.tempstack) {
873       if (set == oldset)
874         *(setp-1)= newset;
875     }
876     qh_setfree(oldsetp);
877   }else
878     newset= qh_setnew(3);
879   *oldsetp= newset;
880 } /* setlarger */
881 
882 
883 /*-<a                             href="qh-set.htm#TOC"
884   >-------------------------------<a name="setlast">-</a>
885 
886   qh_setlast( set )
887     return last element of set or NULL (use type conversion)
888 
889   notes:
890     set may be NULL
891 
892   design:
893     return last element
894 */
qh_setlast(setT * set)895 void *qh_setlast(setT *set) {
896   int size;
897 
898   if (set) {
899     size= SETsizeaddr_(set)->i;
900     if (!size)
901       return SETelem_(set, set->maxsize - 1);
902     else if (size > 1)
903       return SETelem_(set, size - 2);
904   }
905   return NULL;
906 } /* setlast */
907 
908 
909 /*-<a                             href="qh-set.htm#TOC"
910   >-------------------------------<a name="setnew">-</a>
911 
912   qh_setnew( setsize )
913     creates and allocates space for a set
914 
915   notes:
916     setsize means the number of elements (!including the NULL terminator)
917     use qh_settemp/qh_setfreetemp if set is temporary
918 
919   design:
920     allocate memory for set
921     roundup memory if small set
922     initialize as empty set
923 */
qh_setnew(int setsize)924 setT *qh_setnew(int setsize) {
925   setT *set;
926   int sizereceived; /* used if !qh_NOmem */
927   int size;
928   void **freelistp; /* used if !qh_NOmem by qh_memalloc_() */
929 
930   if (!setsize)
931     setsize++;
932   size= sizeof(setT) + setsize * SETelemsize;
933   if (size>0 && size <= qhmem.LASTsize) {
934     qh_memalloc_(size, freelistp, set, setT);
935 #ifndef qh_NOmem
936     sizereceived= qhmem.sizetable[ qhmem.indextable[size]];
937     if (sizereceived > size)
938       setsize += (sizereceived - size)/SETelemsize;
939 #endif
940   }else
941     set= (setT*)qh_memalloc(size);
942   set->maxsize= setsize;
943   set->e[setsize].i= 1;
944   set->e[0].p= NULL;
945   return(set);
946 } /* setnew */
947 
948 
949 /*-<a                             href="qh-set.htm#TOC"
950   >-------------------------------<a name="setnew_delnthsorted">-</a>
951 
952   qh_setnew_delnthsorted( set, size, nth, prepend )
953     creates a sorted set not containing nth element
954     if prepend, the first prepend elements are undefined
955 
956   notes:
957     set must be defined
958     checks nth
959     see also: setdelnthsorted
960 
961   design:
962     create new set
963     setup pointers and allocate room for prepend'ed entries
964     append head of old set to new set
965     append tail of old set to new set
966 */
qh_setnew_delnthsorted(setT * set,int size,int nth,int prepend)967 setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) {
968   setT *newset;
969   void **oldp, **newp;
970   int tailsize= size - nth -1, newsize;
971 
972   if (tailsize < 0) {
973     qh_fprintf(qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth);
974     qh_setprint(qhmem.ferr, "", set);
975     qh_errexit(qhmem_ERRqhull, NULL, NULL);
976   }
977   newsize= size-1 + prepend;
978   newset= qh_setnew(newsize);
979   newset->e[newset->maxsize].i= newsize+1;  /* may be overwritten */
980   oldp= SETaddr_(set, void);
981   newp= SETaddr_(newset, void) + prepend;
982   switch (nth) {
983   case 0:
984     break;
985   case 1:
986     *(newp++)= *oldp++;
987     break;
988   case 2:
989     *(newp++)= *oldp++;
990     *(newp++)= *oldp++;
991     break;
992   case 3:
993     *(newp++)= *oldp++;
994     *(newp++)= *oldp++;
995     *(newp++)= *oldp++;
996     break;
997   case 4:
998     *(newp++)= *oldp++;
999     *(newp++)= *oldp++;
1000     *(newp++)= *oldp++;
1001     *(newp++)= *oldp++;
1002     break;
1003   default:
1004     memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize);
1005     newp += nth;
1006     oldp += nth;
1007     break;
1008   }
1009   oldp++;
1010   switch (tailsize) {
1011   case 0:
1012     break;
1013   case 1:
1014     *(newp++)= *oldp++;
1015     break;
1016   case 2:
1017     *(newp++)= *oldp++;
1018     *(newp++)= *oldp++;
1019     break;
1020   case 3:
1021     *(newp++)= *oldp++;
1022     *(newp++)= *oldp++;
1023     *(newp++)= *oldp++;
1024     break;
1025   case 4:
1026     *(newp++)= *oldp++;
1027     *(newp++)= *oldp++;
1028     *(newp++)= *oldp++;
1029     *(newp++)= *oldp++;
1030     break;
1031   default:
1032     memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize);
1033     newp += tailsize;
1034   }
1035   *newp= NULL;
1036   return(newset);
1037 } /* setnew_delnthsorted */
1038 
1039 
1040 /*-<a                             href="qh-set.htm#TOC"
1041   >-------------------------------<a name="setprint">-</a>
1042 
1043   qh_setprint( fp, string, set )
1044     print set elements to fp with identifying string
1045 
1046   notes:
1047     never errors
1048 */
qh_setprint(FILE * fp,const char * string,setT * set)1049 void qh_setprint(FILE *fp, const char* string, setT *set) {
1050   int size, k;
1051 
1052   if (!set)
1053     qh_fprintf(fp, 9346, "%s set is null\n", string);
1054   else {
1055     SETreturnsize_(set, size);
1056     qh_fprintf(fp, 9347, "%s set=%p maxsize=%d size=%d elems=",
1057              string, set, set->maxsize, size);
1058     if (size > set->maxsize)
1059       size= set->maxsize+1;
1060     for (k=0; k < size; k++)
1061       qh_fprintf(fp, 9348, " %p", set->e[k].p);
1062     qh_fprintf(fp, 9349, "\n");
1063   }
1064 } /* setprint */
1065 
1066 /*-<a                             href="qh-set.htm#TOC"
1067   >-------------------------------<a name="setreplace">-</a>
1068 
1069   qh_setreplace( set, oldelem, newelem )
1070     replaces oldelem in set with newelem
1071 
1072   notes:
1073     errors if oldelem not in the set
1074     newelem may be NULL, but it turns the set into an indexed set (no FOREACH)
1075 
1076   design:
1077     find oldelem
1078     replace with newelem
1079 */
qh_setreplace(setT * set,void * oldelem,void * newelem)1080 void qh_setreplace(setT *set, void *oldelem, void *newelem) {
1081   void **elemp;
1082 
1083   elemp= SETaddr_(set, void);
1084   while (*elemp != oldelem && *elemp)
1085     elemp++;
1086   if (*elemp)
1087     *elemp= newelem;
1088   else {
1089     qh_fprintf(qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n",
1090        oldelem);
1091     qh_setprint(qhmem.ferr, "", set);
1092     qh_errexit(qhmem_ERRqhull, NULL, NULL);
1093   }
1094 } /* setreplace */
1095 
1096 
1097 /*-<a                             href="qh-set.htm#TOC"
1098   >-------------------------------<a name="setsize">-</a>
1099 
1100   qh_setsize( set )
1101     returns the size of a set
1102 
1103   notes:
1104     errors if set's maxsize is incorrect
1105     same as SETreturnsize_(set)
1106     same code for qh_setsize [qset.c] and QhullSetBase::count
1107 
1108   design:
1109     determine actual size of set from maxsize
1110 */
qh_setsize(setT * set)1111 int qh_setsize(setT *set) {
1112   int size;
1113   setelemT *sizep;
1114 
1115   if (!set)
1116     return(0);
1117   sizep= SETsizeaddr_(set);
1118   if ((size= sizep->i)) {
1119     size--;
1120     if (size > set->maxsize) {
1121       qh_fprintf(qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n",
1122                size, set->maxsize);
1123       qh_setprint(qhmem.ferr, "set: ", set);
1124       qh_errexit(qhmem_ERRqhull, NULL, NULL);
1125     }
1126   }else
1127     size= set->maxsize;
1128   return size;
1129 } /* setsize */
1130 
1131 /*-<a                             href="qh-set.htm#TOC"
1132   >-------------------------------<a name="settemp">-</a>
1133 
1134   qh_settemp( setsize )
1135     return a stacked, temporary set of upto setsize elements
1136 
1137   notes:
1138     use settempfree or settempfree_all to release from qhmem.tempstack
1139     see also qh_setnew
1140 
1141   design:
1142     allocate set
1143     append to qhmem.tempstack
1144 
1145 */
qh_settemp(int setsize)1146 setT *qh_settemp(int setsize) {
1147   setT *newset;
1148 
1149   newset= qh_setnew(setsize);
1150   qh_setappend(&qhmem.tempstack, newset);
1151   if (qhmem.IStracing >= 5)
1152     qh_fprintf(qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n",
1153        newset, newset->maxsize, qh_setsize(qhmem.tempstack));
1154   return newset;
1155 } /* settemp */
1156 
1157 /*-<a                             href="qh-set.htm#TOC"
1158   >-------------------------------<a name="settempfree">-</a>
1159 
1160   qh_settempfree( set )
1161     free temporary set at top of qhmem.tempstack
1162 
1163   notes:
1164     nop if set is NULL
1165     errors if set not from previous   qh_settemp
1166 
1167   to locate errors:
1168     use 'T2' to find source and then find mis-matching qh_settemp
1169 
1170   design:
1171     check top of qhmem.tempstack
1172     free it
1173 */
qh_settempfree(setT ** set)1174 void qh_settempfree(setT **set) {
1175   setT *stackedset;
1176 
1177   if (!*set)
1178     return;
1179   stackedset= qh_settemppop();
1180   if (stackedset != *set) {
1181     qh_settemppush(stackedset);
1182     qh_fprintf(qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n",
1183              *set, qh_setsize(*set), qh_setsize(qhmem.tempstack)+1,
1184              stackedset, qh_setsize(stackedset));
1185     qh_errexit(qhmem_ERRqhull, NULL, NULL);
1186   }
1187   qh_setfree(set);
1188 } /* settempfree */
1189 
1190 /*-<a                             href="qh-set.htm#TOC"
1191   >-------------------------------<a name="settempfree_all">-</a>
1192 
1193   qh_settempfree_all(  )
1194     free all temporary sets in qhmem.tempstack
1195 
1196   design:
1197     for each set in tempstack
1198       free set
1199     free qhmem.tempstack
1200 */
qh_settempfree_all(void)1201 void qh_settempfree_all(void) {
1202   setT *set, **setp;
1203 
1204   FOREACHset_(qhmem.tempstack)
1205     qh_setfree(&set);
1206   qh_setfree(&qhmem.tempstack);
1207 } /* settempfree_all */
1208 
1209 /*-<a                             href="qh-set.htm#TOC"
1210   >-------------------------------<a name="settemppop">-</a>
1211 
1212   qh_settemppop(  )
1213     pop and return temporary set from qhmem.tempstack
1214 
1215   notes:
1216     the returned set is permanent
1217 
1218   design:
1219     pop and check top of qhmem.tempstack
1220 */
qh_settemppop(void)1221 setT *qh_settemppop(void) {
1222   setT *stackedset;
1223 
1224   stackedset= (setT*)qh_setdellast(qhmem.tempstack);
1225   if (!stackedset) {
1226     qh_fprintf(qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n");
1227     qh_errexit(qhmem_ERRqhull, NULL, NULL);
1228   }
1229   if (qhmem.IStracing >= 5)
1230     qh_fprintf(qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n",
1231        qh_setsize(qhmem.tempstack)+1, stackedset, qh_setsize(stackedset));
1232   return stackedset;
1233 } /* settemppop */
1234 
1235 /*-<a                             href="qh-set.htm#TOC"
1236   >-------------------------------<a name="settemppush">-</a>
1237 
1238   qh_settemppush( set )
1239     push temporary set unto qhmem.tempstack (makes it temporary)
1240 
1241   notes:
1242     duplicates settemp() for tracing
1243 
1244   design:
1245     append set to tempstack
1246 */
qh_settemppush(setT * set)1247 void qh_settemppush(setT *set) {
1248   if (!set) {
1249     qh_fprintf(qhmem.ferr, 6267, "qhull error (qh_settemppush): can not push a NULL temp\n");
1250     qh_errexit(qhmem_ERRqhull, NULL, NULL);
1251   }
1252   qh_setappend(&qhmem.tempstack, set);
1253   if (qhmem.IStracing >= 5)
1254     qh_fprintf(qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n",
1255       qh_setsize(qhmem.tempstack), set, qh_setsize(set));
1256 } /* settemppush */
1257 
1258 
1259 /*-<a                             href="qh-set.htm#TOC"
1260   >-------------------------------<a name="settruncate">-</a>
1261 
1262   qh_settruncate( set, size )
1263     truncate set to size elements
1264 
1265   notes:
1266     set must be defined
1267 
1268   see:
1269     SETtruncate_
1270 
1271   design:
1272     check size
1273     update actual size of set
1274 */
qh_settruncate(setT * set,int size)1275 void qh_settruncate(setT *set, int size) {
1276 
1277   if (size < 0 || size > set->maxsize) {
1278     qh_fprintf(qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size);
1279     qh_setprint(qhmem.ferr, "", set);
1280     qh_errexit(qhmem_ERRqhull, NULL, NULL);
1281   }
1282   set->e[set->maxsize].i= size+1;   /* maybe overwritten */
1283   set->e[size].p= NULL;
1284 } /* settruncate */
1285 
1286 /*-<a                             href="qh-set.htm#TOC"
1287   >-------------------------------<a name="setunique">-</a>
1288 
1289   qh_setunique( set, elem )
1290     add elem to unsorted set unless it is already in set
1291 
1292   notes:
1293     returns 1 if it is appended
1294 
1295   design:
1296     if elem not in set
1297       append elem to set
1298 */
qh_setunique(setT ** set,void * elem)1299 int qh_setunique(setT **set, void *elem) {
1300 
1301   if (!qh_setin(*set, elem)) {
1302     qh_setappend(set, elem);
1303     return 1;
1304   }
1305   return 0;
1306 } /* setunique */
1307 
1308 /*-<a                             href="qh-set.htm#TOC"
1309   >-------------------------------<a name="setzero">-</a>
1310 
1311   qh_setzero( set, index, size )
1312     zero elements from index on
1313     set actual size of set to size
1314 
1315   notes:
1316     set must be defined
1317     the set becomes an indexed set (can not use FOREACH...)
1318 
1319   see also:
1320     qh_settruncate
1321 
1322   design:
1323     check index and size
1324     update actual size
1325     zero elements starting at e[index]
1326 */
qh_setzero(setT * set,int idx,int size)1327 void qh_setzero(setT *set, int idx, int size) {
1328   int count;
1329 
1330   if (idx < 0 || idx >= size || size > set->maxsize) {
1331     qh_fprintf(qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size);
1332     qh_setprint(qhmem.ferr, "", set);
1333     qh_errexit(qhmem_ERRqhull, NULL, NULL);
1334   }
1335   set->e[set->maxsize].i=  size+1;  /* may be overwritten */
1336   count= size - idx + 1;   /* +1 for NULL terminator */
1337   memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize);
1338 } /* setzero */
1339 
1340 
1341