/**CFile***********************************************************************
FileName [cuddLCache.c]
PackageName [cudd]
Synopsis [Functions for local caches.]
Description [Internal procedures included in this module:
- cuddLocalCacheInit()
- cuddLocalCacheQuit()
- cuddLocalCacheInsert()
- cuddLocalCacheLookup()
- cuddLocalCacheClearDead()
- cuddLocalCacheClearAll()
- cuddLocalCacheProfile()
- cuddHashTableInit()
- cuddHashTableQuit()
- cuddHashTableInsert()
- cuddHashTableLookup()
- cuddHashTableInsert2()
- cuddHashTableLookup2()
- cuddHashTableInsert3()
- cuddHashTableLookup3()
Static procedures included in this module:
- cuddLocalCacheResize()
- ddLCHash()
- cuddLocalCacheAddToList()
- cuddLocalCacheRemoveFromList()
- cuddHashTableResize()
- cuddHashTableAlloc()
]
SeeAlso []
Author [Fabio Somenzi]
Copyright [Copyright (c) 1995-2004, 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 "misc/util/util_hack.h"
#include "cuddInt.h"
ABC_NAMESPACE_IMPL_START
/*---------------------------------------------------------------------------*/
/* 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.24 2009/03/08 02:49:02 fabio Exp $";
#endif
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**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 = ABC_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 *)
ABC_ALLOC(char, cacheSize * cache->itemsize);
if (cache->item == NULL) {
manager->errorCode = CUDD_MEMORY_OUT;
ABC_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);
ABC_FREE(cache->item);
ABC_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 = ABC_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);
}
ABC_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;
#ifdef __osf__
#pragma pointer_size save
#pragma pointer_size short
#endif
hash = ABC_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 = ABC_ALLOC(DdHashItem *, hash->numBuckets);
if (hash->bucket == NULL) {
manager->errorCode = CUDD_MEMORY_OUT;
ABC_FREE(hash);
return(NULL);
}
memset(hash->bucket, 0, hash->numBuckets * sizeof(DdHashItem *));
hash->size = 0;
hash->maxsize = hash->numBuckets * DD_MAX_HASHTABLE_DENSITY;
#ifdef __osf__
#pragma pointer_size restore
#endif
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)
{
#ifdef __osf__
#pragma pointer_size save
#pragma pointer_size short
#endif
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];
ABC_FREE(memlist);
memlist = nextmem;
}
ABC_FREE(hash->bucket);
ABC_FREE(hash);
#ifdef __osf__
#pragma pointer_size restore
#endif
return;
} /* end of cuddHashTableQuit */
/**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 = ddLCHash2(cuddF2L(f),cuddF2L(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 = ddLCHash2(cuddF2L(f),cuddF2L(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
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(cuddF2L(f),cuddF2L(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(cuddF2L(f),cuddF2L(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(cuddF2L(f),cuddF2L(g),cuddF2L(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(cuddF2L(f),cuddF2L(g),cuddF2L(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 *) ABC_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;
}
}
ABC_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;
#ifdef __osf__
#pragma pointer_size save
#pragma pointer_size short
#endif
DdLocalCache **prevCache, *nextCache;
#ifdef __osf__
#pragma pointer_size restore
#endif
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;
#ifdef __osf__
#pragma pointer_size save
#pragma pointer_size short
#endif
DdNode **key;
int numBuckets;
DdHashItem **buckets;
DdHashItem **oldBuckets = hash->bucket;
#ifdef __osf__
#pragma pointer_size restore
#endif
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;
#ifdef __osf__
#pragma pointer_size save
#pragma pointer_size short
#endif
buckets = ABC_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 *));
#ifdef __osf__
#pragma pointer_size restore
#endif
if (hash->keysize == 1) {
for (j = 0; j < oldNumBuckets; j++) {
item = oldBuckets[j];
while (item != NULL) {
next = item->next;
key = item->key;
posn = ddLCHash2(cuddF2L(key[0]), cuddF2L(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(cuddF2L(key[0]), cuddF2L(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(cuddF2L(key[0]), cuddF2L(key[1]), cuddF2L(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;
}
}
}
ABC_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;
#ifdef __osf__
#pragma pointer_size save
#pragma pointer_size short
#endif
DdHashItem **mem, *thisOne, *next, *item;
if (hash->nextFree == NULL) {
saveHandler = MMoutOfMemory;
MMoutOfMemory = Cudd_OutOfMem;
mem = (DdHashItem **) ABC_ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
MMoutOfMemory = saveHandler;
#ifdef __osf__
#pragma pointer_size restore
#endif
if (mem == NULL) {
if (hash->manager->stash != NULL) {
ABC_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);
#ifdef __osf__
#pragma pointer_size save
#pragma pointer_size short
#endif
mem = (DdHashItem **) ABC_ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
#ifdef __osf__
#pragma pointer_size restore
#endif
}
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 */
ABC_NAMESPACE_IMPL_END