Scippy

    SCIP

    Solving Constraint Integer Programs

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