cxxTemplates files now moved to libCom/cxxTemplates.

This commit is contained in:
Janet B. Anderson
2000-02-10 19:19:24 +00:00
parent 28ee655784
commit ec61ce1ee7
17 changed files with 0 additions and 3579 deletions

View File

@@ -1,10 +0,0 @@
TOP=../..
include $(TOP)/configure/CONFIG
INC += resourceLib.h
INC += tsDLList.h
INC += tsSLList.h
INC += tsMinMax.h
INC += tsBTree.h
include $(TOP)/configure/RULES

View File

@@ -1,56 +0,0 @@
C++ templates:
tsSLList.h - type safe single linked list template
tsDLList.h - type safe double linked list template
resourceLib.h - hash table template
the test subdir contains examples
Since I am using templates the linked lists are type safe
(no casting of pointers ala ellList and dllList).
Also, the node class in embedded in the item on the
list (more efficent use of pool).
The file resourceLib.h provides a core hashing library
"resTable <itemClass, idClass>" where "itemClass" objects
are stored in the hash table and "idClass" is the data type
of the key for the hash table. The identifier class provides
the hash alg. I have provided simple string "stringId" and
unsigned integer "uintId" key types in resourceLib.h. It
is easy to implement a new key class.
There are examples under cxxTemplate/test. The list/hashing
templates all depend on a particular inheritance hierarchy.
If the inheritance hierarchy is wrong nothing will compile.
For instance, in tsDLList.h the template data type "T"
must derive from tsDLNode<T>. Likewise, in tsSLList.h
"T" must derive from tsSLNode<T>. Likewise, in resourceLib.h
class "T" (the type stored in the hash table) must derive
from class "ID" (the hash table key type) and also derive from
tsSLNode<T>.
So far, the only confusion I have run into with templates has been:
1) strange compiler messages - unrelated to cause of course -
when I get the class declaration order wrong (so that the
compiler has trouble instantiating the template).
2) sun pro/dec/att compilers use a template database and
gnu/msvc++ compilers use explicit template instantiation.
Therefore blocks of code of this sort are required:
#include "resourceLib.h" // template def
#include "resourceLib.cc" // template functions (that are not inline)
#if defined (EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
//
// This explicitly instantiates the template class's member
// functions into "templInst.o"
//
template class resTable<fred,uintId>;
template class resTable<jane,stringId>;
#endif

View File

