226 lines
7.1 KiB
C
226 lines
7.1 KiB
C
/* ========================================================================== */
|
|
/* === 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 size_t 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) : ((size_t) -1)) ;
|
|
}
|
|
|
|
/* ========================================================================== */
|
|
/* === KLU_mult_size_t ====================================================== */
|
|
/* ========================================================================== */
|
|
|
|
/* Safely compute a*k, where k should be small, and check for size_t 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 ((*ok) ? s : ((size_t) -1)) ;
|
|
}
|
|
|
|
/* ========================================================================== */
|
|
/* === 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 (Common == NULL)
|
|
{
|
|
p = NULL ;
|
|
}
|
|
else 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 */
|
|
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 ;
|
|
}
|
|
else
|
|
{
|
|
Common->memusage += s ;
|
|
Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
|
|
}
|
|
}
|
|
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, n, sizeof (int), Common) ;
|
|
*/
|
|
|
|
void *KLU_free /* always returns NULL */
|
|
(
|
|
/* ---- in/out --- */
|
|
void *p, /* block of memory to free */
|
|
/* ---- input --- */
|
|
size_t n, /* size of block to free, in # of items */
|
|
size_t size, /* size of each item */
|
|
/* --------------- */
|
|
KLU_common *Common
|
|
)
|
|
{
|
|
size_t s ;
|
|
Int ok = TRUE ;
|
|
if (p != NULL && Common != NULL)
|
|
{
|
|
/* only free the object if the pointer is not NULL */
|
|
/* call free, or its equivalent */
|
|
(Common->free_memory) (p) ;
|
|
s = KLU_mult_size_t (MAX (1,n), size, &ok) ;
|
|
Common->memusage -= s ;
|
|
}
|
|
/* 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, nold, 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 nold, /* old # of items */
|
|
size_t size, /* size of each item */
|
|
/* ---- in/out --- */
|
|
void *p, /* block of memory to realloc */
|
|
/* --------------- */
|
|
KLU_common *Common
|
|
)
|
|
{
|
|
void *pnew ;
|
|
size_t snew, sold ;
|
|
Int ok = TRUE ;
|
|
|
|
if (Common == NULL)
|
|
{
|
|
p = NULL ;
|
|
}
|
|
else 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 */
|
|
snew = KLU_mult_size_t (MAX (1,nnew), size, &ok) ;
|
|
sold = KLU_mult_size_t (MAX (1,nold), size, &ok) ;
|
|
pnew = ok ? ((Common->realloc_memory) (p, snew)) : 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 */
|
|
Common->memusage += (snew - sold) ;
|
|
Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
|
|
p = pnew ;
|
|
}
|
|
}
|
|
return (p) ;
|
|
}
|