Leaked source code of windows server 2003
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.

1327 lines
41 KiB

  1. /*++
  2. Copyright (c) 1997-2002 Microsoft Corporation
  3. Module Name :
  4. LKR-hash.h
  5. Abstract:
  6. Declares LKRhash: a fast, scalable, cache- and
  7. multiprocessor-friendly hash table
  8. Public API
  9. Authors:
  10. Paul (Per-Ake) Larson, PALarson@microsoft.com, July 1997
  11. Murali R. Krishnan (MuraliK)
  12. George V. Reilly (GeorgeRe) 06-Jan-1998
  13. --*/
  14. #ifndef __LKR_HASH_H__
  15. #define __LKR_HASH_H__
  16. /* Enable STL-style iterators */
  17. #ifndef LKR_NO_STL_ITERATORS
  18. # define LKR_STL_ITERATORS 1
  19. #endif /* !LKR_NO_STL_ITERATORS */
  20. /* Enable call-back, table visitor routines */
  21. #ifndef LKR_NO_APPLY_IF
  22. # define LKR_APPLY_IF
  23. #endif /* !LKR_NO_APPLY_IF */
  24. /* Expose the table's ReadLock and WriteLock routines */
  25. #ifndef LKR_NO_EXPOSED_TABLE_LOCK
  26. # define LKR_EXPOSED_TABLE_LOCK
  27. #endif /* !LKR_NO_EXPOSED_TABLE_LOCK */
  28. #ifndef __IRTLMISC_H__
  29. # include <irtlmisc.h>
  30. #endif /* !__IRTLMISC_H__ */
  31. #ifdef __cplusplus
  32. extern "C" {
  33. #endif /* __cplusplus */
  34. typedef struct LkrHashTable* PLkrHashTable;
  35. /*--------------------------------------------------------------------
  36. * Possible return codes from LKR_functions and TypedLkrHashTable
  37. */
  38. enum LK_RETCODE {
  39. /* severe errors < 0 */
  40. LK_UNUSABLE = -99, /* Table corrupted: all bets are off */
  41. LK_ALLOC_FAIL, /* Ran out of memory */
  42. LK_BAD_ITERATOR, /* Invalid iterator; e.g., points to another table */
  43. LK_BAD_RECORD, /* Invalid record; e.g., NULL for LKR_InsertRecord */
  44. LK_BAD_PARAMETERS, /* Invalid parameters; e.g., NULL fnptrs to ctor */
  45. LK_NOT_INITIALIZED, /* LKR_Initialize was not called */
  46. LK_BAD_TABLE, /* Called with invalid PLkrHashTable */
  47. LK_SEALED, /* Modifying operation called on sealed table */
  48. LK_SUCCESS = 0, /* Everything's okay */
  49. LK_KEY_EXISTS, /* Key already present for
  50. LKR_InsertRecord(no-overwrite) */
  51. LK_NO_SUCH_KEY, /* Key not found in table */
  52. LK_NO_MORE_ELEMENTS,/* (Oldstyle, deprecated) Iterator exhausted */
  53. };
  54. #define LKR_SUCCEEDED(lkrc) ((lkrc) >= LK_SUCCESS)
  55. /*--------------------------------------------------------------------
  56. * Size parameter to LKR_CreateTable
  57. */
  58. enum LK_TABLESIZE {
  59. LK_SMALL_TABLESIZE = 1, /* < 200 elements */
  60. LK_MEDIUM_TABLESIZE = 2, /* 200...10,000 elements */
  61. LK_LARGE_TABLESIZE = 3, /* 10,000+ elements */
  62. };
  63. /*--------------------------------------------------------------------
  64. * Creation flag parameter to LKR_CreateTable
  65. */
  66. enum {
  67. LK_CREATE_MULTIKEYS = 0x0001, /* Allow multiple identical keys? */
  68. LK_CREATE_USE_LOCKS = 0x0002, /* Use locks to protect data? */
  69. LK_CREATE_DEFAULT = LK_CREATE_USE_LOCKS
  70. };
  71. /*--------------------------------------------------------------------
  72. * Initialization flag parameters to LKR_Initialize
  73. */
  74. enum {
  75. LK_INIT_DEFAULT = 0, /* 0 is an acceptable default */
  76. LK_INIT_DEBUG_SPEW = 0x1000, /* Enable debug output: debug version only */
  77. };
  78. /*--------------------------------------------------------------------
  79. * Reference Counting and Lifetime Management
  80. *
  81. * Increment the reference count of a record before returning it from
  82. * LKR_FindKey. It's necessary to do it in LKR_FindKey itself while the
  83. * bucket is still locked, rather than one of the wrappers, to avoid race
  84. * conditions. Similarly, the reference count is incremented in
  85. * LKR_InsertRecord and decremented in LKR_DeleteKey. Note: if an old
  86. * record is overwritten in LKR_InsertRecord, its reference count is
  87. * decremented. Similarly, for the other functions.
  88. *
  89. * It's up to you to decrement the reference count when you're finished
  90. * with it after retrieving it via LKR_FindKey (e.g., you could call
  91. * pht->AddRefRecord(pRec, LKAR_EXPLICIT_RELEASE)) and to determine the
  92. * semantics of what this means. The hashtable itself has no notion of
  93. * reference counts; this is merely to help with the lifetime management
  94. * of the record objects.
  95. */
  96. /* These reason codes help in debugging refcount leaks */
  97. enum LK_ADDREF_REASON {
  98. /* negative reasons => decrement refcount => release ownership */
  99. LKAR_DESTRUCTOR = -30, /* user calls ht.AddRefRecord in rec's */
  100. /* dtor to release final ref */
  101. LKAR_EXPLICIT_RELEASE = -29, /* user calls ht.AddRefRecord to */
  102. /* explicitly release a record */
  103. LKAR_DELETE_KEY = -28, /* DeleteKey() */
  104. LKAR_DELETE_RECORD = -27, /* DeleteRecord() */
  105. LKAR_INSERT_RELEASE = -26, /* InsertRecord overwrites prev record */
  106. LKAR_CLEAR = -25, /* Clear() */
  107. LKAR_LKR_DTOR = -24, /* internal hash table destructor */
  108. LKAR_APPLY_DELETE = -23, /* Apply[If] LKP_(PERFORM|_DELETE) */
  109. LKAR_DELETEIF_DELETE = -22, /* DeleteIf LKP_(PERFORM|_DELETE) */
  110. LKAR_DELETE_MULTI_FREE = -21, /* DeleteKeyMultipleRecords, freed */
  111. LKAR_ITER_RELEASE = -20, /* ++iter releases previous record */
  112. LKAR_ITER_ASSIGN_RELEASE = -19, /* iter.operator= releases prev rec */
  113. LKAR_ITER_DTOR = -18, /* ~iter */
  114. LKAR_ITER_ERASE = -17, /* Erase(iter): iter releases record */
  115. LKAR_ITER_ERASE_TABLE = -16, /* Erase(iter); table releases record */
  116. LKAR_ITER_CLOSE = -15, /* CloseIterator (obsolete) */
  117. LKAR_FIND_MULTI_FREE = -14, /* FindKeyMultipleRecords, freed */
  118. LKAR_MIN_NEGATIVE = LKAR_EXPLICIT_RELEASE,
  119. LKAR_MAX_NEGATIVE = LKAR_ITER_CLOSE,
  120. LKAR_MIN_DELETE_FROM_TABLE = LKAR_DELETE_KEY,
  121. LKAR_MAX_DELETE_FROM_TABLE = LKAR_DELETE_MULTI_FREE,
  122. /* positive reasons => increment refcount => add an owner */
  123. LKAR_INSERT_RECORD = +11, /* InsertRecord() */
  124. LKAR_FIND_KEY = +12, /* FindKey() */
  125. LKAR_ITER_ACQUIRE = +13, /* ++iter acquires next record */
  126. LKAR_ITER_COPY_CTOR = +14, /* iter copy constructor acquires rec */
  127. LKAR_ITER_ASSIGN_ACQUIRE = +15, /* iter.operator= acquires new rec */
  128. LKAR_ITER_INSERT = +16, /* Insert(iter) */
  129. LKAR_ITER_FIND = +17, /* Find(iter) */
  130. LKAR_CONSTRUCTOR = +18, /* user calls ht.AddRefRecord to */
  131. /* construct initial ref for a rec */
  132. LKAR_EXPLICIT_ACQUIRE = +19, /* user calls ht.AddRefRecord to */
  133. /* explicitly acquire a ref to a rec */
  134. LKAR_MIN_POSITIVE = LKAR_INSERT_RECORD,
  135. LKAR_MAX_POSITIVE = LKAR_CONSTRUCTOR,
  136. };
  137. /* Convert an LK_ADDREF_REASON to a string representation.
  138. * Useful for debugging.
  139. */
  140. IRTL_DLLEXP
  141. const char*
  142. LKR_AddRefReasonAsString(
  143. LK_ADDREF_REASON lkar);
  144. /*--------------------------------------------------------------------
  145. * A collection of records, with identical keys, as returned by
  146. * LKR_FindKeyMultipleRecords and LKR_DeleteKeyMultipleRecords (qv).
  147. * It must be destroyed by LKR_FreeMultipleRecords.
  148. */
  149. typedef struct _LKR_MULTIPLE_RECORDS
  150. {
  151. PVOID m_Table; /* reserved */
  152. PVOID m_SubTable; /* reserved */
  153. LK_ADDREF_REASON m_lkarRelease; /* reserved */
  154. size_t m_cRecords; /* num records in array m_apvRecords */
  155. PVOID m_apvRecords[1]; /* variable size,
  156. bounded by m_cRecords */
  157. } LKR_MULTIPLE_RECORDS;
  158. /*--------------------------------------------------------------------
  159. * Parameter to Apply and ApplyIf, and iterator constructors.
  160. */
  161. enum LK_LOCKTYPE {
  162. LKL_NOLOCK = 1, /* Don't lock the table */
  163. LKL_READLOCK = 2, /* Lock the table for reading (for constness) */
  164. LKL_WRITELOCK = 3, /* Lock the table for writing */
  165. };
  166. /*--------------------------------------------------------------------
  167. * Callback functions needed by table:
  168. * ExtractKey, CalcKeyHash, CompareKeys, AddRefRecord
  169. * Internally, records are handled as `const void*' and
  170. * keys are handled as `const DWORD_PTR'. The latter allows for
  171. * keys to be numbers as well as pointers (polymorphism).
  172. */
  173. /* Use types defined in recent versions of the Platform SDK in <basetsd.h>.
  174. */
  175. #ifndef _W64
  176. typedef DWORD DWORD_PTR; /* integral type big enough to hold a pointer */
  177. /* or a 32-bit integer*/
  178. #endif
  179. /* Given a record, return its key. Assumes that the key is embedded in
  180. * the record, or at least somehow derivable from the record. For
  181. * completely unrelated keys & values, a wrapper class should use
  182. * something like STL's pair<key,value> template to aggregate them
  183. * into a record.
  184. */
  185. typedef
  186. const DWORD_PTR
  187. (WINAPI *LKR_PFnExtractKey) (
  188. const void* pvRecord);
  189. /* Given a key, return its hash signature. The hashing functions in
  190. * hashfn.h (or something that builds upon them) are suggested.
  191. */
  192. typedef
  193. DWORD
  194. (WINAPI *LKR_PFnCalcKeyHash) (
  195. const DWORD_PTR pnKey);
  196. /* Compare two keys; e.g., _stricmp, memcmp
  197. * Return value: <0 => key1 < key2, ==0 => key1 == key2, >0 => key1 > key2
  198. *
  199. * If this is not a multikeys hashtable, it's sufficient to return
  200. * zero if the keys are identical and a non-zero value otherwise.
  201. * For a multikeys table (multiple, identical keys), the keys needed to be
  202. * sorted, so the return value's sign must be correct.
  203. *
  204. * Note: CompareKeys is called only when the two keys have identical
  205. * hash signatures.
  206. */
  207. typedef
  208. int
  209. (WINAPI *LKR_PFnCompareKeys) (
  210. const DWORD_PTR pnKey1,
  211. const DWORD_PTR pnKey2);
  212. /* Adjust the reference count of a record. See the earlier discussion of
  213. * reference counting and lifetime management. Returns the new reference
  214. * count, which should always be non-negative. Do not rely on this value,
  215. * except for debugging purposes, with one exception: If the new reference
  216. * count is zero, the record is no longer in the hashtable.
  217. */
  218. typedef
  219. LONG
  220. (WINAPI *LKR_PFnAddRefRecord)(
  221. void* pvRecord,
  222. LK_ADDREF_REASON lkar);
  223. #ifdef LKR_APPLY_IF
  224. /*--------------------------------------------------------------------
  225. * Apply, ApplyIf, and DeleteIf provide one way to visit (enumerate) all
  226. * records in a table.
  227. */
  228. /*--------------------------------------------------------------------
  229. * Return codes from PFnRecordPred.
  230. */
  231. enum LK_PREDICATE {
  232. LKP_ABORT = 1, /* Stop walking the table immediately */
  233. LKP_NO_ACTION = 2, /* No action, just keep walking */
  234. LKP_PERFORM = 3, /* Perform action and continue walking */
  235. LKP_PERFORM_STOP = 4, /* Perform action, then stop */
  236. LKP_DELETE = 5, /* Delete record and keep walking */
  237. LKP_DELETE_STOP = 6, /* Delete record, then stop */
  238. };
  239. /*--------------------------------------------------------------------
  240. * Return codes from PFnRecordAction.
  241. */
  242. enum LK_ACTION {
  243. LKA_ABORT = 1, /* Stop walking the table immediately */
  244. LKA_FAILED = 2, /* Action failed; continue walking the table */
  245. LKA_SUCCEEDED = 3, /* Action succeeded; continue walking the table */
  246. };
  247. /* LKR_ApplyIf() and LKR_DeleteIf(): Does the record match the predicate?
  248. */
  249. typedef
  250. LK_PREDICATE
  251. (WINAPI *LKR_PFnRecordPred) (
  252. const void* pvRecord,
  253. void* pvState);
  254. /* LKR_Apply() et al: Perform action on record.
  255. */
  256. typedef
  257. LK_ACTION
  258. (WINAPI *LKR_PFnRecordAction)(
  259. const void* pvRecord,
  260. void* pvState);
  261. #endif /* LKR_APPLY_IF */
  262. /* Initialize the global variables needed by other LKR routines.
  263. */
  264. IRTL_DLLEXP
  265. int
  266. LKR_Initialize(
  267. DWORD dwInitFlags);
  268. /* Clean up the global variables needed by other LKR routines.
  269. */
  270. IRTL_DLLEXP
  271. void
  272. LKR_Terminate();
  273. /* Create a new LkrHashTable
  274. * Returns pointer to new table if successful. NULL, otherwise.
  275. * The table must be destroyed with LKR_DeleteTable.
  276. */
  277. IRTL_DLLEXP
  278. PLkrHashTable
  279. LKR_CreateTable(
  280. LPCSTR pszClassName, /* Identify the table for debugging */
  281. LKR_PFnExtractKey pfnExtractKey, /* Extract key from record */
  282. LKR_PFnCalcKeyHash pfnCalcKeyHash, /* Calculate hash signature of key */
  283. LKR_PFnCompareKeys pfnCompareKeys, /* Compare two keys */
  284. LKR_PFnAddRefRecord pfnAddRefRecord,/* AddRef in LKR_FindKey, etc */
  285. LK_TABLESIZE nTableSize, /* Small/Med/Large number of elements*/
  286. DWORD fCreateFlags /* Mixture of LK_CREATE_* flags. */
  287. );
  288. /* Destroy an LkrHashTable created by LKR_CreateTable.
  289. */
  290. IRTL_DLLEXP
  291. void
  292. LKR_DeleteTable(
  293. PLkrHashTable plkr);
  294. /* Insert a new record into hash table.
  295. * Returns LKR_SUCCESS if all OK, LKR_KEY_EXISTS if same key already
  296. * exists (unless fOverwrite), LKR_ALLOC_FAIL if out of space,
  297. * or LKR_BAD_RECORD for a bad record.
  298. * If fOverwrite is set and a record with this key is already present,
  299. * it will be overwritten. If there are multiple records with this key,
  300. * only the first will be overwritten.
  301. */
  302. IRTL_DLLEXP
  303. LK_RETCODE
  304. LKR_InsertRecord(
  305. PLkrHashTable plkr,
  306. const void* pvRecord,
  307. BOOL fOverwrite);
  308. /* Delete record with the given key from the table. Does not actually delete
  309. * record from memory, just calls AddRefRecord(LKAR_DELETE_KEY);
  310. * Returns LKR_SUCCESS if all OK, or LKR_NO_SUCH_KEY if not found
  311. * If ppvRecord is non-NULL, the record is returned in ppvRecord after
  312. * removing it from the table, but AddRefRecord(LKAR_DELETE_KEY) is not called.
  313. * If fDeleteAllSame is set, all records that match pnKey will be deleted
  314. * from the table; otherwise, only the first matching record is deleted.
  315. */
  316. IRTL_DLLEXP
  317. LK_RETCODE
  318. LKR_DeleteKey(
  319. PLkrHashTable plkr,
  320. const DWORD_PTR pnKey,
  321. const void** ppvRecord,
  322. BOOL fDeleteAllSame);
  323. /* Delete a record from the table, if present.
  324. * Returns LKR_SUCCESS if all OK, or LKR_NO_SUCH_KEY if not found
  325. */
  326. IRTL_DLLEXP
  327. LK_RETCODE
  328. LKR_DeleteRecord(
  329. PLkrHashTable plkr,
  330. const void* pvRecord);
  331. /* Find record with given key.
  332. * Returns: LKR_SUCCESS, if record found (record is returned in *ppvRecord)
  333. * LKR_NO_SUCH_KEY, if no record with given key value was found
  334. * LKR_BAD_RECORD, if ppvRecord is invalid
  335. * LKR_UNUSABLE, if hash table not in usable state
  336. * Note: the record is AddRef'd. You must decrement the reference
  337. * count when you are finished with the record (if you're implementing
  338. * refcounting semantics).
  339. */
  340. IRTL_DLLEXP
  341. LK_RETCODE
  342. LKR_FindKey(
  343. PLkrHashTable plkr,
  344. const DWORD_PTR pnKey,
  345. const void** ppvRecord);
  346. /* Sees if the record is contained in the table
  347. * Returns: LKR_SUCCESS, if record found
  348. * LKR_NO_SUCH_KEY, if record is not in the table
  349. * LKR_BAD_RECORD, if pvRecord is invalid
  350. * LKR_UNUSABLE, if hash table not in usable state
  351. * Note: the record is *not* AddRef'd. By definition, the caller
  352. * already has a reference to it.
  353. */
  354. IRTL_DLLEXP
  355. LK_RETCODE
  356. LKR_FindRecord(
  357. PLkrHashTable plkr,
  358. const void* pvRecord);
  359. /* Find all records with given key. If table was not created with
  360. * LK_CREATE_MULTIKEYS, there will be at most one such record.
  361. *
  362. * Returns: LKR_SUCCESS, if record(s) found (number of record is returned
  363. * in *pcRecords)
  364. * LKR_NO_SUCH_KEY, if no record with given key value was found
  365. * LKR_BAD_PARAMETERS, if pcRecords is invalid
  366. * LKR_UNUSABLE, if hash table not in usable state
  367. *
  368. * If pplmr is not NULL, a (*pcRecords)-element array of records is returned
  369. * in *pplmr. These records are AddRef(LKAR_FIND_KEY)'d. The pplmr struct
  370. * must be destroyed with LKR_FreeMultipleRecords, which will take
  371. * care of releasing the references with AddRef(LKAR_FIND_MULTI_FREE).
  372. *
  373. * If pplmr is NULL, *pcRecords contains the number of matching records.
  374. * These records are not AddRef'd.
  375. *
  376. * pcRecords must not be NULL.
  377. */
  378. IRTL_DLLEXP
  379. LK_RETCODE
  380. LKR_FindKeyMultipleRecords(
  381. PLkrHashTable plkr,
  382. const DWORD_PTR pnKey,
  383. size_t* pcRecords,
  384. LKR_MULTIPLE_RECORDS** pplmr);
  385. /* Delete all record(s) with the given key from the table. If table was not
  386. * created with LK_CREATE_MULTIKEYS, there will be at most one such record.
  387. * Does not actually delete record(s) from memory, just removes them
  388. * from the table.
  389. *
  390. * Returns: LKR_SUCCESS, if record(s) found (number of record is returned
  391. * in *pcRecords)
  392. * LKR_NO_SUCH_KEY, if no record with given key value was found
  393. * LKR_BAD_PARAMETERS, if pcRecords is invalid
  394. * LKR_UNUSABLE, if hash table not in usable state
  395. *
  396. * If pplmr is not NULL, a (*pcRecords)-element array of records is returned
  397. * in *pplmr. These records are not AddRef'd, but they have been removed from.
  398. * the table. The pplmr struct must be destroyed with LKR_FreeMultipleRecords,
  399. * which will take care of releasing the final reference on each record
  400. * with AddRef(LKAR_DELETE_MULTI_FREE).
  401. *
  402. * If pplmr is NULL, *pcRecords contains the number of matching records.
  403. * These records were AddRef(LKAR_DELETE_KEY)'d when they were removed
  404. * from the table.
  405. *
  406. * pcRecords must not be NULL.
  407. */
  408. IRTL_DLLEXP
  409. LK_RETCODE
  410. LKR_DeleteKeyMultipleRecords(
  411. PLkrHashTable plkr,
  412. const DWORD_PTR pnKey,
  413. size_t* pcRecords,
  414. LKR_MULTIPLE_RECORDS** pplmr);
  415. /* Destroys an array created by LKR_FindKeyMultipleRecords or
  416. * LKR_DeleteKeyMultipleRecords. Releases a reference on each record,
  417. * using either LKAR_FIND_MULTI_FREE or LKAR_DELETE_MULTI_FREE.
  418. * Returns: LKR_SUCCESS
  419. * LKR_BAD_PARAMETERS, if ppvRecords is invalid
  420. * LKR_UNUSABLE, if hash table not in usable state
  421. */
  422. IRTL_DLLEXP
  423. LK_RETCODE
  424. LKR_FreeMultipleRecords(
  425. LKR_MULTIPLE_RECORDS* plmr);
  426. #ifdef LKR_APPLY_IF
  427. /* Walk the hash table, applying pfnAction to all records.
  428. * Locks one subtable after another with either a (possibly
  429. * shared) readlock or a writelock, according to lkl.
  430. * Loop is aborted if pfnAction ever returns LKA_ABORT.
  431. * Returns the number of successful applications.
  432. */
  433. IRTL_DLLEXP
  434. DWORD
  435. LKR_Apply(
  436. PLkrHashTable plkr,
  437. LKR_PFnRecordAction pfnAction,
  438. void* pvState,
  439. LK_LOCKTYPE lkl);
  440. /* Walk the hash table, applying pfnAction to any records that match
  441. * pfnPredicate. Locks one subtable after another with either
  442. * a (possibly shared) readlock or a writelock, according to lkl.
  443. * Loop is aborted if pfnAction ever returns LKA_ABORT.
  444. * Returns the number of successful applications.
  445. */
  446. IRTL_DLLEXP
  447. DWORD
  448. LKR_ApplyIf(
  449. PLkrHashTable plkr,
  450. LKR_PFnRecordPred pfnPredicate,
  451. LKR_PFnRecordAction pfnAction,
  452. void* pvState,
  453. LK_LOCKTYPE lkl);
  454. /* Delete any records that match pfnPredicate.
  455. * Locks one subtable after another with a writelock.
  456. * Returns the number of deletions.
  457. *
  458. * Do *not* walk the hash table by hand with an iterator and call
  459. * LKR_DeleteKey. The iterator will end up pointing to garbage.
  460. */
  461. IRTL_DLLEXP
  462. DWORD
  463. LKR_DeleteIf(
  464. PLkrHashTable plkr,
  465. LKR_PFnRecordPred pfnPredicate,
  466. void* pvState);
  467. #endif /* LKR_APPLY_IF */
  468. /* Check table for consistency. Returns 0 if okay, or the number of
  469. * errors otherwise.
  470. */
  471. IRTL_DLLEXP
  472. int
  473. LKR_CheckTable(
  474. PLkrHashTable plkr);
  475. /* Remove all data from the table
  476. */
  477. IRTL_DLLEXP
  478. void
  479. LKR_Clear(
  480. PLkrHashTable plkr);
  481. /* Number of elements in the table
  482. */
  483. IRTL_DLLEXP
  484. DWORD
  485. LKR_Size(
  486. PLkrHashTable plkr);
  487. /* Maximum possible number of elements in the table
  488. */
  489. IRTL_DLLEXP
  490. DWORD
  491. LKR_MaxSize(
  492. PLkrHashTable plkr);
  493. /* Is the hash table usable?
  494. */
  495. IRTL_DLLEXP
  496. BOOL
  497. LKR_IsUsable(
  498. PLkrHashTable plkr);
  499. /* Is the hash table consistent and correct?
  500. */
  501. IRTL_DLLEXP
  502. BOOL
  503. LKR_IsValid(
  504. PLkrHashTable plkr);
  505. #ifdef LKR_EXPOSED_TABLE_LOCK
  506. /* Lock the table (exclusively) for writing
  507. */
  508. IRTL_DLLEXP
  509. void
  510. LKR_WriteLock(
  511. PLkrHashTable plkr);
  512. /* Lock the table (possibly shared) for reading
  513. */
  514. IRTL_DLLEXP
  515. void
  516. LKR_ReadLock(
  517. PLkrHashTable plkr);
  518. /* Unlock the table for writing
  519. */
  520. IRTL_DLLEXP
  521. void
  522. LKR_WriteUnlock(
  523. PLkrHashTable plkr);
  524. /* Unlock the table for reading
  525. */
  526. IRTL_DLLEXP
  527. void
  528. LKR_ReadUnlock(
  529. PLkrHashTable plkr);
  530. /* Is the table already locked for writing?
  531. */
  532. IRTL_DLLEXP
  533. BOOL
  534. LKR_IsWriteLocked(
  535. PLkrHashTable plkr);
  536. /* Is the table already locked for reading?
  537. */
  538. IRTL_DLLEXP
  539. BOOL
  540. LKR_IsReadLocked(
  541. PLkrHashTable plkr);
  542. /* Is the table unlocked for writing?
  543. */
  544. IRTL_DLLEXP
  545. BOOL
  546. LKR_IsWriteUnlocked(
  547. PLkrHashTable plkr);
  548. /* Is the table unlocked for reading?
  549. */
  550. IRTL_DLLEXP
  551. BOOL
  552. LKR_IsReadUnlocked(
  553. PLkrHashTable plkr);
  554. /* Convert the read lock to a write lock. Note: another thread may acquire
  555. * exclusive access to the table before this routine returns.
  556. */
  557. IRTL_DLLEXP
  558. void
  559. LKR_ConvertSharedToExclusive(
  560. PLkrHashTable plkr);
  561. /* Convert the write lock to a read lock
  562. */
  563. IRTL_DLLEXP
  564. void
  565. LKR_ConvertExclusiveToShared(
  566. PLkrHashTable plkr);
  567. #endif /* LKR_EXPOSED_TABLE_LOCK */
  568. #ifdef __cplusplus
  569. } // extern "C"
  570. // Only provide iterators in the C++ interface. It's too hard to
  571. // provide the correct ownership semantics in a typesafe way in C,
  572. // and C users can always use the LKR_ApplyIf family of callback
  573. // enumerators if they really need to walk the hashtable.
  574. #ifdef LKR_STL_ITERATORS
  575. #pragma message("STL iterators")
  576. // needed for std::forward_iterator_tag, etc
  577. #include <iterator>
  578. #include <irtldbg.h>
  579. #define LKR_ITER_TRACE IRTLTRACE
  580. class IRTL_DLLEXP LKR_Iterator
  581. {
  582. private:
  583. friend IRTL_DLLEXP LKR_Iterator LKR_Begin(PLkrHashTable plkr);
  584. friend IRTL_DLLEXP LKR_Iterator LKR_End(PLkrHashTable plkr);
  585. // private ctor
  586. LKR_Iterator(bool);
  587. public:
  588. // default ctor
  589. LKR_Iterator();
  590. // copy ctor
  591. LKR_Iterator(const LKR_Iterator& rhs);
  592. // assignment operator
  593. LKR_Iterator& operator=(const LKR_Iterator& rhs);
  594. // dtor
  595. ~LKR_Iterator();
  596. // Increment the iterator to point to the next record, or to LKR_End()
  597. bool Increment();
  598. // Is the iterator valid?
  599. bool IsValid() const;
  600. // Returns the record that the iterator points to.
  601. // Must point to a valid record.
  602. const void* Record() const;
  603. // Returns the key of the record that the iterator points to.
  604. // Must point to a valid record.
  605. const DWORD_PTR Key() const;
  606. // Compare two iterators for equality
  607. bool operator==(const LKR_Iterator& rhs) const;
  608. // Compare two iterators for inequality
  609. bool operator!=(const LKR_Iterator& rhs) const;
  610. // pointer to implementation object
  611. void* pImpl;
  612. }; // class LKR_Iterator
  613. /* Return iterator pointing to first item in table
  614. */
  615. IRTL_DLLEXP
  616. LKR_Iterator
  617. LKR_Begin(
  618. PLkrHashTable plkr);
  619. /* Return a one-past-the-end iterator. Always empty.
  620. */
  621. IRTL_DLLEXP
  622. LKR_Iterator
  623. LKR_End(
  624. PLkrHashTable plkr);
  625. /* Insert a record
  626. * Returns `true' if successful; iterResult points to that record
  627. * Returns `false' otherwise; iterResult == End()
  628. */
  629. IRTL_DLLEXP
  630. bool
  631. LKR_Insert(
  632. PLkrHashTable plkr,
  633. /* in */ const void* pvRecord,
  634. /* out */ LKR_Iterator& riterResult,
  635. /* in */ bool fOverwrite=false);
  636. /* Erase the record pointed to by the iterator; adjust the iterator
  637. * to point to the next record. Returns `true' if successful.
  638. */
  639. IRTL_DLLEXP
  640. bool
  641. LKR_Erase(
  642. PLkrHashTable plkr,
  643. /* in,out */ LKR_Iterator& riter);
  644. /* Erase the records in the range [riterFirst, riterLast).
  645. * Returns `true' if successful.
  646. */
  647. IRTL_DLLEXP
  648. bool
  649. LKR_Erase(
  650. PLkrHashTable plkr,
  651. /*in*/ LKR_Iterator& riterFirst,
  652. /*in*/ LKR_Iterator& riterLast);
  653. /* Find the (first) record that has its key == pnKey.
  654. * If successful, returns `true' and iterator points to (first) record.
  655. * If fails, returns `false' and iterator == End()
  656. */
  657. IRTL_DLLEXP
  658. bool
  659. LKR_Find(
  660. PLkrHashTable plkr,
  661. /* in */ DWORD_PTR pnKey,
  662. /* out */ LKR_Iterator& riterResult);
  663. /* Find the range of records that have their keys == pnKey.
  664. * If successful, returns `true', iterFirst points to first record,
  665. * and iterLast points to one-beyond-the last such record.
  666. * If fails, returns `false' and both iterators == End().
  667. * Primarily useful when fMultiKeys == TRUE
  668. */
  669. IRTL_DLLEXP
  670. bool
  671. LKR_EqualRange(
  672. PLkrHashTable plkr,
  673. /* in */ DWORD_PTR pnKey,
  674. /* out */ LKR_Iterator& riterFirst, // inclusive
  675. /* out */ LKR_Iterator& riterLast); // exclusive
  676. #endif // LKR_STL_ITERATORS
  677. //--------------------------------------------------------------------
  678. // A typesafe wrapper for PLkrHashTable
  679. //
  680. // * _Derived must derive from TypedLkrHashTable and provide certain member
  681. // functions. It's needed for various downcasting operations.
  682. // * _Record is the type of the record. PLkrHashTable will store
  683. // pointers to _Record, as const void*.
  684. // * _Key is the type of the key. _Key is used directly; i.e., it is
  685. // not assumed to be a pointer type. PLkrHashTable assumes that
  686. // the key is stored in the associated record. See the comments
  687. // at the declaration of LKR_PFnExtractKey for more details.
  688. //
  689. // You may need to add the following line to your code to disable
  690. // warning messages about truncating extremly long identifiers.
  691. // #pragma warning (disable : 4786)
  692. //
  693. // The _Derived class should look something like this:
  694. // class CDerived : public TypedLkrHashTable<CDerived, RecordType, KeyType>
  695. // {
  696. // public:
  697. // CDerived()
  698. // : TypedLkrHashTable<CDerived, RecordType, KeyType>("CDerived")
  699. // {/*other ctor actions*/}
  700. // static KeyType ExtractKey(const RecordType* pTest);
  701. // static DWORD CalcKeyHash(const KeyType Key);
  702. // static int CompareKeys(const KeyType Key1, const KeyType Key2);
  703. // static LONG AddRefRecord(RecordType* pRecord,LK_ADDREF_REASON lkar);
  704. // // optional: other functions
  705. // };
  706. //
  707. //--------------------------------------------------------------------
  708. template <class _Derived, class _Record, class _Key>
  709. class TypedLkrHashTable
  710. {
  711. public:
  712. // convenient aliases
  713. typedef _Derived Derived;
  714. typedef _Record Record;
  715. typedef _Key Key;
  716. typedef TypedLkrHashTable<_Derived, _Record, _Key> HashTable;
  717. #ifdef LKR_APPLY_IF
  718. // LKR_ApplyIf() and LKR_DeleteIf(): Does the record match the predicate?
  719. // Note: takes a Record*, not a const Record*. You can modify the
  720. // record in Pred() or Action(), if you like, but if you do, you
  721. // should use LKL_WRITELOCK to lock the table.
  722. typedef LK_PREDICATE (WINAPI *PFnRecordPred) (Record* pRec, void* pvState);
  723. // Apply() et al: Perform action on record.
  724. typedef LK_ACTION (WINAPI *PFnRecordAction)(Record* pRec, void* pvState);
  725. #endif // LKR_APPLY_IF
  726. protected:
  727. PLkrHashTable m_plkr;
  728. // Wrappers for the typesafe methods exposed by the derived class
  729. static const DWORD_PTR WINAPI
  730. _ExtractKey(const void* pvRecord)
  731. {
  732. const _Record* pRec = static_cast<const _Record*>(pvRecord);
  733. const _Key key = static_cast<const _Key>(_Derived::ExtractKey(pRec));
  734. // I would prefer to use reinterpret_cast here and in _CalcKeyHash
  735. // and _CompareKeys, but the stupid Win64 compiler thinks it knows
  736. // better than I do.
  737. return (const DWORD_PTR) key;
  738. }
  739. static DWORD WINAPI
  740. _CalcKeyHash(const DWORD_PTR pnKey)
  741. {
  742. const _Key key = (const _Key) (DWORD_PTR) pnKey;
  743. return _Derived::CalcKeyHash(key);
  744. }
  745. static int WINAPI
  746. _CompareKeys(const DWORD_PTR pnKey1, const DWORD_PTR pnKey2)
  747. {
  748. const _Key key1 = (const _Key) (DWORD_PTR) pnKey1;
  749. const _Key key2 = (const _Key) (DWORD_PTR) pnKey2;
  750. return _Derived::CompareKeys(key1, key2);
  751. }
  752. static LONG WINAPI
  753. _AddRefRecord(void* pvRecord, LK_ADDREF_REASON lkar)
  754. {
  755. _Record* pRec = static_cast<_Record*>(pvRecord);
  756. return _Derived::AddRefRecord(pRec, lkar);
  757. }
  758. #ifdef LKR_APPLY_IF
  759. // Typesafe wrappers for Apply, ApplyIf, and DeleteIf.
  760. class CState
  761. {
  762. public:
  763. PFnRecordPred m_pfnPred;
  764. PFnRecordAction m_pfnAction;
  765. void* m_pvState;
  766. CState(
  767. PFnRecordPred pfnPred,
  768. PFnRecordAction pfnAction,
  769. void* pvState)
  770. : m_pfnPred(pfnPred), m_pfnAction(pfnAction), m_pvState(pvState)
  771. {}
  772. };
  773. static LK_PREDICATE WINAPI
  774. _Pred(const void* pvRecord, void* pvState)
  775. {
  776. _Record* pRec = static_cast<_Record*>(const_cast<void*>(pvRecord));
  777. CState* pState = static_cast<CState*>(pvState);
  778. return (*pState->m_pfnPred)(pRec, pState->m_pvState);
  779. }
  780. static LK_ACTION WINAPI
  781. _Action(const void* pvRecord, void* pvState)
  782. {
  783. _Record* pRec = static_cast<_Record*>(const_cast<void*>(pvRecord));
  784. CState* pState = static_cast<CState*>(pvState);
  785. return (*pState->m_pfnAction)(pRec, pState->m_pvState);
  786. }
  787. #endif // LKR_APPLY_IF
  788. public:
  789. TypedLkrHashTable(
  790. LPCSTR pszName, // An identifier for debugging
  791. LK_TABLESIZE nTableSize, // Small/Med/Large number of elements
  792. bool fMultiKeys=false // Allow multiple identical keys?
  793. )
  794. : m_plkr(NULL)
  795. {
  796. m_plkr = LKR_CreateTable(pszName, _ExtractKey, _CalcKeyHash,
  797. _CompareKeys, _AddRefRecord,
  798. nTableSize, fMultiKeys);
  799. }
  800. ~TypedLkrHashTable()
  801. {
  802. LKR_DeleteTable(m_plkr);
  803. }
  804. LK_RETCODE InsertRecord(const _Record* pRec, bool fOverwrite=false)
  805. { return LKR_InsertRecord(m_plkr, pRec, fOverwrite); }
  806. LK_RETCODE DeleteKey(const _Key key, _Record** ppRec=NULL,
  807. bool fDeleteAllSame=false)
  808. {
  809. const void* pvKey = reinterpret_cast<const void*>((DWORD_PTR)(key));
  810. DWORD_PTR pnKey = reinterpret_cast<DWORD_PTR>(pvKey);
  811. const void** ppvRec = (const void**) ppRec;
  812. return LKR_DeleteKey(m_plkr, pnKey, ppvRec, fDeleteAllSame);
  813. }
  814. LK_RETCODE DeleteRecord(const _Record* pRec)
  815. { return LKR_DeleteRecord(m_plkr, pRec);}
  816. // Note: returns a _Record**, not a const Record**. Note that you
  817. // can use a const type for the template parameter to ensure constness.
  818. LK_RETCODE FindKey(const _Key key, _Record** ppRec) const
  819. {
  820. if (ppRec == NULL)
  821. return LK_BAD_RECORD;
  822. *ppRec = NULL;
  823. const void* pvRec = NULL;
  824. const void* pvKey = reinterpret_cast<const void*>((DWORD_PTR)(key));
  825. DWORD_PTR pnKey = reinterpret_cast<DWORD_PTR>(pvKey);
  826. LK_RETCODE lkrc = LKR_FindKey(m_plkr, pnKey, &pvRec);
  827. *ppRec = static_cast<_Record*>(const_cast<void*>(pvRec));
  828. return lkrc;
  829. }
  830. LK_RETCODE FindRecord(const _Record* pRec) const
  831. { return LKR_FindRecord(m_plkr, pRec);}
  832. LK_RETCODE FindKeyMultipleRecords(const _Key key,
  833. size_t* pcRecords,
  834. LKR_MULTIPLE_RECORDS** pplmr=NULL
  835. ) const
  836. {
  837. const void* pvKey = reinterpret_cast<const void*>(key);
  838. DWORD_PTR pnKey = reinterpret_cast<DWORD_PTR>(pvKey);
  839. return LKR_FindKeyMultipleRecords(m_plkr, pnKey, pcRecords, pplmr);
  840. }
  841. LK_RETCODE DeleteKeyMultipleRecords(const _Key key,
  842. size_t* pcRecords,
  843. LKR_MULTIPLE_RECORDS** pplmr=NULL)
  844. {
  845. const void* pvKey = reinterpret_cast<const void*>(key);
  846. DWORD_PTR pnKey = reinterpret_cast<DWORD_PTR>(pvKey);
  847. return LKR_DeleteKeyMultipleRecords(m_plkr, pnKey, pcRecords, pplmr);
  848. }
  849. static LK_RETCODE FreeMultipleRecords(LKR_MULTIPLE_RECORDS* plmr)
  850. {
  851. return LKR_FreeMultipleRecords(plmr);
  852. }
  853. #ifdef LKR_APPLY_IF
  854. DWORD Apply(PFnRecordAction pfnAction,
  855. void* pvState=NULL,
  856. LK_LOCKTYPE lkl=LKL_READLOCK)
  857. {
  858. IRTLASSERT(pfnAction != NULL);
  859. if (pfnAction == NULL)
  860. return 0;
  861. CState state(NULL, pfnAction, pvState);
  862. return LKR_Apply(m_plkr, _Action, &state, lkl);
  863. }
  864. DWORD ApplyIf(PFnRecordPred pfnPredicate,
  865. PFnRecordAction pfnAction,
  866. void* pvState=NULL,
  867. LK_LOCKTYPE lkl=LKL_READLOCK)
  868. {
  869. IRTLASSERT(pfnPredicate != NULL && pfnAction != NULL);
  870. if (pfnPredicate == NULL || pfnAction == NULL)
  871. return 0;
  872. CState state(pfnPredicate, pfnAction, pvState);
  873. return LKR_ApplyIf(m_plkr, _Pred, _Action, &state, lkl);
  874. }
  875. DWORD DeleteIf(PFnRecordPred pfnPredicate, void* pvState=NULL)
  876. {
  877. IRTLASSERT(pfnPredicate != NULL);
  878. if (pfnPredicate == NULL)
  879. return 0;
  880. CState state(pfnPredicate, NULL, pvState);
  881. return LKR_DeleteIf(m_plkr, _Pred, &state);
  882. }
  883. #endif // LKR_APPLY_IF
  884. int CheckTable() const
  885. { return LKR_CheckTable(m_plkr); }
  886. void Clear()
  887. { return LKR_Clear(m_plkr); }
  888. DWORD Size() const
  889. { return LKR_Size(m_plkr); }
  890. DWORD MaxSize() const
  891. { return LKR_MaxSize(m_plkr); }
  892. BOOL IsUsable() const
  893. { return LKR_IsUsable(m_plkr); }
  894. BOOL IsValid() const
  895. { return LKR_IsValid(m_plkr); }
  896. #ifdef LKR_EXPOSED_TABLE_LOCK
  897. void WriteLock()
  898. { LKR_WriteLock(m_plkr); }
  899. void ReadLock() const
  900. { LKR_ReadLock(m_plkr); }
  901. void WriteUnlock()
  902. { LKR_WriteUnlock(m_plkr); }
  903. void ReadUnlock() const
  904. { LKR_ReadUnlock(m_plkr); }
  905. BOOL IsWriteLocked() const
  906. { return LKR_IsWriteLocked(m_plkr); }
  907. BOOL IsReadLocked() const
  908. { return LKR_IsReadLocked(m_plkr); }
  909. BOOL IsWriteUnlocked() const
  910. { return LKR_IsWriteUnlocked(m_plkr); }
  911. BOOL IsReadUnlocked() const
  912. { return LKR_IsReadUnlocked(m_plkr); }
  913. void ConvertSharedToExclusive() const
  914. { LKR_ConvertSharedToExclusive(m_plkr); }
  915. void ConvertExclusiveToShared() const
  916. { LKR_ConvertExclusiveToShared(m_plkr); }
  917. #endif // LKR_EXPOSED_TABLE_LOCK
  918. #ifdef LKR_STL_ITERATORS
  919. friend class LKR_Iterator;
  920. // TODO: const_iterator
  921. public:
  922. class iterator
  923. {
  924. friend class TypedLkrHashTable<_Derived, _Record, _Key>;
  925. protected:
  926. LKR_Iterator m_iter;
  927. iterator(
  928. const LKR_Iterator& rhs)
  929. : m_iter(rhs)
  930. {
  931. LKR_ITER_TRACE(_TEXT("Typed::prot ctor, this=%p, rhs=%p\n"),
  932. this, &rhs);
  933. }
  934. public:
  935. typedef std::forward_iterator_tag iterator_category;
  936. typedef _Record value_type;
  937. typedef ptrdiff_t difference_type;
  938. typedef size_t size_type;
  939. typedef value_type& reference;
  940. typedef value_type* pointer;
  941. iterator()
  942. : m_iter()
  943. {
  944. LKR_ITER_TRACE(_TEXT("Typed::default ctor, this=%p\n"), this);
  945. }
  946. iterator(
  947. const iterator& rhs)
  948. : m_iter(rhs.m_iter)
  949. {
  950. LKR_ITER_TRACE(_TEXT("Typed::copy ctor, this=%p, rhs=%p\n"),
  951. this, &rhs);
  952. }
  953. iterator& operator=(
  954. const iterator& rhs)
  955. {
  956. LKR_ITER_TRACE(_TEXT("Typed::operator=, this=%p, rhs=%p\n"),
  957. this, &rhs);
  958. m_iter = rhs.m_iter;
  959. return *this;
  960. }
  961. ~iterator()
  962. {
  963. LKR_ITER_TRACE(_TEXT("Typed::dtor, this=%p\n"), this);
  964. }
  965. pointer operator->() const
  966. {
  967. return (reinterpret_cast<_Record*>(
  968. const_cast<void*>(m_iter.Record())));
  969. }
  970. reference operator*() const
  971. {
  972. return * (operator->());
  973. }
  974. // pre-increment
  975. iterator& operator++()
  976. {
  977. LKR_ITER_TRACE(_TEXT("Typed::pre-increment, this=%p\n"), this);
  978. m_iter.Increment();
  979. return *this;
  980. }
  981. // post-increment
  982. iterator operator++(int)
  983. {
  984. LKR_ITER_TRACE(_TEXT("Typed::post-increment, this=%p\n"), this);
  985. iterator iterPrev = *this;
  986. m_iter.Increment();
  987. return iterPrev;
  988. }
  989. bool operator==(
  990. const iterator& rhs) const
  991. {
  992. LKR_ITER_TRACE(_TEXT("Typed::operator==, this=%p, rhs=%p\n"),
  993. this, &rhs);
  994. return m_iter == rhs.m_iter;
  995. }
  996. bool operator!=(
  997. const iterator& rhs) const
  998. {
  999. LKR_ITER_TRACE(_TEXT("Typed::operator!=, this=%p, rhs=%p\n"),
  1000. this, &rhs);
  1001. return m_iter != rhs.m_iter;
  1002. }
  1003. _Record* Record() const
  1004. {
  1005. LKR_ITER_TRACE(_TEXT("Typed::Record, this=%p\n"), this);
  1006. return reinterpret_cast<_Record*>(
  1007. const_cast<void*>(m_iter.Record()));
  1008. }
  1009. _Key Key() const
  1010. {
  1011. LKR_ITER_TRACE(_TEXT("Typed::Key, this=%p\n"), this);
  1012. return reinterpret_cast<_Key>(
  1013. reinterpret_cast<void*>(m_iter.Key()));
  1014. }
  1015. }; // class iterator
  1016. // Return iterator pointing to first item in table
  1017. iterator begin()
  1018. {
  1019. LKR_ITER_TRACE(_TEXT("Typed::begin()\n"));
  1020. return LKR_Begin(m_plkr);
  1021. }
  1022. // Return a one-past-the-end iterator. Always empty.
  1023. iterator end() const
  1024. {
  1025. LKR_ITER_TRACE(_TEXT("Typed::end()\n"));
  1026. return LKR_End(m_plkr);
  1027. }
  1028. template <class _InputIterator>
  1029. TypedLkrHashTable(
  1030. LPCSTR pszName, // An identifier for debugging
  1031. _InputIterator f, // first element in range
  1032. _InputIterator l, // one-beyond-last element
  1033. LK_TABLESIZE nTableSize, // Small/Med/Large number of elements
  1034. bool fMultiKeys=false // Allow multiple identical keys?
  1035. )
  1036. {
  1037. m_plkr = LKR_CreateTable(pszName, _ExtractKey, _CalcKeyHash,
  1038. _CompareKeys, _AddRefRecord,
  1039. nTableSize, fMultiKeys);
  1040. insert(f, l);
  1041. }
  1042. template <class _InputIterator>
  1043. void insert(_InputIterator f, _InputIterator l)
  1044. {
  1045. for ( ; f != l; ++f)
  1046. InsertRecord(&(*f));
  1047. }
  1048. bool
  1049. Insert(
  1050. const _Record* pRecord,
  1051. iterator& riterResult,
  1052. bool fOverwrite=false)
  1053. {
  1054. LKR_ITER_TRACE(_TEXT("Typed::Insert\n"));
  1055. return LKR_Insert(m_plkr, pRecord, riterResult.m_iter, fOverwrite);
  1056. }
  1057. bool
  1058. Erase(
  1059. iterator& riter)
  1060. {
  1061. LKR_ITER_TRACE(_TEXT("Typed::Erase\n"));
  1062. return LKR_Erase(m_plkr, riter.m_iter);
  1063. }
  1064. bool
  1065. Erase(
  1066. iterator& riterFirst,
  1067. iterator& riterLast)
  1068. {
  1069. LKR_ITER_TRACE(_TEXT("Typed::Erase2\n"));
  1070. return LKR_Erase(m_plkr, riterFirst.m_iter, riterLast.m_iter);
  1071. }
  1072. bool
  1073. Find(
  1074. const _Key key,
  1075. iterator& riterResult)
  1076. {
  1077. LKR_ITER_TRACE(_TEXT("Typed::Find\n"));
  1078. const void* pvKey = reinterpret_cast<const void*>((DWORD_PTR)(key));
  1079. DWORD_PTR pnKey = reinterpret_cast<DWORD_PTR>(pvKey);
  1080. return LKR_Find(m_plkr, pnKey, riterResult.m_iter);
  1081. }
  1082. bool
  1083. EqualRange(
  1084. const _Key key,
  1085. iterator& riterFirst,
  1086. iterator& riterLast)
  1087. {
  1088. LKR_ITER_TRACE(_TEXT("Typed::EqualRange\n"));
  1089. const void* pvKey = reinterpret_cast<const void*>((DWORD_PTR)(key));
  1090. DWORD_PTR pnKey = reinterpret_cast<DWORD_PTR>(pvKey);
  1091. return LKR_EqualRange(m_plkr, pnKey, riterFirst.m_iter,
  1092. riterLast.m_iter);
  1093. }
  1094. #undef LKR_ITER_TRACE
  1095. #endif // LKR_STL_ITERATORS
  1096. }; // class TypedLkrHashTable
  1097. #endif /* __cplusplus */
  1098. #endif /* __LKR_HASH_H__ */