diff --git a/src/cxxTemplates/resourceLib.h b/src/cxxTemplates/resourceLib.h index b38d02d51..5b3e97de2 100644 --- a/src/cxxTemplates/resourceLib.h +++ b/src/cxxTemplates/resourceLib.h @@ -1,6 +1,14 @@ /* * $Id$ * + * General hash table templates for fast indexing of resources + * of any base resource type and any resource identifier type. Fast + * indexing is implemented with a hash lookup. The identifier type + * implements the hash algorithm (or derives from one of the supplied + * identifier types which provide a hashing routine). + * + * Unsigned integer and string identifier classes are supplied here. + * * Author Jeffrey O. Hill * (string hash alg by Marty Kraimer and Peter K. Pearson) * @@ -29,87 +37,9 @@ * Argonne National Laboratory * * - * History - * $Log$ - * Revision 1.21 1999/01/29 22:51:09 jhill - * reinstalled const cast away - * - * Revision 1.20 1999/01/29 22:36:53 jhill - * removed const cast away - * - * Revision 1.19 1998/10/23 19:23:46 jhill - * fixed problem associated with deleting "const char *" - * on the solaris compiler - * - * Revision 1.18 1998/10/23 00:20:40 jhill - * attempted to clean up HP-UX warnings - * - * Revision 1.17 1998/06/16 03:00:19 jhill - * cleaned up fast string hash table - * - * Revision 1.16 1998/04/10 23:07:33 jhill - * fixed solaris architecture specific problem where xxx>>32 was ignored - * - * Revision 1.15 1998/02/05 23:25:19 jhill - * workaround vis c++ 5.0 bug - * - * Revision 1.14 1997/08/05 00:53:02 jhill - * changed some inline func to normal func - * - * Revision 1.13 1997/06/30 18:16:13 jhill - * guess at DEC C++ compiler bug workaround - * - * Revision 1.12 1997/06/25 05:48:39 jhill - * moved resourceLib.cc into resourceLib.h - * - * Revision 1.11 1997/06/13 18:26:13 jhill - * allow epicsAssert.h - * - * Revision 1.10 1997/06/13 09:21:51 jhill - * fixed compiler compatibility problems - * - * Revision 1.9 1997/04/23 17:11:15 jhill - * stringId::T[] => stringIdFastHash[] - * - * Revision 1.8 1997/04/10 19:43:09 jhill - * API changes - * - * Revision 1.7 1996/12/06 22:26:36 jhill - * added auto cleanup of installed classes to destroy - * - * Revision 1.6 1996/11/02 01:07:17 jhill - * many improvements - * - * Revision 1.5 1996/09/04 19:57:06 jhill - * string id resource now copies id - * - * Revision 1.4 1996/08/05 19:31:59 jhill - * fixed removes use of iter.cur() - * - * Revision 1.3 1996/07/25 17:58:16 jhill - * fixed missing ref in list decl - * - * Revision 1.2 1996/07/24 22:12:02 jhill - * added remove() to iter class + made node's prev/next private - * - * Revision 1.1.1.1 1996/06/20 22:15:55 jhill - * installed ca server templates - * - * * NOTES: * .01 Storage for identifier must persist until an item is deleted * .02 class T must derive from class ID and tsSLNode - * - * DESIGN NOTES: - * .01 These routines could be made to be significantly faster if the - * size of the hash table was a template parameter, and therefore - * known at compile time. However, there are many applications where - * the size of the hash table must be read in from a file or otherwise - * determined at runtime. The author does not see an easy way to - * provide both compile time and runtime determined hash table - * size without providing two nearly identical versions of these - * routines, and so has provided only runtime determined hash table - * size capabilities. * */ @@ -120,231 +50,236 @@ #include #include #include -#ifndef assert // allow use of epicsAssert.h -#include -#endif #include "tsSLList.h" #include "shareLib.h" -typedef int resLibStatus; -typedef unsigned resTableIndex; - -#define resTableIndexBitWidth (sizeof(resTableIndex)*CHAR_BIT) +typedef size_t resTableIndex; +static const unsigned indexWidth = sizeof(resTableIndex)*CHAR_BIT; // -// class T must derive from class ID and also from class tsSLNode +// class resTable // -// NOTE: Classes installed into this table should have -// a virtual destructor so that the delete in ~resTable() will -// work correctly. +// This class stores resource entires of type T which can be efficiently +// located with a hash key of type ID. +// +// +// NOTES: +// 1) class T _must_ derive from class ID and also from class tsSLNode +// +// 2) Classes of type T installed into this resTable must implement a +// "void destroy ()" method which is called by ~resTable() for each +// resource entry in the resTable. The destroy() method should at a minimum +// remove the resource from the resTable, and might also choose to (at your +// own discretion) "delete" the item itself. +// +// 3) If the "resTable::show (unsigned level)" member function is called then +// class T must also implemt a "show (unsigned level)" member function which +// dumps increasing diagnostics information with increasing "level" to +// standard out. +// +// 4) Classes of type ID must implement the following memeber functions: +// +// // equivalence test +// bool operator == (const ID &); +// +// // ID to hash index convert (see examples below) +// index hash (unsigned nBitsHashIndex) const; +// +// // +// // these determine the minimum and maximum number of elements +// // in the hash table. Knowing these parameters at compile +// // time improves performance. +// // +// // max = 1 << maxIndexBitWidth (); +// // min = 1 << minIndexBitWidth (); +// // +// unsigned minIndexBitWidth (); +// unsigned maxIndexBitWidth (); +// +// 3) Storage for identifier of type ID must persist until the item of type +// T is deleted from the resTable // template class resTable { public: - resTable() : - pTable(0), hashIdMask(0), hashIdNBits(0), nInUse(0) {} - int init(unsigned nHashTableEntries); + // + // exceptions thrown by this class + // + class resourceWithThatNameIsAlreadyInstalled {}; + class dynamicMemoryAllocationFailed {}; + class entryDidntRespondToDestroyVirtualFunction {}; + class sizeExceedsIndexesMaxIndexWith {}; + + resTable (unsigned nHashTableEntries); virtual ~resTable(); - // - // destroy all res in the table - // - void destroyAllEntries(); + void destroyAllEntries(); // destroy all entries // - // call T::show(level) for each res in the table + // Call (pT->show) (level) for each entry + // where pT is a pointer to type T. Show + // returns "void". Show dumps increasing + // diagnostics to std out with increasing + // magnitude of the its level argument. // void show (unsigned level) const; - // - // add a res to the table - // + // + // add entry + // + // returns -1 if the id already exits in the table + // and zero if successful + // int add (T &res); - // - // remove a res from the table - // - T *remove (const ID &idIn) - { - tsSLList &list = this->pTable[this->hash(idIn)]; - return this->findDelete(list, idIn); - } + T *remove (const ID &idIn); // remove entry - - // - // find an res in the table - // - T *lookup (const ID &idIn) - { - tsSLList &list = this->pTable[this->hash(idIn)]; - return this->find(list, idIn); - } + T *lookup (const ID &idIn) const; // locate entry #ifdef _MSC_VER // // required by MS vis c++ 5.0 (but not by 4.0) // - typedef void (T::*pResTableMFArg_t)(); -# define pResTableMFArg(ARG) pResTableMFArg_t ARG + typedef void (T::*pSetMFArg_t)(); +# define pSetMFArg(ARG) pSetMFArg_t ARG #else // // required by gnu g++ 2.7.2 // -# define pResTableMFArg(ARG) void (T:: * ARG)() +# define pSetMFArg(ARG) void (T:: * ARG)() #endif // - // Call (pT->*pCB) () for each item in the table + // Call (pT->*pCB) () for each entry // // where pT is a pointer to type T and pCB is // a pointer to a memmber function of T with // no parameters that returns void // - void traverse(pResTableMFArg(pCB)); + void traverse (pSetMFArg(pCB)) const; private: - tsSLList *pTable; - unsigned hashIdMask; - unsigned hashIdNBits; - unsigned nInUse; + tsSLList *pTable; + unsigned hashIdMask; + unsigned hashIdNBits; + unsigned nInUse; - resTableIndex hash(const ID & idIn) - { - return idIn.resourceHash(this->hashIdNBits) - & this->hashIdMask; - } + resTableIndex hash(const ID & idIn) const; - // - // find - // 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) - // - T *find (tsSLList &list, const ID &idIn); + T *find (tsSLList &list, const ID &idIn) const; - // - // 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 - // T *findDelete (tsSLList &list, const ID &idIn); }; +// +// resTableIntHash() +// +// converts any integer into a hash table index +// +// idWidth: the maximum number of ls bits in "id" which might +// be set during any given call be set. +// +// minIndexWidth: the minimum number of bits in a hash table +// index. This dermines the minimum size of the hash table. +// Knowing this value at compile time improves the performance +// of the hash. Set this parameter to zero if unsure of the +// correct minimum hash table size. +// +template +resTableIndex resTableIntHash (const T &id); + // // Some ID classes that work with the above template // - // -// unsigned identifier +// class intId // -class epicsShareClass uintId { +// signed or unsigned integer identifier +// +// this class works as type ID in resTable +// +// 1< +// +// 1< +// +// MIN_INDEX_WIDTH and MAX_ID_WIDTH are specified here at +// compile time so that the hash index can be produced +// efficently. Hash indexes are produced more efficiently +// when (MAX_ID_WIDTH - MIN_INDEX_WIDTH) is minimized. +// +template +class epicsShareClass intId { public: - uintId (unsigned idIn=UINT_MAX) : id(idIn) {} - virtual ~uintId(); - - int operator == (const uintId &idIn) - { - return this->id == idIn.id; - } - - // - // uintId::resourceHash() - // - resTableIndex resourceHash(unsigned nBitsId) const; - - const unsigned getId() const - { - return id; - } + intId (const T &idIn); + bool operator == (const intId &idIn) const; + resTableIndex hash (unsigned nBitsIndex) const; + const T getId() const; + static unsigned minIndexBitWidth (); + static unsigned maxIndexBitWidth (); protected: - unsigned id; + T id; }; - // -// special resource table which uses -// unsigned integer keys allocated in chronological sequence +// class chronIntIdResTable +// +// a specialized resTable which uses unsigned integer keys which are +// allocated in chronological sequence // -// NOTE: ITEM must public inherit from uintRes +// NOTE: ITEM must public inherit from chronIntIdRes // +typedef intId chronIntId; template -class uintResTable : public resTable { +class chronIntIdResTable : public resTable { public: - uintResTable() : allocId(1u) {} // hashing is faster close to zero - virtual ~uintResTable(); - - inline void installItem(ITEM &item); + chronIntIdResTable (unsigned nHashTableEntries); + virtual ~chronIntIdResTable (); + void add (ITEM &item); private: - unsigned allocId; + unsigned allocId; }; +// +// class chronIntIdRes // // resource with unsigned chronological identifier // template -class uintRes : public uintId, public tsSLNode { -friend class uintResTable; +class chronIntIdRes : public chronIntId, public tsSLNode { + friend class chronIntIdResTable; public: - uintRes(unsigned idIn=UINT_MAX) : uintId(idIn) {} - virtual ~uintRes(); + chronIntIdRes (); private: - // - // workaround for bug in DEC compiler - // - void setId(unsigned newId) {this->id = newId;} + void setId (unsigned newId); }; // -// character string identifier +// class stringId // -// NOTE: to be robust in situations where the new() -// in the constructor might fail a careful consumer -// of this class should check to see if the -// stringId::resourceName() below -// returns a valid (non--NULL) string pointer. -// Eventually an exception will be thrown if -// new fails (when this is portable). +// character string identifier // class epicsShareClass stringId { public: - enum allocationType {copyString, refString}; + // + // exceptions + // + class dynamicMemoryAllocationFailed {}; - // - // allocCopyString() - // - static inline char * allocCopyString(const char * const pStr) - { - char *pNewStr = new char [strlen(pStr)+1u]; - if (pNewStr) { - strcpy (pNewStr, pStr); - } - return pNewStr; - } + enum allocationType {copyString, refString}; // // stringId() constructor // - // Use typeIn==refString only if the string passed in will exist - // and remain constant during the entire lifespan of the stringId - // object. - // - stringId (char const * const idIn, allocationType typeIn=copyString) : - pStr(typeIn==copyString?allocCopyString(idIn):idIn), - allocType(typeIn) {} - virtual ~ stringId(); + stringId (const char * idIn, allocationType typeIn=copyString); + ~ stringId(); // // The hash algorithm is a modification of the algorithm described in @@ -352,68 +287,146 @@ public: // Communications of the ACM, June 1990 // The modifications were designed by Marty Kraimer // - resTableIndex resourceHash(unsigned nBitsId) const; + resTableIndex hash (unsigned nBitsIndex) const; - int operator == (const stringId &idIn) - { - if (this->pStr!=NULL && idIn.pStr!=NULL) { - return strcmp(this->pStr,idIn.pStr)==0; - } - else { - return 0u; // not equal - } - } + bool operator == (const stringId &idIn) const; - // - // return the pointer to the string - // (also used to test to see if "new()" - // failed in the constructor - // - const char * resourceName() - { - return this->pStr; - } + const char * resourceName() const; // return the pointer to the string + + void show (unsigned level) const; + + static unsigned minIndexBitWidth (); + + static unsigned maxIndexBitWidth (); - void show (unsigned level) const - { - if (level>2u) { - printf ("resource id = %s\n", this->pStr); - } - } private: - const char * const pStr; - allocationType const allocType; + const char * pStr; + const allocationType allocType; static const unsigned char stringIdFastHash[256]; }; +///////////////////////////////////////////// +// template functions +///////////////////////////////////////////// + // -// resTable::init() +// resTableIntHash() +// +// converts any integer into a hash table index +// +// idWidth: the maximum number of ls bits in "id" which might +// be set during any given call be set. +// +// minIndexWidth: the minimum number of bits in a hash table +// index. This dermines the minimum size of the hash table. +// Knowing this value at compile time improves the performance +// of the hash. Set this parameter to zero if unsure of the +// correct minimum hash table size. +// +template +inline resTableIndex resTableIntHash (const T &id) +{ + resTableIndex hashid = static_cast(id); + + // + // On most compilers the optimizer will unroll this loop so this + // is actually a very small inline function + // + // Experiments using the microsoft compiler show that this isnt + // slower than switching on the architecture size and urolling the + // loop explicitly (that solution has resulted in portability + // problems in the past). + // + unsigned width = idWidth; + do { + width >>= 1u; + hashid ^= hashid>>width; + } while (width>minIndexWidth); + + // + // the result here is always masked to the + // proper size after it is returned to the "resTable" class + // + return hashid; +} + +///////////////////////////////////////////////// +// resTable member functions +///////////////////////////////////////////////// + +// +// resTable::resTable (unsigned nHashTableEntries) // template -int resTable::init(unsigned nHashTableEntries) +resTable::resTable (unsigned nHashTableEntries) : + nInUse (0) { - unsigned nbits; - - if (nHashTableEntries<1u) { - return -1; - } + unsigned nbits, mask; // // count the number of bits in the hash index // - for (nbits=0; nbitshashIdMask = (1<hashIdMask) == 0){ + for (nbits=0; nbitshashIdNBits = nbits; - this->nInUse = 0u; - this->pTable = new tsSLList [this->hashIdMask+1u]; - if (!pTable) { - return -1; + + if ( nbits > ID::maxIndexBitWidth () ) { + throw sizeExceedsIndexesMaxIndexWith (); + } + + // + // it improves performance to round up to a + // minimum table size + // + if (nbitshashIdNBits = nbits; + this->hashIdMask = mask; + this->nInUse = 0u; + this->pTable = new tsSLList [1<pTable==0) { + throw dynamicMemoryAllocationFailed (); + } +} + +// +// resTable::remove () +// +// remove a res from the resTable +// +template +inline T * resTable::remove (const ID &idIn) +{ + tsSLList &list = this->pTable[this->hash(idIn)]; + return this->findDelete(list, idIn); +} + +// +// resTable::lookup () +// +// find an res in the resTable +// +template +inline T * resTable::lookup (const ID &idIn) const +{ + tsSLList &list = this->pTable[this->hash(idIn)]; + return this->find(list, idIn); +} + +// +// resTable::hash () +// +template +inline resTableIndex resTable::hash (const ID & idIn) const +{ + return idIn.hash(this->hashIdNBits) + & this->hashIdMask; } // @@ -441,12 +454,12 @@ void resTable::destroyAllEntries() // // Check to see if a defective class is // installed that does not remove itself - // from the table when it is destroyed. + // from the resTable when it is destroyed. // { tsSLIterRm iter(*pList); while ( (pItem=iter()) ) { - fprintf(stderr, + fprintf (stderr, "Warning: Defective class still in resTable after it was destroyed\n"); // // remove defective class @@ -505,7 +518,7 @@ void resTable::show (unsigned level) const mean = X/(this->hashIdMask+1); stdDev = sqrt(XX/(this->hashIdMask+1) - mean*mean); printf( - "entries/occupied table entry - mean = %f std dev = %f max = %d\n", + "entries/occupied resTable entry: mean = %f std dev = %f max = %d\n", mean, stdDev, maxEntries); } } @@ -514,9 +527,9 @@ void resTable::show (unsigned level) const // resTable::traverse // template -void resTable::traverse (pResTableMFArg(pCB)) +void resTable::traverse (pSetMFArg(pCB)) const { - tsSLList *pList; + tsSLList *pList; pList = this->pTable; while (pList < &this->pTable[this->hashIdMask+1]) { @@ -531,7 +544,9 @@ void resTable::traverse (pResTableMFArg(pCB)) } // -// add a res to the table +// add a res to the resTable +// +// (bad status on failure) // template int resTable::add (T &res) @@ -541,12 +556,14 @@ int resTable::add (T &res) // tsSLList &list = this->pTable[this->hash(res)]; - if (this->find(list, res) != 0) { + if ( this->find (list, res) != 0 ) { return -1; } - list.add(res); + + list.add (res); this->nInUse++; - return 0; + + return 0; } // @@ -558,7 +575,7 @@ int resTable::add (T &res) // (or NULL if nothing matching was found) // template -T *resTable::find (tsSLList &list, const ID &idIn) +T *resTable::find (tsSLList &list, const ID &idIn) const { tsSLIter iter(list); T *pItem; @@ -609,83 +626,206 @@ resTable::~resTable() { if (this->pTable) { this->destroyAllEntries(); - assert (this->nInUse == 0u); + if (this->nInUse != 0u) { + throw entryDidntRespondToDestroyVirtualFunction (); + } delete [] this->pTable; } } + +////////////////////////////////////////// +// chronIntIdResTable member functions +////////////////////////////////////////// + // -// uintResTable::~uintResTable() +// chronIntIdResTable::chronIntIdResTable() +// +template +inline chronIntIdResTable::chronIntIdResTable (unsigned nHashTableEntries) : + resTable (nHashTableEntries), + allocId(1u) {} // hashing is faster close to zero + +// +// chronIntIdResTable::~chronIntIdResTable() // (not inline because it is virtual) // template -uintResTable::~uintResTable() {} +chronIntIdResTable::~chronIntIdResTable() {} // -// uintRes::~uintRes() -// (not inline because it is virtual) -// -template -uintRes::~uintRes() {} - -// -// this needs to be instanciated only once (normally in libCom) -// -#ifdef instantiateRecourceLib -// -// uintId::resourceHash() -// -resTableIndex uintId::resourceHash(unsigned /* nBitsId */) const -{ - resTableIndex hashid = this->id; - - // - // This assumes worst case hash table index width of 1 bit. - // We will iterate this loop 5 times on a 32 bit architecture. - // - // A good optimizer will unroll this loop? - // Experiments using the microsoft compiler show that this isnt - // slower than switching on the architecture size and urolling the - // loop explicitly (that solution has resulted in portability - // problems in the past). - // - for (unsigned i=(CHAR_BIT*sizeof(unsigned))/2u; i>0u; i >>= 1u) { - hashid ^= (hashid>>i); - } - - // - // the result here is always masked to the - // proper size after it is returned to the resource class - // - return hashid; -} - -// -// uintResTable::~uintResTable() -// (not inline because it is virtual) -// -uintId::~uintId() {} - -#endif // instantiateRecourceLib - -// -// uintRes::installItem() +// chronIntIdResTable::add() // // NOTE: This detects (and avoids) the case where // the PV id wraps around and we attempt to have two // resources with the same id. // template -inline void uintResTable::installItem(ITEM &item) +inline void chronIntIdResTable::add (ITEM &item) { - int resTblStatus; - do { - item.uintRes::setId(allocId++); - resTblStatus = this->add(item); - } - while (resTblStatus); + int status; + do { + item.chronIntIdRes::setId (allocId++); + status = this->resTable::add (item); + } + while (status); } +///////////////////////////////////////////////// +// chronIntIdRes member functions +///////////////////////////////////////////////// + +// +// chronIntIdRes::chronIntIdRes +// +template +inline chronIntIdRes::chronIntIdRes () : chronIntId (UINT_MAX) {} + +// +// id::setId () +// +// workaround for bug in DEC compiler +// +template +inline void chronIntIdRes::setId (unsigned newId) +{ + this->id = newId; +} + +///////////////////////////////////////////////// +// intId member functions +///////////////////////////////////////////////// + +// +// intId::intId () +// +template +inline intId::intId (const T &idIn) + : id (idIn) {} + +// +// intId::operator == () +// +template +inline bool intId::operator == + (const intId &idIn) const +{ + return this->id == idIn.id; +} + +// +// intId::getId () +// +template +inline const T intId::getId () const +{ + return this->id; +} + +// +// intId::unsigned minIndexBitWidth () +// +template +inline unsigned intId::minIndexBitWidth () +{ + return MIN_INDEX_WIDTH; +} + +// +// intId::unsigned maxIndexBitWidth () +// +template +inline unsigned intId::maxIndexBitWidth () +{ + return MAX_ID_WIDTH; +} + +// +// intId::hash() +// +template +inline resTableIndex intId::hash (unsigned /* nBitsIndex */) const +{ + return resTableIntHash (this->id); +} + +//////////////////////////////////////////////////// +// stringId member functions +//////////////////////////////////////////////////// + +// +// stringId::stringId() +// +#ifdef instantiateRecourceLib +stringId::stringId (const char *idIn, allocationType typeIn) : + allocType (typeIn), pStr (idIn) +{ + if (typeIn==copyString) { + unsigned nChars = strlen (idIn) + 1u; + + this->pStr = new char [nChars]; + if (this->pStr!=0) { + memcpy ((void *)this->pStr, idIn, nChars); + } + else { + throw dynamicMemoryAllocationFailed (); + } + } + else { + this->pStr = idIn; + } +} +#endif // instantiateRecourceLib + +// +// stringId::operator == () +// +inline bool stringId::operator == (const stringId &idIn) const +{ + if (this->pStr!=NULL && idIn.pStr!=NULL) { + return strcmp(this->pStr,idIn.pStr)==0; + } + else { + return false; // not equal + } +} + +// +// stringId::resourceName () +// +inline const char * stringId::resourceName () const +{ + return this->pStr; +} + +// +// stringId::minIndexBitWidth () +// +inline unsigned stringId::minIndexBitWidth () +{ + return 8u; +} + +// +// stringId::maxIndexBitWidth () +// +inline unsigned stringId::maxIndexBitWidth () +{ + return sizeof (resTableIndex) * CHAR_BIT; +} + +// +// stringId::show () +// +#ifdef instantiateRecourceLib +void stringId::show (unsigned level) const +{ + if (level>2u) { + printf ("resource id = %s\n", this->pStr); + } +} +#endif // instantiateRecourceLib + // // stringId::~stringId() // @@ -724,14 +864,17 @@ stringId::~stringId() // #ifdef instantiateRecourceLib // -// stringId::resourceHash() +// stringId::hash() // // The hash algorithm is a modification of the algorithm described in // Fast Hashing of Variable Length Text Strings, Peter K. Pearson, // Communications of the ACM, June 1990 // The modifications were designed by Marty Kraimer // -resTableIndex stringId::resourceHash(unsigned nBitsId) const +// This needs to be modified so that it will work with wide characters. +// This will require run time generation of the table. +// +resTableIndex stringId::hash(unsigned nBitsIndex) const { if (this->pStr==NULL) { return 0u; @@ -760,8 +903,8 @@ resTableIndex stringId::resourceHash(unsigned nBitsId) const // does not work well for more than 65k entries ? // (because some indexes in the table will not be produced) // - if (nBitsId>=8u) { - h1 = h1 << (nBitsId-8u); + if (nBitsIndex>=8u) { + h1 = h1 << (nBitsIndex-8u); } return h1 ^ h0; } diff --git a/src/cxxTemplates/tsDLList.h b/src/cxxTemplates/tsDLList.h index 7e804c243..14767e388 100644 --- a/src/cxxTemplates/tsDLList.h +++ b/src/cxxTemplates/tsDLList.h @@ -28,322 +28,120 @@ * Advanced Photon Source * Argonne National Laboratory * - * - * History - * $Log$ - * Revision 1.15 1999/02/01 21:49:04 jhill - * removed redundant API - * - * Revision 1.14 1998/10/23 00:20:41 jhill - * attempted to clean up HP-UX warnings - * - * Revision 1.13 1998/06/16 03:01:44 jhill - * cosmetic - * - * Revision 1.12 1998/05/29 17:25:47 jhill - * allow use of epicsAssert.h - * - * Revision 1.11 1998/05/05 18:06:57 jhill - * rearranged to allow compilation by g++ 2.8.1 - * - * Revision 1.10 1998/02/05 23:28:21 jhill - * fixed hp sompiler warnings - * - * Revision 1.9 1997/06/13 09:21:52 jhill - * fixed compiler compatibility problems - * - * Revision 1.8 1997/04/11 20:49:48 jhill - * added no arg reset() to bwd iter - * - * Revision 1.7 1997/04/10 19:43:10 jhill - * API changes - * - * Revision 1.6 1997/01/22 21:13:49 jhill - * fixed class decl order for VMS - * - * Revision 1.5 1996/11/02 01:07:19 jhill - * many improvements - * - * Revision 1.4 1996/08/14 12:32:09 jbk - * added first() to list class, added first()/last() to iterator. - * - * Revision 1.3 1996/07/25 18:01:41 jhill - * use pointer (not ref) for list in iter class - * - * Revision 1.2 1996/07/24 22:12:03 jhill - * added remove() to iter class + made node's prev/next private - * - * Revision 1.1.1.1 1996/06/20 22:15:55 jhill - * installed ca server templates - * - * */ #ifndef tsDLListH_include #define tsDLListH_include -#ifndef assert // allow use of epicsAssert.h -#include -#endif - template class tsDLList; -template class tsDLIterBD; template class tsDLIter; template class tsDLFwdIter; template class tsDLBwdIter; +template class tsDLIterBD; // -// tsDLNode -// NOTE: T must derive from tsDLNode +// class tsDLNode +// +// a node in a doubly linked list +// +// NOTE: class T must derive from tsDLNode // template class tsDLNode { -friend class tsDLList; -friend class tsDLIterBD; -friend class tsDLIter; -friend class tsDLFwdIter; -friend class tsDLBwdIter; + friend class tsDLList; + friend class tsDLIter; + friend class tsDLFwdIter; + friend class tsDLBwdIter; + friend class tsDLIterBD; public: - tsDLNode() : pNext(0), pPrev(0) {} - // - // when someone copies in a class deriving from this - // do _not_ change the node pointers - // - void operator = (const tsDLNode &) {} - + tsDLNode(); + void operator = (const tsDLNode &) const; protected: - T *getNext(void) { return pNext; } - T *getPrev(void) { return pPrev; } + T *getNext(void) const; + T *getPrev(void) const; private: T *pNext; T *pPrev; }; // -// tsDLList -// NOTE: T must derive from tsDLNode +// class tsDLList +// +// a doubly linked list +// +// NOTE: class T must derive from tsDLNode // template class tsDLList { -friend class tsDLIter; -friend class tsDLFwdIter; -friend class tsDLBwdIter; -private: - // - // clear() - // - void clear() - { - this->pFirst = 0; - this->pLast = 0; - this->itemCount = 0u; - } - + friend class tsDLIter; + friend class tsDLFwdIter; + friend class tsDLBwdIter; public: - tsDLList () - { - clear(); - } + tsDLList (); // create empty list - // - // count() - // (returns the number of items on the list) - // - unsigned count() const - { - return this->itemCount; - } + unsigned count () const; // number of items on list - // - // add() - - // adds addList to the end of the list - // (and removes all items from addList) - // + void add (T &item); // add item to end of list + + // all Ts in addList added to end of list + // (addList left empty) void add (tsDLList &addList); - // - // add() - // (add an item to the end of the list) - // - void add (T &item); + void push (T &item); // add item to beginning of list - // - // get () - // - T * get(); - - // - // insertAfter() - // (place item in the list immediately after itemBefore) - // - void insertAfter (T &item, T &itemBefore); - - // - // insertBefore () - // (place item in the list immediately before itemAfter) - // - void insertBefore (T &item, T &itemAfter); - - // - // remove () - // + // remove item from list void remove (T &item); - // - // pop () - // (returns the first item on the list) - T * pop(); + T * get (); // removes first item on list + T * pop (); // same as get () - // - // push () - // (add an item at the beginning of the list) - // - void push (T &item); + // insert item in the list immediately after itemBefore + void insertAfter (T &item, T &itemBefore); + + // insert item in the list immediately before itemAfter) + void insertBefore (T &item, T &itemAfter); // - // find - // returns -1 if the item isnt on the list - // and the node number (beginning with zero if - // it is) + // returns -1 if the item isnt on the list and the node + // number (beginning with zero if it is) // - int find(T &item) const; + int find (T &item) const; - T *first(void) const { return this->pFirst; } - T *last(void) const { return this->pLast; } + T *first (void) const; // ptr to first item on list + T *last (void) const; // ptr to last item on list private: - T *pFirst; - T *pLast; - unsigned itemCount; + T *pFirst; + T *pLast; + unsigned itemCount; // - // past functionality incompatible - // with strict definition of a copy - // constructor so this has been eliminated + // create empty list + // (throw away any knowledge of current list) + // + void clear (); + // // copying one list item into another and // ending up with to list headers pointing // at the same list is always a questionable // thing to do. // - // therefore, this is intentionally _not_ - // implemented. + // therefore, this is intentionally private + // and _not_ implemented. // tsDLList (const tsDLList &); }; - -// -// tsDLIterBD -// (a bi-directional iterator in the style of the STL) -// -template -class tsDLIterBD { -public: - tsDLIterBD () : - pEntry(0) {} - - tsDLIterBD (T *pInitialEntry) : - pEntry(pInitialEntry) {} - - // - // This is apparently required by some compiler, causes - // trouble with MS Visual C 6.0, but should not be - // required by any compiler. I am assuming that the - // other compiler is a past version of MS Visual C. - // -# if defined(_MSC_VER) && _MSC_VER < 1200 - template - tsDLIterBD (const class tsDLIterBD ©In) : - pEntry(copyIn.pEntry) {} -# endif - - tsDLIterBD & operator = (T *pNewEntry) - { - this->pEntry = pNewEntry; - return *this; - } - - tsDLIterBD &operator = (const tsDLIterBD ©In) - { - this->pEntry = copyIn.pEntry; - return *this; - } - - int operator == (const tsDLIterBD &rhs) const - { - return (this->pEntry == rhs.pEntry); - } - - int operator != (const tsDLIterBD &rhs) const - { - return (this->pEntry != rhs.pEntry); - } - - T & operator * () const - { - return *this->pEntry; - } - - T * operator -> () const - { - return this->pEntry; - } - - operator T* () const - { - return this->pEntry; - } - - // - // prefix ++ - // - T *operator ++ () - { - tsDLNode *pNode = this->pEntry; - return this->pEntry = pNode->pNext; - } - - // - // postfix ++ - // - T *operator ++ (int) - { - T *pE = this->pEntry; - tsDLNode *pNode = this->pEntry; - this->pEntry = pNode->pNext; - return pE; - } - - // - // prefix -- - // - T *operator -- () - { - tsDLNode *pEntryNode = pEntry; - return this->pEntry = pEntryNode->pPrev; - } - - // - // postfix -- - // - T *operator -- (int) - { - T *pE = this->pEntry; - tsDLNode *pEntryNode = pEntry; - this->pEntry = pEntryNode->pPrev; - return pE; - } -private: - T *pEntry; -}; - // // tsDLIter // +// doubly linked list iterator +// // Notes: -// 2) This iterator does not allow for removal +// 1) +// This iterator does not allow for removal // of an item in order to avoid problems // resulting when we remove an item (and // then dont know whether to make pCurrent @@ -353,50 +151,23 @@ private: template class tsDLIter { public: - tsDLIter (tsDLList & listIn) : - pCurrent(0), pList(&listIn) {} - - void reset () - { - this->pCurrent = 0; - } - - void reset (tsDLList &listIn) - { - this->reset(); - this->pList = &listIn; - } - - void operator = (tsDLList &listIn) - { - this->reset(listIn); - } - + tsDLIter (tsDLList & listIn); + void reset (); + void reset (tsDLList &listIn); + void operator = (tsDLList &listIn); T * next (); - T * prev (); - - T * first() - { - this->pCurrent = this->pList->pFirst; - return this->pCurrent; - } - - T * last() - { - this->pCurrent = this->pList->pLast; - return this->pCurrent; - } - + T * first(); + T * last(); T * operator () (); protected: - T *pCurrent; - tsDLList *pList; + T *pCurrent; + tsDLList *pList; }; // -// tsDLFwdIter +// class tsDLFwdIter // // Notes: // 1) No direct access to pCurrent is provided since @@ -413,33 +184,13 @@ protected: template class tsDLFwdIter: private tsDLIter { public: - tsDLFwdIter (tsDLList &listIn) : - tsDLIter(listIn) {} - - void reset () - { - this->tsDLIter::reset(); - } - - void reset (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - - void operator = (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - + tsDLFwdIter (tsDLList &listIn); + void reset (); + void reset (tsDLList &listIn); + void operator = (tsDLList &listIn); T * operator () (); - T * next (); - - T * first() - { - tsDLIter &iterBase = *this; - return iterBase.first(); - } + T * first(); // // remove () @@ -471,33 +222,13 @@ public: template class tsDLBwdIter : private tsDLIter { public: - tsDLBwdIter(tsDLList &listIn) : - tsDLIter(listIn) {} - - void reset () - { - this->tsDLIter::reset(); - } - - void reset (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - - void operator = (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - + tsDLBwdIter (tsDLList &listIn); + void reset (); + void reset (tsDLList &listIn); + void operator = (tsDLList &listIn); T * operator () (); - T * prev (); - - T * last() - { - return this->tsDLIter::last(); - } - + T * last(); // // remove () // remove current item @@ -511,28 +242,150 @@ public: void remove (); }; + +// +// class tsDLIterBD +// +// bi-directional doubly linked list iterator +// +template +class tsDLIterBD { +public: + tsDLIterBD (T *pInitialEntry); + + tsDLIterBD operator = (T *pNewEntry); + + bool operator == (const tsDLIterBD &rhs) const; + bool operator != (const tsDLIterBD &rhs) const; + + T & operator * () const; + T * operator -> () const; + operator T* () const; + + tsDLIterBD operator ++ (); // prefix ++ + tsDLIterBD operator ++ (int); // postfix ++ + tsDLIterBD operator -- (); // prefix -- + tsDLIterBD operator -- (int); // postfix -- + +# if defined(_MSC_VER) && _MSC_VER < 1200 + tsDLIterBD (const class tsDLIterBD ©In); +# endif + + // + // end of the list constant + // + static const tsDLIterBD eol (); + +private: + T *pEntry; +}; + +/////////////////////////////////// +// tsDLNode member functions +/////////////////////////////////// + +// +// tsDLNode::tsDLNode () +// +template +inline tsDLNode::tsDLNode() : pNext(0), pPrev(0) {} + +// +// tsDLNode::operator = () +// +// when someone copies in a class deriving from this +// do _not_ change the node pointers +// +template +inline void tsDLNode::operator = (const tsDLNode &) const {} + +template +T * tsDLNode::getNext (void) const +{ + return pNext; +} + +template +T * tsDLNode::getPrev (void) const +{ + return pPrev; +} + +////////////////////////////////////// +// tsDLList member functions +////////////////////////////////////// + +// +// tsDLList::tsDLList () +// +template +inline tsDLList::tsDLList () +{ + this->clear (); +} + +// +// tsDLList::count () +// +// (returns the number of items on the list) +// +template +inline unsigned tsDLList::count () const +{ + return this->itemCount; +} + +// +// tsDLList::first () +// +template +inline T * tsDLList::first (void) const +{ + return this->pFirst; +} + +// +// tsDLList::last () +// +template +inline T *tsDLList::last (void) const +{ + return this->pLast; +} + +// +// tsDLList::clear () +// +template +inline void tsDLList::clear () +{ + this->pFirst = 0; + this->pLast = 0; + this->itemCount = 0u; +} + // // tsDLList::remove () // template void tsDLList::remove (T &item) { - tsDLNode &node = item; + tsDLNode &theNode = item; if (this->pLast == &item) { - this->pLast = node.pPrev; + this->pLast = theNode.pPrev; } else { - tsDLNode *pNextNode = node.pNext; - pNextNode->pPrev = node.pPrev; + tsDLNode &nextNode = *theNode.pNext; + nextNode.pPrev = theNode.pPrev; } if (this->pFirst == &item) { - this->pFirst = node.pNext; + this->pFirst = theNode.pNext; } else { - tsDLNode *pPrevNode = node.pPrev; - pPrevNode->pNext = node.pNext; + tsDLNode &prevNode = *theNode.pPrev; + prevNode.pNext = theNode.pNext; } this->itemCount--; @@ -555,6 +408,7 @@ inline T * tsDLList::get() // // tsDLList::pop () +// // (returns the first item on the list) template inline T * tsDLList::pop() @@ -563,7 +417,8 @@ inline T * tsDLList::pop() } // -// add() - +// tsDLList::add () +// // adds addList to the end of the list // (and removes all items from addList) // @@ -604,20 +459,21 @@ void tsDLList::add (tsDLList &addList) } // -// add() -// (add an item to the end of the list) +// tsDLList::add () +// +// add an item to the end of the list // template void tsDLList::add (T &item) { - tsDLNode &node = item; + tsDLNode &theNode = item; - node.pNext = 0; - node.pPrev = this->pLast; + theNode.pNext = 0; + theNode.pPrev = this->pLast; if (this->itemCount) { - tsDLNode *pLastNode = this->pLast; - pLastNode->pNext = &item; + tsDLNode &lastNode = *this->pLast; + lastNode.pNext = &item; } else { this->pFirst = &item; @@ -629,21 +485,22 @@ void tsDLList::add (T &item) } // -// insertAfter() -// (place item in the list immediately after itemBefore) +// tsDLList::insertAfter () +// +// place item in the list immediately after itemBefore // template void tsDLList::insertAfter (T &item, T &itemBefore) { - tsDLNode &node = item; + tsDLNode &nodeItem = item; tsDLNode &nodeBefore = itemBefore; - node.pPrev = &itemBefore; - node.pNext = nodeBefore.pNext; + nodeItem.pPrev = &itemBefore; + nodeItem.pNext = nodeBefore.pNext; nodeBefore.pNext = &item; - if (node.pNext) { - tsDLNode *pNextNode = node.pNext; + if (nodeItem.pNext) { + tsDLNode *pNextNode = nodeItem.pNext; pNextNode->pPrev = &item; } else { @@ -654,8 +511,9 @@ void tsDLList::insertAfter (T &item, T &itemBefore) } // -// insertBefore () -// (place item in the list immediately before itemAfter) +// tsDLList::insertBefore () +// +// place item in the list immediately before itemAfter // template void tsDLList::insertBefore (T &item, T &itemAfter) @@ -663,8 +521,8 @@ void tsDLList::insertBefore (T &item, T &itemAfter) tsDLNode &node = item; tsDLNode &nodeAfter = itemAfter; - node.pNext = &itemAfter; - node.pPrev = nodeAfter.pPrev; + tsDLNode.pNext = &itemAfter; + tsDLNode.pPrev = nodeAfter.pPrev; nodeAfter.pPrev = &item; if (node.pPrev) { @@ -679,15 +537,16 @@ void tsDLList::insertBefore (T &item, T &itemAfter) } // -// push () -// (add an item at the beginning of the list) +// tsDLList::push () +// +// add an item at the beginning of the list // template void tsDLList::push (T &item) { - tsDLNode &node = item; - node.pPrev = 0; - node.pNext = this->pFirst; + tsDLNode &theNode = item; + theNode.pPrev = 0; + theNode.pNext = this->pFirst; if (this->itemCount) { tsDLNode *pFirstNode = this->pFirst; @@ -702,11 +561,187 @@ void tsDLList::push (T &item) this->itemCount++; } +// +// tsDLList::find () +// returns -1 if the item isnt on the list +// and the node number (beginning with zero if +// it is) +// +template +int tsDLList::find (T &item) const +{ + tsDLFwdIter iter (*this); + tsDLNode *pItem; + int itemNo=0; + + while ( (pItem = iter.next()) ) { + if (pItem == &item) { + return itemNo; + } + itemNo++; + } + return -1; +} + +////////////////////////////////////////// +// tsDLIterBD member functions +////////////////////////////////////////// + +template +inline tsDLIterBD::tsDLIterBD (T * pInitialEntry) : + pEntry(pInitialEntry) {} + +// +// This is apparently required by some compiler, but +// only causes trouble with MS Visual C 6.0. This +// should not be required by any compiler. I am assuming +// that this "some compiler" is a past version of MS +// Visual C. +// +# if defined(_MSC_VER) && _MSC_VER < 1200 + template + tsDLIterBD::tsDLIterBD (const class tsDLIterBD ©In) : + pEntry(copyIn.pEntry) {} +# endif + +template +inline tsDLIterBD tsDLIterBD::operator = (T *pNewEntry) +{ + this->pEntry = pNewEntry; + return *this; +} + +template +inline bool tsDLIterBD::operator == (const tsDLIterBD &rhs) const +{ + return (this->pEntry == rhs.pEntry); +} + +template +inline bool tsDLIterBD::operator != (const tsDLIterBD &rhs) const +{ + return (this->pEntry != rhs.pEntry); +} + +template +inline T & tsDLIterBD::operator * () const +{ + return *this->pEntry; +} + +template +inline T * tsDLIterBD::operator -> () const +{ + return this->pEntry; +} + +template +inline tsDLIterBD::operator T* () const +{ + return this->pEntry; +} + +// +// prefix ++ +// +template +inline tsDLIterBD tsDLIterBD::operator ++ () +{ + tsDLNode &node = *this->pEntry; + this->pEntry = node.pNext; + return *this; +} + +// +// postfix ++ +// +template +inline tsDLIterBD tsDLIterBD::operator ++ (int) +{ + tsDLIterBD tmp = *this; + tsDLNode &node = *this->pEntry; + this->pEntry = node.pNext; + return tmp; +} + +// +// prefix -- +// +template +inline tsDLIterBD tsDLIterBD::operator -- () +{ + tsDLNode &entryNode = *pEntry; + this->pEntry = entryNode.pPrev; + return *this; +} + +// +// postfix -- +// +template +inline tsDLIterBD tsDLIterBD::operator -- (int) +{ + tsDLIterBD tmp = *this; + tsDLNode &entryNode = *pEntry; + this->pEntry = entryNode.pPrev; + return tmp; +} + +// +// tsDLIterBD::eol +// +template +inline const tsDLIterBD tsDLIterBD::eol () +{ + return tsDLIterBD(0); +} + +////////////////////////////////////////// +// tsDLIter member functions +////////////////////////////////////////// + +template +inline tsDLIter::tsDLIter (tsDLList & listIn) : + pCurrent(0), pList(&listIn) {} + +template +inline void tsDLIter::reset () +{ + this->pCurrent = 0; +} + +template +inline void tsDLIter::reset (tsDLList &listIn) +{ + this->reset(); + this->pList = &listIn; +} + +template +inline void tsDLIter::operator = (tsDLList &listIn) +{ + this->reset(listIn); +} + +template +inline T * tsDLIter::first() +{ + this->pCurrent = this->pList->pFirst; + return this->pCurrent; +} + +template +inline T * tsDLIter::last() +{ + this->pCurrent = this->pList->pLast; + return this->pCurrent; +} + // // tsDLIter::next () // template -T * tsDLIter::next () +inline T * tsDLIter::next () { T *pCur = this->pCurrent; if (pCur==0) { @@ -724,7 +759,7 @@ T * tsDLIter::next () // tsDLIter::prev () // template -T * tsDLIter::prev () +inline T * tsDLIter::prev () { T *pCur = this->pCurrent; if (pCur==0) { @@ -747,8 +782,41 @@ inline T * tsDLIter::operator () () return this->next(); } +/////////////////////////////////////////// +// tsDLBwdIter member functions +/////////////////////////////////////////// + +template +inline tsDLBwdIter::tsDLBwdIter(tsDLList &listIn) : + tsDLIter(listIn) {} + +template +inline void tsDLBwdIter::reset () +{ + this->tsDLIter::reset(); +} + +template +inline void tsDLBwdIter::reset (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline void tsDLBwdIter::operator = (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline T * tsDLBwdIter::last() +{ + return this->tsDLIter::last(); +} + // -// remove () +// tsDLBwdIter::remove () +// // remove current item // (and move current to be the item // pointed to by pNext - the item seen @@ -803,6 +871,39 @@ inline T * tsDLBwdIter::prev () return this->tsDLIter::prev(); } +////////////////////////////////////////// +// tsDLFwdIter member functions +////////////////////////////////////////// + +template +inline tsDLFwdIter::tsDLFwdIter (tsDLList &listIn) : + tsDLIter(listIn) {} + +template +inline void tsDLFwdIter::reset () +{ + this->tsDLIter::reset(); +} + +template +inline void tsDLFwdIter::reset (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline void tsDLFwdIter::operator = (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline T * tsDLFwdIter::first() +{ + tsDLIter &iterBase = *this; + return iterBase.first(); +} + // // tsDLFwdIter::remove () // (and move current to be the item @@ -851,27 +952,5 @@ inline T * tsDLFwdIter::operator () () return this->next(); } -// -// tsDLList::find () -// returns -1 if the item isnt on the list -// and the node number (beginning with zero if -// it is) -// -template -int tsDLList::find(T &item) const -{ - tsDLFwdIter iter(*this); - tsDLNode *pItem; - int itemNo=0; - - while ( (pItem = iter.next()) ) { - if (pItem == &item) { - return itemNo; - } - itemNo++; - } - return -1; -} - #endif // tsDLListH_include diff --git a/src/cxxTemplates/tsSLList.h b/src/cxxTemplates/tsSLList.h index 5f3db88e3..6ff98bb74 100644 --- a/src/cxxTemplates/tsSLList.h +++ b/src/cxxTemplates/tsSLList.h @@ -1,7 +1,7 @@ /* * $Id$ * - * tsSLList - type safe singly linked list templates + * type safe singly linked list templates * * Author Jeffrey O. Hill * johill@lanl.gov @@ -28,58 +28,8 @@ * Advanced Photon Source * Argonne National Laboratory * - * - * History - * $Log$ - * Revision 1.14 1998/10/23 16:40:47 jhill - * fixed missing new line at EOF - * - * Revision 1.13 1998/10/23 00:20:41 jhill - * attempted to clean up HP-UX warnings - * - * Revision 1.12 1998/06/16 03:03:07 jhill - * eliminated dangling ptr warning from bounds checker - * - * Revision 1.11 1998/05/05 18:06:58 jhill - * rearranged to allow compilation by g++ 2.8.1 - * - * Revision 1.10 1998/02/18 22:53:13 jhill - * fixed gnu warning - * - * Revision 1.9 1998/02/05 23:28:21 jhill - * fixed hp sompiler warnings - * - * Revision 1.8 1997/06/13 09:21:53 jhill - * fixed compiler compatibility problems - * - * Revision 1.7 1997/04/10 19:43:10 jhill - * API changes - * - * Revision 1.6 1997/01/22 21:14:21 jhill - * fixed class decl order for VMS - * - * Revision 1.5 1996/11/02 01:07:20 jhill - * many improvements - * - * Revision 1.4 1996/09/04 19:57:07 jhill - * string id resource now copies id - * - * Revision 1.3 1996/07/25 18:01:42 jhill - * use pointer (not ref) for list in iter class - * - * Revision 1.2 1996/07/24 22:12:04 jhill - * added remove() to iter class + made node's prev/next private - * - * Revision 1.1.1.1 1996/06/20 22:15:55 jhill - * installed ca server templates - * - * */ -#ifndef assert // allow use of epicsAssert.h -#include -#endif - // // the hp compiler complains about parameterized friend // class that has not been declared without this? @@ -89,8 +39,8 @@ template class tsSLIter; template class tsSLIterRm; // -// tsSLNode<> -// NOTE: T must derive from tsSLNode +// tsSLNode +// NOTE: class T must derive from tsSLNode // template class tsSLNode { @@ -98,81 +48,39 @@ friend class tsSLList; friend class tsSLIter; friend class tsSLIterRm; public: - tsSLNode() : pNext(0) {} - // - // when someone copies into a class deriving from this - // do _not_ change the node pointers - // - void operator = (const tsSLNode &) {} + tsSLNode(); + + void operator = (const tsSLNode &) const; private: - T *pNext; - // - // removeNextItem () - // - // removes the item after this node - // - void removeNextItem () - { - T *pItem = this->pNext; - if (pItem) { - tsSLNode *pNode = pItem; - this->pNext = pNode->pNext; - } - } + void removeNextItem (); // removes the item after this node + + T *pNext; }; // -// tsSLList<> -// NOTE: T must derive from tsSLNode +// tsSLList +// NOTE: class T must derive from tsSLNode // template class tsSLList : public tsSLNode { public: + tsSLList (); // creates an empty list - // - // insert() - // (itemBefore might be the list header object and therefore - // will not always be of type T) - // - void insert (T &item, tsSLNode &itemBefore) - { - tsSLNode &node = item; - node.pNext = itemBefore.pNext; - itemBefore.pNext = &item; - } + void insert (T &item, tsSLNode &itemBefore); // insert after item before - // - // add() - // - void add (T &item) - { - this->insert (item, *this); - } + void add (T &item); // add to the beginning of the list - // - // get () - // - T * get() - { - tsSLNode *pThisNode = this; - T *pItem = pThisNode->pNext; - pThisNode->removeNextItem(); - return pItem; - } + T * get (); // remove from the beginning of the list - T * pop() - { - return get(); - } + T * pop (); // same as get - void push(T &item) - { - this->add(item); - } + void push (T &item); // same as add +private: + tsSLList (const tsSLList &); // intentionally _not_ implemented }; // @@ -181,25 +89,11 @@ public: template class tsSLIter { public: - tsSLIter(const tsSLList &listIn) : - pCurrent(0), list(listIn) {}; + tsSLIter (const tsSLList &listIn); - // - // move iterator forward - // - // NULL test here is inefficient, but it appears that some architectures - // (intel) dont like to cast a NULL pointer from a tsSLNode to a T even if - // tsSLNode is always a base class of a T. - // - T * next (); + T * next (); // move iterator forward - // - // move iterator forward - // - T * operator () () - { - return this->next(); - } + T * operator () (); // same as next () private: T *pCurrent; @@ -208,59 +102,24 @@ private: // // tsSLIterRm -// (A tsSLIter that allows removing a node) -// -// adds remove method (and does not construct -// with const list) -// -// tsSLIter isnt a base class because this -// requires striping const from pCurrent which could get -// us in trouble with a high quality -// optimizing compiler -// -// Notes: -// 1) No direct access to pCurrent is provided since -// this might allow for confusion when an item -// is removed (and pCurrent ends up pointing at -// an item that has been seen before) -// +// (An tsSLIter that allows removing a node) // template class tsSLIterRm { public: - tsSLIterRm(tsSLList &listIn) : - pPrevious(0), pCurrent(0), list(listIn) {}; // - // move iterator forward + // exceptions // - // NULL test here is inefficient, but it appears that some architectures - // (intel) dont like to cast a NULL pointer from a tsSLNode to a T even if - // tsSLNode is always a base class of a T. - // - T * next (); + class noCurrentItemInIterator {}; - // - // move iterator forward - // - T * operator () () - { - return this->next(); - } + tsSLIterRm (tsSLList &listIn); - // - // remove current node - // (and move current to be the previos item - - // the item seen by the iterator before the - // current one - this guarantee that the list - // will be accessed sequentially even if an item - // is removed) - // - // This cant be called twice in a row without moving - // the iterator to the next item. If there is - // no current item this function assert fails. - // - void remove (); + T * next (); // move iterator forward + + T * operator () (); // same as next () + + void remove (); // remove current node private: T *pPrevious; @@ -268,6 +127,122 @@ private: tsSLList &list; }; +////////////////////////////////////////// +// +// tsSLNode inline member functions +// +////////////////////////////////////////// + +// +// tsSLNode::tsSLNode +// +template +tsSLNode::tsSLNode() : pNext(0) {} + +// +// tsSLNode::operator = +// +// when someone copies into a class deriving from this +// do _not_ change the node pointers +// +template +inline void tsSLNode::operator = (const tsSLNode &) const {} + +// +// removeNextItem () +// +// removes the item after this node +// +template +inline void tsSLNode::removeNextItem () +{ + T *pItem = this->pNext; + if (pItem) { + tsSLNode *pNode = pItem; + this->pNext = pNode->pNext; + } +} + +////////////////////////////////////////// +// +// tsSLList inline memeber functions +// +////////////////////////////////////////// + +// +// tsSLList::tsSLList() +// create an empty list +// +template +inline tsSLList::tsSLList () +{ +} + +// +// tsSLList::insert() +// (itemBefore might be the list header object and therefore +// will not always be of type T) +// +template +inline void tsSLList::insert (T &item, tsSLNode &itemBefore) +{ + tsSLNode &node = item; + node.pNext = itemBefore.pNext; + itemBefore.pNext = &item; +} + +// +// tsSLList::add () +// +template +inline void tsSLList::add (T &item) +{ + this->insert (item, *this); +} + +// +// tsSLList::get () +// +template +inline T * tsSLList::get() +{ + tsSLNode *pThisNode = this; + T *pItem = pThisNode->pNext; + pThisNode->removeNextItem(); + return pItem; +} + +// +// tsSLList::pop () +// +template +inline T * tsSLList::pop() +{ + return this->get(); +} + +// +// tsSLList::push () +// +template +inline void tsSLList::push(T &item) +{ + this->add(item); +} + +////////////////////////////////////////// +// +// tsSLIter inline memeber functions +// +////////////////////////////////////////// + +// +// tsSLIter::tsSLIter +// +template +inline tsSLIter::tsSLIter (const tsSLList &listIn) : + pCurrent (0), list (listIn) {} + // // tsSLIter::next () // @@ -295,6 +270,43 @@ T * tsSLIter::next () return this->pCurrent; } +// +// move iterator forward +// +template +inline T * tsSLIter::operator () () +{ + return this->next(); +} + +////////////////////////////////////////// +// +// tsSLIterRm inline memeber functions +// +// adds remove method (and does not construct +// with const list) +// +// tsSLIter isnt a base class because this +// requires striping const from pCurrent which could get +// us in trouble with a high quality +// optimizing compiler +// +// Notes: +// 1) No direct access to pCurrent is provided since +// this might allow for confusion when an item +// is removed (and pCurrent ends up pointing at +// an item that has been seen before) +// +////////////////////////////////////////// + +// +// tsSLIterRm::tsSLIterRm () +// +template +inline tsSLIterRm::tsSLIterRm (tsSLList &listIn) : + pPrevious (0), pCurrent (0), list (listIn) {}; + + // // tsSLIterRm::next () // @@ -324,6 +336,15 @@ T * tsSLIterRm::next () return this->pCurrent; } +// +// move iterator forward +// +template +inline T * tsSLIterRm::operator () () +{ + return this->next(); +} + // // tsSLIterRm::remove () // @@ -336,12 +357,14 @@ T * tsSLIterRm::next () // // This cant be called twice in a row without moving // the iterator to the next item. If there is -// no current item this function assert fails. +// no current item this function throws an exception. // template void tsSLIterRm::remove () { - assert (this->pCurrent!=0); + if (this->pCurrent==0) { + throw noCurrentItemInIterator (); + } tsSLNode *pPrevNode; tsSLNode *pCurNode = this->pCurrent; @@ -349,10 +372,12 @@ void tsSLIterRm::remove () if (this->pPrevious==0) { pPrevNode = &this->list; // - // this assert fails if it is an attempt to + // fail if it is an attempt to // delete twice without moving the iterator // - assert (pPrevNode->pNext == this->pCurrent); + if (pPrevNode->pNext != this->pCurrent) { + throw noCurrentItemInIterator (); + } } else { pPrevNode = this->pPrevious; diff --git a/src/libCom/cxxTemplates/resourceLib.h b/src/libCom/cxxTemplates/resourceLib.h index b38d02d51..5b3e97de2 100644 --- a/src/libCom/cxxTemplates/resourceLib.h +++ b/src/libCom/cxxTemplates/resourceLib.h @@ -1,6 +1,14 @@ /* * $Id$ * + * General hash table templates for fast indexing of resources + * of any base resource type and any resource identifier type. Fast + * indexing is implemented with a hash lookup. The identifier type + * implements the hash algorithm (or derives from one of the supplied + * identifier types which provide a hashing routine). + * + * Unsigned integer and string identifier classes are supplied here. + * * Author Jeffrey O. Hill * (string hash alg by Marty Kraimer and Peter K. Pearson) * @@ -29,87 +37,9 @@ * Argonne National Laboratory * * - * History - * $Log$ - * Revision 1.21 1999/01/29 22:51:09 jhill - * reinstalled const cast away - * - * Revision 1.20 1999/01/29 22:36:53 jhill - * removed const cast away - * - * Revision 1.19 1998/10/23 19:23:46 jhill - * fixed problem associated with deleting "const char *" - * on the solaris compiler - * - * Revision 1.18 1998/10/23 00:20:40 jhill - * attempted to clean up HP-UX warnings - * - * Revision 1.17 1998/06/16 03:00:19 jhill - * cleaned up fast string hash table - * - * Revision 1.16 1998/04/10 23:07:33 jhill - * fixed solaris architecture specific problem where xxx>>32 was ignored - * - * Revision 1.15 1998/02/05 23:25:19 jhill - * workaround vis c++ 5.0 bug - * - * Revision 1.14 1997/08/05 00:53:02 jhill - * changed some inline func to normal func - * - * Revision 1.13 1997/06/30 18:16:13 jhill - * guess at DEC C++ compiler bug workaround - * - * Revision 1.12 1997/06/25 05:48:39 jhill - * moved resourceLib.cc into resourceLib.h - * - * Revision 1.11 1997/06/13 18:26:13 jhill - * allow epicsAssert.h - * - * Revision 1.10 1997/06/13 09:21:51 jhill - * fixed compiler compatibility problems - * - * Revision 1.9 1997/04/23 17:11:15 jhill - * stringId::T[] => stringIdFastHash[] - * - * Revision 1.8 1997/04/10 19:43:09 jhill - * API changes - * - * Revision 1.7 1996/12/06 22:26:36 jhill - * added auto cleanup of installed classes to destroy - * - * Revision 1.6 1996/11/02 01:07:17 jhill - * many improvements - * - * Revision 1.5 1996/09/04 19:57:06 jhill - * string id resource now copies id - * - * Revision 1.4 1996/08/05 19:31:59 jhill - * fixed removes use of iter.cur() - * - * Revision 1.3 1996/07/25 17:58:16 jhill - * fixed missing ref in list decl - * - * Revision 1.2 1996/07/24 22:12:02 jhill - * added remove() to iter class + made node's prev/next private - * - * Revision 1.1.1.1 1996/06/20 22:15:55 jhill - * installed ca server templates - * - * * NOTES: * .01 Storage for identifier must persist until an item is deleted * .02 class T must derive from class ID and tsSLNode - * - * DESIGN NOTES: - * .01 These routines could be made to be significantly faster if the - * size of the hash table was a template parameter, and therefore - * known at compile time. However, there are many applications where - * the size of the hash table must be read in from a file or otherwise - * determined at runtime. The author does not see an easy way to - * provide both compile time and runtime determined hash table - * size without providing two nearly identical versions of these - * routines, and so has provided only runtime determined hash table - * size capabilities. * */ @@ -120,231 +50,236 @@ #include #include #include -#ifndef assert // allow use of epicsAssert.h -#include -#endif #include "tsSLList.h" #include "shareLib.h" -typedef int resLibStatus; -typedef unsigned resTableIndex; - -#define resTableIndexBitWidth (sizeof(resTableIndex)*CHAR_BIT) +typedef size_t resTableIndex; +static const unsigned indexWidth = sizeof(resTableIndex)*CHAR_BIT; // -// class T must derive from class ID and also from class tsSLNode +// class resTable // -// NOTE: Classes installed into this table should have -// a virtual destructor so that the delete in ~resTable() will -// work correctly. +// This class stores resource entires of type T which can be efficiently +// located with a hash key of type ID. +// +// +// NOTES: +// 1) class T _must_ derive from class ID and also from class tsSLNode +// +// 2) Classes of type T installed into this resTable must implement a +// "void destroy ()" method which is called by ~resTable() for each +// resource entry in the resTable. The destroy() method should at a minimum +// remove the resource from the resTable, and might also choose to (at your +// own discretion) "delete" the item itself. +// +// 3) If the "resTable::show (unsigned level)" member function is called then +// class T must also implemt a "show (unsigned level)" member function which +// dumps increasing diagnostics information with increasing "level" to +// standard out. +// +// 4) Classes of type ID must implement the following memeber functions: +// +// // equivalence test +// bool operator == (const ID &); +// +// // ID to hash index convert (see examples below) +// index hash (unsigned nBitsHashIndex) const; +// +// // +// // these determine the minimum and maximum number of elements +// // in the hash table. Knowing these parameters at compile +// // time improves performance. +// // +// // max = 1 << maxIndexBitWidth (); +// // min = 1 << minIndexBitWidth (); +// // +// unsigned minIndexBitWidth (); +// unsigned maxIndexBitWidth (); +// +// 3) Storage for identifier of type ID must persist until the item of type +// T is deleted from the resTable // template class resTable { public: - resTable() : - pTable(0), hashIdMask(0), hashIdNBits(0), nInUse(0) {} - int init(unsigned nHashTableEntries); + // + // exceptions thrown by this class + // + class resourceWithThatNameIsAlreadyInstalled {}; + class dynamicMemoryAllocationFailed {}; + class entryDidntRespondToDestroyVirtualFunction {}; + class sizeExceedsIndexesMaxIndexWith {}; + + resTable (unsigned nHashTableEntries); virtual ~resTable(); - // - // destroy all res in the table - // - void destroyAllEntries(); + void destroyAllEntries(); // destroy all entries // - // call T::show(level) for each res in the table + // Call (pT->show) (level) for each entry + // where pT is a pointer to type T. Show + // returns "void". Show dumps increasing + // diagnostics to std out with increasing + // magnitude of the its level argument. // void show (unsigned level) const; - // - // add a res to the table - // + // + // add entry + // + // returns -1 if the id already exits in the table + // and zero if successful + // int add (T &res); - // - // remove a res from the table - // - T *remove (const ID &idIn) - { - tsSLList &list = this->pTable[this->hash(idIn)]; - return this->findDelete(list, idIn); - } + T *remove (const ID &idIn); // remove entry - - // - // find an res in the table - // - T *lookup (const ID &idIn) - { - tsSLList &list = this->pTable[this->hash(idIn)]; - return this->find(list, idIn); - } + T *lookup (const ID &idIn) const; // locate entry #ifdef _MSC_VER // // required by MS vis c++ 5.0 (but not by 4.0) // - typedef void (T::*pResTableMFArg_t)(); -# define pResTableMFArg(ARG) pResTableMFArg_t ARG + typedef void (T::*pSetMFArg_t)(); +# define pSetMFArg(ARG) pSetMFArg_t ARG #else // // required by gnu g++ 2.7.2 // -# define pResTableMFArg(ARG) void (T:: * ARG)() +# define pSetMFArg(ARG) void (T:: * ARG)() #endif // - // Call (pT->*pCB) () for each item in the table + // Call (pT->*pCB) () for each entry // // where pT is a pointer to type T and pCB is // a pointer to a memmber function of T with // no parameters that returns void // - void traverse(pResTableMFArg(pCB)); + void traverse (pSetMFArg(pCB)) const; private: - tsSLList *pTable; - unsigned hashIdMask; - unsigned hashIdNBits; - unsigned nInUse; + tsSLList *pTable; + unsigned hashIdMask; + unsigned hashIdNBits; + unsigned nInUse; - resTableIndex hash(const ID & idIn) - { - return idIn.resourceHash(this->hashIdNBits) - & this->hashIdMask; - } + resTableIndex hash(const ID & idIn) const; - // - // find - // 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) - // - T *find (tsSLList &list, const ID &idIn); + T *find (tsSLList &list, const ID &idIn) const; - // - // 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 - // T *findDelete (tsSLList &list, const ID &idIn); }; +// +// resTableIntHash() +// +// converts any integer into a hash table index +// +// idWidth: the maximum number of ls bits in "id" which might +// be set during any given call be set. +// +// minIndexWidth: the minimum number of bits in a hash table +// index. This dermines the minimum size of the hash table. +// Knowing this value at compile time improves the performance +// of the hash. Set this parameter to zero if unsure of the +// correct minimum hash table size. +// +template +resTableIndex resTableIntHash (const T &id); + // // Some ID classes that work with the above template // - // -// unsigned identifier +// class intId // -class epicsShareClass uintId { +// signed or unsigned integer identifier +// +// this class works as type ID in resTable +// +// 1< +// +// 1< +// +// MIN_INDEX_WIDTH and MAX_ID_WIDTH are specified here at +// compile time so that the hash index can be produced +// efficently. Hash indexes are produced more efficiently +// when (MAX_ID_WIDTH - MIN_INDEX_WIDTH) is minimized. +// +template +class epicsShareClass intId { public: - uintId (unsigned idIn=UINT_MAX) : id(idIn) {} - virtual ~uintId(); - - int operator == (const uintId &idIn) - { - return this->id == idIn.id; - } - - // - // uintId::resourceHash() - // - resTableIndex resourceHash(unsigned nBitsId) const; - - const unsigned getId() const - { - return id; - } + intId (const T &idIn); + bool operator == (const intId &idIn) const; + resTableIndex hash (unsigned nBitsIndex) const; + const T getId() const; + static unsigned minIndexBitWidth (); + static unsigned maxIndexBitWidth (); protected: - unsigned id; + T id; }; - // -// special resource table which uses -// unsigned integer keys allocated in chronological sequence +// class chronIntIdResTable +// +// a specialized resTable which uses unsigned integer keys which are +// allocated in chronological sequence // -// NOTE: ITEM must public inherit from uintRes +// NOTE: ITEM must public inherit from chronIntIdRes // +typedef intId chronIntId; template -class uintResTable : public resTable { +class chronIntIdResTable : public resTable { public: - uintResTable() : allocId(1u) {} // hashing is faster close to zero - virtual ~uintResTable(); - - inline void installItem(ITEM &item); + chronIntIdResTable (unsigned nHashTableEntries); + virtual ~chronIntIdResTable (); + void add (ITEM &item); private: - unsigned allocId; + unsigned allocId; }; +// +// class chronIntIdRes // // resource with unsigned chronological identifier // template -class uintRes : public uintId, public tsSLNode { -friend class uintResTable; +class chronIntIdRes : public chronIntId, public tsSLNode { + friend class chronIntIdResTable; public: - uintRes(unsigned idIn=UINT_MAX) : uintId(idIn) {} - virtual ~uintRes(); + chronIntIdRes (); private: - // - // workaround for bug in DEC compiler - // - void setId(unsigned newId) {this->id = newId;} + void setId (unsigned newId); }; // -// character string identifier +// class stringId // -// NOTE: to be robust in situations where the new() -// in the constructor might fail a careful consumer -// of this class should check to see if the -// stringId::resourceName() below -// returns a valid (non--NULL) string pointer. -// Eventually an exception will be thrown if -// new fails (when this is portable). +// character string identifier // class epicsShareClass stringId { public: - enum allocationType {copyString, refString}; + // + // exceptions + // + class dynamicMemoryAllocationFailed {}; - // - // allocCopyString() - // - static inline char * allocCopyString(const char * const pStr) - { - char *pNewStr = new char [strlen(pStr)+1u]; - if (pNewStr) { - strcpy (pNewStr, pStr); - } - return pNewStr; - } + enum allocationType {copyString, refString}; // // stringId() constructor // - // Use typeIn==refString only if the string passed in will exist - // and remain constant during the entire lifespan of the stringId - // object. - // - stringId (char const * const idIn, allocationType typeIn=copyString) : - pStr(typeIn==copyString?allocCopyString(idIn):idIn), - allocType(typeIn) {} - virtual ~ stringId(); + stringId (const char * idIn, allocationType typeIn=copyString); + ~ stringId(); // // The hash algorithm is a modification of the algorithm described in @@ -352,68 +287,146 @@ public: // Communications of the ACM, June 1990 // The modifications were designed by Marty Kraimer // - resTableIndex resourceHash(unsigned nBitsId) const; + resTableIndex hash (unsigned nBitsIndex) const; - int operator == (const stringId &idIn) - { - if (this->pStr!=NULL && idIn.pStr!=NULL) { - return strcmp(this->pStr,idIn.pStr)==0; - } - else { - return 0u; // not equal - } - } + bool operator == (const stringId &idIn) const; - // - // return the pointer to the string - // (also used to test to see if "new()" - // failed in the constructor - // - const char * resourceName() - { - return this->pStr; - } + const char * resourceName() const; // return the pointer to the string + + void show (unsigned level) const; + + static unsigned minIndexBitWidth (); + + static unsigned maxIndexBitWidth (); - void show (unsigned level) const - { - if (level>2u) { - printf ("resource id = %s\n", this->pStr); - } - } private: - const char * const pStr; - allocationType const allocType; + const char * pStr; + const allocationType allocType; static const unsigned char stringIdFastHash[256]; }; +///////////////////////////////////////////// +// template functions +///////////////////////////////////////////// + // -// resTable::init() +// resTableIntHash() +// +// converts any integer into a hash table index +// +// idWidth: the maximum number of ls bits in "id" which might +// be set during any given call be set. +// +// minIndexWidth: the minimum number of bits in a hash table +// index. This dermines the minimum size of the hash table. +// Knowing this value at compile time improves the performance +// of the hash. Set this parameter to zero if unsure of the +// correct minimum hash table size. +// +template +inline resTableIndex resTableIntHash (const T &id) +{ + resTableIndex hashid = static_cast(id); + + // + // On most compilers the optimizer will unroll this loop so this + // is actually a very small inline function + // + // Experiments using the microsoft compiler show that this isnt + // slower than switching on the architecture size and urolling the + // loop explicitly (that solution has resulted in portability + // problems in the past). + // + unsigned width = idWidth; + do { + width >>= 1u; + hashid ^= hashid>>width; + } while (width>minIndexWidth); + + // + // the result here is always masked to the + // proper size after it is returned to the "resTable" class + // + return hashid; +} + +///////////////////////////////////////////////// +// resTable member functions +///////////////////////////////////////////////// + +// +// resTable::resTable (unsigned nHashTableEntries) // template -int resTable::init(unsigned nHashTableEntries) +resTable::resTable (unsigned nHashTableEntries) : + nInUse (0) { - unsigned nbits; - - if (nHashTableEntries<1u) { - return -1; - } + unsigned nbits, mask; // // count the number of bits in the hash index // - for (nbits=0; nbitshashIdMask = (1<hashIdMask) == 0){ + for (nbits=0; nbitshashIdNBits = nbits; - this->nInUse = 0u; - this->pTable = new tsSLList [this->hashIdMask+1u]; - if (!pTable) { - return -1; + + if ( nbits > ID::maxIndexBitWidth () ) { + throw sizeExceedsIndexesMaxIndexWith (); + } + + // + // it improves performance to round up to a + // minimum table size + // + if (nbitshashIdNBits = nbits; + this->hashIdMask = mask; + this->nInUse = 0u; + this->pTable = new tsSLList [1<pTable==0) { + throw dynamicMemoryAllocationFailed (); + } +} + +// +// resTable::remove () +// +// remove a res from the resTable +// +template +inline T * resTable::remove (const ID &idIn) +{ + tsSLList &list = this->pTable[this->hash(idIn)]; + return this->findDelete(list, idIn); +} + +// +// resTable::lookup () +// +// find an res in the resTable +// +template +inline T * resTable::lookup (const ID &idIn) const +{ + tsSLList &list = this->pTable[this->hash(idIn)]; + return this->find(list, idIn); +} + +// +// resTable::hash () +// +template +inline resTableIndex resTable::hash (const ID & idIn) const +{ + return idIn.hash(this->hashIdNBits) + & this->hashIdMask; } // @@ -441,12 +454,12 @@ void resTable::destroyAllEntries() // // Check to see if a defective class is // installed that does not remove itself - // from the table when it is destroyed. + // from the resTable when it is destroyed. // { tsSLIterRm iter(*pList); while ( (pItem=iter()) ) { - fprintf(stderr, + fprintf (stderr, "Warning: Defective class still in resTable after it was destroyed\n"); // // remove defective class @@ -505,7 +518,7 @@ void resTable::show (unsigned level) const mean = X/(this->hashIdMask+1); stdDev = sqrt(XX/(this->hashIdMask+1) - mean*mean); printf( - "entries/occupied table entry - mean = %f std dev = %f max = %d\n", + "entries/occupied resTable entry: mean = %f std dev = %f max = %d\n", mean, stdDev, maxEntries); } } @@ -514,9 +527,9 @@ void resTable::show (unsigned level) const // resTable::traverse // template -void resTable::traverse (pResTableMFArg(pCB)) +void resTable::traverse (pSetMFArg(pCB)) const { - tsSLList *pList; + tsSLList *pList; pList = this->pTable; while (pList < &this->pTable[this->hashIdMask+1]) { @@ -531,7 +544,9 @@ void resTable::traverse (pResTableMFArg(pCB)) } // -// add a res to the table +// add a res to the resTable +// +// (bad status on failure) // template int resTable::add (T &res) @@ -541,12 +556,14 @@ int resTable::add (T &res) // tsSLList &list = this->pTable[this->hash(res)]; - if (this->find(list, res) != 0) { + if ( this->find (list, res) != 0 ) { return -1; } - list.add(res); + + list.add (res); this->nInUse++; - return 0; + + return 0; } // @@ -558,7 +575,7 @@ int resTable::add (T &res) // (or NULL if nothing matching was found) // template -T *resTable::find (tsSLList &list, const ID &idIn) +T *resTable::find (tsSLList &list, const ID &idIn) const { tsSLIter iter(list); T *pItem; @@ -609,83 +626,206 @@ resTable::~resTable() { if (this->pTable) { this->destroyAllEntries(); - assert (this->nInUse == 0u); + if (this->nInUse != 0u) { + throw entryDidntRespondToDestroyVirtualFunction (); + } delete [] this->pTable; } } + +////////////////////////////////////////// +// chronIntIdResTable member functions +////////////////////////////////////////// + // -// uintResTable::~uintResTable() +// chronIntIdResTable::chronIntIdResTable() +// +template +inline chronIntIdResTable::chronIntIdResTable (unsigned nHashTableEntries) : + resTable (nHashTableEntries), + allocId(1u) {} // hashing is faster close to zero + +// +// chronIntIdResTable::~chronIntIdResTable() // (not inline because it is virtual) // template -uintResTable::~uintResTable() {} +chronIntIdResTable::~chronIntIdResTable() {} // -// uintRes::~uintRes() -// (not inline because it is virtual) -// -template -uintRes::~uintRes() {} - -// -// this needs to be instanciated only once (normally in libCom) -// -#ifdef instantiateRecourceLib -// -// uintId::resourceHash() -// -resTableIndex uintId::resourceHash(unsigned /* nBitsId */) const -{ - resTableIndex hashid = this->id; - - // - // This assumes worst case hash table index width of 1 bit. - // We will iterate this loop 5 times on a 32 bit architecture. - // - // A good optimizer will unroll this loop? - // Experiments using the microsoft compiler show that this isnt - // slower than switching on the architecture size and urolling the - // loop explicitly (that solution has resulted in portability - // problems in the past). - // - for (unsigned i=(CHAR_BIT*sizeof(unsigned))/2u; i>0u; i >>= 1u) { - hashid ^= (hashid>>i); - } - - // - // the result here is always masked to the - // proper size after it is returned to the resource class - // - return hashid; -} - -// -// uintResTable::~uintResTable() -// (not inline because it is virtual) -// -uintId::~uintId() {} - -#endif // instantiateRecourceLib - -// -// uintRes::installItem() +// chronIntIdResTable::add() // // NOTE: This detects (and avoids) the case where // the PV id wraps around and we attempt to have two // resources with the same id. // template -inline void uintResTable::installItem(ITEM &item) +inline void chronIntIdResTable::add (ITEM &item) { - int resTblStatus; - do { - item.uintRes::setId(allocId++); - resTblStatus = this->add(item); - } - while (resTblStatus); + int status; + do { + item.chronIntIdRes::setId (allocId++); + status = this->resTable::add (item); + } + while (status); } +///////////////////////////////////////////////// +// chronIntIdRes member functions +///////////////////////////////////////////////// + +// +// chronIntIdRes::chronIntIdRes +// +template +inline chronIntIdRes::chronIntIdRes () : chronIntId (UINT_MAX) {} + +// +// id::setId () +// +// workaround for bug in DEC compiler +// +template +inline void chronIntIdRes::setId (unsigned newId) +{ + this->id = newId; +} + +///////////////////////////////////////////////// +// intId member functions +///////////////////////////////////////////////// + +// +// intId::intId () +// +template +inline intId::intId (const T &idIn) + : id (idIn) {} + +// +// intId::operator == () +// +template +inline bool intId::operator == + (const intId &idIn) const +{ + return this->id == idIn.id; +} + +// +// intId::getId () +// +template +inline const T intId::getId () const +{ + return this->id; +} + +// +// intId::unsigned minIndexBitWidth () +// +template +inline unsigned intId::minIndexBitWidth () +{ + return MIN_INDEX_WIDTH; +} + +// +// intId::unsigned maxIndexBitWidth () +// +template +inline unsigned intId::maxIndexBitWidth () +{ + return MAX_ID_WIDTH; +} + +// +// intId::hash() +// +template +inline resTableIndex intId::hash (unsigned /* nBitsIndex */) const +{ + return resTableIntHash (this->id); +} + +//////////////////////////////////////////////////// +// stringId member functions +//////////////////////////////////////////////////// + +// +// stringId::stringId() +// +#ifdef instantiateRecourceLib +stringId::stringId (const char *idIn, allocationType typeIn) : + allocType (typeIn), pStr (idIn) +{ + if (typeIn==copyString) { + unsigned nChars = strlen (idIn) + 1u; + + this->pStr = new char [nChars]; + if (this->pStr!=0) { + memcpy ((void *)this->pStr, idIn, nChars); + } + else { + throw dynamicMemoryAllocationFailed (); + } + } + else { + this->pStr = idIn; + } +} +#endif // instantiateRecourceLib + +// +// stringId::operator == () +// +inline bool stringId::operator == (const stringId &idIn) const +{ + if (this->pStr!=NULL && idIn.pStr!=NULL) { + return strcmp(this->pStr,idIn.pStr)==0; + } + else { + return false; // not equal + } +} + +// +// stringId::resourceName () +// +inline const char * stringId::resourceName () const +{ + return this->pStr; +} + +// +// stringId::minIndexBitWidth () +// +inline unsigned stringId::minIndexBitWidth () +{ + return 8u; +} + +// +// stringId::maxIndexBitWidth () +// +inline unsigned stringId::maxIndexBitWidth () +{ + return sizeof (resTableIndex) * CHAR_BIT; +} + +// +// stringId::show () +// +#ifdef instantiateRecourceLib +void stringId::show (unsigned level) const +{ + if (level>2u) { + printf ("resource id = %s\n", this->pStr); + } +} +#endif // instantiateRecourceLib + // // stringId::~stringId() // @@ -724,14 +864,17 @@ stringId::~stringId() // #ifdef instantiateRecourceLib // -// stringId::resourceHash() +// stringId::hash() // // The hash algorithm is a modification of the algorithm described in // Fast Hashing of Variable Length Text Strings, Peter K. Pearson, // Communications of the ACM, June 1990 // The modifications were designed by Marty Kraimer // -resTableIndex stringId::resourceHash(unsigned nBitsId) const +// This needs to be modified so that it will work with wide characters. +// This will require run time generation of the table. +// +resTableIndex stringId::hash(unsigned nBitsIndex) const { if (this->pStr==NULL) { return 0u; @@ -760,8 +903,8 @@ resTableIndex stringId::resourceHash(unsigned nBitsId) const // does not work well for more than 65k entries ? // (because some indexes in the table will not be produced) // - if (nBitsId>=8u) { - h1 = h1 << (nBitsId-8u); + if (nBitsIndex>=8u) { + h1 = h1 << (nBitsIndex-8u); } return h1 ^ h0; } diff --git a/src/libCom/cxxTemplates/tsDLList.h b/src/libCom/cxxTemplates/tsDLList.h index 7e804c243..14767e388 100644 --- a/src/libCom/cxxTemplates/tsDLList.h +++ b/src/libCom/cxxTemplates/tsDLList.h @@ -28,322 +28,120 @@ * Advanced Photon Source * Argonne National Laboratory * - * - * History - * $Log$ - * Revision 1.15 1999/02/01 21:49:04 jhill - * removed redundant API - * - * Revision 1.14 1998/10/23 00:20:41 jhill - * attempted to clean up HP-UX warnings - * - * Revision 1.13 1998/06/16 03:01:44 jhill - * cosmetic - * - * Revision 1.12 1998/05/29 17:25:47 jhill - * allow use of epicsAssert.h - * - * Revision 1.11 1998/05/05 18:06:57 jhill - * rearranged to allow compilation by g++ 2.8.1 - * - * Revision 1.10 1998/02/05 23:28:21 jhill - * fixed hp sompiler warnings - * - * Revision 1.9 1997/06/13 09:21:52 jhill - * fixed compiler compatibility problems - * - * Revision 1.8 1997/04/11 20:49:48 jhill - * added no arg reset() to bwd iter - * - * Revision 1.7 1997/04/10 19:43:10 jhill - * API changes - * - * Revision 1.6 1997/01/22 21:13:49 jhill - * fixed class decl order for VMS - * - * Revision 1.5 1996/11/02 01:07:19 jhill - * many improvements - * - * Revision 1.4 1996/08/14 12:32:09 jbk - * added first() to list class, added first()/last() to iterator. - * - * Revision 1.3 1996/07/25 18:01:41 jhill - * use pointer (not ref) for list in iter class - * - * Revision 1.2 1996/07/24 22:12:03 jhill - * added remove() to iter class + made node's prev/next private - * - * Revision 1.1.1.1 1996/06/20 22:15:55 jhill - * installed ca server templates - * - * */ #ifndef tsDLListH_include #define tsDLListH_include -#ifndef assert // allow use of epicsAssert.h -#include -#endif - template class tsDLList; -template class tsDLIterBD; template class tsDLIter; template class tsDLFwdIter; template class tsDLBwdIter; +template class tsDLIterBD; // -// tsDLNode -// NOTE: T must derive from tsDLNode +// class tsDLNode +// +// a node in a doubly linked list +// +// NOTE: class T must derive from tsDLNode // template class tsDLNode { -friend class tsDLList; -friend class tsDLIterBD; -friend class tsDLIter; -friend class tsDLFwdIter; -friend class tsDLBwdIter; + friend class tsDLList; + friend class tsDLIter; + friend class tsDLFwdIter; + friend class tsDLBwdIter; + friend class tsDLIterBD; public: - tsDLNode() : pNext(0), pPrev(0) {} - // - // when someone copies in a class deriving from this - // do _not_ change the node pointers - // - void operator = (const tsDLNode &) {} - + tsDLNode(); + void operator = (const tsDLNode &) const; protected: - T *getNext(void) { return pNext; } - T *getPrev(void) { return pPrev; } + T *getNext(void) const; + T *getPrev(void) const; private: T *pNext; T *pPrev; }; // -// tsDLList -// NOTE: T must derive from tsDLNode +// class tsDLList +// +// a doubly linked list +// +// NOTE: class T must derive from tsDLNode // template class tsDLList { -friend class tsDLIter; -friend class tsDLFwdIter; -friend class tsDLBwdIter; -private: - // - // clear() - // - void clear() - { - this->pFirst = 0; - this->pLast = 0; - this->itemCount = 0u; - } - + friend class tsDLIter; + friend class tsDLFwdIter; + friend class tsDLBwdIter; public: - tsDLList () - { - clear(); - } + tsDLList (); // create empty list - // - // count() - // (returns the number of items on the list) - // - unsigned count() const - { - return this->itemCount; - } + unsigned count () const; // number of items on list - // - // add() - - // adds addList to the end of the list - // (and removes all items from addList) - // + void add (T &item); // add item to end of list + + // all Ts in addList added to end of list + // (addList left empty) void add (tsDLList &addList); - // - // add() - // (add an item to the end of the list) - // - void add (T &item); + void push (T &item); // add item to beginning of list - // - // get () - // - T * get(); - - // - // insertAfter() - // (place item in the list immediately after itemBefore) - // - void insertAfter (T &item, T &itemBefore); - - // - // insertBefore () - // (place item in the list immediately before itemAfter) - // - void insertBefore (T &item, T &itemAfter); - - // - // remove () - // + // remove item from list void remove (T &item); - // - // pop () - // (returns the first item on the list) - T * pop(); + T * get (); // removes first item on list + T * pop (); // same as get () - // - // push () - // (add an item at the beginning of the list) - // - void push (T &item); + // insert item in the list immediately after itemBefore + void insertAfter (T &item, T &itemBefore); + + // insert item in the list immediately before itemAfter) + void insertBefore (T &item, T &itemAfter); // - // find - // returns -1 if the item isnt on the list - // and the node number (beginning with zero if - // it is) + // returns -1 if the item isnt on the list and the node + // number (beginning with zero if it is) // - int find(T &item) const; + int find (T &item) const; - T *first(void) const { return this->pFirst; } - T *last(void) const { return this->pLast; } + T *first (void) const; // ptr to first item on list + T *last (void) const; // ptr to last item on list private: - T *pFirst; - T *pLast; - unsigned itemCount; + T *pFirst; + T *pLast; + unsigned itemCount; // - // past functionality incompatible - // with strict definition of a copy - // constructor so this has been eliminated + // create empty list + // (throw away any knowledge of current list) + // + void clear (); + // // copying one list item into another and // ending up with to list headers pointing // at the same list is always a questionable // thing to do. // - // therefore, this is intentionally _not_ - // implemented. + // therefore, this is intentionally private + // and _not_ implemented. // tsDLList (const tsDLList &); }; - -// -// tsDLIterBD -// (a bi-directional iterator in the style of the STL) -// -template -class tsDLIterBD { -public: - tsDLIterBD () : - pEntry(0) {} - - tsDLIterBD (T *pInitialEntry) : - pEntry(pInitialEntry) {} - - // - // This is apparently required by some compiler, causes - // trouble with MS Visual C 6.0, but should not be - // required by any compiler. I am assuming that the - // other compiler is a past version of MS Visual C. - // -# if defined(_MSC_VER) && _MSC_VER < 1200 - template - tsDLIterBD (const class tsDLIterBD ©In) : - pEntry(copyIn.pEntry) {} -# endif - - tsDLIterBD & operator = (T *pNewEntry) - { - this->pEntry = pNewEntry; - return *this; - } - - tsDLIterBD &operator = (const tsDLIterBD ©In) - { - this->pEntry = copyIn.pEntry; - return *this; - } - - int operator == (const tsDLIterBD &rhs) const - { - return (this->pEntry == rhs.pEntry); - } - - int operator != (const tsDLIterBD &rhs) const - { - return (this->pEntry != rhs.pEntry); - } - - T & operator * () const - { - return *this->pEntry; - } - - T * operator -> () const - { - return this->pEntry; - } - - operator T* () const - { - return this->pEntry; - } - - // - // prefix ++ - // - T *operator ++ () - { - tsDLNode *pNode = this->pEntry; - return this->pEntry = pNode->pNext; - } - - // - // postfix ++ - // - T *operator ++ (int) - { - T *pE = this->pEntry; - tsDLNode *pNode = this->pEntry; - this->pEntry = pNode->pNext; - return pE; - } - - // - // prefix -- - // - T *operator -- () - { - tsDLNode *pEntryNode = pEntry; - return this->pEntry = pEntryNode->pPrev; - } - - // - // postfix -- - // - T *operator -- (int) - { - T *pE = this->pEntry; - tsDLNode *pEntryNode = pEntry; - this->pEntry = pEntryNode->pPrev; - return pE; - } -private: - T *pEntry; -}; - // // tsDLIter // +// doubly linked list iterator +// // Notes: -// 2) This iterator does not allow for removal +// 1) +// This iterator does not allow for removal // of an item in order to avoid problems // resulting when we remove an item (and // then dont know whether to make pCurrent @@ -353,50 +151,23 @@ private: template class tsDLIter { public: - tsDLIter (tsDLList & listIn) : - pCurrent(0), pList(&listIn) {} - - void reset () - { - this->pCurrent = 0; - } - - void reset (tsDLList &listIn) - { - this->reset(); - this->pList = &listIn; - } - - void operator = (tsDLList &listIn) - { - this->reset(listIn); - } - + tsDLIter (tsDLList & listIn); + void reset (); + void reset (tsDLList &listIn); + void operator = (tsDLList &listIn); T * next (); - T * prev (); - - T * first() - { - this->pCurrent = this->pList->pFirst; - return this->pCurrent; - } - - T * last() - { - this->pCurrent = this->pList->pLast; - return this->pCurrent; - } - + T * first(); + T * last(); T * operator () (); protected: - T *pCurrent; - tsDLList *pList; + T *pCurrent; + tsDLList *pList; }; // -// tsDLFwdIter +// class tsDLFwdIter // // Notes: // 1) No direct access to pCurrent is provided since @@ -413,33 +184,13 @@ protected: template class tsDLFwdIter: private tsDLIter { public: - tsDLFwdIter (tsDLList &listIn) : - tsDLIter(listIn) {} - - void reset () - { - this->tsDLIter::reset(); - } - - void reset (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - - void operator = (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - + tsDLFwdIter (tsDLList &listIn); + void reset (); + void reset (tsDLList &listIn); + void operator = (tsDLList &listIn); T * operator () (); - T * next (); - - T * first() - { - tsDLIter &iterBase = *this; - return iterBase.first(); - } + T * first(); // // remove () @@ -471,33 +222,13 @@ public: template class tsDLBwdIter : private tsDLIter { public: - tsDLBwdIter(tsDLList &listIn) : - tsDLIter(listIn) {} - - void reset () - { - this->tsDLIter::reset(); - } - - void reset (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - - void operator = (tsDLList &listIn) - { - this->tsDLIter::reset(listIn); - } - + tsDLBwdIter (tsDLList &listIn); + void reset (); + void reset (tsDLList &listIn); + void operator = (tsDLList &listIn); T * operator () (); - T * prev (); - - T * last() - { - return this->tsDLIter::last(); - } - + T * last(); // // remove () // remove current item @@ -511,28 +242,150 @@ public: void remove (); }; + +// +// class tsDLIterBD +// +// bi-directional doubly linked list iterator +// +template +class tsDLIterBD { +public: + tsDLIterBD (T *pInitialEntry); + + tsDLIterBD operator = (T *pNewEntry); + + bool operator == (const tsDLIterBD &rhs) const; + bool operator != (const tsDLIterBD &rhs) const; + + T & operator * () const; + T * operator -> () const; + operator T* () const; + + tsDLIterBD operator ++ (); // prefix ++ + tsDLIterBD operator ++ (int); // postfix ++ + tsDLIterBD operator -- (); // prefix -- + tsDLIterBD operator -- (int); // postfix -- + +# if defined(_MSC_VER) && _MSC_VER < 1200 + tsDLIterBD (const class tsDLIterBD ©In); +# endif + + // + // end of the list constant + // + static const tsDLIterBD eol (); + +private: + T *pEntry; +}; + +/////////////////////////////////// +// tsDLNode member functions +/////////////////////////////////// + +// +// tsDLNode::tsDLNode () +// +template +inline tsDLNode::tsDLNode() : pNext(0), pPrev(0) {} + +// +// tsDLNode::operator = () +// +// when someone copies in a class deriving from this +// do _not_ change the node pointers +// +template +inline void tsDLNode::operator = (const tsDLNode &) const {} + +template +T * tsDLNode::getNext (void) const +{ + return pNext; +} + +template +T * tsDLNode::getPrev (void) const +{ + return pPrev; +} + +////////////////////////////////////// +// tsDLList member functions +////////////////////////////////////// + +// +// tsDLList::tsDLList () +// +template +inline tsDLList::tsDLList () +{ + this->clear (); +} + +// +// tsDLList::count () +// +// (returns the number of items on the list) +// +template +inline unsigned tsDLList::count () const +{ + return this->itemCount; +} + +// +// tsDLList::first () +// +template +inline T * tsDLList::first (void) const +{ + return this->pFirst; +} + +// +// tsDLList::last () +// +template +inline T *tsDLList::last (void) const +{ + return this->pLast; +} + +// +// tsDLList::clear () +// +template +inline void tsDLList::clear () +{ + this->pFirst = 0; + this->pLast = 0; + this->itemCount = 0u; +} + // // tsDLList::remove () // template void tsDLList::remove (T &item) { - tsDLNode &node = item; + tsDLNode &theNode = item; if (this->pLast == &item) { - this->pLast = node.pPrev; + this->pLast = theNode.pPrev; } else { - tsDLNode *pNextNode = node.pNext; - pNextNode->pPrev = node.pPrev; + tsDLNode &nextNode = *theNode.pNext; + nextNode.pPrev = theNode.pPrev; } if (this->pFirst == &item) { - this->pFirst = node.pNext; + this->pFirst = theNode.pNext; } else { - tsDLNode *pPrevNode = node.pPrev; - pPrevNode->pNext = node.pNext; + tsDLNode &prevNode = *theNode.pPrev; + prevNode.pNext = theNode.pNext; } this->itemCount--; @@ -555,6 +408,7 @@ inline T * tsDLList::get() // // tsDLList::pop () +// // (returns the first item on the list) template inline T * tsDLList::pop() @@ -563,7 +417,8 @@ inline T * tsDLList::pop() } // -// add() - +// tsDLList::add () +// // adds addList to the end of the list // (and removes all items from addList) // @@ -604,20 +459,21 @@ void tsDLList::add (tsDLList &addList) } // -// add() -// (add an item to the end of the list) +// tsDLList::add () +// +// add an item to the end of the list // template void tsDLList::add (T &item) { - tsDLNode &node = item; + tsDLNode &theNode = item; - node.pNext = 0; - node.pPrev = this->pLast; + theNode.pNext = 0; + theNode.pPrev = this->pLast; if (this->itemCount) { - tsDLNode *pLastNode = this->pLast; - pLastNode->pNext = &item; + tsDLNode &lastNode = *this->pLast; + lastNode.pNext = &item; } else { this->pFirst = &item; @@ -629,21 +485,22 @@ void tsDLList::add (T &item) } // -// insertAfter() -// (place item in the list immediately after itemBefore) +// tsDLList::insertAfter () +// +// place item in the list immediately after itemBefore // template void tsDLList::insertAfter (T &item, T &itemBefore) { - tsDLNode &node = item; + tsDLNode &nodeItem = item; tsDLNode &nodeBefore = itemBefore; - node.pPrev = &itemBefore; - node.pNext = nodeBefore.pNext; + nodeItem.pPrev = &itemBefore; + nodeItem.pNext = nodeBefore.pNext; nodeBefore.pNext = &item; - if (node.pNext) { - tsDLNode *pNextNode = node.pNext; + if (nodeItem.pNext) { + tsDLNode *pNextNode = nodeItem.pNext; pNextNode->pPrev = &item; } else { @@ -654,8 +511,9 @@ void tsDLList::insertAfter (T &item, T &itemBefore) } // -// insertBefore () -// (place item in the list immediately before itemAfter) +// tsDLList::insertBefore () +// +// place item in the list immediately before itemAfter // template void tsDLList::insertBefore (T &item, T &itemAfter) @@ -663,8 +521,8 @@ void tsDLList::insertBefore (T &item, T &itemAfter) tsDLNode &node = item; tsDLNode &nodeAfter = itemAfter; - node.pNext = &itemAfter; - node.pPrev = nodeAfter.pPrev; + tsDLNode.pNext = &itemAfter; + tsDLNode.pPrev = nodeAfter.pPrev; nodeAfter.pPrev = &item; if (node.pPrev) { @@ -679,15 +537,16 @@ void tsDLList::insertBefore (T &item, T &itemAfter) } // -// push () -// (add an item at the beginning of the list) +// tsDLList::push () +// +// add an item at the beginning of the list // template void tsDLList::push (T &item) { - tsDLNode &node = item; - node.pPrev = 0; - node.pNext = this->pFirst; + tsDLNode &theNode = item; + theNode.pPrev = 0; + theNode.pNext = this->pFirst; if (this->itemCount) { tsDLNode *pFirstNode = this->pFirst; @@ -702,11 +561,187 @@ void tsDLList::push (T &item) this->itemCount++; } +// +// tsDLList::find () +// returns -1 if the item isnt on the list +// and the node number (beginning with zero if +// it is) +// +template +int tsDLList::find (T &item) const +{ + tsDLFwdIter iter (*this); + tsDLNode *pItem; + int itemNo=0; + + while ( (pItem = iter.next()) ) { + if (pItem == &item) { + return itemNo; + } + itemNo++; + } + return -1; +} + +////////////////////////////////////////// +// tsDLIterBD member functions +////////////////////////////////////////// + +template +inline tsDLIterBD::tsDLIterBD (T * pInitialEntry) : + pEntry(pInitialEntry) {} + +// +// This is apparently required by some compiler, but +// only causes trouble with MS Visual C 6.0. This +// should not be required by any compiler. I am assuming +// that this "some compiler" is a past version of MS +// Visual C. +// +# if defined(_MSC_VER) && _MSC_VER < 1200 + template + tsDLIterBD::tsDLIterBD (const class tsDLIterBD ©In) : + pEntry(copyIn.pEntry) {} +# endif + +template +inline tsDLIterBD tsDLIterBD::operator = (T *pNewEntry) +{ + this->pEntry = pNewEntry; + return *this; +} + +template +inline bool tsDLIterBD::operator == (const tsDLIterBD &rhs) const +{ + return (this->pEntry == rhs.pEntry); +} + +template +inline bool tsDLIterBD::operator != (const tsDLIterBD &rhs) const +{ + return (this->pEntry != rhs.pEntry); +} + +template +inline T & tsDLIterBD::operator * () const +{ + return *this->pEntry; +} + +template +inline T * tsDLIterBD::operator -> () const +{ + return this->pEntry; +} + +template +inline tsDLIterBD::operator T* () const +{ + return this->pEntry; +} + +// +// prefix ++ +// +template +inline tsDLIterBD tsDLIterBD::operator ++ () +{ + tsDLNode &node = *this->pEntry; + this->pEntry = node.pNext; + return *this; +} + +// +// postfix ++ +// +template +inline tsDLIterBD tsDLIterBD::operator ++ (int) +{ + tsDLIterBD tmp = *this; + tsDLNode &node = *this->pEntry; + this->pEntry = node.pNext; + return tmp; +} + +// +// prefix -- +// +template +inline tsDLIterBD tsDLIterBD::operator -- () +{ + tsDLNode &entryNode = *pEntry; + this->pEntry = entryNode.pPrev; + return *this; +} + +// +// postfix -- +// +template +inline tsDLIterBD tsDLIterBD::operator -- (int) +{ + tsDLIterBD tmp = *this; + tsDLNode &entryNode = *pEntry; + this->pEntry = entryNode.pPrev; + return tmp; +} + +// +// tsDLIterBD::eol +// +template +inline const tsDLIterBD tsDLIterBD::eol () +{ + return tsDLIterBD(0); +} + +////////////////////////////////////////// +// tsDLIter member functions +////////////////////////////////////////// + +template +inline tsDLIter::tsDLIter (tsDLList & listIn) : + pCurrent(0), pList(&listIn) {} + +template +inline void tsDLIter::reset () +{ + this->pCurrent = 0; +} + +template +inline void tsDLIter::reset (tsDLList &listIn) +{ + this->reset(); + this->pList = &listIn; +} + +template +inline void tsDLIter::operator = (tsDLList &listIn) +{ + this->reset(listIn); +} + +template +inline T * tsDLIter::first() +{ + this->pCurrent = this->pList->pFirst; + return this->pCurrent; +} + +template +inline T * tsDLIter::last() +{ + this->pCurrent = this->pList->pLast; + return this->pCurrent; +} + // // tsDLIter::next () // template -T * tsDLIter::next () +inline T * tsDLIter::next () { T *pCur = this->pCurrent; if (pCur==0) { @@ -724,7 +759,7 @@ T * tsDLIter::next () // tsDLIter::prev () // template -T * tsDLIter::prev () +inline T * tsDLIter::prev () { T *pCur = this->pCurrent; if (pCur==0) { @@ -747,8 +782,41 @@ inline T * tsDLIter::operator () () return this->next(); } +/////////////////////////////////////////// +// tsDLBwdIter member functions +/////////////////////////////////////////// + +template +inline tsDLBwdIter::tsDLBwdIter(tsDLList &listIn) : + tsDLIter(listIn) {} + +template +inline void tsDLBwdIter::reset () +{ + this->tsDLIter::reset(); +} + +template +inline void tsDLBwdIter::reset (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline void tsDLBwdIter::operator = (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline T * tsDLBwdIter::last() +{ + return this->tsDLIter::last(); +} + // -// remove () +// tsDLBwdIter::remove () +// // remove current item // (and move current to be the item // pointed to by pNext - the item seen @@ -803,6 +871,39 @@ inline T * tsDLBwdIter::prev () return this->tsDLIter::prev(); } +////////////////////////////////////////// +// tsDLFwdIter member functions +////////////////////////////////////////// + +template +inline tsDLFwdIter::tsDLFwdIter (tsDLList &listIn) : + tsDLIter(listIn) {} + +template +inline void tsDLFwdIter::reset () +{ + this->tsDLIter::reset(); +} + +template +inline void tsDLFwdIter::reset (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline void tsDLFwdIter::operator = (tsDLList &listIn) +{ + this->tsDLIter::reset(listIn); +} + +template +inline T * tsDLFwdIter::first() +{ + tsDLIter &iterBase = *this; + return iterBase.first(); +} + // // tsDLFwdIter::remove () // (and move current to be the item @@ -851,27 +952,5 @@ inline T * tsDLFwdIter::operator () () return this->next(); } -// -// tsDLList::find () -// returns -1 if the item isnt on the list -// and the node number (beginning with zero if -// it is) -// -template -int tsDLList::find(T &item) const -{ - tsDLFwdIter iter(*this); - tsDLNode *pItem; - int itemNo=0; - - while ( (pItem = iter.next()) ) { - if (pItem == &item) { - return itemNo; - } - itemNo++; - } - return -1; -} - #endif // tsDLListH_include diff --git a/src/libCom/cxxTemplates/tsSLList.h b/src/libCom/cxxTemplates/tsSLList.h index 5f3db88e3..6ff98bb74 100644 --- a/src/libCom/cxxTemplates/tsSLList.h +++ b/src/libCom/cxxTemplates/tsSLList.h @@ -1,7 +1,7 @@ /* * $Id$ * - * tsSLList - type safe singly linked list templates + * type safe singly linked list templates * * Author Jeffrey O. Hill * johill@lanl.gov @@ -28,58 +28,8 @@ * Advanced Photon Source * Argonne National Laboratory * - * - * History - * $Log$ - * Revision 1.14 1998/10/23 16:40:47 jhill - * fixed missing new line at EOF - * - * Revision 1.13 1998/10/23 00:20:41 jhill - * attempted to clean up HP-UX warnings - * - * Revision 1.12 1998/06/16 03:03:07 jhill - * eliminated dangling ptr warning from bounds checker - * - * Revision 1.11 1998/05/05 18:06:58 jhill - * rearranged to allow compilation by g++ 2.8.1 - * - * Revision 1.10 1998/02/18 22:53:13 jhill - * fixed gnu warning - * - * Revision 1.9 1998/02/05 23:28:21 jhill - * fixed hp sompiler warnings - * - * Revision 1.8 1997/06/13 09:21:53 jhill - * fixed compiler compatibility problems - * - * Revision 1.7 1997/04/10 19:43:10 jhill - * API changes - * - * Revision 1.6 1997/01/22 21:14:21 jhill - * fixed class decl order for VMS - * - * Revision 1.5 1996/11/02 01:07:20 jhill - * many improvements - * - * Revision 1.4 1996/09/04 19:57:07 jhill - * string id resource now copies id - * - * Revision 1.3 1996/07/25 18:01:42 jhill - * use pointer (not ref) for list in iter class - * - * Revision 1.2 1996/07/24 22:12:04 jhill - * added remove() to iter class + made node's prev/next private - * - * Revision 1.1.1.1 1996/06/20 22:15:55 jhill - * installed ca server templates - * - * */ -#ifndef assert // allow use of epicsAssert.h -#include -#endif - // // the hp compiler complains about parameterized friend // class that has not been declared without this? @@ -89,8 +39,8 @@ template class tsSLIter; template class tsSLIterRm; // -// tsSLNode<> -// NOTE: T must derive from tsSLNode +// tsSLNode +// NOTE: class T must derive from tsSLNode // template class tsSLNode { @@ -98,81 +48,39 @@ friend class tsSLList; friend class tsSLIter; friend class tsSLIterRm; public: - tsSLNode() : pNext(0) {} - // - // when someone copies into a class deriving from this - // do _not_ change the node pointers - // - void operator = (const tsSLNode &) {} + tsSLNode(); + + void operator = (const tsSLNode &) const; private: - T *pNext; - // - // removeNextItem () - // - // removes the item after this node - // - void removeNextItem () - { - T *pItem = this->pNext; - if (pItem) { - tsSLNode *pNode = pItem; - this->pNext = pNode->pNext; - } - } + void removeNextItem (); // removes the item after this node + + T *pNext; }; // -// tsSLList<> -// NOTE: T must derive from tsSLNode +// tsSLList +// NOTE: class T must derive from tsSLNode // template class tsSLList : public tsSLNode { public: + tsSLList (); // creates an empty list - // - // insert() - // (itemBefore might be the list header object and therefore - // will not always be of type T) - // - void insert (T &item, tsSLNode &itemBefore) - { - tsSLNode &node = item; - node.pNext = itemBefore.pNext; - itemBefore.pNext = &item; - } + void insert (T &item, tsSLNode &itemBefore); // insert after item before - // - // add() - // - void add (T &item) - { - this->insert (item, *this); - } + void add (T &item); // add to the beginning of the list - // - // get () - // - T * get() - { - tsSLNode *pThisNode = this; - T *pItem = pThisNode->pNext; - pThisNode->removeNextItem(); - return pItem; - } + T * get (); // remove from the beginning of the list - T * pop() - { - return get(); - } + T * pop (); // same as get - void push(T &item) - { - this->add(item); - } + void push (T &item); // same as add +private: + tsSLList (const tsSLList &); // intentionally _not_ implemented }; // @@ -181,25 +89,11 @@ public: template class tsSLIter { public: - tsSLIter(const tsSLList &listIn) : - pCurrent(0), list(listIn) {}; + tsSLIter (const tsSLList &listIn); - // - // move iterator forward - // - // NULL test here is inefficient, but it appears that some architectures - // (intel) dont like to cast a NULL pointer from a tsSLNode to a T even if - // tsSLNode is always a base class of a T. - // - T * next (); + T * next (); // move iterator forward - // - // move iterator forward - // - T * operator () () - { - return this->next(); - } + T * operator () (); // same as next () private: T *pCurrent; @@ -208,59 +102,24 @@ private: // // tsSLIterRm -// (A tsSLIter that allows removing a node) -// -// adds remove method (and does not construct -// with const list) -// -// tsSLIter isnt a base class because this -// requires striping const from pCurrent which could get -// us in trouble with a high quality -// optimizing compiler -// -// Notes: -// 1) No direct access to pCurrent is provided since -// this might allow for confusion when an item -// is removed (and pCurrent ends up pointing at -// an item that has been seen before) -// +// (An tsSLIter that allows removing a node) // template class tsSLIterRm { public: - tsSLIterRm(tsSLList &listIn) : - pPrevious(0), pCurrent(0), list(listIn) {}; // - // move iterator forward + // exceptions // - // NULL test here is inefficient, but it appears that some architectures - // (intel) dont like to cast a NULL pointer from a tsSLNode to a T even if - // tsSLNode is always a base class of a T. - // - T * next (); + class noCurrentItemInIterator {}; - // - // move iterator forward - // - T * operator () () - { - return this->next(); - } + tsSLIterRm (tsSLList &listIn); - // - // remove current node - // (and move current to be the previos item - - // the item seen by the iterator before the - // current one - this guarantee that the list - // will be accessed sequentially even if an item - // is removed) - // - // This cant be called twice in a row without moving - // the iterator to the next item. If there is - // no current item this function assert fails. - // - void remove (); + T * next (); // move iterator forward + + T * operator () (); // same as next () + + void remove (); // remove current node private: T *pPrevious; @@ -268,6 +127,122 @@ private: tsSLList &list; }; +////////////////////////////////////////// +// +// tsSLNode inline member functions +// +////////////////////////////////////////// + +// +// tsSLNode::tsSLNode +// +template +tsSLNode::tsSLNode() : pNext(0) {} + +// +// tsSLNode::operator = +// +// when someone copies into a class deriving from this +// do _not_ change the node pointers +// +template +inline void tsSLNode::operator = (const tsSLNode &) const {} + +// +// removeNextItem () +// +// removes the item after this node +// +template +inline void tsSLNode::removeNextItem () +{ + T *pItem = this->pNext; + if (pItem) { + tsSLNode *pNode = pItem; + this->pNext = pNode->pNext; + } +} + +////////////////////////////////////////// +// +// tsSLList inline memeber functions +// +////////////////////////////////////////// + +// +// tsSLList::tsSLList() +// create an empty list +// +template +inline tsSLList::tsSLList () +{ +} + +// +// tsSLList::insert() +// (itemBefore might be the list header object and therefore +// will not always be of type T) +// +template +inline void tsSLList::insert (T &item, tsSLNode &itemBefore) +{ + tsSLNode &node = item; + node.pNext = itemBefore.pNext; + itemBefore.pNext = &item; +} + +// +// tsSLList::add () +// +template +inline void tsSLList::add (T &item) +{ + this->insert (item, *this); +} + +// +// tsSLList::get () +// +template +inline T * tsSLList::get() +{ + tsSLNode *pThisNode = this; + T *pItem = pThisNode->pNext; + pThisNode->removeNextItem(); + return pItem; +} + +// +// tsSLList::pop () +// +template +inline T * tsSLList::pop() +{ + return this->get(); +} + +// +// tsSLList::push () +// +template +inline void tsSLList::push(T &item) +{ + this->add(item); +} + +////////////////////////////////////////// +// +// tsSLIter inline memeber functions +// +////////////////////////////////////////// + +// +// tsSLIter::tsSLIter +// +template +inline tsSLIter::tsSLIter (const tsSLList &listIn) : + pCurrent (0), list (listIn) {} + // // tsSLIter::next () // @@ -295,6 +270,43 @@ T * tsSLIter::next () return this->pCurrent; } +// +// move iterator forward +// +template +inline T * tsSLIter::operator () () +{ + return this->next(); +} + +////////////////////////////////////////// +// +// tsSLIterRm inline memeber functions +// +// adds remove method (and does not construct +// with const list) +// +// tsSLIter isnt a base class because this +// requires striping const from pCurrent which could get +// us in trouble with a high quality +// optimizing compiler +// +// Notes: +// 1) No direct access to pCurrent is provided since +// this might allow for confusion when an item +// is removed (and pCurrent ends up pointing at +// an item that has been seen before) +// +////////////////////////////////////////// + +// +// tsSLIterRm::tsSLIterRm () +// +template +inline tsSLIterRm::tsSLIterRm (tsSLList &listIn) : + pPrevious (0), pCurrent (0), list (listIn) {}; + + // // tsSLIterRm::next () // @@ -324,6 +336,15 @@ T * tsSLIterRm::next () return this->pCurrent; } +// +// move iterator forward +// +template +inline T * tsSLIterRm::operator () () +{ + return this->next(); +} + // // tsSLIterRm::remove () // @@ -336,12 +357,14 @@ T * tsSLIterRm::next () // // This cant be called twice in a row without moving // the iterator to the next item. If there is -// no current item this function assert fails. +// no current item this function throws an exception. // template void tsSLIterRm::remove () { - assert (this->pCurrent!=0); + if (this->pCurrent==0) { + throw noCurrentItemInIterator (); + } tsSLNode *pPrevNode; tsSLNode *pCurNode = this->pCurrent; @@ -349,10 +372,12 @@ void tsSLIterRm::remove () if (this->pPrevious==0) { pPrevNode = &this->list; // - // this assert fails if it is an attempt to + // fail if it is an attempt to // delete twice without moving the iterator // - assert (pPrevNode->pNext == this->pCurrent); + if (pPrevNode->pNext != this->pCurrent) { + throw noCurrentItemInIterator (); + } } else { pPrevNode = this->pPrevious;