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-2026 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
    1711 for( i = 0; i < CHKHASH_SIZE; ++i )
    1712 {
    1713 chkmem = blkmem->chkmemhash[i];
    1714 while( chkmem != NULL )
    1715 {
    1716 checkChkmem(chkmem);
    1717 tmpmemalloc += ((chkmem->elemsize * chkmem->storesize) + chkmem->nchunks * sizeof(CHUNK) + sizeof(BMS_CHKMEM));
    1718 tmpmemused += (chkmem->elemsize * (chkmem->storesize - chkmem->eagerfreesize - chkmem->lazyfreesize));
    1719 chkmem = chkmem->nextchkmem;
    1720 }
    1721 }
    1722 assert(tmpmemalloc == blkmem->memallocated);
    1723 assert(tmpmemused == blkmem->memused);
    1724}
    1725#else
    1726#define checkBlkmem(blkmem) /**/
    1727#endif
    1728
    1729
    1730/** finds the chunk block, to whick the given pointer belongs to
    1731 *
    1732 * This could be done by selecting the chunk block of the corresponding element size, but in a case of an
    1733 * error (free gives an incorrect element size), we want to identify and output the correct element size.
    1734 */
    1735static
    1737 const BMS_BLKMEM* blkmem, /**< block memory */
    1738 const void* ptr /**< memory element to search */
    1739 )
    1740{
    1741 BMS_CHKMEM* chkmem;
    1742 int i;
    1743
    1744 assert(blkmem != NULL);
    1745
    1746 chkmem = NULL;
    1747 for( i = 0; chkmem == NULL && i < CHKHASH_SIZE; ++i )
    1748 {
    1749 chkmem = blkmem->chkmemhash[i];
    1750 while( chkmem != NULL && !isPtrInChkmem(chkmem, ptr) )
    1751 chkmem = chkmem->nextchkmem;
    1752 }
    1753
    1754 return chkmem;
    1755}
    1756
    1757/** calculates hash number of memory size */
    1758static
    1760 size_t size /**< element size */
    1761 )
    1762{
    1763 assert(BMSisAligned(size));
    1764
    1765 return ((uint32_t)size * UINT32_C(0x9e3779b9)) >> (32-CHKHASH_POWER);
    1766}
    1767
    1768/** creates a block memory allocation data structure */
    1770 int initchunksize, /**< number of elements in the first chunk of each chunk block */
    1771 int garbagefactor, /**< garbage collector is called, if at least garbagefactor * avg. chunksize
    1772 * elements are free (-1: disable garbage collection) */
    1773 const char* filename, /**< source file of the function call */
    1774 int line /**< line number in source file of the function call */
    1775 )
    1776{
    1777 BMS_BLKMEM* blkmem;
    1778 int i;
    1779
    1780 BMSallocMemory(&blkmem);
    1781 if( blkmem != NULL )
    1782 {
    1783 for( i = 0; i < CHKHASH_SIZE; ++i )
    1784 blkmem->chkmemhash[i] = NULL;
    1785 blkmem->initchunksize = initchunksize;
    1786 blkmem->garbagefactor = garbagefactor;
    1787 blkmem->memused = 0;
    1788 blkmem->memallocated = 0;
    1789 blkmem->maxmemused = 0;
    1790 blkmem->maxmemunused = 0;
    1791 blkmem->maxmemallocated = 0;
    1792 }
    1793 else
    1794 {
    1795 printErrorHeader(filename, line);
    1796 printError("Insufficient memory for block memory header.\n");
    1797 }
    1798
    1799 return blkmem;
    1800}
    1801
    1802/** frees all chunk blocks in the block memory */
    1804 BMS_BLKMEM* blkmem, /**< block memory */
    1805 const char* filename, /**< source file of the function call */
    1806 int line /**< line number in source file of the function call */
    1807 )
    1808{
    1809 BMS_CHKMEM* chkmem;
    1810 BMS_CHKMEM* nextchkmem;
    1811 int i;
    1812
    1813 if( blkmem != NULL )
    1814 {
    1815 for( i = 0; i < CHKHASH_SIZE; ++i )
    1816 {
    1817 chkmem = blkmem->chkmemhash[i];
    1818 while( chkmem != NULL )
    1819 {
    1820 nextchkmem = chkmem->nextchkmem;
    1821 destroyChkmem(&chkmem, &blkmem->memallocated);
    1822 chkmem = nextchkmem;
    1823 }
    1824 blkmem->chkmemhash[i] = NULL;
    1825 }
    1826 blkmem->memused = 0;
    1827 assert(blkmem->memallocated == 0);
    1828 }
    1829 else
    1830 {
    1831 printErrorHeader(filename, line);
    1832 printError("Tried to clear null block memory.\n");
    1833 }
    1834}
    1835
    1836/** clears and deletes block memory */
    1838 BMS_BLKMEM** blkmem, /**< pointer to block memory */
    1839 const char* filename, /**< source file of the function call */
    1840 int line /**< line number in source file of the function call */
    1841 )
    1842{
    1843 assert(blkmem != NULL);
    1844
    1845 if( *blkmem != NULL )
    1846 {
    1847 BMSclearBlockMemory_call(*blkmem, filename, line);
    1848 BMSfreeMemory(blkmem);
    1849 assert(*blkmem == NULL);
    1850 }
    1851 else
    1852 {
    1853 printErrorHeader(filename, line);
    1854 printError("Tried to destroy null block memory.\n");
    1855 }
    1856}
    1857
    1858/** work for allocating memory in the block memory pool */
    1859INLINE static
    1861 BMS_BLKMEM* blkmem, /**< block memory */
    1862 size_t size, /**< size of memory element to allocate */
    1863 const char* filename, /**< source file of the function call */
    1864 int line /**< line number in source file of the function call */
    1865 )
    1866{
    1867 BMS_CHKMEM** chkmemptr;
    1868 uint32_t hashnumber;
    1869 void* ptr;
    1870
    1871 assert( blkmem != NULL );
    1872
    1873 /* allocating very large memory blocks is currently not possible, because BMS_CHKMEM::elemsize is of type int only */
    1874 if( size > INT_MAX )
    1875 return NULL;
    1876
    1877 /* calculate hash number of given size */
    1878 alignSize(&size);
    1879 hashnumber = getHashNumber(size);
    1880 assert(hashnumber < CHKHASH_SIZE);
    1881
    1882 /* find corresponding chunk block */
    1883 chkmemptr = &(blkmem->chkmemhash[hashnumber]);
    1884 while( *chkmemptr != NULL && (*chkmemptr)->elemsize != (int)size )
    1885 chkmemptr = &((*chkmemptr)->nextchkmem);
    1886
    1887 /* create new chunk block if necessary */
    1888 if( *chkmemptr == NULL )
    1889 {
    1890 *chkmemptr = createChkmem((int)size, blkmem->initchunksize, blkmem->garbagefactor, &blkmem->memallocated);
    1891 if( *chkmemptr == NULL )
    1892 {
    1893 printErrorHeader(filename, line);
    1894 printError("Insufficient memory for chunk block.\n");
    1895 return NULL;
    1896 }
    1897#ifndef NDEBUG
    1898 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
    1899 (*chkmemptr)->line = line;
    1900#endif
    1901 }
    1902#ifndef NDEBUG
    1903 else
    1904 {
    1905 BMSfreeMemoryArrayNull(&(*chkmemptr)->filename);
    1906 BMSduplicateMemoryArray(&(*chkmemptr)->filename, filename, strlen(filename) + 1);
    1907 (*chkmemptr)->line = line;
    1908 }
    1909#endif
    1910
    1911 /* get memory inside the chunk block */
    1912 ptr = allocChkmemElement(*chkmemptr, &blkmem->memallocated);
    1913
    1914 if( ptr == NULL )
    1915 {
    1916 printErrorHeader(filename, line);
    1917 printError("Insufficient memory for new chunk.\n");
    1918 }
    1919 debugMessage("alloced %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, ptr, filename, line);
    1920
    1921 /* add the used memory */
    1922 blkmem->memused += (long long) size;
    1923 blkmem->maxmemused = MAX(blkmem->maxmemused, blkmem->memused);
    1924 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
    1925 blkmem->maxmemallocated = MAX(blkmem->maxmemallocated, blkmem->memallocated);
    1926
    1927 assert(blkmem->memused >= 0);
    1928 assert(blkmem->memallocated >= 0);
    1929
    1930 checkBlkmem(blkmem);
    1931
    1932 return ptr;
    1933}
    1934
    1935/** allocates memory in the block memory pool */
    1937 BMS_BLKMEM* blkmem, /**< block memory */
    1938 size_t size, /**< size of memory element to allocate */
    1939 const char* filename, /**< source file of the function call */
    1940 int line /**< line number in source file of the function call */
    1941 )
    1942{
    1943#ifndef NDEBUG
    1944 if ( size > MAXMEMSIZE )
    1945 {
    1946 printErrorHeader(filename, line);
    1947 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
    1948 return NULL;
    1949 }
    1950#endif
    1951
    1952 return BMSallocBlockMemory_work(blkmem, size, filename, line);
    1953}
    1954
    1955/** allocates memory in the block memory pool and clears it */
    1957 BMS_BLKMEM* blkmem, /**< block memory */
    1958 size_t size, /**< size of memory element to allocate */
    1959 const char* filename, /**< source file of the function call */
    1960 int line /**< line number in source file of the function call */
    1961 )
    1962{
    1963 void* ptr;
    1964
    1965 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
    1966 if( ptr != NULL )
    1967 BMSclearMemorySize(ptr, size);
    1968
    1969 return ptr;
    1970}
    1971
    1972/** allocates array in the block memory pool */
    1974 BMS_BLKMEM* blkmem, /**< block memory */
    1975 size_t num, /**< size of array to be allocated */
    1976 size_t typesize, /**< size of each component */
    1977 const char* filename, /**< source file of the function call */
    1978 int line /**< line number in source file of the function call */
    1979 )
    1980{
    1981#ifndef NDEBUG
    1982 if ( num > (MAXMEMSIZE / typesize) )
    1983 {
    1984 printErrorHeader(filename, line);
    1985 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
    1986 return NULL;
    1987 }
    1988#endif
    1989
    1990 return BMSallocBlockMemory_work(blkmem, num * typesize, filename, line);
    1991}
    1992
    1993/** allocates array in the block memory pool and clears it */
    1995 BMS_BLKMEM* blkmem, /**< block memory */
    1996 size_t num, /**< size of array to be allocated */
    1997 size_t typesize, /**< size of each component */
    1998 const char* filename, /**< source file of the function call */
    1999 int line /**< line number in source file of the function call */
    2000 )
    2001{
    2002 void* ptr;
    2003
    2004 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
    2005 if ( ptr != NULL )
    2006 BMSclearMemorySize(ptr, num * typesize);
    2007
    2008 return ptr;
    2009}
    2010
    2011/** resizes memory element in the block memory pool and copies the data */
    2013 BMS_BLKMEM* blkmem, /**< block memory */
    2014 void* ptr, /**< memory element to reallocated */
    2015 size_t oldsize, /**< old size of memory element */
    2016 size_t newsize, /**< new size of memory element */
    2017 const char* filename, /**< source file of the function call */
    2018 int line /**< line number in source file of the function call */
    2019 )
    2020{
    2021 void* newptr;
    2022
    2023 if( ptr == NULL )
    2024 {
    2025 assert(oldsize == 0);
    2026 return BMSallocBlockMemory_call(blkmem, newsize, filename, line);
    2027 }
    2028
    2029#ifndef NDEBUG
    2030 if ( newsize > MAXMEMSIZE )
    2031 {
    2032 printErrorHeader(filename, line);
    2033 printError("Tried to allocate block of size exceeding %lu.\n", MAXMEMSIZE);
    2034 return NULL;
    2035 }
    2036#endif
    2037
    2038 alignSize(&oldsize);
    2039 alignSize(&newsize);
    2040 if( oldsize == newsize )
    2041 return ptr;
    2042
    2043 newptr = BMSallocBlockMemory_call(blkmem, newsize, filename, line);
    2044 if( newptr != NULL )
    2045 BMScopyMemorySize(newptr, ptr, MIN(oldsize, newsize));
    2046 BMSfreeBlockMemory_call(blkmem, &ptr, oldsize, filename, line);
    2047
    2048 return newptr;
    2049}
    2050
    2051/** resizes array in the block memory pool and copies the data */
    2053 BMS_BLKMEM* blkmem, /**< block memory */
    2054 void* ptr, /**< memory element to reallocated */
    2055 size_t oldnum, /**< old size of array */
    2056 size_t newnum, /**< new size of array */
    2057 size_t typesize, /**< size of each component */
    2058 const char* filename, /**< source file of the function call */
    2059 int line /**< line number in source file of the function call */
    2060 )
    2061{
    2062 void* newptr;
    2063
    2064 if( ptr == NULL )
    2065 {
    2066 assert(oldnum == 0);
    2067 return BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
    2068 }
    2069
    2070#ifndef NDEBUG
    2071 if ( newnum > (MAXMEMSIZE / typesize) )
    2072 {
    2073 printErrorHeader(filename, line);
    2074 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
    2075 return NULL;
    2076 }
    2077#endif
    2078
    2079 if ( oldnum == newnum )
    2080 return ptr;
    2081
    2082 newptr = BMSallocBlockMemoryArray_call(blkmem, newnum, typesize, filename, line);
    2083 if ( newptr != NULL )
    2084 BMScopyMemorySize(newptr, ptr, MIN(oldnum, newnum) * typesize);
    2085 BMSfreeBlockMemory_call(blkmem, &ptr, oldnum * typesize, filename, line);
    2086
    2087 return newptr;
    2088}
    2089
    2090/** duplicates memory element in the block memory pool and copies the data */
    2092 BMS_BLKMEM* blkmem, /**< block memory */
    2093 const void* source, /**< memory element to duplicate */
    2094 size_t size, /**< size of memory elements */
    2095 const char* filename, /**< source file of the function call */
    2096 int line /**< line number in source file of the function call */
    2097 )
    2098{
    2099 void* ptr;
    2100
    2101 assert(source != NULL);
    2102
    2103 ptr = BMSallocBlockMemory_call(blkmem, size, filename, line);
    2104 if( ptr != NULL )
    2105 BMScopyMemorySize(ptr, source, size);
    2106
    2107 return ptr;
    2108}
    2109
    2110/** duplicates array in the block memory pool and copies the data */
    2112 BMS_BLKMEM* blkmem, /**< block memory */
    2113 const void* source, /**< memory element to duplicate */
    2114 size_t num, /**< size of array to be duplicated */
    2115 size_t typesize, /**< size of each component */
    2116 const char* filename, /**< source file of the function call */
    2117 int line /**< line number in source file of the function call */
    2118 )
    2119{
    2120 void* ptr;
    2121
    2122 assert(source != NULL);
    2123
    2124 ptr = BMSallocBlockMemoryArray_call(blkmem, num, typesize, filename, line);
    2125 if( ptr != NULL )
    2126 BMScopyMemorySize(ptr, source, num * typesize);
    2127
    2128 return ptr;
    2129}
    2130
    2131/** common work for freeing block memory */
    2132INLINE static
    2134 BMS_BLKMEM* blkmem, /**< block memory */
    2135 void** ptr, /**< pointer to pointer to memory element to free */
    2136 size_t size, /**< size of memory element */
    2137 const char* filename, /**< source file of the function call */
    2138 int line /**< line number in source file of the function call */
    2139 )
    2140{
    2141 BMS_CHKMEM* chkmem;
    2142 uint32_t hashnumber;
    2143
    2144 assert(ptr != NULL);
    2145 assert(*ptr != NULL);
    2146
    2147 /* calculate hash number of given size */
    2148 alignSize(&size);
    2149 hashnumber = getHashNumber(size);
    2150 assert(hashnumber < CHKHASH_SIZE);
    2151
    2152 debugMessage("free %8llu bytes in %p [%s:%d]\n", (unsigned long long)size, *ptr, filename, line);
    2153
    2154 /* find corresponding chunk block */
    2155 chkmem = blkmem->chkmemhash[hashnumber];
    2156 while( chkmem != NULL && chkmem->elemsize != (int)size )
    2157 chkmem = chkmem->nextchkmem;
    2158 if( chkmem == NULL )
    2159 {
    2160 printErrorHeader(filename, line);
    2161 printError("Tried to free pointer <%p> in block memory <%p> of unknown size %llu.\n", *ptr, (void*)blkmem, (unsigned long long)size);
    2162 return;
    2163 }
    2164 assert(chkmem->elemsize == (int)size);
    2165
    2166 /* free memory in chunk block */
    2167 freeChkmemElement(chkmem, *ptr, &blkmem->memallocated, filename, line);
    2168 blkmem->memused -= (long long) size;
    2169
    2170 blkmem->maxmemunused = MAX(blkmem->maxmemunused, blkmem->memallocated - blkmem->memused);
    2171
    2172 assert(blkmem->memused >= 0);
    2173 assert(blkmem->memallocated >= 0);
    2174
    2175 checkBlkmem(blkmem);
    2176
    2177 *ptr = NULL;
    2178}
    2179
    2180/** frees memory element in the block memory pool and sets pointer to NULL */
    2182 BMS_BLKMEM* blkmem, /**< block memory */
    2183 void** ptr, /**< pointer to pointer to memory element to free */
    2184 size_t size, /**< size of memory element */
    2185 const char* filename, /**< source file of the function call */
    2186 int line /**< line number in source file of the function call */
    2187 )
    2188{
    2189 assert( blkmem != NULL );
    2190 assert( ptr != NULL );
    2191
    2192 if( *ptr != NULL )
    2193 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
    2194 else if( size != 0 )
    2195 {
    2196 printErrorHeader(filename, line);
    2197 printError("Tried to free null block pointer.\n");
    2198 }
    2199 checkBlkmem(blkmem);
    2200}
    2201
    2202/** frees memory element in the block memory pool if pointer is not NULL and sets pointer to NULL */
    2204 BMS_BLKMEM* blkmem, /**< block memory */
    2205 void** ptr, /**< pointer to pointer to memory element to free */
    2206 size_t size, /**< size of memory element */
    2207 const char* filename, /**< source file of the function call */
    2208 int line /**< line number in source file of the function call */
    2209 )
    2210{
    2211 assert( blkmem != NULL );
    2212 assert( ptr != NULL );
    2213
    2214 if( *ptr != NULL )
    2215 {
    2216 BMSfreeBlockMemory_work(blkmem, ptr, size, filename, line);
    2217 }
    2218 checkBlkmem(blkmem);
    2219}
    2220
    2221/** calls garbage collection of block memory, frees chunks without allocated memory elements, and frees
    2222 * chunk blocks without any chunks
    2223 */
    2225 BMS_BLKMEM* blkmem /**< block memory */
    2226 )
    2227{
    2228 int i;
    2229
    2230 assert(blkmem != NULL);
    2231
    2232 for( i = 0; i < CHKHASH_SIZE; ++i )
    2233 {
    2234 BMS_CHKMEM** chkmemptr;
    2235
    2236 chkmemptr = &blkmem->chkmemhash[i];
    2237 while( *chkmemptr != NULL )
    2238 {
    2239 garbagecollectChkmem(*chkmemptr, &blkmem->memallocated);
    2240 checkBlkmem(blkmem);
    2241 if( (*chkmemptr)->nchunks == 0 )
    2242 {
    2243 BMS_CHKMEM* nextchkmem;
    2244
    2245 assert((*chkmemptr)->lazyfreesize == 0);
    2246 nextchkmem = (*chkmemptr)->nextchkmem;
    2247 destroyChkmem(chkmemptr, &blkmem->memallocated);
    2248 *chkmemptr = nextchkmem;
    2249 checkBlkmem(blkmem);
    2250 }
    2251 else
    2252 chkmemptr = &(*chkmemptr)->nextchkmem;
    2253 }
    2254 }
    2255}
    2256
    2257/** returns the number of allocated bytes in the block memory */
    2259 const BMS_BLKMEM* blkmem /**< block memory */
    2260 )
    2261{
    2262 assert( blkmem != NULL );
    2263
    2264 return blkmem->memallocated;
    2265}
    2266
    2267/** returns the number of used bytes in the block memory */
    2269 const BMS_BLKMEM* blkmem /**< block memory */
    2270 )
    2271{
    2272 assert( blkmem != NULL );
    2273
    2274 return blkmem->memused;
    2275}
    2276
    2277/** returns the number of allocated but not used bytes in the block memory */
    2279 const BMS_BLKMEM* blkmem /**< block memory */
    2280 )
    2281{
    2282 assert( blkmem != NULL );
    2283
    2284 return blkmem->memallocated - blkmem->memused;
    2285}
    2286
    2287/** returns the maximal number of used bytes in the block memory */
    2289 const BMS_BLKMEM* blkmem /**< block memory */
    2290 )
    2291{
    2292 assert( blkmem != NULL );
    2293
    2294 return blkmem->maxmemused;
    2295}
    2296
    2297/** returns the maximal number of allocated but not used bytes in the block memory */
    2299 const BMS_BLKMEM* blkmem /**< block memory */
    2300 )
    2301{
    2302 assert( blkmem != NULL );
    2303
    2304 return blkmem->maxmemunused;
    2305}
    2306
    2307/** returns the maximal number of allocated bytes in the block memory */
    2309 const BMS_BLKMEM* blkmem /**< block memory */
    2310 )
    2311{
    2312 assert( blkmem != NULL );
    2313
    2314 return blkmem->maxmemallocated;
    2315}
    2316
    2317/** returns the size of the given memory element; returns 0, if the element is not member of the block memory */
    2319 const BMS_BLKMEM* blkmem, /**< block memory */
    2320 const void* ptr /**< memory element */
    2321 )
    2322{
    2323 const BMS_CHKMEM* chkmem;
    2324
    2325 assert(blkmem != NULL);
    2326
    2327 if( ptr == NULL )
    2328 return 0;
    2329
    2330 chkmem = findChkmem(blkmem, ptr);
    2331 if( chkmem == NULL )
    2332 return 0;
    2333
    2334 return (size_t)(chkmem->elemsize); /*lint !e571*/
    2335}
    2336
    2337/** outputs allocation diagnostics of block memory */
    2339 const BMS_BLKMEM* blkmem /**< block memory */
    2340 )
    2341{
    2342 const BMS_CHKMEM* chkmem;
    2343 int nblocks = 0;
    2344 int nunusedblocks = 0;
    2345 int totalnchunks = 0;
    2346 int totalneagerchunks = 0;
    2347 int totalnelems = 0;
    2348 int totalneagerelems = 0;
    2349 int totalnlazyelems = 0;
    2350#ifndef NDEBUG
    2351 int totalngarbagecalls = 0;
    2352 int totalngarbagefrees = 0;
    2353#endif
    2354 long long allocedmem = 0;
    2355 long long freemem = 0;
    2356 int i;
    2357
    2358#ifndef NDEBUG
    2359 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr #GCl #GFr Free MBytes First Allocator\n");
    2360#else
    2361 printInfo(" ElSize #Chunk #Eag #Elems #EagFr #LazFr Free MBytes\n");
    2362#endif
    2363
    2364 assert(blkmem != NULL);
    2365
    2366 for( i = 0; i < CHKHASH_SIZE; ++i )
    2367 {
    2368 chkmem = blkmem->chkmemhash[i];
    2369 while( chkmem != NULL )
    2370 {
    2371 int nchunks = 0;
    2372 int nelems = 0;
    2373 int neagerchunks = 0;
    2374 int neagerelems = 0;
    2375
    2376 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
    2377 {
    2378 assert(chunk != NULL);
    2379 assert(chunk->elemsize == chkmem->elemsize);
    2380 assert(chunk->chkmem == chkmem);
    2381 nchunks++;
    2382 nelems += chunk->storesize;
    2383 if( chunk->eagerfree != NULL )
    2384 {
    2385 neagerchunks++;
    2386 neagerelems += chunk->eagerfreesize;
    2387 }
    2388 })
    2389
    2390 assert(nchunks == chkmem->nchunks);
    2391 assert(nelems == chkmem->storesize);
    2392 assert(neagerelems == chkmem->eagerfreesize);
    2393
    2394 if( nelems > 0 )
    2395 {
    2396 nblocks++;
    2397 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
    2398 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
    2399
    2400#ifndef NDEBUG
    2401 printInfo("%7d %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f %s:%d\n",
    2402 chkmem->elemsize, nchunks, neagerchunks, nelems,
    2403 neagerelems, chkmem->lazyfreesize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
    2404 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
    2405 (double)chkmem->elemsize * nelems / (1024.0*1024.0),
    2406 chkmem->filename, chkmem->line);
    2407#else
    2408 printInfo("%7d %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
    2409 chkmem->elemsize, nchunks, neagerchunks, nelems,
    2410 neagerelems, chkmem->lazyfreesize,
    2411 100.0 * (double) (neagerelems + chkmem->lazyfreesize) / (double) (nelems),
    2412 (double)chkmem->elemsize * nelems / (1024.0*1024.0));
    2413#endif
    2414 }
    2415 else
    2416 {
    2417#ifndef NDEBUG
    2418 printInfo("%7d <unused> %5d %4d %s:%d\n",
    2419 chkmem->elemsize, chkmem->ngarbagecalls, chkmem->ngarbagefrees,
    2420 chkmem->filename, chkmem->line);
    2421#else
    2422 printInfo("%7d <unused>\n", chkmem->elemsize);
    2423#endif
    2424 nunusedblocks++;
    2425 }
    2426 totalnchunks += nchunks;
    2427 totalneagerchunks += neagerchunks;
    2428 totalnelems += nelems;
    2429 totalneagerelems += neagerelems;
    2430 totalnlazyelems += chkmem->lazyfreesize;
    2431#ifndef NDEBUG
    2432 totalngarbagecalls += chkmem->ngarbagecalls;
    2433 totalngarbagefrees += chkmem->ngarbagefrees;
    2434#endif
    2435 chkmem = chkmem->nextchkmem;
    2436 }
    2437 }
    2438#ifndef NDEBUG
    2439 printInfo(" Total %6d %4d %7d %7d %7d %5d %4d %5.1f%% %6.1f\n",
    2440 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
    2441 totalngarbagecalls, totalngarbagefrees,
    2442 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
    2443 (double)allocedmem/(1024.0*1024.0));
    2444#else
    2445 printInfo(" Total %6d %4d %7d %7d %7d %5.1f%% %6.1f\n",
    2446 totalnchunks, totalneagerchunks, totalnelems, totalneagerelems, totalnlazyelems,
    2447 totalnelems > 0 ? 100.0 * (double) (totalneagerelems + totalnlazyelems) / (double) (totalnelems) : 0.0,
    2448 (double)allocedmem/(1024.0*1024.0));
    2449#endif
    2450 printInfo("%d blocks (%d unused), %" LONGINT_FORMAT " bytes allocated, %" LONGINT_FORMAT " bytes free", /* cppcheck-suppress syntaxError */
    2451 nblocks + nunusedblocks, nunusedblocks, allocedmem, freemem);
    2452 if( allocedmem > 0 )
    2453 printInfo(" (%.1f%%)", 100.0 * (double) freemem / (double) allocedmem);
    2454 printInfo("\n\n");
    2455
    2456 printInfo("Memory Peaks: Used Lazy Total\n");
    2457 printInfo(" %6.1f %6.1f %6.1f MBytes\n", (double)blkmem->maxmemused / (1024.0 * 1024.0),
    2458 (double)blkmem->maxmemunused / (1024.0 * 1024.0), (double)blkmem->maxmemallocated / (1024.0 * 1024.0));
    2459}
    2460
    2461/** outputs error messages, if there are allocated elements in the block memory and returns number of unfreed bytes */
    2463 const BMS_BLKMEM* blkmem /**< block memory */
    2464 )
    2465{
    2466 const BMS_CHKMEM* chkmem;
    2467 long long allocedmem = 0;
    2468 long long freemem = 0;
    2469 int i;
    2470
    2471 assert(blkmem != NULL);
    2472
    2473 for( i = 0; i < CHKHASH_SIZE; ++i )
    2474 {
    2475 chkmem = blkmem->chkmemhash[i];
    2476 while( chkmem != NULL )
    2477 {
    2478 int nchunks = 0;
    2479 int nelems = 0;
    2480 int neagerelems = 0;
    2481
    2482 FOR_EACH_NODE(CHUNK*, chunk, chkmem->rootchunk,
    2483 {
    2484 assert(chunk != NULL);
    2485 assert(chunk->elemsize == chkmem->elemsize);
    2486 assert(chunk->chkmem == chkmem);
    2487 nchunks++;
    2488 nelems += chunk->storesize;
    2489 if( chunk->eagerfree != NULL )
    2490 neagerelems += chunk->eagerfreesize;
    2491 })
    2492
    2493 assert(nchunks == chkmem->nchunks);
    2494 SCIP_UNUSED(nchunks);
    2495 assert(nelems == chkmem->storesize);
    2496 assert(neagerelems == chkmem->eagerfreesize);
    2497
    2498 if( nelems > 0 )
    2499 {
    2500 allocedmem += (long long)chkmem->elemsize * (long long)nelems;
    2501 freemem += (long long)chkmem->elemsize * ((long long)neagerelems + (long long)chkmem->lazyfreesize);
    2502
    2503 if( nelems != neagerelems + chkmem->lazyfreesize )
    2504 {
    2505#ifndef NDEBUG
    2506 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed. First Allocator: %s:%d\n",
    2507 (((long long)nelems - (long long)neagerelems) - (long long)chkmem->lazyfreesize)
    2508 * (long long)(chkmem->elemsize),
    2509 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize),
    2510 chkmem->filename, chkmem->line);
    2511#else
    2512 errorMessage("%" LONGINT_FORMAT " bytes (%d elements of size %" LONGINT_FORMAT ") not freed.\n",
    2513 ((nelems - neagerelems) - chkmem->lazyfreesize) * (long long)(chkmem->elemsize),
    2514 (nelems - neagerelems) - chkmem->lazyfreesize, (long long)(chkmem->elemsize));
    2515#endif
    2516 }
    2517 }
    2518 chkmem = chkmem->nextchkmem;
    2519 }
    2520 }
    2521
    2522 if( allocedmem != freemem )
    2523 {
    2524 errorMessage("%" LONGINT_FORMAT " bytes not freed in total.\n", allocedmem - freemem);
    2525 }
    2526
    2527 return allocedmem - freemem;
    2528}
    2529
    2530
    2531
    2532
    2533
    2534
    2535/***********************************************************
    2536 * Buffer Memory Management
    2537 *
    2538 * Efficient memory management for temporary objects
    2539 ***********************************************************/
    2540
    2541/** memory buffer storage for temporary objects */
    2543{
    2544 void** data; /**< allocated memory chunks for arbitrary data */
    2545 size_t* size; /**< sizes of buffers in bytes */
    2546 unsigned int* used; /**< 1 iff corresponding buffer is in use */
    2547 size_t totalmem; /**< total memory consumption of buffer */
    2548 unsigned int clean; /**< 1 iff the memory blocks in the buffer should be initialized to zero? */
    2549 size_t ndata; /**< number of memory chunks */
    2550 size_t firstfree; /**< first unused memory chunk */
    2551 double arraygrowfac; /**< memory growing factor for dynamically allocated arrays */
    2552 unsigned int arraygrowinit; /**< initial size of dynamically allocated arrays */
    2553};
    2554
    2555
    2556/** creates memory buffer storage */
    2558 double arraygrowfac, /**< memory growing factor for dynamically allocated arrays */
    2559 int arraygrowinit, /**< initial size of dynamically allocated arrays */
    2560 unsigned int clean, /**< should the memory blocks in the buffer be initialized to zero? */
    2561 const char* filename, /**< source file of the function call */
    2562 int line /**< line number in source file of the function call */
    2563 )
    2564{
    2565 BMS_BUFMEM* buffer;
    2566
    2567 assert( arraygrowinit > 0 );
    2568 assert( arraygrowfac > 0.0 );
    2569
    2570 BMSallocMemory(&buffer);
    2571 if ( buffer != NULL )
    2572 {
    2573 buffer->data = NULL;
    2574 buffer->size = NULL;
    2575 buffer->used = NULL;
    2576 buffer->totalmem = 0UL;
    2577 buffer->clean = clean;
    2578 buffer->ndata = 0;
    2579 buffer->firstfree = 0;
    2580 buffer->arraygrowinit = (unsigned) arraygrowinit;
    2581 buffer->arraygrowfac = arraygrowfac;
    2582 }
    2583 else
    2584 {
    2585 printErrorHeader(filename, line);
    2586 printError("Insufficient memory for buffer memory header.\n");
    2587 }
    2588
    2589 return buffer;
    2590}
    2591
    2592/** destroys buffer memory */
    2594 BMS_BUFMEM** buffer, /**< pointer to memory buffer storage */
    2595 const char* filename, /**< source file of the function call */
    2596 int line /**< line number in source file of the function call */
    2597 )
    2598{
    2599 size_t i;
    2600
    2601 if ( *buffer != NULL )
    2602 {
    2603 i = (*buffer)->ndata;
    2604 if ( i > 0 ) {
    2605 for (--i ; ; i--)
    2606 {
    2607 assert( ! (*buffer)->used[i] );
    2608 BMSfreeMemoryArrayNull(&(*buffer)->data[i]);
    2609 if ( i == 0 )
    2610 break;
    2611 }
    2612 }
    2613 BMSfreeMemoryArrayNull(&(*buffer)->data);
    2614 BMSfreeMemoryArrayNull(&(*buffer)->size);
    2615 BMSfreeMemoryArrayNull(&(*buffer)->used);
    2616 BMSfreeMemory(buffer);
    2617 }
    2618 else
    2619 {
    2620 printErrorHeader(filename, line);
    2621 printError("Tried to free null buffer memory.\n");
    2622 }
    2623}
    2624
    2625/** set arraygrowfac */
    2627 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
    2628 double arraygrowfac /**< memory growing factor for dynamically allocated arrays */
    2629 )
    2630{
    2631 assert( buffer != NULL );
    2632 assert( arraygrowfac > 0.0 );
    2633
    2634 buffer->arraygrowfac = arraygrowfac;
    2635}
    2636
    2637/** set arraygrowinit */
    2639 BMS_BUFMEM* buffer, /**< pointer to memory buffer storage */
    2640 int arraygrowinit /**< initial size of dynamically allocated arrays */
    2641 )
    2642{
    2643 assert( buffer != NULL );
    2644 assert( arraygrowinit > 0 );
    2645
    2646 buffer->arraygrowinit = (unsigned) arraygrowinit;
    2647}
    2648
    2649#ifndef SCIP_NOBUFFERMEM
    2650/** calculate memory size for dynamically allocated arrays
    2651 *
    2652 * This function is a copy of the function in set.c in order to be able to use memory.? separately.
    2653 */
    2654static
    2656 size_t initsize, /**< initial size of array */
    2657 SCIP_Real growfac, /**< growing factor of array */
    2658 size_t num /**< minimum number of entries to store */
    2659 )
    2660{
    2661 size_t size;
    2662
    2663 assert( growfac >= 1.0 );
    2664
    2665 if ( growfac == 1.0 )
    2666 size = MAX(initsize, num);
    2667 else
    2668 {
    2669 size_t oldsize;
    2670
    2671 /* calculate the size with this loop, such that the resulting numbers are always the same */
    2672 initsize = MAX(initsize, 4);
    2673 size = initsize;
    2674 oldsize = size - 1;
    2675
    2676 /* second condition checks against overflow */
    2677 while ( size < num && size > oldsize )
    2678 {
    2679 oldsize = size;
    2680 size = (size_t)(growfac * size + initsize);
    2681 }
    2682
    2683 /* if an overflow happened, set the correct value */
    2684 if ( size <= oldsize )
    2685 size = num;
    2686 }
    2687
    2688 assert( size >= initsize );
    2689 assert( size >= num );
    2690
    2691 return size;
    2692}
    2693#endif
    2694
    2695/** work for allocating the next unused buffer */
    2696INLINE static
    2698 BMS_BUFMEM* buffer, /**< memory buffer storage */
    2699 size_t size, /**< minimal required size of the buffer */
    2700 const char* filename, /**< source file of the function call */
    2701 int line /**< line number in source file of the function call */
    2702 )
    2703{
    2704 void* ptr;
    2705#ifndef SCIP_NOBUFFERMEM
    2706 size_t bufnum;
    2707#endif
    2708
    2709#ifndef SCIP_NOBUFFERMEM
    2710 assert( buffer != NULL );
    2711 assert( buffer->firstfree <= buffer->ndata );
    2712
    2713 /* allocate a minimum of 1 byte */
    2714 if ( size == 0 )
    2715 size = 1;
    2716
    2717 /* check, if we need additional buffers */
    2718 if ( buffer->firstfree == buffer->ndata )
    2719 {
    2720 size_t newsize;
    2721 size_t i;
    2722
    2723 /* create additional buffers */
    2724 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, buffer->firstfree + 1);
    2725 BMSreallocMemoryArray(&buffer->data, newsize);
    2726 if ( buffer->data == NULL )
    2727 {
    2728 printErrorHeader(filename, line);
    2729 printError("Insufficient memory for reallocating buffer data storage.\n");
    2730 return NULL;
    2731 }
    2732 BMSreallocMemoryArray(&buffer->size, newsize);
    2733 if ( buffer->size == NULL )
    2734 {
    2735 printErrorHeader(filename, line);
    2736 printError("Insufficient memory for reallocating buffer size storage.\n");
    2737 return NULL;
    2738 }
    2739 BMSreallocMemoryArray(&buffer->used, newsize);
    2740 if ( buffer->used == NULL )
    2741 {
    2742 printErrorHeader(filename, line);
    2743 printError("Insufficient memory for reallocating buffer used storage.\n");
    2744 return NULL;
    2745 }
    2746
    2747 /* init data */
    2748 for (i = buffer->ndata; i < newsize; ++i)
    2749 {
    2750 buffer->data[i] = NULL;
    2751 buffer->size[i] = 0;
    2752 buffer->used[i] = FALSE;
    2753 }
    2754 buffer->ndata = newsize;
    2755 }
    2756 assert(buffer->firstfree < buffer->ndata);
    2757
    2758 /* check, if the current buffer is large enough */
    2759 bufnum = buffer->firstfree;
    2760 assert( ! buffer->used[bufnum] );
    2761 if ( buffer->size[bufnum] < size )
    2762 {
    2763 size_t newsize;
    2764
    2765 /* enlarge buffer */
    2766 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
    2767 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
    2768
    2769 /* clear new memory */
    2770 if( buffer->clean )
    2771 {
    2772 char* tmpptr = (char*)(buffer->data[bufnum]);
    2773 size_t inc = buffer->size[bufnum] / sizeof(*tmpptr);
    2774 tmpptr += inc;
    2775
    2776 BMSclearMemorySize(tmpptr, newsize - buffer->size[bufnum]);
    2777 }
    2778 assert( newsize > buffer->size[bufnum] );
    2779 buffer->totalmem += newsize - buffer->size[bufnum];
    2780 buffer->size[bufnum] = newsize;
    2781
    2782 if ( buffer->data[bufnum] == NULL )
    2783 {
    2784 printErrorHeader(filename, line);
    2785 printError("Insufficient memory for reallocating buffer storage.\n");
    2786 return NULL;
    2787 }
    2788 }
    2789 assert( buffer->size[bufnum] >= size );
    2790
    2791#ifdef CHECKCLEANBUFFER
    2792 /* check that the memory is cleared */
    2793 if( buffer->clean )
    2794 checkCleanmem(buffer->data[bufnum], buffer->size[bufnum]);
    2795#endif
    2796
    2797 ptr = buffer->data[bufnum];
    2798 buffer->used[bufnum] = TRUE;
    2799 buffer->firstfree++;
    2800
    2801 debugMessage("Allocated buffer %llu/%llu at %p of size %llu (required size: %llu) for pointer %p.\n",
    2802 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
    2803 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, ptr);
    2804
    2805#else
    2806 if( buffer->clean )
    2807 {
    2808 /* we should allocate at least one byte, otherwise BMSallocMemorySize will fail */
    2809 size = MAX(size,1);
    2810
    2811 BMSallocClearMemorySize(&ptr, size);
    2812 }
    2813 else
    2814 {
    2815 BMSallocMemorySize(&ptr, size);
    2816 }
    2817#endif
    2818
    2819 return ptr;
    2820}
    2821
    2822/** allocates the next unused buffer */
    2824 BMS_BUFMEM* buffer, /**< memory buffer storage */
    2825 size_t size, /**< minimal required size of the buffer */
    2826 const char* filename, /**< source file of the function call */
    2827 int line /**< line number in source file of the function call */
    2828 )
    2829{
    2830#ifndef NDEBUG
    2831 if ( size > MAXMEMSIZE )
    2832 {
    2833 printErrorHeader(filename, line);
    2834 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
    2835 return NULL;
    2836 }
    2837#endif
    2838
    2839 return BMSallocBufferMemory_work(buffer, size, filename, line);
    2840}
    2841
    2842/** allocates the next unused buffer array */
    2844 BMS_BUFMEM* buffer, /**< memory buffer storage */
    2845 size_t num, /**< size of array to be allocated */
    2846 size_t typesize, /**< size of components */
    2847 const char* filename, /**< source file of the function call */
    2848 int line /**< line number in source file of the function call */
    2849 )
    2850{
    2851#ifndef NDEBUG
    2852 if ( num > (MAXMEMSIZE / typesize) )
    2853 {
    2854 printErrorHeader(filename, line);
    2855 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
    2856 return NULL;
    2857 }
    2858#endif
    2859
    2860 return BMSallocBufferMemory_work(buffer, num * typesize, filename, line);
    2861}
    2862
    2863/** allocates the next unused buffer and clears it */
    2865 BMS_BUFMEM* buffer, /**< memory buffer storage */
    2866 size_t num, /**< size of array to be allocated */
    2867 size_t typesize, /**< size of components */
    2868 const char* filename, /**< source file of the function call */
    2869 int line /**< line number in source file of the function call */
    2870 )
    2871{
    2872 void* ptr;
    2873
    2874 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
    2875 if ( ptr != NULL )
    2876 BMSclearMemorySize(ptr, num * typesize);
    2877
    2878 return ptr;
    2879}
    2880
    2881/** work for reallocating the buffer to at least the given size */
    2882INLINE static
    2884 BMS_BUFMEM* buffer, /**< memory buffer storage */
    2885 void* ptr, /**< pointer to the allocated memory buffer */
    2886 size_t size, /**< minimal required size of the buffer */
    2887 const char* filename, /**< source file of the function call */
    2888 int line /**< line number in source file of the function call */
    2889 )
    2890{
    2891 void* newptr;
    2892#ifndef SCIP_NOBUFFERMEM
    2893 size_t bufnum;
    2894#endif
    2895
    2896#ifndef SCIP_NOBUFFERMEM
    2897 assert( buffer != NULL );
    2898 assert( buffer->firstfree <= buffer->ndata );
    2899 assert(!buffer->clean); /* reallocating clean buffer elements is not supported */
    2900
    2901 /* if the pointer doesn't exist yet, allocate it */
    2902 if ( ptr == NULL )
    2903 return BMSallocBufferMemory_call(buffer, size, filename, line);
    2904
    2905 assert( buffer->firstfree >= 1 );
    2906
    2907 /* Search the pointer in the buffer list:
    2908 * Usually, buffers are allocated and freed like a stack, such that the currently used pointer is
    2909 * most likely at the end of the buffer list.
    2910 */
    2911 bufnum = buffer->firstfree - 1;
    2912 while ( bufnum > 0 && buffer->data[bufnum] != ptr )
    2913 --bufnum;
    2914
    2915 newptr = ptr;
    2916 assert( buffer->data[bufnum] == newptr );
    2917 assert( buffer->used[bufnum] );
    2918 assert( buffer->size[bufnum] >= 1 );
    2919
    2920 /* check if the buffer has to be enlarged */
    2921 if ( size > buffer->size[bufnum] )
    2922 {
    2923 size_t newsize;
    2924
    2925 /* enlarge buffer */
    2926 newsize = calcMemoryGrowSize((size_t)buffer->arraygrowinit, buffer->arraygrowfac, size);
    2927 BMSreallocMemorySize(&buffer->data[bufnum], newsize);
    2928 assert( newsize > buffer->size[bufnum] );
    2929 buffer->totalmem += newsize - buffer->size[bufnum];
    2930 buffer->size[bufnum] = newsize;
    2931 if ( buffer->data[bufnum] == NULL )
    2932 {
    2933 printErrorHeader(filename, line);
    2934 printError("Insufficient memory for reallocating buffer storage.\n");
    2935 return NULL;
    2936 }
    2937 newptr = buffer->data[bufnum];
    2938 }
    2939 assert( buffer->size[bufnum] >= size );
    2940 assert( newptr == buffer->data[bufnum] );
    2941
    2942 debugMessage("Reallocated buffer %llu/%llu at %p to size %llu (required size: %llu) for pointer %p.\n",
    2943 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
    2944 (unsigned long long)(buffer->size[bufnum]), (unsigned long long)size, newptr);
    2945
    2946#else
    2947 newptr = ptr;
    2948 BMSreallocMemorySize(&newptr, size);
    2949#endif
    2950
    2951 return newptr;
    2952}
    2953
    2954/** reallocates the buffer to at least the given size */
    2956 BMS_BUFMEM* buffer, /**< memory buffer storage */
    2957 void* ptr, /**< pointer to the allocated memory buffer */
    2958 size_t size, /**< minimal required size of the buffer */
    2959 const char* filename, /**< source file of the function call */
    2960 int line /**< line number in source file of the function call */
    2961 )
    2962{
    2963#ifndef NDEBUG
    2964 if ( size > MAXMEMSIZE )
    2965 {
    2966 printErrorHeader(filename, line);
    2967 printError("Tried to allocate buffer of size exceeding %lu.\n", MAXMEMSIZE);
    2968 return NULL;
    2969 }
    2970#endif
    2971
    2972 return BMSreallocBufferMemory_work(buffer, ptr, size, filename, line);
    2973}
    2974
    2975/** reallocates an array in the buffer to at least the given size */
    2977 BMS_BUFMEM* buffer, /**< memory buffer storage */
    2978 void* ptr, /**< pointer to the allocated memory buffer */
    2979 size_t num, /**< size of array to be allocated */
    2980 size_t typesize, /**< size of components */
    2981 const char* filename, /**< source file of the function call */
    2982 int line /**< line number in source file of the function call */
    2983 )
    2984{
    2985#ifndef NDEBUG
    2986 if ( num > (MAXMEMSIZE / typesize) )
    2987 {
    2988 printErrorHeader(filename, line);
    2989 printError("Tried to allocate array of size exceeding %lu.\n", MAXMEMSIZE);
    2990 return NULL;
    2991 }
    2992#endif
    2993
    2994 return BMSreallocBufferMemory_work(buffer, ptr, num * typesize, filename, line);
    2995}
    2996
    2997/** allocates the next unused buffer and copies the given memory into the buffer */
    2999 BMS_BUFMEM* buffer, /**< memory buffer storage */
    3000 const void* source, /**< memory block to copy into the buffer */
    3001 size_t size, /**< minimal required size of the buffer */
    3002 const char* filename, /**< source file of the function call */
    3003 int line /**< line number in source file of the function call */
    3004 )
    3005{
    3006 void* ptr;
    3007
    3008 assert( source != NULL );
    3009
    3010 /* allocate a buffer of the given size */
    3011 ptr = BMSallocBufferMemory_call(buffer, size, filename, line);
    3012
    3013 /* copy the source memory into the buffer */
    3014 if ( ptr != NULL )
    3015 BMScopyMemorySize(ptr, source, size);
    3016
    3017 return ptr;
    3018}
    3019
    3020/** allocates an array in the next unused buffer and copies the given memory into the buffer */
    3022 BMS_BUFMEM* buffer, /**< memory buffer storage */
    3023 const void* source, /**< memory block to copy into the buffer */
    3024 size_t num, /**< size of array to be allocated */
    3025 size_t typesize, /**< size of components */
    3026 const char* filename, /**< source file of the function call */
    3027 int line /**< line number in source file of the function call */
    3028 )
    3029{
    3030 void* ptr;
    3031
    3032 assert( source != NULL );
    3033
    3034 /* allocate a buffer of the given size */
    3035 ptr = BMSallocBufferMemoryArray_call(buffer, num, typesize, filename, line);
    3036
    3037 /* copy the source memory into the buffer */
    3038 if ( ptr != NULL )
    3039 BMScopyMemorySize(ptr, source, num * typesize);
    3040
    3041 return ptr;
    3042}
    3043
    3044/** work for freeing a buffer */
    3045INLINE static
    3047 BMS_BUFMEM* buffer, /**< memory buffer storage */
    3048 void** ptr, /**< pointer to pointer to the allocated memory buffer */
    3049 const char* filename, /**< source file of the function call */
    3050 int line /**< line number in source file of the function call */
    3051 )
    3052{ /*lint --e{715}*/
    3053 size_t bufnum;
    3054
    3055 assert( buffer != NULL );
    3056 assert( buffer->firstfree <= buffer->ndata );
    3057 assert( buffer->firstfree >= 1 );
    3058 assert( ptr != NULL );
    3059 assert( *ptr != NULL );
    3060
    3061 /* Search the pointer in the buffer list:
    3062 * Usually, buffers are allocated and freed like a stack, such that the freed pointer is
    3063 * most likely at the end of the buffer list.
    3064 */
    3065 bufnum = buffer->firstfree-1;
    3066 while ( bufnum > 0 && buffer->data[bufnum] != *ptr )
    3067 --bufnum;
    3068
    3069#ifdef CHECKBUFFERORDER
    3070 if ( bufnum < buffer->firstfree - 1 )
    3071 {
    3072 warningMessage("[%s:%d]: freeing buffer in wrong order.\n", filename, line);
    3073 }
    3074#endif
    3075
    3076#ifndef NDEBUG
    3077 if ( bufnum == 0 && buffer->data[bufnum] != *ptr )
    3078 {
    3079 printErrorHeader(filename, line);
    3080 printError("Tried to free unknown buffer pointer.\n");
    3081 return;
    3082 }
    3083 if ( ! buffer->used[bufnum] )
    3084 {
    3085 printErrorHeader(filename, line);
    3086 printError("Tried to free buffer pointer already freed.\n");
    3087 return;
    3088 }
    3089#endif
    3090
    3091#ifdef CHECKCLEANBUFFER
    3092 /* check that the memory is cleared */
    3093 if( buffer->clean )
    3094 checkCleanmem(buffer->data[bufnum], buffer->size[bufnum]);
    3095#endif
    3096
    3097 assert( buffer->data[bufnum] == *ptr );
    3098 buffer->used[bufnum] = FALSE;
    3099
    3100 while ( buffer->firstfree > 0 && !buffer->used[buffer->firstfree-1] )
    3101 --buffer->firstfree;
    3102
    3103 debugMessage("Freed buffer %llu/%llu at %p of size %llu for pointer %p, first free is %llu.\n",
    3104 (unsigned long long)bufnum, (unsigned long long)(buffer->ndata), buffer->data[bufnum],
    3105 (unsigned long long)(buffer->size[bufnum]), *ptr, (unsigned long long)(buffer->firstfree));
    3106
    3107 *ptr = NULL;
    3108}
    3109
    3110/** frees a buffer and sets pointer to NULL */
    3112 BMS_BUFMEM* buffer, /**< memory buffer storage */
    3113 void** ptr, /**< pointer to pointer to the allocated memory buffer */
    3114 const char* filename, /**< source file of the function call */
    3115 int line /**< line number in source file of the function call */
    3116 )
    3117{ /*lint --e{715}*/
    3118 assert( ptr != NULL );
    3119
    3120#ifndef SCIP_NOBUFFERMEM
    3121 if ( *ptr != NULL )
    3122 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
    3123 else
    3124 {
    3125 printErrorHeader(filename, line);
    3126 printError("Tried to free null buffer pointer.\n");
    3127 }
    3128#else
    3129 BMSfreeMemory(ptr);
    3130#endif
    3131}
    3132
    3133/** frees a buffer if pointer is not NULL and sets pointer to NULL */
    3135 BMS_BUFMEM* buffer, /**< memory buffer storage */
    3136 void** ptr, /**< pointer to pointer to the allocated memory buffer */
    3137 const char* filename, /**< source file of the function call */
    3138 int line /**< line number in source file of the function call */
    3139 )
    3140{ /*lint --e{715}*/
    3141 assert( ptr != NULL );
    3142
    3143 if ( *ptr != NULL )
    3144 {
    3145#ifndef SCIP_NOBUFFERMEM
    3146 BMSfreeBufferMemory_work(buffer, ptr, filename, line);
    3147#else
    3148 BMSfreeMemory(ptr);
    3149#endif
    3150 }
    3151}
    3152
    3153/** gets number of used buffers */
    3155 BMS_BUFMEM* buffer /**< memory buffer storage */
    3156 )
    3157{
    3158 assert( buffer != NULL );
    3159
    3160 return buffer->firstfree;
    3161}
    3162
    3163/** returns the number of allocated bytes in the buffer memory */
    3165 const BMS_BUFMEM* buffer /**< buffer memory */
    3166 )
    3167{
    3168#ifdef CHECKMEM
    3169 size_t totalmem = 0UL;
    3170 size_t i;
    3171
    3172 assert( buffer != NULL );
    3173 for (i = 0; i < buffer->ndata; ++i)
    3174 totalmem += buffer->size[i];
    3175 assert( totalmem == buffer->totalmem );
    3176#endif
    3177
    3178 return (long long) buffer->totalmem;
    3179}
    3180
    3181/** outputs statistics about currently allocated buffers to the screen */
    3183 BMS_BUFMEM* buffer /**< memory buffer storage */
    3184 )
    3185{
    3186 size_t totalmem;
    3187 size_t i;
    3188
    3189 assert( buffer != NULL );
    3190
    3191 totalmem = 0UL;
    3192 for (i = 0; i < buffer->ndata; ++i)
    3193 {
    3194 printf("[%c] %8llu bytes at %p\n", buffer->used[i] ? '*' : ' ', (unsigned long long)(buffer->size[i]), buffer->data[i]);
    3195 totalmem += buffer->size[i];
    3196 }
    3197 printf(" %8llu bytes total in %llu buffers\n", (unsigned long long)totalmem, (unsigned long long)(buffer->ndata));
    3198}
    common defines and data types used in all packages of SCIP
    #define NULL
    Definition: def.h:255
    #define INLINE
    Definition: def.h:127
    #define SCIP_UNUSED(x)
    Definition: def.h:416
    #define SCIP_Bool
    Definition: def.h:98
    #define MIN(x, y)
    Definition: def.h:231
    #define SCIP_Real
    Definition: def.h:163
    #define TRUE
    Definition: def.h:100
    #define FALSE
    Definition: def.h:101
    #define MAX(x, y)
    Definition: def.h:227
    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:2998
    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:2203
    #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:2318
    #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:2133
    int BMSisAligned(size_t size)
    Definition: memory.c:777
    void BMSclearBlockMemory_call(BMS_BLKMEM *blkmem, const char *filename, int line)
    Definition: memory.c:1803
    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:2462
    long long BMSgetBufferMemoryUsed(const BMS_BUFMEM *buffer)
    Definition: memory.c:3164
    #define ALIGNMENT
    Definition: memory.c:697
    void BMSfreeBufferMemory_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
    Definition: memory.c:3111
    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:2012
    void BMSfreeMemoryNull_call(void **ptr, const char *filename, int line)
    Definition: memory.c:642
    void BMSsetBufferMemoryArraygrowinit(BMS_BUFMEM *buffer, int arraygrowinit)
    Definition: memory.c:2638
    static void unlinkChunk(CHUNK *chunk)
    Definition: memory.c:996
    static uint32_t getHashNumber(size_t size)
    Definition: memory.c:1759
    void BMSdestroyBufferMemory_call(BMS_BUFMEM **buffer, const char *filename, int line)
    Definition: memory.c:2593
    #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:2955
    static INLINE void BMSfreeBufferMemory_work(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
    Definition: memory.c:3046
    static size_t calcMemoryGrowSize(size_t initsize, SCIP_Real growfac, size_t num)
    Definition: memory.c:2655
    #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:2288
    static BMS_CHKMEM * findChkmem(const BMS_BLKMEM *blkmem, const void *ptr)
    Definition: memory.c:1736
    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:2843
    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:1973
    #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:1860
    void * BMSreallocBufferMemoryArray_call(BMS_BUFMEM *buffer, void *ptr, size_t num, size_t typesize, const char *filename, int line)
    Definition: memory.c:2976
    #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:2338
    long long BMSgetBlockMemoryAllocated_call(const BMS_BLKMEM *blkmem)
    Definition: memory.c:2258
    void BMSclearMemory_call(void *ptr, size_t size)
    Definition: memory.c:536
    long long BMSgetBlockMemoryUsed_call(const BMS_BLKMEM *blkmem)
    Definition: memory.c:2268
    void BMSfreeBufferMemoryNull_call(BMS_BUFMEM *buffer, void **ptr, const char *filename, int line)
    Definition: memory.c:3134
    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:1769
    void * BMSallocClearBlockMemoryArray_call(BMS_BLKMEM *blkmem, size_t num, size_t typesize, const char *filename, int line)
    Definition: memory.c:1994
    void * BMSduplicateBlockMemoryArray_call(BMS_BLKMEM *blkmem, const void *source, size_t num, size_t typesize, const char *filename, int line)
    Definition: memory.c:2111
    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:2557
    static INLINE void * BMSreallocBufferMemory_work(BMS_BUFMEM *buffer, void *ptr, size_t size, const char *filename, int line)
    Definition: memory.c:2883
    static void unlinkEagerChunk(CHUNK *chunk)
    Definition: memory.c:1044
    void BMSdestroyBlockMemory_call(BMS_BLKMEM **blkmem, const char *filename, int line)
    Definition: memory.c:1837
    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:2278
    void BMSprintBufferMemory(BMS_BUFMEM *buffer)
    Definition: memory.c:3182
    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:1726
    void * BMSallocClearBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
    Definition: memory.c:1956
    void * BMSallocBufferMemory_call(BMS_BUFMEM *buffer, size_t size, const char *filename, int line)
    Definition: memory.c:2823
    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:2697
    void * BMSallocBlockMemory_call(BMS_BLKMEM *blkmem, size_t size, const char *filename, int line)
    Definition: memory.c:1936
    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:2626
    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:3021
    void BMSdestroyChunkMemory_call(BMS_CHKMEM **chkmem, const char *filename, int line)
    Definition: memory.c:1540
    void BMSgarbagecollectBlockMemory_call(BMS_BLKMEM *blkmem)
    Definition: memory.c:2224
    void BMSfreeBlockMemory_call(BMS_BLKMEM *blkmem, void **ptr, size_t size, const char *filename, int line)
    Definition: memory.c:2181
    void * BMSallocClearBufferMemoryArray_call(BMS_BUFMEM *buffer, size_t num, size_t typesize, const char *filename, int line)
    Definition: memory.c:2864
    #define GARBAGE_SIZE
    Definition: memory.c:696
    long long BMSgetBlockMemoryUnusedMax_call(const BMS_BLKMEM *blkmem)
    Definition: memory.c:2298
    void * BMSduplicateBlockMemory_call(BMS_BLKMEM *blkmem, const void *source, size_t size, const char *filename, int line)
    Definition: memory.c:2091
    #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:2052
    size_t BMSgetNUsedBufferMemory(BMS_BUFMEM *buffer)
    Definition: memory.c:3154
    long long BMSgetBlockMemoryAllocatedMax_call(const BMS_BLKMEM *blkmem)
    Definition: memory.c:2308
    #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:2545
    unsigned int * used
    Definition: memory.c:2546
    void ** data
    Definition: memory.c:2544
    size_t firstfree
    Definition: memory.c:2550
    double arraygrowfac
    Definition: memory.c:2551
    unsigned int arraygrowinit
    Definition: memory.c:2552
    unsigned int clean
    Definition: memory.c:2548
    size_t totalmem
    Definition: memory.c:2547
    size_t ndata
    Definition: memory.c:2549