/* ========================================================================== */
/* === klu_memory =========================================================== */
/* ========================================================================== */
/* KLU memory management routines:
*
* klu_malloc malloc wrapper
* klu_free free wrapper
* klu_realloc realloc wrapper
*/
#include "klu_internal.h"
/* ========================================================================== */
/* === klu_add_size_t ======================================================= */
/* ========================================================================== */
/* Safely compute a+b, and check for integer overflow */
size_t klu_add_size_t (size_t a, size_t b, int *ok)
{
(*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
return ((*ok) ? (a + b) : 0) ;
}
/* ========================================================================== */
/* === klu_mult_size_t ====================================================== */
/* ========================================================================== */
/* Safely compute a*k, where k should be small, & check for integer overflow */
size_t klu_mult_size_t (size_t a, size_t k, int *ok)
{
size_t i, s = 0 ;
for (i = 0 ; i < k ; i++)
{
s = klu_add_size_t (s, a, ok) ;
}
return (s) ;
}
/* ========================================================================== */
/* === klu_malloc =========================================================== */
/* ========================================================================== */
/* Wrapper around malloc routine (mxMalloc for a mexFunction). Allocates
* space of size MAX(1,n)*size, where size is normally a sizeof (...).
*
* This routine and klu_realloc do not set Common->status to KLU_OK on success,
* so that a sequence of klu_malloc's or klu_realloc's can be used. If any of
* them fails, the Common->status will hold the most recent error status.
*
* Usage, for a pointer to int:
*
* p = klu_malloc (n, sizeof (int), Common)
*
* Uses a pointer to the malloc routine (or its equivalent) defined in Common.
*/
void *klu_malloc /* returns pointer to the newly malloc'd block */
(
/* ---- input ---- */
size_t n, /* number of items */
size_t size, /* size of each item */
/* --------------- */
klu_common *Common
)
{
void *p ;
size_t s ;
int ok = TRUE ;
if (size == 0)
{
/* size must be > 0 */
Common->status = KLU_INVALID ;
p = NULL ;
}
else if (n >= INT_MAX)
{
/* object is too big to allocate; p[i] where i is an int will not
* be enough. */
Common->status = KLU_TOO_LARGE ;
p = NULL ;
}
else
{
/* call malloc, or its equivalent */
/*
p = (Common->malloc_memory) (MAX (1,n) * size) ;
*/
s = klu_mult_size_t (MAX (1,n), size, &ok) ;
p = ok ? ((Common->malloc_memory) (s)) : NULL ;
if (p == NULL)
{
/* failure: out of memory */
Common->status = KLU_OUT_OF_MEMORY ;
}
}
return (p) ;
}
/* ========================================================================== */
/* === klu_free ============================================================= */
/* ========================================================================== */
/* Wrapper around free routine (mxFree for a mexFunction). Returns NULL,
* which can be assigned to the pointer being freed, as in:
*
* p = klu_free (p, Common) ;
*/
void *klu_free /* always returns NULL */
(
/* ---- in/out --- */
void *p, /* block of memory to free */
/* --------------- */
klu_common *Common
)
{
if (p != NULL)
{
/* only free the object if the pointer is not NULL */
/* call free, or its equivalent */
(Common->free_memory) (p) ;
}
/* return NULL, and the caller should assign this to p. This avoids
* freeing the same pointer twice. */
return (NULL) ;
}
/* ========================================================================== */
/* === klu_realloc ========================================================== */
/* ========================================================================== */
/* Wrapper around realloc routine (mxRealloc for a mexFunction). Given a
* pointer p to a block allocated by klu_malloc, it changes the size of the
* block pointed to by p to be MAX(1,nnew)*size in size. It may return a
* pointer different than p. This should be used as (for a pointer to int):
*
* p = klu_realloc (nnew, sizeof (int), p, Common) ;
*
* If p is NULL, this is the same as p = klu_malloc (...).
* A size of nnew=0 is treated as nnew=1.
*
* If the realloc fails, p is returned unchanged and Common->status is set
* to KLU_OUT_OF_MEMORY. If successful, Common->status is not modified,
* and p is returned (possibly changed) and pointing to a large block of memory.
*
* Uses a pointer to the realloc routine (or its equivalent) defined in Common.
*/
void *klu_realloc /* returns pointer to reallocated block */
(
/* ---- input ---- */
size_t nnew, /* requested # of items in reallocated block */
size_t size, /* size of each item */
/* ---- in/out --- */
void *p, /* block of memory to realloc */
/* --------------- */
klu_common *Common
)
{
void *pnew ;
size_t s ;
int ok = TRUE ;
if (size == 0)
{
/* size must be > 0 */
Common->status = KLU_INVALID ;
p = NULL ;
}
else if (p == NULL)
{
/* A fresh object is being allocated. */
p = klu_malloc (nnew, size, Common) ;
}
else if (nnew >= INT_MAX)
{
/* failure: nnew is too big. Do not change p */
Common->status = KLU_TOO_LARGE ;
}
else
{
/* The object exists, and is changing to some other nonzero size. */
/* call realloc, or its equivalent */
/*
pnew = (Common->realloc_memory) (p, MAX (1,nnew) * size) ;
*/
s = klu_mult_size_t (MAX (1,nnew), size, &ok) ;
pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ;
if (pnew == NULL)
{
/* Do not change p, since it still points to allocated memory */
Common->status = KLU_OUT_OF_MEMORY ;
}
else
{
/* success: return the new p and change the size of the block */
p = pnew ;
}
}
return (p) ;
}
syntax highlighted by Code2HTML, v. 0.9.1