blender/extern/qhull/src/mem.c
2007-08-28 10:07:08 +00:00

448 lines
13 KiB
C

/*<html><pre> -<a href="qh-mem.htm"
>-------------------------------</a><a name="TOP">-</a>
mem.c
memory management routines for qhull
This is a standalone program.
To initialize memory:
qh_meminit (stderr);
qh_meminitbuffers (qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf);
qh_memsize(sizeof(facetT));
qh_memsize(sizeof(facetT));
...
qh_memsetup();
To free up all memory buffers:
qh_memfreeshort (&curlong, &totlong);
if qh_NOmem,
malloc/free is used instead of mem.c
notes:
uses Quickfit algorithm (freelists for commonly allocated sizes)
assumes small sizes for freelists (it discards the tail of memory buffers)
see:
qh-mem.htm and mem.h
global.c (qh_initbuffers) for an example of using mem.c
copyright (c) 1993-2002 The Geometry Center
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mem.h"
#ifndef qhDEFqhull
typedef struct ridgeT ridgeT;
typedef struct facetT facetT;
void qh_errexit(int exitcode, facetT *, ridgeT *);
#endif
/*============ -global data structure ==============
see mem.h for definition
*/
qhmemT qhmem= {0}; /* remove "= {0}" if this causes a compiler error */
#ifndef qh_NOmem
/*============= internal functions ==============*/
static int qh_intcompare(const void *i, const void *j);
/*========== functions in alphabetical order ======== */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="intcompare">-</a>
qh_intcompare( i, j )
used by qsort and bsearch to compare two integers
*/
static int qh_intcompare(const void *i, const void *j) {
return(*((int *)i) - *((int *)j));
} /* intcompare */
/*-<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 malloc()
*/
void *qh_memalloc(int insize) {
void **freelistp, *newbuffer;
int index, size;
int outsize, bufsize;
void *object;
if ((unsigned) insize <= (unsigned) qhmem.LASTsize) {
index= qhmem.indextable[insize];
freelistp= qhmem.freelists+index;
if ((object= *freelistp)) {
qhmem.cntquick++;
*freelistp= *((void **)*freelistp); /* replace freelist with next object */
return (object);
}else {
outsize= qhmem.sizetable[index];
qhmem.cntshort++;
if (outsize > qhmem .freesize) {
if (!qhmem.curbuffer)
bufsize= qhmem.BUFinit;
else
bufsize= qhmem.BUFsize;
qhmem.totshort += bufsize;
if (!(newbuffer= malloc(bufsize))) {
fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
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;
}
object= qhmem.freemem;
qhmem.freemem= (void *)((char *)qhmem.freemem + outsize);
qhmem.freesize -= outsize;
return object;
}
}else { /* long allocation */
if (!qhmem.indextable) {
fprintf (qhmem.ferr, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n");
qh_errexit(qhmem_ERRqhull, NULL, NULL);
}
outsize= insize;
qhmem .cntlong++;
qhmem .curlong++;
qhmem .totlong += outsize;
if (qhmem.maxlong < qhmem.totlong)
qhmem.maxlong= qhmem.totlong;
if (!(object= malloc(outsize))) {
fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
if (qhmem.IStracing >= 5)
fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", outsize, object);
}
return (object);
} /* memalloc */
/*-<a href="qh-mem.htm#TOC"
>--------------------------------</a><a name="memfree">-</a>
qh_memfree( object, size )
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 free(object)
*/
void qh_memfree(void *object, int size) {
void **freelistp;
if (!object)
return;
if (size <= qhmem.LASTsize) {
qhmem .freeshort++;
freelistp= qhmem.freelists + qhmem.indextable[size];
*((void **)object)= *freelistp;
*freelistp= object;
}else {
qhmem .freelong++;
qhmem .totlong -= size;
free (object);
if (qhmem.IStracing >= 5)
fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
}
} /* memfree */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="memfreeshort">-</a>
qh_memfreeshort( curlong, totlong )
frees up all short and qhmem memory allocations
returns:
number and size of current long allocations
*/
void qh_memfreeshort (int *curlong, int *totlong) {
void *buffer, *nextbuffer;
*curlong= qhmem .cntlong - qhmem .freelong;
*totlong= qhmem .totlong;
for(buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) {
nextbuffer= *((void **) buffer);
free(buffer);
}
qhmem.curbuffer= NULL;
if (qhmem .LASTsize) {
free (qhmem .indextable);
free (qhmem .freelists);
free (qhmem .sizetable);
}
memset((char *)&qhmem, 0, sizeof qhmem); /* every field is 0, FALSE, NULL */
} /* memfreeshort */
/*-<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)) {
fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int). qset.c will not work\n");
exit (1); /* can not use qh_errexit() */
}
} /* meminit */
/*-<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) {
fprintf (qhmem.ferr, "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 (numsizes, sizeof(int));
qhmem.freelists= (void **) calloc (numsizes, sizeof(void *));
if (!qhmem.sizetable || !qhmem.freelists) {
fprintf(qhmem.ferr, "qhull error (qh_meminit): insufficient memory\n");
qh_errexit (qhmem_ERRmem, NULL, NULL);
}
if (qhmem.IStracing >= 1)
fprintf (qhmem.ferr, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment);
} /* meminitbuffers */
/*-<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, qhmem.TABLEsize, sizeof(int), qh_intcompare);
qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1];
if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) {
fprintf (qhmem.ferr, "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 *)malloc((qhmem.LASTsize+1) * sizeof(int)))) {
fprintf(qhmem.ferr, "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 */
/*-<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) {
fprintf (qhmem .ferr, "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
fprintf(qhmem.ferr, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes);
} /* memsize */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="memstatistics">-</a>
qh_memstatistics( fp )
print out memory statistics
notes:
does not account for wasted memory at the end of each block
*/
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;
}
fprintf (fp, "\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 long memory allocated (except for input)\n\
%7d bytes of long memory in use (in %d pieces)\n\
%7d bytes per memory buffer (initially %d bytes)\n",
qhmem .cntquick, qhmem.cntshort, qhmem.cntlong,
qhmem .freeshort, qhmem.freelong,
qhmem .totshort - qhmem .freesize - totfree,
totfree,
qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong,
qhmem .BUFsize, qhmem .BUFinit);
if (qhmem.cntlarger) {
fprintf (fp, "%7d calls to qh_setlarger\n%7.2g average copy size\n",
qhmem.cntlarger, ((float) qhmem.totlarger)/ qhmem.cntlarger);
fprintf (fp, " freelists (bytes->count):");
}
for (i=0; i < qhmem.TABLEsize; i++) {
count=0;
for (object= qhmem .freelists[i]; object; object= *((void **)object))
count++;
fprintf (fp, " %d->%d", qhmem.sizetable[i], count);
}
fprintf (fp, "\n\n");
} /* memstatistics */
/*-<a href="qh-mem.htm#TOC"
>-------------------------------</a><a name="NOmem">-</a>
qh_NOmem
turn off quick-fit memory allocation
notes:
uses malloc() and free() instead
*/
#else /* qh_NOmem */
void *qh_memalloc(int insize) {
void *object;
if (!(object= malloc(insize))) {
fprintf(qhmem.ferr, "qhull error (qh_memalloc): insufficient memory\n");
qh_errexit(qhmem_ERRmem, NULL, NULL);
}
if (qhmem.IStracing >= 5)
fprintf (qhmem.ferr, "qh_memalloc long: %d bytes at %p\n", insize, object);
return object;
}
void qh_memfree(void *object, int size) {
if (!object)
return;
free (object);
if (qhmem.IStracing >= 5)
fprintf (qhmem.ferr, "qh_memfree long: %d bytes at %p\n", size, object);
}
void qh_memfreeshort (int *curlong, int *totlong) {
memset((char *)&qhmem, 0, sizeof qhmem); /* every field is 0, FALSE, NULL */
*curlong= 0;
*totlong= 0;
}
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)) {
fprintf (ferr, "qhull internal error (qh_meminit): sizeof(void*) < sizeof(int). qset.c will not work\n");
qh_errexit (qhmem_ERRqhull, NULL, NULL);
}
}
void qh_meminitbuffers (int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) {
qhmem.IStracing= tracelevel;
}
void qh_memsetup (void) {
}
void qh_memsize(int size) {
}
void qh_memstatistics (FILE *fp) {
}
#endif /* qh_NOmem */