dont allocate table space until its needed and remove leftover junk

This commit is contained in:
Jeff Hill
2002-02-06 02:06:08 +00:00
parent 497eb2d1c4
commit e7270cccb1

View File

@@ -78,7 +78,7 @@ template <class T, class ID> class resTableIter;
// located with a hash key of type ID.
//
// NOTES:
// 1) class T _must_ derive from class ID and also from class tsSLNode<T>
// 1) class T must derive from class ID and also from class tsSLNode<T>
//
// 2) If the "resTable::show (unsigned level)" member function is called then
// class T must also implement a "show (unsigned level)" member function which
@@ -93,19 +93,7 @@ template <class T, class ID> class resTableIter;
// // ID to hash index convert (see examples below)
// resTableIndex hash (unsigned nBitsHashIndex) const;
//
// 4) Classes of type ID must provide the following member functions
// (which will usually be static const inline for improved performance).
// They determine the minimum and maximum number of elements in the hash
// table. If minIndexBitWidth() == maxIndexBitWidth() then the hash table
// size is determined at compile time
//
// inline static const unsigned maxIndexBitWidth ();
// inline static const unsigned minIndexBitWidth ();
//
// max number of hash table elements = 1 << maxIndexBitWidth();
// min number of hash table elements = 1 << minIndexBitWidth();
//
// 5) Storage for identifier of type ID must persist until the item of type
// 4) Storage for identifier of type ID must persist until the item of type
// T is deleted from the resTable
//
template <class T, class ID>
@@ -123,24 +111,23 @@ public:
void traverse ( void (T::*pCB)() );
void traverseConst ( void (T::*pCB)() const ) const;
unsigned numEntriesInstalled () const;
//
// exceptions thrown
//
class epicsShareClass dynamicMemoryAllocationFailed {};
class epicsShareClass sizeExceedsMaxIndexWidth {};
void setTableSize ( const unsigned newTableSize );
private:
tsSLList < T > * pTable;
unsigned nextSplitIndex;
unsigned hashIxMask;
unsigned hashIxSplitMask;
unsigned nBitsHashIxSplitMask;
unsigned logBaseTwoTableSize;
unsigned nInUse;
resTableIndex hash ( const ID & idIn ) const;
T * find ( tsSLList<T> & list, const ID & idIn ) const;
T * findDelete ( tsSLList<T> & list, const ID & idIn );
void splitBucket ();
unsigned tableSize () const;
bool setTableSizePrivate ( unsigned logBaseTwoTableSize );
resTable ( const resTable & );
resTable & operator = ( const resTable & );
static unsigned resTableBitMask ( const unsigned nBits );
friend class resTableIter<T,ID>;
};
@@ -156,9 +143,9 @@ public:
T * next ();
T * operator () ();
private:
tsSLIter<T> iter;
unsigned index;
const resTable<T,ID> &table;
tsSLIter<T> iter;
unsigned index;
const resTable<T,ID> &table;
};
//
@@ -194,8 +181,6 @@ public:
bool operator == (const intId &idIn) const;
resTableIndex hash () const;
const T getId() const;
static const unsigned maxIndexBitWidth ();
static const unsigned minIndexBitWidth ();
protected:
T id;
};
@@ -219,9 +204,11 @@ class chronIntIdResTable : public resTable<ITEM, chronIntId> {
public:
chronIntIdResTable ();
virtual ~chronIntIdResTable ();
void add (ITEM &item);
void add ( ITEM & item );
private:
unsigned allocId;
chronIntIdResTable ( const chronIntIdResTable & );
chronIntIdResTable & operator = ( const chronIntIdResTable & );
};
//
@@ -236,6 +223,7 @@ public:
chronIntIdRes ();
private:
void setId (unsigned newId);
chronIntIdRes (const chronIntIdRes & );
};
//
@@ -252,12 +240,6 @@ public:
bool operator == (const stringId &idIn) const;
const char * resourceName() const; // return the pointer to the string
void show (unsigned level) const;
static const unsigned maxIndexBitWidth ();
static const unsigned minIndexBitWidth ();
//
// exceptions
//
class epicsShareClass dynamicMemoryAllocationFailed {};
private:
stringId & operator = ( const stringId & );
stringId ( const stringId &);
@@ -274,21 +256,15 @@ private:
// resTable::resTable ()
//
template <class T, class ID>
resTable<T,ID>::resTable () :
nextSplitIndex ( 0 ),
hashIxMask ( ( 1 << ID::minIndexBitWidth() ) - 1 ),
hashIxSplitMask ( ( 1 << ( ID::minIndexBitWidth() + 1 ) ) - 1 ),
nInUse ( 0 )
inline resTable<T,ID>::resTable () :
pTable ( 0 ), nextSplitIndex ( 0 ), hashIxMask ( 0 ),
hashIxSplitMask ( 0 ), nBitsHashIxSplitMask ( 0 ),
logBaseTwoTableSize ( 0 ), nInUse ( 0 ) {}
template <class T, class ID>
inline unsigned resTable<T,ID>::resTableBitMask ( const unsigned nBits )
{
unsigned newTableSize = this->hashIxSplitMask + 1;
this->pTable = ( tsSLList<T> * )
operator new ( newTableSize * sizeof ( tsSLList<T> ) );
if ( ! this->pTable ) {
throwWithLocation ( dynamicMemoryAllocationFailed () );
}
for ( unsigned i = 0u; i < newTableSize; i++ ) {
new ( &this->pTable[i] ) tsSLList<T>;
}
return ( 1 << nBits ) - 1;
}
//
@@ -297,22 +273,48 @@ resTable<T,ID>::resTable () :
// remove a res from the resTable
//
template <class T, class ID>
inline T * resTable<T,ID>::remove ( const ID &idIn )
T * resTable<T,ID>::remove ( const ID &idIn )
{
tsSLList<T> &list = this->pTable[ this->hash(idIn) ];
return this->findDelete ( list, idIn );
if ( this->pTable ) {
// search list for idIn and remove the first match
tsSLList<T> & list = this->pTable [ this->hash(idIn) ];
tsSLIter <T> pItem = list.firstIter ();
T *pPrev = 0;
while ( pItem.valid () ) {
const ID & id = *pItem;
if ( id == idIn ) {
if ( pPrev ) {
list.remove ( *pPrev );
}
else {
list.get ();
}
this->nInUse--;
break;
}
pPrev = pItem.pointer ();
pItem++;
}
return pItem.pointer ();
}
else {
return 0;
}
}
//
// resTable::lookup ()
//
// find an res in the resTable
//
template <class T, class ID>
inline T * resTable<T,ID>::lookup ( const ID &idIn ) const
{
tsSLList<T> &list = this->pTable[this->hash(idIn)];
return this->find (list, idIn);
if ( this->pTable ) {
tsSLList<T> & list = this->pTable [ this->hash ( idIn ) ];
return this->find ( list, idIn );
}
else {
return 0;
}
}
//
@@ -334,15 +336,15 @@ inline resTableIndex resTable<T,ID>::hash ( const ID & idIn ) const
//
template <class T, class ID>
void resTable<T,ID>::show ( unsigned level ) const
{
unsigned N = this->tableSize ();
{
const unsigned N = this->tableSize ();
printf ( "%u bucket hash table with %u items of type %s installed\n",
N, this->nInUse, typeid(T).name() );
{
if ( N ) {
tsSLList<T> * pList = this->pTable;
while ( pList < &this->pTable[N] ) {
while ( pList < & this->pTable[N] ) {
tsSLIter<T> pItem = pList->firstIter ();
while ( pItem.valid () ) {
tsSLIter<T> pNext = pItem;
@@ -355,12 +357,11 @@ void resTable<T,ID>::show ( unsigned level ) const
}
if ( level >=1u ) {
tsSLList <T> *pList = this->pTable;
double X = 0.0;
double XX = 0.0;
unsigned maxEntries = 0u;
for ( unsigned i = 0u; i < N; i++ ) {
tsSLIter<T> pItem = pList[i].firstIter ();
tsSLIter<T> pItem = this->pTable[i].firstIter ();
unsigned count = 0;
while ( pItem.valid () ) {
if ( level >= 3u ) {
@@ -389,14 +390,34 @@ void resTable<T,ID>::show ( unsigned level ) const
}
}
// self test
template <class T, class ID>
void resTable<T,ID>::verify () const
{
unsigned N = this->tableSize ();
const unsigned N = this->tableSize ();
if ( this->pTable ) {
assert ( this->nextSplitIndex <= this->hashIxMask + 1 );
assert ( this->hashIxMask );
assert ( this->hashIxMask == this->hashIxSplitMask >> 1 );
assert ( this->hashIxSplitMask );
assert ( this->nBitsHashIxSplitMask );
assert ( resTableBitMask ( this->nBitsHashIxSplitMask )
== this->hashIxSplitMask );
assert ( this->logBaseTwoTableSize );
assert ( this->nBitsHashIxSplitMask <= this->logBaseTwoTableSize );
}
else {
assert ( this->nextSplitIndex == 0 );
assert ( this->hashIxMask == 0 );
assert ( this->hashIxSplitMask == 0 );
assert ( this->nBitsHashIxSplitMask == 0 );
assert ( this->logBaseTwoTableSize == 0 );
}
unsigned total = 0u;
tsSLList <T> *pList = this->pTable;
for ( unsigned i = 0u; i < N; i++ ) {
tsSLIter<T> pItem = pList[i].firstIter ();
tsSLIter<T> pItem = this->pTable[i].firstIter ();
unsigned count = 0;
while ( pItem.valid () ) {
resTableIndex index = this->hash ( *pItem );
@@ -416,17 +437,15 @@ void resTable<T,ID>::verify () const
template <class T, class ID>
void resTable<T,ID>::traverse ( void (T::*pCB)() )
{
tsSLList<T> * pList = this->pTable;
unsigned N = this->tableSize ();
while ( pList < &this->pTable[N] ) {
tsSLIter<T> pItem = pList->firstIter ();
const unsigned N = this->tableSize ();
for ( unsigned i = 0u; i < N; i++ ) {
tsSLIter<T> pItem = this->pTable[i].firstIter ();
while ( pItem.valid () ) {
tsSLIter<T> pNext = pItem;
pNext++;
( pItem.pointer ()->*pCB ) ();
pItem = pNext;
}
pList++;
}
}
@@ -436,19 +455,16 @@ void resTable<T,ID>::traverse ( void (T::*pCB)() )
template <class T, class ID>
void resTable<T,ID>::traverseConst ( void (T::*pCB)() const ) const
{
const tsSLList<T> *pList;
pList = this->pTable;
unsigned N = this->tableSize ();
while ( pList < &this->pTable[N] ) {
tsSLIterConst<T> pItem = pList->firstIter ();
const unsigned N = this->tableSize ();
for ( unsigned i = 0u; i < N; i++ ) {
const tsSLList < T > & table = this->pTable[i];
tsSLIterConst<T> pItem = table.firstIter ();
while ( pItem.valid () ) {
tsSLIterConst<T> pNext = pItem;
pNext++;
( pItem.pointer ()->*pCB ) ();
pItem = pNext;
}
pList++;
}
}
@@ -459,9 +475,95 @@ inline unsigned resTable<T,ID>::numEntriesInstalled () const
}
template <class T, class ID>
unsigned resTable<T,ID>::tableSize () const
inline unsigned resTable<T,ID>::tableSize () const
{
return ( this->hashIxMask + 1 ) + this->nextSplitIndex;
if ( this->pTable ) {
return ( this->hashIxMask + 1 ) + this->nextSplitIndex;
}
else {
return 0;
}
}
// it will be more efficent to call this once prior to installing
// the first entry
template <class T, class ID>
void resTable<T,ID>::setTableSize ( const unsigned newTableSize )
{
if ( newTableSize == 0u ) {
return;
}
//
// count the number of bits in newTableSize and round up
// to the next power of two
//
unsigned newMask = newTableSize - 1;
unsigned nbits;
for ( nbits = 0; nbits < sizeof (newTableSize) * CHAR_BIT; nbits++ ) {
unsigned nBitsMask = resTableBitMask ( nbits );
if ( ( newMask & ~nBitsMask ) == 0){
break;
}
}
setTableSizePrivate ( nbits );
}
template <class T, class ID>
bool resTable<T,ID>::setTableSizePrivate ( unsigned logBaseTwoTableSize )
{
// dont shrink
if ( this->logBaseTwoTableSize >= logBaseTwoTableSize ) {
return true;
}
// dont allow ridiculously small tables
if ( logBaseTwoTableSize < 4 ) {
logBaseTwoTableSize = 4;
}
const unsigned newTableSize = 1 << logBaseTwoTableSize;
const unsigned oldTableSize = this->pTable ? 1 << this->logBaseTwoTableSize : 0;
const unsigned oldTableOccupiedSize = this->tableSize ();
tsSLList<T> * pNewTable = ( tsSLList<T> * )
operator new ( newTableSize * sizeof ( tsSLList<T> ), std::nothrow );
if ( ! pNewTable ) {
if ( ! this->pTable ) {
throw std::bad_alloc();
}
return false;
}
// run the constructors using placement new
unsigned i;
for ( i = 0u; i < oldTableOccupiedSize; i++ ) {
new ( &pNewTable[i] ) tsSLList<T> ( this->pTable[i] );
}
for ( i = oldTableOccupiedSize; i < newTableSize; i++ ) {
new ( &pNewTable[i] ) tsSLList<T>;
}
// Run the destructors explicitly. Currently this destructor is a noop.
// The Tornado II compiler and RedHat 6.2 will not compile ~tsSLList<T>() but
// since its a NOOP we can find an ugly workaround
# if ! defined (__GNUC__) || __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 92 )
for ( i = 0; i < oldTableSize; i++ ) {
this->pTable[i].~tsSLList<T>();
}
# endif
if ( ! this->pTable ) {
this->hashIxSplitMask = resTableBitMask ( logBaseTwoTableSize );
this->nBitsHashIxSplitMask = logBaseTwoTableSize;
this->hashIxMask = this->hashIxSplitMask >> 1;
this->nextSplitIndex = 0;
}
operator delete ( this->pTable );
this->pTable = pNewTable;
this->logBaseTwoTableSize = logBaseTwoTableSize;
return true;
}
template <class T, class ID>
@@ -471,34 +573,13 @@ void resTable<T,ID>::splitBucket ()
// (this results in only a memcpy overhead, but
// no hashing or entry redistribution)
if ( this->nextSplitIndex > this->hashIxMask ) {
unsigned oldTableSize = this->hashIxSplitMask + 1;
unsigned newTableSize = oldTableSize * 2;
tsSLList<T> *pNewTable = ( tsSLList<T> * )
operator new ( newTableSize * sizeof ( tsSLList<T> ), std::nothrow );
if ( ! pNewTable ) {
bool success = this->setTableSizePrivate ( this->nBitsHashIxSplitMask + 1 );
if ( ! success ) {
return;
}
unsigned oldTableOccupiedSize = ( this->hashIxMask + 1 ) + this->nextSplitIndex;
// run the constructors using placement new
unsigned i;
for ( i = 0u; i < oldTableOccupiedSize; i++ ) {
new ( &pNewTable[i] ) tsSLList<T> ( this->pTable[i] );
}
for ( i = oldTableOccupiedSize; i < newTableSize; i++ ) {
new ( &pNewTable[i] ) tsSLList<T>;
}
// Run the destructors explicitly. Currently this destructor is a noop.
// The Tornado II compiler and RedHat 6.2 will not compile ~tsSLList<T>() but
// since its a NOOP we can find an ugly workaround :-(
# if ! defined (__GNUC__) || __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 92 )
for ( i = 0; i < oldTableSize; i++ ) {
this->pTable[i].~tsSLList<T>();
}
# endif
operator delete ( this->pTable );
this->pTable = pNewTable;
this->hashIxMask = this->hashIxSplitMask;
this->hashIxSplitMask = newTableSize - 1;
this->nBitsHashIxSplitMask += 1;
this->hashIxSplitMask = resTableBitMask ( this->nBitsHashIxSplitMask );
this->hashIxMask = this->hashIxSplitMask >> 1;
this->nextSplitIndex = 0;
}
@@ -507,9 +588,8 @@ void resTable<T,ID>::splitBucket ()
this->nextSplitIndex++;
T *pItem = tmp.get();
while ( pItem ) {
resTableIndex index = this->hash(*pItem);
tsSLList<T> &list = this->pTable[index];
list.add ( *pItem );
resTableIndex index = this->hash ( *pItem );
this->pTable[index].add ( *pItem );
pItem = tmp.get();
}
}
@@ -517,13 +597,18 @@ void resTable<T,ID>::splitBucket ()
//
// add a res to the resTable
//
// (bad status on failure)
//
template <class T, class ID>
int resTable<T,ID>::add ( T &res )
{
if ( this->nInUse > this->tableSize() ) {
if ( ! this->pTable ) {
this->setTableSizePrivate ( 10 );
}
else if ( this->nInUse >= this->tableSize() ) {
this->splitBucket ();
tsSLList<T> &list = this->pTable[this->hash(res)];
if ( this->find ( list, res ) != 0 ) {
return -1;
}
}
tsSLList<T> &list = this->pTable[this->hash(res)];
if ( this->find ( list, res ) != 0 ) {
@@ -556,40 +641,6 @@ T *resTable<T,ID>::find ( tsSLList<T> &list, const ID &idIn ) const
return pItem.pointer ();
}
//
// findDelete
// searches from where the iterator points to the
// end of the list for idIn
//
// iterator points to the item found upon return
// (or NULL if nothing matching was found)
//
// removes the item if it finds it
//
template <class T, class ID>
T *resTable<T,ID>::findDelete ( tsSLList<T> &list, const ID &idIn )
{
tsSLIter <T> pItem = list.firstIter ();
T *pPrev = 0;
while ( pItem.valid () ) {
const ID &id = *pItem;
if ( id == idIn ) {
if ( pPrev ) {
list.remove ( *pPrev );
}
else {
list.get ();
}
this->nInUse--;
break;
}
pPrev = pItem.pointer ();
pItem++;
}
return pItem.pointer ();
}
//
// ~resTable<T,ID>::resTable()
//
@@ -627,7 +678,9 @@ inline resTable<T,ID> & resTable<T,ID>::operator = ( const resTable & )
//
template <class T, class ID>
inline resTableIter<T,ID>::resTableIter (const resTable<T,ID> &tableIn) :
iter ( tableIn.pTable[0].firstIter () ), index (1), table ( tableIn ) {}
iter ( tableIn.pTable ? tableIn.pTable[0].firstIter () :
tsSLList<T>::invalidIter() ),
index (1), table ( tableIn ) {}
//
// resTableIter<T,ID>::next ()
@@ -676,6 +729,17 @@ template <class ITEM>
inline chronIntIdResTable<ITEM>::chronIntIdResTable () :
resTable<ITEM, chronIntId> (), allocId(1u) {}
template <class ITEM>
inline chronIntIdResTable<ITEM>::chronIntIdResTable ( const chronIntIdResTable<ITEM> & ) :
resTable<ITEM, chronIntId> (), allocId(1u) {}
template <class ITEM>
inline chronIntIdResTable<ITEM> & chronIntIdResTable<ITEM>::
operator = ( const chronIntIdResTable<ITEM> & )
{
return *this;
}
//
// chronIntIdResTable<ITEM>::~chronIntIdResTable()
// (not inline because it is virtual)
@@ -752,25 +816,6 @@ inline const T intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::getId () const // X aCC
return this->id;
}
//
// const unsigned intId::minIndexBitWidth ()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline const unsigned intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::minIndexBitWidth () // X aCC 361
{
return MIN_INDEX_WIDTH;
}
//
// const unsigned intId::maxIndexBitWidth ()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline const unsigned intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::maxIndexBitWidth () // X aCC 361
{
return sizeof (resTableIndex) * CHAR_BIT;
}
//
// integerHash()
//
@@ -845,22 +890,6 @@ inline const char * stringId::resourceName () const
static const unsigned stringIdMinIndexWidth = CHAR_BIT;
static const unsigned stringIdMaxIndexWidth = sizeof ( unsigned );
//
// const unsigned stringId::minIndexBitWidth ()
//
inline const unsigned stringId::minIndexBitWidth ()
{
return stringIdMinIndexWidth;
}
//
// const unsigned stringId::maxIndexBitWidth ()
//
inline const unsigned stringId::maxIndexBitWidth ()
{
return stringIdMaxIndexWidth;
}
#ifdef instantiateRecourceLib
//
@@ -877,7 +906,7 @@ stringId::stringId (const char * idIn, allocationType typeIn) :
memcpy ((void *)this->pStr, idIn, nChars);
}
else {
throwWithLocation ( dynamicMemoryAllocationFailed () );
throw std::bad_alloc();
}
}
else {