@@ -1,975 +0,0 @@
/*
* $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)
*
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*
* NOTES:
* .01 Storage for identifier must persist until an item is deleted
* .02 class T must derive from class ID and tsSLNode<T>
*
*/
#ifndef INCresourceLibh
#define INCresourceLibh
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "tsSLList.h"
#include "shareLib.h"
typedef size_t resTableIndex;
template <class T, class ID> class resTableIter;
//
// class resTable <T, ID>
//
// 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<T>
//
// 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)
// resTableIndex hash (unsigned nBitsHashIndex) const;
//
// 5) Classes of type ID must provide the following member functions
// (which will usually be static const inline for improved performance).
// They determine the minimum and maximum number of elements in the hash
// table. If minIndexBitWidth() == maxIndexBitWidth() then the hash table
// size is determined at compile time
//
// inline static const unsigned maxIndexBitWidth ();
// inline static const unsigned minIndexBitWidth ();
//
// max number of hash table elements = 1 << maxIndexBitWidth();
// min number of hash table elements = 1 << minIndexBitWidth();
//
// 6) Storage for identifier of type ID must persist until the item of type
// T is deleted from the resTable
//
template <class T, class ID>
class resTable {
friend class resTableIter<T,ID>;
public:
//
// exceptions thrown
//
class epicsShareClass dynamicMemoryAllocationFailed {};
class epicsShareClass entryDidntRespondToDestroyVirtualFunction {};
class epicsShareClass sizeExceedsMaxIndexWidth {};
resTable (unsigned nHashTableEntries);
virtual ~resTable();
void destroyAllEntries(); // destroy all entries
//
// 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 entry
//
// returns -1 if the id already exits in the table
// and zero if successful
//
int add (T &res);
T *remove (const ID &idIn); // remove entry
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::*pSetMFArg_t)();
# define pSetMFArg(ARG) pSetMFArg_t ARG
#else
//
// required by gnu g++ 2.7.2
//
# define pSetMFArg(ARG) void (T:: * ARG)()
#endif
//
// 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 (pSetMFArg(pCB)) const;
private:
tsSLList<T> *pTable;
unsigned hashIdMask;
unsigned hashIdNBits;
unsigned nInUse;
resTableIndex hash (const ID & idIn) const;
T *find (tsSLList<T> &list, const ID &idIn) const;
T *findDelete (tsSLList<T> &list, const ID &idIn);
};
//
// class resTableIter
//
// an iterator for the resource table class
//
template <class T, class ID>
class resTableIter {
public:
resTableIter (const resTable<T,ID> &tableIn);
T * next ();
T * operator () ();
private:
tsSLIter<T> iter;
unsigned index;
const resTable<T,ID> &table;
};
//
// Some ID classes that work with the above template
//
//
// class intId
//
// signed or unsigned integer identifier (class T must be
// a signed or unsigned interger type)
//
// this class works as type ID in resTable <class T, class ID>
//
// 1<<MIN_INDEX_WIDTH specifies the minimum number of
// elements in the hash table within resTable <class T, class ID>
//
// MAX_ID_WIDTH specifies the maximum number of ls bits in an
// integer identifier which might be set at any time. Set this
// parameter to zero if unsure of the correct minimum hash table
// size.
//
// 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.
//
#if defined(__GNUC__) && ( __GNUC__<2 || (__GNUC__==2 && __GNUC__<8) )
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
#else
template <class T, unsigned MIN_INDEX_WIDTH=4, unsigned MAX_ID_WIDTH = sizeof(T)*CHAR_BIT>
#endif
class intId {
public:
intId (const T &idIn);
bool operator == (const intId &idIn) const;
resTableIndex hash (unsigned nBitsIndex) const;
const T getId() const;
static resTableIndex hashEngine (const T &id);
static const unsigned maxIndexBitWidth ();
static const unsigned minIndexBitWidth ();
protected:
T id;
};
//
// class chronIntIdResTable <ITEM>
//
// a specialized resTable which uses unsigned integer keys which are
// allocated in chronological sequence
//
// NOTE: ITEM must public inherit from chronIntIdRes <ITEM>
//
#if defined(__GNUC__) && ( __GNUC__<2 || (__GNUC__==2 && __GNUC__<8) )
typedef intId<unsigned, 8, sizeof(unsigned)*CHAR_BIT> chronIntId;
#else
typedef intId<unsigned, 8> chronIntId;
#endif
template <class ITEM>
class chronIntIdResTable : public resTable<ITEM, chronIntId> {
public:
chronIntIdResTable (unsigned nHashTableEntries);
virtual ~chronIntIdResTable ();
void add (ITEM &item);
private:
unsigned allocId;
};
//
// class chronIntIdRes<ITEM>
//
// resource with unsigned chronological identifier
//
template <class ITEM>
class chronIntIdRes : public chronIntId, public tsSLNode<ITEM> {
friend class chronIntIdResTable<ITEM>;
public:
chronIntIdRes ();
private:
void setId (unsigned newId);
};
//
// class stringId
//
// character string identifier
//
class epicsShareClass stringId {
public:
//
// exceptions
//
class epicsShareClass dynamicMemoryAllocationFailed {};
enum allocationType {copyString, refString};
stringId (const char * idIn, allocationType typeIn=copyString);
~ stringId();
resTableIndex hash (unsigned nBitsIndex) const;
bool operator == (const stringId &idIn) const;
const char * resourceName() const; // return the pointer to the string
void show (unsigned level) const;
static const unsigned maxIndexBitWidth ();
static const unsigned minIndexBitWidth ();
private:
const char * pStr;
const allocationType allocType;
static const unsigned char fastHashPermutedIndexSpace[256];
};
/////////////////////////////////////////////////
// resTable<class T, class ID> member functions
/////////////////////////////////////////////////
//
// resTable::resTable (unsigned nHashTableEntries)
//
template <class T, class ID>
resTable<T,ID>::resTable (unsigned nHashTableEntries) :
nInUse (0)
{
unsigned nbits, mask;
//
// count the number of bits in the hash index
//
for (nbits=0; nbits < sizeof (resTableIndex) * CHAR_BIT; nbits++) {
mask = (1<<nbits) - 1;
if ( ((nHashTableEntries-1) & ~mask) == 0){
break;
}
}
if ( nbits > ID::maxIndexBitWidth () ) {
# ifdef noExceptionsFromCXX
assert (0);
# else
throw sizeExceedsMaxIndexWidth ();
# endif
}
//
// it improves performance to round up to a
// minimum table size
//
if ( nbits < ID::minIndexBitWidth () ) {
nbits = ID::minIndexBitWidth ();
mask = (1<<nbits) - 1;
}
this->hashIdNBits = nbits;
this->hashIdMask = mask;
this->nInUse = 0u;
this->pTable = new tsSLList<T> [1<<nbits];
if (this->pTable==0) {
# ifdef noExceptionsFromCXX
assert (0);
# else
throw dynamicMemoryAllocationFailed ();
# endif
}
}
//
// resTable::remove ()
//
// remove a res from the resTable
//
template <class T, class ID>
inline T * resTable<T,ID>::remove (const ID &idIn)
{
tsSLList<T> &list = this->pTable[this->hash(idIn)];
return this->findDelete(list, idIn);
}
//
// resTable::lookup ()
//
// find an res in the resTable
//
template <class T, class ID>
inline T * resTable<T,ID>::lookup (const ID &idIn) const
{
tsSLList<T> &list = this->pTable[this->hash(idIn)];
return this->find(list, idIn);
}
//
// resTable::hash ()
//
template <class T, class ID>
inline resTableIndex resTable<T,ID>::hash (const ID & idIn) const
{
return idIn.hash (this->hashIdNBits) & this->hashIdMask;
}
//
// resTable<T,ID>::destroyAllEntries()
//
template <class T, class ID>
void resTable<T,ID>::destroyAllEntries()
{
tsSLList<T> *pList = this->pTable;
while (pList<&this->pTable[this->hashIdMask+1]) {
T *pItem;
T *pNextItem;
{
tsSLIter<T> iter(*pList);
pItem = iter();
while (pItem) {
pNextItem = iter();
pItem->destroy();
pItem = pNextItem;
}
}
//
// Check to see if a defective class is
// installed that does not remove itself
// from the resTable when it is destroyed.
//
{
tsSLIterRm<T> iter(*pList);
while ( (pItem=iter()) ) {
fprintf (stderr,
"Warning: Defective class still in resTable<T,ID> after it was destroyed\n");
//
// remove defective class
//
iter.remove();
this->nInUse--;
}
}
pList++;
}
}
//
// resTable<T,ID>::show
//
template <class T, class ID>
void resTable<T,ID>::show (unsigned level) const
{
tsSLList<T> *pList;
double X;
double XX;
double mean;
double stdDev;
unsigned maxEntries;
printf("resTable with %d resources installed\n", this->nInUse);
if (level >=1u) {
pList = this->pTable;
X = 0.0;
XX = 0.0;
maxEntries = 0u;
while (pList < &this->pTable[this->hashIdMask+1]) {
unsigned count;
tsSLIter<T> iter(*pList);
T *pItem;
count = 0;
while ( (pItem = iter()) ) {
if (level >= 3u) {
pItem->show (level);
}
count++;
}
if (count>0u) {
X += count;
XX += count*count;
if (count>maxEntries) {
maxEntries = count;
}
}
pList++;
}
mean = X/(this->hashIdMask+1);
stdDev = sqrt(XX/(this->hashIdMask+1) - mean*mean);
printf(
"entries/occupied resTable entry: mean = %f std dev = %f max = %d\n",
mean, stdDev, maxEntries);
}
}
//
// resTable<T,ID>::traverse
//
template <class T, class ID>
void resTable<T,ID>::traverse (pSetMFArg(pCB)) const
{
tsSLList<T> *pList;
pList = this->pTable;
while (pList < &this->pTable[this->hashIdMask+1]) {
tsSLIter<T> iter(*pList);
T *pItem;
while ( (pItem = iter()) ) {
(pItem->*pCB) ();
}
pList++;
}
}
//
// add a res to the resTable
//
// (bad status on failure)
//
template <class T, class ID>
int resTable<T,ID>::add (T &res)
{
//
// T must derive from ID
//
tsSLList<T> &list = this->pTable[this->hash(res)];
if ( this->find (list, res) != 0 ) {
return -1;
}
list.add (res);
this->nInUse++;
return 0;
}
//
// 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)
//
template <class T, class ID>
T *resTable<T,ID>::find (tsSLList<T> &list, const ID &idIn) const
{
tsSLIter<T> iter(list);
T *pItem;
ID *pId;
while ( (pItem = iter()) ) {
pId = pItem;
if (*pId == idIn) {
break;
}
}
return pItem;
}
//
// findDelete
// searches from where the iterator points to the
// end of the list for idIn
//
// iterator points to the item found upon return
// (or NULL if nothing matching was found)
//
// removes the item if it finds it
//
template <class T, class ID>
T *resTable<T,ID>::findDelete (tsSLList<T> &list, const ID &idIn)
{
tsSLIterRm<T> iter(list);
T *pItem;
ID *pId;
while ( (pItem = iter()) ) {
pId = pItem;
if (*pId == idIn) {
iter.remove();
this->nInUse--;
break;
}
}
return pItem;
}
//
// ~resTable<T,ID>::resTable()
//
template <class T, class ID>
resTable<T,ID>::~resTable()
{
if (this->pTable) {
this->destroyAllEntries();
if (this->nInUse != 0u) {
# ifdef noExceptionsFromCXX
assert (0);
# else
throw entryDidntRespondToDestroyVirtualFunction ();
# endif
}
delete [] this->pTable;
}
}
//////////////////////////////////////////////
// resTableIter<T,ID> member functions
//////////////////////////////////////////////
//
// resTableIter<T,ID>::resTableIter ()
//
template <class T, class ID>
inline resTableIter<T,ID>::resTableIter (const resTable<T,ID> &tableIn) :
iter (tableIn.pTable[0]), index (1), table (tableIn) {}
//
// resTableIter<T,ID>::next ()
//
template <class T, class ID>
inline T * resTableIter<T,ID>::next ()
{
T *pNext = this->iter.next();
if (pNext) {
return pNext;
}
if ( this->index >= (1u<<this->table.hashIdNBits) ) {
return 0;
}
this->iter = tsSLIter<T> (this->table.pTable[this->index++]);
return this->iter.next ();
}
//
// resTableIter<T,ID>::operator () ()
//
template <class T, class ID>
inline T * resTableIter<T,ID>::operator () ()
{
return this->next ();
}
//////////////////////////////////////////////
// chronIntIdResTable<ITEM> member functions
//////////////////////////////////////////////
//
// chronIntIdResTable<ITEM>::chronIntIdResTable()
//
template <class ITEM>
inline chronIntIdResTable<ITEM>::chronIntIdResTable (unsigned nHashTableEntries) :
resTable<ITEM, chronIntId> (nHashTableEntries),
allocId(1u) {} // hashing is faster close to zero
//
// chronIntIdResTable<ITEM>::~chronIntIdResTable()
// (not inline because it is virtual)
//
template <class ITEM>
chronIntIdResTable<ITEM>::~chronIntIdResTable() {}
//
// chronIntIdResTable<ITEM>::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 <class ITEM>
inline void chronIntIdResTable<ITEM>::add (ITEM &item)
{
int status;
do {
item.chronIntIdRes<ITEM>::setId (allocId++);
status = this->resTable<ITEM,chronIntId>::add (item);
}
while (status);
}
/////////////////////////////////////////////////
// chronIntIdRes<ITEM> member functions
/////////////////////////////////////////////////
//
// chronIntIdRes<ITEM>::chronIntIdRes
//
template <class ITEM>
inline chronIntIdRes<ITEM>::chronIntIdRes () : chronIntId (UINT_MAX) {}
//
// id<ITEM>::setId ()
//
// workaround for bug in DEC compiler
//
template <class ITEM>
inline void chronIntIdRes<ITEM>::setId (unsigned newId)
{
this->id = newId;
}
/////////////////////////////////////////////////
// intId member functions
/////////////////////////////////////////////////
//
// intId::intId ()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::intId (const T &idIn)
: id (idIn) {}
//
// intId::operator == ()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline bool intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::operator ==
(const intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH> &idIn) const
{
return this->id == idIn.id;
}
//
// intId::getId ()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline const T intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::getId () const
{
return this->id;
}
//
// const unsigned intId::minIndexBitWidth ()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline const unsigned intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::minIndexBitWidth ()
{
return MIN_INDEX_WIDTH;
}
//
// const unsigned intId::maxIndexBitWidth ()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline const unsigned intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::maxIndexBitWidth ()
{
return sizeof (resTableIndex) * CHAR_BIT;
}
//
// intId::hashEngine()
//
// converts any integer into a hash table index
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline resTableIndex intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::hashEngine (const T &id)
{
resTableIndex hashid = static_cast<resTableIndex>(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 = MAX_ID_WIDTH;
do {
width >>= 1u;
hashid ^= hashid>>width;
} while (width>MIN_INDEX_WIDTH);
//
// the result here is always masked to the
// proper size after it is returned to the "resTable" class
//
return hashid;
}
//
// intId::hash()
//
template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
inline resTableIndex intId<T, MIN_INDEX_WIDTH, MAX_ID_WIDTH>::hash (unsigned /* nBitsIndex */) const
{
return this->hashEngine (this->id);
}
////////////////////////////////////////////////////
// stringId member functions
////////////////////////////////////////////////////
//
// 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;
}
#ifdef instantiateRecourceLib
//
// stringId::stringId()
//
stringId::stringId (const char * idIn, allocationType typeIn) :
allocType (typeIn)
{
if (typeIn==copyString) {
unsigned nChars = strlen (idIn) + 1u;
this->pStr = new char [nChars];
if (this->pStr!=0) {
memcpy ((void *)this->pStr, idIn, nChars);
}
else {
# ifdef noExceptionsFromCXX
assert (0);
# else
throw dynamicMemoryAllocationFailed ();
# endif
}
}
else {
this->pStr = idIn;
}
}
//
// const unsigned stringId::minIndexBitWidth ()
//
// this limit is based on limitations in the hash
// function below
//
inline const unsigned stringId::minIndexBitWidth ()
{
return 8;
}
//
// const unsigned stringId::maxIndexBitWidth ()
//
// see comments related to this limit in the hash
// function below
//
inline const unsigned stringId::maxIndexBitWidth ()
{
return 16;
}
//
// stringId::show ()
//
void stringId::show (unsigned level) const
{
if (level>2u) {
printf ("resource id = %s\n", this->pStr);
}
}
//
// stringId::~stringId()
//
//
// this needs to be instanciated only once (normally in libCom)
//
stringId::~stringId()
{
if (this->allocType==copyString) {
if (this->pStr!=NULL) {
//
// the microsoft and solaris compilers will
// not allow a pointer to "const char"
// to be deleted
//
// the HP-UX compiler gives us a warning on
// each cast away of const, but in this case
// it cant be avoided.
//
// The DEC compiler complains that const isnt
// really significant in a cast if it is present.
//
// I hope that deleting a pointer to "char"
// is the same as deleting a pointer to
// "const char" on all compilers
//
delete [] const_cast<char *>(this->pStr);
}
}
}
//
// stringId::hash()
//
// This 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 initial modifications
// were designed by Marty Kraimer. Some additional minor optimizations
// by Jeff Hill.
//
resTableIndex stringId::hash(unsigned nBitsIndex) const
{
const unsigned char *pUStr =
reinterpret_cast<const unsigned char *>(this->pStr);
if (pUStr==NULL) {
return 0u;
}
unsigned h0 = 0u;
unsigned h1 = 0u;
unsigned c;
while (true) {
c = *(pUStr++);
if (c==0) {
break;
}
h0 = fastHashPermutedIndexSpace[h0 ^ c];
c = *(pUStr++);
if (c==0) {
break;
}
h1 = fastHashPermutedIndexSpace[h1 ^ c];
}
h1 = h1 << (nBitsIndex-8u);
h0 = h1 ^ h0;
return h0;
}
//
// 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
//
const unsigned char stringId::fastHashPermutedIndexSpace[256] = {
39,159,180,252, 71, 6, 13,164,232, 35,226,155, 98,120,154, 69,
157, 24,137, 29,147, 78,121, 85,112, 8,248,130, 55,117,190,160,
176,131,228, 64,211,106, 38, 27,140, 30, 88,210,227,104, 84, 77,
75,107,169,138,195,184, 70, 90, 61,166, 7,244,165,108,219, 51,
9,139,209, 40, 31,202, 58,179,116, 33,207,146, 76, 60,242,124,
254,197, 80,167,153,145,129,233,132, 48,246, 86,156,177, 36,187,
45, 1, 96, 18, 19, 62,185,234, 99, 16,218, 95,128,224,123,253,
42,109, 4,247, 72, 5,151,136, 0,152,148,127,204,133, 17, 14,
182,217, 54,199,119,174, 82, 57,215, 41,114,208,206,110,239, 23,
189, 15, 3, 22,188, 79,113,172, 28, 2,222, 21,251,225,237,105,
102, 32, 56,181,126, 83,230, 53,158, 52, 59,213,118,100, 67,142,
220,170,144,115,205, 26,125,168,249, 66,175, 97,255, 92,229, 91,
214,236,178,243, 46, 44,201,250,135,186,150,221,163,216,162, 43,
11,101, 34, 37,194, 25, 50, 12, 87,198,173,240,193,171,143,231,
111,141,191,103, 74,245,223, 20,161,235,122, 63, 89,149, 73,238,
134, 68, 93,183,241, 81,196, 49,192, 65,212, 94,203, 10,200, 47
};
#endif // if instantiateRecourceLib is defined
#endif // INCresourceLibh

