1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the library                         */
4    	/*          BMS --- Block Memory Shell                                       */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2022 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  BMS 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 BMS; see the file COPYING. If not email to scip@zib.de.       */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file   memory.c
17   	 * @ingroup OTHER_CFILES
18   	 * @brief  memory allocation routines
19   	 * @author Tobias Achterberg
20   	 * @author Gerald Gamrath
21   	 * @author Marc Pfetsch
22   	 * @author Jakob Witzig
23   	 */
24   	
25   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
26   	
27   	#ifdef __cplusplus
28   	#define __STDC_LIMIT_MACROS
29   	#endif
30   	
31   	#include <stdio.h>
32   	#include <stdlib.h>
33   	#include <assert.h>
34   	#include <string.h>
35   	
36   	/*
37   	 * include build configuration flags
38   	 */
39   	#ifndef NO_CONFIG_HEADER
40   	#include "scip/config.h"
41   	#endif
42   	
43   	#ifdef WITH_SCIPDEF
44   	#include "scip/def.h"
45   	#include "scip/pub_message.h"
46   	#else
47   	#include <stdint.h>
48   	#endif
49   	
50   	#include "blockmemshell/memory.h"
51   	#include "scip/rbtree.h"
52   	
53   	/* uncomment the following to enable the use of a memlist in debug mode
54   	 * that checks for some memory leaks and allows to add the additional
55   	 * checks enabled with the defines below.
56   	 * The maintenance of the memlist, however, is not threadsafe.
57   	 */
58   	#ifndef SCIP_THREADSAFE
59   	/*#define ENABLE_MEMLIST_CHECKS*/
60   	#endif
61   	
62   	#ifdef ENABLE_MEMLIST_CHECKS
63   	/* uncomment the following for debugging:
64   	 * - CHECKMEM:      run a thorough test on every memory function call, very slow
65   	 * - CHECKCHKFREE:  check for the presence of a pointer in a chunk block
66   	 */
67   	/*#define CHECKMEM*/
68   	/*#define CHECKCHKFREE*/
69   	#endif
70   	
71   	/* Uncomment the following for checks that clean buffer is really clean when being freed. */
72   	/* #define CHECKCLEANBUFFER */
73   	
74   	/* Uncomment the following for a warnings if buffers are not freed in the reverse order of allocation. */
75   	/* #define CHECKBUFFERORDER */
76   	
77   	/* if we are included in SCIP, use SCIP's message output methods */
78   	#ifdef SCIPdebugMessage
79   	#define debugMessage SCIPdebugMessage
80   	#define errorMessage SCIPerrorMessage
81   	#else
82   	#define debugMessage while( FALSE ) printf
83   	#define errorMessage printf
84   	#define printErrorHeader(f,l) printf("[%s:%d] ERROR: ", f, l)
85   	#define printError printf
86   	#endif
87   	
88   	#ifdef ENABLE_MEMLIST_CHECKS
89   	#define warningMessage printf
90   	#endif
91   	#define printInfo printf
92   	
93   	/* define some macros (if not already defined) */
94   	#ifndef FALSE
95   	#define FALSE 0
96   	#define TRUE  1
97   	#endif
98   	#ifndef MAX
99   	#define MAX(x,y) ((x) >= (y) ? (x) : (y))
100  	#define MIN(x,y) ((x) <= (y) ? (x) : (y))
101  	#endif
102  	
103  	#ifndef SCIP_LONGINT_FORMAT
104  	#if defined(_WIN32) || defined(_WIN64)
105  	#define LONGINT_FORMAT           "I64d"
106  	#else
107  	#define LONGINT_FORMAT           "lld"
108  	#endif
109  	#else
110  	#define LONGINT_FORMAT SCIP_LONGINT_FORMAT
111  	#endif
112  	
113  	#ifndef SCIP_MAXMEMSIZE
114  	/* we take SIZE_MAX / 2 to detect negative sizes which got a very large value when casting to (unsigned) size_t */
115  	#define MAXMEMSIZE SIZE_MAX / 2
116  	#else
117  	#define MAXMEMSIZE SCIP_MAXMEMSIZE
118  	#endif
119  	
120  	/* define inline (if not already defined) */
121  	#ifndef INLINE
122  	#if defined(_WIN32) || defined(_WIN64) || defined(__STDC__)
123  	#define INLINE                 __inline
124  	#else
125  	#define INLINE                 inline
126  	#endif
127  	#endif
128  	
129  	/*************************************************************************************
130  	 * Standard Memory Management
131  	 *
132  	 * In debug mode, these methods extend malloc() and free() by logging all currently
133  	 * allocated memory elements in an allocation list. This can be used as a simple leak
134  	 * detection.
135  	 *************************************************************************************/
136  	#if !defined(NDEBUG) && defined(ENABLE_MEMLIST_CHECKS)
137  	
138  	typedef struct Memlist MEMLIST;         /**< memory list for debugging purposes */
139  	
140  	/** memory list for debugging purposes */
141  	struct Memlist
142  	{
143  	   const void*           ptr;                /**< pointer to allocated memory */
144  	   size_t                size;               /**< size of memory element */
145  	   char*                 filename;           /**< source file where the allocation was performed */
146  	   int                   line;               /**< line number in source file where the allocation was performed */
147  	   MEMLIST*              next;               /**< next entry in the memory list */
148  	};
149  	
150  	static MEMLIST*          memlist = NULL;     /**< global memory list for debugging purposes */
151  	static size_t            memused = 0;        /**< number of allocated bytes */
152  	
153  	#ifdef CHECKMEM
154  	/** checks, whether the number of allocated bytes match the entries in the memory list */
155  	static
156  	void checkMemlist(
157  	   void
158  	   )
159  	{
160  	   MEMLIST* list = memlist;
161  	   size_t used = 0;
162  	
163  	   while( list != NULL )
164  	   {
165  	      used += list->size;
166  	      list = list->next;
167  	   }
168  	   assert(used == memused);
169  	}
170  	#else
171  	#define checkMemlist() /**/
172  	#endif
173  	
174  	/** adds entry to list of allocated memory */
175  	static
176  	void addMemlistEntry(
177  	   const void*           ptr,                /**< pointer to allocated memory */
178  	   size_t                size,               /**< size of memory element */
179  	   const char*           filename,           /**< source file where the allocation was performed */
180  	   int                   line                /**< line number in source file where the allocation was performed */
181  	   )
182  	{
183  	   MEMLIST* list;
184  	
185  	   assert(ptr != NULL && size > 0);
186  	
187  	   list = (MEMLIST*)malloc(sizeof(MEMLIST));
188  	   assert(list != NULL);
189  	
190  	   list->ptr = ptr;
191  	   list->size = size;
192  	   list->filename = strdup(filename);
193  	   assert(list->filename != NULL);
194  	   list->line = line;
195  	   list->next = memlist;
196  	   memlist = list;
197  	   memused += size;
198  	   checkMemlist();
199  	}
200  	
201  	/** removes entry from the list of allocated memory */
202  	static
203  	void removeMemlistEntry(
204  	   const void*           ptr,                /**< pointer to allocated memory */
205  	   const char*           filename,           /**< source file where the deallocation was performed */
206  	   int                   line                /**< line number in source file where the deallocation was performed */
207  	   )
208  	{
209  	   MEMLIST* list;
210  	   MEMLIST** listptr;
211  	
212  	   assert(ptr != NULL);
213  	
214  	   list = memlist;
215  	   listptr = &memlist;
216  	   while( list != NULL && ptr != list->ptr )
217  	   {
218  	      listptr = &(list->next);
219  	      list = list->next;
220  	   }
221  	   if( list != NULL )
222  	   {
223  	      assert(ptr == list->ptr);
224  	
225  	      *listptr = list->next;
226  	      assert( list->size <= memused );
227  	      memused -= list->size;
228  	      free(list->filename);
229  	      free(list);
230  	   }
231  	   else
232  	   {
233  	      printErrorHeader(filename, line);
234  	      printError("Tried to free unknown pointer <%p>.\n", ptr);
235  	   }
236  	   checkMemlist();
237  	}
238  	
239  	/** returns the size of an allocated memory element */
240  	size_t BMSgetPointerSize_call(
241  	   const void*           ptr                 /**< pointer to allocated memory */
242  	   )
243  	{
244  	   MEMLIST* list;
245  	
246  	   list = memlist;
247  	   while( list != NULL && ptr != list->ptr )
248  	      list = list->next;
249  	   if( list != NULL )
250  	      return list->size;
251  	   else
252  	      return 0;
253  	}
254  	
255  	/** outputs information about currently allocated memory to the screen */
256  	void BMSdisplayMemory_call(
257  	   void
258  	   )
259  	{
260  	   MEMLIST* list;
261  	   size_t used = 0;
262  	
263  	   printInfo("Allocated memory:\n");
264  	   list = memlist;
265  	   while( list != NULL )
266  	   {
267  	      printInfo("%12p %8llu %s:%d\n", list->ptr, (unsigned long long) list->size, list->filename, list->line);
268  	      used += list->size;
269  	      list = list->next;
270  	   }
271  	   printInfo("Total:    %8llu\n", (unsigned long long) memused);
272  	   if( used != memused )
273  	   {
274  	      errorMessage("Used memory in list sums up to %llu instead of %llu\n", (unsigned long long)used, (unsigned long long)memused);
275  	   }
276  	   checkMemlist();
277  	}
278  	
279  	/** displays a warning message on the screen, if allocated memory exists */
280  	void BMScheckEmptyMemory_call(
281  	   void
282  	   )
283  	{
284  	   if( memlist != NULL || memused > 0 )
285  	   {
286  	      warningMessage("Memory list not empty.\n");
287  	      BMSdisplayMemory_call();
288  	   }
289  	}
290  	
291  	/** returns total number of allocated bytes */
292  	long long BMSgetMemoryUsed_call(
293  	   void
294  	   )
295  	{
296  	   return (long long) memused;
297  	}
298  	
299  	#else
300  	
301  	#define addMemlistEntry(ptr, size, filename, line) do { (void) (ptr); (void) (size); (void) (filename); (void) (line); } while(0)
302  	#define removeMemlistEntry(ptr, filename, line) do { (void) (ptr); (void) (filename); (void) (line); } while(0)
303  	
304  	/* these methods are implemented even in optimized mode, such that a program, that includes memory.h in debug mode
305  	 * but links the optimized version compiles
306  	 */
307  	
308  	/** returns the size of an allocated memory element */
309  	size_t BMSgetPointerSize_call(
310  	   const void*           ptr                 /**< pointer to allocated memory */
311  	   )
312  	{
313  	   (void) ptr;
314  	   return 0;
315  	}
316  	
317  	/** outputs information about currently allocated memory to the screen */
318  	void BMSdisplayMemory_call(
319  	   void
320  	   )
321  	{
322  	   printInfo("Optimized, threadsafe version of memory shell linked - no memory diagnostics available.\n");
323  	}
324  	
325  	/** displays a warning message on the screen, if allocated memory exists */
326  	void BMScheckEmptyMemory_call(
327  	   void
328  	   )
329  	{
330  	}
331  	
332  	/** returns total number of allocated bytes */
333  	long long BMSgetMemoryUsed_call(
334  	   void
335  	   )
336  	{
337  	   return 0;
338  	}
339  	
340  	#endif
341  	
342  	/** allocates array and initializes it with 0; returns NULL if memory allocation failed */
343  	void* BMSallocClearMemory_call(
344  	   size_t                num,                /**< number of memory element to allocate */
345  	   size_t                typesize,           /**< size of one memory element to allocate */
346  	   const char*           filename,           /**< source file where the allocation is performed */
347  	   int                   line                /**< line number in source file where the allocation is performed */
348  	   )
349  	{
350  	   void* ptr;
351  	
352  	   assert(typesize > 0);
353  	
354  	   debugMessage("calloc %llu elements of %llu bytes [%s:%d]\n", (unsigned long long)num, (unsigned long long)typesize,
355  	      filename, line);
356  	
357  	#ifndef NDEBUG
358  	   if ( num > (MAXMEMSIZE / typesize) )
359  	   {
360  	      printErrorHeader(filename, line);
361  	      printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
362  	      return NULL;
363  	   }
364  	#endif
365  	
366  	   num = MAX(num, 1);
367  	   typesize = MAX(typesize, 1);
368  	   ptr = calloc(num, typesize);
369  	
370  	   if( ptr == NULL )
371  	   {
372  	      printErrorHeader(filename, line);
373  	      printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)(num) * (typesize));
374  	   }
375  	   else
376  	      addMemlistEntry(ptr, num*typesize, filename, line);
377  	
378  	   return ptr;
379  	}
380  	
381  	/** allocates memory; returns NULL if memory allocation failed */
382  	void* BMSallocMemory_call(
383  	   size_t                size,               /**< size of memory element to allocate */
384  	   const char*           filename,           /**< source file where the allocation is performed */
385  	   int                   line                /**< line number in source file where the allocation is performed */
386  	   )
387  	{
388  	   void* ptr;
389  	
390  	   debugMessage("malloc %llu bytes [%s:%d]\n", (unsigned long long)size, filename, line);
391  	
392  	#ifndef NDEBUG
393  	   if ( size > MAXMEMSIZE )
394  	   {
395  	      printErrorHeader(filename, line);
396  	      printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
397  	      return NULL;
398  	   }
399  	#endif
400  	
401  	   size = MAX(size, 1);
402  	   ptr = malloc(size);
403  	
404  	   if( ptr == NULL )
405  	   {
406  	      printErrorHeader(filename, line);
407  	      printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)size);
408  	   }
409  	   else
410  	      addMemlistEntry(ptr, size, filename, line);
411  	
412  	   return ptr;
413  	}
414  	
415  	/** allocates array; returns NULL if memory allocation failed */
416  	void* BMSallocMemoryArray_call(
417  	   size_t                num,                /**< number of components of array to allocate */
418  	   size_t                typesize,           /**< size of each component */
419  	   const char*           filename,           /**< source file where the allocation is performed */
420  	   int                   line                /**< line number in source file where the allocation is performed */
421  	   )
422  	{
423  	   void* ptr;
424  	   size_t size;
425  	
426  	   debugMessage("malloc %llu elements of %llu bytes [%s:%d]\n",
427  	      (unsigned long long)num, (unsigned long long)typesize, filename, line);
428  	
429  	#ifndef NDEBUG
430  	   if ( num > (MAXMEMSIZE / typesize) )
431  	   {
432  	      printErrorHeader(filename, line);
433  	      printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
434  	      return NULL;
435  	   }
436  	#endif
437  	
438  	   size = num * typesize;
439  	   size = MAX(size, 1);
440  	   ptr = malloc(size);
441  	
442  	   if( ptr == NULL )
443  	   {
444  	      printErrorHeader(filename, line);
445  	      printError("Insufficient memory for allocation of %llu bytes.\n", (unsigned long long)size);
446  	   }
447  	   else
448  	      addMemlistEntry(ptr, size, filename, line);
449  	
450  	   return ptr;
451  	}
452  	
453  	/** allocates memory; returns NULL if memory allocation failed */
454  	void* BMSreallocMemory_call(
455  	   void*                 ptr,                /**< pointer to memory to reallocate */
456  	   size_t                size,               /**< new size of memory element */
457  	   const char*           filename,           /**< source file where the reallocation is performed */
458  	   int                   line                /**< line number in source file where the reallocation is performed */
459  	   )
460  	{
461  	   void* newptr;
462  	
463  	   if( ptr != NULL )
464  	      removeMemlistEntry(ptr, filename, line);
465  	
466  	#ifndef NDEBUG
467  	   if ( size > MAXMEMSIZE )
468  	   {
469  	      printErrorHeader(filename, line);
470  	      printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
471  	      return NULL;
472  	   }
473  	#endif
474  	
475  	   size = MAX(size, 1);
476  	   newptr = realloc(ptr, size);
477  	
478  	   if( newptr == NULL )
479  	   {
480  	      printErrorHeader(filename, line);
481  	      printError("Insufficient memory for reallocation of %llu bytes.\n", (unsigned long long)size);
482  	   }
483  	   else
484  	      addMemlistEntry(newptr, size, filename, line);
485  	
486  	   return newptr;
487  	}
488  	
489  	/** reallocates array; returns NULL if memory allocation failed */
490  	void* BMSreallocMemoryArray_call(
491  	   void*                 ptr,                /**< pointer to memory to reallocate */
492  	   size_t                num,                /**< number of components of array to allocate */
493  	   size_t                typesize,           /**< size of each component */
494  	   const char*           filename,           /**< source file where the reallocation is performed */
495  	   int                   line                /**< line number in source file where the reallocation is performed */
496  	   )
497  	{
498  	   void* newptr;
499  	   size_t size;
500  	
501  	   if( ptr != NULL )
502  	      removeMemlistEntry(ptr, filename, line);
503  	
504  	#ifndef NDEBUG
505  	   if ( num > (MAXMEMSIZE / typesize) )
506  	   {
507  	      printErrorHeader(filename, line);
508  	      printError("Tried to allocate standard memory of size exceeding %lu.\n", MAXMEMSIZE);
509  	      return NULL;
510  	   }
511  	#endif
512  	
513  	   size = num * typesize;
514  	   size = MAX(size, 1);
515  	   newptr = realloc(ptr, size);
516  	
517  	   if( newptr == NULL )
518  	   {
519  	      printErrorHeader(filename, line);
520  	      printError("Insufficient memory for reallocation of %llu bytes.\n", (unsigned long long)size);
521  	   }
522  	   else
523  	      addMemlistEntry(newptr, size, filename, line);
524  	
525  	   return newptr;
526  	}
527  	
528  	/** clears a memory element (i.e. fills it with zeros) */
529  	void BMSclearMemory_call(
530  	   void*                 ptr,                /**< pointer to memory element */
531  	   size_t                size                /**< size of memory element */
532  	   )
533  	{
534  	   if( size > 0 )
535  	   {
536  	      assert(ptr != NULL);
537  	      memset(ptr, 0, size);
538  	   }
539  	}
540  	
541  	/** copies the contents of one memory element into another memory element */
542  	void BMScopyMemory_call(
543  	   void*                 ptr,                /**< pointer to target memory element */
544  	   const void*           source,             /**< pointer to source memory element */
545  	   size_t                size                /**< size of memory element to copy */
546  	   )
547  	{
548  	   if( size > 0 )
549  	   {
550  	      assert(ptr != NULL);
551  	      assert(source != NULL);
552  	      memcpy(ptr, source, size);
553  	   }
554  	}
555  	
556  	/** moves the contents of one memory element into another memory element, should be used if both elements overlap,
557  	 *  otherwise BMScopyMemory is faster
558  	 */
559  	void BMSmoveMemory_call(
560  	   void*                 ptr,                /**< pointer to target memory element */
561  	   const void*           source,             /**< pointer to source memory element */
562  	   size_t                size                /**< size of memory element to copy */
563  	   )
564  	{
565  	   if( size > 0 )
566  	   {
567  	      assert(ptr != NULL);
568  	      assert(source != NULL);
569  	      memmove(ptr, source, size);
570  	   }
571  	}
572  	
573  	/** allocates memory and copies the contents of the given memory element into the new memory element */
574  	void* BMSduplicateMemory_call(
575  	   const void*           source,             /**< pointer to source memory element */
576  	   size_t                size,               /**< size of memory element to copy */
577  	   const char*           filename,           /**< source file where the duplication is performed */
578  	   int                   line                /**< line number in source file where the duplication is performed */
579  	   )
580  	{
581  	   void* ptr;
582  	
583  	   assert(source != NULL || size == 0);
584  	
585  	   ptr = BMSallocMemory_call(size, filename, line);
586  	   if( ptr != NULL )
587  	      BMScopyMemory_call(ptr, source, size);
588  	
589  	   return ptr;
590  	}
591  	
592  	/** allocates array and copies the contents of the given source array into the new array */
593  	void* BMSduplicateMemoryArray_call(
594  	   const void*           source,             /**< pointer to source memory element */
595  	   size_t                num,                /**< number of components of array to allocate */
596  	   size_t                typesize,           /**< size of each component */
597  	   const char*           filename,           /**< source file where the duplication is performed */
598  	   int                   line                /**< line number in source file where the duplication is performed */
599  	   )
600  	{
601  	   void* ptr;
602  	
603  	   assert(source != NULL || num == 0);
604  	
605  	   ptr = BMSallocMemoryArray_call(num, typesize, filename, line);
606  	   if( ptr != NULL )
607  	      BMScopyMemory_call(ptr, source, num * typesize);
608  	
609  	   return ptr;
610  	}
611  	
612  	/** frees an allocated memory element and sets pointer to NULL */
613  	void BMSfreeMemory_call(
614  	   void**                ptr,                /**< pointer to pointer to memory element */
615  	   const char*           filename,           /**< source file where the deallocation is performed */
616  	   int                   line                /**< line number in source file where the deallocation is performed */
617  	   )
618  	{
619  	   assert( ptr != NULL );
(1) Event cond_true: Condition "*ptr != NULL", taking true branch.
(1) Event cond_true: Condition "*ptr != NULL", taking true branch.
620  	   if( *ptr != NULL )
621  	   {
622  	      removeMemlistEntry(*ptr, filename, line);
623  	
(2) Event freed_arg: "free" frees parameter "*ptr".
(2) Event freed_arg: "free" frees parameter "*ptr".
624  	      free(*ptr);
625  	      *ptr = NULL;
626  	   }
627  	   else
628  	   {
629  	      printErrorHeader(filename, line);
630  	      printError("Tried to free null pointer.\n");
631  	   }
632  	}
633  	
634  	/** frees an allocated memory element if pointer is not NULL and sets pointer to NULL */
635  	void BMSfreeMemoryNull_call(
636  	   void**                ptr,                /**< pointer to pointer to memory element */
637  	   const char*           filename,           /**< source file where the deallocation is performed */
638  	   int                   line                /**< line number in source file where the deallocation is performed */
639  	   )
640  	{
641  	   assert( ptr != NULL );
642  	   if ( *ptr != NULL )
643  	   {
644  	      removeMemlistEntry(*ptr, filename, line);
645  	
646  	      free(*ptr);
647  	      *ptr = NULL;
648  	   }
649  	}
650  	
651  	
652  	/***********************************************************
653  	 * Block Memory Management (forward declaration)
654  	 *
655  	 * Efficient memory management for objects of varying sizes
656  	 ***********************************************************/
657  	
658  	#define CHKHASH_POWER              10                 /**< power for size of chunk block hash table */
659  	#define CHKHASH_SIZE               (1<<CHKHASH_POWER) /**< size of chunk block hash table is 2^CHKHASH_POWER */
660  	
661  	/** collection of chunk blocks */
662  	struct BMS_BlkMem
663  	{
664  	   BMS_CHKMEM*           chkmemhash[CHKHASH_SIZE]; /**< hash table with chunk blocks */
665  	   long long             memused;            /**< total number of used bytes in the memory header */
666  	   long long             memallocated;       /**< total number of allocated bytes in the memory header */
667  	   long long             maxmemused;         /**< maximal number of used bytes in the memory header */
668  	   long long             maxmemunused;       /**< maximal number of allocated but not used bytes in the memory header */
669  	   long long             maxmemallocated;    /**< maximal number of allocated bytes in the memory header */
670  	   int                   initchunksize;      /**< number of elements in the first chunk of each chunk block */
671  	   int                   garbagefactor;      /**< garbage collector is called, if at least garbagefactor * avg. chunksize
672  	                                              *   elements are free (-1: disable garbage collection) */
673  	};
674  	
675  	
676  	/********************************************************************
677  	 * Chunk Memory Management
678  	 *
679  	 * Efficient memory management for multiple objects of the same size
680  	 ********************************************************************/
681  	
682  	/* 
683  	 * block memory methods for faster memory access
684  	 */
685  	
686  	#define CHUNKLENGTH_MIN            1024 /**< minimal size of a chunk (in bytes) */
687  	#define CHUNKLENGTH_MAX         1048576 /**< maximal size of a chunk (in bytes) */
688  	#define STORESIZE_MAX              8192 /**< maximal number of elements in one chunk */
689  	#define GARBAGE_SIZE                256 /**< size of lazy free list to start garbage collection */
690  	#define ALIGNMENT    (sizeof(FREELIST)) /**< minimal alignment of chunks */
691  	
692  	typedef struct Freelist FREELIST;       /**< linked list of free memory elements */
693  	typedef struct Chunk CHUNK;             /**< chunk of memory elements */
694  	
695  	/** linked list of free memory elements */
696  	struct Freelist
697  	{
698  	   FREELIST*        next;               /**< pointer to the next free element */
699  	};
700  	
701  	/** chunk of memory elements */
702  	struct Chunk
703  	{
704  	   SCIP_RBTREE_HOOKS;                        /**< organize chunks in a red black tree */ /*lint !e768 */
705  	   void*                 store;              /**< data storage */
706  	   void*                 storeend;           /**< points to the first byte in memory not belonging to the chunk */
707  	   FREELIST*             eagerfree;          /**< eager free list */
708  	   CHUNK*                nexteager;          /**< next chunk, that has a non-empty eager free list */
709  	   CHUNK*                preveager;          /**< previous chunk, that has a non-empty eager free list */
710  	   BMS_CHKMEM*           chkmem;             /**< chunk memory collection, this chunk belongs to */
711  	   int                   elemsize;           /**< size of each element in the chunk */
712  	   int                   storesize;          /**< number of elements in this chunk */
713  	   int                   eagerfreesize;      /**< number of elements in the eager free list */
714  	}; /* the chunk data structure must be aligned, because the storage is allocated directly behind the chunk header! */
715  	
716  	/** collection of memory chunks of the same element size */
717  	struct BMS_ChkMem
718  	{
719  	   CHUNK*                rootchunk;          /**< array with the chunks of the chunk header */
720  	   FREELIST*             lazyfree;           /**< lazy free list of unused memory elements of all chunks of this chunk block */
721  	   CHUNK*                firsteager;         /**< first chunk with a non-empty eager free list */ 
722  	   BMS_CHKMEM*           nextchkmem;         /**< next chunk block in the block memory's hash list */
723  	   int                   elemsize;           /**< size of each memory element in the chunk memory */
724  	   int                   nchunks;            /**< number of chunks in this chunk block (used slots of the chunk array) */
725  	   int                   lastchunksize;      /**< number of elements in the last allocated chunk */
726  	   int                   storesize;          /**< total number of elements in this chunk block */
727  	   int                   lazyfreesize;       /**< number of elements in the lazy free list of the chunk block */
728  	   int                   eagerfreesize;      /**< total number of elements of all eager free lists of the block's chunks */
729  	   int                   initchunksize;      /**< number of elements in the first chunk */
730  	   int                   garbagefactor;      /**< garbage collector is called, if at least garbagefactor * avg. chunksize 
731  	                                              *   elements are free (-1: disable garbage collection) */
732  	#ifndef NDEBUG
733  	   char*                 filename;           /**< source file, where this chunk block was created */
734  	   int                   line;               /**< source line, where this chunk block was created */
735  	   int                   ngarbagecalls;      /**< number of times, the garbage collector was called */
736  	   int                   ngarbagefrees;      /**< number of chunks, the garbage collector freed */
737  	#endif
738  	};
739  	
740  	/* define a find function to find a chunk in a red black tree of chunks */
741  	#define CHUNK_LT(ptr,chunk)  ptr < chunk->store
742  	#define CHUNK_GT(ptr,chunk)  ptr >= chunk->storeend
743  	
744  	static
745  	SCIP_DEF_RBTREE_FIND(rbTreeFindChunk, const void*, CHUNK, CHUNK_LT, CHUNK_GT) /*lint !e123*/
746  	
747  	
748  	/** aligns the given byte size corresponding to the minimal alignment */
749  	static
750  	void alignSize(
751  	   size_t*               size                /**< pointer to the size to align */
752  	   )
753  	{
754  	   if( *size < ALIGNMENT )
755  	      *size = ALIGNMENT;
756  	   else
757  	      *size = ((*size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
758  	}
759  	
760  	/** aligns the given byte size corresponding to the minimal alignment for chunk and block memory  */
761  	void BMSalignMemsize(
762  	   size_t*               size                /**< pointer to the size to align */
763  	   )
764  	{
765  	   assert(ALIGNMENT == sizeof(void*)); /*lint !e506*/
766  	   alignSize(size);
767  	}
768  	
769  	/** checks whether the given size meets the alignment conditions for chunk and block memory */
770  	int BMSisAligned(
771  	   size_t                size                /**< size to check for alignment */
772  	   )
773  	{
774  	   assert(ALIGNMENT == sizeof(void*)); /*lint !e506*/
775  	   return( size >= ALIGNMENT && size % ALIGNMENT == 0 );
776  	}
777  	
778  	#ifndef NDEBUG
779  	/** checks, if the given pointer belongs to the given chunk */
780  	static
781  	int isPtrInChunk(
782  	   const CHUNK*          chunk,              /**< memory chunk */
783  	   const void*           ptr                 /**< pointer */
784  	   )
785  	{
786  	   assert(chunk != NULL);
787  	   assert(chunk->store <= chunk->storeend);
788  	
789  	   return (ptr >= (void*)(chunk->store) && ptr < (void*)(chunk->storeend));
790  	}
791  	#endif
792  	
793  	/** given a pointer, finds the chunk this pointer points to in the chunk array of the given chunk block;
794  	 *  binary search is used;
795  	 *  returns NULL if the pointer does not belong to the chunk block
796  	 */
797  	static
798  	CHUNK* findChunk(
799  	   const BMS_CHKMEM*     chkmem,             /**< chunk block */
800  	   const void*           ptr                 /**< pointer */
801  	   )
802  	{
803  	   CHUNK* chunk;
804  	
805  	   assert(chkmem != NULL);
806  	   assert(ptr != NULL);
807  	
808  	   if( rbTreeFindChunk(chkmem->rootchunk, ptr, &chunk) == 0 )
809  	      return chunk;
810  	
811  	   /* ptr was not found in chunk */
812  	   return NULL;
813  	}
814  	
815  	/** checks, if a pointer belongs to a chunk of the given chunk block */
816  	static
817  	int isPtrInChkmem(
818  	   const BMS_CHKMEM*     chkmem,             /**< chunk block */
819  	   const void*           ptr                 /**< pointer */
820  	   )
821  	{
822  	   assert(chkmem != NULL);
823  	
824  	   return (findChunk(chkmem, ptr) != NULL);
825  	}
826  	
827  	
828  	
829  	/*
830  	 * debugging methods
831  	 */
832  	
833  	#ifdef CHECKMEM
834  	/** sanity check for a memory chunk */
835  	static
836  	void checkChunk(
837  	   const CHUNK*       chunk               /**< memory chunk */
838  	   )
839  	{
840  	   FREELIST* eager;
841  	   int eagerfreesize;
842  	
843  	   assert(chunk != NULL);
844  	   assert(chunk->store != NULL);
845  	   assert(chunk->storeend == (void*)((char*)(chunk->store) + chunk->elemsize * chunk->storesize));
846  	   assert(chunk->chkmem != NULL);
847  	   assert(chunk->chkmem->elemsize == chunk->elemsize);
848  	
849  	   if( chunk->eagerfree == NULL )
850  	      assert(chunk->nexteager == NULL && chunk->preveager == NULL);
851  	   else if( chunk->preveager == NULL )
852  	      assert(chunk->chkmem->firsteager == chunk);
853  	
854  	   if( chunk->nexteager != NULL )
855  	      assert(chunk->nexteager->preveager == chunk);
856  	   if( chunk->preveager != NULL )
857  	      assert(chunk->preveager->nexteager == chunk);
858  	
859  	   eagerfreesize = 0;
860  	   eager = chunk->eagerfree;
861  	   while( eager != NULL )
862  	   {
863  	      assert(isPtrInChunk(chunk, eager));
864  	      eagerfreesize++;
865  	      eager = eager->next;
866  	   }
867  	   assert(chunk->eagerfreesize == eagerfreesize);
868  	}
869  	
870  	/** sanity check for a chunk block */
871  	static
872  	void checkChkmem(
873  	   const BMS_CHKMEM*     chkmem              /**< chunk block */
874  	   )
875  	{
876  	   FREELIST* lazy;
877  	   int nchunks;
878  	   int storesize;
879  	   int lazyfreesize;
880  	   int eagerfreesize;
881  	
882  	   assert(chkmem != NULL);
883  	
884  	   nchunks = 0;
885  	   storesize = 0;
886  	   lazyfreesize = 0;
887  	   eagerfreesize = 0;
888  	
889  	   FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
890  	   {
891  	      checkChunk(chunk);
892  	      nchunks++;
893  	      storesize += chunk->storesize;
894  	      eagerfreesize += chunk->eagerfreesize;
895  	   })
896  	
897  	   assert(chkmem->nchunks == nchunks);
898  	   assert(chkmem->storesize == storesize);
899  	   assert(chkmem->eagerfreesize == eagerfreesize);
900  	
901  	   assert(((unsigned int) (chkmem->eagerfreesize == 0)) ^ ( (unsigned int) (chkmem->firsteager != NULL)));
902  	
903  	   if( chkmem->firsteager != NULL )
904  	      assert(chkmem->firsteager->preveager == NULL);
905  	
906  	   lazy = chkmem->lazyfree;
907  	   while( lazy != NULL )
908  	   {
909  	      CHUNK* chunk = findChunk(chkmem, lazy);
910  	      assert(chunk != NULL);
911  	      assert(chunk->chkmem == chkmem);
912  	      lazyfreesize++;
913  	      lazy = lazy->next;
914  	   }
915  	   assert(chkmem->lazyfreesize == lazyfreesize);
916  	}
917  	#else
918  	#define checkChunk(chunk) /**/
919  	#define checkChkmem(chkmem) /**/
920  	#endif
921  	
922  	
923  	/** links chunk to the block's chunk array, sort it by store pointer;
924  	 *  returns TRUE if successful, FALSE otherwise
925  	 */
926  	static
927  	int linkChunk(
928  	   BMS_CHKMEM*           chkmem,             /**< chunk block */
929  	   CHUNK*                chunk               /**< memory chunk */
930  	   )
931  	{
932  	   CHUNK* parent;
933  	   int pos;
934  	
935  	   assert(chkmem != NULL);
936  	   assert(chunk != NULL);
937  	   assert(chunk->store != NULL);
938  	
939  	   debugMessage("linking chunk %p to chunk block %p [elemsize:%d, %d chunks]\n", 
940  	      (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
941  	
942  	   pos = rbTreeFindChunk(chkmem->rootchunk, chunk->store, &parent);
943  	   assert(pos != 0);
944  	
945  	   SCIPrbtreeInsert(&chkmem->rootchunk, parent, pos, chunk);
946  	
947  	   chkmem->nchunks++;
948  	   chkmem->storesize += chunk->storesize;
949  	
950  	   return TRUE;
951  	}
952  	
953  	/** unlinks chunk from the chunk block's chunk list */
954  	static
955  	void unlinkChunk(
956  	   CHUNK*                chunk               /**< memory chunk */
957  	   )
958  	{
959  	   BMS_CHKMEM* chkmem;
960  	
961  	   assert(chunk != NULL);
962  	   assert(chunk->eagerfree == NULL);
963  	   assert(chunk->nexteager == NULL);
964  	   assert(chunk->preveager == NULL);
965  	
966  	   chkmem = chunk->chkmem;
967  	   assert(chkmem != NULL);
968  	   assert(chkmem->elemsize == chunk->elemsize);
969  	
970  	   debugMessage("unlinking chunk %p from chunk block %p [elemsize:%d, %d chunks]\n", 
971  	      (void*)chunk, (void*)chkmem, chkmem->elemsize, chkmem->nchunks);
972  	
973  	   /* remove the chunk from the chunks of the chunk block */
974  	   SCIPrbtreeDelete(&chkmem->rootchunk, chunk);
975  	
976  	   chkmem->nchunks--;
977  	   chkmem->storesize -= chunk->storesize;
978  	}
979  	
980  	/** links chunk to the chunk block's eager chunk list */
981  	static
982  	void linkEagerChunk(
983  	   BMS_CHKMEM*           chkmem,             /**< chunk block */
984  	   CHUNK*                chunk               /**< memory chunk */
985  	   )
986  	{
987  	   assert(chunk->chkmem == chkmem);
988  	   assert(chunk->nexteager == NULL);
989  	   assert(chunk->preveager == NULL);
990  	
991  	   chunk->nexteager = chkmem->firsteager;
992  	   chunk->preveager = NULL;
993  	   if( chkmem->firsteager != NULL )
994  	   {
995  	      assert(chkmem->firsteager->preveager == NULL);
996  	      chkmem->firsteager->preveager = chunk;
997  	   }
998  	   chkmem->firsteager = chunk;
999  	}
1000 	
1001 	/** unlinks chunk from the chunk block's eager chunk list */
1002 	static
1003 	void unlinkEagerChunk(
1004 	   CHUNK*                chunk               /**< memory chunk */
1005 	   )
1006 	{
1007 	   assert(chunk != NULL);
1008 	   assert(chunk->eagerfreesize == 0 || chunk->eagerfreesize == chunk->storesize);
1009 	
1010 	   if( chunk->nexteager != NULL )
1011 	      chunk->nexteager->preveager = chunk->preveager;
1012 	   if( chunk->preveager != NULL )
1013 	      chunk->preveager->nexteager = chunk->nexteager;
1014 	   else
1015 	   {
1016 	      assert(chunk->chkmem->firsteager == chunk);
1017 	      chunk->chkmem->firsteager = chunk->nexteager;
1018 	   }
1019 	   chunk->nexteager = NULL;
1020 	   chunk->preveager = NULL;
1021 	   chunk->eagerfree = NULL;
1022 	}
1023 	
1024 	/** creates a new memory chunk in the given chunk block and adds memory elements to the lazy free list;
1025 	 *  returns TRUE if successful, FALSE otherwise
1026 	 */
1027 	static
1028 	int createChunk(
1029 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1030 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1031 	   )
1032 	{
1033 	   CHUNK *newchunk;
1034 	   FREELIST *freelist;
1035 	   int i;
1036 	   int storesize;
1037 	   int retval;
1038 	
1039 	   assert(chkmem != NULL);
1040 	
1041 	   debugMessage("creating new chunk in chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1042 	
1043 	   /* calculate store size */
1044 	   if( chkmem->nchunks == 0 )
1045 	      storesize = chkmem->initchunksize;
1046 	   else
1047 	      storesize = 2 * chkmem->lastchunksize;
1048 	   assert(storesize > 0);
1049 	   storesize = MAX(storesize, CHUNKLENGTH_MIN / chkmem->elemsize);
1050 	   storesize = MIN(storesize, CHUNKLENGTH_MAX / chkmem->elemsize);
1051 	   storesize = MIN(storesize, STORESIZE_MAX);
1052 	   storesize = MAX(storesize, 1);
1053 	   chkmem->lastchunksize = storesize;
1054 	
1055 	   /* create new chunk */
1056 	   assert(BMSisAligned(sizeof(CHUNK)));
1057 	   assert( chkmem->elemsize < INT_MAX / storesize );
1058 	   assert( sizeof(CHUNK) < MAXMEMSIZE - (size_t)(storesize * chkmem->elemsize) ); /*lint !e571 !e647*/
1059 	   BMSallocMemorySize(&newchunk, sizeof(CHUNK) + storesize * chkmem->elemsize);
1060 	   if( newchunk == NULL )
1061 	      return FALSE;
1062 	
1063 	   /* the store is allocated directly behind the chunk header */
1064 	   newchunk->store = (void*) ((char*) newchunk + sizeof(CHUNK));
1065 	   newchunk->storeend = (void*) ((char*) newchunk->store + (ptrdiff_t)storesize * chkmem->elemsize);
1066 	   newchunk->eagerfree = NULL;
1067 	   newchunk->nexteager = NULL;
1068 	   newchunk->preveager = NULL;
1069 	   newchunk->chkmem = chkmem;
1070 	   newchunk->elemsize = chkmem->elemsize;
1071 	   newchunk->storesize = storesize;
1072 	   newchunk->eagerfreesize = 0;
1073 	
1074 	   if( memsize != NULL )
1075 	      (*memsize) += ((long long)((long long)sizeof(CHUNK) + (long long)storesize * chkmem->elemsize));
1076 	
1077 	   debugMessage("allocated new chunk %p: %d elements with size %d\n", (void*)newchunk, newchunk->storesize, newchunk->elemsize);
1078 	
1079 	   /* add new memory to the lazy free list
1080 	    * (due to the BMSisAligned assert above, we know that elemsize is divisible by the size of pointers)
1081 	    */
1082 	   for( i = 0; i < newchunk->storesize - 1; ++i )
1083 	   {
1084 	      freelist = (FREELIST*) newchunk->store + (ptrdiff_t)i * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1085 	      freelist->next = (FREELIST*) newchunk->store + ((ptrdiff_t)i + 1) * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1086 	   }
1087 	
1088 	   freelist = (FREELIST*) newchunk->store + ((ptrdiff_t) newchunk->storesize - 1) * chkmem->elemsize / (ptrdiff_t)sizeof(FREELIST*); /*lint !e573 !e647*/
1089 	   freelist->next = chkmem->lazyfree;
1090 	   chkmem->lazyfree = (FREELIST*) (newchunk->store);
1091 	   chkmem->lazyfreesize += newchunk->storesize;
1092 	
1093 	   /* link chunk into chunk block */
1094 	   retval = linkChunk(chkmem, newchunk);
1095 	
1096 	   checkChkmem(chkmem);
1097 	
1098 	   return retval;
1099 	}
1100 	
1101 	/** destroys a chunk without updating the chunk lists */
1102 	static
1103 	void destroyChunk(
1104 	   CHUNK**               chunk,              /**< memory chunk */
1105 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1106 	   )
1107 	{
1108 	   assert(chunk != NULL);
1109 	   assert(*chunk != NULL);
1110 	
1111 	   debugMessage("destroying chunk %p\n", (void*)*chunk);
1112 	
1113 	   if( memsize != NULL )
1114 	      (*memsize) -= ((long long)sizeof(CHUNK) + (long long)(*chunk)->storesize * (*chunk)->elemsize);
1115 	
1116 	   /* free chunk header and store (allocated in one call) */
1117 	   BMSfreeMemory(chunk);
1118 	}
1119 	
1120 	/** removes a completely unused chunk, i.e. a chunk with all elements in the eager free list */
1121 	static
1122 	void freeChunk(
1123 	   CHUNK**               chunk,              /**< memory chunk */
1124 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1125 	   )
1126 	{
1127 	   assert(chunk != NULL);
1128 	   assert(*chunk != NULL);
1129 	   assert((*chunk)->store != NULL);
1130 	   assert((*chunk)->eagerfree != NULL);
1131 	   assert((*chunk)->chkmem != NULL);
1132 	   assert((*chunk)->chkmem->rootchunk != NULL);
1133 	   assert((*chunk)->chkmem->firsteager != NULL);
1134 	   assert((*chunk)->eagerfreesize == (*chunk)->storesize);
1135 	
1136 	   debugMessage("freeing chunk %p of chunk block %p [elemsize: %d]\n", (void*)*chunk, (void*)(*chunk)->chkmem, (*chunk)->chkmem->elemsize);
1137 	
1138 	   /* count the deleted eager free slots */
1139 	   (*chunk)->chkmem->eagerfreesize -= (*chunk)->eagerfreesize;
1140 	   assert((*chunk)->chkmem->eagerfreesize >= 0);
1141 	
1142 	   /* remove chunk from eager chunk list */
1143 	   unlinkEagerChunk(*chunk);
1144 	
1145 	   /* remove chunk from chunk list */
1146 	   unlinkChunk(*chunk);
1147 	
1148 	   /* destroy the chunk */
1149 	   destroyChunk(chunk, memsize);
1150 	}
1151 	
1152 	/** returns an element of the eager free list and removes it from the list */
1153 	static
1154 	void* allocChunkElement(
1155 	   CHUNK*                chunk               /**< memory chunk */
1156 	   )
1157 	{
1158 	   FREELIST* ptr;
1159 	
1160 	   assert(chunk != NULL);
1161 	   assert(chunk->eagerfree != NULL);
1162 	   assert(chunk->eagerfreesize > 0);
1163 	   assert(chunk->chkmem != NULL);
1164 	
1165 	   debugMessage("allocating chunk element in chunk %p [elemsize: %d]\n", (void*)chunk, chunk->chkmem->elemsize);
1166 	
1167 	   /* unlink first element in the eager free list */
1168 	   ptr = chunk->eagerfree;
1169 	   chunk->eagerfree = ptr->next;
1170 	   chunk->eagerfreesize--;
1171 	   chunk->chkmem->eagerfreesize--;
1172 	
1173 	   assert((chunk->eagerfreesize == 0 && chunk->eagerfree == NULL)
1174 	      ||  (chunk->eagerfreesize != 0 && chunk->eagerfree != NULL));
1175 	   assert(chunk->chkmem->eagerfreesize >= 0);
1176 	
1177 	   /* unlink chunk from eager chunk list if necessary */
1178 	   if( chunk->eagerfree == NULL )
1179 	   {
1180 	      assert(chunk->eagerfreesize == 0);
1181 	      unlinkEagerChunk(chunk);
1182 	   }
1183 	
1184 	   checkChunk(chunk);
1185 	
1186 	   return (void*) ptr;
1187 	}
1188 	
1189 	/** puts given pointer into the eager free list and adds the chunk to the eager list of its chunk block, if necessary */
1190 	static
1191 	void freeChunkElement(
1192 	   CHUNK*                chunk,              /**< memory chunk */
1193 	   void*                 ptr                 /**< pointer */
1194 	   )
1195 	{
1196 	   assert(chunk != NULL);
1197 	   assert(chunk->chkmem != NULL);
1198 	   assert(isPtrInChunk(chunk, ptr));
1199 	
1200 	   debugMessage("freeing chunk element %p of chunk %p [elemsize: %d]\n", (void*)ptr, (void*)chunk, chunk->chkmem->elemsize);
1201 	
1202 	   /* link chunk to the eager chunk list if necessary */
1203 	   if( chunk->eagerfree == NULL )
1204 	   {
1205 	      assert(chunk->eagerfreesize == 0);
1206 	      linkEagerChunk(chunk->chkmem, chunk);
1207 	   }
1208 	
1209 	   /* add ptr to the chunks eager free list */
1210 	   ((FREELIST*)ptr)->next = chunk->eagerfree;
1211 	   chunk->eagerfree = (FREELIST*)ptr;
1212 	   chunk->eagerfreesize++;
1213 	   chunk->chkmem->eagerfreesize++;
1214 	
1215 	   checkChunk(chunk);
1216 	}
1217 	
1218 	/** creates a new chunk block data structure */
1219 	static
1220 	BMS_CHKMEM* createChkmem(
1221 	   int                   size,               /**< element size of the chunk block */
1222 	   int                   initchunksize,      /**< number of elements in the first chunk of the chunk block */
1223 	   int                   garbagefactor,      /**< garbage collector is called, if at least garbagefactor * avg. chunksize
1224 	                                              *   elements are free (-1: disable garbage collection) */
1225 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1226 	   )
1227 	{
1228 	   BMS_CHKMEM* chkmem;
1229 	
1230 	   assert(size >= 0);
1231 	   assert(BMSisAligned((size_t)size)); /*lint !e571*/
1232 	
1233 	   BMSallocMemory(&chkmem);
1234 	   if( chkmem == NULL )
1235 	      return NULL;
1236 	
1237 	   chkmem->lazyfree = NULL;
1238 	   chkmem->rootchunk = NULL;
1239 	   chkmem->firsteager = NULL;
1240 	   chkmem->nextchkmem = NULL;
1241 	   chkmem->elemsize = size;
1242 	   chkmem->nchunks = 0;
1243 	   chkmem->lastchunksize = 0;
1244 	   chkmem->storesize = 0;
1245 	   chkmem->lazyfreesize = 0;
1246 	   chkmem->eagerfreesize = 0;
1247 	   chkmem->initchunksize = initchunksize;
1248 	   chkmem->garbagefactor = garbagefactor;
1249 	#ifndef NDEBUG
1250 	   chkmem->filename = NULL;
1251 	   chkmem->line = 0;
1252 	   chkmem->ngarbagecalls = 0;
1253 	   chkmem->ngarbagefrees = 0;
1254 	#endif
1255 	
1256 	   if( memsize != NULL )
1257 	      (*memsize) += (long long)sizeof(BMS_CHKMEM);
1258 	
1259 	   return chkmem;
1260 	}
1261 	
1262 	/** destroys all chunks of the chunk block, but keeps the chunk block header structure */
1263 	static
1264 	void clearChkmem(
1265 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1266 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1267 	   )
1268 	{
1269 	   assert(chkmem != NULL);
1270 	
1271 	   /* destroy all chunks of the chunk block */
1272 	   FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
1273 	   {
1274 	      SCIPrbtreeDelete(&chkmem->rootchunk, chunk);
1275 	      destroyChunk(&chunk, memsize);
1276 	   })
1277 	
1278 	   chkmem->lazyfree = NULL;
1279 	   chkmem->firsteager = NULL;
1280 	   chkmem->nchunks = 0;
1281 	   chkmem->lastchunksize = 0;
1282 	   chkmem->storesize = 0;
1283 	   chkmem->lazyfreesize = 0;
1284 	   chkmem->eagerfreesize = 0;
1285 	}
1286 	
1287 	/** deletes chunk block and frees all associated memory chunks */
1288 	static
1289 	void destroyChkmem(
1290 	   BMS_CHKMEM**          chkmem,             /**< pointer to chunk block */
1291 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1292 	   )
1293 	{
1294 	   assert(chkmem != NULL);
1295 	   assert(*chkmem != NULL);
1296 	
1297 	   clearChkmem(*chkmem, memsize);
1298 	
1299 	#ifndef NDEBUG
1300 	   BMSfreeMemoryArrayNull(&(*chkmem)->filename);
1301 	#endif
1302 	
1303 	   if( memsize != NULL )
1304 	      (*memsize) -= (long long)(sizeof(BMS_CHKMEM));
1305 	
1306 	   BMSfreeMemory(chkmem);
1307 	}
1308 	
1309 	/** allocates a new memory element from the chunk block */
1310 	static
1311 	void* allocChkmemElement(
1312 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1313 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1314 	   )
1315 	{
1316 	   FREELIST* ptr;
1317 	
1318 	   assert(chkmem != NULL);
1319 	
1320 	   /* if the lazy freelist is empty, we have to find the memory element somewhere else */
1321 	   if( chkmem->lazyfree == NULL )
1322 	   {
1323 	      assert(chkmem->lazyfreesize == 0);
1324 	
1325 	      /* check for a free element in the eager freelists */
1326 	      if( chkmem->firsteager != NULL )
1327 	         return allocChunkElement(chkmem->firsteager);
1328 	
1329 	      /* allocate a new chunk */
1330 	      if( !createChunk(chkmem, memsize) )
1331 	         return NULL;
1332 	   }
1333 	
1334 	   /* now the lazy freelist should contain an element */
1335 	   assert(chkmem->lazyfree != NULL);
1336 	   assert(chkmem->lazyfreesize > 0);
1337 	
1338 	   ptr = chkmem->lazyfree;
1339 	   chkmem->lazyfree = ptr->next;
1340 	   chkmem->lazyfreesize--;
1341 	
1342 	   checkChkmem(chkmem);
1343 	
1344 	   return (void*) ptr;
1345 	}
1346 	
1347 	/** sorts the lazy free list of the chunk block into the eager free lists of the chunks, and removes completely
1348 	 *  unused chunks
1349 	 */
1350 	static
1351 	void garbagecollectChkmem(
1352 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1353 	   long long*            memsize             /**< pointer to total size of allocated memory (or NULL) */
1354 	   )
1355 	{
1356 	   CHUNK* chunk;
1357 	   CHUNK* nexteager;
1358 	   FREELIST* lazyfree;
1359 	
1360 	   assert(chkmem != NULL);
1361 	
1362 	   debugMessage("garbage collection for chunk block %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1363 	
1364 	   /* check, if the chunk block is completely unused */
1365 	   if( chkmem->lazyfreesize + chkmem->eagerfreesize == chkmem->storesize )
1366 	   {
1367 	      clearChkmem(chkmem, memsize);
1368 	      return;
1369 	   }
1370 	
1371 	#ifndef NDEBUG
1372 	   chkmem->ngarbagecalls++;
1373 	#endif
1374 	
1375 	   /* put the lazy free elements into the eager free lists */
1376 	   while( chkmem->lazyfree != NULL )
1377 	   {
1378 	      /* unlink first element from the lazy free list */
1379 	      lazyfree = chkmem->lazyfree;
1380 	      chkmem->lazyfree = chkmem->lazyfree->next;
1381 	      chkmem->lazyfreesize--;
1382 	
1383 	      /* identify the chunk of the element */
1384 	      chunk = findChunk(chkmem, (void*)lazyfree);
1385 	#ifndef NDEBUG
1386 	      if( chunk == NULL )
1387 	      {
1388 	         errorMessage("chunk for lazy free chunk %p not found in chunk block %p\n", (void*)lazyfree, (void*)chkmem);
1389 	      }
1390 	#endif
1391 	      assert(chunk != NULL);
1392 	
1393 	      /* add the element to the chunk's eager free list */
1394 	      freeChunkElement(chunk, (void*)lazyfree);
1395 	      assert(chunk->eagerfreesize > 0);
1396 	   }
1397 	   assert(chkmem->lazyfreesize == 0);
1398 	
1399 	   /* delete completely unused chunks, but keep at least one */
1400 	   chunk = chkmem->firsteager;
1401 	   while( chunk != NULL && chkmem->nchunks > 1 )
1402 	   {
1403 	      nexteager = chunk->nexteager;
1404 	      if( chunk->eagerfreesize == chunk->storesize )
1405 	      {
1406 	#ifndef NDEBUG
1407 		 chkmem->ngarbagefrees++;
1408 	#endif
1409 		 freeChunk(&chunk, memsize);
1410 	      }
1411 	      chunk = nexteager;
1412 	   }
1413 	
1414 	   checkChkmem(chkmem);
1415 	}
1416 	
1417 	/** frees a memory element and returns it to the lazy freelist of the chunk block */ /*lint -e715*/
1418 	static
1419 	void freeChkmemElement(
1420 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1421 	   void*                 ptr,                /**< memory element */
1422 	   long long*            memsize,            /**< pointer to total size of allocated memory (or NULL) */
1423 	   const char*           filename,           /**< source file of the function call */
1424 	   int                   line                /**< line number in source file of the function call */
1425 	   )
1426 	{  /*lint --e{715}*/
1427 	   assert(chkmem != NULL);
1428 	   assert(ptr != NULL);
1429 	
1430 	#if ( defined(CHECKMEM) || defined(CHECKCHKFREE) )
1431 	   /* check, if ptr belongs to the chunk block */
1432 	   if( !isPtrInChkmem(chkmem, ptr) )
1433 	   {
1434 	      printErrorHeader(filename, line);
1435 	      printError("Pointer %p does not belong to chunk block %p (size: %d).\n", ptr, chkmem, chkmem->elemsize);
1436 	   }
1437 	#endif
1438 	
1439 	   /* put ptr in lazy free list */
1440 	   ((FREELIST*)ptr)->next = chkmem->lazyfree;
1441 	   chkmem->lazyfree = (FREELIST*)ptr;
1442 	   chkmem->lazyfreesize++;
1443 	
1444 	   /* check if we want to apply garbage collection */
1445 	   if( chkmem->garbagefactor >= 0 && chkmem->nchunks > 0 && chkmem->lazyfreesize >= GARBAGE_SIZE
1446 	      && chkmem->lazyfreesize + chkmem->eagerfreesize
1447 	      > chkmem->garbagefactor * (double)(chkmem->storesize) / (double)(chkmem->nchunks) )
1448 	   {
1449 	      garbagecollectChkmem(chkmem, memsize);
1450 	   }
1451 	
1452 	   checkChkmem(chkmem);
1453 	}
1454 	
1455 	/** creates a new chunk block data structure */
1456 	BMS_CHKMEM* BMScreateChunkMemory_call(
1457 	   size_t                size,               /**< element size of the chunk block */
1458 	   int                   initchunksize,      /**< number of elements in the first chunk of the chunk block */
1459 	   int                   garbagefactor,      /**< garbage collector is called, if at least garbagefactor * avg. chunksize 
1460 	                                              *   elements are free (-1: disable garbage collection) */
1461 	   const char*           filename,           /**< source file of the function call */
1462 	   int                   line                /**< line number in source file of the function call */
1463 	   )
1464 	{
1465 	   BMS_CHKMEM* chkmem;
1466 	
1467 	   alignSize(&size);
1468 	   chkmem = createChkmem((int) size, initchunksize, garbagefactor, NULL);
1469 	   if( chkmem == NULL )
1470 	   {
1471 	      printErrorHeader(filename, line);
1472 	      printError("Insufficient memory for chunk block.\n");
1473 	   }
1474 	   debugMessage("created chunk memory %p [elemsize: %d]\n", (void*)chkmem, (int)size);
1475 	
1476 	   return chkmem;
1477 	}
1478 	
1479 	/** clears a chunk block data structure */
1480 	void BMSclearChunkMemory_call(
1481 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1482 	   const char*           filename,           /**< source file of the function call */
1483 	   int                   line                /**< line number in source file of the function call */
1484 	   )
1485 	{
1486 	   debugMessage("clearing chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1487 	
1488 	   if( chkmem != NULL )
1489 	      clearChkmem(chkmem, NULL);
1490 	   else
1491 	   {
1492 	      printErrorHeader(filename, line);
1493 	      printError("Tried to clear null chunk block.\n");
1494 	   }
1495 	}
1496 	
1497 	/** destroys and frees a chunk block data structure */
1498 	void BMSdestroyChunkMemory_call(
1499 	   BMS_CHKMEM**          chkmem,             /**< pointer to chunk block */
1500 	   const char*           filename,           /**< source file of the function call */
1501 	   int                   line                /**< line number in source file of the function call */
1502 	   )
1503 	{
1504 	   assert(chkmem != NULL);
1505 	
1506 	   debugMessage("destroying chunk memory %p [elemsize: %d]\n", (void*)*chkmem, (*chkmem)->elemsize);
1507 	
1508 	   if( *chkmem != NULL )
1509 	      destroyChkmem(chkmem, NULL);
1510 	   else
1511 	   {
1512 	      printErrorHeader(filename, line);
1513 	      printError("Tried to destroy null chunk block.\n");
1514 	   }
1515 	}
1516 	
1517 	/** allocates a memory element of the given chunk block */
1518 	void* BMSallocChunkMemory_call(
1519 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1520 	   size_t                size,               /**< size of memory element to allocate (only needed for sanity check) */
1521 	   const char*           filename,           /**< source file of the function call */
1522 	   int                   line                /**< line number in source file of the function call */
1523 	   )
1524 	{
1525 	   void* ptr;
1526 	
1527 	   assert(chkmem != NULL);
1528 	   assert((int)size == chkmem->elemsize);
1529 	
1530 	   /* get memory inside the chunk block */
1531 	   ptr = allocChkmemElement(chkmem, NULL);
1532 	   if( ptr == NULL )
1533 	   {
1534 	      printErrorHeader(filename, line);
1535 	      printError("Insufficient memory for new chunk.\n");
1536 	   }
1537 	   debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, (void*)ptr, filename, line);
1538 	
1539 	   checkChkmem(chkmem);
1540 	
1541 	   return ptr;
1542 	}
1543 	
1544 	/** duplicates a given memory element by allocating a new element of the same chunk block and copying the data */
1545 	void* BMSduplicateChunkMemory_call(
1546 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1547 	   const void*           source,             /**< source memory element */
1548 	   size_t                size,               /**< size of memory element to allocate (only needed for sanity check) */
1549 	   const char*           filename,           /**< source file of the function call */
1550 	   int                   line                /**< line number in source file of the function call */
1551 	   )
1552 	{
1553 	   void* ptr;
1554 	
1555 	   assert(chkmem != NULL);
1556 	   assert(source != NULL);
1557 	   assert((int)size == chkmem->elemsize);
1558 	
1559 	   ptr = BMSallocChunkMemory_call(chkmem, size, filename, line);
1560 	   if( ptr != NULL )
1561 	      BMScopyMemorySize(ptr, source, chkmem->elemsize);
1562 	
1563 	   return ptr;
1564 	}
1565 	
1566 	/** frees a memory element of the given chunk block and sets pointer to NULL */
1567 	void BMSfreeChunkMemory_call(
1568 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1569 	   void**                ptr,                /**< pointer to pointer to memory element to free */
1570 	   size_t                size,               /**< size of memory element to allocate (only needed for sanity check) */
1571 	   const char*           filename,           /**< source file of the function call */
1572 	   int                   line                /**< line number in source file of the function call */
1573 	   )
1574 	{
1575 	   assert(chkmem != NULL);
1576 	   assert((int)size == chkmem->elemsize);
1577 	   assert( ptr != NULL );
1578 	
1579 	   if ( *ptr != NULL )
1580 	   {
1581 	      debugMessage("free    %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1582 	
1583 	      /* free memory in chunk block */
1584 	      freeChkmemElement(chkmem, *ptr, NULL, filename, line);
1585 	      checkChkmem(chkmem);
1586 	      *ptr = NULL;
1587 	   }
1588 	   else
1589 	   {
1590 	      printErrorHeader(filename, line);
1591 	      printError("Tried to free null chunk pointer.\n");
1592 	   }
1593 	}
1594 	
1595 	/** frees a memory element of the given chunk block if pointer is not NULL and sets pointer to NULL */
1596 	void BMSfreeChunkMemoryNull_call(
1597 	   BMS_CHKMEM*           chkmem,             /**< chunk block */
1598 	   void**                ptr,                /**< pointer to pointer to memory element to free */
1599 	   size_t                size,               /**< size of memory element to allocate (only needed for sanity check) */
1600 	   const char*           filename,           /**< source file of the function call */
1601 	   int                   line                /**< line number in source file of the function call */
1602 	   )
1603 	{
1604 	   assert(chkmem != NULL);
1605 	   assert((int)size == chkmem->elemsize);
1606 	   assert( ptr != NULL );
1607 	
1608 	   if ( *ptr != NULL )
1609 	   {
1610 	      debugMessage("free    %8d bytes in %p [%s:%d]\n", chkmem->elemsize, *ptr, filename, line);
1611 	
1612 	      /* free memory in chunk block */
1613 	      freeChkmemElement(chkmem, *ptr, NULL, filename, line);
1614 	      checkChkmem(chkmem);
1615 	      *ptr = NULL;
1616 	   }
1617 	}
1618 	
1619 	/** calls garbage collection of chunk block and frees chunks without allocated memory elements */
1620 	void BMSgarbagecollectChunkMemory_call(
1621 	   BMS_CHKMEM*           chkmem              /**< chunk block */
1622 	   )
1623 	{
1624 	   debugMessage("garbage collection on chunk memory %p [elemsize: %d]\n", (void*)chkmem, chkmem->elemsize);
1625 	
1626 	   garbagecollectChkmem(chkmem, NULL);
1627 	}
1628 	
1629 	/** returns the number of allocated bytes in the chunk block */
1630 	long long BMSgetChunkMemoryUsed_call(
1631 	   const BMS_CHKMEM*     chkmem              /**< chunk block */
1632 	   )
1633 	{
1634 	   assert(chkmem != NULL);
1635 	
1636 	   return ((long long)(chkmem->elemsize) * (long long)(chkmem->storesize));
1637 	}
1638 	
1639 	
1640 	
1641 	
1642 	/***********************************************************
1643 	 * Block Memory Management
1644 	 *
1645 	 * Efficient memory management for objects of varying sizes
1646 	 ***********************************************************/
1647 	
1648 	/* for a definition of the struct, see above */
1649 	
1650 	
1651 	/*
1652 	 * debugging methods
1653 	 */
1654 	
1655 	#ifdef CHECKMEM
1656 	static
1657 	void checkBlkmem(
1658 	   const BMS_BLKMEM*     blkmem              /**< block memory */
1659 	   )
1660 	{
1661 	   const BMS_CHKMEM* chkmem;
1662 	   long long tmpmemalloc = 0LL;
1663 	   long long tmpmemused = 0LL;
1664 	   int i;
1665 	
1666 	   assert(blkmem != NULL);
1667 	   assert(blkmem->chkmemhash != NULL);
1668 	
1669 	   for( i = 0; i < CHKHASH_SIZE; ++i )
1670 	   {
1671 	      chkmem = blkmem->chkmemhash[i];
1672 	      while( chkmem != NULL )
1673 	      {
1674 	         checkChkmem(chkmem);
1675 	         tmpmemalloc += ((chkmem->elemsize * chkmem->storesize) + chkmem->nchunks * sizeof(CHUNK) + sizeof(BMS_CHKMEM));
1676 	         tmpmemused += (chkmem->elemsize * (chkmem->storesize - chkmem->eagerfreesize - chkmem->lazyfreesize));
1677 	         chkmem = chkmem->nextchkmem;
1678 	      }
1679 	   }
1680 	   assert(tmpmemalloc == blkmem->memallocated);
1681 	   assert(tmpmemused == blkmem->memused);
1682 	}
1683 	#else
1684 	#define checkBlkmem(blkmem) /**/
1685 	#endif
1686 	
1687 	
1688 	/** finds the chunk block, to whick the given pointer belongs to
1689 	 *
1690 	 *  This could be done by selecting the chunk block of the corresponding element size, but in a case of an
1691 	 *  error (free gives an incorrect element size), we want to identify and output the correct element size.
1692 	 */
1693 	static
1694 	BMS_CHKMEM* findChkmem(
1695 	   const BMS_BLKMEM*     blkmem,             /**< block memory */
1696 	   const void*           ptr                 /**< memory element to search */
1697 	   )
1698 	{
1699 	   BMS_CHKMEM* chkmem;
1700 	   int i;
1701 	
1702 	   assert(blkmem != NULL);
1703 	
1704 	   chkmem = NULL;
1705 	   for( i = 0; chkmem == NULL && i < CHKHASH_SIZE; ++i )
1706 	   {
1707 	      chkmem = blkmem->chkmemhash[i];
1708 	      while( chkmem != NULL && !isPtrInChkmem(chkmem, ptr) )
1709 	         chkmem = chkmem->nextchkmem;
1710 	   }
1711 	
1712 	   return chkmem;
1713 	}
1714 	
1715 	/** calculates hash number of memory size */
1716 	static
1717 	int getHashNumber(
1718 	   int                   size                /**< element size */
1719 	   )
1720 	{
1721 	   assert(size >= 0);
1722 	   assert(BMSisAligned((size_t)size)); /*lint !e571*/
1723 	
1724 	   return (int) (((uint32_t)size * UINT32_C(0x9e3779b9))>>(32-CHKHASH_POWER));
1725 	}
1726 	
1727 	/** creates a block memory allocation data structure */
1728 	BMS_BLKMEM* BMScreateBlockMemory_call(
1729 	   int                   initchunksize,      /**< number of elements in the first chunk of each chunk block */
1730 	   int                   garbagefactor,      /**< garbage collector is called, if at least garbagefactor * avg. chunksize 
1731 	                                              *   elements are free (-1: disable garbage collection) */
1732 	   const char*           filename,           /**< source file of the function call */
1733 	   int                   line                /**< line number in source file of the function call */
1734 	   )
1735 	{
1736 	   BMS_BLKMEM* blkmem;
1737 	   int i;
1738 	
1739 	   BMSallocMemory(&blkmem);
1740 	   if( blkmem != NULL )
1741 	   {
1742 	      for( i = 0; i < CHKHASH_SIZE; ++i )
1743 	         blkmem->chkmemhash[i] = NULL;
1744 	      blkmem->initchunksize = initchunksize;
1745 	      blkmem->garbagefactor = garbagefactor;
1746 	      blkmem->memused = 0;
1747 	      blkmem->memallocated = 0;
1748 	      blkmem->maxmemused = 0;
1749 	      blkmem->maxmemunused = 0;
1750 	      blkmem->maxmemallocated = 0;
1751 	   }
1752 	   else
1753 	   {
1754 	      printErrorHeader(filename, line);
1755 	      printError("Insufficient memory for block memory header.\n");
1756 	   }
1757 	
1758 	   return blkmem;
1759 	}
1760 	
1761 	/** frees all chunk blocks in the block memory */
1762 	void BMSclearBlockMemory_call(
1763 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1764 	   const char*           filename,           /**< source file of the function call */
1765 	   int                   line                /**< line number in source file of the function call */
1766 	   )
1767 	{
1768 	   BMS_CHKMEM* chkmem;
1769 	   BMS_CHKMEM* nextchkmem;
1770 	   int i;
1771 	
1772 	   if( blkmem != NULL )
1773 	   {
1774 	      for( i = 0; i < CHKHASH_SIZE; ++i )
1775 	      {
1776 	         chkmem = blkmem->chkmemhash[i];
1777 	         while( chkmem != NULL )
1778 	         {
1779 	            nextchkmem = chkmem->nextchkmem;
1780 	            destroyChkmem(&chkmem, &blkmem->memallocated);
1781 	            chkmem = nextchkmem;
1782 	         }
1783 	         blkmem->chkmemhash[i] = NULL;
1784 	      }
1785 	      blkmem->memused = 0;
1786 	      assert(blkmem->memallocated == 0);
1787 	   }
1788 	   else
1789 	   {
1790 	      printErrorHeader(filename, line);
1791 	      printError("Tried to clear null block memory.\n");
1792 	   }
1793 	}
1794 	
1795 	/** clears and deletes block memory */
1796 	void BMSdestroyBlockMemory_call(
1797 	   BMS_BLKMEM**          blkmem,             /**< pointer to block memory */
1798 	   const char*           filename,           /**< source file of the function call */
1799 	   int                   line                /**< line number in source file of the function call */
1800 	   )
1801 	{
1802 	   assert(blkmem != NULL);
1803 	
1804 	   if( *blkmem != NULL )
1805 	   {
1806 	      BMSclearBlockMemory_call(*blkmem, filename, line);
1807 	      BMSfreeMemory(blkmem);
1808 	      assert(*blkmem == NULL);
1809 	   }
1810 	   else
1811 	   {
1812 	      printErrorHeader(filename, line);
1813 	      printError("Tried to destroy null block memory.\n");
1814 	   }
1815 	}
1816 	
1817 	/** work for allocating memory in the block memory pool */
1818 	INLINE static
1819 	void* BMSallocBlockMemory_work(
1820 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1821 	   size_t                size,               /**< size of memory element to allocate */
1822 	   const char*           filename,           /**< source file of the function call */
1823 	   int                   line                /**< line number in source file of the function call */
1824 	   )
1825 	{
1826 	   BMS_CHKMEM** chkmemptr;
1827 	   int hashnumber;
1828 	   void* ptr;
1829 	
1830 	   assert( blkmem != NULL );
1831 	
1832 	   /* calculate hash number of given size */
1833 	   alignSize(&size);
1834 	   hashnumber = getHashNumber((int)size);
1835 	
1836 	   /* find correspoding chunk block */
1837 	   chkmemptr = &(blkmem->chkmemhash[hashnumber]);
1838 	   while( *chkmemptr != NULL && (*chkmemptr)->elemsize != (int)size )
1839 	      chkmemptr = &((*chkmemptr)->nextchkmem);
1840 	
1841 	   /* create new chunk block if necessary */
1842 	   if( *chkmemptr == NULL  )
1843 	   {
1844 	      *chkmemptr = createChkmem((int)size, blkmem->initchunksize, blkmem->garbagefactor, &blkmem->memallocated);
1845 	      if( *chkmemptr == NULL )
1846 	      {
1847 	         printErrorHeader(filename, line);
1848 	         printError("Insufficient memory for chunk block.\n");
1849 	         return NULL;
1850 	      }
1851 	#ifndef NDEBUG
1852 	      BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
1853 	      (*chkmemptr)->line = line;
1854 	#endif
1855 	   }
1856 	
1857 	   /* get memory inside the chunk block */
1858 	   ptr = allocChkmemElement(*chkmemptr, &blkmem->memallocated);
1859 	
1860 	   if( ptr == NULL )
1861 	   {
1862 	      printErrorHeader(filename, line);
1863 	      printError("Insufficient memory for new chunk.\n");
1864 	   }
1865 	   debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, ptr, filename, line);
1866 	
1867 	   /* add the used memory */
1868 	   blkmem->memused += (long long) size;
1869 	   blkmem->maxmemused = MAX(blkmem->maxmemused, blkmem->memused);
1870 	   blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
1871 	   blkmem->maxmemallocated = MAX(blkmem->maxmemallocated, blkmem->memallocated);
1872 	
1873 	   assert(blkmem->memused >= 0);
1874 	   assert(blkmem->memallocated >= 0);
1875 	
1876 	   checkBlkmem(blkmem);
1877 	
1878 	   return ptr;
1879 	}
1880 	
1881 	/** allocates memory in the block memory pool */
1882 	void* BMSallocBlockMemory_call(
1883 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1884 	   size_t                size,               /**< size of memory element to allocate */
1885 	   const char*           filename,           /**< source file of the function call */
1886 	   int                   line                /**< line number in source file of the function call */
1887 	   )
1888 	{
1889 	#ifndef NDEBUG
1890 	   if ( size > MAXMEMSIZE )
1891 	   {
1892 	      printErrorHeader(filename, line);
1893 	      printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1894 	      return NULL;
1895 	   }
1896 	#endif
1897 	
1898 	   return BMSallocBlockMemory_work(blkmem, size, filename, line);
1899 	}
1900 	
1901 	/** allocates memory in the block memory pool and clears it */
1902 	void* BMSallocClearBlockMemory_call(
1903 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1904 	   size_t                size,               /**< size of memory element to allocate */
1905 	   const char*           filename,           /**< source file of the function call */
1906 	   int                   line                /**< line number in source file of the function call */
1907 	   )
1908 	{
1909 	   void* ptr;
1910 	
1911 	   ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
1912 	   if( ptr != NULL )
1913 	      BMSclearMemorySize(ptr, size);
1914 	
1915 	   return ptr;
1916 	}
1917 	
1918 	/** allocates array in the block memory pool */
1919 	void* BMSallocBlockMemoryArray_call(
1920 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1921 	   size_t                num,                /**< size of array to be allocated */
1922 	   size_t                typesize,           /**< size of each component */
1923 	   const char*           filename,           /**< source file of the function call */
1924 	   int                   line                /**< line number in source file of the function call */
1925 	   )
1926 	{
1927 	#ifndef NDEBUG
1928 	   if ( num > (MAXMEMSIZE / typesize) )
1929 	   {
1930 	      printErrorHeader(filename, line);
1931 	      printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1932 	      return NULL;
1933 	   }
1934 	#endif
1935 	
1936 	   return BMSallocBlockMemory_work(blkmem, num * typesize, filename, line);
1937 	}
1938 	
1939 	/** allocates array in the block memory pool and clears it */
1940 	void* BMSallocClearBlockMemoryArray_call(
1941 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1942 	   size_t                num,                /**< size of array to be allocated */
1943 	   size_t                typesize,           /**< size of each component */
1944 	   const char*           filename,           /**< source file of the function call */
1945 	   int                   line                /**< line number in source file of the function call */
1946 	   )
1947 	{
1948 	   void* ptr;
1949 	
1950 	   ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
1951 	   if ( ptr != NULL )
1952 	      BMSclearMemorySize(ptr, num * typesize);
1953 	
1954 	   return ptr;
1955 	}
1956 	
1957 	/** resizes memory element in the block memory pool and copies the data */
1958 	void* BMSreallocBlockMemory_call(
1959 	   BMS_BLKMEM*           blkmem,             /**< block memory */
1960 	   void*                 ptr,                /**< memory element to reallocated */
1961 	   size_t                oldsize,            /**< old size of memory element */
1962 	   size_t                newsize,            /**< new size of memory element */
1963 	   const char*           filename,           /**< source file of the function call */
1964 	   int                   line                /**< line number in source file of the function call */
1965 	   )
1966 	{
1967 	   void* newptr;
1968 	
1969 	   if( ptr == NULL )
1970 	   {
1971 	      assert(oldsize == 0);
1972 	      return BMSallocBlockMemory_call(blkmem, newsize, filename, line);
1973 	   }
1974 	
1975 	#ifndef NDEBUG
1976 	   if ( newsize > MAXMEMSIZE )
1977 	   {
1978 	      printErrorHeader(filename, line);
1979 	      printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
1980 	      return NULL;
1981 	   }
1982 	#endif
1983 	
1984 	   alignSize(&oldsize);
1985 	   alignSize(&newsize);
1986 	   if( oldsize == newsize )
1987 	      return ptr;
1988 	
1989 	   newptr = BMSallocBlockMemory_call(blkmem, newsize, filename, line);
1990 	   if( newptr != NULL )
1991 	      BMScopyMemorySize(newptr, ptr, MIN(oldsize, newsize));
1992 	   BMSfreeBlockMemory_call(blkmem, &ptr, oldsize, filename, line);
1993 	
1994 	   return newptr;
1995 	}
1996 	
1997 	/** resizes array in the block memory pool and copies the data */
1998 	void* BMSreallocBlockMemoryArray_call(
1999 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2000 	   void*                 ptr,                /**< memory element to reallocated */
2001 	   size_t                oldnum,             /**< old size of array */
2002 	   size_t                newnum,             /**< new size of array */
2003 	   size_t                typesize,           /**< size of each component */
2004 	   const char*           filename,           /**< source file of the function call */
2005 	   int                   line                /**< line number in source file of the function call */
2006 	   )
2007 	{
2008 	   void* newptr;
2009 	
2010 	   if( ptr == NULL )
2011 	   {
2012 	      assert(oldnum == 0);
2013 	      return BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2014 	   }
2015 	
2016 	#ifndef NDEBUG
2017 	   if ( newnum > (MAXMEMSIZE / typesize) )
2018 	   {
2019 	      printErrorHeader(filename, line);
2020 	      printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2021 	      return NULL;
2022 	   }
2023 	#endif
2024 	
2025 	   if ( oldnum == newnum )
2026 	      return ptr;
2027 	
2028 	   newptr = BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
2029 	   if ( newptr != NULL )
2030 	      BMScopyMemorySize(newptr, ptr, MIN(oldnum, newnum) * typesize);
2031 	   BMSfreeBlockMemory_call(blkmem, &ptr, oldnum * typesize, filename, line);
2032 	
2033 	   return newptr;
2034 	}
2035 	
2036 	/** duplicates memory element in the block memory pool and copies the data */
2037 	void* BMSduplicateBlockMemory_call(
2038 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2039 	   const void*           source,             /**< memory element to duplicate */
2040 	   size_t                size,               /**< size of memory elements */
2041 	   const char*           filename,           /**< source file of the function call */
2042 	   int                   line                /**< line number in source file of the function call */
2043 	   )
2044 	{
2045 	   void* ptr;
2046 	
2047 	   assert(source != NULL);
2048 	
2049 	   ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
2050 	   if( ptr != NULL )
2051 	      BMScopyMemorySize(ptr, source, size);
2052 	
2053 	   return ptr;
2054 	}
2055 	
2056 	/** duplicates array in the block memory pool and copies the data */
2057 	void* BMSduplicateBlockMemoryArray_call(
2058 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2059 	   const void*           source,             /**< memory element to duplicate */
2060 	   size_t                num,                /**< size of array to be duplicated */
2061 	   size_t                typesize,           /**< size of each component */
2062 	   const char*           filename,           /**< source file of the function call */
2063 	   int                   line                /**< line number in source file of the function call */
2064 	   )
2065 	{
2066 	   void* ptr;
2067 	
2068 	   assert(source != NULL);
2069 	
2070 	   ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
2071 	   if( ptr != NULL )
2072 	      BMScopyMemorySize(ptr, source, num * typesize);
2073 	
2074 	   return ptr;
2075 	}
2076 	
2077 	/** common work for freeing block memory */
2078 	INLINE static
2079 	void BMSfreeBlockMemory_work(
2080 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2081 	   void**                ptr,                /**< pointer to pointer to memory element to free */
2082 	   size_t                size,               /**< size of memory element */
2083 	   const char*           filename,           /**< source file of the function call */
2084 	   int                   line                /**< line number in source file of the function call */
2085 	   )
2086 	{
2087 	   BMS_CHKMEM* chkmem;
2088 	   int hashnumber;
2089 	
2090 	   assert(ptr != NULL);
2091 	   assert(*ptr != NULL);
2092 	
2093 	   /* calculate hash number of given size */
2094 	   alignSize(&size);
2095 	   hashnumber = getHashNumber((int)size);
2096 	
2097 	   debugMessage("free    %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, *ptr, filename, line);
2098 	
2099 	   /* find correspoding chunk block */
2100 	   assert( blkmem->chkmemhash != NULL );
2101 	   chkmem = blkmem->chkmemhash[hashnumber];
2102 	   while( chkmem != NULL && chkmem->elemsize != (int)size )
2103 	      chkmem = chkmem->nextchkmem;
2104 	   if( chkmem == NULL )
2105 	   {
2106 	      printErrorHeader(filename, line);
2107 	      printError("Tried to free pointer <%p> in block memory <%p> of unknown size %llu.\n", *ptr, (void*)blkmem, (unsigned long long)size);
2108 	      return;
2109 	   }
2110 	   assert(chkmem->elemsize == (int)size);
2111 	
2112 	   /* free memory in chunk block */
2113 	   freeChkmemElement(chkmem, *ptr, &blkmem->memallocated, filename, line);
2114 	   blkmem->memused -= (long long) size;
2115 	
2116 	   blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
2117 	
2118 	   assert(blkmem->memused >= 0);
2119 	   assert(blkmem->memallocated >= 0);
2120 	
2121 	   checkBlkmem(blkmem);
2122 	
2123 	   *ptr = NULL;
2124 	}
2125 	
2126 	/** frees memory element in the block memory pool and sets pointer to NULL */
2127 	void BMSfreeBlockMemory_call(
2128 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2129 	   void**                ptr,                /**< pointer to pointer to memory element to free */
2130 	   size_t                size,               /**< size of memory element */
2131 	   const char*           filename,           /**< source file of the function call */
2132 	   int                   line                /**< line number in source file of the function call */
2133 	   )
2134 	{
2135 	   assert( blkmem != NULL );
2136 	   assert( ptr != NULL );
2137 	
2138 	   if( *ptr != NULL )
2139 	      BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2140 	   else if( size != 0 )
2141 	   {
2142 	      printErrorHeader(filename, line);
2143 	      printError("Tried to free null block pointer.\n");
2144 	   }
2145 	   checkBlkmem(blkmem);
2146 	}
2147 	
2148 	/** frees memory element in the block memory pool if pointer is not NULL and sets pointer to NULL */
2149 	void BMSfreeBlockMemoryNull_call(
2150 	   BMS_BLKMEM*           blkmem,             /**< block memory */
2151 	   void**                ptr,                /**< pointer to pointer to memory element to free */
2152 	   size_t                size,               /**< size of memory element */
2153 	   const char*           filename,           /**< source file of the function call */
2154 	   int                   line                /**< line number in source file of the function call */
2155 	   )
2156 	{
2157 	   assert( blkmem != NULL );
2158 	   assert( ptr != NULL );
2159 	
2160 	   if( *ptr != NULL )
2161 	   {
2162 	      BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
2163 	   }
2164 	   checkBlkmem(blkmem);
2165 	}
2166 	
2167 	/** calls garbage collection of block memory, frees chunks without allocated memory elements, and frees
2168 	 *  chunk blocks without any chunks
2169 	 */
2170 	void BMSgarbagecollectBlockMemory_call(
2171 	   BMS_BLKMEM*           blkmem              /**< block memory */
2172 	   )
2173 	{
2174 	   int i;
2175 	
2176 	   assert(blkmem != NULL);
2177 	
2178 	   for( i = 0; i < CHKHASH_SIZE; ++i )
2179 	   {
2180 	      BMS_CHKMEM** chkmemptr;
2181 	
2182 	      chkmemptr = &blkmem->chkmemhash[i];
2183 	      while( *chkmemptr != NULL )
2184 	      {
2185 	         garbagecollectChkmem(*chkmemptr, &blkmem->memallocated);
2186 	         checkBlkmem(blkmem);
2187 	         if( (*chkmemptr)->nchunks == 0 )
2188 	         {
2189 	            BMS_CHKMEM* nextchkmem;
2190 	
2191 	            assert((*chkmemptr)->lazyfreesize == 0);
2192 	            nextchkmem = (*chkmemptr)->nextchkmem;
2193 	            destroyChkmem(chkmemptr, &blkmem->memallocated);
2194 	            *chkmemptr = nextchkmem;
2195 	            checkBlkmem(blkmem);
2196 	         }
2197 	         else
2198 	            chkmemptr = &(*chkmemptr)->nextchkmem;
2199 	      }
2200 	   }
2201 	}
2202 	
2203 	/** returns the number of allocated bytes in the block memory */
2204 	long long BMSgetBlockMemoryAllocated_call(
2205 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2206 	   )
2207 	{
2208 	   assert( blkmem != NULL );
2209 	
2210 	   return blkmem->memallocated;
2211 	}
2212 	
2213 	/** returns the number of used bytes in the block memory */
2214 	long long BMSgetBlockMemoryUsed_call(
2215 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2216 	   )
2217 	{
2218 	   assert( blkmem != NULL );
2219 	
2220 	   return blkmem->memused;
2221 	}
2222 	
2223 	/** returns the number of allocated but not used bytes in the block memory */
2224 	long long BMSgetBlockMemoryUnused_call(
2225 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2226 	   )
2227 	{
2228 	   assert( blkmem != NULL );
2229 	
2230 	   return blkmem->memallocated - blkmem->memused;
2231 	}
2232 	
2233 	/** returns the maximal number of used bytes in the block memory */
2234 	long long BMSgetBlockMemoryUsedMax_call(
2235 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2236 	   )
2237 	{
2238 	   assert( blkmem != NULL );
2239 	
2240 	   return blkmem->maxmemused;
2241 	}
2242 	
2243 	/** returns the maximal number of allocated but not used bytes in the block memory */
2244 	long long BMSgetBlockMemoryUnusedMax_call(
2245 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2246 	   )
2247 	{
2248 	   assert( blkmem != NULL );
2249 	
2250 	   return blkmem->maxmemunused;
2251 	}
2252 	
2253 	/** returns the maximal number of allocated bytes in the block memory */
2254 	long long BMSgetBlockMemoryAllocatedMax_call(
2255 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2256 	   )
2257 	{
2258 	   assert( blkmem != NULL );
2259 	
2260 	   return blkmem->maxmemallocated;
2261 	}
2262 	
2263 	/** returns the size of the given memory element; returns 0, if the element is not member of the block memory */
2264 	size_t BMSgetBlockPointerSize_call(
2265 	   const BMS_BLKMEM*     blkmem,             /**< block memory */
2266 	   const void*           ptr                 /**< memory element */
2267 	   )
2268 	{
2269 	   const BMS_CHKMEM* chkmem;
2270 	
2271 	   assert(blkmem != NULL);
2272 	
2273 	   if( ptr == NULL )
2274 	      return 0;
2275 	
2276 	   chkmem = findChkmem(blkmem, ptr);
2277 	   if( chkmem == NULL )
2278 	      return 0;
2279 	
2280 	   return (size_t)(chkmem->elemsize); /*lint !e571*/
2281 	}
2282 	
2283 	/** outputs allocation diagnostics of block memory */
2284 	void BMSdisplayBlockMemory_call(
2285 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2286 	   )
2287 	{
2288 	   const BMS_CHKMEM* chkmem;
2289 	   int nblocks = 0;
2290 	   int nunusedblocks = 0;
2291 	   int totalnchunks = 0;
2292 	   int totalneagerchunks = 0;
2293 	   int totalnelems = 0;
2294 	   int totalneagerelems = 0;
2295 	   int totalnlazyelems = 0;
2296 	#ifndef NDEBUG
2297 	   int totalngarbagecalls = 0;
2298 	   int totalngarbagefrees = 0;
2299 	#endif
2300 	   long long allocedmem = 0;
2301 	   long long freemem = 0;
2302 	   int i;
2303 	
2304 	#ifndef NDEBUG
2305 	   printInfo(" ElSize #Chunk #Eag  #Elems  #EagFr  #LazFr  #GCl #GFr  Free  MBytes First Allocator\n");
2306 	#else
2307 	   printInfo(" ElSize #Chunk #Eag  #Elems  #EagFr  #LazFr  Free  MBytes\n");
2308 	#endif
2309 	
2310 	   assert(blkmem != NULL);
2311 	
2312 	   for( i = 0; i < CHKHASH_SIZE; ++i )
2313 	   {
2314 	      chkmem = blkmem->chkmemhash[i];
2315 	      while( chkmem != NULL )
2316 	      {
2317 	         int nchunks = 0;
2318 	         int nelems = 0;
2319 	         int neagerchunks = 0;
2320 	         int neagerelems = 0;
2321 	
2322 	         FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2323 	         {
2324 	            assert(chunk != NULL);
2325 	            assert(chunk->elemsize == chkmem->elemsize);
2326 	            assert(chunk->chkmem == chkmem);
2327 	            nchunks++;
2328 	            nelems += chunk->storesize;
2329 	            if( chunk->eagerfree != NULL )
2330 	            {
2331 	               neagerchunks++;
2332 	               neagerelems += chunk->eagerfreesize;
2333 	            }
2334 	         })
2335 	
2336 	         assert(nchunks == chkmem->nchunks);
2337 	         assert(nelems == chkmem->storesize);
2338 	         assert(neagerelems == chkmem->eagerfreesize);
2339 	
2340 	         if( nelems > 0 )
2341 	         {
2342 	            nblocks++;
2343 	            allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2344 	            freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2345 	
2346 	#ifndef NDEBUG
2347 	            printInfo("%7d %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f %s:%d\n",
2348 	            chkmem->elemsize, nchunks, neagerchunks, nelems,
2349 	            neagerelems, chkmem->lazyfreesize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2350 	            100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2351 	               (double)chkmem->elemsize * nelems / (1024.0*1024.0),
2352 	               chkmem->filename, chkmem->line);
2353 	#else
2354 	            printInfo("%7d %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2355 	            chkmem->elemsize, nchunks, neagerchunks, nelems,
2356 	            neagerelems, chkmem->lazyfreesize,
2357 	            100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
2358 	               (double)chkmem->elemsize * nelems / (1024.0*1024.0));
2359 	#endif
2360 	         }
2361 	         else
2362 	         {
2363 	#ifndef NDEBUG
2364 	            printInfo("%7d <unused>                            %5d %4d        %s:%d\n",
2365 	            chkmem->elemsize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
2366 	               chkmem->filename, chkmem->line);
2367 	#else
2368 	            printInfo("%7d <unused>\n", chkmem->elemsize);
2369 	#endif
2370 	            nunusedblocks++;
2371 	         }
2372 	         totalnchunks += nchunks;
2373 	         totalneagerchunks += neagerchunks;
2374 	         totalnelems += nelems;
2375 	         totalneagerelems += neagerelems;
2376 	         totalnlazyelems += chkmem->lazyfreesize;
2377 	#ifndef NDEBUG
2378 	         totalngarbagecalls += chkmem->ngarbagecalls;
2379 	         totalngarbagefrees += chkmem->ngarbagefrees;
2380 	#endif
2381 	         chkmem = chkmem->nextchkmem;
2382 	      }
2383 	   }
2384 	#ifndef NDEBUG
2385 	   printInfo("  Total %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f\n",
2386 	      totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems, 
2387 	      totalngarbagecalls, totalngarbagefrees,
2388 	      totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2389 	      (double)allocedmem/(1024.0*1024.0));
2390 	#else
2391 	   printInfo("  Total %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
2392 	      totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems, 
2393 	      totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
2394 	      (double)allocedmem/(1024.0*1024.0));
2395 	#endif
2396 	   printInfo("%d blocks (%d unused), %" LONGINT_FORMAT " bytes allocated, %" LONGINT_FORMAT " bytes free",
2397 	      nblocks + nunusedblocks, nunusedblocks, allocedmem, freemem);
2398 	   if( allocedmem > 0 )
2399 	      printInfo(" (%.1f%%)", 100.0 * (double) freemem / (double) allocedmem);
2400 	   printInfo("\n\n");
2401 	
2402 	   printInfo("Memory Peaks:    Used    Lazy   Total\n");
2403 	   printInfo("               %6.1f  %6.1f  %6.1f MBytes\n", (double)blkmem->maxmemused / (1024.0 * 1024.0),
2404 	         (double)blkmem->maxmemunused / (1024.0 * 1024.0), (double)blkmem->maxmemallocated / (1024.0 * 1024.0));
2405 	}
2406 	
2407 	/** outputs error messages, if there are allocated elements in the block memory and returns number of unfreed bytes */
2408 	long long BMScheckEmptyBlockMemory_call(
2409 	   const BMS_BLKMEM*     blkmem              /**< block memory */
2410 	   )
2411 	{
2412 	   const BMS_CHKMEM* chkmem;
2413 	   long long allocedmem = 0;
2414 	   long long freemem = 0;
2415 	   int i;
2416 	
2417 	   assert(blkmem != NULL);
2418 	
2419 	   for( i = 0; i < CHKHASH_SIZE; ++i )
2420 	   {
2421 	      chkmem = blkmem->chkmemhash[i];
2422 	      while( chkmem != NULL )
2423 	      {
2424 	         int nchunks = 0;
2425 	         int nelems = 0;
2426 	         int neagerelems = 0;
2427 	
2428 	         FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
2429 	         {
2430 	            assert(chunk != NULL);
2431 	            assert(chunk->elemsize == chkmem->elemsize);
2432 	            assert(chunk->chkmem == chkmem);
2433 	            nchunks++;
2434 	            nelems += chunk->storesize;
2435 	            if( chunk->eagerfree != NULL )
2436 	               neagerelems += chunk->eagerfreesize;
2437 	         })
2438 	
2439 	         assert(nchunks == chkmem->nchunks);
2440 	         assert(nelems == chkmem->storesize);
2441 	         assert(neagerelems == chkmem->eagerfreesize);
2442 	
2443 	         if( nelems > 0 )
2444 	         {
2445 	            allocedmem += (long long)chkmem->elemsize * (long long)nelems;
2446 	            freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
2447 	
2448 	            if( nelems != neagerelems + chkmem->lazyfreesize )
2449 	            {
2450 	#ifndef NDEBUG
2451 	               errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed. First Allocator: %s:%d\n",
2452 	                  (((long long)nelems - (long long)neagerelems) - (long long)chkmem->lazyfreesize)
2453 	                  * (long long)(chkmem->elemsize),
2454 	                  (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize),
2455 	                  chkmem->filename, chkmem->line);
2456 	#else
2457 	               errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed.\n",
2458 	                  ((nelems - neagerelems) - chkmem->lazyfreesize) * (long long)(chkmem->elemsize),
2459 	                  (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize));
2460 	#endif
2461 	            }
2462 	         }
2463 	         chkmem = chkmem->nextchkmem;
2464 	      }
2465 	   }
2466 	
2467 	   if( allocedmem != freemem )
2468 	   {
2469 	      errorMessage("%" LONGINT_FORMAT " bytes not freed in total.\n", allocedmem - freemem);
2470 	   }
2471 	
2472 	   return allocedmem - freemem;
2473 	}
2474 	
2475 	
2476 	
2477 	
2478 	
2479 	
2480 	/***********************************************************
2481 	 * Buffer Memory Management
2482 	 *
2483 	 * Efficient memory management for temporary objects
2484 	 ***********************************************************/
2485 	
2486 	/** memory buffer storage for temporary objects */
2487 	struct BMS_BufMem
2488 	{
2489 	   void**                data;               /**< allocated memory chunks for arbitrary data */
2490 	   size_t*               size;               /**< sizes of buffers in bytes */
2491 	   unsigned int*         used;               /**< 1 iff corresponding buffer is in use */
2492 	   size_t                totalmem;           /**< total memory consumption of buffer */
2493 	   unsigned int          clean;              /**< 1 iff the memory blocks in the buffer should be initialized to zero? */
2494 	   size_t                ndata;              /**< number of memory chunks */
2495 	   size_t                firstfree;          /**< first unused memory chunk */
2496 	   double                arraygrowfac;       /**< memory growing factor for dynamically allocated arrays */
2497 	   unsigned int          arraygrowinit;      /**< initial size of dynamically allocated arrays */
2498 	};
2499 	
2500 	
2501 	/** creates memory buffer storage */
2502 	BMS_BUFMEM* BMScreateBufferMemory_call(
2503 	   double                arraygrowfac,       /**< memory growing factor for dynamically allocated arrays */
2504 	   int                   arraygrowinit,      /**< initial size of dynamically allocated arrays */
2505 	   unsigned int          clean,              /**< should the memory blocks in the buffer be initialized to zero? */
2506 	   const char*           filename,           /**< source file of the function call */
2507 	   int                   line                /**< line number in source file of the function call */
2508 	   )
2509 	{
2510 	   BMS_BUFMEM* buffer;
2511 	
2512 	   assert( arraygrowinit > 0 );
2513 	   assert( arraygrowfac > 0.0 );
2514 	
2515 	   BMSallocMemory(&buffer);
2516 	   if ( buffer != NULL )
2517 	   {
2518 	      buffer->data = NULL;
2519 	      buffer->size = NULL;
2520 	      buffer->used = NULL;
2521 	      buffer->totalmem = 0UL;
2522 	      buffer->clean = clean;
2523 	      buffer->ndata = 0;
2524 	      buffer->firstfree = 0;
2525 	      buffer->arraygrowinit = (unsigned) arraygrowinit;
2526 	      buffer->arraygrowfac = arraygrowfac;
2527 	   }
2528 	   else
2529 	   {
2530 	      printErrorHeader(filename, line);
2531 	      printError("Insufficient memory for buffer memory header.\n");
2532 	   }
2533 	
2534 	   return buffer;
2535 	}
2536 	
2537 	/** destroys buffer memory */
2538 	void BMSdestroyBufferMemory_call(
2539 	   BMS_BUFMEM**          buffer,             /**< pointer to memory buffer storage */
2540 	   const char*           filename,           /**< source file of the function call */
2541 	   int                   line                /**< line number in source file of the function call */
2542 	   )
2543 	{
2544 	   size_t i;
2545 	
2546 	   if ( *buffer != NULL )
2547 	   {
2548 	      i = (*buffer)->ndata;
2549 	      if ( i > 0 ) {
2550 	         for (--i ; ; i--)
2551 	         {
2552 	            assert( ! (*buffer)->used[i] );
2553 	            BMSfreeMemoryArrayNull(&(*buffer)->data[i]);
2554 	            if ( i == 0 )
2555 	               break;
2556 	         }
2557 	      }
2558 	      BMSfreeMemoryArrayNull(&(*buffer)->data);
2559 	      BMSfreeMemoryArrayNull(&(*buffer)->size);
2560 	      BMSfreeMemoryArrayNull(&(*buffer)->used);
2561 	      BMSfreeMemory(buffer);
2562 	   }
2563 	   else
2564 	   {
2565 	      printErrorHeader(filename, line);
2566 	      printError("Tried to free null buffer memory.\n");
2567 	   }
2568 	}
2569 	
2570 	/** set arraygrowfac */
2571 	void BMSsetBufferMemoryArraygrowfac(
2572 	   BMS_BUFMEM*           buffer,             /**< pointer to memory buffer storage */
2573 	   double                arraygrowfac        /**< memory growing factor for dynamically allocated arrays */
2574 	   )
2575 	{
2576 	   assert( buffer != NULL );
2577 	   assert( arraygrowfac > 0.0 );
2578 	
2579 	   buffer->arraygrowfac = arraygrowfac;
2580 	}
2581 	
2582 	/** set arraygrowinit */
2583 	void BMSsetBufferMemoryArraygrowinit(
2584 	   BMS_BUFMEM*           buffer,             /**< pointer to memory buffer storage */
2585 	   int                   arraygrowinit       /**< initial size of dynamically allocated arrays */
2586 	   )
2587 	{
2588 	   assert( buffer != NULL );
2589 	   assert( arraygrowinit > 0 );
2590 	
2591 	   buffer->arraygrowinit = (unsigned) arraygrowinit;
2592 	}
2593 	
2594 	#ifndef SCIP_NOBUFFERMEM
2595 	/** calculate memory size for dynamically allocated arrays
2596 	 *
2597 	 *  This function is a copy of the function in set.c in order to be able to use memory.? separately.
2598 	 */
2599 	static
2600 	size_t calcMemoryGrowSize(
2601 	   size_t                initsize,           /**< initial size of array */
2602 	   SCIP_Real             growfac,            /**< growing factor of array */
2603 	   size_t                num                 /**< minimum number of entries to store */
2604 	   )
2605 	{
2606 	   size_t size;
2607 	
2608 	   assert( growfac >= 1.0 );
2609 	
2610 	   if ( growfac == 1.0 )
2611 	      size = MAX(initsize, num);
2612 	   else
2613 	   {
2614 	      size_t oldsize;
2615 	
2616 	      /* calculate the size with this loop, such that the resulting numbers are always the same */
2617 	      initsize = MAX(initsize, 4);
2618 	      size = initsize;
2619 	      oldsize = size - 1;
2620 	
2621 	      /* second condition checks against overflow */
2622 	      while ( size < num && size > oldsize )
2623 	      {
2624 	         oldsize = size;
2625 	         size = (size_t)(growfac * size + initsize);
2626 	      }
2627 	
2628 	      /* if an overflow happened, set the correct value */
2629 	      if ( size <= oldsize )
2630 	         size = num;
2631 	   }
2632 	
2633 	   assert( size >= initsize );
2634 	   assert( size >= num );
2635 	
2636 	   return size;
2637 	}
2638 	#endif
2639 	
2640 	/** work for allocating the next unused buffer */
2641 	INLINE static
2642 	void* BMSallocBufferMemory_work(
2643 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2644 	   size_t                size,               /**< minimal required size of the buffer */
2645 	   const char*           filename,           /**< source file of the function call */
2646 	   int                   line                /**< line number in source file of the function call */
2647 	   )
2648 	{
2649 	   /* cppcheck-suppress unassignedVariable */
2650 	   void* ptr;
2651 	#ifndef SCIP_NOBUFFERMEM
2652 	   size_t bufnum;
2653 	#endif
2654 	
2655 	#ifndef SCIP_NOBUFFERMEM
2656 	   assert( buffer != NULL );
2657 	   assert( buffer->firstfree <= buffer->ndata );
2658 	
2659 	   /* allocate a minimum of 1 byte */
2660 	   if ( size == 0 )
2661 	      size = 1;
2662 	
2663 	   /* check, if we need additional buffers */
2664 	   if ( buffer->firstfree == buffer->ndata )
2665 	   {
2666 	      size_t newsize;
2667 	      size_t i;
2668 	
2669 	      /* create additional buffers */
2670 	      newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, buffer->firstfree + 1);
2671 	      BMSreallocMemoryArray(&buffer->data, newsize);
2672 	      if ( buffer->data == NULL )
2673 	      {
2674 	         printErrorHeader(filename, line);
2675 	         printError("Insufficient memory for reallocating buffer data storage.\n");
2676 	         return NULL;
2677 	      }
2678 	      BMSreallocMemoryArray(&buffer->size, newsize);
2679 	      if ( buffer->size == NULL )
2680 	      {
2681 	         printErrorHeader(filename, line);
2682 	         printError("Insufficient memory for reallocating buffer size storage.\n");
2683 	         return NULL;
2684 	      }
2685 	      BMSreallocMemoryArray(&buffer->used, newsize);
2686 	      if ( buffer->used == NULL )
2687 	      {
2688 	         printErrorHeader(filename, line);
2689 	         printError("Insufficient memory for reallocating buffer used storage.\n");
2690 	         return NULL;
2691 	      }
2692 	
2693 	      /* init data */
2694 	      for (i = buffer->ndata; i < newsize; ++i)
2695 	      {
2696 	         buffer->data[i] = NULL;
2697 	         buffer->size[i] = 0;
2698 	         buffer->used[i] = FALSE;
2699 	      }
2700 	      buffer->ndata = newsize;
2701 	   }
2702 	   assert(buffer->firstfree < buffer->ndata);
2703 	
2704 	   /* check, if the current buffer is large enough */
2705 	   bufnum = buffer->firstfree;
2706 	   assert( ! buffer->used[bufnum] );
2707 	   if ( buffer->size[bufnum] < size )
2708 	   {
2709 	      size_t newsize;
2710 	
2711 	      /* enlarge buffer */
2712 	      newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2713 	      BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2714 	
2715 	      /* clear new memory */
2716 	      if( buffer->clean )
2717 	      {
2718 	         char* tmpptr = (char*)(buffer->data[bufnum]);
2719 	         size_t inc = buffer->size[bufnum] / sizeof(*tmpptr);
2720 	         tmpptr += inc;
2721 	
2722 	         BMSclearMemorySize(tmpptr, newsize - buffer->size[bufnum]);
2723 	      }
2724 	      assert( newsize > buffer->size[bufnum] );
2725 	      buffer->totalmem += newsize - buffer->size[bufnum];
2726 	      buffer->size[bufnum] = newsize;
2727 	
2728 	      if ( buffer->data[bufnum] == NULL )
2729 	      {
2730 	         printErrorHeader(filename, line);
2731 	         printError("Insufficient memory for reallocating buffer storage.\n");
2732 	         return NULL;
2733 	      }
2734 	   }
2735 	   assert( buffer->size[bufnum] >= size );
2736 	
2737 	#ifdef CHECKCLEANBUFFER
2738 	   /* check that the memory is cleared */
2739 	   if( buffer->clean )
2740 	   {
2741 	      char* tmpptr = (char*)(buffer->data[bufnum]);
2742 	      unsigned int inc = buffer->size[bufnum] / sizeof(*tmpptr);
2743 	      tmpptr += inc;
2744 	
2745 	      while( --tmpptr >= (char*)(buffer->data[bufnum]) )
2746 	         assert(*tmpptr == '\0');
2747 	   }
2748 	#endif
2749 	
2750 	   ptr = buffer->data[bufnum];
2751 	   buffer->used[bufnum] = TRUE;
2752 	   buffer->firstfree++;
2753 	
2754 	   debugMessage("Allocated buffer %llu/%llu at %p of size %llu (required size: %llu) for pointer %p.\n",
2755 	      (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2756 	      (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, ptr);
2757 	
2758 	#else
2759 	   if( buffer->clean )
2760 	   {
2761 	      /* we should allocate at least one byte, otherwise BMSallocMemorySize will fail */
2762 	      size = MAX(size,1);
2763 	
2764 	      BMSallocClearMemorySize(&ptr, size);
2765 	   }
2766 	   else
2767 	   {
2768 	      BMSallocMemorySize(&ptr, size);
2769 	   }
2770 	#endif
2771 	
2772 	   return ptr;
2773 	}
2774 	
2775 	/** allocates the next unused buffer */
2776 	void* BMSallocBufferMemory_call(
2777 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2778 	   size_t                size,               /**< minimal required size of the buffer */
2779 	   const char*           filename,           /**< source file of the function call */
2780 	   int                   line                /**< line number in source file of the function call */
2781 	   )
2782 	{
2783 	#ifndef NDEBUG
2784 	   if ( size > MAXMEMSIZE )
2785 	   {
2786 	      printErrorHeader(filename, line);
2787 	      printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2788 	      return NULL;
2789 	   }
2790 	#endif
2791 	
2792 	   return BMSallocBufferMemory_work(buffer, size, filename, line);
2793 	}
2794 	
2795 	/** allocates the next unused buffer array */
2796 	void* BMSallocBufferMemoryArray_call(
2797 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2798 	   size_t                num,                /**< size of array to be allocated */
2799 	   size_t                typesize,           /**< size of components */
2800 	   const char*           filename,           /**< source file of the function call */
2801 	   int                   line                /**< line number in source file of the function call */
2802 	   )
2803 	{
2804 	#ifndef NDEBUG
2805 	   if ( num > (MAXMEMSIZE / typesize) )
2806 	   {
2807 	      printErrorHeader(filename, line);
2808 	      printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2809 	      return NULL;
2810 	   }
2811 	#endif
2812 	
2813 	   return BMSallocBufferMemory_work(buffer, num * typesize, filename, line);
2814 	}
2815 	
2816 	/** allocates the next unused buffer and clears it */
2817 	void* BMSallocClearBufferMemoryArray_call(
2818 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2819 	   size_t                num,                /**< size of array to be allocated */
2820 	   size_t                typesize,           /**< size of components */
2821 	   const char*           filename,           /**< source file of the function call */
2822 	   int                   line                /**< line number in source file of the function call */
2823 	   )
2824 	{
2825 	   void* ptr;
2826 	
2827 	   ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
2828 	   if ( ptr != NULL )
2829 	      BMSclearMemorySize(ptr, num * typesize);
2830 	
2831 	   return ptr;
2832 	}
2833 	
2834 	/** work for reallocating the buffer to at least the given size */
2835 	INLINE static
2836 	void* BMSreallocBufferMemory_work(
2837 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2838 	   void*                 ptr,                /**< pointer to the allocated memory buffer */
2839 	   size_t                size,               /**< minimal required size of the buffer */
2840 	   const char*           filename,           /**< source file of the function call */
2841 	   int                   line                /**< line number in source file of the function call */
2842 	   )
2843 	{
2844 	   void* newptr;
2845 	#ifndef SCIP_NOBUFFERMEM
2846 	   size_t bufnum;
2847 	#endif
2848 	
2849 	#ifndef SCIP_NOBUFFERMEM
2850 	   assert( buffer != NULL );
2851 	   assert( buffer->firstfree <= buffer->ndata );
2852 	   assert(!buffer->clean); /* reallocating clean buffer elements is not supported */
2853 	
2854 	   /* if the pointer doesn't exist yet, allocate it */
2855 	   if ( ptr == NULL )
2856 	      return BMSallocBufferMemory_call(buffer, size, filename, line);
2857 	
2858 	   assert( buffer->firstfree >= 1 );
2859 	
2860 	   /* Search the pointer in the buffer list:
2861 	    * Usually, buffers are allocated and freed like a stack, such that the currently used pointer is
2862 	    * most likely at the end of the buffer list.
2863 	    */
2864 	   bufnum = buffer->firstfree - 1;
2865 	   while ( bufnum > 0 && buffer->data[bufnum] != ptr )
2866 	      --bufnum;
2867 	
2868 	   newptr = ptr;
2869 	   assert( buffer->data[bufnum] == newptr );
2870 	   assert( buffer->used[bufnum] );
2871 	   assert( buffer->size[bufnum] >= 1 );
2872 	
2873 	   /* check if the buffer has to be enlarged */
2874 	   if ( size > buffer->size[bufnum] )
2875 	   {
2876 	      size_t newsize;
2877 	
2878 	      /* enlarge buffer */
2879 	      newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
2880 	      BMSreallocMemorySize(&buffer->data[bufnum], newsize);
2881 	      assert( newsize > buffer->size[bufnum] );
2882 	      buffer->totalmem += newsize - buffer->size[bufnum];
2883 	      buffer->size[bufnum] = newsize;
2884 	      if ( buffer->data[bufnum] == NULL )
2885 	      {
2886 	         printErrorHeader(filename, line);
2887 	         printError("Insufficient memory for reallocating buffer storage.\n");
2888 	         return NULL;
2889 	      }
2890 	      newptr = buffer->data[bufnum];
2891 	   }
2892 	   assert( buffer->size[bufnum] >= size );
2893 	   assert( newptr == buffer->data[bufnum] );
2894 	
2895 	   debugMessage("Reallocated buffer %llu/%llu at %p to size %llu (required size: %llu) for pointer %p.\n",
2896 	      (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
2897 	      (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, newptr);
2898 	
2899 	#else
2900 	   newptr = ptr;
2901 	   BMSreallocMemorySize(&newptr, size);
2902 	#endif
2903 	
2904 	   return newptr;
2905 	}
2906 	
2907 	/** reallocates the buffer to at least the given size */
2908 	void* BMSreallocBufferMemory_call(
2909 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2910 	   void*                 ptr,                /**< pointer to the allocated memory buffer */
2911 	   size_t                size,               /**< minimal required size of the buffer */
2912 	   const char*           filename,           /**< source file of the function call */
2913 	   int                   line                /**< line number in source file of the function call */
2914 	   )
2915 	{
2916 	#ifndef NDEBUG
2917 	   if ( size > MAXMEMSIZE )
2918 	   {
2919 	      printErrorHeader(filename, line);
2920 	      printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
2921 	      return NULL;
2922 	   }
2923 	#endif
2924 	
2925 	   return BMSreallocBufferMemory_work(buffer, ptr, size, filename, line);
2926 	}
2927 	
2928 	/** reallocates an array in the buffer to at least the given size */
2929 	void* BMSreallocBufferMemoryArray_call(
2930 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2931 	   void*                 ptr,                /**< pointer to the allocated memory buffer */
2932 	   size_t                num,                /**< size of array to be allocated */
2933 	   size_t                typesize,           /**< size of components */
2934 	   const char*           filename,           /**< source file of the function call */
2935 	   int                   line                /**< line number in source file of the function call */
2936 	   )
2937 	{
2938 	#ifndef NDEBUG
2939 	   if ( num > (MAXMEMSIZE / typesize) )
2940 	   {
2941 	      printErrorHeader(filename, line);
2942 	      printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
2943 	      return NULL;
2944 	   }
2945 	#endif
2946 	
2947 	   return BMSreallocBufferMemory_work(buffer, ptr, num * typesize, filename, line);
2948 	}
2949 	
2950 	/** allocates the next unused buffer and copies the given memory into the buffer */
2951 	void* BMSduplicateBufferMemory_call(
2952 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2953 	   const void*           source,             /**< memory block to copy into the buffer */
2954 	   size_t                size,               /**< minimal required size of the buffer */
2955 	   const char*           filename,           /**< source file of the function call */
2956 	   int                   line                /**< line number in source file of the function call */
2957 	   )
2958 	{
2959 	   void* ptr;
2960 	
2961 	   assert( source != NULL );
2962 	
2963 	   /* allocate a buffer of the given size */
2964 	   ptr = BMSallocBufferMemory_call(buffer, size, filename, line);
2965 	
2966 	   /* copy the source memory into the buffer */
2967 	   if ( ptr != NULL )
2968 	      BMScopyMemorySize(ptr, source, size);
2969 	
2970 	   return ptr;
2971 	}
2972 	
2973 	/** allocates an array in the next unused buffer and copies the given memory into the buffer */
2974 	void* BMSduplicateBufferMemoryArray_call(
2975 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
2976 	   const void*           source,             /**< memory block to copy into the buffer */
2977 	   size_t                num,                /**< size of array to be allocated */
2978 	   size_t                typesize,           /**< size of components */
2979 	   const char*           filename,           /**< source file of the function call */
2980 	   int                   line                /**< line number in source file of the function call */
2981 	   )
2982 	{
2983 	   void* ptr;
2984 	
2985 	   assert( source != NULL );
2986 	
2987 	   /* allocate a buffer of the given size */
2988 	   ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
2989 	
2990 	   /* copy the source memory into the buffer */
2991 	   if ( ptr != NULL )
2992 	      BMScopyMemorySize(ptr, source, num * typesize);
2993 	
2994 	   return ptr;
2995 	}
2996 	
2997 	/** work for freeing a buffer */
2998 	INLINE static
2999 	void BMSfreeBufferMemory_work(
3000 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
3001 	   void**                ptr,                /**< pointer to pointer to the allocated memory buffer */
3002 	   const char*           filename,           /**< source file of the function call */
3003 	   int                   line                /**< line number in source file of the function call */
3004 	   )
3005 	{  /*lint --e{715}*/
3006 	   size_t bufnum;
3007 	
3008 	   assert( buffer != NULL );
3009 	   assert( buffer->firstfree <= buffer->ndata );
3010 	   assert( buffer->firstfree >= 1 );
3011 	   assert( ptr != NULL );
3012 	   assert( *ptr != NULL );
3013 	
3014 	   /* Search the pointer in the buffer list:
3015 	    * Usually, buffers are allocated and freed like a stack, such that the freed pointer is
3016 	    * most likely at the end of the buffer list.
3017 	    */
3018 	   bufnum = buffer->firstfree-1;
3019 	   while ( bufnum > 0 && buffer->data[bufnum] != *ptr )
3020 	      --bufnum;
3021 	
3022 	#ifdef CHECKBUFFERORDER
3023 	   if ( bufnum < buffer->firstfree - 1 )
3024 	   {
3025 	      warningMessage("[%s:%d]: freeing buffer in wrong order.\n", filename, line);
3026 	   }
3027 	#endif
3028 	
3029 	#ifndef NDEBUG
3030 	   if ( bufnum == 0 && buffer->data[bufnum] != *ptr )
3031 	   {
3032 	      printErrorHeader(filename, line);
3033 	      printError("Tried to free unkown buffer pointer.\n");
3034 	      return;
3035 	   }
3036 	   if ( ! buffer->used[bufnum] )
3037 	   {
3038 	      printErrorHeader(filename, line);
3039 	      printError("Tried to free buffer pointer already freed.\n");
3040 	      return;
3041 	   }
3042 	#endif
3043 	
3044 	#ifdef CHECKCLEANBUFFER
3045 	   /* check that the memory is cleared */
3046 	   if( buffer->clean )
3047 	   {
3048 	      size_t i;
3049 	      uint8_t* tmpptr = (uint8_t*)(buffer->data[bufnum]);
3050 	
3051 	      for( i = 0; i < buffer->size[bufnum]; ++i )
3052 	         assert(tmpptr[i] == 0);
3053 	   }
3054 	#endif
3055 	
3056 	   assert( buffer->data[bufnum] == *ptr );
3057 	   buffer->used[bufnum] = FALSE;
3058 	
3059 	   while ( buffer->firstfree > 0 && !buffer->used[buffer->firstfree-1] )
3060 	      --buffer->firstfree;
3061 	
3062 	   debugMessage("Freed buffer %llu/%llu at %p of size %llu for pointer %p, first free is %llu.\n",
3063 	      (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
3064 	      (unsigned long long)(buffer->size[bufnum]), *ptr, (unsigned long long)(buffer->firstfree));
3065 	
3066 	   *ptr = NULL;
3067 	}
3068 	
3069 	/** frees a buffer and sets pointer to NULL */
3070 	void BMSfreeBufferMemory_call(
3071 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
3072 	   void**                ptr,                /**< pointer to pointer to the allocated memory buffer */
3073 	   const char*           filename,           /**< source file of the function call */
3074 	   int                   line                /**< line number in source file of the function call */
3075 	   )
3076 	{  /*lint --e{715}*/
3077 	   assert( ptr != NULL );
3078 	
3079 	#ifndef SCIP_NOBUFFERMEM
3080 	   if ( *ptr != NULL )
3081 	      BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3082 	   else
3083 	   {
3084 	      printErrorHeader(filename, line);
3085 	      printError("Tried to free null buffer pointer.\n");
3086 	   }
3087 	#else
3088 	   BMSfreeMemory(ptr);
3089 	#endif
3090 	}
3091 	
3092 	/** frees a buffer if pointer is not NULL and sets pointer to NULL */
3093 	void BMSfreeBufferMemoryNull_call(
3094 	   BMS_BUFMEM*           buffer,             /**< memory buffer storage */
3095 	   void**                ptr,                /**< pointer to pointer to the allocated memory buffer */
3096 	   const char*           filename,           /**< source file of the function call */
3097 	   int                   line                /**< line number in source file of the function call */
3098 	   )
3099 	{  /*lint --e{715}*/
3100 	   assert( ptr != NULL );
3101 	
3102 	   if ( *ptr != NULL )
3103 	   {
3104 	#ifndef SCIP_NOBUFFERMEM
3105 	      BMSfreeBufferMemory_work(buffer, ptr, filename, line);
3106 	#else
3107 	      BMSfreeMemory(ptr);
3108 	#endif
3109 	   }
3110 	}
3111 	
3112 	/** gets number of used buffers */
3113 	size_t BMSgetNUsedBufferMemory(
3114 	   BMS_BUFMEM*           buffer              /**< memory buffer storage */
3115 	   )
3116 	{
3117 	   assert( buffer != NULL );
3118 	
3119 	   return buffer->firstfree;
3120 	}
3121 	
3122 	/** returns the number of allocated bytes in the buffer memory */
3123 	long long BMSgetBufferMemoryUsed(
3124 	   const BMS_BUFMEM*     buffer              /**< buffer memory */
3125 	   )
3126 	{
3127 	#ifdef CHECKMEM
3128 	   size_t totalmem = 0UL;
3129 	   size_t i;
3130 	
3131 	   assert( buffer != NULL );
3132 	   for (i = 0; i < buffer->ndata; ++i)
3133 	      totalmem += buffer->size[i];
3134 	   assert( totalmem == buffer->totalmem );
3135 	#endif
3136 	
3137 	   return (long long) buffer->totalmem;
3138 	}
3139 	
3140 	/** outputs statistics about currently allocated buffers to the screen */
3141 	void BMSprintBufferMemory(
3142 	   BMS_BUFMEM*           buffer              /**< memory buffer storage */
3143 	   )
3144 	{
3145 	   size_t totalmem;
3146 	   size_t i;
3147 	
3148 	   assert( buffer != NULL );
3149 	
3150 	   totalmem = 0UL;
3151 	   for (i = 0; i < buffer->ndata; ++i)
3152 	   {
3153 	      printf("[%c] %8llu bytes at %p\n", buffer->used[i] ? '*' : ' ', (unsigned long long)(buffer->size[i]), buffer->data[i]);
3154 	      totalmem += buffer->size[i];
3155 	   }
3156 	   printf("    %8llu bytes total in %llu buffers\n", (unsigned long long)totalmem, (unsigned long long)(buffer->ndata));
3157 	}
3158