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