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 
55 template <typename Int>
56 size_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 
68 template <typename Int>
69 size_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 
97 template <typename Entry, typename Int>
98 void *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 
158 template <typename Entry, typename Int>
159 void *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 
207 template <typename Entry, typename Int>
208 void *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 */