/* ******** airArrayLenPreSet() ** ** allocates the array to hold up to given length, without ** actually changing the length. In order for this to be ** useful, this also turns on noReallocWhenSmaller ** ** NB: this used to have a "boolean" return to indicate allocation ** error, but nothing in Teem actually did the error checking. Now ** conscientious users can look at NULL-ity of a->data to detect such ** an error. */ void airArrayLenPreSet(airArray *a, unsigned int newlen) { unsigned int newsize; void *newdata; if (!a) { return; } if (newlen == 0) { /* there is no pre-set length, turn off noReallocWhenSmaller */ a->noReallocWhenSmaller = AIR_FALSE; } else { newsize = (newlen-1)/a->incr + 1; if (newsize > a->size) { newdata = calloc(newsize*a->incr, a->unit); if (!newdata) { free(a->data); _airSetData(a, NULL); return; } memcpy(newdata, a->data, AIR_MIN(a->len*a->unit, newsize*a->incr*a->unit)); free(a->data); _airSetData(a, newdata); a->size = newsize; } a->noReallocWhenSmaller = AIR_TRUE; } return; }
/* ******** airArrayNew() ** ** creates a new airArray struct and returns a pointer to it. ** dataP is a pointer to the user's data pointer ** lenP is a pointer to the user's array length variable (optional) ** unit is the size (in bytes) of one element in the array ** incr is the number of units by which the array will grow or shrink ** ** returns NULL on error, or the new airArray pointer if okay ** errors: bogus arguments, or couldn't alloc airArray struct ** ** --> The user CAN NOT change the pointer variable (of which *dataP ** is the address) after this is called, or else everything will ** get all bolloxed up. The same goes for the array length ** variable, if its address is passed- though in that case the ** correct value will over-write any other. */ airArray * airArrayNew(void **dataP, unsigned int *lenP, size_t unit, unsigned int incr) { airArray *a; if (unit<=0 || incr<=0) { return NULL; } a = (airArray *)calloc(1, sizeof(airArray)); if (!a) { return NULL; } a->dataP = dataP; _airSetData(a, NULL); a->lenP = lenP; _airLenSet(a, 0); a->incr = incr; a->unit = unit; a->noReallocWhenSmaller = AIR_FALSE; a->allocCB = NULL; a->freeCB = NULL; a->initCB = NULL; a->doneCB = NULL; return a; }
/* ******** airArrayLenPreSet() ** ** allocates the array to hold up to given length, without ** actually changing the length. In order for this to be ** useful, this also turns on noReallocWhenSmaller ** ** NB: this used to have a "boolean" return to indicate allocation ** error, but nothing in Teem actually did the error checking. Now ** conscientious users can look at NULL-ity of a->data to detect such ** an error. */ void airArrayLenPreSet(airArray *a, unsigned int newlen) { /* char me[]="airArrayLenPreSet"; */ unsigned int newsize; void *newdata; if (!a) { return; } if (newlen == 0) { /* there is no pre-set length, turn off noReallocWhenSmaller */ a->noReallocWhenSmaller = AIR_FALSE; } else { newsize = (newlen-1)/a->incr + 1; /* fprintf(stderr, "!%s: newlen = %u, incr = %u -> newsize = %u\n", me, newlen, a->incr, newsize); fprintf(stderr, "!%s: a->size = %u, a->len = %u, a->unit = %u\n", me, a->size, a->len, a->unit); */ if (newsize > a->size) { newdata = calloc(newsize*a->incr, a->unit); /* fprintf(stderr, "!%s: a->data = %p, newdata = %p\n", me, a->data, newdata); */ if (!newdata) { free(a->data); _airSetData(a, NULL); return; } if (a->data) { memcpy(newdata, a->data, AIR_MIN(a->len*a->unit, newsize*a->incr*a->unit)); free(a->data); } _airSetData(a, newdata); a->size = newsize; } a->noReallocWhenSmaller = AIR_TRUE; } /* fprintf(stderr, "!%s: returning data %p\n", me, a->data); */ return; }
/* ******** airArrayLenSet() ** ** Set the length of the array, allocating or freeing as needed ** ** returns 1 on error, otherwise 0 if okay ** possible errors: bogus arguments, or couldn't allocate new memory segment ** ** In case we can't allocate the new space, the old space is left untouched, ** however if the new length is smaller, the free/done callbacks will ** have been called on invalidated elements ** ** NB: this used to have a "boolean" return to indicate allocation ** error, but almost nothing in Teem actually did the error checking. ** Now conscientious users can look at NULL-ity of a->data to detect ** such an error. */ void airArrayLenSet(airArray *a, unsigned int newlen) { unsigned int newsize; int ii; void *addr, *newdata; if (!a) { /* user is a moron, what can you do */ return; } if (newlen == a->len) { /* nothing to do */ return; } /* call freeCB/doneCB on all the elements which are going bye-bye */ if (newlen < a->len && (a->freeCB || a->doneCB)) { for (ii=a->len-1; ii>=(int)newlen; ii--) { addr = (char*)(a->data) + ii*a->unit; if (a->freeCB) { (a->freeCB)(*((void**)addr)); } else { (a->doneCB)(addr); } } } newsize = newlen ? (newlen-1)/a->incr + 1 : 0; if (newsize != a->size) { /* we have to change the size of the array */ if (newsize) { /* array should be bigger or smaller, but not zero-length */ if (newsize > a->size || (newsize < a->size && !(a->noReallocWhenSmaller)) ) { newdata = calloc(newsize*a->incr, a->unit); if (!newdata) { free(a->data); _airSetData(a, NULL); return; } memcpy(newdata, a->data, AIR_MIN(a->len*a->unit, newsize*a->incr*a->unit)); free(a->data); _airSetData(a, newdata); a->size = newsize; } } else { /* array should be zero-length */ free(a->data); _airSetData(a, NULL); a->size = newsize; } } /* else new size is still within current allocated length, and neither "size" nor "data" need to change */ /* call allocCB/initCB on newly created elements */ if (newlen > a->len && (a->allocCB || a->initCB)) { for (ii=newlen; ii<(int)(a->len); ii++) { addr = (char*)(a->data) + ii*a->unit; if (a->allocCB) { *((void**)addr) = (a->allocCB)(); } else { (a->initCB)(addr); } } } _airLenSet(a, newlen); return; }