You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1557 lines
40 KiB
1557 lines
40 KiB
/**CFile***********************************************************************
|
|
|
|
FileName [cuddLCache.c]
|
|
|
|
PackageName [cudd]
|
|
|
|
Synopsis [Functions for local caches.]
|
|
|
|
Description [Internal procedures included in this module:
|
|
<ul>
|
|
<li> cuddLocalCacheInit()
|
|
<li> cuddLocalCacheQuit()
|
|
<li> cuddLocalCacheInsert()
|
|
<li> cuddLocalCacheLookup()
|
|
<li> cuddLocalCacheClearDead()
|
|
<li> cuddLocalCacheClearAll()
|
|
<li> cuddLocalCacheProfile()
|
|
<li> cuddHashTableInit()
|
|
<li> cuddHashTableQuit()
|
|
<li> cuddHashTableGenericQuit()
|
|
<li> cuddHashTableInsert()
|
|
<li> cuddHashTableLookup()
|
|
<li> cuddHashTableGenericInsert()
|
|
<li> cuddHashTableGenericLookup()
|
|
<li> cuddHashTableInsert2()
|
|
<li> cuddHashTableLookup2()
|
|
<li> cuddHashTableInsert3()
|
|
<li> cuddHashTableLookup3()
|
|
</ul>
|
|
Static procedures included in this module:
|
|
<ul>
|
|
<li> cuddLocalCacheResize()
|
|
<li> ddLCHash()
|
|
<li> cuddLocalCacheAddToList()
|
|
<li> cuddLocalCacheRemoveFromList()
|
|
<li> cuddHashTableResize()
|
|
<li> cuddHashTableAlloc()
|
|
</ul> ]
|
|
|
|
SeeAlso []
|
|
|
|
Author [Fabio Somenzi]
|
|
|
|
Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.]
|
|
|
|
******************************************************************************/
|
|
|
|
#include "util.h"
|
|
#include "cuddInt.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Constant declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#define DD_MAX_HASHTABLE_DENSITY 2 /* tells when to resize a table */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] DD_UNUSED = "$Id: cuddLCache.c,v 1.27 2012/02/05 01:07:19 fabio Exp $";
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**Macro***********************************************************************
|
|
|
|
Synopsis [Computes hash function for keys of one operand.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [ddLCHash3 ddLCHash]
|
|
|
|
******************************************************************************/
|
|
#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
|
|
#define ddLCHash1(f,shift) \
|
|
(((unsigned)(ptruint)(f) * DD_P1) >> (shift))
|
|
#else
|
|
#define ddLCHash1(f,shift) \
|
|
(((unsigned)(f) * DD_P1) >> (shift))
|
|
#endif
|
|
|
|
|
|
/**Macro***********************************************************************
|
|
|
|
Synopsis [Computes hash function for keys of two operands.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [ddLCHash3 ddLCHash]
|
|
|
|
******************************************************************************/
|
|
#if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
|
|
#define ddLCHash2(f,g,shift) \
|
|
((((unsigned)(ptruint)(f) * DD_P1 + \
|
|
(unsigned)(ptruint)(g)) * DD_P2) >> (shift))
|
|
#else
|
|
#define ddLCHash2(f,g,shift) \
|
|
((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (shift))
|
|
#endif
|
|
|
|
|
|
/**Macro***********************************************************************
|
|
|
|
Synopsis [Computes hash function for keys of three operands.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [ddLCHash2 ddLCHash]
|
|
|
|
******************************************************************************/
|
|
#define ddLCHash3(f,g,h,shift) ddCHash2(f,g,h,shift)
|
|
|
|
|
|
/**AutomaticStart*************************************************************/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void cuddLocalCacheResize (DdLocalCache *cache);
|
|
DD_INLINE static unsigned int ddLCHash (DdNodePtr *key, unsigned int keysize, int shift);
|
|
static void cuddLocalCacheAddToList (DdLocalCache *cache);
|
|
static void cuddLocalCacheRemoveFromList (DdLocalCache *cache);
|
|
static int cuddHashTableResize (DdHashTable *hash);
|
|
DD_INLINE static DdHashItem * cuddHashTableAlloc (DdHashTable *hash);
|
|
|
|
/**AutomaticEnd***************************************************************/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Initializes a local computed table.]
|
|
|
|
Description [Initializes a computed table. Returns a pointer the
|
|
the new local cache in case of success; NULL otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddInitCache]
|
|
|
|
******************************************************************************/
|
|
DdLocalCache *
|
|
cuddLocalCacheInit(
|
|
DdManager * manager /* manager */,
|
|
unsigned int keySize /* size of the key (number of operands) */,
|
|
unsigned int cacheSize /* Initial size of the cache */,
|
|
unsigned int maxCacheSize /* Size of the cache beyond which no resizing occurs */)
|
|
{
|
|
DdLocalCache *cache;
|
|
int logSize;
|
|
|
|
cache = ALLOC(DdLocalCache,1);
|
|
if (cache == NULL) {
|
|
manager->errorCode = CUDD_MEMORY_OUT;
|
|
return(NULL);
|
|
}
|
|
cache->manager = manager;
|
|
cache->keysize = keySize;
|
|
cache->itemsize = (keySize + 1) * sizeof(DdNode *);
|
|
#ifdef DD_CACHE_PROFILE
|
|
cache->itemsize += sizeof(ptrint);
|
|
#endif
|
|
logSize = cuddComputeFloorLog2(ddMax(cacheSize,manager->slots/2));
|
|
cacheSize = 1 << logSize;
|
|
cache->item = (DdLocalCacheItem *)
|
|
ALLOC(char, cacheSize * cache->itemsize);
|
|
if (cache->item == NULL) {
|
|
manager->errorCode = CUDD_MEMORY_OUT;
|
|
FREE(cache);
|
|
return(NULL);
|
|
}
|
|
cache->slots = cacheSize;
|
|
cache->shift = sizeof(int) * 8 - logSize;
|
|
cache->maxslots = ddMin(maxCacheSize,manager->slots);
|
|
cache->minHit = manager->minHit;
|
|
/* Initialize to avoid division by 0 and immediate resizing. */
|
|
cache->lookUps = (double) (int) (cacheSize * cache->minHit + 1);
|
|
cache->hits = 0;
|
|
manager->memused += cacheSize * cache->itemsize + sizeof(DdLocalCache);
|
|
|
|
/* Initialize the cache. */
|
|
memset(cache->item, 0, cacheSize * cache->itemsize);
|
|
|
|
/* Add to manager's list of local caches for GC. */
|
|
cuddLocalCacheAddToList(cache);
|
|
|
|
return(cache);
|
|
|
|
} /* end of cuddLocalCacheInit */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Shuts down a local computed table.]
|
|
|
|
Description [Initializes the computed table. It is called by
|
|
Cudd_Init. Returns a pointer the the new local cache in case of
|
|
success; NULL otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddLocalCacheInit]
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddLocalCacheQuit(
|
|
DdLocalCache * cache /* cache to be shut down */)
|
|
{
|
|
cache->manager->memused -=
|
|
cache->slots * cache->itemsize + sizeof(DdLocalCache);
|
|
cuddLocalCacheRemoveFromList(cache);
|
|
FREE(cache->item);
|
|
FREE(cache);
|
|
|
|
return;
|
|
|
|
} /* end of cuddLocalCacheQuit */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts a result in a local cache.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddLocalCacheInsert(
|
|
DdLocalCache * cache,
|
|
DdNodePtr * key,
|
|
DdNode * value)
|
|
{
|
|
unsigned int posn;
|
|
DdLocalCacheItem *entry;
|
|
|
|
posn = ddLCHash(key,cache->keysize,cache->shift);
|
|
entry = (DdLocalCacheItem *) ((char *) cache->item +
|
|
posn * cache->itemsize);
|
|
memcpy(entry->key,key,cache->keysize * sizeof(DdNode *));
|
|
entry->value = value;
|
|
#ifdef DD_CACHE_PROFILE
|
|
entry->count++;
|
|
#endif
|
|
|
|
} /* end of cuddLocalCacheInsert */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Looks up in a local cache.]
|
|
|
|
Description [Looks up in a local cache. Returns the result if found;
|
|
it returns NULL if no result is found.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode *
|
|
cuddLocalCacheLookup(
|
|
DdLocalCache * cache,
|
|
DdNodePtr * key)
|
|
{
|
|
unsigned int posn;
|
|
DdLocalCacheItem *entry;
|
|
DdNode *value;
|
|
|
|
cache->lookUps++;
|
|
posn = ddLCHash(key,cache->keysize,cache->shift);
|
|
entry = (DdLocalCacheItem *) ((char *) cache->item +
|
|
posn * cache->itemsize);
|
|
if (entry->value != NULL &&
|
|
memcmp(key,entry->key,cache->keysize*sizeof(DdNode *)) == 0) {
|
|
cache->hits++;
|
|
value = Cudd_Regular(entry->value);
|
|
if (value->ref == 0) {
|
|
cuddReclaim(cache->manager,value);
|
|
}
|
|
return(entry->value);
|
|
}
|
|
|
|
/* Cache miss: decide whether to resize */
|
|
|
|
if (cache->slots < cache->maxslots &&
|
|
cache->hits > cache->lookUps * cache->minHit) {
|
|
cuddLocalCacheResize(cache);
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
} /* end of cuddLocalCacheLookup */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Clears the dead entries of the local caches of a manager.]
|
|
|
|
Description [Clears the dead entries of the local caches of a manager.
|
|
Used during garbage collection.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddLocalCacheClearDead(
|
|
DdManager * manager)
|
|
{
|
|
DdLocalCache *cache = manager->localCaches;
|
|
unsigned int keysize;
|
|
unsigned int itemsize;
|
|
unsigned int slots;
|
|
DdLocalCacheItem *item;
|
|
DdNodePtr *key;
|
|
unsigned int i, j;
|
|
|
|
while (cache != NULL) {
|
|
keysize = cache->keysize;
|
|
itemsize = cache->itemsize;
|
|
slots = cache->slots;
|
|
item = cache->item;
|
|
for (i = 0; i < slots; i++) {
|
|
if (item->value != NULL) {
|
|
if (Cudd_Regular(item->value)->ref == 0) {
|
|
item->value = NULL;
|
|
} else {
|
|
key = item->key;
|
|
for (j = 0; j < keysize; j++) {
|
|
if (Cudd_Regular(key[j])->ref == 0) {
|
|
item->value = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
item = (DdLocalCacheItem *) ((char *) item + itemsize);
|
|
}
|
|
cache = cache->next;
|
|
}
|
|
return;
|
|
|
|
} /* end of cuddLocalCacheClearDead */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Clears the local caches of a manager.]
|
|
|
|
Description [Clears the local caches of a manager.
|
|
Used before reordering.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddLocalCacheClearAll(
|
|
DdManager * manager)
|
|
{
|
|
DdLocalCache *cache = manager->localCaches;
|
|
|
|
while (cache != NULL) {
|
|
memset(cache->item, 0, cache->slots * cache->itemsize);
|
|
cache = cache->next;
|
|
}
|
|
return;
|
|
|
|
} /* end of cuddLocalCacheClearAll */
|
|
|
|
|
|
#ifdef DD_CACHE_PROFILE
|
|
|
|
#define DD_HYSTO_BINS 8
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Computes and prints a profile of a local cache usage.]
|
|
|
|
Description [Computes and prints a profile of a local cache usage.
|
|
Returns 1 if successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
int
|
|
cuddLocalCacheProfile(
|
|
DdLocalCache * cache)
|
|
{
|
|
double count, mean, meansq, stddev, expected;
|
|
long max, min;
|
|
int imax, imin;
|
|
int i, retval, slots;
|
|
long *hystogram;
|
|
int nbins = DD_HYSTO_BINS;
|
|
int bin;
|
|
long thiscount;
|
|
double totalcount;
|
|
int nzeroes;
|
|
DdLocalCacheItem *entry;
|
|
FILE *fp = cache->manager->out;
|
|
|
|
slots = cache->slots;
|
|
|
|
meansq = mean = expected = 0.0;
|
|
max = min = (long) cache->item[0].count;
|
|
imax = imin = nzeroes = 0;
|
|
totalcount = 0.0;
|
|
|
|
hystogram = ALLOC(long, nbins);
|
|
if (hystogram == NULL) {
|
|
return(0);
|
|
}
|
|
for (i = 0; i < nbins; i++) {
|
|
hystogram[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < slots; i++) {
|
|
entry = (DdLocalCacheItem *) ((char *) cache->item +
|
|
i * cache->itemsize);
|
|
thiscount = (long) entry->count;
|
|
if (thiscount > max) {
|
|
max = thiscount;
|
|
imax = i;
|
|
}
|
|
if (thiscount < min) {
|
|
min = thiscount;
|
|
imin = i;
|
|
}
|
|
if (thiscount == 0) {
|
|
nzeroes++;
|
|
}
|
|
count = (double) thiscount;
|
|
mean += count;
|
|
meansq += count * count;
|
|
totalcount += count;
|
|
expected += count * (double) i;
|
|
bin = (i * nbins) / slots;
|
|
hystogram[bin] += thiscount;
|
|
}
|
|
mean /= (double) slots;
|
|
meansq /= (double) slots;
|
|
stddev = sqrt(meansq - mean*mean);
|
|
|
|
retval = fprintf(fp,"Cache stats: slots = %d average = %g ", slots, mean);
|
|
if (retval == EOF) return(0);
|
|
retval = fprintf(fp,"standard deviation = %g\n", stddev);
|
|
if (retval == EOF) return(0);
|
|
retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
|
|
if (retval == EOF) return(0);
|
|
retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
|
|
if (retval == EOF) return(0);
|
|
retval = fprintf(fp,"Cache unused slots = %d\n", nzeroes);
|
|
if (retval == EOF) return(0);
|
|
|
|
if (totalcount) {
|
|
expected /= totalcount;
|
|
retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
|
|
if (retval == EOF) return(0);
|
|
retval = fprintf(fp," (expected bin value = %g)\n# ", expected);
|
|
if (retval == EOF) return(0);
|
|
for (i = nbins - 1; i>=0; i--) {
|
|
retval = fprintf(fp,"%ld ", hystogram[i]);
|
|
if (retval == EOF) return(0);
|
|
}
|
|
retval = fprintf(fp,"\n");
|
|
if (retval == EOF) return(0);
|
|
}
|
|
|
|
FREE(hystogram);
|
|
return(1);
|
|
|
|
} /* end of cuddLocalCacheProfile */
|
|
#endif
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Initializes a hash table.]
|
|
|
|
Description [Initializes a hash table. Returns a pointer to the new
|
|
table if successful; NULL otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableQuit]
|
|
|
|
******************************************************************************/
|
|
DdHashTable *
|
|
cuddHashTableInit(
|
|
DdManager * manager,
|
|
unsigned int keySize,
|
|
unsigned int initSize)
|
|
{
|
|
DdHashTable *hash;
|
|
int logSize;
|
|
|
|
hash = ALLOC(DdHashTable, 1);
|
|
if (hash == NULL) {
|
|
manager->errorCode = CUDD_MEMORY_OUT;
|
|
return(NULL);
|
|
}
|
|
hash->keysize = keySize;
|
|
hash->manager = manager;
|
|
hash->memoryList = NULL;
|
|
hash->nextFree = NULL;
|
|
hash->itemsize = (keySize + 1) * sizeof(DdNode *) +
|
|
sizeof(ptrint) + sizeof(DdHashItem *);
|
|
/* We have to guarantee that the shift be < 32. */
|
|
if (initSize < 2) initSize = 2;
|
|
logSize = cuddComputeFloorLog2(initSize);
|
|
hash->numBuckets = 1 << logSize;
|
|
hash->shift = sizeof(int) * 8 - logSize;
|
|
hash->bucket = ALLOC(DdHashItem *, hash->numBuckets);
|
|
if (hash->bucket == NULL) {
|
|
manager->errorCode = CUDD_MEMORY_OUT;
|
|
FREE(hash);
|
|
return(NULL);
|
|
}
|
|
memset(hash->bucket, 0, hash->numBuckets * sizeof(DdHashItem *));
|
|
hash->size = 0;
|
|
hash->maxsize = hash->numBuckets * DD_MAX_HASHTABLE_DENSITY;
|
|
return(hash);
|
|
|
|
} /* end of cuddHashTableInit */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Shuts down a hash table.]
|
|
|
|
Description [Shuts down a hash table, dereferencing all the values.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableInit]
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddHashTableQuit(
|
|
DdHashTable * hash)
|
|
{
|
|
unsigned int i;
|
|
DdManager *dd = hash->manager;
|
|
DdHashItem *bucket;
|
|
DdHashItem **memlist, **nextmem;
|
|
unsigned int numBuckets = hash->numBuckets;
|
|
|
|
for (i = 0; i < numBuckets; i++) {
|
|
bucket = hash->bucket[i];
|
|
while (bucket != NULL) {
|
|
Cudd_RecursiveDeref(dd, bucket->value);
|
|
bucket = bucket->next;
|
|
}
|
|
}
|
|
|
|
memlist = hash->memoryList;
|
|
while (memlist != NULL) {
|
|
nextmem = (DdHashItem **) memlist[0];
|
|
FREE(memlist);
|
|
memlist = nextmem;
|
|
}
|
|
|
|
FREE(hash->bucket);
|
|
FREE(hash);
|
|
|
|
return;
|
|
|
|
} /* end of cuddHashTableQuit */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Shuts down a hash table.]
|
|
|
|
Description [Shuts down a hash table, when the values are not DdNode
|
|
pointers.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableInit]
|
|
|
|
******************************************************************************/
|
|
void
|
|
cuddHashTableGenericQuit(
|
|
DdHashTable * hash)
|
|
{
|
|
#ifdef __osf__
|
|
#pragma pointer_size save
|
|
#pragma pointer_size short
|
|
#endif
|
|
DdHashItem **memlist, **nextmem;
|
|
|
|
memlist = hash->memoryList;
|
|
while (memlist != NULL) {
|
|
nextmem = (DdHashItem **) memlist[0];
|
|
FREE(memlist);
|
|
memlist = nextmem;
|
|
}
|
|
|
|
FREE(hash->bucket);
|
|
FREE(hash);
|
|
#ifdef __osf__
|
|
#pragma pointer_size restore
|
|
#endif
|
|
|
|
return;
|
|
|
|
} /* end of cuddHashTableGenericQuit */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts an item in a hash table.]
|
|
|
|
Description [Inserts an item in a hash table when the key has more than
|
|
three pointers. Returns 1 if successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [[cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableInsert3
|
|
cuddHashTableLookup]
|
|
|
|
******************************************************************************/
|
|
int
|
|
cuddHashTableInsert(
|
|
DdHashTable * hash,
|
|
DdNodePtr * key,
|
|
DdNode * value,
|
|
ptrint count)
|
|
{
|
|
int result;
|
|
unsigned int posn;
|
|
DdHashItem *item;
|
|
unsigned int i;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize > 3);
|
|
#endif
|
|
|
|
if (hash->size > hash->maxsize) {
|
|
result = cuddHashTableResize(hash);
|
|
if (result == 0) return(0);
|
|
}
|
|
item = cuddHashTableAlloc(hash);
|
|
if (item == NULL) return(0);
|
|
hash->size++;
|
|
item->value = value;
|
|
cuddRef(value);
|
|
item->count = count;
|
|
for (i = 0; i < hash->keysize; i++) {
|
|
item->key[i] = key[i];
|
|
}
|
|
posn = ddLCHash(key,hash->keysize,hash->shift);
|
|
item->next = hash->bucket[posn];
|
|
hash->bucket[posn] = item;
|
|
|
|
return(1);
|
|
|
|
} /* end of cuddHashTableInsert */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Looks up a key in a hash table.]
|
|
|
|
Description [Looks up a key consisting of more than three pointers
|
|
in a hash table. Returns the value associated to the key if there
|
|
is an entry for the given key in the table; NULL otherwise. If the
|
|
entry is present, its reference counter is decremented if not
|
|
saturated. If the counter reaches 0, the value of the entry is
|
|
dereferenced, and the entry is returned to the free list.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableLookup3
|
|
cuddHashTableInsert]
|
|
|
|
******************************************************************************/
|
|
DdNode *
|
|
cuddHashTableLookup(
|
|
DdHashTable * hash,
|
|
DdNodePtr * key)
|
|
{
|
|
unsigned int posn;
|
|
DdHashItem *item, *prev;
|
|
unsigned int i, keysize;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize > 3);
|
|
#endif
|
|
|
|
posn = ddLCHash(key,hash->keysize,hash->shift);
|
|
item = hash->bucket[posn];
|
|
prev = NULL;
|
|
|
|
keysize = hash->keysize;
|
|
while (item != NULL) {
|
|
DdNodePtr *key2 = item->key;
|
|
int equal = 1;
|
|
for (i = 0; i < keysize; i++) {
|
|
if (key[i] != key2[i]) {
|
|
equal = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (equal) {
|
|
DdNode *value = item->value;
|
|
cuddSatDec(item->count);
|
|
if (item->count == 0) {
|
|
cuddDeref(value);
|
|
if (prev == NULL) {
|
|
hash->bucket[posn] = item->next;
|
|
} else {
|
|
prev->next = item->next;
|
|
}
|
|
item->next = hash->nextFree;
|
|
hash->nextFree = item;
|
|
hash->size--;
|
|
}
|
|
return(value);
|
|
}
|
|
prev = item;
|
|
item = item->next;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of cuddHashTableLookup */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts an item in a hash table.]
|
|
|
|
Description [Inserts an item in a hash table when the key is one pointer.
|
|
Returns 1 if successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableInsert cuddHashTableInsert2 cuddHashTableInsert3
|
|
cuddHashTableLookup1]
|
|
|
|
******************************************************************************/
|
|
int
|
|
cuddHashTableInsert1(
|
|
DdHashTable * hash,
|
|
DdNode * f,
|
|
DdNode * value,
|
|
ptrint count)
|
|
{
|
|
int result;
|
|
unsigned int posn;
|
|
DdHashItem *item;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 1);
|
|
#endif
|
|
|
|
if (hash->size > hash->maxsize) {
|
|
result = cuddHashTableResize(hash);
|
|
if (result == 0) return(0);
|
|
}
|
|
item = cuddHashTableAlloc(hash);
|
|
if (item == NULL) return(0);
|
|
hash->size++;
|
|
item->value = value;
|
|
cuddRef(value);
|
|
item->count = count;
|
|
item->key[0] = f;
|
|
posn = ddLCHash1(f,hash->shift);
|
|
item->next = hash->bucket[posn];
|
|
hash->bucket[posn] = item;
|
|
|
|
return(1);
|
|
|
|
} /* end of cuddHashTableInsert1 */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Looks up a key consisting of one pointer in a hash table.]
|
|
|
|
Description [Looks up a key consisting of one pointer in a hash table.
|
|
Returns the value associated to the key if there is an entry for the given
|
|
key in the table; NULL otherwise. If the entry is present, its reference
|
|
counter is decremented if not saturated. If the counter reaches 0, the
|
|
value of the entry is dereferenced, and the entry is returned to the free
|
|
list.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableLookup cuddHashTableLookup2 cuddHashTableLookup3
|
|
cuddHashTableInsert1]
|
|
|
|
******************************************************************************/
|
|
DdNode *
|
|
cuddHashTableLookup1(
|
|
DdHashTable * hash,
|
|
DdNode * f)
|
|
{
|
|
unsigned int posn;
|
|
DdHashItem *item, *prev;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 1);
|
|
#endif
|
|
|
|
posn = ddLCHash1(f,hash->shift);
|
|
item = hash->bucket[posn];
|
|
prev = NULL;
|
|
|
|
while (item != NULL) {
|
|
DdNodePtr *key = item->key;
|
|
if (f == key[0]) {
|
|
DdNode *value = item->value;
|
|
cuddSatDec(item->count);
|
|
if (item->count == 0) {
|
|
cuddDeref(value);
|
|
if (prev == NULL) {
|
|
hash->bucket[posn] = item->next;
|
|
} else {
|
|
prev->next = item->next;
|
|
}
|
|
item->next = hash->nextFree;
|
|
hash->nextFree = item;
|
|
hash->size--;
|
|
}
|
|
return(value);
|
|
}
|
|
prev = item;
|
|
item = item->next;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of cuddHashTableLookup1 */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts an item in a hash table.]
|
|
|
|
Description [Inserts an item in a hash table when the key is one
|
|
pointer and the value is not a DdNode pointer. Returns 1 if
|
|
successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableInsert1 cuddHashTableGenericLookup]
|
|
|
|
******************************************************************************/
|
|
int
|
|
cuddHashTableGenericInsert(
|
|
DdHashTable * hash,
|
|
DdNode * f,
|
|
void * value)
|
|
{
|
|
int result;
|
|
unsigned int posn;
|
|
DdHashItem *item;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 1);
|
|
#endif
|
|
|
|
if (hash->size > hash->maxsize) {
|
|
result = cuddHashTableResize(hash);
|
|
if (result == 0) return(0);
|
|
}
|
|
item = cuddHashTableAlloc(hash);
|
|
if (item == NULL) return(0);
|
|
hash->size++;
|
|
item->value = (DdNode *) value;
|
|
item->count = 0;
|
|
item->key[0] = f;
|
|
posn = ddLCHash1(f,hash->shift);
|
|
item->next = hash->bucket[posn];
|
|
hash->bucket[posn] = item;
|
|
|
|
return(1);
|
|
|
|
} /* end of cuddHashTableGenericInsert */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Looks up a key consisting of one pointer in a hash table.]
|
|
|
|
Description [Looks up a key consisting of one pointer in a hash
|
|
table when the value is not a DdNode pointer. Returns the value
|
|
associated to the key if there is an entry for the given key in the
|
|
table; NULL otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableLookup1 cuddHashTableGenericInsert]
|
|
|
|
******************************************************************************/
|
|
void *
|
|
cuddHashTableGenericLookup(
|
|
DdHashTable * hash,
|
|
DdNode * f)
|
|
{
|
|
unsigned int posn;
|
|
DdHashItem *item;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 1);
|
|
#endif
|
|
|
|
posn = ddLCHash1(f,hash->shift);
|
|
item = hash->bucket[posn];
|
|
|
|
while (item != NULL) {
|
|
if (f == item->key[0]) {
|
|
return ((void *) item->value);
|
|
}
|
|
item = item->next;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of cuddHashTableGenericLookup */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts an item in a hash table.]
|
|
|
|
Description [Inserts an item in a hash table when the key is
|
|
composed of two pointers. Returns 1 if successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert3
|
|
cuddHashTableLookup2]
|
|
|
|
******************************************************************************/
|
|
int
|
|
cuddHashTableInsert2(
|
|
DdHashTable * hash,
|
|
DdNode * f,
|
|
DdNode * g,
|
|
DdNode * value,
|
|
ptrint count)
|
|
{
|
|
int result;
|
|
unsigned int posn;
|
|
DdHashItem *item;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 2);
|
|
#endif
|
|
|
|
if (hash->size > hash->maxsize) {
|
|
result = cuddHashTableResize(hash);
|
|
if (result == 0) return(0);
|
|
}
|
|
item = cuddHashTableAlloc(hash);
|
|
if (item == NULL) return(0);
|
|
hash->size++;
|
|
item->value = value;
|
|
cuddRef(value);
|
|
item->count = count;
|
|
item->key[0] = f;
|
|
item->key[1] = g;
|
|
posn = ddLCHash2(f,g,hash->shift);
|
|
item->next = hash->bucket[posn];
|
|
hash->bucket[posn] = item;
|
|
|
|
return(1);
|
|
|
|
} /* end of cuddHashTableInsert2 */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Looks up a key consisting of two pointers in a hash table.]
|
|
|
|
Description [Looks up a key consisting of two pointer in a hash table.
|
|
Returns the value associated to the key if there is an entry for the given
|
|
key in the table; NULL otherwise. If the entry is present, its reference
|
|
counter is decremented if not saturated. If the counter reaches 0, the
|
|
value of the entry is dereferenced, and the entry is returned to the free
|
|
list.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup3
|
|
cuddHashTableInsert2]
|
|
|
|
******************************************************************************/
|
|
DdNode *
|
|
cuddHashTableLookup2(
|
|
DdHashTable * hash,
|
|
DdNode * f,
|
|
DdNode * g)
|
|
{
|
|
unsigned int posn;
|
|
DdHashItem *item, *prev;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 2);
|
|
#endif
|
|
|
|
posn = ddLCHash2(f,g,hash->shift);
|
|
item = hash->bucket[posn];
|
|
prev = NULL;
|
|
|
|
while (item != NULL) {
|
|
DdNodePtr *key = item->key;
|
|
if ((f == key[0]) && (g == key[1])) {
|
|
DdNode *value = item->value;
|
|
cuddSatDec(item->count);
|
|
if (item->count == 0) {
|
|
cuddDeref(value);
|
|
if (prev == NULL) {
|
|
hash->bucket[posn] = item->next;
|
|
} else {
|
|
prev->next = item->next;
|
|
}
|
|
item->next = hash->nextFree;
|
|
hash->nextFree = item;
|
|
hash->size--;
|
|
}
|
|
return(value);
|
|
}
|
|
prev = item;
|
|
item = item->next;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of cuddHashTableLookup2 */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts an item in a hash table.]
|
|
|
|
Description [Inserts an item in a hash table when the key is
|
|
composed of three pointers. Returns 1 if successful; 0 otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert2
|
|
cuddHashTableLookup3]
|
|
|
|
******************************************************************************/
|
|
int
|
|
cuddHashTableInsert3(
|
|
DdHashTable * hash,
|
|
DdNode * f,
|
|
DdNode * g,
|
|
DdNode * h,
|
|
DdNode * value,
|
|
ptrint count)
|
|
{
|
|
int result;
|
|
unsigned int posn;
|
|
DdHashItem *item;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 3);
|
|
#endif
|
|
|
|
if (hash->size > hash->maxsize) {
|
|
result = cuddHashTableResize(hash);
|
|
if (result == 0) return(0);
|
|
}
|
|
item = cuddHashTableAlloc(hash);
|
|
if (item == NULL) return(0);
|
|
hash->size++;
|
|
item->value = value;
|
|
cuddRef(value);
|
|
item->count = count;
|
|
item->key[0] = f;
|
|
item->key[1] = g;
|
|
item->key[2] = h;
|
|
posn = ddLCHash3(f,g,h,hash->shift);
|
|
item->next = hash->bucket[posn];
|
|
hash->bucket[posn] = item;
|
|
|
|
return(1);
|
|
|
|
} /* end of cuddHashTableInsert3 */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Looks up a key consisting of three pointers in a hash table.]
|
|
|
|
Description [Looks up a key consisting of three pointers in a hash table.
|
|
Returns the value associated to the key if there is an entry for the given
|
|
key in the table; NULL otherwise. If the entry is present, its reference
|
|
counter is decremented if not saturated. If the counter reaches 0, the
|
|
value of the entry is dereferenced, and the entry is returned to the free
|
|
list.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup2
|
|
cuddHashTableInsert3]
|
|
|
|
******************************************************************************/
|
|
DdNode *
|
|
cuddHashTableLookup3(
|
|
DdHashTable * hash,
|
|
DdNode * f,
|
|
DdNode * g,
|
|
DdNode * h)
|
|
{
|
|
unsigned int posn;
|
|
DdHashItem *item, *prev;
|
|
|
|
#ifdef DD_DEBUG
|
|
assert(hash->keysize == 3);
|
|
#endif
|
|
|
|
posn = ddLCHash3(f,g,h,hash->shift);
|
|
item = hash->bucket[posn];
|
|
prev = NULL;
|
|
|
|
while (item != NULL) {
|
|
DdNodePtr *key = item->key;
|
|
if ((f == key[0]) && (g == key[1]) && (h == key[2])) {
|
|
DdNode *value = item->value;
|
|
cuddSatDec(item->count);
|
|
if (item->count == 0) {
|
|
cuddDeref(value);
|
|
if (prev == NULL) {
|
|
hash->bucket[posn] = item->next;
|
|
} else {
|
|
prev->next = item->next;
|
|
}
|
|
item->next = hash->nextFree;
|
|
hash->nextFree = item;
|
|
hash->size--;
|
|
}
|
|
return(value);
|
|
}
|
|
prev = item;
|
|
item = item->next;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of cuddHashTableLookup3 */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Resizes a local cache.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static void
|
|
cuddLocalCacheResize(
|
|
DdLocalCache * cache)
|
|
{
|
|
DdLocalCacheItem *item, *olditem, *entry, *old;
|
|
int i, shift;
|
|
unsigned int posn;
|
|
unsigned int slots, oldslots;
|
|
extern DD_OOMFP MMoutOfMemory;
|
|
DD_OOMFP saveHandler;
|
|
|
|
olditem = cache->item;
|
|
oldslots = cache->slots;
|
|
slots = cache->slots = oldslots << 1;
|
|
|
|
#ifdef DD_VERBOSE
|
|
(void) fprintf(cache->manager->err,
|
|
"Resizing local cache from %d to %d entries\n",
|
|
oldslots, slots);
|
|
(void) fprintf(cache->manager->err,
|
|
"\thits = %.0f\tlookups = %.0f\thit ratio = %5.3f\n",
|
|
cache->hits, cache->lookUps, cache->hits / cache->lookUps);
|
|
#endif
|
|
|
|
saveHandler = MMoutOfMemory;
|
|
MMoutOfMemory = Cudd_OutOfMem;
|
|
cache->item = item =
|
|
(DdLocalCacheItem *) ALLOC(char, slots * cache->itemsize);
|
|
MMoutOfMemory = saveHandler;
|
|
/* If we fail to allocate the new table we just give up. */
|
|
if (item == NULL) {
|
|
#ifdef DD_VERBOSE
|
|
(void) fprintf(cache->manager->err,"Resizing failed. Giving up.\n");
|
|
#endif
|
|
cache->slots = oldslots;
|
|
cache->item = olditem;
|
|
/* Do not try to resize again. */
|
|
cache->maxslots = oldslots - 1;
|
|
return;
|
|
}
|
|
shift = --(cache->shift);
|
|
cache->manager->memused += (slots - oldslots) * cache->itemsize;
|
|
|
|
/* Clear new cache. */
|
|
memset(item, 0, slots * cache->itemsize);
|
|
|
|
/* Copy from old cache to new one. */
|
|
for (i = 0; (unsigned) i < oldslots; i++) {
|
|
old = (DdLocalCacheItem *) ((char *) olditem + i * cache->itemsize);
|
|
if (old->value != NULL) {
|
|
posn = ddLCHash(old->key,cache->keysize,shift);
|
|
entry = (DdLocalCacheItem *) ((char *) item +
|
|
posn * cache->itemsize);
|
|
memcpy(entry->key,old->key,cache->keysize*sizeof(DdNode *));
|
|
entry->value = old->value;
|
|
}
|
|
}
|
|
|
|
FREE(olditem);
|
|
|
|
/* Reinitialize measurements so as to avoid division by 0 and
|
|
** immediate resizing.
|
|
*/
|
|
cache->lookUps = (double) (int) (slots * cache->minHit + 1);
|
|
cache->hits = 0;
|
|
|
|
} /* end of cuddLocalCacheResize */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Computes the hash value for a local cache.]
|
|
|
|
Description [Computes the hash value for a local cache. Returns the
|
|
bucket index.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DD_INLINE
|
|
static unsigned int
|
|
ddLCHash(
|
|
DdNodePtr * key,
|
|
unsigned int keysize,
|
|
int shift)
|
|
{
|
|
unsigned int val = (unsigned int) (ptrint) key[0] * DD_P2;
|
|
unsigned int i;
|
|
|
|
for (i = 1; i < keysize; i++) {
|
|
val = val * DD_P1 + (int) (ptrint) key[i];
|
|
}
|
|
|
|
return(val >> shift);
|
|
|
|
} /* end of ddLCHash */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Inserts a local cache in the manager list.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static void
|
|
cuddLocalCacheAddToList(
|
|
DdLocalCache * cache)
|
|
{
|
|
DdManager *manager = cache->manager;
|
|
|
|
cache->next = manager->localCaches;
|
|
manager->localCaches = cache;
|
|
return;
|
|
|
|
} /* end of cuddLocalCacheAddToList */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Removes a local cache from the manager list.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
static void
|
|
cuddLocalCacheRemoveFromList(
|
|
DdLocalCache * cache)
|
|
{
|
|
DdManager *manager = cache->manager;
|
|
DdLocalCache **prevCache, *nextCache;
|
|
|
|
prevCache = &(manager->localCaches);
|
|
nextCache = manager->localCaches;
|
|
|
|
while (nextCache != NULL) {
|
|
if (nextCache == cache) {
|
|
*prevCache = nextCache->next;
|
|
return;
|
|
}
|
|
prevCache = &(nextCache->next);
|
|
nextCache = nextCache->next;
|
|
}
|
|
return; /* should never get here */
|
|
|
|
} /* end of cuddLocalCacheRemoveFromList */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Resizes a hash table.]
|
|
|
|
Description [Resizes a hash table. Returns 1 if successful; 0
|
|
otherwise.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddHashTableInsert]
|
|
|
|
******************************************************************************/
|
|
static int
|
|
cuddHashTableResize(
|
|
DdHashTable * hash)
|
|
{
|
|
int j;
|
|
unsigned int posn;
|
|
DdHashItem *item;
|
|
DdHashItem *next;
|
|
DdNode **key;
|
|
int numBuckets;
|
|
DdHashItem **buckets;
|
|
DdHashItem **oldBuckets = hash->bucket;
|
|
int shift;
|
|
int oldNumBuckets = hash->numBuckets;
|
|
extern DD_OOMFP MMoutOfMemory;
|
|
DD_OOMFP saveHandler;
|
|
|
|
/* Compute the new size of the table. */
|
|
numBuckets = oldNumBuckets << 1;
|
|
saveHandler = MMoutOfMemory;
|
|
MMoutOfMemory = Cudd_OutOfMem;
|
|
buckets = ALLOC(DdHashItem *, numBuckets);
|
|
MMoutOfMemory = saveHandler;
|
|
if (buckets == NULL) {
|
|
hash->maxsize <<= 1;
|
|
return(1);
|
|
}
|
|
|
|
hash->bucket = buckets;
|
|
hash->numBuckets = numBuckets;
|
|
shift = --(hash->shift);
|
|
hash->maxsize <<= 1;
|
|
memset(buckets, 0, numBuckets * sizeof(DdHashItem *));
|
|
if (hash->keysize == 1) {
|
|
for (j = 0; j < oldNumBuckets; j++) {
|
|
item = oldBuckets[j];
|
|
while (item != NULL) {
|
|
next = item->next;
|
|
key = item->key;
|
|
posn = ddLCHash2(key[0], key[0], shift);
|
|
item->next = buckets[posn];
|
|
buckets[posn] = item;
|
|
item = next;
|
|
}
|
|
}
|
|
} else if (hash->keysize == 2) {
|
|
for (j = 0; j < oldNumBuckets; j++) {
|
|
item = oldBuckets[j];
|
|
while (item != NULL) {
|
|
next = item->next;
|
|
key = item->key;
|
|
posn = ddLCHash2(key[0], key[1], shift);
|
|
item->next = buckets[posn];
|
|
buckets[posn] = item;
|
|
item = next;
|
|
}
|
|
}
|
|
} else if (hash->keysize == 3) {
|
|
for (j = 0; j < oldNumBuckets; j++) {
|
|
item = oldBuckets[j];
|
|
while (item != NULL) {
|
|
next = item->next;
|
|
key = item->key;
|
|
posn = ddLCHash3(key[0], key[1], key[2], shift);
|
|
item->next = buckets[posn];
|
|
buckets[posn] = item;
|
|
item = next;
|
|
}
|
|
}
|
|
} else {
|
|
for (j = 0; j < oldNumBuckets; j++) {
|
|
item = oldBuckets[j];
|
|
while (item != NULL) {
|
|
next = item->next;
|
|
posn = ddLCHash(item->key, hash->keysize, shift);
|
|
item->next = buckets[posn];
|
|
buckets[posn] = item;
|
|
item = next;
|
|
}
|
|
}
|
|
}
|
|
FREE(oldBuckets);
|
|
return(1);
|
|
|
|
} /* end of cuddHashTableResize */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Fast storage allocation for items in a hash table.]
|
|
|
|
Description [Fast storage allocation for items in a hash table. The
|
|
first 4 bytes of a chunk contain a pointer to the next block; the
|
|
rest contains DD_MEM_CHUNK spaces for hash items. Returns a pointer to
|
|
a new item if successful; NULL is memory is full.]
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso [cuddAllocNode cuddDynamicAllocNode]
|
|
|
|
******************************************************************************/
|
|
DD_INLINE
|
|
static DdHashItem *
|
|
cuddHashTableAlloc(
|
|
DdHashTable * hash)
|
|
{
|
|
int i;
|
|
unsigned int itemsize = hash->itemsize;
|
|
extern DD_OOMFP MMoutOfMemory;
|
|
DD_OOMFP saveHandler;
|
|
DdHashItem **mem, *thisOne, *next, *item;
|
|
|
|
if (hash->nextFree == NULL) {
|
|
saveHandler = MMoutOfMemory;
|
|
MMoutOfMemory = Cudd_OutOfMem;
|
|
mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
|
|
MMoutOfMemory = saveHandler;
|
|
if (mem == NULL) {
|
|
if (hash->manager->stash != NULL) {
|
|
FREE(hash->manager->stash);
|
|
hash->manager->stash = NULL;
|
|
/* Inhibit resizing of tables. */
|
|
hash->manager->maxCacheHard = hash->manager->cacheSlots - 1;
|
|
hash->manager->cacheSlack = - (int) (hash->manager->cacheSlots + 1);
|
|
for (i = 0; i < hash->manager->size; i++) {
|
|
hash->manager->subtables[i].maxKeys <<= 2;
|
|
}
|
|
hash->manager->gcFrac = 0.2;
|
|
hash->manager->minDead =
|
|
(unsigned) (0.2 * (double) hash->manager->slots);
|
|
mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
|
|
}
|
|
if (mem == NULL) {
|
|
(*MMoutOfMemory)((long)((DD_MEM_CHUNK + 1) * itemsize));
|
|
hash->manager->errorCode = CUDD_MEMORY_OUT;
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
mem[0] = (DdHashItem *) hash->memoryList;
|
|
hash->memoryList = mem;
|
|
|
|
thisOne = (DdHashItem *) ((char *) mem + itemsize);
|
|
hash->nextFree = thisOne;
|
|
for (i = 1; i < DD_MEM_CHUNK; i++) {
|
|
next = (DdHashItem *) ((char *) thisOne + itemsize);
|
|
thisOne->next = next;
|
|
thisOne = next;
|
|
}
|
|
|
|
thisOne->next = NULL;
|
|
|
|
}
|
|
item = hash->nextFree;
|
|
hash->nextFree = item->next;
|
|
return(item);
|
|
|
|
} /* end of cuddHashTableAlloc */
|