blob: beb00147e5243364347475e6054d033f0ce48e74 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
**************************************************************************
*
* File: Collections.C
* Description: Implementation for Collection type templates
* Created: 4/27/94
* Language: C++
*
*
*
**************************************************************************
*/
// -----------------------------------------------------------------------
// functions for the NACollection<T> template
// -----------------------------------------------------------------------
#include "Platform.h"
#include "Collections.h"
template <class T> NACollection<T>::~NACollection()
{
deallocate();
}
// For HSC, define these methods as inline methods in the Collections.h header file.
template <class T>
void NACollection<T>::copy(const NACollection<T> &other)
{
// allocate the arrays
// heap_ = other.heap_; //!!!do not change the value of a collection's heap_!!!
allocate(other.maxLength_);
usedLength_ = other.usedLength_;
entries_ = other.entries_;
// copy the entries
for (CollIndex i = FIRST_COLL_INDEX; i < usedLength_; i++)
{
arr_[i] = other.arr_[i];
usages_[i] = other.usages_[i];
}
}
template <class T>
void NACollection<T>::insert(CollIndex posToInsert,
const T &newElement,
CollIndex newUsage)
{
// is a valid position and usage given?
assert((posToInsert < MAX_COLL_INDEX) AND
(newUsage != UNUSED_COLL_ENTRY));
// do we need to increase the size?
if (posToInsert >= maxLength_)
resize(posToInsert + 1);
// is the new position in the unused portion?
if (posToInsert >= usedLength_)
{
// extend the used portion by filling in the usages_
// entries with UNUSED_COLL_ENTRY values
for (CollIndex i = usedLength_; i <= posToInsert; i++)
{
usages_[i] = UNUSED_COLL_ENTRY;
}
usedLength_ = posToInsert + 1;
}
// overwrite or insert?
if (usages_[posToInsert] == UNUSED_COLL_ENTRY)
entries_++;
// ok, now we're ready to insert the new element
usages_[posToInsert] = newUsage;
arr_[posToInsert] = newElement;
return;
}
template <class T>
CollIndex NACollection<T>::resize(CollIndex newSize)
{
if (newSize == maxLength_ OR
newSize < usedLength_)
// no need to resize or impossible to resize
return maxLength_;
else
{
// increment the size in larger chunks to avoid
// many expensive resize calls
if (newSize > maxLength_ AND
newSize/3 < (maxLength_+2)/2)
{
newSize = 3 * (maxLength_+2)/2;
}
// shouldn't even come close to this
assert (newSize < MAX_COLL_INDEX);
// use a temp collection with the new size
NACollection<T> newOne(heap_,newSize);
assert(newSize >= usedLength_);
for (CollIndex i = FIRST_COLL_INDEX; i < usedLength_; i++)
{
newOne.usages_[i] = usages_[i];
if (usages_[i] != UNUSED_COLL_ENTRY)
{
newOne.arr_[i] = arr_[i];
}
}
// now just deallocate the old arrays and take the new
// arrays and maxLength_
deallocate();
usages_ = newOne.usages_;
arr_ = newOne.arr_;
maxLength_ = newOne.maxLength_;
// make sure the destructor of newOne won't mess things up
newOne.usages_ = NULL;
newOne.arr_ = NULL;
newOne.usedLength_ = 0;
newOne.maxLength_ = 0;
return maxLength_;
}
}
#ifdef __GNUC__
# if __GNUC__ * 100 + __GNUC_MINOR__ >= 404
// push_options added in 4.4
#pragma GCC push_options
// GCC prior to 4.4 did not complain about this
// need to ignore uninitialized for this statement:
// T temp;
# pragma GCC diagnostic ignored "-Wuninitialized"
# if __GNUC__ * 100 + __GNUC_MINOR__ >= 408
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
# endif
# endif
#endif
template <class T> void NACollection<T>::allocate(CollIndex initLen)
{
// NOTE: this assumes that the heap_ data member has been set.
// No other data members need to be set before calling this.
assert(initLen < MAX_COLL_INDEX);
maxLength_ = initLen;
usedLength_ = 0;
entries_ = 0;
if (maxLength_ > 0)
{
// Since new[] and new are different operators, the following
// can not be combined, even that in new(size_t, NAMemory*)
// used the ::operator new if NAMemory* is 0.
if ( heap_ == NABasicObject::systemHeapPtr() )
{
arr_ = new T[maxLength_];
usages_ = new CollIndex[maxLength_];
}
else
{
// The method for dynamic allocation should match the one in
// deallocate. When the compiler supports the feature to overload
// new[] and delete[], the following two lines should be used
// instead.
//arr_ = new(heap_) T[maxLength_];
//usages_ = new(heap_) CollIndex[maxLength_];
arr_ = (T *)heap_->allocateMemory(sizeof(T) * ((size_t) maxLength_));
usages_ = (CollIndex *) heap_->allocateMemory(
sizeof(CollIndex) * ((size_t) maxLength_));
// To finish up, we copy uninitialized objects of type T into
// the newly-alloc'd space, so vtbl-pointers get set properly.
// (This is not always necessary, but it's a good idea in
// general!)
T temp;
for ( CollIndex i = 0 ; i < maxLength_ ; i++ )
memcpy ((void*)&arr_[i], (void*)&temp, sizeof(T)) ;
}
}
else
{
arr_ = NULL;
usages_ = NULL;
}
}
#ifdef __GNUC__
# if __GNUC__ * 100 + __GNUC_MINOR__ >= 404
// pop_options added in 4.4
# pragma GCC pop_options
# endif
#endif
template <class T> void NACollection<T>::clearFrom( CollIndex entry )
{
assert( entry >= FIRST_COLL_INDEX );
for (CollIndex i = entry; i < usedLength_; i++)
usages_[i] = UNUSED_COLL_ENTRY;
entries_ = entry;
usedLength_ = entry;
}
template <class T> T & NACollection<T>::rawEntry(CollIndex ix)
{
// resize, if index lies out of the allocated portion
if (ix >= maxLength_)
resize(ix + 1);
// adjust used part to contain ix
if (ix >= usedLength_)
{
for (CollIndex i = usedLength_; i <= ix; i++)
usages_[i] = UNUSED_COLL_ENTRY;
usedLength_ = ix + 1;
}
// if ix refers to a new entry, initialize its usage
if (usages_[ix] == UNUSED_COLL_ENTRY)
{
entries_++;
usages_[ix] = NULL_COLL_INDEX;
}
return arr_[ix];
}
template <class T>
CollIndex NACollection<T>::findUsage(const CollIndex &toFind)
{
for (CollIndex i = FIRST_COLL_INDEX; i < usedLength_; i++)
{
if (usages_[i] == toFind)
return i;
}
// return a "not found" indicator
return NULL_COLL_INDEX;
}
// For HSC, define these methods as inline methods in the Collections.h header file.
// -----------------------------------------------------------------------
// functions for the NASubCollection<T> template
// -----------------------------------------------------------------------
template <class T>
NASubCollection<T>::NASubCollection (NACollection<T> *superset,
NAMemory *heap
)
: builtin_ ( TRUE ),
entries_ ( 0 ),
heap_ ( (heap==NULL && superset!=NULL) ? superset->heap_ : heap ),
maxLength_( BuiltinSubsetWords ),
superset_ ( superset ),
wordSize_ ( BuiltinSubsetWords ),
lastStaleBit_(0)
{
CollIndex i = BuiltinSubsetWords;
WordAsBits * pBits = (WordAsBits*)(&sbits_[ 0 ]);
pBits_ = pBits;
do
{
*pBits++ = 0x0;
}
while (--i);
}
template <class T>
NASubCollection<T>::NASubCollection( const NASubCollection<T> &other,
NAMemory * heap
)
: builtin_ ( other.builtin_ ),
entries_ ( other.entries_ ),
heap_ ( (heap==NULL) ? other.heap_ : heap ),
maxLength_( other.maxLength_ ),
superset_ ( other.superset_ ),
wordSize_ ( other.wordSize_ ),
lastStaleBit_( other.lastStaleBit_ )
{
CollIndex i = maxLength_;
WordAsBits * pBits;
WordAsBits * pOtherBits = other.pBits_;
if (builtin_)
pBits_ = (WordAsBits*)(&sbits_[ 0 ]);
else
pBits_ = allocateBits( maxLength_ );
pBits = pBits_;
do
{
*pBits++ = *pOtherBits++;
}
while (--i);
}
template <class T>
NASubCollection<T>::~NASubCollection()
{
if (!builtin_)
deallocateBits();
}
template <class T>
void NASubCollection<T>::setHeap(CollHeap *heap)
{
assert( builtin_ );
heap_ = heap;
}
template <class T>
NABoolean NASubCollection<T>::contains( const NASubCollection<T> & other ) const
{
assert( superset_ == other.superset_ );
if (other.entries_)
{
CollIndex otherWords = other.wordSize_;
CollIndex commonWords = MINOF( wordSize_, otherWords );
CollIndex i = commonWords;
WordAsBits * pBits = pBits_;
WordAsBits * pOtherBits = other.pBits_;
WordAsBits w;
if (i)
{
do
{
w = *pBits++;
// for a word present in both, "other" mustn't have bits on that
// are off in word(i) (in other words, when ORing the two words,
// other must not cause any changes by having additional bits set)
if (w != (w LOR *pOtherBits++))
return( FALSE );
}
while (--i);
}
i = otherWords - commonWords;
if ((Lng32) i > 0)
{
do
{
// if "other" has any bits set that "this" doesn't have, return FALSE
if (*pOtherBits++)
return( FALSE );
}
while (--i);
}
}
return( TRUE );
}
template <class T>
NABoolean NASubCollection<T>::lastUsed(CollIndex &lastBit) const
{
CollIndex lastNonZeroWord = getWordSize() - 1;
// find last non-zero word -- the > 0 test is there to avoid wrapping
// in case CollIndex is an unsigned integer
while ((lastNonZeroWord > 0) && (word(lastNonZeroWord) == 0))
{
lastNonZeroWord--;
}
// at this point, we either found the last non-zero word or there
// are none
if (word(lastNonZeroWord) == 0)
return FALSE; // return; there are none
// we know we have the last non-zero word; find last set bit
lastBit =
(lastNonZeroWord << LogBitsPerWord) + BitsPerWord - 1;
while (!testBit(lastBit))
{
lastBit--;
}
return TRUE; // found the last set bit
}
template <class T>
NABoolean NASubCollection<T>::operator == ( const NASubCollection<T> & other ) const
{
assert( superset_ == other.superset_ );
if (other.entries_ != entries_)
return( FALSE );
else
{
if (other.entries_ == 0 && entries_ == 0)
return( TRUE );
}
CollIndex commonWords = MINOF( wordSize_, other.wordSize_ );
CollIndex i = commonWords;
WordAsBits * pBits = pBits_;
WordAsBits * pOtherBits = other.pBits_;
if (i)
{
//
// compare the common words.
//
do
{
if (*pBits++ != *pOtherBits++)
return( FALSE );
}
while (--i);
}
// if one of the bitmap arrays is longer, then it must contain zeroes.
i = wordSize_ - commonWords;
if ((Lng32) i > 0)
{
do
{
if (*pBits++)
return( FALSE );
}
while (--i);
}
else
{
i = other.wordSize_ - commonWords;
if ((Lng32) i > 0)
{
do
{
if (*pOtherBits++)
return( FALSE );
}
while (--i);
}
}
return( TRUE );
}
template <class T>
NASubCollection<T> & NASubCollection<T>::addSet( const NASubCollection<T> & other )
{
CollIndex maxWords = other.wordSize_;
assert( superset_ == other.superset_ );
if (other.entries_)
{
if (wordSize_ < maxWords)
extendWordSize( maxWords );
if (maxWords)
{
WordAsBits * pBits = pBits_;
WordAsBits * pOtherBits = other.pBits_;
if (entries_ == 0) // We can skip computing the entries.
{
do
{
*pBits++ |= *pOtherBits++;
}
while (--maxWords);
entries_ = other.entries_;
}
else
{
Lng32 entryCount = 0;
Lng32 trailingWords = (Lng32) (wordSize_ - maxWords);
do
{
*pBits |= *pOtherBits++;
entryCount += ones( *pBits++ );
}
while (--maxWords);
while (trailingWords-- > 0)
{
entryCount += ones( *pBits++ );
}
entries_ = entryCount;
}
}
}
if (other.lastStaleBit_ > lastStaleBit_)
lastStaleBit_ = other.lastStaleBit_;
return( *this );
}
template <class T>
NASubCollection<T> & NASubCollection<T>::intersectSet( const NASubCollection<T> & other )
{
assert( superset_ == other.superset_ );
if (entries_)
{
CollIndex commonWords = MINOF( wordSize_, other.wordSize_ );
CollIndex i = commonWords;
WordAsBits * pBits = pBits_;
if (i)
{
WordAsBits * pOtherBits = other.pBits_;
if (other.entries_)
{
Lng32 entryCount = 0;
do
{
*pBits &= *pOtherBits++;
entryCount += ones( *pBits++ );
}
while (--i);
entries_ = entryCount;
}
else
{
do
{
*pBits++ = 0x0;
}
while (--i);
entries_ = 0;
}
}
i = wordSize_ - commonWords;
if ((Lng32) i > 0)
{
do
{
*pBits++ = 0x0;
}
while (--i);
}
}
return( *this );
}
template <class T>
NASubCollection<T> & NASubCollection<T>::subtractSet( const NASubCollection<T> & other )
{
assert( superset_ == other.superset_ );
if (other.entries_ && entries_)
{
CollIndex commonWords = MINOF( wordSize_, other.wordSize_ );
if (commonWords)
{
Lng32 entryCount = 0;
CollIndex trailingWords = wordSize_ - commonWords;
WordAsBits * pBits = pBits_;
WordAsBits * pOtherBits = other.pBits_;
do
{
*pBits &= LNOT *pOtherBits++;
entryCount += ones( *pBits++ );
}
while (--commonWords);
while (trailingWords-- > 0)
{
entryCount += ones( *pBits++ );
}
entries_ = entryCount;
}
}
return( *this );
}
template <class T>
WordAsBits NASubCollection<T>::hash() const
{
CollIndex i = wordSize_;
WordAsBits result = 0x0;
WordAsBits * pBits = pBits_;
if (i && entries_)
{
do
{
result ^= *pBits++;
}
while (--i);
}
return( result );
}
template <class T>
NASubCollection<T> & NASubCollection<T>::complement()
{
// can only take the complement of a subset
assert(superset_ != NULL);
CollIndex maxWords;
CollIndex superSetSize = superset_->getSize();
resize(superSetSize);
maxWords = getWordSize();
// for each used entry in the superset, toggle the corresponding subset bit
for (Int32 i = 0; i < (Int32) superSetSize; i++)
{
if (superset_->getUsage(i) == UNUSED_COLL_ENTRY)
{
// a subset shouldn't have an element that's not part of
// the superset
assert(NOT testBit(i));
}
else
{
// is the element in the subset
if (testBit(i))
// yes, then delete it
subtractElement(i);
else
// no, then add it
addElement(i);
}
}
return *this;
}
// -----------------------------------------------------------------------
// functions for the NASet<T> template
// -----------------------------------------------------------------------
template <class T>
NASet<T>::~NASet()
{}
template <class T>
T & NASet<T>::operator [] (CollIndex i)
{
CollIndex userIndex;
CollIndex arrayIndex;
if (i >= this->entries())
ABORT("Set index exceeds # of entries");
if (userIndexCache_ <= i)
{
// start with the cached position
userIndex = userIndexCache_;
arrayIndex = arrayIndexCache_;
}
else
{
// start with the first occupied entry
userIndex = 0;
arrayIndex = 0;
// skip over unused entries
while (this->getUsage(arrayIndex) == UNUSED_COLL_ENTRY AND
arrayIndex < this->getSize())
arrayIndex ++;
}
// advance to the desired entry
while (userIndex < i)
{
userIndex++;
arrayIndex++;
// skip over unused entries
while (this->getUsage(arrayIndex) == UNUSED_COLL_ENTRY AND
arrayIndex < this->getSize())
arrayIndex ++;
}
// cache the results
userIndexCache_ = userIndex;
arrayIndexCache_ = arrayIndex;
return this->usedEntry(arrayIndex);
}
template <class T>
const T & NASet<T>::operator [] (CollIndex i) const
{
CollIndex userIndex = 0;
CollIndex arrayIndex = 0;
if (i >= this->entries())
ABORT("Set index exceeds # of entries");
// skip over unused entries
while (this->getUsage(arrayIndex) == UNUSED_COLL_ENTRY AND
arrayIndex < this->getSize())
arrayIndex ++;
// advance to the desired entry
while (userIndex < i)
{
userIndex++;
arrayIndex++;
// skip over unused entries
while (this->getUsage(arrayIndex) == UNUSED_COLL_ENTRY AND
arrayIndex < this->getSize())
arrayIndex ++;
}
return this->constEntry(arrayIndex);
}
template <class T>
NABoolean NASet<T>::operator==(const NASet<T> &other) const
{
CollIndex count = this->entries();
if (count != other.entries())
return FALSE;
for (CollIndex i = 0; i < count; i++)
{
if (NOT this->contains(other[i]))
return FALSE;
}
return TRUE;
}
// -----------------------------------------------------------------------
// functions for the NAList<T> template
// -----------------------------------------------------------------------
template <class T>
NAList<T>::~NAList()
{}
template <class T>
NAList<T> & NAList<T>::operator=(const NAList<T> &other)
{
if ( this != &other ) // avoid copy-self!
{
this->deallocate();
NACollection<T>::copy( (const NACollection<T>&) other);
first_ = other.first_;
last_ = other.last_;
userIndexCache_ = other.userIndexCache_;
arrayIndexCache_ = other.arrayIndexCache_;
}
return *this;
}
template <class T>
NABoolean NAList<T>::operator== (const NAList<T> &other) const
{
if (this->entries() != other.entries())
return FALSE;
for (CollIndex i = 0; i < this->entries(); i++)
{
if (NOT (at(i) == other.at(i)))
return FALSE;
}
return TRUE;
}
template <class T>
NABoolean NAList<T>::find(const T &elem, T &returnedElem) const
{
CollIndex foundIndex;
if ((foundIndex = NACollection<T>::find(elem)) == NULL_COLL_INDEX)
return FALSE;
else
{
returnedElem = this->constEntry(foundIndex);
return TRUE;
}
}
template <class T>
T & NAList<T>::operator [] (CollIndex i)
{
CollIndex userIndex;
CollIndex arrayIndex;
if (userIndexCache_ <= i)
{
// start with the cached position
userIndex = userIndexCache_;
arrayIndex = arrayIndexCache_;
}
else
{
// start with the first entry
userIndex = 0;
arrayIndex = first_;
}
while (userIndex < i)
{
userIndex++;
arrayIndex = this->getUsage(arrayIndex);
if (arrayIndex == NULL_COLL_INDEX)
ABORT("List index exceeds # of entries");
}
userIndexCache_ = userIndex;
arrayIndexCache_ = arrayIndex;
return this->usedEntry(arrayIndex);
}
template <class T>
const T & NAList<T>::operator [] (CollIndex i) const
{
CollIndex userIndex;
CollIndex arrayIndex;
if (userIndexCache_ <= i)
{
// start with the cached position
userIndex = userIndexCache_;
arrayIndex = arrayIndexCache_;
}
else
{
// start with the first entry
userIndex = 0;
arrayIndex = first_;
}
while (userIndex < i)
{
userIndex++;
arrayIndex = this->getUsage(arrayIndex);
if (arrayIndex == NULL_COLL_INDEX)
{
ABORT("List index exceeds # of entries");
}
}
// We cast away const-ness from _this_ so that we can update the 2
// IndexCache data members. Semantically, this is alright, since
// changing those 2 data members does not truly "modify" the NAList
// object. But we get a big performance benefit from this.
//
// Yes, if MSVC++ supported the mutable keyword reliably, this unusual
// cast would not be necessary.
NAList<T>* thisPtr = (NAList<T>*) this ;
thisPtr->userIndexCache_ = userIndex;
thisPtr->arrayIndexCache_ = arrayIndex;
return this->constEntry(arrayIndex);
}
template <class T>
CollIndex NAList<T>::removeCounted(const T &elem, const CollIndex desiredCount)
{
CollIndex actualCount = 0;
CollIndex curr = first_; // current entry
CollIndex pred = NULL_COLL_INDEX; // predecessor of current entry
while (curr != NULL_COLL_INDEX) {
if (this->usedEntry(curr) == elem) {
// ok, found (first) matching entry, now delete it
if (pred == NULL_COLL_INDEX)
// we have a new first element in the list
first_ = this->getUsage(curr);
else
// unlink this element from the list
this->setUsage(pred,this->getUsage(curr));
// delete the actual entry
NACollection<T>::remove(curr);
// take care of the last_ pointer
if (last_ == curr) last_ = pred;
if (++actualCount == desiredCount) break;
curr = pred;
}
// go to the next element
pred = curr;
curr = this->getUsage(curr);
}
// invalidate the cache if necessary
if (actualCount) invalidateCache();
return actualCount;
}
template <class T>
CollIndex NAList<T>::findArraysIndex(CollIndex i)
{
CollIndex userIndex;
CollIndex arrayIndex;
if (userIndexCache_ <= i)
{
// start with the cached position
userIndex = userIndexCache_;
arrayIndex = arrayIndexCache_;
}
else
{
// start with the first entry
userIndex = 0;
arrayIndex = first_;
}
while (userIndex < i)
{
userIndex++;
arrayIndex = this->getUsage(arrayIndex);
if (arrayIndex == NULL_COLL_INDEX)
ABORT("List index exceeds # of entries");
}
userIndexCache_ = userIndex;
arrayIndexCache_ = arrayIndex;
return arrayIndex;
}
template <class T>
CollIndex NAList<T>::findArraysIndex(CollIndex i) const
{
CollIndex userIndex;
CollIndex arrayIndex;
if (userIndexCache_ <= i)
{
// start with the cached position
userIndex = userIndexCache_;
arrayIndex = arrayIndexCache_;
}
else
{
// start with the first entry
userIndex = 0;
arrayIndex = first_;
}
while (userIndex < i)
{
userIndex++;
arrayIndex = this->getUsage(arrayIndex);
if (arrayIndex == NULL_COLL_INDEX)
ABORT("List index exceeds # of entries");
}
// We cast away const-ness from _this_ so that we can update the 2
// IndexCache data members. Semantically, this is alright, since
// changing those 2 data members does not truly "modify" the NAList
// object. But we get a big performance benefit from this.
//
// Yes, if MSVC++ supported the mutable keyword reliably, this unusual
// cast would not be necessary.
NAList<T>* thisPtr = (NAList<T>*) this ;
thisPtr->userIndexCache_ = userIndex;
thisPtr->arrayIndexCache_ = arrayIndex;
return arrayIndex;
}
// For HSC, define this method as an inline method in the Collections.h header file.
// A dumb but easy implementation for insert one LIST into another
template <class T>
void NAList<T>::insert(const NAList<T> &other)
{
CollIndex count = other.entries();
for (CollIndex i = 0; i < count; i++)
{
insert(other[i]);
} // for loop for iterating over members of the set
} // insert(LIST(T))
// For HSC, define this method as an inline method in the Collections.h header file.
template <class T>
NABoolean NAList<T>::getLast(T &elem)
{
if (this->entries() > 0)
{
// copy last element
elem = this->usedEntry(last_);
// remove the last element from the list
NACollection<T>::remove(last_);
// fix up the list pointers
if (first_ == last_)
first_ = last_ = NULL_COLL_INDEX;
else
{
last_ = this->findUsage(last_);
this->setUsage(last_, NULL_COLL_INDEX);
}
// invalidate the cache, if necessary
if (userIndexCache_ >= this->entries())
invalidateCache();
return TRUE;
}
else
return FALSE;
}
// -----------------------------------------------------------------------
// functions for the NAArray<T> template
// -----------------------------------------------------------------------
template <class T>
NABoolean NAArray<T>::operator ==(const NAArray<T> &other) const
{
if(this->entries() != other.entries())
return FALSE;
for(CollIndex i = 0; i < this->entries(); i++)
{
if(NOT(at(i) == other.at(i)))
return FALSE;
}
return TRUE;
}
// -----------------------------------------------------------------------
// functions for the NASubArray<T> template
// -----------------------------------------------------------------------
template <class T>
NASubArray<T>::~NASubArray()
{}
// ***********************************************************************
// functions for the Hash Dictionary
// ***********************************************************************
template <class K, class V>
NAHashBucketEntry<K,V>::~NAHashBucketEntry()
{
} // NAHashBucketEntry<K,V>::~NAHashBucketEntry()
template <class K, class V>
void NAHashBucketEntry<K,V>::clear(NABoolean deleteContents)
{
if (deleteContents)
{
delete key_;
delete value_;
}
} // NAHashBucketEntry<K,V>::clear()
template <class K, class V>
void NAHashBucketEntry<K,V>::display() const
{
printf("(%p,%p) ",key_, value_);
} // NAHashBucketEntry<K,V>::display()
template <class K, class V>
Int32 NAHashBucketEntry<K,V>::printStatistics(char *buf)
{
return sprintf(buf, "(0X%X,0X%X) ",key_, value_);
} // NAHashBucketEntry<K,V>::printStatistics()
// -----------------------------------------------------------------------
// NAHashBucket::NAHashBucket()
// -----------------------------------------------------------------------
template <class K, class V>
NAHashBucket<K,V>::NAHashBucket(const NAHashBucket<K,V> & other, NAMemory * heap)
: heap_( (heap==NULL) ? other.heap_ : heap )
,bucket_(other.bucket_)
{
} // NAHashBucket<K,V>::NAHashBucket()
template <class K, class V>
NAHashBucket<K,V>::~NAHashBucket()
{
clear(FALSE); // delete all hash bucket entries
} // NAHashBucket<K,V>::~NAHashBucket()
// -----------------------------------------------------------------------
// NAHashBucket::clear()
// -----------------------------------------------------------------------
template <class K, class V>
void NAHashBucket<K,V>::clear(NABoolean deleteContents)
{
CollIndex ne = bucket_.entries();
for (CollIndex index = 0; index < ne; index++)
{
bucket_[index]->clear(deleteContents);
delete bucket_[index];
}
bucket_.clear(); // clear list head
} // NAHashBucket<K,V>::clear()
// -----------------------------------------------------------------------
// NAHashBucket::contains()
// Making two separate contains() methods allows a hash dictionary with
// a value type for which we don't have a comparison operator
// -----------------------------------------------------------------------
template <class K, class V>
NABoolean NAHashBucket<K,V>::contains(const K* key) const
{
CollIndex ne = bucket_.entries();
for (CollIndex index = 0; index < ne; index++)
{
// ----------------------------------------------------------------
// Index a hash bucket entry.
// ----------------------------------------------------------------
NAHashBucketEntry<K,V>* bep = bucket_[index];
// ----------------------------------------------------------------
// Compare the stored key value with the given key value.
// ----------------------------------------------------------------
if (*bep->getKey() == * key) // NOTE: uses K::operator==()
{
return TRUE;
} // endif
} // end for
return FALSE;
} // NAHashBucket<K,V>::contains()
template <class K, class V>
NABoolean NAHashBucket<K,V>::contains(const K* key, const V* value) const
{
CollIndex ne = bucket_.entries();
for (CollIndex index = 0; index < ne; index++)
{
// ----------------------------------------------------------------
// Index a hash bucket entry.
// ----------------------------------------------------------------
NAHashBucketEntry<K,V>* bep = bucket_[index];
// ----------------------------------------------------------------
// Compare the stored key value with the given key value.
// ----------------------------------------------------------------
if (*bep->getKey() == * key) // NOTE: uses K::operator==()
{
if (value) // a value is also supplied
{
// --------------------------------------------------------
// Compare the stored value with the given value.
// --------------------------------------------------------
if (*bep->getValue() == * value) // NOTE: uses V::operator==()
return TRUE;
}
else // keys are equal
return TRUE;
} // endif
} // end for
return FALSE;
} // NAHashBucket<K,V>::contains()
// -----------------------------------------------------------------------
// NAHashBucket::display()
// -----------------------------------------------------------------------
template <class K, class V>
void NAHashBucket<K,V>::display() const
{
CollIndex ne = bucket_.entries();
if (ne > 0)
{
for (CollIndex index = 0; index < ne; index++)
{
bucket_[index]->display();
if (index > 0 AND (index/4* 4 == index)) printf("\n");
}
}
else
printf("*** empty ***\n");
} // NAHashBucket<K,V>::display()
// -----------------------------------------------------------------------
// NAHashBucket::printStatistics()
// -----------------------------------------------------------------------
template <class K, class V>
Int32 NAHashBucket<K,V>::printStatistics(char *buf)
{
CollIndex ne = bucket_.entries(); Int32 c = 0;
if (ne > 0) {
for (CollIndex index = 0; index < ne; index++) {
c += bucket_[index]->printStatistics(buf+c);
if (index > 0 AND (index/4* 4 == index))
c += sprintf(buf+c,"\n");
}
}
else {
c = sprintf(buf,"*** empty ***\n");
}
return c;
} // NAHashBucket<K,V>::printStatistics()
// -----------------------------------------------------------------------
// NAHashBucket::getFirstValue()
// -----------------------------------------------------------------------
template <class K, class V>
V* NAHashBucket<K,V>::getFirstValue(const K* key) const
{
CollIndex ne = bucket_.entries();
for (CollIndex index = 0; index < ne; index++)
{
// ----------------------------------------------------------------
// Index a hash bucket entry.
// ----------------------------------------------------------------
NAHashBucketEntry<K,V>* bep = bucket_[index];
// ----------------------------------------------------------------
// Compare the stored key value with the given key value.
// ----------------------------------------------------------------
if (*bep->getKey() == *key) // NOTE: uses K::operator==()
return bep->getValue();
} // end for
return NULL; // key not found in the hash dictionary
} // NAHashBucket<K,V>::getFirstValue()
// -----------------------------------------------------------------------
// NAHashBucket::getKeyValuePair()
// -----------------------------------------------------------------------
template <class K, class V>
void NAHashBucket<K,V>::getKeyValuePair(const K* key, const V* value,
NAHashBucket<K,V>& container) const
{
CollIndex ne = bucket_.entries();
if (key)
{ // a key is given
for (CollIndex index = 0; index < ne; index++)
{
// -------------------------------------------------------------
// Index a hash bucket entry.
// -------------------------------------------------------------
NAHashBucketEntry<K,V>* bep = bucket_[index];
// -------------------------------------------------------------
// Compare the stored key value with the given key value.
// -------------------------------------------------------------
if (*bep->getKey() == * key) // NOTE: uses K::operator==()
{
if (value) // a value is also supplied
{
// -----------------------------------------------------
// Compare the stored value with the given value.
// -----------------------------------------------------
if (*bep->getValue() == * value) // NOTE: uses V::operator==()
container.insert(bep->getKey(), bep->getValue());
}
else // keys are equal
container.insert(bep->getKey(), bep->getValue());
} // endif stored key == given key
} // end for
} // a key is given
else
{
// Return all hash bucket entries
for (CollIndex index = 0; index < ne; index++)
container.insert(bucket_[index]->getKey(), bucket_[index]->getValue());
}
} // NAHashBucket<K,V>::getKeyValuePair()
// -----------------------------------------------------------------------
// NAHashBucket::remove()
// -----------------------------------------------------------------------
template <class K, class V>
K* NAHashBucket<K,V>::remove(K* key)
{
CollIndex ne = bucket_.entries();
for (CollIndex index = 0; index < ne; index++)
{
// ----------------------------------------------------------------
// Index a hash bucket entry.
// ----------------------------------------------------------------
NAHashBucketEntry<K,V>* bep = bucket_[index];
// ----------------------------------------------------------------
// Compare the stored key value with the given key value.
// ----------------------------------------------------------------
if (*bep->getKey() == *key) // NOTE: uses K::operator==()
{
bucket_.removeAt(index);
delete bep;
return key;
}
} // end for
return NULL; // key not found in the hash dictionary
} // NAHashBucket<K,V>::remove()
// ----------------------------------------------------------------------
// NAHashDictionary constructor functions
// ----------------------------------------------------------------------
template <class K, class V>
NAHashDictionary<K,V>::NAHashDictionary(
// see long detailed comment in Collections.h about the hash function param.
ULng32 (*hashFunction)(const K &),
ULng32 hashSize,
NABoolean enforceUniqueness,
NAMemory* heap)
: heap_(heap),
hash_(hashFunction),
entries_(0),
enforceUniqueness_(enforceUniqueness)
{
createHashTable(hashSize);
}
template <class K, class V>
NAHashDictionary<K,V>::NAHashDictionary (const NAHashDictionary<K,V> & other,
NAMemory * heap)
: heap_( (heap==NULL) ? other.heap_ : heap ),
hash_(other.hash_),
entries_(other.entries_),
enforceUniqueness_(other.enforceUniqueness_)
{
createHashTable(other.hashSize_);
for (CollIndex index = 0; index < hashSize_; index++)
(*hashTable_)[index] = (*other.hashTable_)[index];
}
// ----------------------------------------------------------------------
// NAHashDictionary destructor function.
// ----------------------------------------------------------------------
template <class K, class V>
NAHashDictionary<K,V>::~NAHashDictionary()
{
for (CollIndex index = 0; index < hashSize_; index++)
delete (*hashTable_)[index];
delete hashTable_;
}
// ----------------------------------------------------------------------
// NAHashDictionary::clear()
// Deletes all entries in the hash buckets.
// Does not delete any key or value.
// Does not delete any hash bucket or the hash table.
// ----------------------------------------------------------------------
template <class K, class V>
void NAHashDictionary<K,V>::clear(NABoolean deleteContents)
{
for (ULng32 index = 0; index < hashSize_; index++)
(*hashTable_)[index]->clear(deleteContents);
entries_ = 0;
} // NAHashDictionary<K,V>::clear()
// ----------------------------------------------------------------------
// NAHashDictionary::createHashTable()
// Helper function for creating a hash table.
// ----------------------------------------------------------------------
template <class K, class V>
void NAHashDictionary<K,V>::createHashTable(ULng32 hashSize)
{
assert (hashSize > 0);
hashSize_ = hashSize;
hashTable_ = new(heap_) NAArray<NAHashBucket<K,V>* >(heap_,hashSize);
for (CollIndex index = 0; index < hashSize; index++)
hashTable_->insertAt(index, new(heap_) NAHashBucket<K,V>(heap_));
} // NAHashDictionary<K,V>::createHashTable()
// ----------------------------------------------------------------------
// NAHashDictionary::getHashCode()
// Function for generating a hash code
// ----------------------------------------------------------------------
template <class K, class V>
ULng32 NAHashDictionary<K,V>::getHashCode(const K& key) const
{
// use the key's hash method to get the hash value
// unsigned long hashValue = key.hash() % hashSize_;
//#else
ULng32 hashValue = hash_(key) % hashSize_;
//#endif
assert(hashValue < hashSize_);
return hashValue;
} // NAHashDictionary<K,V>::getHashCode()
// ----------------------------------------------------------------------
// NAHashDictionary::insert()
// ----------------------------------------------------------------------
template <class K, class V>
K* NAHashDictionary<K,V>::insert(K* key, V* value)
{
if (enforceUniqueness_ AND contains(key))
{
assert(enforceUniqueness_);
return NULL; // don't insert a duplicate key
}
(*hashTable_)[getHashCode(*key)]->insert(key, value);
entries_++;
return key;
} // NAHashDictionary<K,V>::insert()
// ----------------------------------------------------------------------
// NAHashDictionaryIterator::ctor()
// ----------------------------------------------------------------------
template <class K, class V>
NAHashDictionaryIterator<K,V>::NAHashDictionaryIterator (const NAHashDictionary<K,V> & dict,
const K* key,
const V* value)
: iterator_(dict.heap_)
{
if (key)
(*(dict.hashTable_))[dict.getHashCode(*key)]->getKeyValuePair(key,value,iterator_);
else
{
// iterate over all key value pairs in the hash table
for (CollIndex index = 0; index < dict.hashSize_; index++)
(*(dict.hashTable_))[index]->getKeyValuePair(key,value,iterator_) ;
}
// iterator_ now contains all the qualifying key value pairs
reset() ; // set the position so we're ready to iterate
} // NAHashDictionaryIterator<K,V>()
// ----------------------------------------------------------------------
// NAHashDictionaryIterator::copy ctor()
// ----------------------------------------------------------------------
template <class K, class V>
NAHashDictionaryIterator<K,V>::NAHashDictionaryIterator (const NAHashDictionaryIterator<K,V> & other, NAMemory * heap)
: iterator_(heap) // NB: we always put copies on the stmt heap
{
iterator_ = other.iterator_ ;
iteratorPosition_ = other.iteratorPosition_ ;
} // NAHashDictionaryIterator<K,V>() copy ctor()
// ----------------------------------------------------------------------
// ~NAHashDictionaryIterator()
// ----------------------------------------------------------------------
template <class K, class V>
NAHashDictionaryIterator<K,V>::~NAHashDictionaryIterator()
{
iterator_.clear() ;
reset() ;
} // ~NAHashDictionaryIterator<K,V>
// ----------------------------------------------------------------------
// NAHashDictionaryIterator::getNext()
// ----------------------------------------------------------------------
template <class K, class V>
void NAHashDictionaryIterator<K,V>::getNext(K*& key, V*& value)
{
if (iteratorPosition_ < iterator_.entries())
{
key = iterator_[iteratorPosition_]->getKey();
value = iterator_[iteratorPosition_]->getValue();
iteratorPosition_++ ;
}
else
{
// If the application has advanced the iterator beyond the number
// of entries, signal that there are no more keys and values.
key = NULL;
value = NULL;
}
} // NAHashDictionaryIterator<K,V>::getNext()
// ----------------------------------------------------------------------
// NAHashDictionary::remove()
// ----------------------------------------------------------------------
template <class K, class V>
K* NAHashDictionary<K,V>::remove(K* key)
{
K* removedKey = (*hashTable_)[getHashCode(*key)]->remove(key);
if (removedKey)
entries_--;
return removedKey;
} // NAHashDictionary<K,V>::remove()
// ----------------------------------------------------------------------
// NAHashDictionary::resize()
// ----------------------------------------------------------------------
template <class K, class V>
void NAHashDictionary<K,V>::resize(ULng32 newHashSize)
{
assert(newHashSize > 0);
// TODO -- if indeed this is dead code -- remove this method !
// This method is not used anywhere, and makes calls to undefined functions
// like iteratorCreate() and iteratorDestroy()
assert(FALSE);
} // NAHashDictionary<K,V>::resize()
// ----------------------------------------------------------------------
// NAHashDictionary::display()
// ----------------------------------------------------------------------
template <class K, class V>
void NAHashDictionary<K,V>::display() const
{
if (hashSize_ > 0)
{
for (CollIndex index = 0; index < hashSize_; index++)
{
printf("\nbucket[%d] : \n",index);
(*hashTable_)[index]->display();
}
}
else
printf("*** hash table is empty ***");
printf("\n");
} // NAHashDictionary<K,V>::display()
// ----------------------------------------------------------------------
// NAHashDictionary::printStatistics()
// ----------------------------------------------------------------------
template <class K, class V>
Int32 NAHashDictionary<K,V>::printStatistics(char *buf)
{
Int32 c = 0;
if (hashSize_ > 0) {
for (CollIndex index = 0; index < hashSize_; index++) {
c += sprintf(buf+c, "\nbucket[%d] : \n",index);
c += (*hashTable_)[index]->printStatistics(buf+c);
}
}
else
c = sprintf(buf,"*** hash table is empty ***");
c += sprintf(buf+c,"\n");
return c;
} // NAHashDictionary<K,V>::printStatistics()