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.

230 lines
5.8 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1994.
  5. //
  6. // File: tblrowal.cxx
  7. //
  8. // Contents: The CTableRowAlloc class, used in allocation
  9. // of table row data and checking of column bindings.
  10. //
  11. // Classes: CTableRowAlloc
  12. //
  13. // History: 27 Jun 1994 Alanw Created
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "pch.cxx"
  17. #pragma hdrstop
  18. #include <tblrowal.hxx>
  19. #include "tabledbg.hxx"
  20. //+-------------------------------------------------------------------------
  21. //
  22. // Member: CTableRowAlloc::CTableRowAlloc, public
  23. //
  24. // Synopsis: Constructor for a row field allocator. Initializes
  25. // max. width and other members.
  26. //
  27. // Arguments: [cbRow] - maximum size of the row. Can be zero if the
  28. // row is to grow dynamically via the AllocOffset
  29. // method.
  30. //
  31. // Notes:
  32. //
  33. //+-------------------------------------------------------------------------
  34. CTableRowAlloc::CTableRowAlloc(unsigned cbRow) :
  35. _maxRow( (USHORT)cbRow ),
  36. _cbRow( sizeof(_aRowMap) ),
  37. _iFirstFree(0)
  38. {
  39. RtlZeroMemory( _aRowMap, sizeof(_aRowMap) );
  40. _pRowMap = _aRowMap;
  41. }
  42. //+---------------------------------------------------------------------------
  43. //
  44. // Member: CTableRowAlloc::_IsLikelyFree
  45. //
  46. // Synopsis: Quickly checks to see if the given offset is likely to be
  47. // free.
  48. //
  49. // Arguments: [iOffset] - Offset to test
  50. // [cbData] - Length of the data needed.
  51. //
  52. // Returns: TRUE if that location is likely to be free.
  53. // FALSE if it is guaranteed not to be a free candidate.
  54. //
  55. // History: 5-03-96 srikants Created
  56. //
  57. // Notes: This is a quick check to see if the location is likely to
  58. // be free. Does not guarantee that it is free.
  59. //
  60. //----------------------------------------------------------------------------
  61. inline BOOL CTableRowAlloc::_IsLikelyFree( unsigned iOffset, unsigned cbData )
  62. {
  63. if ( iOffset < _cbRow && _pRowMap[iOffset] != 0 )
  64. return FALSE;
  65. if (iOffset + cbData > _maxRow)
  66. return FALSE;
  67. return TRUE;
  68. }
  69. inline unsigned AlignedOffset( unsigned offset, unsigned cbAlign )
  70. {
  71. Win4Assert( ( cbAlign & (cbAlign-1) ) == 0 );
  72. return (offset + cbAlign-1) & ~(cbAlign-1);
  73. }
  74. //+-------------------------------------------------------------------------
  75. //
  76. // Member: CTableRowAlloc::AllocOffset, public
  77. //
  78. // Synopsis: Allocate a row field. Return the offset in the row.
  79. //
  80. // Arguments: [cbData] - size of data field
  81. // [cbAlign] - required alignment of field (may be zero
  82. // if no alignment requirement)
  83. // [fGrow] - TRUE if row can be grown
  84. //
  85. // Returns: USHORT - offset of allocted field. 0xFFFF if failed.
  86. //
  87. // Notes:
  88. //
  89. //+-------------------------------------------------------------------------
  90. USHORT CTableRowAlloc::AllocOffset(
  91. unsigned cbData,
  92. unsigned cbAlign,
  93. BOOL fGrow
  94. ) {
  95. Win4Assert(cbAlign <= 16);
  96. if (cbAlign == 0)
  97. cbAlign = 1;
  98. USHORT usSavedMax = _maxRow;
  99. for ( unsigned i = AlignedOffset(_iFirstFree,cbAlign);
  100. i < _cbRow;
  101. i += cbAlign)
  102. {
  103. if (fGrow && (i + cbData) > _maxRow)
  104. SetRowWidth(i + cbData);
  105. if ( _IsLikelyFree(i, cbData) && ReserveRowSpace( i, cbData )) {
  106. return (USHORT)i;
  107. }
  108. }
  109. if (fGrow)
  110. {
  111. SetRowWidth(i + cbData);
  112. if (ReserveRowSpace( i, cbData )) {
  113. return (USHORT)i;
  114. }
  115. SetRowWidth(usSavedMax);
  116. }
  117. return 0xFFFF;
  118. }
  119. //+-------------------------------------------------------------------------
  120. //
  121. // Member: CTableRowAlloc::ReserveRowSpace, public
  122. //
  123. // Synopsis: Reserve a row field in the allocation map.
  124. //
  125. // Arguments: [iOffset] - offset of field in row
  126. // [cbData] - size of data field
  127. //
  128. // Returns: BOOL - TRUE if field could be reserved, FALSE otherwise
  129. //
  130. // Notes:
  131. //
  132. //+-------------------------------------------------------------------------
  133. BOOL CTableRowAlloc::ReserveRowSpace(
  134. unsigned iOffset,
  135. unsigned cbData
  136. ) {
  137. Win4Assert(cbData > 0);
  138. if (iOffset + cbData > _maxRow) {
  139. return FALSE;
  140. }
  141. if (iOffset + cbData >= _cbRow) {
  142. //
  143. // Before growing the array, check to see if the reservation
  144. // would fail anyway.
  145. //
  146. if (iOffset < _cbRow && _pRowMap[ iOffset ] != 0)
  147. {
  148. return FALSE;
  149. }
  150. //
  151. // Need to allocate more space for the row map
  152. //
  153. unsigned cbNew = iOffset + max( cbData, CB_INIT );
  154. BYTE* pNewMap = new BYTE [cbNew];
  155. Win4Assert( _cbRow > 0 );
  156. RtlCopyMemory(pNewMap, _pRowMap, _cbRow);
  157. RtlZeroMemory((void *)&pNewMap[_cbRow], cbNew - _cbRow);
  158. if ( _pRowMap != _aRowMap )
  159. delete [] _pRowMap;
  160. _pRowMap = pNewMap;
  161. _cbRow = (USHORT)cbNew;
  162. }
  163. //
  164. // Check if any byte in the field has already been reserved.
  165. //
  166. for (unsigned i = 0; i < cbData; i++) {
  167. if (_pRowMap[ iOffset + i ] != 0) {
  168. return FALSE;
  169. }
  170. }
  171. //
  172. // Reserve the requested field
  173. //
  174. for (i = 0; i < cbData; i++) {
  175. _pRowMap[ iOffset + i ] = 1;
  176. }
  177. //
  178. // Update the _iFirstFree if appropriate.
  179. //
  180. Win4Assert( _iFirstFree <= _cbRow );
  181. if ( _iFirstFree == iOffset )
  182. {
  183. //
  184. // Find the next free location
  185. //
  186. Win4Assert( i+iOffset == _iFirstFree+cbData );
  187. Win4Assert( i == cbData );
  188. for ( i += iOffset; i < _cbRow; i++ )
  189. {
  190. if ( !_IsInUse(i) )
  191. break;
  192. }
  193. _iFirstFree = i;
  194. }
  195. return TRUE;
  196. }