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