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.

643 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1995.
  5. //
  6. // File: WLCURSOR.CXX
  7. //
  8. // Contents: Wordlist Merge Cursor
  9. //
  10. // Classes: CWlCursor
  11. //
  12. // History: 17-Jun--91 BartoszM Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <curstk.hxx>
  18. #include "wlcursor.hxx"
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Member: CWlCursor::CWlCursor, public
  22. //
  23. // Synopsis: Create a cursor that merges a number of chunk cursors.
  24. //
  25. // Arguments: [cCursor] -- count of cursors
  26. // [stkCursor] -- CKeyCurStack
  27. //
  28. // History: 17-Jun-91 BartoszM Created
  29. // 24-Jan-92 AmyA Modified to take CKeyCurArray as a
  30. // parameter.
  31. //
  32. // Notes: The cursors and the array will be deleted by destructor.
  33. //
  34. //----------------------------------------------------------------------------
  35. CWlCursor::CWlCursor( int cCursor, CKeyCurStack & stkCursor, WORKID widMax )
  36. : CKeyCursor ( 0, widMax ),
  37. _keyHeap(),
  38. _widHeap ( cCursor ),
  39. _occHeap ( cCursor )
  40. {
  41. // Two step construction of the heap.
  42. // We have to make sure that all cursors have a valid key
  43. CKeyCursor **aCursor = stkCursor.AcqStack();
  44. int count = 0;
  45. //
  46. // Remove 1. empty cursors
  47. // 2. cursors which are positioned on widInvalid and which
  48. // don't have a valid nextKey
  49. //
  50. for ( int i = 0; i < cCursor; i++ )
  51. {
  52. Win4Assert ( aCursor[i] != 0 );
  53. BOOL fDelete = FALSE;
  54. if ( aCursor[i]->GetKey() == 0 )
  55. fDelete = TRUE;
  56. else
  57. {
  58. if ( aCursor[i]->WorkId() == widInvalid )
  59. {
  60. if ( aCursor[i]->GetNextKey() == 0 )
  61. fDelete = TRUE;
  62. }
  63. }
  64. if ( fDelete )
  65. {
  66. delete aCursor[i];
  67. }
  68. else if ( count != i )
  69. aCursor[count++] = aCursor[i];
  70. else
  71. count++;
  72. }
  73. _keyHeap.MakeHeap ( count, aCursor );
  74. if ( !_keyHeap.IsEmpty() )
  75. {
  76. _iid = _keyHeap.Top()->IndexId();
  77. _pid = _keyHeap.Top()->Pid();
  78. ReplenishWid();
  79. ComputeWidCount();
  80. ReplenishOcc();
  81. ComputeOccCount();
  82. UpdateWeight();
  83. }
  84. }
  85. //+---------------------------------------------------------------------------
  86. //
  87. // Member: CWlCursor::GetKey, public
  88. //
  89. // Synopsis: Get current key.
  90. //
  91. // History: 06-May-91 BartoszM Created
  92. //
  93. // Notes: Does not replenish occHeap or widHeap
  94. // Current key is defined as:
  95. // 1. cur key of all cursors in occHeap and widHeap, or,
  96. // 2. if both empty, cur key of Top of keyHeap and
  97. // all others with the same cur key
  98. //
  99. //----------------------------------------------------------------------------
  100. const CKeyBuf * CWlCursor::GetKey()
  101. {
  102. if ( _occHeap.IsEmpty() )
  103. {
  104. if (_widHeap.IsEmpty() )
  105. {
  106. if ( _keyHeap.IsEmpty() )
  107. return 0;
  108. return _keyHeap.Top()->GetKey();
  109. }
  110. else
  111. return _widHeap.Top()->GetKey();
  112. }
  113. else
  114. return _occHeap.Top()->GetKey();
  115. }
  116. //+---------------------------------------------------------------------------
  117. //
  118. // Member: CWlCursor::WorkId, public
  119. //
  120. // Synopsis: Get current work id.
  121. //
  122. // History: 06-May-91 BartoszM Created
  123. //
  124. // Notes: Current wid is defined as:
  125. // 1. cur wid of all cursors in occHeap, or,
  126. // 2. if occHeap empty, cur wid of Top of widHeap
  127. // and cur wid of all cursors in widHeap
  128. // with the same wid
  129. //
  130. //----------------------------------------------------------------------------
  131. WORKID CWlCursor::WorkId()
  132. {
  133. if ( _occHeap.IsEmpty() )
  134. {
  135. if ( _widHeap.IsEmpty() )
  136. {
  137. return widInvalid;
  138. }
  139. return _widHeap.Top()->WorkId();
  140. }
  141. else
  142. return _occHeap.Top()->WorkId();
  143. }
  144. //+---------------------------------------------------------------------------
  145. //
  146. // Member: CWlCursor::Occurrence, public
  147. //
  148. // Synopsis: Get current occurrence.
  149. //
  150. // History: 06-May-91 BartoszM Created
  151. //
  152. // Notes: Current occurrence is defined as:
  153. // 1. cur occ of top of occHeap and cur occ of all other
  154. // cursors in it with the same cur occ
  155. //
  156. //----------------------------------------------------------------------------
  157. OCCURRENCE CWlCursor::Occurrence()
  158. {
  159. if ( _occHeap.IsEmpty() )
  160. return OCC_INVALID;
  161. return _occHeap.Top()->Occurrence();
  162. }
  163. //+---------------------------------------------------------------------------
  164. //
  165. // Member: CWlCursor::GetNextKey, public
  166. //
  167. // Synopsis: Move to next key
  168. //
  169. // Returns: Target key or NULL if no more keys
  170. //
  171. // History: 06-May-91 BartoszM Created
  172. //
  173. // Notes: 1. Increment and move to keyHeap all cursors from
  174. // occHeap and widHeap, or,
  175. // 2. if both empty, increment and reheap all cursors
  176. // from the keyHeap with the same cur key as Top
  177. //
  178. //----------------------------------------------------------------------------
  179. const CKeyBuf * CWlCursor::GetNextKey()
  180. {
  181. if ( ! _occHeap.IsEmpty() || !_widHeap.IsEmpty() )
  182. {
  183. // Move all cursors from occHeap and widHeap to keyHeap
  184. // advancing them to the next key
  185. CKeyCursor * cur;
  186. while ( ( cur = _occHeap.RemoveBottom() ) != 0 )
  187. {
  188. if ( cur->GetNextKey() == 0 )
  189. {
  190. delete cur;
  191. }
  192. else
  193. {
  194. _keyHeap.Add ( cur );
  195. }
  196. }
  197. while ( ( cur = _widHeap.RemoveBottom() ) != 0 )
  198. {
  199. if ( cur->GetNextKey() == 0 )
  200. {
  201. delete cur;
  202. }
  203. else
  204. {
  205. _keyHeap.Add ( cur );
  206. }
  207. }
  208. }
  209. else if ( !_keyHeap.IsEmpty() )
  210. {
  211. // Advance all cursors
  212. // with the lowest key.
  213. CKeyBuf key = *_keyHeap.Top()->GetKey();
  214. do {
  215. if ( _keyHeap.Top()->GetNextKey() == 0 )
  216. {
  217. delete _keyHeap.RemoveTop();
  218. if ( _keyHeap.IsEmpty () )
  219. return 0;
  220. }
  221. else
  222. _keyHeap.Reheap();
  223. } while ( AreEqual ( &key, _keyHeap.Top()->GetKey()) );
  224. }
  225. else
  226. return 0;
  227. if ( _keyHeap.IsEmpty() )
  228. return 0;
  229. else
  230. {
  231. _pid = _keyHeap.Top()->Pid();
  232. ReplenishWid();
  233. ComputeWidCount();
  234. ReplenishOcc();
  235. ComputeOccCount();
  236. UpdateWeight();
  237. return GetKey();
  238. }
  239. }
  240. //+---------------------------------------------------------------------------
  241. //
  242. // Member: CWlCursor::NextWorkId, public
  243. //
  244. // Synopsis: Move to next work id
  245. //
  246. // Returns: Target work id or widInvalid if no more wid's for current key
  247. //
  248. // History: 06-May-91 BartoszM Created
  249. //
  250. // Notes: 1. increment and move to widHeap all cursors in occHeap, or,
  251. // 2. if occHeap empty, increment and reheap all cursors with
  252. // the same wid as Top of widHeap
  253. //
  254. //----------------------------------------------------------------------------
  255. WORKID CWlCursor::NextWorkId()
  256. {
  257. if ( ! _occHeap.IsEmpty() )
  258. {
  259. CKeyCursor * cur;
  260. while ( ( cur = _occHeap.RemoveBottom() ) != 0 )
  261. {
  262. cur->NextWorkId();
  263. _widHeap.Add ( cur );
  264. }
  265. }
  266. else
  267. {
  268. if ( _widHeap.IsEmpty() )
  269. return widInvalid;
  270. WORKID wid = _widHeap.Top()->WorkId();
  271. if ( wid == widInvalid )
  272. return widInvalid;
  273. do
  274. {
  275. _widHeap.Top()->NextWorkId();
  276. _widHeap.Reheap();
  277. } while ( _widHeap.Top()->WorkId() == wid && wid != widInvalid );
  278. }
  279. if ( WorkId() != widInvalid )
  280. {
  281. ReplenishOcc();
  282. ComputeOccCount();
  283. }
  284. return WorkId();
  285. }
  286. //+---------------------------------------------------------------------------
  287. //
  288. // Member: CWlCursor::NextOccurrence, public
  289. //
  290. // Synopsis: Move to next occurrence
  291. //
  292. // Returns: Target occurrence or OCC_INVALID if no more occurrences
  293. // for current wid
  294. //
  295. // History: 06-May-91 BartoszM Created
  296. //
  297. // Notes: 1. Increment and reheap Top of occHeap
  298. //
  299. //----------------------------------------------------------------------------
  300. OCCURRENCE CWlCursor::NextOccurrence()
  301. {
  302. Win4Assert( WorkId() != widInvalid );
  303. if ( _occHeap.IsEmpty() )
  304. return OCC_INVALID;
  305. OCCURRENCE occPrev = _occHeap.Top()->Occurrence();
  306. if ( occPrev == OCC_INVALID )
  307. return OCC_INVALID;
  308. OCCURRENCE occNext;
  309. // Skip duplicate occurrences
  310. do {
  311. _occHeap.Top()->NextOccurrence();
  312. _occHeap.Reheap();
  313. occNext = _occHeap.Top()->Occurrence();
  314. } while ( occPrev == occNext && occPrev != OCC_INVALID);
  315. return occNext;
  316. }
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Member: CWlCursor::RatioFinished
  320. //
  321. // Synopsis: Return query progress
  322. //
  323. // Arguments: [ulDenominator] - on return, denominator of fraction
  324. // [ulNumerator] - on return, numerator of fraction
  325. //
  326. // History: 23-Jun-96 SitaramR Added header
  327. //
  328. //----------------------------------------------------------------------------
  329. void CWlCursor::RatioFinished (ULONG& denom, ULONG& num)
  330. {
  331. if ( _occHeap.IsEmpty() && _widHeap.IsEmpty() && _keyHeap.IsEmpty() )
  332. {
  333. num = denom = 1;
  334. return;
  335. }
  336. denom = 0;
  337. num = 0;
  338. // at least one of the heaps is not empty
  339. CKeyCursor **vector;
  340. int count = _occHeap.Count();
  341. vector = _occHeap.GetVector();
  342. for (int i = 0; i < count; i++)
  343. {
  344. ULONG d, n;
  345. vector[i]->RatioFinished(d, n);
  346. denom += d;
  347. num += n;
  348. Win4Assert( denom >= d && d > 0 ); // overflow?
  349. }
  350. count = _widHeap.Count();
  351. vector = _widHeap.GetVector();
  352. for (i = 0; i < count; i++)
  353. {
  354. ULONG d, n;
  355. vector[i]->RatioFinished(d, n);
  356. denom += d;
  357. num += n;
  358. Win4Assert( denom >= d && d > 0 ); // overflow?
  359. }
  360. Win4Assert( 0 != denom );
  361. // may be more in the heap -- not really done yet.
  362. if ( denom == num )
  363. denom++;
  364. }
  365. //+---------------------------------------------------------------------------
  366. //
  367. // Member: CWlCursor::MaxOccurrence
  368. //
  369. // Synopsis: Returns max occurrence of current wid, pid
  370. //
  371. // History: 20-Jun-96 SitaramR Created
  372. //
  373. //----------------------------------------------------------------------------
  374. OCCURRENCE CWlCursor::MaxOccurrence()
  375. {
  376. if ( _occHeap.IsEmpty() )
  377. {
  378. if (_widHeap.IsEmpty() )
  379. return OCC_INVALID;
  380. return _widHeap.Top()->MaxOccurrence();
  381. }
  382. else
  383. return _occHeap.Top()->MaxOccurrence();
  384. }
  385. //+---------------------------------------------------------------------------
  386. //
  387. // Member: CWlCursor::ComputeWidCount
  388. //
  389. // Synopsis: Computes the wid count
  390. //
  391. // History: 23-Jun-96 SitaramR Created
  392. //
  393. //----------------------------------------------------------------------------
  394. void CWlCursor::ComputeWidCount()
  395. {
  396. _ulWidCount = 0;
  397. int count = _widHeap.Count();
  398. if ( count > 0 )
  399. {
  400. CKeyCursor **curVec = _widHeap.GetVector();
  401. while ( --count >= 0 )
  402. _ulWidCount += curVec[count]->WorkIdCount();
  403. }
  404. if ( _ulWidCount == 0 )
  405. _ulWidCount = 1;
  406. //
  407. // _ulWidCount is an approximation because wid's can be counted multiple
  408. // times. However, the widCount cannot be more than the number of docs
  409. // in a wordlist.
  410. //
  411. if ( _ulWidCount > CI_MAX_DOCS_IN_WORDLIST )
  412. _ulWidCount = CI_MAX_DOCS_IN_WORDLIST;
  413. }
  414. //+---------------------------------------------------------------------------
  415. //
  416. // Member: CWlCursor::WorkIdCount, public
  417. //
  418. // Synopsis: return wid count
  419. //
  420. // History: 21-Jun-91 BartoszM Created
  421. //
  422. //----------------------------------------------------------------------------
  423. ULONG CWlCursor::WorkIdCount()
  424. {
  425. return _ulWidCount;
  426. }
  427. //+---------------------------------------------------------------------------
  428. //
  429. // Member: CWlCursor::ComputeOccCount
  430. //
  431. // Synopsis: Computes the occurrence count
  432. //
  433. // History: 23-Jun-96 SitaramR Created
  434. //
  435. //----------------------------------------------------------------------------
  436. void CWlCursor::ComputeOccCount()
  437. {
  438. Win4Assert( WorkId() != widInvalid );
  439. _ulOccCount = 0;
  440. int count = _occHeap.Count();
  441. if ( count > 0 )
  442. {
  443. CKeyCursor **curVec = _occHeap.GetVector();
  444. while ( --count >= 0 )
  445. {
  446. Win4Assert( curVec[count]->WorkId() != widInvalid );
  447. _ulOccCount += curVec[count]->OccurrenceCount();
  448. }
  449. }
  450. }
  451. //+---------------------------------------------------------------------------
  452. //
  453. // Member: CWlCursor::OccurrenceCount, public
  454. //
  455. // Synopsis: return occurrence count
  456. //
  457. // History: 21-Jun-91 BartoszM Created
  458. //
  459. //----------------------------------------------------------------------------
  460. ULONG CWlCursor::OccurrenceCount()
  461. {
  462. Win4Assert( WorkId() != widInvalid );
  463. return _ulOccCount;
  464. }
  465. //+---------------------------------------------------------------------------
  466. //
  467. // Member: CWlCursor::HitCount, public
  468. //
  469. // Synopsis: return occurrence count
  470. //
  471. // History: 27-Feb-92 AmyA Created
  472. //
  473. // Notes: see notes for OccurrenceCount().
  474. //
  475. //----------------------------------------------------------------------------
  476. ULONG CWlCursor::HitCount()
  477. {
  478. return OccurrenceCount();
  479. }
  480. //+---------------------------------------------------------------------------
  481. //
  482. // Member: CWlCursor::ReplenishOcc, private
  483. //
  484. // Synopsis: Replenish the occurrence heap
  485. //
  486. // Returns: TRUE if successful, FALSE if key heap exhausted
  487. //
  488. // Requires: _occHeap empty
  489. //
  490. // History: 06-May-91 BartoszM Created
  491. //
  492. //----------------------------------------------------------------------------
  493. BOOL CWlCursor::ReplenishOcc()
  494. {
  495. ciAssert ( _occHeap.IsEmpty() );
  496. Win4Assert( WorkId() != widInvalid );
  497. if ( _widHeap.IsEmpty() )
  498. {
  499. return FALSE;
  500. }
  501. // Move all cursors with the current wid
  502. // to occ heap
  503. WORKID wid = _widHeap.Top()->WorkId();
  504. do {
  505. CKeyCursor* cur = _widHeap.RemoveTop();
  506. _occHeap.Add ( cur );
  507. } while ( !_widHeap.IsEmpty() && (wid == _widHeap.Top()->WorkId()) );
  508. return TRUE;
  509. }
  510. //+---------------------------------------------------------------------------
  511. //
  512. // Member: CWlCursor::ReplenishWid, protected
  513. //
  514. // Synopsis: Replenish the wid heap
  515. //
  516. // Returns: TRUE if successful, FALSE if key heap exhausted
  517. //
  518. // Effects: Updates _iid to the ones of the widHeap top
  519. //
  520. // History: 06-May-91 BartoszM Created
  521. //
  522. //----------------------------------------------------------------------------
  523. BOOL CWlCursor::ReplenishWid()
  524. {
  525. if ( _keyHeap.IsEmpty() )
  526. {
  527. return FALSE;
  528. }
  529. Win4Assert( _keyHeap.Top()->GetKey() != 0 );
  530. Win4Assert( _keyHeap.Top()->WorkId() != widInvalid );
  531. //
  532. // Move all cursors with the lowest key to widHeap
  533. //
  534. CKeyBuf key = *_keyHeap.Top()->GetKey();
  535. do {
  536. CKeyCursor* cur = _keyHeap.RemoveTop();
  537. _widHeap.Add ( cur );
  538. } while ( !_keyHeap.IsEmpty()
  539. && AreEqual (&key, _keyHeap.Top()->GetKey()) );
  540. _iid = _widHeap.Top()->IndexId();
  541. return TRUE;
  542. }