Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

766 lines
19 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ClassHash.h
  6. * Content: Hash table that takes a class as a key. The key class MUST support
  7. * two member functions:
  8. * 'HashFunction' will perform a hash down to a specified number of bits.
  9. * 'CompareFunction' will perform a comparison of two items of that class.
  10. *
  11. * Note: This class requires an FPM to operate.
  12. *
  13. * THIS CLASS IS NOT THREAD SAFE!!
  14. *
  15. * History:
  16. * Date By Reason
  17. * ==== == ======
  18. * 11/15/98 jwo Created it (map).
  19. * 04/19/99 jtk Rewrote without using STL (map)
  20. * 08/03/99 jtk Derived from ClassMap.h
  21. ***************************************************************************/
  22. #ifndef __CLASS_HASH_H__
  23. #define __CLASS_HASH_H__
  24. #undef DPF_SUBCOMP
  25. #define DPF_SUBCOMP DN_SUBCOMP_COMMON
  26. //**********************************************************************
  27. // Constant definitions
  28. //**********************************************************************
  29. //**********************************************************************
  30. // Macro definitions
  31. //**********************************************************************
  32. #ifndef OFFSETOF
  33. // Macro to compute the offset of an element inside of a larger structure (copied from MSDEV's STDLIB.H)
  34. #define OFFSETOF(s,m) ( (INT_PTR) &(((s *)0)->m) )
  35. #define __LOCAL_OFFSETOF_DEFINED__
  36. #endif // OFFSETOF
  37. //**********************************************************************
  38. // Structure definitions
  39. //**********************************************************************
  40. //**********************************************************************
  41. // Variable prototypes
  42. //**********************************************************************
  43. //**********************************************************************
  44. // Function prototypes
  45. //**********************************************************************
  46. //**********************************************************************
  47. // Class definitions
  48. //**********************************************************************
  49. //
  50. // Template class for entry in map.
  51. //
  52. template<class T, class S>
  53. class CClassHashEntry
  54. {
  55. public:
  56. CClassHashEntry(){};
  57. ~CClassHashEntry(){};
  58. //
  59. // internals, put the linkage at the end to make sure the FPM doesn't
  60. // wail on it!
  61. //
  62. PVOID m_FPMPlaceHolder;
  63. S m_Key;
  64. T m_Item;
  65. CBilink m_Linkage;
  66. //
  67. // linkage functions
  68. //
  69. static CClassHashEntry *EntryFromBilink( CBilink *const pLinkage )
  70. {
  71. DBG_CASSERT( sizeof( void* ) == sizeof( INT_PTR ) );
  72. return reinterpret_cast<CClassHashEntry*>( &reinterpret_cast<BYTE*>( pLinkage )[ -OFFSETOF( CClassHashEntry, m_Linkage ) ] );
  73. }
  74. void AddToList( CBilink *const pLinkage )
  75. {
  76. m_Linkage.InsertAfter( pLinkage );
  77. }
  78. void RemoveFromList( void )
  79. {
  80. m_Linkage.RemoveFromList();
  81. }
  82. //
  83. // pool management functions
  84. //
  85. #undef DPF_MODNAME
  86. #define DPF_MODNAME "CClassHashEntry::InitAlloc"
  87. static BOOL InitAlloc( void *pItem )
  88. {
  89. CClassHashEntry<T,S> *pThisObject;
  90. DNASSERT( pItem != NULL );
  91. pThisObject = static_cast<CClassHashEntry<T,S>*>( pItem );
  92. pThisObject->m_Linkage.Initialize();
  93. return TRUE;
  94. }
  95. #undef DPF_MODNAME
  96. #define DPF_MODNAME "CClassHashEntry::Init"
  97. static void Init( void *pItem )
  98. {
  99. CClassHashEntry<T,S> *pThisObject;
  100. DNASSERT( pItem != NULL );
  101. pThisObject = static_cast<CClassHashEntry<T,S>*>( pItem );
  102. DNASSERT( pThisObject->m_Linkage.IsEmpty() != FALSE );
  103. }
  104. #undef DPF_MODNAME
  105. #define DPF_MODNAME "CClassHashEntry::Release"
  106. static void Release( void *pItem )
  107. {
  108. CClassHashEntry<T,S> *pThisObject;
  109. DNASSERT( pItem != NULL );
  110. pThisObject = static_cast<CClassHashEntry<T,S>*>( pItem );
  111. DNASSERT( pThisObject->m_Linkage.IsEmpty() != FALSE );
  112. }
  113. #undef DPF_MODNAME
  114. #define DPF_MODNAME "CClassHashEntry::Dealloc"
  115. static void Dealloc( void *pItem )
  116. {
  117. CClassHashEntry<T,S> *pThisObject;
  118. DNASSERT( pItem != NULL );
  119. pThisObject = static_cast<CClassHashEntry<T,S>*>( pItem );
  120. DNASSERT( pThisObject->m_Linkage.IsEmpty() != FALSE );
  121. }
  122. protected:
  123. private:
  124. //
  125. // make copy constructor and assignment operator private and unimplemented
  126. // to prevent illegal copies from being made
  127. //
  128. CClassHashEntry( const CClassHashEntry & );
  129. CClassHashEntry& operator=( const CClassHashEntry & );
  130. };
  131. //
  132. // template class for the map
  133. //
  134. template<class T, class S>
  135. class CClassHash
  136. {
  137. public:
  138. CClassHash();
  139. ~CClassHash();
  140. BOOL Initialize( const INT_PTR iBitDepth, const INT_PTR iGrowBits );
  141. void Deinitialize( void );
  142. BOOL Insert( const S& Key, T Item );
  143. void Remove( const S& Key );
  144. BOOL RemoveLastEntry( T *const pItem );
  145. BOOL Find( const S& Key, T *const pItem );
  146. BOOL IsEmpty( void ) { return ( m_iEntriesInUse == 0 ); }
  147. INT_PTR m_iHashBitDepth; // number of bits used for hash entry
  148. INT_PTR m_iGrowBits; // number of bits to grow has by
  149. CBilink *m_pHashEntries; // list of hash entries
  150. INT_PTR m_iAllocatedEntries; // count of allocated entries in index/item list
  151. INT_PTR m_iEntriesInUse; // count of entries in use
  152. FPOOL m_EntryPool; // pool of entries
  153. private:
  154. DEBUG_ONLY( BOOL m_fInitialized );
  155. BOOL LocalFind( const S& Key, CBilink **const ppLink );
  156. void Grow( void );
  157. void InitializeHashEntries( const UINT_PTR uEntryCount ) const;
  158. //
  159. // make copy constructor and assignment operator private and unimplemented
  160. // to prevent illegal copies from being made
  161. //
  162. CClassHash( const CClassHash & );
  163. CClassHash& operator=( const CClassHash & );
  164. };
  165. //**********************************************************************
  166. // Class function definitions
  167. //**********************************************************************
  168. //**********************************************************************
  169. // ------------------------------
  170. // CClassHash::CClassHash - constructor
  171. //
  172. // Entry: Nothing
  173. //
  174. // Exit: Nothing
  175. // ------------------------------
  176. #undef DPF_MODNAME
  177. #define DPF_MODNAME "CClassHash::CClassHash"
  178. template<class T, class S>
  179. CClassHash< T, S >::CClassHash():
  180. m_iHashBitDepth( 0 ),
  181. m_iGrowBits( 0 ),
  182. m_pHashEntries( NULL ),
  183. m_iAllocatedEntries( 0 ),
  184. m_iEntriesInUse( 0 )
  185. {
  186. //
  187. // clear internals
  188. //
  189. DEBUG_ONLY( m_fInitialized = FALSE );
  190. memset( &m_EntryPool, 0x00, sizeof( m_EntryPool ) );
  191. }
  192. //**********************************************************************
  193. //**********************************************************************
  194. // ------------------------------
  195. // CClassHash::~CClassHash - destructor
  196. //
  197. // Entry: Nothing
  198. //
  199. // Exit: Nothing
  200. // ------------------------------
  201. #undef DPF_MODNAME
  202. #define DPF_MODNAME "CClassHash::~CClassHash"
  203. template<class T, class S>
  204. CClassHash< T, S >::~CClassHash()
  205. {
  206. DNASSERT( m_iHashBitDepth == 0 );
  207. DNASSERT( m_iGrowBits == 0 );
  208. DNASSERT( m_pHashEntries == NULL );
  209. DNASSERT( m_iAllocatedEntries == 0 );
  210. DNASSERT( m_iEntriesInUse == 0 );
  211. DEBUG_ONLY( DNASSERT( m_fInitialized == FALSE ) );
  212. }
  213. //**********************************************************************
  214. //**********************************************************************
  215. // ------------------------------
  216. // CClassHash::Initialize - initialize hash table
  217. //
  218. // Entry: Pointer to key
  219. // Pointer to 'key' associated with this item
  220. // Pointer to item to add
  221. //
  222. // Exit: Boolean indicating success
  223. // TRUE = success
  224. // FALSE = failure
  225. // ------------------------------
  226. #undef DPF_MODNAME
  227. #define DPF_MODNAME "CClassHash::Initialize"
  228. template<class T, class S>
  229. BOOL CClassHash< T, S >::Initialize( const INT_PTR iBitDepth, const INT_PTR iGrowBits )
  230. {
  231. BOOL fReturn;
  232. DNASSERT( iBitDepth != 0 );
  233. //
  234. // initialize
  235. //
  236. fReturn = TRUE;
  237. DNASSERT( m_pHashEntries == NULL );
  238. m_pHashEntries = static_cast<CBilink*>( DNMalloc( sizeof( *m_pHashEntries ) * ( 1 << iBitDepth ) ) );
  239. if ( m_pHashEntries == NULL )
  240. {
  241. fReturn = FALSE;
  242. DPFX(DPFPREP, 0, "Unable to allocate memory for hash table!" );
  243. goto Exit;
  244. }
  245. m_iAllocatedEntries = 1 << iBitDepth;
  246. InitializeHashEntries( m_iAllocatedEntries );
  247. if ( FPM_Initialize( &m_EntryPool, // pointer to pool
  248. sizeof( CClassHashEntry<T,S> ), // size of pool entry
  249. CClassHashEntry<T,S>::InitAlloc, // function for allocating item
  250. CClassHashEntry<T,S>::Init, // function for getting item from pool
  251. CClassHashEntry<T,S>::Release, // function for releasing item
  252. CClassHashEntry<T,S>::Dealloc // function for deallocating item
  253. ) == FALSE )
  254. {
  255. DPFX(DPFPREP, 0, "Failed to initialize FPM!" );
  256. fReturn = FALSE;
  257. }
  258. m_iHashBitDepth = iBitDepth;
  259. m_iGrowBits = iGrowBits;
  260. DEBUG_ONLY( m_fInitialized = TRUE );
  261. Exit:
  262. return fReturn;
  263. }
  264. //**********************************************************************
  265. //**********************************************************************
  266. // ------------------------------
  267. // CClassHash::Deinitialize - deinitialize hash table
  268. //
  269. // Entry: Nothing
  270. //
  271. // Exit: Nothing
  272. // ------------------------------
  273. #undef DPF_MODNAME
  274. #define DPF_MODNAME "CClassHash::Deinitialize"
  275. template<class T, class S>
  276. void CClassHash< T, S >::Deinitialize( void )
  277. {
  278. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  279. DNASSERT( m_iEntriesInUse == 0 );
  280. DNASSERT( m_pHashEntries != NULL );
  281. DNFree( m_pHashEntries );
  282. m_pHashEntries = NULL;
  283. FPM_Deinitialize( &m_EntryPool );
  284. m_iHashBitDepth = 0;
  285. m_iGrowBits = 0;
  286. m_iAllocatedEntries = 0;
  287. DEBUG_ONLY( m_fInitialized = FALSE );
  288. }
  289. //**********************************************************************
  290. //**********************************************************************
  291. // ------------------------------
  292. // CClassHash::Insert - add item to map
  293. //
  294. // Entry: Pointer to 'key' associated with this item
  295. // Pointer to item to add
  296. //
  297. // Exit: Boolean indicating success:
  298. // TRUE = success
  299. // FALSE = failure
  300. // ------------------------------
  301. #undef DPF_MODNAME
  302. #define DPF_MODNAME "CClassHash::Insert"
  303. template<class T, class S>
  304. BOOL CClassHash< T, S >::Insert( const S& Key, T Item )
  305. {
  306. BOOL fReturn;
  307. BOOL fFound;
  308. CBilink *pLink;
  309. CClassHashEntry< T, S > *pNewEntry;
  310. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  311. //
  312. // initialize
  313. //
  314. fReturn = TRUE;
  315. pNewEntry = NULL;
  316. //
  317. // grow the map if applicable
  318. //
  319. if ( ( m_iEntriesInUse >= ( m_iAllocatedEntries / 2 ) ) &&
  320. ( m_iGrowBits != 0 ) )
  321. {
  322. Grow();
  323. }
  324. //
  325. // get a new table entry before trying the lookup
  326. //
  327. pNewEntry = static_cast<CClassHashEntry<T,S>*>( m_EntryPool.Get( &m_EntryPool ) );
  328. if ( pNewEntry == NULL )
  329. {
  330. fReturn = FALSE;
  331. DPFX(DPFPREP, 0, "Problem allocating new hash table entry on Insert!" );
  332. goto Exit;
  333. }
  334. //
  335. // scan for this item in the list, since we're only supposed to have
  336. // unique items in the list, ASSERT if a duplicate is found
  337. //
  338. fFound = LocalFind( Key, &pLink );
  339. DNASSERT( pLink != NULL );
  340. DNASSERT( fFound == FALSE );
  341. //
  342. // officially add entry to the hash table
  343. //
  344. m_iEntriesInUse++;
  345. pNewEntry->m_Key = Key;
  346. pNewEntry->m_Item = Item;
  347. DNASSERT( pLink != NULL );
  348. pNewEntry->AddToList( pLink );
  349. DNASSERT( fReturn == TRUE );
  350. Exit:
  351. return fReturn;
  352. }
  353. //**********************************************************************
  354. //**********************************************************************
  355. // ------------------------------
  356. // CClassHash::Remove - remove item from map
  357. //
  358. // Entry: Reference to 'key' used to look up this item
  359. //
  360. // Exit: Nothing
  361. // ------------------------------
  362. #undef DPF_MODNAME
  363. #define DPF_MODNAME "CClassHash::Remove"
  364. template<class T, class S>
  365. void CClassHash< T, S >::Remove( const S& Key )
  366. {
  367. CBilink *pLink;
  368. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  369. if ( LocalFind( Key, &pLink ) != FALSE )
  370. {
  371. CClassHashEntry< T, S > *pEntry;
  372. DNASSERT( pLink != NULL );
  373. pEntry = CClassHashEntry< T, S >::EntryFromBilink( pLink );
  374. pEntry->RemoveFromList();
  375. m_EntryPool.Release( &m_EntryPool, pEntry );
  376. DNASSERT( m_iEntriesInUse != 0 );
  377. m_iEntriesInUse--;
  378. }
  379. }
  380. //**********************************************************************
  381. //**********************************************************************
  382. // ------------------------------
  383. // CClassHash::RemoveLastEntry - remove last item from map
  384. //
  385. // Entry: Pointer to pointer to item data
  386. //
  387. // Exit: Boolean indicating success
  388. // TRUE = item was removed
  389. // FALSE = item was not removed (map empty)
  390. // ------------------------------
  391. #undef DPF_MODNAME
  392. #define DPF_MODNAME "CClassHash::RemoveLastEntry"
  393. template<class T, class S>
  394. BOOL CClassHash< T, S >::RemoveLastEntry( T *const pItem )
  395. {
  396. BOOL fReturn;
  397. DNASSERT( pItem != NULL );
  398. //
  399. // initialize
  400. //
  401. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  402. fReturn = FALSE;
  403. if ( m_iEntriesInUse != 0 )
  404. {
  405. INT_PTR iIndex;
  406. DNASSERT( m_pHashEntries != NULL );
  407. iIndex = m_iAllocatedEntries;
  408. while ( iIndex > 0 )
  409. {
  410. iIndex--;
  411. if ( m_pHashEntries[ iIndex ].IsEmpty() == FALSE )
  412. {
  413. CClassHashEntry<T,S> *pEntry;
  414. pEntry = pEntry->EntryFromBilink( m_pHashEntries[ iIndex ].GetNext() );
  415. pEntry->RemoveFromList();
  416. *pItem = pEntry->m_Item;
  417. m_EntryPool.Release( &m_EntryPool, pEntry );
  418. m_iEntriesInUse--;
  419. fReturn = TRUE;
  420. goto Exit;
  421. }
  422. }
  423. }
  424. Exit:
  425. return fReturn;
  426. }
  427. //**********************************************************************
  428. //**********************************************************************
  429. // ------------------------------
  430. // CClassHash::Find - find item in map
  431. //
  432. // Entry: Reference of 'key' used to look up this item
  433. // Pointer to pointer to be filled in with data
  434. //
  435. // Exit: Boolean indicating success
  436. // TRUE = item found
  437. // FALSE = item not found
  438. // ------------------------------
  439. #undef DPF_MODNAME
  440. #define DPF_MODNAME "CClassHash::Find"
  441. template<class T, class S>
  442. BOOL CClassHash< T, S >::Find( const S& Key, T *const pItem )
  443. {
  444. BOOL fReturn;
  445. CBilink *pLinkage;
  446. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  447. //
  448. // initialize
  449. //
  450. fReturn = FALSE;
  451. pLinkage = NULL;
  452. if ( LocalFind( Key, &pLinkage ) != FALSE )
  453. {
  454. CClassHashEntry<T,S> *pEntry;
  455. pEntry = CClassHashEntry<T,S>::EntryFromBilink( pLinkage );
  456. *pItem = pEntry->m_Item;
  457. fReturn = TRUE;
  458. }
  459. return fReturn;
  460. }
  461. //**********************************************************************
  462. //**********************************************************************
  463. // ------------------------------
  464. // CClassHash::LocalFind - find an entry in a hash table, or find out where to insert.
  465. //
  466. // Entry: Refernce of 'key' to look for
  467. // Pointer to pointer to linkage of find or insert
  468. //
  469. // Exit: Boolean indicating whether the item was found
  470. // TRUE = found
  471. // FALSE = not found
  472. // ------------------------------
  473. #undef DPF_MODNAME
  474. #define DPF_MODNAME "CClassHash::LocalFind"
  475. template<class T, class S>
  476. BOOL CClassHash< T, S >::LocalFind( const S& Key, CBilink **const ppLinkage )
  477. {
  478. BOOL fFound;
  479. INT_PTR HashResult;
  480. CBilink *pTemp;
  481. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  482. HashResult = Key->HashFunction( m_iHashBitDepth );
  483. DNASSERT( ( HashResult < ( 1 << m_iHashBitDepth ) ) &&
  484. ( HashResult >= 0 ) );
  485. fFound = FALSE;
  486. pTemp = &m_pHashEntries[ HashResult ];
  487. while ( pTemp->GetNext() != &m_pHashEntries[ HashResult ] )
  488. {
  489. const CClassHashEntry< T, S > *pEntry;
  490. pEntry = CClassHashEntry< T, S >::EntryFromBilink( pTemp->GetNext() );
  491. if ( Key->CompareFunction( pEntry->m_Key ) == 0 )
  492. {
  493. fFound = TRUE;
  494. *ppLinkage = pTemp->GetNext();
  495. goto Exit;
  496. }
  497. else
  498. {
  499. pTemp = pTemp->GetNext();
  500. }
  501. }
  502. //
  503. // entry was not found, return pointer to linkage to insert after if a new
  504. // entry is being added to the table
  505. //
  506. *ppLinkage = pTemp;
  507. Exit:
  508. return fFound;
  509. }
  510. //**********************************************************************
  511. //**********************************************************************
  512. // ------------------------------
  513. // CClassHash::Grow - grow hash table to next larger size
  514. //
  515. // Entry: Nothing
  516. //
  517. // Exit: Nothing
  518. // ------------------------------
  519. #undef DPF_MODNAME
  520. #define DPF_MODNAME "CClassHash::Grow"
  521. template<class T, class S>
  522. void CClassHash< T, S >::Grow( void )
  523. {
  524. CBilink *pTemp;
  525. INT_PTR iNewEntryBitCount;
  526. DEBUG_ONLY( DNASSERT( m_fInitialized != FALSE ) );
  527. DNASSERT( m_iGrowBits != 0 );
  528. //
  529. // We're more than 50% full, find a new has table size that will accomodate
  530. // all of the current entries, and keep a pointer to the old data in case
  531. // the memory allocation fails.
  532. //
  533. pTemp = m_pHashEntries;
  534. iNewEntryBitCount = m_iHashBitDepth;
  535. do
  536. {
  537. iNewEntryBitCount += m_iGrowBits;
  538. } while ( m_iEntriesInUse >= ( ( 1 << iNewEntryBitCount ) / 2 ) );
  539. //
  540. // assert that we don't pull up half of the machine's address space!
  541. //
  542. DNASSERT( iNewEntryBitCount <= ( sizeof( UINT_PTR ) * 8 / 2 ) );
  543. m_pHashEntries = static_cast<CBilink*>( DNMalloc( sizeof( *pTemp ) * ( 1 << iNewEntryBitCount ) ) );
  544. if ( m_pHashEntries == NULL )
  545. {
  546. //
  547. // Allocation failed, restore the old data pointer and insert the item
  548. // into the hash table. This will probably result in adding to a bucket.
  549. //
  550. m_pHashEntries = pTemp;
  551. DPFX(DPFPREP, 0, "Warning: Failed to grow hash table when 50% full!" );
  552. }
  553. else
  554. {
  555. INT_PTR iOldHashSize;
  556. DEBUG_ONLY( INT_PTR iOldEntryCount );
  557. //
  558. // we have more memory, reorient the hash table and re-add all of
  559. // the old items
  560. //
  561. InitializeHashEntries( 1 << iNewEntryBitCount );
  562. DEBUG_ONLY( iOldEntryCount = m_iEntriesInUse );
  563. iOldHashSize = 1 << m_iHashBitDepth;
  564. m_iHashBitDepth = iNewEntryBitCount;
  565. m_iAllocatedEntries = 1 << iNewEntryBitCount;
  566. m_iEntriesInUse = 0;
  567. DNASSERT( iOldHashSize > 0 );
  568. while ( iOldHashSize > 0 )
  569. {
  570. iOldHashSize--;
  571. while ( pTemp[ iOldHashSize ].GetNext() != &pTemp[ iOldHashSize ] )
  572. {
  573. BOOL fTempReturn;
  574. S Key;
  575. T Item;
  576. CClassHashEntry<T,S> *pTempEntry;
  577. pTempEntry = pTempEntry->EntryFromBilink( pTemp[ iOldHashSize ].GetNext() );
  578. pTempEntry->RemoveFromList();
  579. Key = pTempEntry->m_Key;
  580. Item = pTempEntry->m_Item;
  581. m_EntryPool.Release( &m_EntryPool, pTempEntry );
  582. //
  583. // Since we're returning the current hash table entry to the pool
  584. // it will be immediately reused in the new table. We should never
  585. // have a problem adding to the new list.
  586. //
  587. fTempReturn = Insert( Key, Item );
  588. DNASSERT( fTempReturn != FALSE );
  589. DEBUG_ONLY( iOldEntryCount-- );
  590. }
  591. }
  592. DEBUG_ONLY( DNASSERT( iOldEntryCount == 0 ) );
  593. DNFree( pTemp );
  594. pTemp = NULL;
  595. }
  596. }
  597. //**********************************************************************
  598. //**********************************************************************
  599. // ------------------------------
  600. // CClassHash::InitializeHashEntries - initialize all of the entries in the hash table
  601. //
  602. // Entry: Count of entries to initialize.
  603. //
  604. // Exit: Nothing
  605. // ------------------------------
  606. #undef DPF_MODNAME
  607. #define DPF_MODNAME "CClassHash::InitializeHashEntries"
  608. template<class T, class S>
  609. void CClassHash< T, S >::InitializeHashEntries( const UINT_PTR uEntryCount ) const
  610. {
  611. UINT_PTR uLocalEntryCount;
  612. DNASSERT( m_pHashEntries != NULL );
  613. uLocalEntryCount = uEntryCount;
  614. while ( uLocalEntryCount != 0 )
  615. {
  616. uLocalEntryCount--;
  617. m_pHashEntries[ uLocalEntryCount ].Initialize();
  618. }
  619. }
  620. //**********************************************************************
  621. #ifdef __LOCAL_OFFSETOF_DEFINED__
  622. #undef __LOCAL_OFFSETOF_DEFINED__
  623. #undef OFFSETOF
  624. #endif // __LOCAL_OFFSETOF_DEFINED__
  625. #undef DPF_SUBCOMP
  626. #undef DPF_MODNAME
  627. #endif // __CLASS_HASH_H__