View File

@@ -1,43 +0,0 @@
TOP=../../..
include $(TOP)/configure/CONFIG
resourceLibTest_SRCS += resourceLibTest.cc
PROD += resourceLibTest
OBJS_IOC += resourceLibTest
tsDLListBench_SRCS += tsDLListBench.cc
PROD += tsDLListBench
OBJS_IOC += tsDLListBench
tsDLListTest_SRCS += tsDLListTest.cc
PROD += tsDLListTest
OBJS_IOC += tsDLListTest
tsSLListBench_SRCS += tsSLListBench.cc
PROD += tsSLListBench
OBJS_IOC += tsSLListBench
tsSLListTest_SRCS += tsSLListTest.cc
PROD += tsSLListTest
OBJS_IOC += tsSLListTest
minmaxTest_SRCS += minmaxTest.cc
PROD += minmaxTest
OBJS_IOC += minmaxTest
tsBTreeTest_SRCS += tsBTreeTest.cc
PROD += tsBTreeTest
OBJS_IOC += tsBTreeTest
tsBTreeBench_SRCS += tsBTreeBench.cc
PROD += tsBTreeBench
OBJS_IOC += tsBTreeBench
CXXCMPLR = STRICT
PROD_LIBS = Com
include $(TOP)/configure/RULES

View File

@@ -1,15 +0,0 @@
TOP=../../..
include $(TOP)/configure/CONFIG
CXXCMPLR = STRICT
PROD_LIBS = Com
SYS_PROD_LIBS_WIN32 := ws2_32 advapi32
TESTPROD := resourceLibTest tsDLListBench tsDLListTest tsDLListTest \
tsSLListBench tsSLListTest minmaxTest tsBTreeBench tsBTreeTest
include $(TOP)/configure/RULES_BUILD

View File

@@ -1,30 +0,0 @@
#include <assert.h>
#include "tsMinMax.h"
int main ()
{
float f1 = 3.3f;
float f2 = 3.4f;
float f3;
f3 = tsMin(f1,f2);
assert(f3==f1);
f3 = tsMax(f1,f2);
assert(f3==f2);
int i1 = 3;
int i2 = 4;
int i3;
i3 = tsMin(i1,i2);
assert(i3==i1);
i3 = tsMax(i1,i2);
assert(i3==i2);
return 0;
}

View File

