void setupMemory(int tracelevel, int numInts, int **intarray) { int i; if(numInts<0 || numInts*(int)sizeof(int)<0){ qh_fprintf(stderr, 6303, "qset does not currently support 64-bit ints. Integer overflow\n"); exit(1); } *intarray= qh_malloc(numInts * sizeof(int)); if(!*intarray){ qh_fprintf(stderr, 6304, "Failed to allocate %d bytes of memory\n", numInts * sizeof(int)); exit(1); } for(i= 0; i<numInts; i++){ (*intarray)[i] =i; } qh_meminit(stderr); qh_meminitbuffers(tracelevel, qh_MEMalign, 4 /*sizes*/, qh_MEMbufsize,qh_MEMinitbuf); qh_memsize(10); qh_memsize(20); qh_memsize(30); qh_memsize(40); qh_memsetup(); qh_fprintf(stderr, 8001, "SETelemsize is %d bytes for pointer-to-int\n", SETelemsize); }/*setupMemmory*/
int main(int argc, char **argv) { int *intarray= NULL; int numInts; int checkEvery= MAXint; int curlong, totlong; int traceLevel= 4; /* 4 normally, no tracing since qset does not log. 5 for memory tracing */ readOptions(argc, argv, prompt, &numInts, &checkEvery, &traceLevel); setupMemory(traceLevel, numInts, &intarray); testSetappendSettruncate(numInts, intarray, checkEvery); testSetdelSetadd(numInts, intarray, checkEvery); testSetappendSet(numInts, intarray, checkEvery); testSetcompactCopy(numInts, intarray, checkEvery); testSetequalInEtc(numInts, intarray, checkEvery); testSettemp(numInts, intarray, checkEvery); testSetlastEtc(numInts, intarray, checkEvery); testSetdelsortedEtc(numInts, intarray, checkEvery); printf("\n\nNot testing qh_setduplicate and qh_setfree2.\n These routines use heap-allocated set contents. See qhull tests.\n"); qh_memstatistics(stdout); qh_memfreeshort(&curlong, &totlong); if (curlong || totlong){ qh_fprintf(stderr, 8043, "qh_memfreeshort: did not free %d bytes of long memory(%d pieces)\n", totlong, curlong); error_count++; } if(error_count){ qh_fprintf(stderr, 8012, "testqset: %d errors\n\n", error_count); exit(1); }else{ printf("testqset: OK\n\n"); } return 0; }/*main*/
/*-<a href="qh-mem.htm#TOC" >--------------------------------</a><a name="memfree">-</a> qh_memfree( object, insize ) free up an object of size bytes size is insize from qh_memalloc notes: object may be NULL type checking warns if using (void **)object use qh_memfree_() for quick free's of small objects design: if size <= qhmem.LASTsize append object to corresponding freelist else call qh_free(object) */ void qh_memfree(void *object, int insize) { void **freelistp; int idx, outsize; if (!object) return; if (insize <= qhmem.LASTsize) { qhmem .freeshort++; idx= qhmem.indextable[insize]; outsize= qhmem.sizetable[idx]; qhmem .totfree += outsize; qhmem .totshort -= outsize; freelistp= qhmem.freelists + idx; *((void **)object)= *freelistp; *freelistp= object; #ifdef qh_TRACEshort idx= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort; if (qhmem.IStracing >= 5) qh_fprintf(qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort); #endif } else { qhmem .freelong++; qhmem .totlong -= insize; qh_free(object); if (qhmem.IStracing >= 5) qh_fprintf(qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); } } /* memfree */
/*-<a href="qh-mem.htm#TOC" >--------------------------------</a><a name="meminit">-</a> qh_meminit( ferr ) initialize qhmem and test sizeof( void*) */ void qh_meminit(FILE *ferr) { memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */ qhmem.ferr= ferr; if (sizeof(void*) < sizeof(int)) { qh_fprintf(ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int)); qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */ } if (sizeof(void*) > sizeof(ptr_intT)) { qh_fprintf(ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT)); qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */ } } /* meminit */
void *qh_memalloc(int insize) { void *object; if (!(object= qh_malloc((size_t)insize))) { qh_fprintf(qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n"); qh_errexit(qhmem_ERRmem, NULL, NULL); } qhmem .cntlong++; qhmem .totlong += insize; if (qhmem.maxlong < qhmem.totlong) qhmem.maxlong= qhmem.totlong; if (qhmem.IStracing >= 5) qh_fprintf(qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); return object; }
void readOptions(int argc, char **argv, const char *promptstr, int *numInts, int *checkEvery, int *traceLevel) { long numIntsArg; long checkEveryArg; char *endp; int isTracing= 0; if (argc < 2 || argc > 4) { printf("%s", promptstr); exit(0); } numIntsArg= strtol(argv[1], &endp, 10); if(numIntsArg<1){ qh_fprintf(stderr, 6301, "First argument should be 1 or greater. Got '%s'\n", argv[1]); exit(1); } if(numIntsArg>MAXint){ qh_fprintf(stderr, 6302, "qset does not currently support 64-bit ints. Maximum count is %d\n", MAXint); exit(1); } *numInts= (int)numIntsArg; if(argc==3 && argv[2][0]=='T' && argv[2][1]=='5' ){ isTracing= 1; *traceLevel= 5; } if(argc==4 || (argc==3 && !isTracing)){ checkEveryArg= strtol(argv[2], &endp, 10); if(checkEveryArg<1){ qh_fprintf(stderr, 6321, "checkEvery argument should be 1 or greater. Got '%s'\n", argv[2]); exit(1); } if(checkEveryArg>MAXint){ qh_fprintf(stderr, 6322, "qset does not currently support 64-bit ints. Maximum checkEvery is %d\n", MAXint); exit(1); } if(argc==4){ if(argv[3][0]=='T' && argv[3][1]=='5' ){ isTracing= 1; *traceLevel= 5; }else{ qh_fprintf(stderr, 6242, "Optional third argument must be 'T5'. Got '%s'\n", argv[3]); exit(1); } } *checkEvery= (int)checkEveryArg; } }/*readOptions*/
void testSetdelSetadd(int numInts, int *intarray, int checkEvery) { setT *ints=qh_setnew(1); int i,j,isCheck; qh_fprintf(stderr, 8003, "\n\nTesting qh_setdelnthsorted and qh_setaddnth 1..%d. Test", numInts-1); for(j=1; j<numInts; j++){ /* size 0 not valid */ if(log_i(ints, "j", j, numInts, MAXint)){ for(i= qh_setsize(ints); i<j; i++){ qh_setappend(&ints, intarray+i); } checkSetContents("qh_setappend", ints, j, 0, -1, -1); for(i= 0; i<j && i<100; i++){ /* otherwise too slow */ isCheck= log_i(ints, "", i, numInts, checkEvery); (void)isCheck; /* unused */ qh_setdelnthsorted(ints, i); qh_setaddnth(&ints, i, intarray+i); if(checkEvery==1){ checkSetContents("qh_setdelnthsorted qh_setaddnth", ints, j, 0, -1, -1); } } checkSetContents("qh_setdelnthsorted qh_setaddnth 2", ints, j, 0, -1, -1); } } qh_setfree(&ints); }/*testSetdelSetadd*/
void testSetcompactCopy(int numInts, int *intarray, int checkEvery) { setT *ints= qh_setnew(20); setT *ints2= NULL; int i,j,k; qh_fprintf(stderr, 8017, "\n\nTesting qh_setcompact and qh_setcopy 0..%d. Test", numInts-1); for(j=0; j<numInts; j++){ if(log_i(ints, "j", j, numInts, checkEvery)){ for(i= qh_setsize(ints); i<j; i++){ /* Test i<j to test the empty set */ for(k= 0; k<i%7; k++){ qh_setappend(&ints, NULL); } qh_setappend(&ints, intarray+i); } qh_setfree(&ints2); ints2= qh_setcopy(ints, 0); qh_setcompact(ints); qh_setcompact(ints2); checkSetContents("qh_setcompact", ints, j, 0, 0, -1); checkSetContents("qh_setcompact", ints2, j, 0, 0, -1); qh_setcompact(ints); checkSetContents("qh_setcompact", ints, j, 0, 0, -1); } } qh_setfree(&ints); qh_setfree(&ints2); }/*testSetcompactCopy*/
void testSetappendSettruncate(int numInts, int *intarray, int checkEvery) { setT *ints= qh_setnew(4); int i, isCheck; qh_fprintf(stderr, 8002, "\n\nTesting qh_setappend 0..%d. Test", numInts-1); for(i= 0; i<numInts; i++){ isCheck= log_i(ints, "i", i, numInts, checkEvery); qh_setappend(&ints, intarray+i); if(isCheck){ checkSetContents("qh_setappend", ints, i+1, 0, -1, -1); } } qh_fprintf(stderr, 8014, "\n\nTesting qh_settruncate %d and 0. Test", numInts/2); if(numInts>=2){ isCheck= log_i(ints, "n", numInts/2, numInts, checkEvery); qh_settruncate(ints, numInts/2); checkSetContents("qh_settruncate by half", ints, numInts/2, 0, -1, -1); } isCheck= log_i(ints, "n", 0, numInts, checkEvery); qh_settruncate(ints, 0); checkSetContents("qh_settruncate", ints, 0, -1, -1, -1); qh_fprintf(stderr, 8003, "\n\nTesting qh_setappend2ndlast 0,0..%d. Test 0", numInts-1); qh_setfree(&ints); ints= qh_setnew(4); qh_setappend(&ints, intarray+0); for(i= 0; i<numInts; i++){ isCheck= log_i(ints, "i", i, numInts, checkEvery); qh_setappend2ndlast(&ints, intarray+i); if(isCheck){ checkSetContents("qh_setappend2ndlast", ints, i+2, 0, 0, -1); } } qh_fprintf(stderr, 8015, "\n\nTesting SETtruncate_ %d and 0. Test", numInts/2); if(numInts>=2){ isCheck= log_i(ints, "n", numInts/2, numInts, checkEvery); SETtruncate_(ints, numInts/2); checkSetContents("SETtruncate_ by half", ints, numInts/2, 0, -1, -1); } isCheck= log_i(ints, "n", 0, numInts, checkEvery); SETtruncate_(ints, 0); checkSetContents("SETtruncate_", ints, 0, -1, -1, -1); qh_setfree(&ints); }/*testSetappendSettruncate*/
/*-<a href="qh-mem.htm#TOC" >-------------------------------</a><a name="memstatistics">-</a> qh_memstatistics( fp ) print out memory statistics Verifies that qhmem.totfree == sum of freelists */ void qh_memstatistics(FILE *fp) { int i, count, totfree= 0; void *object; for (i=0; i < qhmem.TABLEsize; i++) { count=0; for (object= qhmem .freelists[i]; object; object= *((void **)object)) count++; totfree += qhmem.sizetable[i] * count; } if (totfree != qhmem .totfree) { qh_fprintf(qhmem.ferr, 6211, "qh_memstatistics internal error: totfree %d not equal to freelist total %d\n", qhmem.totfree, totfree); qh_errexit(qhmem_ERRqhull, NULL, NULL); } qh_fprintf(fp, 9278, "\nmemory statistics:\n\ %7d quick allocations\n\ %7d short allocations\n\ %7d long allocations\n\ %7d short frees\n\ %7d long frees\n\ %7d bytes of short memory in use\n\ %7d bytes of short memory in freelists\n\ %7d bytes of dropped short memory\n\ %7d bytes of unused short memory (estimated)\n\ %7d bytes of long memory allocated (max, except for input)\n\ %7d bytes of long memory in use (in %d pieces)\n\ %7d bytes of short memory buffers (minus links)\n\ %7d bytes per short memory buffer (initially %d bytes)\n", qhmem .cntquick, qhmem .cntshort, qhmem .cntlong, qhmem .freeshort, qhmem .freelong, qhmem .totshort, qhmem .totfree, qhmem .totdropped + qhmem .freesize, qhmem .totunused, qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong, qhmem .totbuffer, qhmem .BUFsize, qhmem .BUFinit); if (qhmem.cntlarger) { qh_fprintf(fp, 9279, "%7d calls to qh_setlarger\n%7.2g average copy size\n", qhmem.cntlarger, ((float)qhmem.totlarger)/(float)qhmem.cntlarger); qh_fprintf(fp, 9280, " freelists(bytes->count):"); } for (i=0; i < qhmem.TABLEsize; i++) { count=0; for (object= qhmem .freelists[i]; object; object= *((void **)object)) count++; qh_fprintf(fp, 9281, " %d->%d", qhmem.sizetable[i], count); } qh_fprintf(fp, 9282, "\n\n"); } /* memstatistics */
/*-<a href="qh-mem.htm#TOC" >-------------------------------</a><a name="memsize">-</a> qh_memsize( size ) define a free list for this size */ void qh_memsize(int size) { int k; if (qhmem .LASTsize) { qh_fprintf(qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n"); qh_errexit(qhmem_ERRqhull, NULL, NULL); } size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask; for (k=qhmem.TABLEsize; k--; ) { if (qhmem.sizetable[k] == size) return; } if (qhmem.TABLEsize < qhmem.NUMsizes) qhmem.sizetable[qhmem.TABLEsize++]= size; else qh_fprintf(qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes); } /* memsize */
/* Check that a set contains count elements Ranges are consecutive (e.g., 1,2,3,...) starting with first, mid, and last Use -1 for missing ranges Returns -1 if should check results */ int log_i(setT *set, const char *s, int i, int numInts, int checkEvery) { int j= i; int scale= 1; int e= 0; int *i2, **i2p; if(*s || checkEvery==1){ if(i<10){ qh_fprintf(stderr, 8004, " %s%d", s, i); }else{ if(i==11 && checkEvery==1){ qh_fprintf(stderr, 8005, "\nResults after 10: "); FOREACHint_(set){ qh_fprintf(stderr, 8006, " %d", *i2); } qh_fprintf(stderr, 8007, " Continue"); } while((j= j/10)>=1){ scale *= 10; e++; } if(i==numInts-1){ qh_fprintf(stderr, 8008, " %s%d", s, i); }else if(i==scale){ if(i<=1000){ qh_fprintf(stderr, 8010, " %s%d", s, i); }else{ qh_fprintf(stderr, 8009, " %s1e%d", s, e); } } } }
void qh_meminit(FILE *ferr) { memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */ qhmem.ferr= ferr; if (sizeof(void*) < sizeof(int)) { qh_fprintf(ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int)); qh_errexit(qhmem_ERRqhull, NULL, NULL); } }
void qh_memfree(void *object, int insize) { if (!object) return; qh_free(object); qhmem .freelong++; qhmem .totlong -= insize; if (qhmem.IStracing >= 5) qh_fprintf(qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); }
void testSetdelsortedEtc(int numInts, int *intarray, int checkEvery) { setT *ints= qh_setnew(1); setT *ints2= NULL; int i,j; qh_fprintf(stderr, 8018, "\n\nTesting qh_setdel*, qh_setaddsorted, and 0..%d. Test", numInts-1); for(j=0; j<numInts; j++){ if(log_i(ints, "j", j, numInts, checkEvery)){ for(i= qh_setsize(ints); i<j; i++){ /* Test i<j to test the empty set */ qh_setaddsorted(&ints, intarray+i); } checkSetContents("qh_setaddsorted", ints, j, 0, 0, -1); if(j>3){ qh_setdelsorted(ints, intarray+i/2); checkSetContents("qh_setdelsorted", ints, j-1, 0, i/2+1, -1); qh_setaddsorted(&ints, intarray+i/2); checkSetContents("qh_setaddsorted i/2", ints, j, 0, 0, -1); } qh_setdellast(ints); checkSetContents("qh_setdellast", ints, (j ? j-1 : 0), 0, -1, -1); if(j>0){ qh_setaddsorted(&ints, intarray+j-1); checkSetContents("qh_setaddsorted j-1", ints, j, 0, -1, -1); } if(j>4){ qh_setdelnthsorted(ints, i/2); if (checkEvery==1) checkSetContents("qh_setdelnthsorted", ints, j-1, 0, i/2+1, -1); /* test qh_setdelnth and move-to-front */ qh_setdelsorted(ints, intarray+i/2+1); checkSetContents("qh_setdelsorted 2", ints, j-2, 0, i/2+2, -1); qh_setaddsorted(&ints, intarray+i/2+1); if (checkEvery==1) checkSetContents("qh_setaddsorted i/2+1", ints, j-1, 0, i/2+1, -1); qh_setaddsorted(&ints, intarray+i/2); checkSetContents("qh_setaddsorted i/2 again", ints, j, 0, -1, -1); } qh_setfree(&ints2); ints2= qh_setcopy(ints, 0); qh_setcompact(ints); qh_setcompact(ints2); checkSetContents("qh_setcompact", ints, j, 0, 0, -1); checkSetContents("qh_setcompact 2", ints2, j, 0, 0, -1); qh_setcompact(ints); checkSetContents("qh_setcompact 3", ints, j, 0, 0, -1); qh_setfree(&ints2); } } qh_setfreelong(&ints); if(ints){ qh_setfree(&ints); /* Was quick memory */ } }/*testSetdelsortedEtc*/
/*-<a href="qh-mem.htm#TOC" >-------------------------------</a><a name="meminitbuffers">-</a> qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit ) initialize qhmem if tracelevel >= 5, trace memory allocations alignment= desired address alignment for memory allocations numsizes= number of freelists bufsize= size of additional memory buffers for short allocations bufinit= size of initial memory buffer for short allocations */ void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) { qhmem.IStracing= tracelevel; qhmem.NUMsizes= numsizes; qhmem.BUFsize= bufsize; qhmem.BUFinit= bufinit; qhmem.ALIGNmask= alignment-1; if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) { qh_fprintf(qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment); qh_errexit(qhmem_ERRqhull, NULL, NULL); } qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int)); qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *)); if (!qhmem.sizetable || !qhmem.freelists) { qh_fprintf(qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n"); qh_errexit(qhmem_ERRmem, NULL, NULL); } if (qhmem.IStracing >= 1) qh_fprintf(qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment); } /* meminitbuffers */
/*-<a href="qh-globa.htm#TOC" >-------------------------------</a><a name="argv_to_command">-</a> qh_argv_to_command( argc, argv, command, max_size ) build command from argc/argv max_size is at least returns: a space-delimited string of options (just as typed) returns false if max_size is too short notes: silently removes makes option string easy to input and output matches qh_argv_to_command_size() argc may be 0 */ int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) { int i, remaining; char *s; *command= '\0'; /* max_size > 0 */ if (argc) { if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */ || (s= strrchr( argv[0], '/'))) s++; else s= argv[0]; if ((int)strlen(s) < max_size) /* WARN64 */ strcpy(command, s); else goto error_argv; if ((s= strstr(command, ".EXE")) || (s= strstr(command, ".exe"))) *s= '\0'; } for (i=1; i < argc; i++) { s= argv[i]; remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2; /* WARN64 */ if (!*s || strchr(s, ' ')) { char *t= command + strlen(command); remaining -= 2; if (remaining < 0) { goto error_argv; } *t++= ' '; *t++= '"'; while (*s) { if (*s == '"') { if (--remaining < 0) goto error_argv; *t++= '\\'; } *t++= *s++; } *t++= '"'; *t= '\0'; }else if (remaining < 0) { goto error_argv; }else strcat(command, " "); strcat(command, s); } return 1; error_argv: qh_fprintf(qh ferr, 6033, "qhull input error: more than %d characters in command line\n", max_size); return 0; } /* argv_to_command */
/*-<a href="qh-mem.htm#TOC" >--------------------------------</a><a name="memcheck">-</a> qh_memcheck( ) */ void qh_memcheck(void) { int i, count, totfree= 0; void *object; if (qhmem.ferr == 0 || qhmem.IStracing < 0 || qhmem.IStracing > 10 || (((qhmem.ALIGNmask+1) & qhmem.ALIGNmask) != 0)) { qh_fprintf_stderr(6244, "qh_memcheck error: either qhmem is overwritten or qhmem is not initialized. Call qh_meminit() or qh_new_qhull() before calling qh_mem routines. ferr 0x%x IsTracing %d ALIGNmask 0x%x", qhmem.ferr, qhmem.IStracing, qhmem.ALIGNmask); qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */ } if (qhmem.IStracing != 0) qh_fprintf(qhmem.ferr, 8143, "qh_memcheck: check size of freelists on qhmem\nqh_memcheck: A segmentation fault indicates an overwrite of qhmem\n"); for (i=0; i < qhmem.TABLEsize; i++) { count=0; for (object= qhmem.freelists[i]; object; object= *((void **)object)) count++; totfree += qhmem.sizetable[i] * count; } if (totfree != qhmem.totfree) { qh_fprintf(qhmem.ferr, 6211, "Qhull internal error (qh_memcheck): totfree %d not equal to freelist total %d\n", qhmem.totfree, totfree); qh_errexit(qhmem_ERRqhull, NULL, NULL); } if (qhmem.IStracing != 0) qh_fprintf(qhmem.ferr, 8144, "qh_memcheck: total size of freelists totfree is the same as qhmem.totfree\n", totfree); } /* memcheck */
/*-<a href="qh-mem.htm#TOC" >-------------------------------</a><a name="memsetup">-</a> qh_memsetup() set up memory after running memsize() */ void qh_memsetup(void) { int k,i; qsort(qhmem.sizetable, (size_t)qhmem.TABLEsize, sizeof(int), qh_intcompare); qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1]; if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) { qh_fprintf(qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n", qhmem .LASTsize, qhmem .BUFsize, qhmem .BUFinit); qh_errexit(qhmem_ERRmem, NULL, NULL); } if (!(qhmem.indextable= (int *)qh_malloc((qhmem.LASTsize+1) * sizeof(int)))) { qh_fprintf(qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n"); qh_errexit(qhmem_ERRmem, NULL, NULL); } for (k=qhmem.LASTsize+1; k--; ) qhmem.indextable[k]= k; i= 0; for (k=0; k <= qhmem.LASTsize; k++) { if (qhmem.indextable[k] <= qhmem.sizetable[i]) qhmem.indextable[k]= i; else qhmem.indextable[k]= ++i; } } /* memsetup */
void testSettemp(int numInts, int *intarray, int checkEvery) { setT *ints= NULL; setT *ints2= NULL; setT *ints3= NULL; int i,j; qh_fprintf(stderr, 8021, "\n\nTesting qh_settemp* 0..%d. Test", numInts-1); for(j=0; j<numInts; j++){ if(log_i(ints, "j", j, numInts, checkEvery)){ if(j<20){ for(i=0; i<j; i++){ ints2= qh_settemp(j); } qh_settempfree_all(); } for(i= qh_setsize(ints); i<j; i++){ /* Test i<j to test the empty set */ qh_setappend(&ints, intarray+i); } ints2= qh_settemp(j); if(j>0){ qh_settemppush(ints); ints3= qh_settemppop(); if(ints!=ints3){ qh_fprintf(stderr, 6343, "qh_settemppop: didn't pop the push\n"); error_count++; } } qh_settempfree(&ints2); } } qh_setfreelong(&ints); if(ints){ qh_setfree(&ints); /* Was quick memory */ } }/*testSettemp*/
void testSetappendSet(int numInts, int *intarray, int checkEvery) { setT *ints=qh_setnew(1); setT *ints2; int i,j,k; qh_fprintf(stderr, 8016, "\n\nTesting qh_setappend_set 0..%d. Test", numInts-1); for(j=0; j<numInts; j++){ if(log_i(ints, "j", j, numInts, numInts)){ for(i= qh_setsize(ints); i<j; i++){ qh_setappend(&ints, intarray+i); } if(checkEvery==1){ checkSetContents("qh_setappend", ints, j, 0, -1, -1); } ints2= qh_setnew(j==0 ? 0 : j-1); /* One less than needed */ for(i= 0; i<=j && i<=20; i++){ /* otherwise too slow */ if(log_i(ints, "", i, numInts, numInts)){ for(k= qh_setsize(ints2); k<i; k++){ qh_setappend(&ints2, intarray+k); } if(checkEvery==1){ checkSetContents("qh_setappend 2", ints2, i, 0, -1, -1); } qh_setappend_set(&ints, ints2); checkSetContents("qh_setappend_set", ints, i+j, 0, (j==0 ? -1 : 0), -1); qh_settruncate(ints, j); if(checkEvery==1){ checkSetContents("qh_settruncate", ints, j, 0, -1, -1); } } } qh_setfree(&ints2); } } qh_setfree(&ints); }/*testSetappendSet*/
void testSetlastEtc(int numInts, int *intarray, int checkEvery) { setT *ints= NULL; setT *ints2= NULL; int i,j,prepend; qh_fprintf(stderr, 8020, "\n\nTesting qh_setlast, qh_setnew_delnthsorted, qh_setunique, and qh_setzero 0..%d. Test", numInts-1); for(j=0; j<numInts; j++){ if(log_i(ints, "j", j, numInts, checkEvery)){ for(i= qh_setsize(ints); i<j; i++){ /* Test i<j to test the empty set */ if(!qh_setunique(&ints, intarray+i)){ qh_fprintf(stderr, 6340, "qh_setunique: not able to append next element %d\n", i); error_count++; } if(checkEvery==1){ checkSetContents("qh_setunique", ints, i+1, 0, -1, -1); } if(qh_setunique(&ints, intarray+i)){ qh_fprintf(stderr, 6341, "qh_setunique: appended next element twice %d\n", i); error_count++; } if(qh_setunique(&ints, intarray+i/2)){ qh_fprintf(stderr, 6346, "qh_setunique: appended middle element twice %d/2\n", i); error_count++; } } checkSetContents("qh_setunique 2", ints, j, 0, -1, -1); if(j==0 && NULL!=qh_setlast(ints)){ qh_fprintf(stderr, 6339, "qh_setlast: returned last element of empty set\n"); error_count++; } if(j>0){ if(intarray+j-1!=qh_setlast(ints)){ qh_fprintf(stderr, 6338, "qh_setlast: wrong last element\n"); error_count++; } prepend= (j<100 ? j/4 : 0); ints2= qh_setnew_delnthsorted(ints, qh_setsize(ints), j/2, prepend); if(qh_setsize(ints2)!=j+prepend-1){ qh_fprintf(stderr, 6345, "qh_setnew_delnthsorted: Expecting %d elements, got %d\n", j+prepend-1, qh_setsize(ints2)); error_count++; } /* Define prepended elements. Otherwise qh_setdelnthsorted may fail */ for(i= 0; i<prepend; i++){ void **p= &SETelem_(ints2, i); *p= intarray+0; } for(i= 0; i<prepend; i++){ qh_setdelnthsorted(ints2, 0); /* delete undefined prefix */ } checkSetContents("qh_setnew_delnthsorted", ints2, j-1, 0, j/2+1, -1); if(j>2){ qh_setzero(ints2, j/2, j-1); /* max size may be j-1 */ if(qh_setsize(ints2)!=j-1){ qh_fprintf(stderr, 6342, "qh_setzero: Expecting %d elements, got %d\n", j, qh_setsize(ints2)); error_count++; } qh_setcompact(ints2); checkSetContents("qh_setzero", ints2, j/2, 0, -1, -1); } } qh_setfree(&ints2); } } qh_setfreelong(&ints); if(ints){ qh_setfree(&ints); /* Was quick memory */ } }/*testSetlastEtc*/
void testSetequalInEtc(int numInts, int *intarray, int checkEvery) { setT *ints= NULL; setT *ints2= NULL; setT *ints3= NULL; int i,j,n; qh_fprintf(stderr, 8019, "\n\nTesting qh_setequal*, qh_setin*, qh_setdel, qh_setdelnth, and qh_setlarger 0..%d. Test", numInts-1); for(j=0; j<numInts; j++){ if(log_i(ints, "j", j, numInts, checkEvery)){ n= qh_setsize(ints); qh_setlarger(&ints); checkSetContents("qh_setlarger", ints, n, 0, -1, -1); for(i= qh_setsize(ints); i<j; i++){ /* Test i<j to test the empty set */ qh_setappend(&ints, intarray+i); } checkSetContents("qh_setappend", ints, j, 0, -1, -1); if(!qh_setequal(ints, ints)){ qh_fprintf(stderr, 6300, "testSetequalInEtc: set not equal to itself at length %d\n", j); error_count++; } if(j==0 && !qh_setequal(ints, ints2)){ qh_fprintf(stderr, 6323, "testSetequalInEtc: empty set not equal to null set\n"); error_count++; } if(j>0){ if(qh_setequal(ints, ints2)){ qh_fprintf(stderr, 6324, "testSetequalInEtc: non-empty set equal to empty set\n", j); error_count++; } qh_setfree(&ints3); ints3= qh_setcopy(ints, 0); checkSetContents("qh_setreplace", ints3, j, 0, -1, -1); qh_setreplace(ints3, intarray+j/2, intarray+j/2+1); if(j==1){ checkSetContents("qh_setreplace 2", ints3, j, j/2+1, -1, -1); }else if(j==2){ checkSetContents("qh_setreplace 3", ints3, j, 0, j/2+1, -1); }else{ checkSetContents("qh_setreplace 3", ints3, j, 0, j/2+1, j/2+1); } if(qh_setequal(ints, ints3)){ qh_fprintf(stderr, 6325, "testSetequalInEtc: modified set equal to original set at %d/2\n", j); error_count++; } if(!qh_setequal_except(ints, intarray+j/2, ints3, intarray+j/2+1)){ qh_fprintf(stderr, 6326, "qh_setequal_except: modified set not equal to original set except modified\n", j); error_count++; } if(qh_setequal_except(ints, intarray+j/2, ints3, intarray)){ qh_fprintf(stderr, 6327, "qh_setequal_except: modified set equal to original set with wrong excepts\n", j); error_count++; } if(!qh_setequal_skip(ints, j/2, ints3, j/2)){ qh_fprintf(stderr, 6328, "qh_setequal_skip: modified set not equal to original set except modified\n", j); error_count++; } if(j>2 && qh_setequal_skip(ints, j/2, ints3, 0)){ qh_fprintf(stderr, 6329, "qh_setequal_skip: modified set equal to original set with wrong excepts\n", j); error_count++; } if(intarray+j/2+1!=qh_setdel(ints3, intarray+j/2+1)){ qh_fprintf(stderr, 6330, "qh_setdel: failed to find added element\n", j); error_count++; } checkSetContents("qh_setdel", ints3, j-1, 0, j-1, (j==1 ? -1 : j/2+1)); /* swaps last element with deleted element */ if(j>3){ qh_setdelnth(ints3, j/2); /* Delete at the same location as the original replace, for only one out-of-order element */ checkSetContents("qh_setdelnth", ints3, j-2, 0, j-2, (j==2 ? -1 : j/2+1)); } if(qh_setin(ints3, intarray+j/2)){ qh_fprintf(stderr, 6331, "qh_setin: found deleted element\n"); error_count++; } if(j>4 && !qh_setin(ints3, intarray+1)){ qh_fprintf(stderr, 6332, "qh_setin: did not find second element\n"); error_count++; } if(j>4 && !qh_setin(ints3, intarray+j-2)){ qh_fprintf(stderr, 6333, "qh_setin: did not find last element\n"); error_count++; } if(-1!=qh_setindex(ints2, intarray)){ qh_fprintf(stderr, 6334, "qh_setindex: found element in empty set\n"); error_count++; } if(-1!=qh_setindex(ints3, intarray+j/2)){ qh_fprintf(stderr, 6335, "qh_setindex: found deleted element in set\n"); error_count++; } if(0!=qh_setindex(ints, intarray)){ qh_fprintf(stderr, 6336, "qh_setindex: did not find first in set\n"); error_count++; } if(j-1!=qh_setindex(ints, intarray+j-1)){ qh_fprintf(stderr, 6337, "qh_setindex: did not find last in set\n"); error_count++; } } qh_setfree(&ints2); } } qh_setfree(&ints3); qh_setfreelong(&ints); if(ints){ qh_setfree(&ints); /* Was quick memory */ } }/*testSetequalInEtc*/
/*-<a href="qh-mem.htm#TOC" >--------------------------------</a><a name="memalloc">-</a> qh_memalloc( insize ) returns object of insize bytes qhmem is the global memory structure returns: pointer to allocated memory errors if insufficient memory notes: use explicit type conversion to avoid type warnings on some compilers actual object may be larger than insize use qh_memalloc_() for inline code for quick allocations logs allocations if 'T5' design: if size < qhmem.LASTsize if qhmem.freelists[size] non-empty return first object on freelist else round up request to size of qhmem.freelists[size] allocate new allocation buffer if necessary allocate object from allocation buffer else allocate object with qh_malloc() in user.c */ void *qh_memalloc(int insize) { void **freelistp, *newbuffer; int idx, size, n; int outsize, bufsize; void *object; if (insize<0) { qh_fprintf(qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d). Did int overflow due to high-D?\n", insize); /* WARN64 */ qh_errexit(qhmem_ERRmem, NULL, NULL); } if (insize>=0 && insize <= qhmem.LASTsize) { idx= qhmem.indextable[insize]; outsize= qhmem.sizetable[idx]; qhmem.totshort += outsize; freelistp= qhmem.freelists+idx; if ((object= *freelistp)) { qhmem.cntquick++; qhmem.totfree -= outsize; *freelistp= *((void **)*freelistp); /* replace freelist with next object */ #ifdef qh_TRACEshort n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort; if (qhmem.IStracing >= 5) qh_fprintf(qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort); #endif return(object); } else { qhmem.cntshort++; if (outsize > qhmem .freesize) { qhmem .totdropped += qhmem .freesize; if (!qhmem.curbuffer) bufsize= qhmem.BUFinit; else bufsize= qhmem.BUFsize; if (!(newbuffer= qh_malloc((size_t)bufsize))) { qh_fprintf(qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize); qh_errexit(qhmem_ERRmem, NULL, NULL); } *((void **)newbuffer)= qhmem.curbuffer; /* prepend newbuffer to curbuffer list */ qhmem.curbuffer= newbuffer; size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask; qhmem.freemem= (void *)((char *)newbuffer+size); qhmem.freesize= bufsize - size; qhmem.totbuffer += bufsize - size; /* easier to check */ /* Periodically test totbuffer. It matches at beginning and exit of every call */ n = qhmem.totshort + qhmem.totfree + qhmem.totdropped + qhmem.freesize - outsize; if (qhmem.totbuffer != n) { qh_fprintf(qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qhmem.totbuffer, n); qh_errexit(qhmem_ERRmem, NULL, NULL); } } object= qhmem.freemem; qhmem.freemem= (void *)((char *)qhmem.freemem + outsize); qhmem.freesize -= outsize; qhmem.totunused += outsize - insize; #ifdef qh_TRACEshort n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort; if (qhmem.IStracing >= 5) qh_fprintf(qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort); #endif return object; } } else { /* long allocation */ if (!qhmem.indextable) { qh_fprintf(qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n"); qh_errexit(qhmem_ERRqhull, NULL, NULL); } outsize= insize; qhmem .cntlong++; qhmem .totlong += outsize; if (qhmem.maxlong < qhmem.totlong) qhmem.maxlong= qhmem.totlong; if (!(object= qh_malloc((size_t)outsize))) { qh_fprintf(qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize); qh_errexit(qhmem_ERRmem, NULL, NULL); } if (qhmem.IStracing >= 5) qh_fprintf(qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, outsize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); } return(object); } /* memalloc */