This is Unofficial EPICS BASE Doxygen Site
resourceLib.h
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /*
10  * General hash table templates for fast indexing of resources
11  * of any base resource type and any resource identifier type. Fast
12  * indexing is implemented with a hash lookup. The identifier type
13  * implements the hash algorithm (or derives from one of the supplied
14  * identifier types which provide a hashing routine). The table expands
15  * dynamically depending on load, and without introducing non-determanistic
16  * latency.
17  *
18  * Unsigned integer and string identifier classes are supplied here.
19  *
20  * Authors Jeffrey O. Hill
21  * Marty Kraimer (string hash algorithm)
22  * influenced by papers by Peter K. Pearson and Per-Ake Larson
23  *
24  * johill@lanl.gov
25  * 505 665 1831
26  */
27 
28 #ifndef INCresourceLibh
29 #define INCresourceLibh
30 
31 #include <new>
32 #include <typeinfo>
33 
34 #include <stdio.h>
35 #include <limits.h>
36 #include <string.h>
37 #include <math.h>
38 #ifndef assert // allow use of epicsAssert.h
39 #include <assert.h>
40 #endif
41 
42 #include "tsSLList.h"
43 #include "epicsString.h"
44 #include "libComAPI.h"
45 typedef size_t resTableIndex;
46 
47 template < class T, class ID > class resTableIter;
48 template < class T, class ID > class resTableIterConst;
49 
50 //
51 // class resTable <T, ID>
52 //
53 // This class stores resource entries of type T which can be efficiently
54 // located with a hash key of type ID.
55 //
56 // NOTES:
57 // 1) class T must derive from class ID and also from class tsSLNode<T>
58 //
59 // 2) If the "resTable::show (unsigned level)" member function is called then
60 // class T must also implement a "show (unsigned level)" member function which
61 // dumps increasing diagnostics information with increasing "level" to
62 // standard out.
63 //
64 // 3) Classes of type ID must implement the following member functions:
65 //
66 // // equivalence test
67 // bool operator == (const ID &);
68 //
69 // // ID to hash index convert (see examples below)
70 // resTableIndex hash (unsigned nBitsHashIndex) const;
71 //
72 // 4) Storage for identifier of type ID must persist until the item of type
73 // T is deleted from the resTable
74 //
75 template <class T, class ID>
76 class resTable {
77 public:
78  resTable ();
79  virtual ~resTable();
80  // Call " void T::show (unsigned level)" for each entry
81  void show ( unsigned level ) const;
82  void verify () const;
83  int add ( T & res ); // returns -1 (id exists in table), 0 (success)
84  T * remove ( const ID &idIn ); // remove entry
85  void removeAll ( tsSLList<T> & destination ); // remove all entries
86  T * lookup ( const ID &idIn ) const; // locate entry
87  // Call (pT->*pCB) () for each entry but expect poor performance
88  // with sparcely populated tables
89  void traverse ( void (T::*pCB)() );
90  void traverseConst ( void (T::*pCB)() const ) const;
91  unsigned numEntriesInstalled () const;
92  void setTableSize ( const unsigned newTableSize );
93  // iterate through all entries but expect poor performance
94  // with sparcely populated tables
97  iterator firstIter ();
98  iteratorConst firstIter () const;
99 private:
100  tsSLList < T > * pTable;
101  unsigned nextSplitIndex;
102  unsigned hashIxMask;
103  unsigned hashIxSplitMask;
104  unsigned nBitsHashIxSplitMask;
105  unsigned logBaseTwoTableSize;
106  unsigned nInUse;
107  resTableIndex hash ( const ID & idIn ) const;
108  T * find ( tsSLList<T> & list, const ID & idIn ) const;
109  void splitBucket ();
110  unsigned tableSize () const;
111  bool setTableSizePrivate ( unsigned logBaseTwoTableSize );
112  resTable ( const resTable & );
113  resTable & operator = ( const resTable & );
114  static unsigned resTableBitMask ( const unsigned nBits );
115  friend class resTableIter < T, ID >;
116  friend class resTableIterConst < T, ID >;
117 };
118 
119 //
120 // class resTableIter
121 //
122 // an iterator for the resource table class
123 //
124 template < class T, class ID >
125 class resTableIter {
126 public:
127  resTableIter ();
128  bool valid () const;
129  bool operator == ( const resTableIter < T,ID > & rhs ) const;
130  bool operator != ( const resTableIter < T,ID > & rhs ) const;
131  resTableIter < T, ID > & operator = ( const resTableIter < T, ID > & );
132  T & operator * () const;
133  T * operator -> () const;
134  resTableIter < T, ID > & operator ++ ();
135  resTableIter < T, ID > operator ++ ( int );
136  T * pointer ();
137 private:
138  tsSLIter < T > iter;
139  unsigned index;
140  resTable < T,ID > * pResTable;
141  resTableIter ( resTable < T,ID > & tableIn );
142  void findNextEntry ();
143  friend class resTable < T, ID >;
144 };
145 
146 //
147 // class resTableIterConst
148 //
149 // an iterator for a const resource table class
150 //
151 template < class T, class ID >
152 class resTableIterConst {
153 public:
155  bool valid () const;
156  bool operator == ( const resTableIterConst < T,ID > & rhs ) const;
157  bool operator != ( const resTableIterConst < T,ID > & rhs ) const;
159  const T & operator * () const;
160  const T * operator -> () const;
161  resTableIterConst < T, ID > & operator ++ ();
162  resTableIterConst < T, ID > operator ++ ( int );
163  const T * pointer () const;
164 private:
165  tsSLIterConst < T > iter;
166  unsigned index;
167  const resTable < T,ID > * pResTable;
168  resTableIterConst ( const resTable < T,ID > & tableIn );
169  void findNextEntry ();
170  friend class resTable < T, ID >;
171 };
172 
173 //
174 // Some ID classes that work with the above template
175 //
176 
177 //
178 // class intId
179 //
180 // signed or unsigned integer identifier (class T must be
181 // a signed or unsigned integer type)
182 //
183 // this class works as type ID in resTable <class T, class ID>
184 //
185 // 1<<MIN_INDEX_WIDTH specifies the minimum number of
186 // elements in the hash table within resTable <class T, class ID>.
187 // Set this parameter to zero if unsure of the correct minimum
188 // hash table size.
189 //
190 // MAX_ID_WIDTH specifies the maximum number of ls bits in an
191 // integer identifier which might be set at any time.
192 //
193 // MIN_INDEX_WIDTH and MAX_ID_WIDTH are specified here at
194 // compile time so that the hash index can be produced
195 // efficiently. Hash indexes are produced more efficiently
196 // when (MAX_ID_WIDTH - MIN_INDEX_WIDTH) is minimized.
197 //
198 template <class T, unsigned MIN_INDEX_WIDTH=4u,
199  unsigned MAX_ID_WIDTH = sizeof(T)*CHAR_BIT>
200 class intId {
201 public:
202  intId (const T &idIn);
203  bool operator == (const intId &idIn) const;
204  resTableIndex hash () const;
205  const T getId() const;
206 protected:
207  T id;
208 };
209 
210 //
211 // class chronIntIdResTable <ITEM>
212 //
213 // a specialized resTable which uses unsigned integer keys which are
214 // allocated in chronological sequence
215 //
216 // NOTE: ITEM must public inherit from chronIntIdRes <ITEM>
217 //
219 {
220 public:
221  chronIntId ( const unsigned &idIn );
222 };
223 
224 template <class ITEM>
226 public:
228  virtual ~chronIntIdResTable ();
229  void idAssignAdd ( ITEM & item );
230 private:
231  unsigned allocId;
233  chronIntIdResTable & operator = ( const chronIntIdResTable & );
234 };
235 
236 //
237 // class chronIntIdRes<ITEM>
238 //
239 // resource with unsigned chronological identifier
240 //
241 template <class ITEM>
242 class chronIntIdRes : public chronIntId, public tsSLNode<ITEM> {
243 public:
244  chronIntIdRes ();
245 private:
246  void setId (unsigned newId);
247  chronIntIdRes (const chronIntIdRes & );
249 };
250 
251 //
252 // class stringId
253 //
254 // character string identifier
255 //
256 class LIBCOM_API stringId {
257 public:
258  enum allocationType {copyString, refString};
259  stringId (const char * idIn, allocationType typeIn=copyString);
260  virtual ~stringId();
261  resTableIndex hash () const;
262  bool operator == (const stringId &idIn) const;
263  const char * resourceName() const; // return the pointer to the string
264  void show (unsigned level) const;
265 private:
266  stringId & operator = ( const stringId & );
267  stringId ( const stringId &);
268  const char * pStr;
269  const allocationType allocType;
270 };
271 
273 // resTable<class T, class ID> member functions
275 
276 //
277 // resTable::resTable ()
278 //
279 template <class T, class ID>
281  pTable ( 0 ), nextSplitIndex ( 0 ), hashIxMask ( 0 ),
282  hashIxSplitMask ( 0 ), nBitsHashIxSplitMask ( 0 ),
283  logBaseTwoTableSize ( 0 ), nInUse ( 0 ) {}
284 
285 template <class T, class ID>
286 inline unsigned resTable<T,ID>::resTableBitMask ( const unsigned nBits )
287 {
288  return ( 1 << nBits ) - 1;
289 }
290 
291 //
292 // resTable::remove ()
293 //
294 // remove a res from the resTable
295 //
296 template <class T, class ID>
297 T * resTable<T,ID>::remove ( const ID & idIn )
298 {
299  if ( this->pTable ) {
300  // search list for idIn and remove the first match
301  tsSLList<T> & list = this->pTable [ this->hash(idIn) ];
302  tsSLIter <T> pItem = list.firstIter ();
303  T *pPrev = 0;
304  while ( pItem.valid () ) {
305  const ID & idOfItem = *pItem;
306  if ( idOfItem == idIn ) {
307  if ( pPrev ) {
308  list.remove ( *pPrev );
309  }
310  else {
311  list.get ();
312  }
313  this->nInUse--;
314  break;
315  }
316  pPrev = pItem.pointer ();
317  pItem++;
318  }
319  return pItem.pointer ();
320  }
321  else {
322  return 0;
323  }
324 }
325 
326 template <class T, class ID>
328 {
329  const unsigned N = this->tableSize ();
330  for ( unsigned i = 0u; i < N; i++ ) {
331  while ( T * pItem = this->pTable[i].get() ) {
332  destination.add ( *pItem );
333  }
334  }
335  this->nInUse = 0;
336 }
337 
338 //
339 // resTable::lookup ()
340 //
341 template <class T, class ID>
342 inline T * resTable<T,ID>::lookup ( const ID & idIn ) const
343 {
344  if ( this->pTable ) {
345  tsSLList<T> & list = this->pTable [ this->hash ( idIn ) ];
346  return this->find ( list, idIn );
347  }
348  else {
349  return 0;
350  }
351 }
352 
353 //
354 // resTable::hash ()
355 //
356 template <class T, class ID>
357 inline resTableIndex resTable<T,ID>::hash ( const ID & idIn ) const
358 {
359  resTableIndex h = idIn.hash ();
360  resTableIndex h0 = h & this->hashIxMask;
361  if ( h0 >= this->nextSplitIndex ) {
362  return h0;
363  }
364  return h & this->hashIxSplitMask;
365 }
366 
367 //
368 // resTable<T,ID>::show
369 //
370 template <class T, class ID>
371 void resTable<T,ID>::show ( unsigned level ) const
372 {
373  const unsigned N = this->tableSize ();
374 
375  printf ( "Hash table with %u buckets and %u items of type %s installed\n",
376  N, this->nInUse, typeid(T).name() );
377 
378  if ( level >= 1u && N ) {
379 
380  if ( level >= 2u ) {
381  tsSLList<T> * pList = this->pTable;
382  while ( pList < & this->pTable[N] ) {
383  tsSLIter<T> pItem = pList->firstIter ();
384  while ( pItem.valid () ) {
385  tsSLIter<T> pNext = pItem;
386  pNext++;
387  pItem.pointer()->show ( level - 2u );
388  pItem = pNext;
389  }
390  pList++;
391  }
392  }
393 
394  double X = 0.0;
395  double XX = 0.0;
396  unsigned maxEntries = 0u;
397  unsigned empty = 0;
398  for ( unsigned i = 0u; i < N; i++ ) {
399  tsSLIter<T> pItem = this->pTable[i].firstIter ();
400  unsigned count = 0;
401  while ( pItem.valid () ) {
402  if ( level >= 3u ) {
403  pItem->show ( level );
404  }
405  count++;
406  pItem++;
407  }
408  if ( count > 0u ) {
409  X += count;
410  XX += count * count;
411  if ( count > maxEntries ) {
412  maxEntries = count;
413  }
414  } else
415  empty++;
416  }
417 
418  double mean = X / N;
419  double stdDev = sqrt( XX / N - mean * mean );
420  printf (
421  "entries per bucket: mean = %f std dev = %f max = %u\n",
422  mean, stdDev, maxEntries );
423  printf("%u empty buckets\n", empty);
424  if ( X != this->nInUse ) {
425  printf ("this->nInUse didnt match items counted which was %f????\n", X );
426  }
427  }
428 }
429 
430 // self test
431 template <class T, class ID>
433 {
434  const unsigned N = this->tableSize ();
435 
436  if ( this->pTable ) {
437  assert ( this->nextSplitIndex <= this->hashIxMask + 1 );
438  assert ( this->hashIxMask );
439  assert ( this->hashIxMask == ( this->hashIxSplitMask >> 1 ) );
440  assert ( this->hashIxSplitMask );
441  assert ( this->nBitsHashIxSplitMask );
442  assert ( resTableBitMask ( this->nBitsHashIxSplitMask )
443  == this->hashIxSplitMask );
444  assert ( this->logBaseTwoTableSize );
445  assert ( this->nBitsHashIxSplitMask <= this->logBaseTwoTableSize );
446  }
447  else {
448  assert ( this->nextSplitIndex == 0 );
449  assert ( this->hashIxMask == 0 );
450  assert ( this->hashIxSplitMask == 0 );
451  assert ( this->nBitsHashIxSplitMask == 0 );
452  assert ( this->logBaseTwoTableSize == 0 );
453  }
454 
455  unsigned total = 0u;
456  for ( unsigned i = 0u; i < N; i++ ) {
457  tsSLIter<T> pItem = this->pTable[i].firstIter ();
458  unsigned count = 0;
459  while ( pItem.valid () ) {
460  resTableIndex index = this->hash ( *pItem );
461  assert ( index == i );
462  count++;
463  pItem++;
464  }
465  total += count;
466  }
467  assert ( total == this->nInUse );
468 }
469 
470 
471 //
472 // resTable<T,ID>::traverse
473 //
474 template <class T, class ID>
475 void resTable<T,ID>::traverse ( void (T::*pCB)() )
476 {
477  const unsigned N = this->tableSize ();
478  for ( unsigned i = 0u; i < N; i++ ) {
479  tsSLIter<T> pItem = this->pTable[i].firstIter ();
480  while ( pItem.valid () ) {
481  tsSLIter<T> pNext = pItem;
482  pNext++;
483  ( pItem.pointer ()->*pCB ) ();
484  pItem = pNext;
485  }
486  }
487 }
488 
489 //
490 // resTable<T,ID>::traverseConst
491 //
492 template <class T, class ID>
493 void resTable<T,ID>::traverseConst ( void (T::*pCB)() const ) const
494 {
495  const unsigned N = this->tableSize ();
496  for ( unsigned i = 0u; i < N; i++ ) {
497  const tsSLList < T > & table = this->pTable[i];
498  tsSLIterConst<T> pItem = table.firstIter ();
499  while ( pItem.valid () ) {
500  tsSLIterConst<T> pNext = pItem;
501  pNext++;
502  ( pItem.pointer ()->*pCB ) ();
503  pItem = pNext;
504  }
505  }
506 }
507 
508 template <class T, class ID>
509 inline unsigned resTable<T,ID>::numEntriesInstalled () const
510 {
511  return this->nInUse;
512 }
513 
514 template <class T, class ID>
515 inline unsigned resTable<T,ID>::tableSize () const
516 {
517  if ( this->pTable ) {
518  return ( this->hashIxMask + 1 ) + this->nextSplitIndex;
519  }
520  else {
521  return 0;
522  }
523 }
524 
525 // it will be more efficent to call this once prior to installing
526 // the first entry
527 template <class T, class ID>
528 void resTable<T,ID>::setTableSize ( const unsigned newTableSize )
529 {
530  if ( newTableSize == 0u ) {
531  return;
532  }
533 
534  //
535  // count the number of bits in newTableSize and round up
536  // to the next power of two
537  //
538  unsigned newMask = newTableSize - 1;
539  unsigned nbits;
540  for ( nbits = 0; nbits < sizeof (newTableSize) * CHAR_BIT; nbits++ ) {
541  unsigned nBitsMask = resTableBitMask ( nbits );
542  if ( ( newMask & ~nBitsMask ) == 0){
543  break;
544  }
545  }
546  setTableSizePrivate ( nbits );
547 }
548 
549 template <class T, class ID>
550 bool resTable<T,ID>::setTableSizePrivate ( unsigned logBaseTwoTableSizeIn )
551 {
552  // dont shrink
553  if ( this->logBaseTwoTableSize >= logBaseTwoTableSizeIn ) {
554  return true;
555  }
556 
557  // dont allow ridiculously small tables
558  if ( logBaseTwoTableSizeIn < 4 ) {
559  logBaseTwoTableSizeIn = 4;
560  }
561 
562  const unsigned newTableSize = 1 << logBaseTwoTableSizeIn;
563 # if ! defined (__GNUC__) || __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 92 )
564  const unsigned oldTableSize = this->pTable ? 1 << this->logBaseTwoTableSize : 0;
565 # endif
566  const unsigned oldTableOccupiedSize = this->tableSize ();
567 
568  tsSLList<T> * pNewTable;
569  try {
570  pNewTable = ( tsSLList<T> * )
571  ::operator new ( newTableSize * sizeof ( tsSLList<T> ) );
572  }
573  catch ( ... ){
574  if ( ! this->pTable ) {
575  throw;
576  }
577  return false;
578  }
579 
580  // run the constructors using placement new
581  unsigned i;
582  for ( i = 0u; i < oldTableOccupiedSize; i++ ) {
583  new ( &pNewTable[i] ) tsSLList<T> ( this->pTable[i] );
584  }
585  for ( i = oldTableOccupiedSize; i < newTableSize; i++ ) {
586  new ( &pNewTable[i] ) tsSLList<T>;
587  }
588  // Run the destructors explicitly. Currently this destructor is a noop.
589  // The Tornado II compiler and RedHat 6.2 will not compile ~tsSLList<T>() but
590  // since its a NOOP we can find an ugly workaround
591 # if ! defined (__GNUC__) || __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 92 )
592  for ( i = 0; i < oldTableSize; i++ ) {
593  this->pTable[i].~tsSLList<T>();
594  }
595 # endif
596 
597  if ( ! this->pTable ) {
598  this->hashIxSplitMask = resTableBitMask ( logBaseTwoTableSizeIn );
599  this->nBitsHashIxSplitMask = logBaseTwoTableSizeIn;
600  this->hashIxMask = this->hashIxSplitMask >> 1;
601  this->nextSplitIndex = 0;
602  }
603 
604  operator delete ( this->pTable );
605  this->pTable = pNewTable;
606  this->logBaseTwoTableSize = logBaseTwoTableSizeIn;
607 
608  return true;
609 }
610 
611 template <class T, class ID>
613 {
614  // double the hash table when necessary
615  // (this results in only a memcpy overhead, but
616  // no hashing or entry redistribution)
617  if ( this->nextSplitIndex > this->hashIxMask ) {
618  bool success = this->setTableSizePrivate ( this->nBitsHashIxSplitMask + 1 );
619  if ( ! success ) {
620  return;
621  }
622  this->nBitsHashIxSplitMask += 1;
623  this->hashIxSplitMask = resTableBitMask ( this->nBitsHashIxSplitMask );
624  this->hashIxMask = this->hashIxSplitMask >> 1;
625  this->nextSplitIndex = 0;
626  }
627 
628  // rehash only the items in the split bucket
629  tsSLList<T> tmp ( this->pTable[ this->nextSplitIndex ] );
630  this->nextSplitIndex++;
631  T *pItem = tmp.get();
632  while ( pItem ) {
633  resTableIndex index = this->hash ( *pItem );
634  this->pTable[index].add ( *pItem );
635  pItem = tmp.get();
636  }
637 }
638 
639 //
640 // add a res to the resTable
641 //
642 template <class T, class ID>
643 int resTable<T,ID>::add ( T &res )
644 {
645  if ( ! this->pTable ) {
646  this->setTableSizePrivate ( 10 );
647  }
648  else if ( this->nInUse >= this->tableSize() ) {
649  this->splitBucket ();
650  tsSLList<T> &list = this->pTable[this->hash(res)];
651  if ( this->find ( list, res ) != 0 ) {
652  return -1;
653  }
654  }
655  tsSLList<T> &list = this->pTable[this->hash(res)];
656  if ( this->find ( list, res ) != 0 ) {
657  return -1;
658  }
659  list.add ( res );
660  this->nInUse++;
661  return 0;
662 }
663 
664 //
665 // find
666 // searches from where the iterator points to the
667 // end of the list for idIn
668 //
669 // iterator points to the item found upon return
670 // (or NULL if nothing matching was found)
671 //
672 template <class T, class ID>
673 T * resTable<T,ID>::find ( tsSLList<T> &list, const ID &idIn ) const
674 {
675  tsSLIter <T> pItem = list.firstIter ();
676  while ( pItem.valid () ) {
677  const ID & idOfItem = *pItem;
678  if ( idOfItem == idIn ) {
679  break;
680  }
681  pItem++;
682  }
683  return pItem.pointer ();
684 }
685 
686 //
687 // ~resTable<T,ID>::resTable()
688 //
689 template <class T, class ID>
691 {
692  operator delete ( this->pTable );
693 }
694 
695 //
696 // resTable<T,ID>::resTable ( const resTable & )
697 // private - not to be used - implemented to eliminate warnings
698 //
699 template <class T, class ID>
700 inline resTable<T,ID>::resTable ( const resTable & )
701 {
702 }
703 
704 //
705 // resTable<T,ID>::resTable & operator = ( const resTable & )
706 // private - not to be used - implemented to eliminate warnings
707 //
708 template <class T, class ID>
710 {
711  return *this;
712 }
713 
714 template <class T, class ID>
716 {
717  return resTableIterConst < T, ID > ( *this );
718 }
719 
720 template <class T, class ID>
722 {
723  return resTableIter < T, ID > ( *this );
724 }
725 
727 // resTableIter<T,ID> member functions
729 
730 template < class T, class ID >
732  index ( 0 ), pResTable ( & tableIn )
733 {
734  this->findNextEntry ();
735 }
736 
737 template < class T, class ID >
739  iter ( tsSLList<T>::invalidIter() ),
740  index ( 0 ), pResTable ( 0 )
741 {
742 }
743 
744 template < class T, class ID >
746 {
747  if ( this->pResTable ) {
748  while ( this->index < this->pResTable->tableSize() ) {
749  this->iter = this->pResTable->pTable[this->index++].firstIter ();
750  if ( this->iter.valid () ) {
751  break;
752  }
753  }
754  }
755 }
756 
757 template < class T, class ID >
758 inline bool resTableIter<T,ID>::valid () const
759 {
760  return this->iter.valid ();
761 }
762 
763 template < class T, class ID >
764 inline bool resTableIter<T,ID>::operator ==
765  ( const resTableIter < T,ID > & rhs ) const
766 {
767  return ( this->pResTable == rhs.pResTable
768  && this->index == rhs.index
769  && this->iter == rhs.iter );
770 }
771 
772 template < class T, class ID >
773 inline bool resTableIter<T,ID>::operator !=
774  ( const resTableIter < T,ID > & rhs ) const
775 {
776  return ! this->operator == ( rhs );
777 }
778 
779 template < class T, class ID >
780 inline resTableIter < T, ID > & resTableIter<T,ID>::operator =
781  ( const resTableIter < T, ID > & rhs )
782 {
783  this->pResTable = rhs.pResTable;
784  this->index = rhs.index;
785  this->iter = rhs.iter;
786  return *this;
787 }
788 
789 template < class T, class ID >
791 {
792  return this->iter.operator * ();
793 }
794 
795 template < class T, class ID >
797 {
798  return this->iter.operator -> ();
799 }
800 
801 template < class T, class ID >
803 {
804  this->iter++;
805  if ( ! this->iter.valid() ) {
806  this->findNextEntry ();
807  }
808  return *this;
809 }
810 
811 template < class T, class ID >
813 {
814  resTableIter<T,ID> tmp = *this;
815  this->operator ++ ();
816  return tmp;
817 }
818 
819 template < class T, class ID >
821 {
822  return this->iter.pointer ();
823 }
824 
826 // resTableIterConst<T,ID> member functions
828 
829 template < class T, class ID >
831  index ( 0 ), pResTable ( & tableIn )
832 {
833  this->findNextEntry ();
834 }
835 
836 template < class T, class ID >
838  iter ( tsSLList<T>::invalidIter() ),
839  index ( 0 ), pResTable ( 0 )
840 {
841 }
842 
843 template < class T, class ID >
845 {
846  if ( this->pResTable ) {
847  while ( this->index < this->pResTable->tableSize() ) {
848  const tsSLList<T> * pList = & this->pResTable->pTable[this->index++];
849  this->iter = pList->firstIter ();
850  if ( this->iter.valid () ) {
851  break;
852  }
853  }
854  }
855 }
856 
857 template < class T, class ID >
858 inline bool resTableIterConst<T,ID>::valid () const
859 {
860  return this->iter.valid ();
861 }
862 
863 template < class T, class ID >
865  ( const resTableIterConst < T,ID > & rhs ) const
866 {
867  return ( this->pResTable == rhs.pResTable
868  && this->index == rhs.index
869  && this->iter == rhs.iter );
870 }
871 
872 template < class T, class ID >
873 inline bool resTableIterConst<T,ID>::operator !=
874  ( const resTableIterConst < T,ID > & rhs ) const
875 {
876  return ! this->operator == ( rhs );
877 }
878 
879 template < class T, class ID >
880 inline resTableIterConst < T, ID > & resTableIterConst<T,ID>::operator =
882 {
883  this->pResTable = rhs.pResTable;
884  this->index = rhs.index;
885  this->iter = rhs.iter;
886  return *this;
887 }
888 
889 template < class T, class ID >
890 inline const T & resTableIterConst<T,ID>::operator * () const
891 {
892  return this->iter.operator * ();
893 }
894 
895 template < class T, class ID >
897 {
898  return this->iter.operator -> ();
899 }
900 
901 template < class T, class ID >
903 {
904  this->iter++;
905  if ( ! this->iter.valid() ) {
906  this->findNextEntry ();
907  }
908  return *this;
909 }
910 
911 template < class T, class ID >
913 {
914  resTableIterConst<T,ID> tmp = *this;
915  this->operator ++ ();
916  return tmp;
917 }
918 
919 template < class T, class ID >
920 inline const T * resTableIterConst<T,ID>::pointer () const
921 {
922  return this->iter.pointer ();
923 }
924 
926 // chronIntIdResTable<ITEM> member functions
928 inline chronIntId::chronIntId ( const unsigned &idIn ) :
929  intId<unsigned, 8u, sizeof(unsigned)*CHAR_BIT> ( idIn ) {}
930 
931 //
932 // chronIntIdResTable<ITEM>::chronIntIdResTable()
933 //
934 template <class ITEM>
936  resTable<ITEM, chronIntId> (), allocId(1u) {}
937 
938 template <class ITEM>
940  resTable<ITEM, chronIntId> (), allocId(1u) {}
941 
942 template <class ITEM>
945 {
946  return *this;
947 }
948 
949 //
950 // chronIntIdResTable<ITEM>::~chronIntIdResTable()
951 // (not inline because it is virtual)
952 //
953 template <class ITEM>
955 
956 //
957 // chronIntIdResTable<ITEM>::add()
958 //
959 // NOTE: This detects (and avoids) the case where
960 // the PV id wraps around and we attempt to have two
961 // resources with the same id.
962 //
963 template <class ITEM>
965 {
966  int status;
967  do {
968  item.chronIntIdRes<ITEM>::setId (allocId++);
969  status = this->resTable<ITEM,chronIntId>::add (item);
970  }
971  while (status);
972 }
973 
975 // chronIntIdRes<ITEM> member functions
977 
978 //
979 // chronIntIdRes<ITEM>::chronIntIdRes
980 //
981 template <class ITEM>
983 
984 //
985 // id<ITEM>::setId ()
986 //
987 // workaround for bug in DEC compiler
988 //
989 template <class ITEM>
990 inline void chronIntIdRes<ITEM>::setId (unsigned newId)
991 {
992  this->id = newId;
993 }
994 
996 // intId member functions
998 
999 //
1000 // intId::intId
1001 //
1002 // (if this is inline SUN PRO botches the template instantiation)
1003 template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
1005  : id (idIn) {}
1006 
1007 //
1008 // intId::operator == ()
1009 //
1010 template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
1013 {
1014  return this->id == idIn.id;
1015 }
1016 
1017 //
1018 // intId::getId ()
1019 //
1020 template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
1022 {
1023  return this->id;
1024 }
1025 
1026 //
1027 // integerHash()
1028 //
1029 // converts any integer into a hash table index
1030 //
1031 template < class T >
1032 inline resTableIndex integerHash ( unsigned MIN_INDEX_WIDTH,
1033  unsigned MAX_ID_WIDTH, const T &id )
1034 {
1035  resTableIndex hashid = static_cast <resTableIndex> ( id );
1036 
1037  //
1038  // the intent here is to gurantee that all components of the
1039  // integer contribute even if the resTableIndex returned might
1040  // index a small table.
1041  //
1042  // On most compilers the optimizer will unroll this loop so this
1043  // is actually a very small inline function
1044  //
1045  // Experiments using the microsoft compiler show that this isnt
1046  // slower than switching on the architecture size and unrolling the
1047  // loop explicitly (that solution has resulted in portability
1048  // problems in the past).
1049  //
1050  unsigned width = MAX_ID_WIDTH;
1051  do {
1052  width >>= 1u;
1053  hashid ^= hashid>>width;
1054  } while (width>MIN_INDEX_WIDTH);
1055 
1056  //
1057  // the result here is always masked to the
1058  // proper size after it is returned to the "resTable" class
1059  //
1060  return hashid;
1061 }
1062 
1063 
1064 //
1065 // intId::hash()
1066 //
1067 template <class T, unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH>
1069 {
1070  return integerHash ( MIN_INDEX_WIDTH, MAX_ID_WIDTH, this->id );
1071 }
1072 
1074 // stringId member functions
1076 
1077 //
1078 // stringId::operator == ()
1079 //
1080 inline bool stringId::operator ==
1081  (const stringId &idIn) const
1082 {
1083  if (this->pStr!=NULL && idIn.pStr!=NULL) {
1084  return strcmp(this->pStr,idIn.pStr)==0;
1085  }
1086  return false; // not equal
1087 }
1088 
1089 //
1090 // stringId::resourceName ()
1091 //
1092 inline const char * stringId::resourceName () const
1093 {
1094  return this->pStr;
1095 }
1096 
1097 #ifdef instantiateRecourceLib
1098 
1099 //
1100 // stringId::stringId()
1101 //
1102 stringId::stringId (const char * idIn, allocationType typeIn) :
1103  allocType (typeIn)
1104 {
1105  if (typeIn==copyString) {
1106  unsigned nChars = strlen (idIn) + 1u;
1107  this->pStr = new char [nChars];
1108  memcpy ( (void *) this->pStr, idIn, nChars );
1109  }
1110  else {
1111  this->pStr = idIn;
1112  }
1113 }
1114 
1115 //
1116 // stringId::show ()
1117 //
1118 void stringId::show (unsigned level) const
1119 {
1120  if (level>2u) {
1121  printf ("resource id = %s\n", this->pStr);
1122  }
1123 }
1124 
1125 //
1126 // stringId::~stringId()
1127 //
1128 //
1129 // this needs to be instantiated only once (normally in libCom)
1130 //
1132 {
1133  if (this->allocType==copyString) {
1134  if (this->pStr!=NULL) {
1135  //
1136  // the microsoft and solaris compilers will
1137  // not allow a pointer to "const char"
1138  // to be deleted
1139  //
1140  // the HP-UX compiler gives us a warning on
1141  // each cast away of const, but in this case
1142  // it cant be avoided.
1143  //
1144  // The DEC compiler complains that const isnt
1145  // really significant in a cast if it is present.
1146  //
1147  // I hope that deleting a pointer to "char"
1148  // is the same as deleting a pointer to
1149  // "const char" on all compilers
1150  //
1151  delete [] const_cast<char *>(this->pStr);
1152  }
1153  }
1154 }
1155 
1156 //
1157 // stringId::hash()
1158 //
1160 {
1161  if (!this->pStr) {
1162  return 0u;
1163  }
1164  return epicsStrHash(this->pStr, 0);
1165 }
1166 
1167 #endif // if instantiateRecourceLib is defined
1168 
1169 #endif // INCresourceLibh
1170 
T * pointer() const
Definition: tsSLList.h:438
unsigned int epicsStrHash(const char *str, unsigned int seed)
Definition: epicsString.c:356
epics::pvData::BitSetPtr empty
Definition: pvAccess.cpp:135
#define assert(exp)
Declare that a condition should be true.
Definition: epicsAssert.h:70
tsSLIterConst< T > firstIter() const
Definition: tsSLList.h:262
pvd::Status status
T * operator->() const
Definition: resourceLib.h:796
resTableIter< T, ID > iterator
Definition: resourceLib.h:95
int i
Definition: scan.c:967
const T * pointer() const
Definition: resourceLib.h:920
unsigned numEntriesInstalled() const
Definition: resourceLib.h:509
Internal: bucket item structure.
Definition: bucketLib.h:40
int add(T &res)
Definition: resourceLib.h:643
chronIntId(const unsigned &idIn)
Definition: resourceLib.h:928
#define printf
Definition: epicsStdio.h:41
bool operator==(const resTableIterConst< T, ID > &rhs) const
Definition: resourceLib.h:865
void show(unsigned level) const
const T * operator->() const
Definition: resourceLib.h:896
#define NULL
Definition: catime.c:38
T & operator*() const
Definition: resourceLib.h:790
const T getId() const
Definition: resourceLib.h:1021
intId(const T &idIn)
Definition: resourceLib.h:1004
T * lookup(const ID &idIn) const
Definition: resourceLib.h:342
void traverse(void(T::*pCB)())
Definition: resourceLib.h:475
virtual ~stringId()
void setTableSize(const unsigned newTableSize)
Definition: resourceLib.h:528
iterator firstIter()
Definition: resourceLib.h:721
resTableIndex hash() const
stringId(const char *idIn, allocationType typeIn=copyString)
void add(T &item)
Definition: tsSLList.h:211
void idAssignAdd(ITEM &item)
Definition: resourceLib.h:964
void removeAll(tsSLList< T > &destination)
Definition: resourceLib.h:327
void traverseConst(void(T::*pCB)() const ) const
Definition: resourceLib.h:493
virtual ~chronIntIdResTable()
Definition: resourceLib.h:954
bool operator==(const resTableIter< T, ID > &rhs) const
Definition: resourceLib.h:765
resTableIter< T, ID > & operator++()
Definition: resourceLib.h:802
const T * pointer() const
Definition: tsSLList.h:360
T * get()
Definition: tsSLList.h:220
const char * resourceName() const
Definition: resourceLib.h:1092
resTableIterConst< T, ID > iteratorConst
Definition: resourceLib.h:96
T * remove(const ID &idIn)
Definition: resourceLib.h:297
const T & operator*() const
Definition: resourceLib.h:890
void show(unsigned level) const
Definition: resourceLib.h:371
bool valid() const
Definition: tsSLList.h:306
size_t resTableIndex
Definition: resourceLib.h:45
resTableIndex integerHash(unsigned MIN_INDEX_WIDTH, unsigned MAX_ID_WIDTH, const T &id)
Definition: resourceLib.h:1032
bool valid() const
Definition: resourceLib.h:858
void remove(T &itemBefore)
Definition: tsSLList.h:254
virtual ~resTable()
Definition: resourceLib.h:690
resTableIndex hash() const
Definition: resourceLib.h:1068
void verify() const
Definition: resourceLib.h:432
resTableIterConst< T, ID > & operator++()
Definition: resourceLib.h:902
bool operator!=(const epics::pvData::shared_vector< A > &a, const epics::pvData::shared_vector< B > &b)
Definition: sharedVector.h:978
bool valid() const
Definition: tsSLList.h:384
bool valid() const
Definition: resourceLib.h:758
bool operator==(const epics::pvData::shared_vector< A > &a, const epics::pvData::shared_vector< B > &b)
Definition: sharedVector.h:967