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