@@ -1,266 +0,0 @@
#include <assert.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define epicsExportSharedSymbols
#define instantiateRecourceLib
#include "resourceLib.h"
void empty();
#if defined(__GNUC__) && ( __GNUC__<2 || (__GNUC__==2 && __GNUC__<8) )
typedef intId<unsigned,8,16> testIntId;
#else
typedef intId<unsigned,8> testIntId;
#endif
class albert : public testIntId, public tsSLNode<albert> {
public:
albert (resTable< albert, testIntId > &atIn, unsigned idIn) :
testIntId(idIn), at(atIn)
{
assert (at.add (*this)==0);
}
void show (unsigned /* level */)
{
}
void destroy()
{
at.remove(*this);
delete this;
}
private:
resTable< albert, testIntId > &at;
};
class fred : public testIntId, public tsSLNode<fred> {
public:
fred (const char *pNameIn, unsigned idIn) :
testIntId(idIn), pName(pNameIn) {}
void show (unsigned)
{
printf("fred %s\n", pName);
}
void destroy()
{
// always on stack so noop
}
private:
const char * const pName;
};
class jane : public stringId, public tsSLNode<jane> {
public:
jane (const char *pNameIn) : stringId (pNameIn) {}
void testTraverse();
void destroy()
{
// always on stack so noop
}
};
//
// jane::testTraverse()
//
void jane::testTraverse()
{
printf("Traverse Test\n");
this->show(10);
}
//
// explicitly instantiates on compilers that support this
//
#if defined(EXPL_TEMPL)
//
// From Stroustrups's "The C++ Programming Language"
// Appendix A: r.14.9
//
// This explicitly instantiates the template class's member
// functions into "templInst.o"
//
template class resTable<fred,testIntId >;
template class resTable<jane,stringId>;
#endif
int main()
{
unsigned i;
clock_t start, finish;
double duration;
const unsigned LOOPS = 50000;
resTable<fred, testIntId > intTbl (8);
resTable<jane, stringId> strTbl (8);
fred fred0("fred0",0);
fred fred1("fred1",0x1000a432);
fred fred2("fred2",0x0000a432);
fred fred3("fred3",1);
fred fred4("fred4",2);
fred fred5("fred5",3);
fred fred6("fred6",4);
fred fred7("fred7",5);
fred fred8("fred8",6);
fred fred9("fred9",7);
jane jane1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
jane jane2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
fred *pFred;
jane *pJane;
testIntId intId0 (0);
testIntId intId1 (0x1000a432);
testIntId intId2 (0x0000a432);
testIntId intId3 (1);
testIntId intId4 (2);
testIntId intId5 (3);
testIntId intId6 (4);
testIntId intId7 (5);
testIntId intId8 (6);
testIntId intId9 (7);
stringId strId1("rrrrrrrrrrrrrrrrrrrrrrrrrr1");
stringId strId2("rrrrrrrrrrrrrrrrrrrrrrrrrr2");
assert (intTbl.add(fred0)==0);
assert (intTbl.add(fred1)==0);
assert (intTbl.add(fred2)==0);
assert (intTbl.add(fred3)==0);
assert (intTbl.add(fred4)==0);
assert (intTbl.add(fred5)==0);
assert (intTbl.add(fred6)==0);
assert (intTbl.add(fred7)==0);
assert (intTbl.add(fred8)==0);
assert (intTbl.add(fred9)==0);
start = clock();
for (i=0; i<LOOPS; i++) {
pFred = intTbl.lookup(intId1);
assert(pFred==&fred1);
pFred = intTbl.lookup(intId2);
assert(pFred==&fred2);
pFred = intTbl.lookup(intId3);
assert(pFred==&fred3);
pFred = intTbl.lookup(intId4);
assert(pFred==&fred4);
pFred = intTbl.lookup(intId5);
assert(pFred==&fred5);
pFred = intTbl.lookup(intId6);
assert(pFred==&fred6);
pFred = intTbl.lookup(intId7);
assert(pFred==&fred7);
pFred = intTbl.lookup(intId8);
assert(pFred==&fred8);
pFred = intTbl.lookup(intId9);
assert(pFred==&fred9);
pFred = intTbl.lookup(intId0);
assert(pFred==&fred0);
}
finish = clock();
duration = finish-start;
duration /= CLOCKS_PER_SEC;
printf("It took %15.10f total sec for integer hash lookups\n", duration);
duration /= LOOPS;
duration /= 10;
duration *= 1e6;
printf("It took %15.10f u sec per integer hash lookup\n", duration);
intTbl.show(10u);
intTbl.remove(intId1);
intTbl.remove(intId2);
assert (strTbl.add(jane1)==0);
assert (strTbl.add(jane2)==0);
start = clock();
for(i=0; i<LOOPS; i++){
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId1);
assert(pJane==&jane1);
pJane = strTbl.lookup(strId2);
assert(pJane==&jane2);
}
finish = clock();
duration = finish-start;
duration /= CLOCKS_PER_SEC;
printf("It took %15.10f total sec for string hash lookups\n", duration);
duration /= LOOPS;
duration /= 10;
duration *= 1e6;
printf("It took %15.10f u sec per string hash lookup\n", duration);
strTbl.show(10u);
strTbl.traverse(&jane::testTraverse);
strTbl.remove(strId1);
strTbl.remove(strId2);
start = clock();
for(i=0; i<LOOPS; i++){
empty();
empty();
empty();
empty();
empty();
empty();
empty();
empty();
empty();
empty();
}
finish = clock();
duration = finish-start;
duration /= CLOCKS_PER_SEC;
printf("It took %15.10f total sec for empty subroutines\n", duration);
duration /= LOOPS;
duration /= 10;
duration *= 1e6;
printf("It took %15.10f u sec to call an empty subroutine\n", duration);
//
// hash distribution test
//
static const unsigned tableSize = 0x1000;
resTable< albert, testIntId > alTbl (tableSize);
for (i=0; i<tableSize*8; i++) {
albert *pa = new albert (alTbl, i);
assert (pa);
}
alTbl.show(1u);
resTableIter< albert, testIntId > alTblIter (alTbl);
albert *pa;
i=0;
while ( (pa = alTblIter.next()) ) {
i++;
}
assert (i==tableSize*8);
return 0;
}
void empty()
{
}

View File

@@ -1,84 +0,0 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include "tsBTree.h"
#include "tsSLList.h"
class A : public tsBTreeNode<A>, public tsSLNode<A> {
public:
A()
{
key = (unsigned) rand();
}
btCmp tsBTreeCompare(const A &item) const
{
if (this->key<=item.key) {
return btLessOrEqual;
}
else {
return btGreater;
}
}
void show()
{
printf("A: %u\n", key);
}
private:
unsigned key;
};
#define LOOPCOUNT 10000u
int main ()
{
unsigned i;
tsBTree<A> tree;
tsSLList<A> list;
A *pA;
A a;
clock_t clk;
clock_t diff;
double delay;
tree.insert (a);
list.add (a);
for (i=0u; i<LOOPCOUNT; i++) {
pA = new A;
assert (pA);
tree.insert (*pA);
list.add (*pA);
}
clk = clock ();
for (i=0u; i<LOOPCOUNT; i++) {
assert ( tree.verify(a) );
}
diff = clock () - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf ("delay = %15.10f\n", delay);
clk = clock ();
while ( ( pA = list.get () ) ) {
assert (tree.remove(*pA));
}
diff = clock () - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf ("delay = %15.10f\n", delay);
tree.traverse (&A::show);
return 0;
}

View File

@@ -1,81 +0,0 @@
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "tsBTree.h"
class A : public tsBTreeNode<A> {
public:
A(const char *pNameIn) : pName(pNameIn) {}
btCmp tsBTreeCompare(const A &item) const
{
int cmp = strcmp(this->pName, item.pName);
if (cmp<=0) {
return btLessOrEqual;
}
else {
return btGreater;
}
}
void show()
{
printf("A: %s\n", pName);
}
private:
const char *pName;
};
int main ()
{
tsBTree<A> tree;
A a0 ("fred");
A a1 ("jane");
A a2 ("jane0");
A a3 ("bill");
A a4 ("jane");
A a5 ("dan");
A a6 ("joe");
tree.insert (a0);
tree.insert (a1);
tree.insert (a2);
tree.insert (a3);
tree.insert (a4);
tree.insert (a5);
tree.traverse (&A::show);
assert (tree.remove(a6)==tsbtrrNotFound);
tree.insert (a6);
assert (tree.remove(a6)==tsbtrrFound);
assert (tree.remove(a5)==tsbtrrFound);
assert (tree.remove(a5)==tsbtrrNotFound);
assert (!tree.verify(a5));
assert (tree.verify(a4));
assert (tree.remove(a0)==tsbtrrFound);
assert (!tree.verify(a0));
assert (tree.remove(a0)==tsbtrrNotFound);
tree.insert (a5);
assert (tree.verify(a5));
assert (tree.verify(a2));
assert (tree.remove(a2)==tsbtrrFound);
assert (!tree.verify(a2));
assert (tree.remove(a2)==tsbtrrNotFound);
assert (tree.verify(a5));
assert (tree.remove(a5)==tsbtrrFound);
assert (tree.remove(a5)==tsbtrrNotFound);
assert (tree.remove(a0)==tsbtrrNotFound);
assert (tree.remove(a4)==tsbtrrFound);
assert (tree.remove(a3)==tsbtrrFound);
assert (tree.remove(a4)==tsbtrrNotFound);
assert (tree.remove(a1)==tsbtrrFound);
tree.traverse (&A::show);
return 0;
}

View File

