Amesos2 - Direct Sparse Solver Interfaces  Version of the Day
klu2_memory.hpp
1 /* ========================================================================== */
2 /* === KLU_memory =========================================================== */
3 /* ========================================================================== */
4 // @HEADER
5 // *****************************************************************************
6 // KLU2: A Direct Linear Solver package
7 //
8 // Copyright 2011 NTESS and the KLU2 contributors.
9 // SPDX-License-Identifier: LGPL-2.1-or-later
10 // *****************************************************************************
11 // @HEADER
12 
13 /* KLU memory management routines:
14  *
15  * KLU_malloc malloc wrapper
16  * KLU_free free wrapper
17  * KLU_realloc realloc wrapper
18  */
19 
20 #ifndef KLU2_MEMORY_H
21 #define KLU2_MEMORY_H
22 
23 #include "klu2_internal.h"
24 
25 /* ========================================================================== */
26 /* === KLU_add_size_t ======================================================= */
27 /* ========================================================================== */
28 
29 /* Safely compute a+b, and check for size_t overflow */
30 
31 template <typename Int>
32 size_t KLU_add_size_t (size_t a, size_t b, Int *ok)
33 {
34  (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
35  return ((*ok) ? (a + b) : ((size_t) -1)) ;
36 }
37 
38 /* ========================================================================== */
39 /* === KLU_mult_size_t ====================================================== */
40 /* ========================================================================== */
41 
42 /* Safely compute a*k, where k should be small, and check for size_t overflow */
43 
44 template <typename Int>
45 size_t KLU_mult_size_t (size_t a, size_t k, Int *ok)
46 {
47  size_t i, s = 0 ;
48  for (i = 0 ; i < k ; i++)
49  {
50  s = KLU_add_size_t (s, a, ok) ;
51  }
52  return ((*ok) ? s : ((size_t) -1)) ;
53 }
54 
55 /* ========================================================================== */
56 /* === KLU_malloc =========================================================== */
57 /* ========================================================================== */
58 
59 /* Wrapper around malloc routine (mxMalloc for a mexFunction). Allocates
60  * space of size MAX(1,n)*size, where size is normally a sizeof (...).
61  *
62  * This routine and KLU_realloc do not set Common->status to KLU_OK on success,
63  * so that a sequence of KLU_malloc's or KLU_realloc's can be used. If any of
64  * them fails, the Common->status will hold the most recent error status.
65  *
66  * Usage, for a pointer to Int:
67  *
68  * p = KLU_malloc (n, sizeof (Int), Common)
69  *
70  * Uses a pointer to the malloc routine (or its equivalent) defined in Common.
71  */
72 
73 template <typename Entry, typename Int>
74 void *KLU_malloc /* returns pointer to the newly malloc'd block */
75 (
76  /* ---- input ---- */
77  size_t n, /* number of items */
78  size_t size, /* size of each item */
79  /* --------------- */
80  KLU_common<Entry, Int> *Common
81 )
82 {
83  void *p ;
84  size_t s ;
85  Int ok = TRUE ;
86 
87  if (Common == NULL)
88  {
89  p = NULL ;
90  }
91  else if (size == 0)
92  {
93  /* size must be > 0 */
94  Common->status = KLU_INVALID ;
95  p = NULL ;
96  }
97  else if (n >= INT_MAX)
98  {
99  /* object is too big to allocate; p[i] where i is an Int will not
100  * be enough. */
101  Common->status = KLU_TOO_LARGE ;
102  p = NULL ;
103  }
104  else
105  {
106  /* call malloc, or its equivalent */
107  s = KLU_mult_size_t (MAX (1,n), size, &ok) ;
108  p = ok ? ((Common->malloc_memory) (s)) : NULL ;
109  if (p == NULL)
110  {
111  /* failure: out of memory */
112  Common->status = KLU_OUT_OF_MEMORY ;
113  }
114  else
115  {
116  Common->memusage += s ;
117  Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
118  }
119  }
120  return (p) ;
121 }
122 
123 
124 /* ========================================================================== */
125 /* === KLU_free ============================================================= */
126 /* ========================================================================== */
127 
128 /* Wrapper around free routine (mxFree for a mexFunction). Returns NULL,
129  * which can be assigned to the pointer being freed, as in:
130  *
131  * p = KLU_free (p, n, sizeof (int), Common) ;
132  */
133 
134 template <typename Entry, typename Int>
135 void *KLU_free /* always returns NULL */
136 (
137  /* ---- in/out --- */
138  void *p, /* block of memory to free */
139  /* ---- input --- */
140  size_t n, /* size of block to free, in # of items */
141  size_t size, /* size of each item */
142  /* --------------- */
143  KLU_common<Entry, Int> *Common
144 )
145 {
146  size_t s ;
147  Int ok = TRUE ;
148  if (p != NULL && Common != NULL)
149  {
150  /* only free the object if the pointer is not NULL */
151  /* call free, or its equivalent */
152  (Common->free_memory) (p) ;
153  s = KLU_mult_size_t (MAX (1,n), size, &ok) ;
154  Common->memusage -= s ;
155  }
156  /* return NULL, and the caller should assign this to p. This avoids
157  * freeing the same pointer twice. */
158  return (NULL) ;
159 }
160 
161 
162 /* ========================================================================== */
163 /* === KLU_realloc ========================================================== */
164 /* ========================================================================== */
165 
166 /* Wrapper around realloc routine (mxRealloc for a mexFunction). Given a
167  * pointer p to a block allocated by KLU_malloc, it changes the size of the
168  * block pointed to by p to be MAX(1,nnew)*size in size. It may return a
169  * pointer different than p. This should be used as (for a pointer to Int):
170  *
171  * p = KLU_realloc (nnew, nold, sizeof (Int), p, Common) ;
172  *
173  * If p is NULL, this is the same as p = KLU_malloc (...).
174  * A size of nnew=0 is treated as nnew=1.
175  *
176  * If the realloc fails, p is returned unchanged and Common->status is set
177  * to KLU_OUT_OF_MEMORY. If successful, Common->status is not modified,
178  * and p is returned (possibly changed) and pointing to a large block of memory.
179  *
180  * Uses a pointer to the realloc routine (or its equivalent) defined in Common.
181  */
182 
183 template <typename Entry, typename Int>
184 void *KLU_realloc /* returns pointer to reallocated block */
185 (
186  /* ---- input ---- */
187  size_t nnew, /* requested # of items in reallocated block */
188  size_t nold, /* old # of items */
189  size_t size, /* size of each item */
190  /* ---- in/out --- */
191  void *p, /* block of memory to realloc */
192  /* --------------- */
193  KLU_common<Entry, Int> *Common
194 )
195 {
196  void *pnew ;
197  size_t snew, sold ;
198  Int ok = TRUE ;
199 
200  if (Common == NULL)
201  {
202  p = NULL ;
203  }
204  else if (size == 0)
205  {
206  /* size must be > 0 */
207  Common->status = KLU_INVALID ;
208  p = NULL ;
209  }
210  else if (p == NULL)
211  {
212  /* A fresh object is being allocated. */
213  p = KLU_malloc (nnew, size, Common) ;
214  }
215  else if (nnew >= INT_MAX)
216  {
217  /* failure: nnew is too big. Do not change p */
218  Common->status = KLU_TOO_LARGE ;
219  }
220  else
221  {
222  /* The object exists, and is changing to some other nonzero size. */
223  /* call realloc, or its equivalent */
224  snew = KLU_mult_size_t (MAX (1,nnew), size, &ok) ;
225  sold = KLU_mult_size_t (MAX (1,nold), size, &ok) ;
226  pnew = ok ? ((Common->realloc_memory) (p, snew)) : NULL ;
227  if (pnew == NULL)
228  {
229  /* Do not change p, since it still points to allocated memory */
230  Common->status = KLU_OUT_OF_MEMORY ;
231  }
232  else
233  {
234  /* success: return the new p and change the size of the block */
235  Common->memusage += (snew - sold) ;
236  Common->mempeak = MAX (Common->mempeak, Common->memusage) ;
237  p = pnew ;
238  }
239  }
240  return (p) ;
241 }
242 
243 #endif /* KLU_MEMORY_H */
const int size
Definition: klu2_simple.cpp:50