cxxTemplates files now moved to libCom/cxxTemplates.
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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> ©In);
|
||||
# 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> ©In) :
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user