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.

1131 lines
33 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1992.
  5. //
  6. // File: SORT.CXX
  7. //
  8. // Contents: Key sorting
  9. //
  10. // History: 12-Jun-91 BartoszM Created
  11. // 19-Jun-91 reviewed
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <pch.cxx>
  15. #pragma hdrstop
  16. #include <entry.hxx>
  17. #include "sort.hxx"
  18. #include "compress.hxx"
  19. void CDirectory::AddEntry ( CBlock* pBlock, CKeyBuf& key )
  20. {
  21. /*
  22. ciDebugOut (( DEB_ITRACE, "directory: add %d - %.*ws\n",
  23. _counter, key.StrLen(), key.GetStr() ));
  24. */
  25. _tree.Add ( _counter, key );
  26. _blocks [_counter] = pBlock;
  27. _counter++;
  28. }
  29. //+---------------------------------------------------------------------------
  30. //
  31. // Member: CSortChunk::CSortChunk, public
  32. //
  33. // Synopsis: Copy logically sorted buffer into sort chunk
  34. // using a compressor
  35. //
  36. // Arguments: [maxOccTable] -- table of max occurrences for wids
  37. //
  38. // History: 28-May-92 KyleP Separate Single/Multiple wid compressor
  39. // 07-Jun-91 BartoszM Created
  40. //
  41. //----------------------------------------------------------------------------
  42. CSortChunk::CSortChunk( CMaxOccTable& maxOccTable )
  43. : _blocks( 0 ),
  44. _cBlocks( 0 ),
  45. _maxOccTable( maxOccTable )
  46. {
  47. }
  48. //+---------------------------------------------------------------------------
  49. //
  50. // Member: CSortChunk::Init, public
  51. //
  52. // Synopsis: 2nd-phase of construction for a CShortChunk
  53. //
  54. // Arguments: [buf] -- sorted entry buffer
  55. // [cb] -- count of bytes in buffer
  56. // [widMax] -- maximum WORKID for the word list.
  57. //
  58. // History: 28-May-92 KyleP Separate Single/Multiple wid compressor
  59. // 07-Jun-91 BartoszM Created
  60. //
  61. //----------------------------------------------------------------------------
  62. void CSortChunk::Init(
  63. const BYTE * pBuf,
  64. ULONG cb,
  65. WORKID widMax )
  66. {
  67. //ciDebugOut (( DEB_ITRACE, "copying into sort chunk\n" ));
  68. if ( cb < sizeof(int) + sizeof(WORKID) )
  69. { // buffer is too small to hold correct information
  70. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  71. }
  72. // extract necessary information from the end of the buffer
  73. const BYTE* pbEndVector = pBuf + cb - sizeof(int) - sizeof(WORKID);
  74. INT_PTR * pEndVector = (INT_PTR *)pbEndVector;
  75. int offsetVector = *(int *)(pbEndVector + sizeof(WORKID));
  76. _widSingle = *(WORKID *)(pbEndVector);
  77. INT_PTR * pVector = (INT_PTR *)(pBuf + offsetVector);
  78. int cbEntries = (int)((BYTE *)pVector - pBuf);
  79. // get count by taking size of the array of offsets, then subtracting space
  80. // for the two sentinel entries.
  81. int count = (int)(pEndVector - pVector) - 2;
  82. if ( (offsetVector < 0) || ( count < 0 ) )
  83. { // pVector is not valid
  84. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  85. }
  86. _cBlocks = 0;
  87. OCCURRENCE oldOcc = OCC_INVALID;
  88. if ( pVector[0] >= cbEntries || pVector[0] < 0 )
  89. {
  90. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  91. }
  92. CEntry * pLastEntry = (CEntry *)(pBuf + pVector[0]); // sentinel
  93. if ((pLastEntry->Pid()!=0)||
  94. (pLastEntry->Wid()!=widInvalid)||
  95. (pLastEntry->Occ()!=0)||
  96. (pLastEntry->Count()!=0))
  97. { // this is not a sentinel
  98. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  99. }
  100. if ( _widSingle == widInvalid )
  101. {
  102. CCompress compr;
  103. _blocks = compr.GetFirstBlock();
  104. for ( int i = 1; i <= count; i++ )
  105. {
  106. if ( pVector[i] >= cbEntries || pVector[i] < 0 )
  107. {
  108. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  109. }
  110. CEntry * pEntry = (CEntry *)(pBuf + pVector[i]);
  111. OCCURRENCE newOcc = pEntry->Occ();
  112. Win4Assert(pEntry->Pid()!=pidInvalid); // invalid PROPID
  113. Win4Assert(pEntry->Pid()!=pidAll);
  114. Win4Assert(pEntry->Wid()<=widMax); // invalid WORKID
  115. Win4Assert(pEntry->Wid() != 0); // invalid WORKID
  116. Win4Assert(pEntry->Wid()<=CI_MAX_DOCS_IN_WORDLIST); // invalid WORKID
  117. Win4Assert(newOcc!=OCC_INVALID); // invalid OCCURRENCE
  118. Win4Assert(pEntry->Count()<=MAXKEYSIZE); // invalid key size
  119. Win4Assert( pLastEntry->Compare( pEntry ) <= 0 ); // unsorted buffer
  120. if ((pEntry->Pid() == pidInvalid)|| // invalid PROPID
  121. (pEntry->Pid() == pidAll)||
  122. (pEntry->Wid() > widMax)|| // invalid WORKID
  123. (pEntry->Wid() > CI_MAX_DOCS_IN_WORDLIST)|| // invalid WORKID
  124. (pEntry->Wid() == 0 ) || // invalid WORKID
  125. (newOcc == OCC_INVALID)|| // invalid OCCURRENCE
  126. (pEntry->Count() > MAXKEYSIZE)|| // invalid key size
  127. (pLastEntry->Compare( pEntry ) > 0)) // unsorted buffer
  128. {
  129. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  130. }
  131. _maxOccTable.PutOcc( pEntry->Wid(), pEntry->Pid(), pEntry->Occ() );
  132. if ( !compr.SameKey ( pEntry->Count(), pEntry->GetKeyBuf() ) ||
  133. !compr.SamePid ( pEntry->Pid() ) )
  134. {
  135. compr.PutKey( pEntry->Count(),
  136. pEntry->GetKeyBuf(),
  137. pEntry->Pid() );
  138. compr.PutWid( pEntry->Wid() );
  139. }
  140. else
  141. {
  142. if ( !compr.SameWid ( pEntry->Wid() ) )
  143. {
  144. compr.PutWid ( pEntry->Wid() );
  145. }
  146. else if ( newOcc == oldOcc )
  147. {
  148. // adding exact same key twice
  149. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  150. }
  151. }
  152. compr.PutOcc( newOcc );
  153. oldOcc = newOcc;
  154. pLastEntry = pEntry;
  155. }
  156. _cBlocks = compr.KeyBlockCount();
  157. }
  158. else
  159. {
  160. if ( _widSingle > widMax )
  161. {
  162. // invalid WORKID
  163. ciDebugOut (( DEB_WARN, "_widSingle %d, widMax %d\n",
  164. _widSingle, widMax ));
  165. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  166. }
  167. COneWidCompress compr;
  168. _blocks = compr.GetFirstBlock();
  169. for ( int i = 1; i <= count; i++ )
  170. {
  171. if ( pVector[i] >= cbEntries || pVector[i] < 0 )
  172. {
  173. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  174. }
  175. CEntry * pEntry = (CEntry *)(pBuf + pVector[i]);
  176. OCCURRENCE newOcc = pEntry->Occ();
  177. if ((pEntry->Pid()==pidInvalid)|| // invalid PROPID
  178. (pEntry->Pid()==pidAll)||
  179. (newOcc==OCC_INVALID)|| // invalid OCCURRENCE
  180. (pEntry->Count()>MAXKEYSIZE)|| // invalid key size
  181. (pLastEntry->Compare(pEntry)>0)) // unsorted buffer
  182. {
  183. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  184. }
  185. _maxOccTable.PutOcc( _widSingle, pEntry->Pid(), pEntry->Occ() );
  186. if ( !compr.SameKey ( pEntry->Count(), pEntry->GetKeyBuf() ) ||
  187. !compr.SamePid ( pEntry->Pid() ) )
  188. {
  189. compr.PutKey( pEntry->Count(),
  190. pEntry->GetKeyBuf(),
  191. pEntry->Pid() );
  192. }
  193. else if ( newOcc == oldOcc )
  194. {
  195. // adding exact same key twice
  196. THROW(CException(CI_CORRUPT_FILTER_BUFFER));
  197. }
  198. compr.PutOcc( newOcc );
  199. oldOcc = newOcc;
  200. pLastEntry = pEntry;
  201. }
  202. _cBlocks = compr.KeyBlockCount();
  203. }
  204. _dir.Init ( _cBlocks );
  205. // scan blocks and add all the keys
  206. CKeyBuf keyBuf;
  207. for ( CBlock* pBlock = _blocks; pBlock != 0; pBlock = pBlock->_pNext )
  208. {
  209. if ( pBlock->_offFirstKey != offInvalid )
  210. {
  211. pBlock->GetFirstKey( keyBuf );
  212. _dir.AddEntry( pBlock, keyBuf );
  213. }
  214. }
  215. // save some memory
  216. _blocks->CompressList();
  217. _dir.Done();
  218. } //Init
  219. //+---------------------------------------------------------------------------
  220. //
  221. // Member: CSortChunk::~CSortChunk, public
  222. //
  223. // History: 12-Aug-91 BartoszM Created
  224. //
  225. //----------------------------------------------------------------------------
  226. CSortChunk::~CSortChunk ()
  227. {
  228. while ( _blocks != 0 )
  229. {
  230. CBlock * tmp = _blocks;
  231. _blocks = _blocks->_pNext;
  232. delete tmp;
  233. }
  234. }
  235. //+---------------------------------------------------------------------------
  236. //
  237. // Member: CSortChunk::QueryCursor
  238. //
  239. // Synopsis: Creates a cursor for a given key
  240. //
  241. // Arguments: [iid] -- index id
  242. // [widTable] -- wid translation table
  243. //
  244. // History: 28-May-92 KyleP Separate Single/Multiple wid compressor
  245. // 27-Sep-91 BartoszM Created
  246. //
  247. //----------------------------------------------------------------------------
  248. CChunkCursor* CSortChunk::QueryCursor (
  249. INDEXID iid,
  250. const CWidTable& widTable,
  251. WORKID widMax )
  252. {
  253. XPtr<CChunkCursor> xCur;
  254. if ( _widSingle == widInvalid )
  255. xCur.Set( new CManyWidChunkCursor ( iid, widTable, this, widMax, _maxOccTable ) );
  256. else
  257. xCur.Set( new COneWidChunkCursor( iid, widTable, _widSingle, this, widMax, _maxOccTable ) );
  258. xCur->Init();
  259. return xCur.Acquire();
  260. }
  261. //+---------------------------------------------------------------------------
  262. //
  263. // Member: CSortChunk::QueryCursor
  264. //
  265. // Synopsis: Creates a cursor for a given key
  266. //
  267. // Arguments: [iid] -- index id
  268. // [widTable] -- wid translation table
  269. // [pkey] -- key to seek
  270. //
  271. // Returns: Cursor or NULL if key not found
  272. //
  273. // History: 28-May-92 KyleP Separate Single/Multiple wid compressor
  274. // 27-Sep-91 BartoszM Created
  275. //
  276. //----------------------------------------------------------------------------
  277. CChunkCursor* CSortChunk::QueryCursor (
  278. INDEXID iid,
  279. const CWidTable& widTable,
  280. const CKey * pKeySearch,
  281. WORKID widMax )
  282. {
  283. XPtr<CChunkCursor> xCur;
  284. if ( _widSingle == widInvalid )
  285. xCur.Set( new CManyWidChunkCursor ( iid, widTable, this, widMax, _maxOccTable ) );
  286. else
  287. xCur.Set( new COneWidChunkCursor( iid, widTable, _widSingle, this, widMax, _maxOccTable ) );
  288. const CKeyBuf* pKeyFound = xCur->SeekKey ( pKeySearch );
  289. if ( !pKeyFound ||
  290. !pKeySearch->MatchPid (*pKeyFound) ||
  291. pKeySearch->CompareStr(*pKeyFound) != 0 )
  292. {
  293. xCur.Free();
  294. }
  295. return xCur.Acquire();
  296. }
  297. //+---------------------------------------------------------------------------
  298. //
  299. // Member: CSortChunk::CreateRange(), public
  300. //
  301. // Synopsis: Adds all cursors with keys between pkey and pkeyEnd to curStk.
  302. //
  303. // Arguments: [curStk] -- CKeyCurStack to add cursors to.
  304. // [pkey] -- Beginning of key range.
  305. // [pkeyEnd] -- End of key range.
  306. // [iid] -- Index id for QueryCursor.
  307. // [widTable] -- Wid Table for QueryCursor.
  308. //
  309. // History: 07-Feb-92 AmyA Created.
  310. // 14-Feb-92 AmyA Moved from CWordList.
  311. // 28-May-92 KyleP Separate Single/Multiple wid compressor
  312. //
  313. //----------------------------------------------------------------------------
  314. void CSortChunk::CreateRange(COccCurStack & curStk,
  315. const CKey * pKeyStart,
  316. const CKey * pKeyEnd,
  317. INDEXID iid,
  318. const CWidTable& widTable,
  319. WORKID widMax )
  320. {
  321. XPtr<CChunkCursor> xCursor;
  322. if ( _widSingle == widInvalid )
  323. xCursor.Set( new CManyWidChunkCursor ( iid, widTable, this, widMax, _maxOccTable ) );
  324. else
  325. xCursor.Set( new COneWidChunkCursor( iid, widTable, _widSingle, this, widMax, _maxOccTable ) );
  326. const CKeyBuf* pKeyCurrent = xCursor->SeekKey ( pKeyStart );
  327. if ( 0 == pKeyCurrent )
  328. {
  329. xCursor.Free();
  330. return;
  331. }
  332. CChunkCursor * pCursor = xCursor.Acquire();
  333. curStk.Push( pCursor );
  334. PROPID pid = pKeyStart->Pid();
  335. ciDebugOut((DEB_ITRACE, "Found key %.*ws, pid %d\n",
  336. pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pKeyCurrent->Pid()));
  337. do
  338. {
  339. if (pid != pidAll) // exact pid match
  340. {
  341. // skip wrong pids
  342. while (pid != pKeyCurrent->Pid())
  343. {
  344. #if CIDBG == 1 //------------------------------------------
  345. if (pKeyCurrent)
  346. {
  347. ciDebugOut(( DEB_ITRACE, " skip: %.*ws, pid %d, wid %d\n",
  348. pKeyCurrent->StrLen(),
  349. pKeyCurrent->GetStr(),
  350. pKeyCurrent->Pid(),
  351. pCursor->WorkId() ));
  352. }
  353. else
  354. ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
  355. #endif //--------------------------------------------------
  356. pKeyCurrent = pCursor->GetNextKey();
  357. if (pKeyCurrent == 0
  358. || pKeyEnd->CompareStr(*pKeyCurrent) < 0 )
  359. break;
  360. }
  361. // either pid matches or we have overshot
  362. // i.e. different pids and current string > end
  363. }
  364. if (pKeyCurrent == 0 || !pKeyEnd->MatchPid (*pKeyCurrent)
  365. || pKeyEnd->CompareStr (*pKeyCurrent) < 0 )
  366. {
  367. break; // <--- LOOP EXIT
  368. }
  369. if ( _widSingle == widInvalid )
  370. pCursor = new CManyWidChunkCursor( *(CManyWidChunkCursor *)pCursor );
  371. else
  372. pCursor = new COneWidChunkCursor( *(COneWidChunkCursor *)pCursor );
  373. curStk.Push(pCursor);
  374. pKeyCurrent = pCursor->GetNextKey();
  375. #if CIDBG == 1
  376. if (pKeyCurrent)
  377. {
  378. ciDebugOut((DEB_ITRACE, "Key is %.*ws\n",
  379. pKeyCurrent->StrLen(), pKeyCurrent->GetStr()));
  380. }
  381. else
  382. ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
  383. #endif // CIDBG == 1
  384. } while ( pKeyCurrent );
  385. // Since we have one more cursor in curStk than we wanted...
  386. curStk.DeleteTop();
  387. }
  388. //+---------------------------------------------------------------------------
  389. //
  390. // Member: CManyWidChunkCursor::CManyWidChunkCursor, private
  391. //
  392. // Synopsis: initialize a chunk cursor
  393. //
  394. // Arguments: [iid] -- index id
  395. // [widTable] -- wid translation table
  396. // [pChunk] -- sort chunk
  397. // [widMax] -- maximum wid
  398. // [maxOccTable] -- table of max occurrences of wids
  399. //
  400. // Notes: No seek is made! Can be used for merges,
  401. // otherwise Seek has to be called next.
  402. //
  403. // History: 22-May-91 Brianb Created
  404. // 05-Jun-91 BartoszM Rewrote it
  405. //
  406. //----------------------------------------------------------------------------
  407. CManyWidChunkCursor::CManyWidChunkCursor( INDEXID iid,
  408. const CWidTable& widTable,
  409. CSortChunk *pChunk,
  410. WORKID widMax,
  411. CMaxOccTable& maxOccTable )
  412. : CChunkCursor(iid, widMax, pChunk),
  413. _widTable( widTable ),
  414. _maxOccTable( maxOccTable )
  415. {
  416. Win4Assert ( pChunk != 0 );
  417. }
  418. void CManyWidChunkCursor::Init()
  419. {
  420. Init( _pChunk->GetBlock() );
  421. }
  422. void CManyWidChunkCursor::Init( CBlock* pBlock )
  423. {
  424. Win4Assert ( pBlock != 0 );
  425. _decomp.Init ( pBlock );
  426. const CKeyBuf *pKey = _decomp.GetKey();
  427. if ( pKey )
  428. _pid = pKey->Pid();
  429. // should try to position on a valid work id
  430. _curFakeWid = _decomp.WorkId();
  431. WORKID wid = _widTable.FakeWidToWid( _curFakeWid );
  432. Win4Assert ( _curFakeWid != widInvalid );
  433. if ( wid == widInvalid )
  434. wid = NextWorkId();
  435. if ( wid == widInvalid )
  436. GetNextKey();
  437. }
  438. //+---------------------------------------------------------------------------
  439. //
  440. // Member: CManyWidChunkCursor::SeekKey,private
  441. //
  442. // Synopsis: seek to the specified key
  443. //
  444. // Effects: positions cursor at specified key or later
  445. //
  446. // History: 22-May-91 Brianb Created
  447. // 05-Jun-91 BartoszM Rewrote it
  448. //
  449. //----------------------------------------------------------------------------
  450. const CKeyBuf * CManyWidChunkCursor::SeekKey( const CKey * pkey )
  451. {
  452. Win4Assert ( pkey != 0 );
  453. CDirectory& dir = _pChunk->GetDir();
  454. CBlock* pBlock = dir.Seek ( *pkey );
  455. Init ( pBlock );
  456. const CKeyBuf * tmpKey = _decomp.GetKey();
  457. //----------------------------------------------------
  458. // Notice: Make sure that pidAll is smaller
  459. // than any other legal PID. If the search key
  460. // has pidAll we want to be positioned at the beginning
  461. // of the range.
  462. //----------------------------------------------------
  463. Win4Assert ( pidAll == 0 );
  464. while ( tmpKey != 0 && pkey->Compare(*tmpKey) > 0 )
  465. tmpKey = GetNextKey();
  466. if ( tmpKey )
  467. {
  468. _pid = tmpKey->Pid();
  469. UpdateWeight();
  470. }
  471. return tmpKey;
  472. }
  473. //+---------------------------------------------------------------------------
  474. //
  475. // Member: CManyWidChunkCursor::GetKey, public
  476. //
  477. // Synopsis: return the current key, NULL if it doesn't exist
  478. //
  479. // Returns: current key
  480. //
  481. // History: 22-May-91 Brianb Created
  482. // 05-Jun-91 BartoszM Rewrote it
  483. //
  484. //----------------------------------------------------------------------------
  485. const CKeyBuf *CManyWidChunkCursor::GetKey()
  486. {
  487. return _decomp.GetKey();
  488. }
  489. //+---------------------------------------------------------------------------
  490. //
  491. // Member: CManyWidChunkCursor::GetNextKey, public
  492. //
  493. // Synopsis: advance to next key and return it if it exists
  494. //
  495. // Effects: changes cursor position
  496. //
  497. // Returns: next key if it exists or NULL
  498. //
  499. // History: 22-May-91 Brianb Created
  500. // 05-Jun-91 BartoszM Rewrote it
  501. //
  502. //----------------------------------------------------------------------------
  503. const CKeyBuf * CManyWidChunkCursor::GetNextKey()
  504. {
  505. const CKeyBuf* key;
  506. WORKID wid;
  507. do
  508. {
  509. key = _decomp.GetNextKey();
  510. if ( key != 0)
  511. {
  512. _curFakeWid = _decomp.WorkId();
  513. wid = _widTable.FakeWidToWid( _curFakeWid );
  514. Win4Assert( _curFakeWid != widInvalid );
  515. if ( wid == widInvalid )
  516. wid = NextWorkId();
  517. }
  518. } while ( key != 0 && wid == widInvalid );
  519. if ( key )
  520. {
  521. _pid = key->Pid();
  522. UpdateWeight();
  523. }
  524. return key;
  525. }
  526. //+---------------------------------------------------------------------------
  527. //
  528. // Member: CManyWidChunkCursor::WorkId, public
  529. //
  530. // Synopsis: return current work id under cursor
  531. //
  532. // Returns: a workid or widInvalid
  533. //
  534. // History: 22-May-91 Brianb Created
  535. // 05-Jun-91 BartoszM Rewrote it
  536. // 28-May-92 KyleP Added WorkId mapping
  537. //
  538. //----------------------------------------------------------------------------
  539. WORKID CManyWidChunkCursor::WorkId()
  540. {
  541. _curFakeWid = _decomp.WorkId();
  542. return ( _widTable.FakeWidToWid( _curFakeWid ) );
  543. }
  544. //+---------------------------------------------------------------------------
  545. //
  546. // Member: CManyWidChunkCursor::NextWorkId
  547. //
  548. // Synopsis: Advance to next workid within key and return it if it exists
  549. //
  550. // Returns: next workid or widInvalid if it doesn't exist
  551. //
  552. // History: 22-May-91 Brianb Created
  553. // 05-Jun-91 BartoszM Rewrote it
  554. // 28-May-92 KyleP Added WorkId mapping
  555. // 22-Sep-93 AmyA Added additional check for widInvalid
  556. //
  557. //----------------------------------------------------------------------------
  558. WORKID CManyWidChunkCursor::NextWorkId()
  559. {
  560. WORKID wid;
  561. do
  562. {
  563. _curFakeWid = _decomp.NextWorkId();
  564. wid = _widTable.FakeWidToWid( _curFakeWid );
  565. } while ( wid == widInvalid && _curFakeWid != widInvalid );
  566. return wid;
  567. }
  568. void CManyWidChunkCursor::RatioFinished (ULONG& denom, ULONG& num)
  569. {
  570. _decomp.RatioFinished (denom, num);
  571. }
  572. //+---------------------------------------------------------------------------
  573. //
  574. // Member: CManyWidChunkCursor::Occurrence, public
  575. //
  576. // Synopsis: return current occurrence under cursor
  577. //
  578. // Returns: occurrence or OCC_INVALID
  579. //
  580. // History: 22-May-91 Brianb Created
  581. // 05-Jun-91 BartoszM Rewrote it
  582. //
  583. //----------------------------------------------------------------------------
  584. OCCURRENCE CManyWidChunkCursor::Occurrence()
  585. {
  586. return _decomp.Occurrence();
  587. }
  588. //+---------------------------------------------------------------------------
  589. //
  590. // Member: CManyWidChunkCursor::NextOccurrence, public
  591. //
  592. // Synopsis: advance to next occurrence within current workid
  593. //
  594. // Returns: next occurrence if it exists, otherwise OCC_INVALID
  595. //
  596. // History: 22-May-91 Brianb Created
  597. // 05-Jun-91 BartoszM Rewrote it
  598. //
  599. //----------------------------------------------------------------------------
  600. OCCURRENCE CManyWidChunkCursor::NextOccurrence()
  601. {
  602. return _decomp.NextOccurrence();
  603. }
  604. //+---------------------------------------------------------------------------
  605. //
  606. // Member: CManyWidChunkCursor::MaxOccurrence, public
  607. //
  608. // Synopsis: Returns max occurrence count of current workid and pid
  609. //
  610. // History: 20-Jun-96 SitaramR Created
  611. //
  612. //----------------------------------------------------------------------------
  613. OCCURRENCE CManyWidChunkCursor::MaxOccurrence()
  614. {
  615. return _maxOccTable.GetMaxOcc( _curFakeWid, _pid );
  616. }
  617. //+---------------------------------------------------------------------------
  618. //
  619. // Member: CManyWidChunkCursor::WorkIdCount, public
  620. //
  621. // Synopsis: return wid count
  622. //
  623. // Expects: cursor positioned after key, wid heap empty
  624. //
  625. // History: 21-Jun-91 BartoszM Created
  626. //
  627. //----------------------------------------------------------------------------
  628. ULONG CManyWidChunkCursor::WorkIdCount()
  629. {
  630. return _decomp.WorkIdCount();
  631. }
  632. //+---------------------------------------------------------------------------
  633. //
  634. // Member: CManyWidChunkCursor::OccurrenceCount, public
  635. //
  636. // Synopsis: return occurrence count
  637. //
  638. // Expects: cursor positioned after work id
  639. //
  640. // History: 21-Jun-91 BartoszM Created
  641. //
  642. //----------------------------------------------------------------------------
  643. ULONG CManyWidChunkCursor::OccurrenceCount()
  644. {
  645. return _decomp.OccurrenceCount();
  646. }
  647. //+---------------------------------------------------------------------------
  648. //
  649. // Member: CManyWidChunkCursor::HitCount, public
  650. //
  651. // Synopsis: return occurrence count for current work id
  652. //
  653. // Expects: cursor positioned after work id
  654. //
  655. // History: 27-Feb-92 AmyA Created
  656. //
  657. //----------------------------------------------------------------------------
  658. ULONG CManyWidChunkCursor::HitCount()
  659. {
  660. return OccurrenceCount();
  661. }
  662. //+---------------------------------------------------------------------------
  663. //
  664. // Member: COneWidChunkCursor::COneWidChunkCursor, private
  665. //
  666. // Synopsis: initialize a chunk cursor
  667. //
  668. // Arguments: [iid] -- index id
  669. // [widTable] -- wid mapping
  670. // [wid] -- The single wid in the chunk.
  671. // [pChunk] -- sort chunk
  672. // [widMax] -- maximum wid
  673. // [maxOccTable] -- table of max occurrences of wids
  674. //
  675. // Notes: No seek is made! Can be used for merges,
  676. // otherwise Seek has to be called next.
  677. //
  678. // History: 28-May-92 KyleP Created
  679. //
  680. //----------------------------------------------------------------------------
  681. COneWidChunkCursor::COneWidChunkCursor( INDEXID iid,
  682. CWidTable const & widTable,
  683. WORKID wid,
  684. CSortChunk *pChunk,
  685. WORKID widMax,
  686. CMaxOccTable& maxOccTable )
  687. : CChunkCursor( iid, widMax, pChunk ),
  688. _wid( widTable.FakeWidToWid( wid ) ),
  689. _maxOccTable( maxOccTable ),
  690. _fakeWid( wid )
  691. {
  692. _widReal = _wid;
  693. }
  694. void COneWidChunkCursor::Init()
  695. {
  696. _decomp.Init ( _pChunk->GetBlock() );
  697. const CKeyBuf *pKey = _decomp.GetKey();
  698. if ( pKey )
  699. _pid = pKey->Pid();
  700. }
  701. //+---------------------------------------------------------------------------
  702. //
  703. // Member: COneWidChunkCursor::SeekKey,private
  704. //
  705. // Synopsis: Seek to the specified key
  706. //
  707. // Effects: positions cursor at specified key or later
  708. //
  709. // Arguments: [pkey] -- Key to seek to.
  710. //
  711. // History: 28-May-92 KyleP Created
  712. //
  713. //----------------------------------------------------------------------------
  714. const CKeyBuf * COneWidChunkCursor::SeekKey( const CKey * pkey )
  715. {
  716. if ( _widReal == widInvalid )
  717. return 0;
  718. Win4Assert ( pkey != 0 );
  719. //
  720. // Find the chunk.
  721. //
  722. CDirectory& dir = _pChunk->GetDir();
  723. CBlock* pBlock = dir.Seek ( *pkey );
  724. Win4Assert ( pBlock != 0 );
  725. //
  726. // Set up.
  727. //
  728. _decomp.Init ( pBlock );
  729. //
  730. // Go forward to the correct key.
  731. //
  732. CKeyBuf const * tmpKey;
  733. //----------------------------------------------------
  734. // Notice: Make sure that pidAll is smaller
  735. // than any other legal PID. If the search key
  736. // has pidAll we want to be positioned at the beginning
  737. // of the range.
  738. //----------------------------------------------------
  739. Win4Assert ( pidAll == 0 );
  740. for ( tmpKey = _decomp.GetKey();
  741. tmpKey != 0 && pkey->Compare(*tmpKey) > 0;
  742. tmpKey = _decomp.GetNextKey() )
  743. continue; // Null body
  744. if ( tmpKey )
  745. {
  746. _pid = tmpKey->Pid();
  747. UpdateWeight();
  748. }
  749. return tmpKey;
  750. }
  751. //+---------------------------------------------------------------------------
  752. //
  753. // Member: COneWidChunkCursor::GetKey, public
  754. //
  755. // Synopsis: return the current key, NULL if it doesn't exist
  756. //
  757. // Returns: current key
  758. //
  759. // History: 28-May-92 KyleP Created
  760. //
  761. //----------------------------------------------------------------------------
  762. const CKeyBuf *COneWidChunkCursor::GetKey()
  763. {
  764. if ( _widReal == widInvalid )
  765. return 0;
  766. return _decomp.GetKey();
  767. }
  768. //+---------------------------------------------------------------------------
  769. //
  770. // Member: COneWidChunkCursor::GetNextKey, public
  771. //
  772. // Synopsis: advance to next key and return it if it exists
  773. //
  774. // Effects: changes cursor position
  775. //
  776. // Returns: next key if it exists or NULL
  777. //
  778. // History: 28-May-92 KyleP Created
  779. // 02-Jun-92 KyleP Restore real wid
  780. //
  781. //----------------------------------------------------------------------------
  782. const CKeyBuf * COneWidChunkCursor::GetNextKey()
  783. {
  784. if ( _widReal == widInvalid )
  785. return 0;
  786. const CKeyBuf* key = _decomp.GetNextKey();
  787. if ( key )
  788. {
  789. _wid = _widReal;
  790. _pid = key->Pid();
  791. UpdateWeight();
  792. }
  793. return key;
  794. }
  795. //+---------------------------------------------------------------------------
  796. //
  797. // Member: COneWidChunkCursor::WorkId, public
  798. //
  799. // Synopsis: return current work id under cursor
  800. //
  801. // Returns: a workid or widInvalid
  802. //
  803. // History: 28-May-92 KyleP Created
  804. //
  805. //----------------------------------------------------------------------------
  806. WORKID COneWidChunkCursor::WorkId()
  807. {
  808. return( _wid );
  809. }
  810. //+---------------------------------------------------------------------------
  811. //
  812. // Member: COneWidChunkCursor::NextWorkId
  813. //
  814. // Synopsis: Advance to next workid within key and return it if it exists
  815. //
  816. // Returns: next workid or widInvalid if it doesn't exist
  817. //
  818. // History: 28-May-92 KyleP Created
  819. //
  820. //----------------------------------------------------------------------------
  821. WORKID COneWidChunkCursor::NextWorkId()
  822. {
  823. _wid = widInvalid;
  824. return( widInvalid );
  825. }
  826. void COneWidChunkCursor::RatioFinished (ULONG& denom, ULONG& num)
  827. {
  828. denom = 1;
  829. if (_wid == widInvalid)
  830. num = 1;
  831. else
  832. num = 0;
  833. }
  834. //+---------------------------------------------------------------------------
  835. //
  836. // Member: COneWidChunkCursor::WorkIdCount, public
  837. //
  838. // Returns: 1
  839. //
  840. // Expects: cursor positioned after key, wid heap empty
  841. //
  842. // History: 28-May-92 KyleP Created
  843. //
  844. //----------------------------------------------------------------------------
  845. ULONG COneWidChunkCursor::WorkIdCount()
  846. {
  847. return( 1 );
  848. }
  849. //+---------------------------------------------------------------------------
  850. //
  851. // Member: COneWidChunkCursor::Occurrence, public
  852. //
  853. // Synopsis: return current occurrence under cursor
  854. //
  855. // Returns: occurrence or OCC_INVALID
  856. //
  857. // History: 28-May-92 KyleP Created
  858. //
  859. //----------------------------------------------------------------------------
  860. OCCURRENCE COneWidChunkCursor::Occurrence()
  861. {
  862. Win4Assert( _wid != widInvalid );
  863. return _decomp.Occurrence();
  864. }
  865. //+---------------------------------------------------------------------------
  866. //
  867. // Member: COneWidChunkCursor::NextOccurrence, public
  868. //
  869. // Synopsis: advance to next occurrence within current workid
  870. //
  871. // Returns: next occurrence if it exists, otherwise OCC_INVALID
  872. //
  873. // History: 28-May-92 KyleP Created
  874. //
  875. //----------------------------------------------------------------------------
  876. OCCURRENCE COneWidChunkCursor::NextOccurrence()
  877. {
  878. Win4Assert( _wid != widInvalid );
  879. return _decomp.NextOccurrence();
  880. }
  881. //+---------------------------------------------------------------------------
  882. //
  883. // Member: COneWidChunkCursor::MaxOccurrence, public
  884. //
  885. // Synopsis: Returns max occurrence count of current workid and pid
  886. //
  887. // History: 20-Jun-96 SitaramR Created
  888. //
  889. //----------------------------------------------------------------------------
  890. OCCURRENCE COneWidChunkCursor::MaxOccurrence()
  891. {
  892. return _maxOccTable.GetMaxOcc( _fakeWid, _pid );
  893. }
  894. //+---------------------------------------------------------------------------
  895. //
  896. // Member: COneWidChunkCursor::OccurrenceCount, public
  897. //
  898. // Synopsis: return occurrence count
  899. //
  900. // Expects: cursor positioned after work id
  901. //
  902. // History: 28-May-92 KyleP Created
  903. //
  904. //----------------------------------------------------------------------------
  905. ULONG COneWidChunkCursor::OccurrenceCount()
  906. {
  907. Win4Assert( _wid != widInvalid );
  908. return _decomp.OccurrenceCount();
  909. }
  910. //+---------------------------------------------------------------------------
  911. //
  912. // Member: COneWidChunkCursor::HitCount, public
  913. //
  914. // Synopsis: return occurrence count for current work id
  915. //
  916. // Expects: cursor positioned after work id
  917. //
  918. // History: 28-May-92 KyleP Created
  919. //
  920. //----------------------------------------------------------------------------
  921. ULONG COneWidChunkCursor::HitCount()
  922. {
  923. return OccurrenceCount();
  924. }
  925. //+-------------------------------------------------------------------------
  926. //
  927. // Member: CWidTable::CWidTable, public
  928. //
  929. // Synopsis: Create a WorkId mapping table.
  930. //
  931. // History: 20-May-92 KyleP Created
  932. //
  933. //--------------------------------------------------------------------------
  934. CWidTable::CWidTable()
  935. : _count( 0 )
  936. {
  937. #if CIDBG == 1
  938. //
  939. // Initially the table will be all 0 \(illegal wid\)
  940. //
  941. memset( _table, 0, sizeof(_table) );
  942. #endif
  943. }
  944. //+-------------------------------------------------------------------------
  945. //
  946. // Member: CWidTable::WidToFakeWid, public
  947. //
  948. // Synopsis: Maps a WorkId to a table index.
  949. //
  950. // Arguments: [wid] -- WorkId to map. May already be mapped.
  951. //
  952. // Returns: The index of [wid]
  953. //
  954. // History: 20-May-92 KyleP Created
  955. //
  956. // Notes: This is clearly a non-optimal insertion algorithm but
  957. // it's called so infrequently that a more complex solution
  958. // would involve more code than it's worth.
  959. //
  960. //--------------------------------------------------------------------------
  961. WORKID CWidTable::WidToFakeWid( WORKID wid )
  962. {
  963. Win4Assert( _count <= CI_MAX_DOCS_IN_WORDLIST );
  964. for ( int iDoc = _count - 1; iDoc >= 0; iDoc-- )
  965. {
  966. if ( wid == _table[iDoc].Wid() )
  967. return( iDocToFakeWid ( iDoc ) );
  968. }
  969. WORKID fakeWid = iDocToFakeWid ( _count );
  970. _table[ _count ].SetWid( wid );
  971. _count++;
  972. return( fakeWid );
  973. }