Scippy

SCIP

Solving Constraint Integer Programs

buffer.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file buffer.c
17  * @brief methods for memory buffers for temporary objects
18  * @author Tobias Achterberg
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 
25 #include "scip/def.h"
26 #include "scip/pub_message.h"
27 #include "blockmemshell/memory.h"
28 #include "scip/set.h"
29 #include "scip/buffer.h"
30 
31 #include "scip/struct_buffer.h"
32 
33 
34 
35 /** creates memory buffer storage */
37  SCIP_BUFFER** buffer /**< pointer to memory buffer storage */
38  )
39 {
40  assert(buffer != NULL);
41 
42  SCIP_ALLOC( BMSallocMemory(buffer) );
43  (*buffer)->data = NULL;
44  (*buffer)->size = NULL;
45  (*buffer)->used = NULL;
46  (*buffer)->ndata = 0;
47  (*buffer)->firstfree = 0;
48 
49  return SCIP_OKAY;
50 }
51 
52 /** frees memory buffer */
54  SCIP_BUFFER** buffer /**< pointer to memory buffer storage */
55  )
56 {
57  int i;
58 
59  assert(buffer != NULL);
60 
61  for( i = 0; i < (*buffer)->ndata; ++i )
62  {
63  assert(!(*buffer)->used[i]);
64  BMSfreeMemoryArrayNull(&(*buffer)->data[i]);
65  }
66  BMSfreeMemoryArrayNull(&(*buffer)->data);
67  BMSfreeMemoryArrayNull(&(*buffer)->size);
68  BMSfreeMemoryArrayNull(&(*buffer)->used);
69  BMSfreeMemory(buffer);
70 }
71 
72 /** allocates the next unused buffer */
74  SCIP_BUFFER* buffer, /**< memory buffer storage */
75  SCIP_SET* set, /**< global SCIP settings */
76  void** ptr, /**< pointer to store the allocated memory buffer */
77  int size /**< minimal required size of the buffer */
78  )
79 {
80 #ifndef SCIP_NOBUFFERMEM
81  int bufnum;
82 
83  assert(buffer != NULL);
84  assert(buffer->firstfree <= buffer->ndata);
85  assert(ptr != NULL);
86  assert(size >= 0);
87 
88  /* allocate minimal 1 byte */
89  if( size == 0 )
90  size = 1;
91 
92  /* check, if we need additional buffers */
93  if( buffer->firstfree == buffer->ndata )
94  {
95  int newsize;
96  int i;
97 
98  /* create additional buffers */
99  newsize = SCIPsetCalcMemGrowSize(set, buffer->firstfree+1);
100  SCIP_ALLOC( BMSreallocMemoryArray(&buffer->data, newsize) );
101  SCIP_ALLOC( BMSreallocMemoryArray(&buffer->size, newsize) );
102  SCIP_ALLOC( BMSreallocMemoryArray(&buffer->used, newsize) );
103  for( i = buffer->ndata; i < newsize; ++i )
104  {
105  buffer->data[i] = NULL;
106  buffer->size[i] = 0;
107  buffer->used[i] = FALSE;
108  }
109  buffer->ndata = newsize;
110  }
111  assert(buffer->firstfree < buffer->ndata);
112 
113  /* check, if the current buffer is large enough */
114  bufnum = buffer->firstfree;
115  assert(!buffer->used[bufnum]);
116  if( buffer->size[bufnum] < size )
117  {
118  int newsize;
119 
120  /* enlarge buffer */
121  newsize = SCIPsetCalcMemGrowSize(set, size);
122  SCIP_ALLOC( BMSreallocMemorySize(&buffer->data[bufnum], newsize) );
123  buffer->size[bufnum] = newsize;
124  }
125  assert(buffer->size[bufnum] >= size);
126 
127  *ptr = buffer->data[bufnum];
128  buffer->used[bufnum] = TRUE;
129  buffer->firstfree++;
130 
131  SCIPdebugMessage("allocated buffer %d/%d at %p of size %d (required size: %d) for pointer %p\n",
132  bufnum, buffer->ndata, buffer->data[bufnum], buffer->size[bufnum], size, (void*)ptr);
133 
134 #else
135  SCIP_ALLOC( BMSallocMemorySize(ptr, size) );
136 #endif
137 
138  return SCIP_OKAY;
139 }
140 
141 /** allocates the next unused buffer and copies the given memory into the buffer */
143  SCIP_BUFFER* buffer, /**< memory buffer storage */
144  SCIP_SET* set, /**< global SCIP settings */
145  void** ptr, /**< pointer to store the allocated memory buffer */
146  const void* source, /**< memory block to copy into the buffer */
147  int size /**< minimal required size of the buffer */
148  )
149 {
150  assert(source != NULL);
151 
152  /* allocate a buffer of the given size */
153  SCIP_CALL( SCIPbufferAllocMem(buffer, set, ptr, size) );
154 
155  /* copy the source memory into the buffer */
156  BMScopyMemorySize(*ptr, source, size);
157 
158  return SCIP_OKAY;
159 }
160 
161 /** reallocates the buffer to at least the given size */
163  SCIP_BUFFER* buffer, /**< memory buffer storage */
164  SCIP_SET* set, /**< global SCIP settings */
165  void** ptr, /**< pointer to the allocated memory buffer */
166  int size /**< minimal required size of the buffer */
167  )
168 {
169 #ifndef SCIP_NOBUFFERMEM
170  int bufnum;
171 
172  assert(buffer != NULL);
173  assert(buffer->firstfree <= buffer->ndata);
174  assert(ptr != NULL);
175  assert(size >= 0);
176 
177  /* if the pointer doesn't exist yet, allocate it */
178  if( *ptr == NULL )
179  return SCIPbufferAllocMem(buffer, set, ptr, size);
180 
181  assert(buffer->firstfree >= 1);
182 
183  /* Search the pointer in the buffer list
184  * Usually, buffers are allocated and freed like a stack, such that the currently used pointer is
185  * most likely at the end of the buffer list.
186  */
187  for( bufnum = buffer->firstfree-1; bufnum >= 0 && buffer->data[bufnum] != *ptr; --bufnum )
188  {
189  }
190  assert(bufnum >= 0);
191  assert(buffer->data[bufnum] == *ptr);
192  assert(buffer->used[bufnum]);
193  assert(buffer->size[bufnum] >= 1);
194 
195  /* check if the buffer has to be enlarged */
196  if( size > buffer->size[bufnum] )
197  {
198  int newsize;
199 
200  /* enlarge buffer */
201  newsize = SCIPsetCalcMemGrowSize(set, size);
202  SCIP_ALLOC( BMSreallocMemorySize(&buffer->data[bufnum], newsize) );
203  buffer->size[bufnum] = newsize;
204  *ptr = buffer->data[bufnum];
205  }
206  assert(buffer->size[bufnum] >= size);
207  assert(*ptr == buffer->data[bufnum]);
208 
209  SCIPdebugMessage("reallocated buffer %d/%d at %p to size %d (required size: %d) for pointer %p\n",
210  bufnum, buffer->ndata, buffer->data[bufnum], buffer->size[bufnum], size, (void*)ptr);
211 
212 #else
213  SCIP_ALLOC( BMSreallocMemorySize(ptr, size) );
214 #endif
215 
216  return SCIP_OKAY;
217 }
218 
219 #ifndef NDEBUG
220 /** allocates the next unused buffer; checks for integer overflow */
222  SCIP_SET* set, /**< global SCIP settings */
223  void** ptr, /**< pointer to store the allocated memory buffer */
224  int num, /**< number of entries to allocate */
225  size_t elemsize /**< size of one element in the array */
226  )
227 {
228  if( ((size_t)(num)) > (UINT_MAX / elemsize) )
229  {
230  *ptr = NULL;
231  return SCIP_NOMEMORY;
232  }
233 
234  SCIP_CALL( SCIPbufferAllocMem((set)->buffer, set, (void**)(ptr), (int)(num*elemsize)) );
235 
236  return SCIP_OKAY;
237 }
238 
239 /** allocates the next unused buffer and copies the given memory into the buffer; checks for integer overflows */
241  SCIP_SET* set, /**< global SCIP settings */
242  void** ptr, /**< pointer to store the allocated memory buffer */
243  const void* source, /**< memory block to copy into the buffer */
244  int num, /**< number of entries to copy */
245  size_t elemsize /**< size of one element in the array */
246  )
247 {
248  if( ((size_t)(num)) > (UINT_MAX / elemsize) )
249  {
250  *ptr = NULL;
251  return SCIP_NOMEMORY;
252  }
253 
254  SCIP_CALL( SCIPbufferDuplicateMem((set)->buffer, set, (void**)(ptr), source, (int)(num*elemsize)) );
255 
256  return SCIP_OKAY;
257 }
258 
259 /** reallocates the buffer to at least the given size; checks for integer overflows */
261  SCIP_SET* set, /**< global SCIP settings */
262  void** ptr, /**< pointer to the allocated memory buffer */
263  int num, /**< number of entries to get memory for */
264  size_t elemsize /**< size of one element in the array */
265  )
266 {
267  if( ((size_t)(num)) > (UINT_MAX / elemsize) )
268  {
269  *ptr = NULL;
270  return SCIP_NOMEMORY;
271  }
272 
273  SCIP_CALL( SCIPbufferReallocMem((set)->buffer, set, (void**)(ptr), (int)(num*elemsize)) );
274 
275  return SCIP_OKAY;
276 }
277 #endif
278 
279 /** frees a buffer */
281  SCIP_BUFFER* buffer, /**< memory buffer storage */
282  void** ptr, /**< pointer to the allocated memory buffer */
283  int dummysize /**< used to get a safer define for SCIPsetFreeBufferSize/Array */
284  )
285 { /*lint --e{715}*/
286 #ifndef SCIP_NOBUFFERMEM
287  int bufnum;
288 
289  assert(buffer != NULL);
290  assert(buffer->firstfree <= buffer->ndata);
291  assert(buffer->firstfree >= 1);
292  assert(dummysize == 0);
293 
294  /* Search the pointer in the buffer list
295  * Usually, buffers are allocated and freed like a stack, such that the freed pointer is
296  * most likely at the end of the buffer list.
297  */
298  for( bufnum = buffer->firstfree-1; bufnum >= 0 && buffer->data[bufnum] != *ptr; --bufnum )
299  {
300  }
301  assert(bufnum >= 0);
302  assert(buffer->data[bufnum] == *ptr);
303  assert(buffer->used[bufnum]);
304 
305  *ptr = NULL;
306  buffer->used[bufnum] = FALSE;
307 
308  while( buffer->firstfree > 0 && !buffer->used[buffer->firstfree-1] )
309  buffer->firstfree--;
310 
311  SCIPdebugMessage("freed buffer %d/%d at %p of size %d for pointer %p, first free is %d\n",
312  bufnum, buffer->ndata, buffer->data[bufnum], buffer->size[bufnum], (void*)ptr, buffer->firstfree);
313 
314 #else
315  BMSfreeMemory(ptr);
316 #endif
317 }
318 
319 /** gets number of used buffers */
321  SCIP_BUFFER* buffer /**< memory buffer storage */
322  )
323 {
324  assert(buffer != NULL);
325 
326  return buffer->firstfree;
327 }
328 
329 /** outputs statistics about currently allocated buffers to the screen */
331  SCIP_BUFFER* buffer /**< memory buffer storage */
332  )
333 {
334  int totalmem;
335  int i;
336 
337  assert(buffer != NULL);
338 
339  totalmem = 0;
340  for( i = 0; i < buffer->ndata; ++i )
341  {
342  printf("[%c] %8d bytes at %p\n", buffer->used[i] ? '*' : ' ', buffer->size[i], buffer->data[i]);
343  totalmem += buffer->size[i];
344  }
345  printf(" %8d bytes total in %d buffers\n", totalmem, buffer->ndata);
346 }
347 
348 
349