/* grow.c : dynamically resize allocated arrays */ /* Copyright (c) 2013-2015, 2020 Jon Mayo * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* The purpose of the wrapper function of grow() is to do the necessary book * keeping for a dynamic array with realloc(). * * Usage: * * float *f = NULL; * int f_allocated = 0; * int f_used = 0; * * float testdata[] = { 1.0, 2.0, 3.0, 4.0, }; * int i; * * for (i = 0; i < 4; i++) { * if (grow(&f, &f_allocated, f_used + 1, sizeof(*f)) != 0) { * return -1; // error * } * f[f_used++] = testdata[i]; * } * */ #include "grow.h" #include #include #include #include /* grow * * The argument ptr needs to be a pointer to a pointer. (i.e. long** from a & * of a long* pointer) * * max is maintained by this function and only needs to be initialized the * first time. further increases are determined by the logic that doubles the * size each time growth is required. * * min is the minimum size that must be allocated. after this function * successfully returns you may access that minimum index into the array. * * elem is the size of an element. (e.g. sizeof(*arr)) * * return is 0 on success, -1 on error */ int grow(void *ptr, unsigned *max, unsigned min, size_t elem) { size_t old = *max * elem; size_t new = min * elem; char *p; if (new <= old) { return 0; } /* round up to next power-of-2 bigger than a pointer */ new += sizeof(void*); new--; new |= new >> 1; new |= new >> 2; new |= new >> 4; new |= new >> 8; new |= new >> 16; new++; new -= sizeof(void*); *max = new / elem; assert(ptr != NULL); assert(old <= new); p = realloc(*(char**)ptr, new); if (!p) { perror(__func__); return -1; } memset(p + old, 0, new - old); *(void**)ptr = p; assert(*(void**)ptr != NULL); return 0; }