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.

578 lines
16 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: rowindex.cxx
  7. //
  8. // Contents: Implementation of CRowIndex
  9. //
  10. // Classes: CRowIndex
  11. //
  12. // History: 23 Aug 1994 dlee Created
  13. // 30 Nov 1996 dlee Converted to use dynarrayinplace
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "pch.cxx"
  17. #pragma hdrstop
  18. #include "rowindex.hxx"
  19. #include "tabledbg.hxx"
  20. inline BOOL isOdd(ULONG x) { return 0 != (x & 1); }
  21. //+-------------------------------------------------------------------------
  22. //
  23. // Member: CRowIndex::_FindInsertionPoint, private
  24. //
  25. // Synopsis: Binary search to find insertion point for a row.
  26. // Returns one past the last row or the first row >=
  27. // to the given row
  28. //
  29. // Arguments: [Value] -- value of the row -- internally an offset
  30. //
  31. // History: 23 Aug 1994 dlee Created
  32. //
  33. //--------------------------------------------------------------------------
  34. ULONG CRowIndex::_FindInsertionPoint(
  35. TBL_OFF Value ) const
  36. {
  37. ULONG cRows = _aRows.Count();
  38. ULONG iLo = 0;
  39. ULONG iHi = cRows - 1;
  40. do
  41. {
  42. ULONG cHalf = cRows / 2;
  43. if (0 != cHalf)
  44. {
  45. ULONG iMid = isOdd(cRows) ? cHalf : (cHalf - 1);
  46. iMid += iLo;
  47. int i = _pRowCompare->Compare( Value, _aRows[iMid] );
  48. if (0 == i)
  49. {
  50. return iMid;
  51. }
  52. else if (i < 0)
  53. {
  54. iHi = iMid - 1;
  55. cRows = isOdd(cRows) ? cHalf : (cHalf - 1);
  56. }
  57. else
  58. {
  59. iLo = iMid + 1;
  60. cRows = cHalf;
  61. }
  62. }
  63. else if (0 != cRows)
  64. {
  65. int i = _pRowCompare->Compare( Value, _aRows[iLo] );
  66. if (i <= 0)
  67. return iLo;
  68. else
  69. return iLo + 1;
  70. }
  71. else return iLo;
  72. }
  73. while (TRUE);
  74. Win4Assert(! "Invalid CRowIndex::_Find function exit point");
  75. return 0;
  76. } //_FindInsertionPoint
  77. //+---------------------------------------------------------------------------
  78. //
  79. // Function: _FindRowByLinearSearch, private
  80. //
  81. // Synopsis: Given the offset of a row in the table window, this method
  82. // searches for the entry in the row index which points to that
  83. // row.
  84. //
  85. // Arguments: [oTableRow] -- Offset of the row in the table window.
  86. // [iRowIndex] -- On output, will have the index of the entry
  87. // in the row index which points to oTableRow.
  88. //
  89. // Returns: TRUE if found; FALSE o/w
  90. //
  91. // History: 11-22-94 srikants Created
  92. //
  93. // Notes: The row index is searched linearly. This must be used only
  94. // if there is no row comparator.
  95. //
  96. //----------------------------------------------------------------------------
  97. inline BOOL CRowIndex::_FindRowByLinearSearch(
  98. TBL_OFF oTableRow,
  99. ULONG & iRowIndex ) const
  100. {
  101. for ( ULONG iCurr = 0; iCurr < _aRows.Count(); iCurr++ )
  102. {
  103. if ( _aRows[iCurr] == oTableRow )
  104. {
  105. iRowIndex = iCurr;
  106. return TRUE;
  107. }
  108. }
  109. return FALSE;
  110. } // _FindRowByLinearSearch
  111. #if 0
  112. //+---------------------------------------------------------------------------
  113. //
  114. // Function: _FindRowByBinarySearch, private
  115. //
  116. // Synopsis: Using a binary search, this method locates the entry in the
  117. // row index which is same as the row indicated by oTableRow.
  118. // As duplicates are allowed, it is possible that there is more
  119. // than one entry in the row index, which will match the row in
  120. // the table window indicated by the oTableRow.
  121. //
  122. // Arguments: [oTableRow] -- Offset of the row in the table window.
  123. // [iRowIndex] -- On output, will contain the index of the entry
  124. // in the row index which has the same key as the "oTableRow"
  125. //
  126. // Returns: TRUE if found successfully. FALSE o/w
  127. //
  128. // History: 11-22-94 srikants Created
  129. //
  130. // Notes: NOT TESTED OR REVIEWED
  131. //
  132. //----------------------------------------------------------------------------
  133. inline BOOL CRowIndex::_FindRowByBinarySearch(
  134. TBL_OFF oTableRow,
  135. ULONG & iRowIndex ) const
  136. {
  137. Win4Assert( 0 != _pRowCompare );
  138. ULONG *pBase = _Base();
  139. ULONG cRows = _aRows.Count();
  140. ULONG iLo = 0;
  141. ULONG iHi = _aRows.Count() - 1;
  142. ULONG cHalf = 0;
  143. do
  144. {
  145. cHalf = cRows / 2;
  146. if (0 != cHalf)
  147. {
  148. ULONG iMid = isOdd(cRows) ? cHalf : (cHalf - 1);
  149. iMid += iLo;
  150. int i = _pRowCompare->Compare(oTableRow, pBase[iMid]);
  151. if (0 == i)
  152. {
  153. iRowIndex = iMid;
  154. return TRUE;
  155. }
  156. else if (i < 0)
  157. {
  158. iHi = iMid - 1;
  159. cRows = isOdd(cRows) ? cHalf : (cHalf - 1);
  160. }
  161. else
  162. {
  163. iLo = iMid + 1;
  164. cRows = cHalf;
  165. }
  166. }
  167. else if (0 != cRows)
  168. {
  169. Win4Assert( 1 == cRows );
  170. int i = _pRowCompare->Compare(oTableRow, pBase[iLo]);
  171. if ( 0 == i )
  172. {
  173. iRowIndex = iLo;
  174. return TRUE;
  175. }
  176. }
  177. }
  178. while ( 0 != cHalf );
  179. Win4Assert( !_FindRowByLinearSearch( oTableRow, iRowIndex ) );
  180. return FALSE;
  181. } // FindRowByBinarySearch
  182. #endif
  183. //+---------------------------------------------------------------------------
  184. //
  185. // Function: FindRow, public
  186. //
  187. // Synopsis: Given an offset of a row in the table window, this method
  188. // locates the entry in the row index, which points to the
  189. // row in the table window.
  190. //
  191. // Arguments: [oTableRow] -- (IN) The offset of the row in the table window.
  192. // [iRowIndex] -- (OUT) The index of the entry in the row index
  193. // which points to the oTableRow.
  194. //
  195. // Returns: TRUE if search successful; FALSE O/W
  196. //
  197. // History: 11-22-94 srikants Created
  198. //
  199. // Notes:
  200. //
  201. //----------------------------------------------------------------------------
  202. BOOL CRowIndex::FindRow( TBL_OFF oTableRow, ULONG &iRowIndex ) const
  203. {
  204. return _FindRowByLinearSearch( oTableRow, iRowIndex );
  205. }
  206. //+-------------------------------------------------------------------------
  207. //
  208. // Member: CRowIndex::AddRow, public
  209. //
  210. // Synopsis: Adds a row in sort order to the index
  211. //
  212. // Arguments: [Value] -- Value to insert in the index, represents a row
  213. //
  214. // Returns: Index of the newly added row
  215. //
  216. // History: 23 Aug 1994 dlee Created
  217. //
  218. //--------------------------------------------------------------------------
  219. ULONG CRowIndex::AddRow(TBL_OFF Value)
  220. {
  221. Win4Assert( 0 != _pRowCompare );
  222. ULONG cRows = _aRows.Count();
  223. // Find the insertion point for the new row.
  224. if ( 0 == cRows )
  225. {
  226. // No rows yet
  227. _aRows[0] = Value;
  228. return 0;
  229. }
  230. else if ( ( _pRowCompare->Compare( _aRows[cRows - 1], Value ) ) <= 0 )
  231. {
  232. // append a row to the end
  233. _aRows[ cRows ] = Value;
  234. return cRows;
  235. }
  236. // insert a row.
  237. ULONG iInsertionPoint = _FindInsertionPoint( Value );
  238. _aRows.Insert( Value, iInsertionPoint );
  239. return iInsertionPoint;
  240. } //AddRow
  241. //+-------------------------------------------------------------------------
  242. //
  243. // Member: CRowIndex::DeleteRow, public
  244. //
  245. // Synopsis: Deletes a row from the index and moves the following rows
  246. // up a notch in the array.
  247. //
  248. // Arguments: [iRow] -- row to be deleted
  249. //
  250. // History: 29 Aug 1994 dlee Created
  251. //
  252. //--------------------------------------------------------------------------
  253. void CRowIndex::DeleteRow(ULONG iRow)
  254. {
  255. Win4Assert( iRow < _aRows.Count() );
  256. _aRows.Remove( iRow );
  257. } //DeleteRow
  258. //+-------------------------------------------------------------------------
  259. //
  260. // Member: CRowIndex::ResortRow, public
  261. //
  262. // Synopsis: Bubbles the given row up or down based on the sort key.
  263. // Useful for when a file property is updated after being
  264. // added to the table.
  265. //
  266. // Arguments: [iRow] -- row to be resorted
  267. //
  268. // Returns: ULONG - new index of the row
  269. //
  270. // PERFFIX: should probably do a binary search, not a linear one
  271. //
  272. // History: 29 Aug 1994 dlee Created
  273. //
  274. //--------------------------------------------------------------------------
  275. ULONG CRowIndex::ResortRow(ULONG iRow)
  276. {
  277. Win4Assert(iRow < _aRows.Count());
  278. Win4Assert( 0 != _pRowCompare );
  279. // Get the start of the array of offsets
  280. TBL_OFF *pBase = _Base();
  281. Win4Assert(0 != pBase);
  282. // Bubble toward row 0
  283. while ((iRow > 0) &&
  284. (_pRowCompare->Compare(pBase[iRow], pBase[iRow - 1]) < 0))
  285. {
  286. TBL_OFF iTmp = pBase[iRow];
  287. pBase[iRow] = pBase[iRow - 1];
  288. iRow--;
  289. pBase[iRow] = iTmp;
  290. }
  291. // Bubble toward the last row
  292. while ((iRow < (_aRows.Count() - 1)) &&
  293. (_pRowCompare->Compare(pBase[iRow], pBase[iRow + 1]) > 0))
  294. {
  295. TBL_OFF iTmp = pBase[iRow];
  296. pBase[iRow] = pBase[iRow + 1];
  297. iRow++;
  298. pBase[iRow] = iTmp;
  299. }
  300. return iRow;
  301. } //ResortRow
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Member: CRowIndex::ResizeAndInit
  305. //
  306. // Synopsis: Resizes the current row index to be the same size as
  307. // specified.
  308. //
  309. // Arguments: [cNewRows] - Number of rows in the new row index.
  310. //
  311. // History: 7-31-95 srikants Created
  312. //
  313. // Notes:
  314. //
  315. //----------------------------------------------------------------------------
  316. void CRowIndex::ResizeAndInit( ULONG cNewRows )
  317. {
  318. _aRows.Clear();
  319. }
  320. //+---------------------------------------------------------------------------
  321. //
  322. // Function: SyncUp
  323. //
  324. // Synopsis: Synchronizes the permutation (rowindex contents) with that
  325. // of the new index.
  326. //
  327. // Arguments: [newIndex] -- The newIndex whose permutation must be copied
  328. // to our permutation.
  329. //
  330. // History: 11-29-94 srikants Created
  331. // 11-30-96 dlee converted to dynarrayinplace
  332. //
  333. // Notes: The implementation is optimized by doing a block copy of the
  334. // contents of the source row index. That is much faster than
  335. // adding individual entries from the source row index.
  336. //
  337. //----------------------------------------------------------------------------
  338. void CRowIndex::SyncUp( CRowIndex & newIndex )
  339. {
  340. _aRows.Duplicate( newIndex._aRows );
  341. }
  342. //+---------------------------------------------------------------------------
  343. //
  344. // Function: FindSplitPoint
  345. //
  346. // Synopsis: Given a row whose offset in the table is "oTableRow", this
  347. // method finds out the highest row in the rowIndex which is <=
  348. // "oTableRow". This method is used during a window split to
  349. // determine the split-position of a rowIndex.
  350. //
  351. // Arguments: [oTableRow] - Offset of the row to compare with.
  352. //
  353. // Returns: The first row that belongs to the RHS.
  354. //
  355. // History: 1-08-95 srikants Created
  356. //
  357. // Notes: This method is used to find a split point in the client
  358. // row index during a window split. After determining the split
  359. // point in the query row index, we have to find a point in the
  360. // client row index which will split the client row index also
  361. // in the same manner as the query row index.
  362. //
  363. //----------------------------------------------------------------------------
  364. LONG CRowIndex::FindSplitPoint( TBL_OFF oTableRow ) const
  365. {
  366. #if DBG==1
  367. // CheckSortOrder();
  368. #endif // DBG==1
  369. // Get the start of the array of offsets
  370. LONG iSplitRow = LONG_MAX;
  371. int iComp = 0;
  372. if ( 0 == _pRowCompare || 0 == _aRows.Count() )
  373. {
  374. iSplitRow = 0;
  375. }
  376. else if ( _pRowCompare->Compare( oTableRow, _aRows[0] ) < 0 )
  377. {
  378. //
  379. // The given row is < the smallest row in the row index.
  380. //
  381. iSplitRow = 0;
  382. }
  383. else if ( (iComp =
  384. _pRowCompare->Compare( oTableRow, _aRows[_aRows.Count()-1] )) >= 0 )
  385. {
  386. //
  387. // The given row is >= the biggest row in the row index.
  388. //
  389. iSplitRow = _aRows.Count();
  390. }
  391. else
  392. {
  393. ULONG oSplitRow = _FindInsertionPoint( oTableRow );
  394. Win4Assert( oSplitRow < _aRows.Count() );
  395. iSplitRow = (LONG) _aRows.Count();
  396. for ( unsigned i = oSplitRow; i < _aRows.Count(); i++ )
  397. {
  398. int iComp = _pRowCompare->Compare( oTableRow, _aRows[i] );
  399. Win4Assert( iComp <= 0 );
  400. if ( iComp < 0 )
  401. {
  402. iSplitRow = (LONG) i;
  403. break;
  404. }
  405. }
  406. }
  407. Win4Assert( LONG_MAX != iSplitRow );
  408. return iSplitRow;
  409. }
  410. //+---------------------------------------------------------------------------
  411. //
  412. // Function: FindMidSplitPoint
  413. //
  414. // Synopsis: Finds out a point in the row index which can serve as a split
  415. // point during a window split. The split point is such that
  416. // all rows in the rowindex from 0..SplitPoint are <= the row
  417. // in the SplitPoint and all rows SplitPoint+1.._aRows.Count()-1 are
  418. // > the row in the SplitPoint.
  419. //
  420. // Arguments: [riSplitPoint] - (output) The split point, if one exists.
  421. //
  422. // Returns: TRUE if a split point satisfying the above requirement is
  423. // found. FALSE o/w
  424. //
  425. // History: 1-25-95 srikants Created
  426. //
  427. // Notes: This method is used during a window split to determine a
  428. // split point in the query row index (if one exists).
  429. //
  430. //----------------------------------------------------------------------------
  431. BOOL CRowIndex::FindMidSplitPoint( ULONG & riSplitPoint ) const
  432. {
  433. #if DBG==1
  434. // CheckSortOrder();
  435. #endif // DBG==1
  436. BOOL fFound = FALSE;
  437. if ( 0 != _aRows.Count() && 0 != _pRowCompare )
  438. {
  439. ULONG oMidPoint = _aRows.Count()/2;
  440. //
  441. // Find the first row to the RHS which is > the middle row.
  442. //
  443. for ( ULONG j = oMidPoint+1; j < _aRows.Count(); j++ )
  444. {
  445. int iComp;
  446. if ( 0 != ( iComp =
  447. _pRowCompare->Compare( _aRows[oMidPoint],
  448. _aRows[j]) ) )
  449. {
  450. Win4Assert( iComp < 0 );
  451. fFound = TRUE;
  452. riSplitPoint = j-1;
  453. break;
  454. }
  455. }
  456. if ( !fFound )
  457. {
  458. //
  459. // All rows to the right of oMidPoint are equal. We should now
  460. // try the LHS.
  461. //
  462. for ( int i = (int) oMidPoint-1; i >= 0; i-- )
  463. {
  464. int iComp;
  465. if ( 0 != (iComp = _pRowCompare->Compare( _aRows[i], _aRows[oMidPoint] )) )
  466. {
  467. Win4Assert( iComp < 0 );
  468. fFound = TRUE;
  469. riSplitPoint = (ULONG) i;
  470. break;
  471. }
  472. }
  473. }
  474. //
  475. // PERFFIX - this algorithm can be modified to find the split point
  476. // which is as close to the mid point as possible. That would mean
  477. // looking the LHS even if we find a split point in the RHS and the
  478. // split point != the oMidPoint. That will involve more comparisons.
  479. //
  480. }
  481. return fFound;
  482. }
  483. #if CIDBG==1 || DBG==1
  484. void CRowIndex::CheckSortOrder() const
  485. {
  486. if ( _aRows.Count() <= 1 || 0 == _pRowCompare )
  487. {
  488. return;
  489. }
  490. for ( unsigned i = 0; i < _aRows.Count()-1 ; i++ )
  491. {
  492. int iComp = _pRowCompare->Compare( _aRows[i], _aRows[i+1] );
  493. Win4Assert( iComp <= 0 );
  494. }
  495. }
  496. #endif // CIDBG==1 || DBG==1