void UtlHashMap::destroyAll() { OsLock take(mContainerLock); size_t i; size_t toBeDestroyed; for (i = 0, toBeDestroyed = mElements; i < numberOfBuckets() && toBeDestroyed; i++ ) // for each bucket { while(!mpBucket[i].isUnLinked()) // bucket is not empty yet { UtlPair* pair = static_cast<UtlPair*>(mpBucket[i].head()); notifyIteratorsOfRemove(pair); pair->detachFromList(&mpBucket[i]); delete pair->data; if (pair->value != INTERNAL_NULL) { delete pair->value; } pair->release(); toBeDestroyed--; } } mElements = 0; }
/* * Allocate additional buckets and redistribute existing contents. * This should only be called through resizeIfNeededAndSafe. */ void UtlHashBag::resize() { // already holding the mContainerLock UtlChain* newBucket; size_t newBucketBits; // if an iterator had prevented resizing while many elements were added, // we might need to double more than once to restore the target ratio. for (newBucketBits = mBucketBits+1; mElements / NUM_HASHBAG_BUCKETS(newBucketBits) >= 3; newBucketBits++ ) { } // allocate the new buckets newBucket = new UtlChain[NUM_HASHBAG_BUCKETS(newBucketBits)]; if (newBucket) { // save the old buckets until we move the entries out of them UtlChain* oldBucket = mpBucket; size_t numOldBuckets = numberOfBuckets(); // put in the new buckets mBucketBits = newBucketBits; mpBucket = newBucket; // move all the entries to the new buckets size_t old; size_t toBeMoved; for (old = 0, toBeMoved = mElements; old < numOldBuckets && toBeMoved; old++ ) { while(!oldBucket[old].isUnLinked()) // old bucket is not empty yet { UtlLink* link = static_cast<UtlLink*>(oldBucket[old].head()); link->detachFromList(&oldBucket[old]); insert(link, &mpBucket[bucketNumber(link->hash)]); toBeMoved--; } } delete [] oldBucket; // finished with the old empty buckets } else { assert(newBucket); // failed to allocate new buckets } }
/** * Search for the designated object by reference. * @return the object if found, otherwise NULL. */ UtlContainable* UtlHashBag::findReference(const UtlContainable* object) const { UtlContainable* found = NULL; if (object) { OsLock take(mContainerLock); UtlLink* link = NULL; UtlChain* bucket; UtlLink* check; // walk the buckets for (size_t i = 0; link == NULL && i < numberOfBuckets(); i++) { bucket = &mpBucket[i]; for (link = NULL, check = static_cast<UtlLink*>(bucket->listHead()); ( !link // not found && check // not end of list ); check = check->next() ) { if (check->data == object) { link = check; // found it } } } if (link) { found = link->data; } } return found; }
void UtlHashBag::removeAll() { OsLock take(mContainerLock); size_t i; size_t toBeRemoved; for (i = 0, toBeRemoved = mElements; i < numberOfBuckets() && toBeRemoved; i++ ) // for each bucket { while(!mpBucket[i].isUnLinked()) // bucket is not empty yet { UtlLink* link = static_cast<UtlLink*>(mpBucket[i].head()); notifyIteratorsOfRemove(link); link->detachFromList(&mpBucket[i]); link->release(); toBeRemoved--; } } mElements = 0; }
size_t UtlHashMap::bucketNumber(unsigned hash) const { /* * We only use mBucketBits of the hash to index mpBucket, but we don't want to * loose the information in the higher bits of the hash code. So we 'fold' the * high order bits by XORing them mBucketBits at a time into the bits we'll * use until there are no non-zero high order bits left. */ size_t foldedHash; size_t highBits; size_t lowBitsMask = numberOfBuckets() - 1; for ( (foldedHash = hash & lowBitsMask, // get the low bits we want into the folded value highBits = hash // don't bother masking off the low bits ); (highBits = highBits >> mBucketBits); // shift out bits already used until zero foldedHash ^= highBits & lowBitsMask // incorporate non-zero ) { } return foldedHash; }
// Destructor UtlHashBag::~UtlHashBag() { UtlContainer::acquireIteratorConnectionLock(); OsLock take(mContainerLock); invalidateIterators(); UtlContainer::releaseIteratorConnectionLock(); // still holding the mContainerLock // walk the buckets for (size_t i = 0; i < numberOfBuckets(); i++) { // empty each bucket and release each UtlPair back to the pool while (!mpBucket[i].isUnLinked()) { UtlLink* link = static_cast<UtlLink*>(mpBucket[i].listHead()); link->detachFromList(&mpBucket[i]); link->release(); } } delete [] mpBucket; // free the bucket headers }