Amesos2 - Direct Sparse Solver Interfaces Version of the Day
klu2_memory.hpp
1/* ========================================================================== */
2/* === KLU_memory =========================================================== */
3/* ========================================================================== */
4// @HEADER
5// ***********************************************************************
6//
7// KLU2: A Direct Linear Solver package
8// Copyright 2011 Sandia Corporation
9//
10// Under terms of Contract DE-AC04-94AL85000, with Sandia Corporation, the
11// U.S. Government retains certain rights in this software.
12//
13// This library is free software; you can redistribute it and/or modify
14// it under the terms of the GNU Lesser General Public License as
15// published by the Free Software Foundation; either version 2.1 of the
16// License, or (at your option) any later version.
17//
18// This library is distributed in the hope that it will be useful, but
19// WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21// Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public
24// License along with this library; if not, write to the Free Software
25// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
26// USA
27// Questions? Contact Mike A. Heroux (maherou@sandia.gov)
28//
29// KLU2 is derived work from KLU, licensed under LGPL, and copyrighted by
30// University of Florida. The Authors of KLU are Timothy A. Davis and
31// Eka Palamadai. See Doc/KLU_README.txt for the licensing and copyright
32// information for KLU.
33//
34// ***********************************************************************
35// @HEADER
36
37/* KLU memory management routines:
38 *
39 * KLU_malloc malloc wrapper
40 * KLU_free free wrapper
41 * KLU_realloc realloc wrapper
42 */
43
44#ifndef KLU2_MEMORY_H
45#define KLU2_MEMORY_H
46
47#include "klu2_internal.h"
48
49/* ========================================================================== */
50/* === KLU_add_size_t ======================================================= */
51/* ========================================================================== */
52
53/* Safely compute a+b, and check for size_t overflow */
54
55template <typename Int>
56size_t KLU_add_size_t (size_t a, size_t b, Int *ok)
57{
58 (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
59 return ((*ok) ? (a + b) : ((size_t) -1)) ;
60}
61
62/* ========================================================================== */
63/* === KLU_mult_size_t ====================================================== */
64/* ========================================================================== */
65
66/* Safely compute a*k, where k should be small, and check for size_t overflow */
67
68template <typename Int>
69size_t KLU_mult_size_t (size_t a, size_t k, Int *ok)
70{
71 size_t i, s = 0 ;
72 for (i = 0 ; i < k ; i++)
73 {
74 s = KLU_add_size_t (s, a, ok) ;
75 }
76 return ((*ok) ? s : ((size_t) -1)) ;
77}
78
79/* ========================================================================== */
80/* === KLU_malloc =========================================================== */
81/* ========================================================================== */
82
83/* Wrapper around malloc routine (mxMalloc for a mexFunction). Allocates
84 * space of size MAX(1,n)*size, where size is normally a sizeof (...).
85 *
86 * This routine and KLU_realloc do not set Common->status to KLU_OK on success,
87 * so that a sequence of KLU_malloc's or KLU_realloc's can be used. If any of
88 * them fails, the Common->status will hold the most recent error status.
89 *
90 * Usage, for a pointer to Int:
91 *
92 * p = KLU_malloc (n, sizeof (Int), Common)
93 *
94 * Uses a pointer to the malloc routine (or its equivalent) defined in Common.
95 */
96
97template <typename Entry, typename Int>
98void *KLU_malloc /* returns pointer to the newly malloc'd block */
99(
100 /* ---- input ---- */
101 size_t n, /* number of items */
102 size_t size, /* size of each item */
103 /* --------------- */
104 KLU_common<Entry, Int> *Common
105)
106{
107 void *p ;
108 size_t s ;
109 Int ok = TRUE ;
110
111 if (Common == NULL)
112 {
113 p = NULL ;
114 }
115 else if (size == 0)
116 {
117 /* size must be > 0 */
118 Common->status = KLU_INVALID ;
119 p = NULL ;
120 }
121 else if (n >= INT_MAX)
122 {
123 /* object is too big to allocate; p[i] where i is an Int will not
124 * be enough. */
125 Common->status = KLU_TOO_LARGE ;
126 p = NULL ;
127 }
128 else
129 {
130 /* call malloc, or its equivalent */
131 s = KLU_mult_size_t (MAX (1,n), size, &ok) ;
132 p = ok ? ((Common->malloc_memory) (s)) : NULL ;
133 if (p == NULL)
134 {
135 /* failure: out of memory */
136 Common->status = KLU_OUT_OF_MEMORY ;
137 }
138 else
139 {
140 Common->memusage += s ;
141 Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
142 }
143 }
144 return (p) ;
145}
146
147
148/* ========================================================================== */
149/* === KLU_free ============================================================= */
150/* ========================================================================== */
151
152/* Wrapper around free routine (mxFree for a mexFunction). Returns NULL,
153 * which can be assigned to the pointer being freed, as in:
154 *
155 * p = KLU_free (p, n, sizeof (int), Common) ;
156 */
157
158template <typename Entry, typename Int>
159void *KLU_free /* always returns NULL */
160(
161 /* ---- in/out --- */
162 void *p, /* block of memory to free */
163 /* ---- input --- */
164 size_t n, /* size of block to free, in # of items */
165 size_t size, /* size of each item */
166 /* --------------- */
167 KLU_common<Entry, Int> *Common
168)
169{
170 size_t s ;
171 Int ok = TRUE ;
172 if (p != NULL && Common != NULL)
173 {
174 /* only free the object if the pointer is not NULL */
175 /* call free, or its equivalent */
176 (Common->free_memory) (p) ;
177 s = KLU_mult_size_t (MAX (1,n), size, &ok) ;
178 Common->memusage -= s ;
179 }
180 /* return NULL, and the caller should assign this to p. This avoids
181 * freeing the same pointer twice. */
182 return (NULL) ;
183}
184
185
186/* ========================================================================== */
187/* === KLU_realloc ========================================================== */
188/* ========================================================================== */
189
190/* Wrapper around realloc routine (mxRealloc for a mexFunction). Given a
191 * pointer p to a block allocated by KLU_malloc, it changes the size of the
192 * block pointed to by p to be MAX(1,nnew)*size in size. It may return a
193 * pointer different than p. This should be used as (for a pointer to Int):
194 *
195 * p = KLU_realloc (nnew, nold, sizeof (Int), p, Common) ;
196 *
197 * If p is NULL, this is the same as p = KLU_malloc (...).
198 * A size of nnew=0 is treated as nnew=1.
199 *
200 * If the realloc fails, p is returned unchanged and Common->status is set
201 * to KLU_OUT_OF_MEMORY. If successful, Common->status is not modified,
202 * and p is returned (possibly changed) and pointing to a large block of memory.
203 *
204 * Uses a pointer to the realloc routine (or its equivalent) defined in Common.
205 */
206
207template <typename Entry, typename Int>
208void *KLU_realloc /* returns pointer to reallocated block */
209(
210 /* ---- input ---- */
211 size_t nnew, /* requested # of items in reallocated block */
212 size_t nold, /* old # of items */
213 size_t size, /* size of each item */
214 /* ---- in/out --- */
215 void *p, /* block of memory to realloc */
216 /* --------------- */
217 KLU_common<Entry, Int> *Common
218)
219{
220 void *pnew ;
221 size_t snew, sold ;
222 Int ok = TRUE ;
223
224 if (Common == NULL)
225 {
226 p = NULL ;
227 }
228 else if (size == 0)
229 {
230 /* size must be > 0 */
231 Common->status = KLU_INVALID ;
232 p = NULL ;
233 }
234 else if (p == NULL)
235 {
236 /* A fresh object is being allocated. */
237 p = KLU_malloc (nnew, size, Common) ;
238 }
239 else if (nnew >= INT_MAX)
240 {
241 /* failure: nnew is too big. Do not change p */
242 Common->status = KLU_TOO_LARGE ;
243 }
244 else
245 {
246 /* The object exists, and is changing to some other nonzero size. */
247 /* call realloc, or its equivalent */
248 snew = KLU_mult_size_t (MAX (1,nnew), size, &ok) ;
249 sold = KLU_mult_size_t (MAX (1,nold), size, &ok) ;
250 pnew = ok ? ((Common->realloc_memory) (p, snew)) : NULL ;
251 if (pnew == NULL)
252 {
253 /* Do not change p, since it still points to allocated memory */
254 Common->status = KLU_OUT_OF_MEMORY ;
255 }
256 else
257 {
258 /* success: return the new p and change the size of the block */
259 Common->memusage += (snew - sold) ;
260 Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
261 p = pnew ;
262 }
263 }
264 return (p) ;
265}
266
267#endif /* KLU_MEMORY_H */