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.

465 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: sglookup.cxx
  7. //
  8. // Contents: A class for doing a quick lookup of a segment based on the
  9. // key. It will do a binary search and locate the segment.
  10. // This is useful for doing row insertions into a large table
  11. // when keys are not coming in any specific order.
  12. //
  13. // Classes: CSegmentArrray
  14. //
  15. // History: 10-20-95 srikants Created
  16. //
  17. //----------------------------------------------------------------------------
  18. #include "pch.cxx"
  19. #pragma hdrstop
  20. #include <sglookup.hxx>
  21. #include <seglist.hxx>
  22. #include "tabledbg.hxx"
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Member: CSegmentArray consructor
  26. //
  27. // Synopsis: Initializes the segment array
  28. //
  29. // History: 10-20-95 srikants Created
  30. //
  31. //----------------------------------------------------------------------------
  32. CSegmentArray::CSegmentArray()
  33. : CDynArrayInPlace<CTableSegment *>(eMinSegments),
  34. _pComparator(0),
  35. _iHint(0)
  36. {
  37. }
  38. //+---------------------------------------------------------------------------
  39. //
  40. // Member: CSegmentArray::_FindSegment
  41. //
  42. // Synopsis: Given a segment pointer, it searches for the segment in the
  43. // array and returns the index in the array.
  44. //
  45. // Arguments: [pSeg] - Segment to look for.
  46. //
  47. // Returns: Index in the array if the segment is located.
  48. // -1 otherwise.
  49. //
  50. // History: 10-25-95 srikants Created
  51. //
  52. //----------------------------------------------------------------------------
  53. int CSegmentArray::_FindSegment( const CTableSegment * pSeg )
  54. {
  55. Win4Assert( 0 != pSeg );
  56. //
  57. // Optimization - use the last returned segment index as a hint
  58. //
  59. if ( _iHint < Count() && Get(_iHint) == pSeg )
  60. return (int) _iHint;
  61. for ( unsigned i = 0; i < Count(); i++ )
  62. {
  63. if ( Get(i) == pSeg )
  64. {
  65. _iHint = i;
  66. return (int) i;
  67. }
  68. }
  69. //
  70. // The segment could not be located.
  71. //
  72. _iHint = 0;
  73. return -1;
  74. }
  75. //+---------------------------------------------------------------------------
  76. //
  77. // Member: CSegmentArray::LookUp
  78. //
  79. // Synopsis: Looks up the segment which is likely to contain the given
  80. // key or is a candidate to insert the given key.
  81. //
  82. // Arguments: [key] - Key to look up.
  83. //
  84. // Returns: The segment pointer where to look for/insert the given key.
  85. // 0 if there are no segments
  86. //
  87. // History: 10-20-95 srikants Created
  88. //
  89. // Notes: Please note that each segment has only the "smallest" key in
  90. // that segment. We don't know anything about the highest key in
  91. // that segment. if we two adjacent segments with lowest keys
  92. // k1 and k3 and a new key if k1 < k2 < k3,
  93. // k2 will end up in segment 1
  94. //
  95. //----------------------------------------------------------------------------
  96. CTableSegment * CSegmentArray::LookUp( CTableRowKey & key )
  97. {
  98. Win4Assert( 0 != _pComparator );
  99. int cSegs = (int) Count();
  100. if ( 0 == cSegs )
  101. return 0;
  102. int iLow = 0;
  103. int iHigh = cSegs - 1;
  104. int iMid = iHigh/2;
  105. int iComp = 0;
  106. while ( iLow <= iHigh )
  107. {
  108. iMid = (iLow + iHigh)/2;
  109. CTableSegment * pCurrSeg = Get( (unsigned) iMid );
  110. iComp = _pComparator->Compare( key, pCurrSeg->GetLowestKey() );
  111. if ( 0 == iComp )
  112. return pCurrSeg;
  113. if ( iComp > 0 ) // key is bigger than the smallest key in the seg
  114. iLow = iMid+1;
  115. else // key is < the smallest key in the seg
  116. iHigh = iMid-1;
  117. }
  118. Win4Assert( iLow > iHigh );
  119. int iGet = 0;
  120. if ( iMid > iHigh )
  121. {
  122. Win4Assert( iLow == iMid );
  123. Win4Assert( iComp < 0 );
  124. iGet = iHigh >= 0 ? iHigh : 0;
  125. }
  126. else
  127. {
  128. Win4Assert( iMid == iHigh );
  129. Win4Assert( iMid < iLow && iMid < cSegs );
  130. iGet = iMid;
  131. }
  132. return Get( (unsigned) iGet );
  133. }
  134. //+---------------------------------------------------------------------------
  135. //
  136. // Member: CSegmentArray::Append
  137. //
  138. // Synopsis: Adds the given segment to the end of the array.
  139. //
  140. // Arguments: [pSeg] - Segment to be appended.
  141. //
  142. // History: 10-20-95 srikants Created
  143. //
  144. //----------------------------------------------------------------------------
  145. void CSegmentArray::Append( CTableSegment * pSeg )
  146. {
  147. Win4Assert( 0 != pSeg );
  148. Win4Assert( !IsFound(pSeg) );
  149. Add( pSeg, Count() );
  150. }
  151. //+---------------------------------------------------------------------------
  152. //
  153. // Member: CSegmentArray::InsertAfter
  154. //
  155. // Synopsis: Inserts the given segment after the marker segment
  156. //
  157. // Arguments: [pMarker] - Segment already present in the array.
  158. // [pSeg] - New segment to be inserted.
  159. //
  160. // History: 10-20-95 srikants Created
  161. //
  162. //----------------------------------------------------------------------------
  163. void CSegmentArray::InsertAfter( const CTableSegment * pMarker,
  164. CTableSegment * pSeg )
  165. {
  166. Win4Assert( 0 != pSeg );
  167. Win4Assert( !IsFound(pSeg) );
  168. Win4Assert( 0 != pMarker );
  169. int iMarker = _FindSegment( pMarker );
  170. Win4Assert( iMarker >= 0 );
  171. Insert( pSeg, (unsigned)iMarker+1 );
  172. }
  173. //+---------------------------------------------------------------------------
  174. //
  175. // Member: CSegmentArray::InsertBefore
  176. //
  177. // Synopsis: Inserts the given segment "before" the marker segment
  178. //
  179. // Arguments: [pMarker] - The segment before which the new segment must
  180. // be inserted. If NULL, the given segment will be added as
  181. // the first segment in the array.
  182. //
  183. // [pSeg] - The new segment
  184. //
  185. // History: 10-20-95 srikants Created
  186. //
  187. //----------------------------------------------------------------------------
  188. void CSegmentArray::InsertBefore( const CTableSegment * pMarker,
  189. CTableSegment * pSeg )
  190. {
  191. Win4Assert( 0 != pSeg );
  192. Win4Assert( !IsFound(pSeg) );
  193. if ( 0 != pMarker )
  194. {
  195. int iPos = _FindSegment( pMarker );
  196. Win4Assert( iPos >= 0 );
  197. Insert( pSeg, (unsigned) iPos );
  198. }
  199. else
  200. {
  201. Insert( pSeg, 0 ); // make this the first in the array
  202. }
  203. }
  204. //+---------------------------------------------------------------------------
  205. //
  206. // Member: CSegmentArray::Replace
  207. //
  208. // Synopsis: Replaces the old segment with the new segment
  209. //
  210. // Arguments: [pOld] -
  211. // [pNew] -
  212. //
  213. // History: 10-20-95 srikants Created
  214. //
  215. //----------------------------------------------------------------------------
  216. void CSegmentArray::Replace( const CTableSegment * pOld, CTableSegment * pNew )
  217. {
  218. Win4Assert( 0 != pOld && 0 != pNew );
  219. int iPos = _FindSegment( pOld );
  220. Win4Assert( iPos >= 0 );
  221. Win4Assert( !IsFound( pNew ) );
  222. Add( pNew, (unsigned) iPos );
  223. }
  224. //+---------------------------------------------------------------------------
  225. //
  226. // Member: CSegmentArray::_MoveEntries
  227. //
  228. // Synopsis: Moves entries from the specified offset by the given number
  229. // of entries..
  230. //
  231. // Arguments: [iStart] - Starting offset to move
  232. // [cEntries] - Number of entries to move by.
  233. //
  234. // History: 10-20-95 srikants Created
  235. //
  236. //----------------------------------------------------------------------------
  237. void CSegmentArray::_MoveEntries( unsigned iStart, unsigned cEntries )
  238. {
  239. Win4Assert( iStart < _count );
  240. if ( 0 == cEntries )
  241. return;
  242. Win4Assert( cEntries + _count <= Size() );
  243. unsigned iNewPos = iStart + cEntries;
  244. memmove( _aItem + iNewPos, _aItem + iStart,
  245. (_count - iStart) * sizeof(CTableSegment *) );
  246. _count += cEntries;
  247. #if CIDBG==1
  248. //
  249. // The caller can asser that the moved entries are all NULL.
  250. //
  251. for ( unsigned i = iStart; i < iNewPos; i++ )
  252. {
  253. _aItem[i] = 0;
  254. }
  255. #endif // CIDBG==1
  256. }
  257. //+---------------------------------------------------------------------------
  258. //
  259. // Member: CSegmentArray::Replace
  260. //
  261. // Synopsis: Removes "pOld" from the list and inserts the new list of
  262. // segments in its place.
  263. //
  264. // Arguments: [pOld] -
  265. // [segList] -
  266. //
  267. // History: 10-20-95 srikants Created
  268. //
  269. //----------------------------------------------------------------------------
  270. void CSegmentArray::Replace( const CTableSegment * pOld,
  271. CTableSegList & segList )
  272. {
  273. unsigned cSegsToInsert = segList.GetSegmentsCount();
  274. if ( cSegsToInsert == 0 )
  275. {
  276. RemoveEntry( pOld );
  277. return;
  278. }
  279. int iSeg = _FindSegment( pOld );
  280. Win4Assert( iSeg >= 0 );
  281. unsigned iInsert = (unsigned) iSeg;
  282. //
  283. // Replace the current segment with the first one in the list
  284. //
  285. CFwdTableSegIter iter( segList );
  286. Win4Assert ( !segList.AtEnd(iter) );
  287. _aItem[iInsert++] = iter.GetSegment();
  288. segList.Advance(iter);
  289. cSegsToInsert--;
  290. if ( !segList.AtEnd(iter) )
  291. {
  292. Win4Assert( cSegsToInsert > 0 );
  293. //
  294. // There is more than one segment to replace with. We should
  295. // iterate and move them.
  296. //
  297. unsigned cTotalSegs = _count + cSegsToInsert;
  298. //
  299. // Grow the array if necessary.
  300. //
  301. if ( (cTotalSegs-1) >= _size )
  302. _GrowToSize( cTotalSegs-1 );
  303. if ( iInsert != _count )
  304. {
  305. Win4Assert( iInsert < _count );
  306. _MoveEntries( iInsert, cSegsToInsert );
  307. }
  308. else
  309. {
  310. //
  311. // We are just appending at the end. No need to move anything
  312. //
  313. #if CIDBG==1
  314. for ( unsigned i = _count; i < cTotalSegs; i++ )
  315. {
  316. _aItem[i] = 0;
  317. }
  318. #endif // CIDBG==1
  319. _count +=cSegsToInsert;
  320. Win4Assert( _count == cTotalSegs );
  321. }
  322. for ( ; !segList.AtEnd(iter); segList.Advance(iter) )
  323. {
  324. #if CIDBG==1
  325. //
  326. // We are either appending to the end or the entries got moved
  327. // and nullified.
  328. //
  329. Win4Assert( 0 == _aItem[iInsert] );
  330. #endif // CIDBG==1
  331. Win4Assert( !IsFound(iter.GetSegment()) );
  332. _aItem[iInsert++] = iter.GetSegment();
  333. }
  334. }
  335. }
  336. //+---------------------------------------------------------------------------
  337. //
  338. // Member: CSegmentArray::RemoveEntry
  339. //
  340. // Synopsis: Removes the specified segment from the array.
  341. //
  342. // Arguments: [pSeg] -
  343. //
  344. // History: 10-20-95 srikants Created
  345. //
  346. //----------------------------------------------------------------------------
  347. void CSegmentArray::RemoveEntry( const CTableSegment * pSeg )
  348. {
  349. int iSeg = _FindSegment( pSeg );
  350. Win4Assert( iSeg >= 0 );
  351. Remove( (unsigned) iSeg );
  352. }
  353. #if CIDBG==1
  354. //+---------------------------------------------------------------------------
  355. //
  356. // Member: CSegmentArray::TestInSync
  357. //
  358. // Synopsis: Tests that the list and the array are fully in sync.
  359. //
  360. // Arguments: [list] - The global list of segments
  361. //
  362. // History: 10-25-95 srikants Created
  363. //
  364. //----------------------------------------------------------------------------
  365. void CSegmentArray::TestInSync( CTableSegList & list )
  366. {
  367. if ( Count() != list.GetSegmentsCount() )
  368. {
  369. tbDebugOut(( DEB_ERROR, "Array Count = 0x%X ListCount = 0x%X \n",
  370. Count(), list.GetSegmentsCount() ));
  371. Win4Assert( !"Array Count and List Count Not In Sync" );
  372. return;
  373. }
  374. unsigned i = 0;
  375. for ( CFwdTableSegIter iter(list); !list.AtEnd(iter); list.Advance(iter) )
  376. {
  377. if ( iter.GetSegment() != Get(i) )
  378. {
  379. tbDebugOut(( DEB_ERROR, "iter.GetSegment() = 0x%X : i = 0x%X : Array[i] = 0x%X\n",
  380. iter.GetSegment(), i, Get(i) ));
  381. Win4Assert( !"List and Array are not in sync" );
  382. }
  383. i++;
  384. }
  385. }
  386. #endif // CIDBG==1