@@ -1,61 +0,0 @@
#include <tsDLList.h>
#include <assert.h>
#include <time.h>
#include <stdio.h>
class fred : public tsDLNode<fred> {
public:
fred() : count(0) {}
void inc () {count++;}
private:
unsigned count;
};
class jane : public fred, public tsDLNode<jane> {
public:
jane() {}
private:
};
#define LOOPCOUNT 100000
int main ()
{
tsDLList<fred> list;
tsDLFwdIter<fred> iter(list);
fred *pFred;
unsigned i;
clock_t clk;
clock_t diff;
double delay;
for (i=0; i<LOOPCOUNT; i++) {
pFred = new fred();
list.add(*pFred);
}
clk = clock();
while ( (pFred = iter()) ) {
pFred->inc();
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10f\n", delay);
pFred = new fred();
clk = clock();
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10f\n", delay);
return 0;
}

View File

@@ -1,102 +0,0 @@
#include <tsDLList.h>
#include <assert.h>
#include <stdio.h>
class fred : public tsDLNode<fred> {
public:
fred(const char * const pNameIn) : pName(pNameIn){}
void show () {printf("%s\n", pName);}
private:
const char * const pName;
};
class jane : public fred, public tsDLNode<jane> {
public:
jane(const char * const pNameIn) : fred(pNameIn){}
private:
};
int main ()
{
tsDLList<fred> list;
tsDLFwdIter<fred> iter(list);
fred *pFred;
fred *pFredII;
fred *pFredBack;
tsDLList<jane> janeList;
tsDLFwdIter<jane> janeFwdIter(janeList);
tsDLBwdIter<jane> janeBwdIter(janeList);
jane *pJane;
pFred = new fred("A");
pFredII = new fred("B");
list.add(*pFred);
list.add(*pFredII);
pFredBack = iter();
assert(pFredBack == pFred);
pFredBack = iter();
assert(pFredBack == pFredII);
list.remove(*pFred);
list.add(*pFred);
pFredBack = list.get();
assert (pFredBack == pFredII);
pFredBack = list.get();
assert (pFredBack == pFred);
assert (list.count() == 0u);
list.add(*pFred);
list.add(*pFredII);
list.add(* new fred("C"));
list.add(* new fred("D"));
iter.reset();
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
pJane = new jane("JA");
janeList.add(*pJane);
pJane = new jane("JB");
janeList.add(*pJane);
while ( (pJane = janeFwdIter()) ) {
pJane->show();
}
while ( (pJane = janeBwdIter()) ) {
pJane->show();
}
iter.reset();
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
iter.reset();
while ( (pFredBack = iter()) ) {
iter.remove();
}
assert(list.count()==0);
janeFwdIter.reset();
while ( (pFredBack = janeFwdIter()) ) {
janeFwdIter.remove();
}
assert(janeList.count()==0);
pJane = new jane("JA");
janeList.add(*pJane);
pJane = new jane("JB");
janeList.add(*pJane);
janeBwdIter.reset();
while ( (pFredBack = janeBwdIter()) ) {
janeBwdIter.remove();
}
assert(janeList.count()==0);
return 0;
}

View File

@@ -1,75 +0,0 @@
#include <tsSLList.h>
#include <assert.h>
#include <stdio.h>
#include <time.h>
/*
* gnuc does not provide this under sunos4
*/
#if !defined(CLOCKS_PER_SEC) && defined(SUNOS4)
# define CLOCKS_PER_SEC 1000000
#endif
class fred : public tsSLNode<fred> {
public:
fred() : count(0) {}
void inc () {count++;}
private:
unsigned count;
};
class jane : public fred, public tsSLNode<jane> {
public:
jane() {}
private:
};
#define LOOPCOUNT 100000
int main ()
{
tsSLList<fred> list;
fred *pFred;
unsigned i;
clock_t clk;
clock_t diff;
double delay;
for (i=0; i<LOOPCOUNT; i++) {
pFred = new fred();
list.add(*pFred);
}
clk = clock();
{
tsSLIter<fred> iter(list);
while ( (pFred = iter()) ) {
pFred->inc();
}
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10f\n", delay);
pFred = new fred();
clk = clock();
{
tsSLIter<fred> iter(list);
for (i=0; i<LOOPCOUNT; i++) {
pFred->inc();
}
}
diff = clock() - clk;
delay = diff;
delay = delay/CLOCKS_PER_SEC;
delay = delay/LOOPCOUNT;
printf("delay = %15.10f\n", delay);
return 0;
}

View File

@@ -1,105 +0,0 @@
#include <tsSLList.h>
#include <assert.h>
#include <stdio.h>
class fred : public tsSLNode<fred> {
public:
fred(const char * const pNameIn) : pName(pNameIn){}
void show () {printf("%s\n", pName);}
private:
const char * const pName;
};
class jane : public fred, public tsSLNode<jane> {
public:
jane(const char * const pNameIn) : fred(pNameIn){}
private:
};
int main ()
{
tsSLList<fred> list;
fred *pFred;
fred *pFredII;
fred *pFredBack;
tsSLList<jane> janeList;
jane *pJane;
pFred = new fred("A");
pFredII = new fred("B");
list.add(*pFred);
list.add(*pFredII);
{
tsSLIterRm<fred> iter(list);
pFredBack = iter();
assert(pFredBack == pFredII);
pFredBack = iter();
assert(pFredBack == pFred);
iter.remove(); // removes pFred
}
list.add(*pFred);
pFredBack = list.get();
assert (pFredBack == pFred);
pFredBack = list.get();
assert (pFredBack == pFredII);
list.add(*pFredII);
list.add(*pFred);
{
tsSLIterRm<fred> iter(list);
while ( (pFredBack = iter()) ) {
iter.remove();
}
}
pFredBack = list.get();
assert (pFredBack == 0);
list.add(*pFred);
list.add(*pFredII);
list.add(* new fred("C"));
list.add(* new fred("D"));
{
tsSLIter<fred> iter(list);
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
}
pJane = new jane("JA");
janeList.add(*pJane);
pJane = new jane("JB");
janeList.add(*pJane);
{
tsSLIter<jane> janeIter(janeList);
while ( (pJane = janeIter()) ) {
pJane->show();
}
}
{
tsSLIter<fred> iter(list);
while ( (pFredBack = iter()) ) {
pFredBack->show();
}
}
{
tsSLIterRm<fred> iter(list);
while ( (pFredBack = iter()) ) {
iter.remove();
}
}
{
tsSLIter<fred> iter(list);
pFredBack = iter();
assert(pFredBack==NULL);
}
return 0;
}

View File

@@ -1,271 +0,0 @@
#include <assert.h>
//
// tsBTreeRMRet
//
enum tsbtRR {tsbtrrNotFound, tsbtrrFound};
template <class T>
class tsBTreeRMRet {
public:
tsBTreeRMRet (tsbtRR foundItIn, T *pNewSegIn) :
foundIt(foundItIn), pNewSeg(pNewSegIn) {}
operator tsbtRR ()
{
return this->foundIt;
}
const tsbtRR foundIt;
T * const pNewSeg;
};
template <class T> class tsBTree;
//
// tsBTreeNode
//
template <class T>
class tsBTreeNode
{
friend class tsBTree<T>;
public:
//
// exceptions
//
class invalid_btCmp {};
//
// when someone copies into a class deriving from this
// do _not_ change the node pointers
//
void operator = (tsBTreeNode<T> &) {}
enum btCmp {btGreater, btLessOrEqual};
//
// class T must supply this member function which
// comapres *this with item
//
// returns:
// btGreater *this is greater than item
// btLessOrEqual *this is less than or equal to item
//
// btCmp tsBTreeCompare(const T &item) const;
//
private:
T *pLeft;
T *pRight;
//
// run callback for evey item in the B-Treee in sort order
//
static void traverse (T &item, void (T::*pCallBack)())
{
tsBTreeNode<T> &node = item;
if (node.pLeft) {
tsBTreeNode<T>::traverse (*node.pLeft, pCallBack);
}
(item.*pCallBack)();
if (node.pRight) {
tsBTreeNode<T>::traverse (*node.pRight, pCallBack);
}
}
//
// NOTE:
// no change to item.pLeft and item.pRight here
// so that an segment of a tree can be inserted
//
static void insert(T &self, T &item)
{
tsBTreeNode<T> &node = self;
btCmp result = item.tsBTreeCompare(self);
if (result==btLessOrEqual) {
if (node.pLeft) {
tsBTreeNode<T>::insert (*node.pLeft, item);
}
else {
node.pLeft = &item;
}
}
else if(result==btGreater) {
if (node.pRight) {
tsBTreeNode<T>::insert (*node.pRight, item);
}
else {
node.pRight = &item;
}
}
else {
# ifdef noExceptionsFromCXX
assert (0);
# else
throw invalid_btCmp ();
# endif
}
}
//
// remove()
// returns pointer to modified tree and found/not found
// (NULL if this portion of the tree is empty)
//
static tsBTreeRMRet<T> remove(T &self, T &item)
{
tsBTreeNode<T> &node = self;
if (&self == &item) {
if (node.pLeft) {
if (node.pRight) {
tsBTreeNode<T> *pLeftNode = node.pLeft;
T *pR = pLeftNode->pRight;
if (pR) {
tsBTreeNode<T>::insert (*pR, *node.pRight);
}
else {
pLeftNode->pRight = node.pRight;
}
}
return tsBTreeRMRet<T>(tsbtrrFound, node.pLeft); // found it
}
else {
return tsBTreeRMRet<T>(tsbtrrFound, node.pRight); // found it
}
}
btCmp result = item.tsBTreeCompare(self);
if (result==btLessOrEqual) {
if (node.pLeft) {
tsBTreeRMRet<T> ret = tsBTreeNode<T>::remove(*node.pLeft, item);
if (ret.foundIt==tsbtrrFound) {
node.pLeft= ret.pNewSeg;
return tsBTreeRMRet<T> (tsbtrrFound, &self); // TRUE - found it
}
}
return tsBTreeRMRet<T>(tsbtrrNotFound, 0u); // not found
}
else if(result==btGreater) {
if (node.pRight) {
tsBTreeRMRet<T> ret = tsBTreeNode<T>::remove(*node.pRight, item);
if (ret.foundIt==tsbtrrFound) {
node.pRight = ret.pNewSeg;
return tsBTreeRMRet<T>(tsbtrrFound,&self); // TRUE - found it
}
}
return tsBTreeRMRet<T>(tsbtrrNotFound, 0u); // not found
}
else {
return tsBTreeRMRet<T>(tsbtrrNotFound, 0u); // not found
}
}
//
// verify
//
static unsigned verify(const T &self, const T &item)
{
const tsBTreeNode<T> &node = self;
if (&self == &item) {
return 1u; // TRUE -item is present
}
btCmp result = item.tsBTreeCompare(self);
if (result==btLessOrEqual) {
if (node.pLeft) {
return tsBTreeNode<T>::verify (*node.pLeft, item);
}
else {
return 0u; // FALSE - not found
}
}
else if(result==btGreater) {
if (node.pRight) {
return tsBTreeNode<T>::verify (*node.pRight, item);
}
else {
return 0u; // FALSE - not found
}
}
else {
return 0u; // FALSE - not found
}
}
};
//
// tsBTree
//
template <class T>
class tsBTree
{
public:
tsBTree() : pRoot(0u) {}
// ~tsBTree()
// {
// this->traverse(T::~T);
// }
void insert(T &item)
{
tsBTreeNode<T> &node = item;
node.pLeft = 0;
node.pRight = 0;
if (this->pRoot) {
tsBTreeNode<T>::insert(*this->pRoot, item);
}
else {
this->pRoot = &item;
}
}
//
// remove item from the tree
//
// returns true if item was in the tree
// (otherwise FALSE)
//
unsigned remove(T &item)
{
if (this->pRoot) {
tsBTreeRMRet<T> ret =
tsBTreeNode<T>::remove(*this->pRoot, item);
if (ret.foundIt) {
this->pRoot = ret.pNewSeg;
return 1u; // TRUE - found it
}
}
return 0u; // FALSE - not found
}
//
// verify that item is in the tree
//
// returns true if item is in the tree
// (otherwise FALSE)
//
unsigned verify(T &item) const
{
if (this->pRoot) {
return tsBTreeNode<T>::verify(*this->pRoot, item);
}
else {
return 0u; // FALSE - not found
}
}
//
// Call (pT->*pCB) () for each item in the table
//
// where pT is a pointer to type T and pCB is
// a pointer to a memmber function of T with
// no parameters and returning void
//
void traverse(void (T::*pCB)())
{
if (this->pRoot) {
tsBTreeNode<T>::traverse(*this->pRoot, pCB);
}
}
private:
T *pRoot;
};

View File

@@ -1,984 +0,0 @@
/*
* $Id$
*
* type safe doubly linked list templates
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*/
#ifndef tsDLListH_include
#define tsDLListH_include
template <class T> class tsDLList;
template <class T> class tsDLIter;
template <class T> class tsDLFwdIter;
template <class T> class tsDLBwdIter;
template <class T> class tsDLIterBD;
//
// class tsDLNode<T>
//
// a node in a doubly linked list
//
// NOTE: class T must derive from tsDLNode<T>
//
template <class T>
class tsDLNode {
friend class tsDLList<T>;
friend class tsDLIter<T>;
friend class tsDLFwdIter<T>;
friend class tsDLBwdIter<T>;
friend class tsDLIterBD<T>;
public:
tsDLNode();
void operator = (const tsDLNode<T> &) const;
private:
T *pNext;
T *pPrev;
//protected:
// T *getNext(void) const;
// T *getPrev(void) const;
};
//
// class tsDLList<T>
//
// a doubly linked list
//
// NOTE: class T must derive from tsDLNode<T>
//
template <class T>
class tsDLList {
friend class tsDLIter<T>;
friend class tsDLFwdIter<T>;
friend class tsDLBwdIter<T>;
public:
tsDLList (); // create empty list
unsigned count () const; // number of items on list
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<T> &addList);
void push (T &item); // add item to beginning of list
// remove item from list
void remove (T &item);
T * get (); // removes first item on list
T * pop (); // same as get ()
// 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);
//
// returns -1 if the item isnt on the list and the node
// number (beginning with zero if it is)
//
int find (T &item) const;
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;
//
// 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 private
// and _not_ implemented.
//
tsDLList (const tsDLList &);
};
//
// tsDLIter<T>
//
// doubly linked list iterator
//
// Notes:
// 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
// point at the item before or after the
// item removed
//
template <class T>
class tsDLIter {
public:
tsDLIter (tsDLList<T> & listIn);
void reset ();
void reset (tsDLList<T> &listIn);
void operator = (tsDLList<T> &listIn);
T * next ();
T * prev ();
T * first();
T * last();
T * operator () ();
protected:
T *pCurrent;
tsDLList<T> *pList;
T * current (); // certain compilers require this
};
//
// class tsDLFwdIter<T>
//
// 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)
//
// 2) This iterator only moves forward in order to
// avoid problems resulting when we remove an
// item (and then dont know whether to make
// pCurrent point at the item before or after
// the item removed
//
template <class T>
class tsDLFwdIter: private tsDLIter<T> {
public:
tsDLFwdIter (tsDLList<T> &listIn);
void reset ();
void reset (tsDLList<T> &listIn);
void operator = (tsDLList<T> &listIn);
T * operator () ();
T * next ();
T * first();
//
// remove ()
// (and move current to be the item
// pointed to by pPrev - 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)
//
void remove ();
protected:
T *current ();
};
//
// tsDLBwdIter<T>
//
// 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)
//
// 2) This iterator only moves backward in order to
// avoid problems resulting when we remove an
// item (and then dont know whether to make
// pCurrent point at the item before or after
// the item removed
//
template <class T>
class tsDLBwdIter : private tsDLIter<T> {
public:
tsDLBwdIter (tsDLList<T> &listIn);
void reset ();
void reset (tsDLList<T> &listIn);
void operator = (tsDLList<T> &listIn);
T * operator () ();
T * prev ();
T * last();
//
// remove ()
// remove current item
// (and move current to be the item
// pointed to by pNext - 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)
//
void remove ();
protected:
T * current ();
};
//
// class tsDLIterBD<T>
//
// bi-directional doubly linked list iterator
//
template <class T>
class tsDLIterBD {
public:
tsDLIterBD (T *pInitialEntry);
tsDLIterBD<T> operator = (T *pNewEntry);
bool operator == (const tsDLIterBD<T> &rhs) const;
bool operator != (const tsDLIterBD<T> &rhs) const;
T & operator * () const;
T * operator -> () const;
operator T* () const;
tsDLIterBD<T> operator ++ (); // prefix ++
tsDLIterBD<T> operator ++ (int); // postfix ++
tsDLIterBD<T> operator -- (); // prefix --
tsDLIterBD<T> operator -- (int); // postfix --
# if defined(_MSC_VER) && _MSC_VER < 1200
tsDLIterBD (const class tsDLIterBD<T> &copyIn);
# endif
//
// end of the list constant
//
static const tsDLIterBD<T> eol ();
private:
T *pEntry;
};
///////////////////////////////////
// tsDLNode<T> member functions
///////////////////////////////////
//
// tsDLNode<T>::tsDLNode ()
//
template <class T>
inline tsDLNode<T>::tsDLNode() : pNext(0), pPrev(0) {}
//
// tsDLNode<T>::operator = ()
//
// when someone copies in a class deriving from this
// do _not_ change the node pointers
//
template <class T>
inline void tsDLNode<T>::operator = (const tsDLNode<T> &) const {}
//template <class T>
//T * tsDLNode<T>::getNext (void) const
//{
// return pNext;
//}
//template <class T>
//T * tsDLNode<T>::getPrev (void) const
//{
// return pPrev;
//}
//////////////////////////////////////
// tsDLList<T> member functions
//////////////////////////////////////
//
// tsDLList<T>::tsDLList ()
//
template <class T>
inline tsDLList<T>::tsDLList ()
{
this->clear ();
}
//
// tsDLList<T>::count ()
//
// (returns the number of items on the list)
//
template <class T>
inline unsigned tsDLList<T>::count () const
{
return this->itemCount;
}
//
// tsDLList<T>::first ()
//
template <class T>
inline T * tsDLList<T>::first (void) const
{
return this->pFirst;
}
//
// tsDLList<T>::last ()
//
template <class T>
inline T *tsDLList<T>::last (void) const
{
return this->pLast;
}
//
// tsDLList<T>::clear ()
//
template <class T>
inline void tsDLList<T>::clear ()
{
this->pFirst = 0;
this->pLast = 0;
this->itemCount = 0u;
}
//
// tsDLList<T>::remove ()
//
template <class T>
void tsDLList<T>::remove (T &item)
{
tsDLNode<T> &theNode = item;
if (this->pLast == &item) {
this->pLast = theNode.pPrev;
}
else {
tsDLNode<T> &nextNode = *theNode.pNext;
nextNode.pPrev = theNode.pPrev;
}
if (this->pFirst == &item) {
this->pFirst = theNode.pNext;
}
else {
tsDLNode<T> &prevNode = *theNode.pPrev;
prevNode.pNext = theNode.pNext;
}
this->itemCount--;
}
//
// tsDLList<T>::get ()
//
template <class T>
inline T * tsDLList<T>::get()
{
T *pItem = this->pFirst;
if (pItem) {
this->remove (*pItem);
}
return pItem;
}
//
// tsDLList<T>::pop ()
//
// (returns the first item on the list)
template <class T>
inline T * tsDLList<T>::pop()
{
return this->get();
}
//
// tsDLList<T>::add ()
//
// adds addList to the end of the list
// (and removes all items from addList)
//
template <class T>
void tsDLList<T>::add (tsDLList<T> &addList)
{
//
// NOOP if addList is empty
//
if (addList.itemCount==0u) {
return;
}
if (this->itemCount==0u) {
//
// this is empty so just init from
// addList
//
*this = addList;
}
else {
tsDLNode<T> *pLastNode = this->pLast;
tsDLNode<T> *pAddListFirstNode = addList.pFirst;
//
// add addList to the end of this
//
pLastNode->pNext = addList.pFirst;
pAddListFirstNode->pPrev = addList.pLast;
this->pLast = addList.pLast;
this->itemCount += addList.itemCount;
}
//
// leave addList empty
//
addList.clear();
}
//
// tsDLList<T>::add ()
//
// add an item to the end of the list
//
template <class T>
void tsDLList<T>::add (T &item)
{
tsDLNode<T> &theNode = item;
theNode.pNext = 0;
theNode.pPrev = this->pLast;
if (this->itemCount) {
tsDLNode<T> &lastNode = *this->pLast;
lastNode.pNext = &item;
}
else {
this->pFirst = &item;
}
this->pLast = &item;
this->itemCount++;
}
//
// tsDLList<T>::insertAfter ()
//
// place item in the list immediately after itemBefore
//
template <class T>
void tsDLList<T>::insertAfter (T &item, T &itemBefore)
{
tsDLNode<T> &nodeItem = item;
tsDLNode<T> &nodeBefore = itemBefore;
nodeItem.pPrev = &itemBefore;
nodeItem.pNext = nodeBefore.pNext;
nodeBefore.pNext = &item;
if (nodeItem.pNext) {
tsDLNode<T> *pNextNode = nodeItem.pNext;
pNextNode->pPrev = &item;
}
else {
this->pLast = &item;
}
this->itemCount++;
}
//
// tsDLList<T>::insertBefore ()
//
// place item in the list immediately before itemAfter
//
template <class T>
void tsDLList<T>::insertBefore (T &item, T &itemAfter)
{
tsDLNode<T> &node = item;
tsDLNode<T> &nodeAfter = itemAfter;
node.pNext = &itemAfter;
node.pPrev = nodeAfter.pPrev;
nodeAfter.pPrev = &item;
if (node.pPrev) {
tsDLNode<T> &prevNode = *node.pPrev;
prevNode.pNext = &item;
}
else {
this->pFirst = &item;
}
this->itemCount++;
}
//
// tsDLList<T>::push ()
//
// add an item at the beginning of the list
//
template <class T>
void tsDLList<T>::push (T &item)
{
tsDLNode<T> &theNode = item;
theNode.pPrev = 0;
theNode.pNext = this->pFirst;
if (this->itemCount) {
tsDLNode<T> *pFirstNode = this->pFirst;
pFirstNode->pPrev = &item;
}
else {
this->pLast = &item;
}
this->pFirst = &item;
this->itemCount++;
}
//
// tsDLList<T>::find ()
// returns -1 if the item isnt on the list
// and the node number (beginning with zero if
// it is)
//
template <class T>
int tsDLList<T>::find (T &item) const
{
tsDLFwdIter<T> iter (*this);
tsDLNode<T> *pItem;
int itemNo=0;
while ( (pItem = iter.next()) ) {
if (pItem == &item) {
return itemNo;
}
itemNo++;
}
return -1;
}
//////////////////////////////////////////
// tsDLIterBD<T> member functions
//////////////////////////////////////////
template <class T>
inline tsDLIterBD<T>::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 <class T>
tsDLIterBD<T>::tsDLIterBD (const class tsDLIterBD<T> &copyIn) :
pEntry(copyIn.pEntry) {}
# endif
template <class T>
inline tsDLIterBD<T> tsDLIterBD<T>::operator = (T *pNewEntry)
{
this->pEntry = pNewEntry;
return *this;
}
template <class T>
inline bool tsDLIterBD<T>::operator == (const tsDLIterBD<T> &rhs) const
{
return (this->pEntry == rhs.pEntry);
}
template <class T>
inline bool tsDLIterBD<T>::operator != (const tsDLIterBD<T> &rhs) const
{
return (this->pEntry != rhs.pEntry);
}
template <class T>
inline T & tsDLIterBD<T>::operator * () const
{
return *this->pEntry;
}
template <class T>
inline T * tsDLIterBD<T>::operator -> () const
{
return this->pEntry;
}
template <class T>
inline tsDLIterBD<T>::operator T* () const
{
return this->pEntry;
}
//
// prefix ++
//
template <class T>
inline tsDLIterBD<T> tsDLIterBD<T>::operator ++ ()
{
tsDLNode<T> &node = *this->pEntry;
this->pEntry = node.pNext;
return *this;
}
//
// postfix ++
//
template <class T>
inline tsDLIterBD<T> tsDLIterBD<T>::operator ++ (int)
{
tsDLIterBD<T> tmp = *this;
tsDLNode<T> &node = *this->pEntry;
this->pEntry = node.pNext;
return tmp;
}
//
// prefix --
//
template <class T>
inline tsDLIterBD<T> tsDLIterBD<T>::operator -- ()
{
tsDLNode<T> &entryNode = *this->pEntry;
this->pEntry = entryNode.pPrev;
return *this;
}
//
// postfix --
//
template <class T>
inline tsDLIterBD<T> tsDLIterBD<T>::operator -- (int)
{
tsDLIterBD<T> tmp = *this;
tsDLNode<T> &entryNode = *this->pEntry;
this->pEntry = entryNode.pPrev;
return tmp;
}
//
// tsDLIterBD<T>::eol
//
template <class T>
inline const tsDLIterBD<T> tsDLIterBD<T>::eol ()
{
return tsDLIterBD<T>(0);
}
//////////////////////////////////////////
// tsDLIter<T> member functions
//////////////////////////////////////////
template <class T>
inline tsDLIter<T>::tsDLIter (tsDLList<T> & listIn) :
pCurrent(0), pList(&listIn) {}
template <class T>
inline void tsDLIter<T>::reset ()
{
this->pCurrent = 0;
}
template <class T>
inline void tsDLIter<T>::reset (tsDLList<T> &listIn)
{
this->reset();
this->pList = &listIn;
}
template <class T>
inline void tsDLIter<T>::operator = (tsDLList<T> &listIn)
{
this->reset(listIn);
}
template <class T>
inline T * tsDLIter<T>::first()
{
this->pCurrent = this->pList->pFirst;
return this->pCurrent;
}
template <class T>
inline T * tsDLIter<T>::last()
{
this->pCurrent = this->pList->pLast;
return this->pCurrent;
}
//
// tsDLIter<T>::next ()
//
template <class T>
inline T * tsDLIter<T>::next ()
{
T *pCur = this->pCurrent;
if (pCur==0) {
pCur = this->pList->pFirst;
}
else {
tsDLNode<T> *pCurNode = pCur;
pCur = pCurNode->pNext;
}
this->pCurrent = pCur;
return pCur;
}
//
// tsDLIter<T>::prev ()
//
template <class T>
inline T * tsDLIter<T>::prev ()
{
T *pCur = this->pCurrent;
if (pCur==0) {
pCur = this->pList->pLast;
}
else {
tsDLNode<T> *pCurNode = pCur;
pCur = pCurNode->pPrev;
}
this->pCurrent = pCur;
return pCur;
}
//
// tsDLIter<T>::operator () ()
//
template <class T>
inline T * tsDLIter<T>::operator () ()
{
return this->next();
}
//
// tsDLIter<T>::current()
//
template <class T>
inline T * tsDLIter<T>::current()
{
return this->pCurrent;
}
///////////////////////////////////////////
// tsDLBwdIter<T> member functions
///////////////////////////////////////////
template <class T>
inline tsDLBwdIter<T>::tsDLBwdIter(tsDLList<T> &listIn) :
tsDLIter<T>(listIn) {}
template <class T>
inline void tsDLBwdIter<T>::reset ()
{
this->tsDLIter<T>::reset();
}
template <class T>
inline void tsDLBwdIter<T>::reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
template <class T>
inline void tsDLBwdIter<T>::operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
template <class T>
inline T * tsDLBwdIter<T>::last()
{
return this->tsDLIter<T>::last();
}
//
// tsDLBwdIter<T>::remove ()
//
// remove current item
// (and move current to be the item
// pointed to by pNext - 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)
//
template <class T>
void tsDLBwdIter<T>::remove ()
{
T *pCur = this->pCurrent;
if (pCur) {
tsDLNode<T> *pCurNode = pCur;
//
// strip const (we didnt declare the
// list const in the constructor)
//
tsDLList<T> * pMutableList =
(tsDLList<T> *) this->pList;
//
// Move this->pCurrent to the item after the
// item being deleted
//
this->pCurrent = pCurNode->pNext;
//
// delete current item
//
pMutableList->remove(*pCur);
}
}
//
// tsDLBwdIter<T>::operator () ()
//
template <class T>
inline T * tsDLBwdIter<T>::operator () ()
{
return this->tsDLIter<T>::prev();
}
//
// tsDLBwdIter<T>::prev ()
//
template <class T>
inline T * tsDLBwdIter<T>::prev ()
{
return this->tsDLIter<T>::prev();
}
template <class T>
inline T * tsDLBwdIter<T>::current()
{
return this->tsDLIter<T>::current ();
}
//////////////////////////////////////////
// tsDLFwdIter<T> member functions
//////////////////////////////////////////
template <class T>
inline tsDLFwdIter<T>::tsDLFwdIter (tsDLList<T> &listIn) :
tsDLIter<T>(listIn) {}
template <class T>
inline void tsDLFwdIter<T>::reset ()
{
this->tsDLIter<T>::reset();
}
template <class T>
inline void tsDLFwdIter<T>::reset (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
template <class T>
inline void tsDLFwdIter<T>::operator = (tsDLList<T> &listIn)
{
this->tsDLIter<T>::reset(listIn);
}
template <class T>
inline T * tsDLFwdIter<T>::first()
{
tsDLIter<T> &iterBase = *this;
return iterBase.first();
}
template <class T>
inline T * tsDLFwdIter<T>::current()
{
return this->tsDLIter<T>::current ();
}
//
// tsDLFwdIter<T>::remove ()
// (and move current to be the item
// pointed to by pPrev - 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)
//
template <class T>
void tsDLFwdIter<T>::remove ()
{
T *pCur = this->pCurrent;
if (pCur) {
tsDLNode<T> *pCurNode = pCur;
//
// Move this->pCurrent to the previous item
//
this->pCurrent = pCurNode->pPrev;
//
// delete current item
//
this->pList->remove(*pCur);
}
}
//
// tsDLFwdIter<T>::next ()
//
template <class T>
inline T * tsDLFwdIter<T>::next ()
{
tsDLIter<T> &iterBase = *this;
return iterBase.next();
}
//
// tsDLFwdIter<T>::operator () ()
//
template <class T>
inline T * tsDLFwdIter<T>::operator () ()
{
return this->next();
}
#endif // tsDLListH_include

View File

@@ -1,17 +0,0 @@
//
// simple type safe inline template functions to replace
// the min() and max() macros
//
template <class T>
inline const T & tsMax (const T &a, const T &b)
{
return (a>b) ? a : b;
}
template <class T>
inline const T & tsMin (const T &a, const T &b)
{
return (a<b) ? a : b;
}

View File

@@ -1,404 +0,0 @@
/*
* $Id$
*
* type safe singly linked list templates
*
* Author Jeffrey O. Hill
* johill@lanl.gov
* 505 665 1831
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991, the Regents of the University of California,
* and the University of Chicago Board of Governors.
*
* This software was produced under U.S. Government contracts:
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
* and (W-31-109-ENG-38) at Argonne National Laboratory.
*
* Initial development by:
* The Controls and Automation Group (AT-8)
* Ground Test Accelerator
* Accelerator Technology Division
* Los Alamos National Laboratory
*
* Co-developed with
* The Controls and Computing Group
* Accelerator Systems Division
* Advanced Photon Source
* Argonne National Laboratory
*
*/
#ifndef tsSLListh
#define tsSLListh
#include <assert.h>
//
// the hp compiler complains about parameterized friend
// class that has not been declared without this?
//
template <class T> class tsSLList;
template <class T> class tsSLIter;
template <class T> class tsSLIterRm;
//
// tsSLNode<T>
// NOTE: class T must derive from tsSLNode<T>
//
template <class T>
class tsSLNode {
friend class tsSLList<T>;
friend class tsSLIter<T>;
friend class tsSLIterRm<T>;
public:
tsSLNode ();
void operator = (const tsSLNode<T> &) const;
private:
void removeNextItem (); // removes the item after this node
T *pNext;
};
//
// tsSLList<T>
// NOTE: class T must derive from tsSLNode<T>
//
template <class T>
class tsSLList : public tsSLNode<T> {
public:
tsSLList (); // creates an empty list
void insert (T &item, tsSLNode<T> &itemBefore); // insert after item before
void add (T &item); // add to the beginning of the list
T * get (); // remove from the beginning of the list
T * pop (); // same as get
void push (T &item); // same as add
private:
tsSLList (const tsSLList &); // intentionally _not_ implemented
};
//
// tsSLIter<T>
//
template <class T>
class tsSLIter {
public:
tsSLIter (const tsSLList<T> &listIn);
T * next (); // move iterator forward
T * operator () (); // same as next ()
private:
T *pCurrent;
const tsSLList<T> *pList; // ptr allows cpy op
};
//
// tsSLIterRm<T>
// (An tsSLIter<T> that allows removing a node)
//
template <class T>
class tsSLIterRm {
public:
//
// exceptions
//
class noCurrentItemInIterator {};
tsSLIterRm (tsSLList<T> &listIn);
T * next (); // move iterator forward
T * operator () (); // same as next ()
void remove (); // remove current node
private:
T *pPrevious;
T *pCurrent;
tsSLList<T> *pList; // ptr allows cpy op
};
//////////////////////////////////////////
//
// tsSLNode<T> inline member functions
//
//////////////////////////////////////////
//
// tsSLNode<T>::tsSLNode
//
template <class T>
tsSLNode<T>::tsSLNode() : pNext(0) {}
//
// tsSLNode<T>::operator =
//
// when someone copies into a class deriving from this
// do _not_ change the node pointers
//
template <class T>
inline void tsSLNode<T>::operator = (const tsSLNode<T> &) const {}
//
// removeNextItem ()
//
// removes the item after this node
//
template <class T>
inline void tsSLNode<T>::removeNextItem ()
{
T *pItem = this->pNext;
if (pItem) {
tsSLNode<T> *pNode = pItem;
this->pNext = pNode->pNext;
}
}
//////////////////////////////////////////
//
// tsSLList<T> inline memeber functions
//
//////////////////////////////////////////
//
// tsSLList<T>::tsSLList()
// create an empty list
//
template <class T>
inline tsSLList<T>::tsSLList ()
{
}
//
// tsSLList<T>::insert()
// (itemBefore might be the list header object and therefore
// will not always be of type T)
//
template <class T>
inline void tsSLList<T>::insert (T &item, tsSLNode<T> &itemBefore)
{
tsSLNode<T> &node = item;
node.pNext = itemBefore.pNext;
itemBefore.pNext = &item;
}
//
// tsSLList<T>::add ()
//
template <class T>
inline void tsSLList<T>::add (T &item)
{
this->insert (item, *this);
}
//
// tsSLList<T>::get ()
//
template <class T>
inline T * tsSLList<T>::get()
{
tsSLNode<T> *pThisNode = this;
T *pItem = pThisNode->pNext;
pThisNode->removeNextItem();
return pItem;
}
//
// tsSLList<T>::pop ()
//
template <class T>
inline T * tsSLList<T>::pop()
{
return this->get();
}
//
// tsSLList<T>::push ()
//
template <class T>
inline void tsSLList<T>::push(T &item)
{
this->add(item);
}
//////////////////////////////////////////
//
// tsSLIter<T> inline memeber functions
//
//////////////////////////////////////////
//
// tsSLIter<T>::tsSLIter
//
template <class T>
inline tsSLIter<T>::tsSLIter (const tsSLList<T> &listIn) :
pCurrent (0), pList (&listIn) {}
//
// tsSLIter<T>::next ()
//
// 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<T> to a T even if
// tsSLNode<T> is always a base class of a T.
//
template <class T>
T * tsSLIter<T>::next ()
{
if (this->pCurrent!=0) {
tsSLNode<T> *pCurNode = this->pCurrent;
this->pCurrent = pCurNode->pNext;
}
else {
const tsSLNode<T> &first = *this->pList;
//
// assume that we are starting (or restarting) at the
// beginning of the list
//
this->pCurrent = first.pNext;
}
return this->pCurrent;
}
//
// move iterator forward
//
template <class T>
inline T * tsSLIter<T>::operator () ()
{
return this->next();
}
//////////////////////////////////////////
//
// tsSLIterRm<T> 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<T>::tsSLIterRm ()
//
template <class T>
inline tsSLIterRm<T>::tsSLIterRm (tsSLList<T> &listIn) :
pPrevious (0), pCurrent (0), pList (&listIn) {}
//
// tsSLIterRm<T>::next ()
//
// 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<T> to a T even if
// tsSLNode<T> is always a base class of a T.
//
template <class T>
T * tsSLIterRm<T>::next ()
{
if (this->pCurrent!=0) {
tsSLNode<T> *pCurNode = this->pCurrent;
this->pPrevious = this->pCurrent;
this->pCurrent = pCurNode->pNext;
}
else {
const tsSLNode<T> &first = *this->pList;
//
// assume that we are starting (or restarting) at the
// beginning of the list
//
this->pCurrent = first.pNext;
this->pPrevious = 0;
}
return this->pCurrent;
}
//
// move iterator forward
//
template <class T>
inline T * tsSLIterRm<T>::operator () ()
{
return this->next();
}
//
// tsSLIterRm<T>::remove ()
//
// 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 throws an exception.
//
template <class T>
void tsSLIterRm<T>::remove ()
{
if (this->pCurrent==0) {
# ifdef noExceptionsFromCXX
assert (0);
# else
throw noCurrentItemInIterator ();
# endif
}
tsSLNode<T> *pPrevNode;
tsSLNode<T> *pCurNode = this->pCurrent;
if (this->pPrevious==0) {
pPrevNode = this->pList;
//
// fail if it is an attempt to
// delete twice without moving the iterator
//
if (pPrevNode->pNext != this->pCurrent) {
# ifdef noExceptionsFromCXX
assert (0);
# else
throw noCurrentItemInIterator ();
# endif
}
}
else {
pPrevNode = this->pPrevious;
}
pPrevNode->pNext = pCurNode->pNext;
this->pCurrent = this->pPrevious;
this->pPrevious = 0;
}
#endif // tsSLListh