/* These are some dynamic memory allocation facilities. They are essentially an extension to C, as they do allocations with a cognizance of C variables. You can use them to make C read more like a high level language. Before including this, you must define an __inline__ macro if your compiler doesn't recognize it as a keyword. */ #ifndef MALLOCVAR_INCLUDED #define MALLOCVAR_INCLUDED #include "pm_config.h" #include #include #ifdef __cplusplus extern "C" { #endif #if 0 } /* to fake out automatic code indenters */ #endif static __inline__ void mallocProduct(void ** const resultP, size_t const factor1, unsigned int const factor2) { /*---------------------------------------------------------------------------- malloc a space whose size in bytes is the product of 'factor1' and 'factor2'. But if the malloc fails, or that size is too large even to request from malloc, return NULL without allocating anything. If either factor is zero, malloc a single byte. -----------------------------------------------------------------------------*/ /* C99 introduces SIZE_MAX, the maximum size_t value. Pre-C99, we do the best we can, assuming conventional encoding of numbers and that size_t is unsigned. */ size_t const sizeMax = #if defined(SIZE_MAX) SIZE_MAX #else ~((size_t)0) #endif ; if (factor1 == 0 || factor2 == 0) *resultP = malloc(1); else { /* N.B. The type of malloc's argument is size_t */ if ((size_t)factor2 != factor2) *resultP = NULL; else { if (sizeMax / factor2 < factor1) *resultP = NULL; else *resultP = malloc(factor1 * factor2); } } } static __inline__ void reallocProduct(void ** const blockP, size_t const factor1, unsigned int const factor2) { /*---------------------------------------------------------------------------- Reallocate the block at *blockPP to size 'factor1' * 'factor2'. (Reallocate means make *blockPP point to a block of that size that contains the same data as the block to which *blockP points now, with additional space as needed at the end). If *blockPP is null, make *blockPP point to a new block of memory of the desired size with no contents. If the reallocation fails, release any memory pointed by *blockP and make *blockP null. -----------------------------------------------------------------------------*/ size_t const sizeMax = #if defined(SIZE_MAX) SIZE_MAX #else ~((size_t)0) #endif ; void * const oldBlockP = *blockP; void * newBlockP; /* N.B. The type of realloc's argument is size_t */ if ((size_t)factor2 != factor2) newBlockP = NULL; else { if (sizeMax / factor2 < factor1) newBlockP = NULL; else newBlockP = realloc(oldBlockP, factor1 * factor2); } if (newBlockP) *blockP = newBlockP; else { free(oldBlockP); *blockP = NULL; } } #define MALLOCARRAY(arrayName, nElements) do { \ void * array; \ mallocProduct(&array, nElements, sizeof(arrayName[0])); \ arrayName = array; \ } while (0) #define REALLOCARRAY(arrayName, nElements) do { \ void * array; \ array = arrayName; \ reallocProduct(&array, nElements, sizeof(arrayName[0])); \ arrayName = array; \ } while (0) #define MALLOCARRAY_NOFAIL(arrayName, nElements) \ do { \ MALLOCARRAY(arrayName, nElements); \ if ((arrayName) == NULL) \ abort(); \ } while(0) #define REALLOCARRAY_NOFAIL(arrayName, nElements) \ do { \ REALLOCARRAY(arrayName, nElements); \ if ((arrayName) == NULL) \ abort(); \ } while(0) #define MALLOCARRAY2(arrayName, nRows, nCols) do { \ void * array; \ pm_mallocarray2(&array, nRows, nCols, sizeof(arrayName[0][0])); \ arrayName = array; \ } while (0) #define MALLOCARRAY2_NOFAIL(arrayName, nRows, nCols) do { \ MALLOCARRAY2(arrayName, nRows, nCols); \ if ((arrayName) == NULL) \ abort(); \ } while (0) void pm_freearray2(void ** const rowIndex); #define MALLOCVAR(varName) \ varName = malloc(sizeof(*varName)) #define MALLOCVAR_NOFAIL(varName) \ do {if ((varName = malloc(sizeof(*varName))) == NULL) abort();} while(0) void pm_mallocarray2(void ** const resultP, unsigned int const cols, unsigned int const rows, unsigned int const elementSize); #ifdef __cplusplus } #endif #endif