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.

306 lines
6.7 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module ARRAY.C -- Generic Array Implementation |
  5. *
  6. * Original Author: <nl>
  7. * Christian Fortini
  8. *
  9. * History: <nl>
  10. * 6/25/95 alexgo Cleanup and Commented
  11. *
  12. * Copyright (c) 1995-1997, Microsoft Corporation. All rights reserved.
  13. */
  14. #include "_common.h"
  15. #include "_array.h"
  16. ASSERTDATA
  17. const int celGrow = 8;
  18. //
  19. // Invariant support
  20. //
  21. #define DEBUG_CLASSNAME CArrayBase
  22. #include "_invar.h"
  23. // =================================== CArrayBase ================================================
  24. #ifdef DEBUG
  25. /*
  26. * CArrayBase::Invariant()
  27. *
  28. * @mfunc Tests the array state to make sure it is valid. DEBUG only
  29. *
  30. * @rdesc TRUE if the tests succeed, FALSE otherwise
  31. */
  32. BOOL CArrayBase::Invariant() const
  33. {
  34. Assert(_cbElem > 0);
  35. if(!_prgel)
  36. {
  37. Assert(_cel == 0);
  38. Assert(_celMax == 0);
  39. // We go ahead and return a value here so that
  40. // this function can be executed in the "watch"
  41. // window of various debuggers
  42. if(_cel || _celMax)
  43. return FALSE;
  44. }
  45. else
  46. {
  47. Assert(_celMax > 0 );
  48. Assert(_cel <= _celMax);
  49. if(_celMax == 0 || _cel > _celMax)
  50. return FALSE;
  51. }
  52. return TRUE;
  53. }
  54. /*
  55. * CArrayBase::Elem(iel)
  56. *
  57. * @mfunc Returns a pointer to the element indexed by <p iel>
  58. *
  59. * @rdesc A pointer to the element indexed by <p iel>. This pointer may
  60. * be cast to a pointer of the appropriate element type.
  61. */
  62. void* CArrayBase::Elem(
  63. LONG iel) const //@parm Index to use
  64. {
  65. _TEST_INVARIANT_
  66. // This can arise with empty froms^3 controls.
  67. // Review (keithcu) Why did this start happening in Richedit 3?
  68. if (!_cel)
  69. return NULL;
  70. AssertSz(iel == 0 || (iel > 0 && iel < _cel),
  71. "CArrayBase::Elem() - Index out of range");
  72. return _prgel + iel * _cbElem;
  73. }
  74. #endif
  75. /*
  76. * CArrayBase::CArrayBase
  77. *
  78. * @mfunc Constructor
  79. */
  80. CArrayBase::CArrayBase(
  81. LONG cbElem) //@parm Size of an individual array element
  82. {
  83. _prgel = NULL;
  84. _cel = 0;
  85. _celMax = 0;
  86. _cbElem = cbElem;
  87. }
  88. /*
  89. * CArrayBase::ArAdd
  90. *
  91. * @mfunc Adds <p celAdd> elements to the end of the array.
  92. *
  93. * @rdesc A pointer to the start of the new elements added. If non-NULL,
  94. * <p pielIns> will be set to the index at which elements were added.
  95. *
  96. * We grow in steps of celGrow when small and exponentially when large.
  97. */
  98. void* CArrayBase::ArAdd(
  99. LONG celAdd, //@parm Count of elements to add
  100. LONG *pielIns) //@parm Out parm for index of first element added
  101. {
  102. _TEST_INVARIANT_
  103. char *pel;
  104. if(_cel + celAdd > _celMax) // need to grow
  105. {
  106. LONG celNew = max(celAdd, celGrow) + _cel / 16;
  107. pel = (char*)PvReAlloc(_prgel, (_celMax + celNew) * _cbElem);
  108. if(!pel)
  109. return NULL;
  110. _prgel = pel;
  111. _celMax += celNew;
  112. }
  113. pel = _prgel + _cel * _cbElem;
  114. ZeroMemory(pel, celAdd * _cbElem);
  115. if(pielIns)
  116. *pielIns = _cel;
  117. _cel += celAdd;
  118. return pel;
  119. }
  120. /*
  121. * CArrayBase::ArInsert (iel, celIns)
  122. *
  123. * @mfunc Inserts <p celIns> new elements at index <p iel>
  124. *
  125. * @rdesc A pointer to the newly inserted elements. Will be NULL on
  126. * failure.
  127. */
  128. void* CArrayBase::ArInsert(
  129. LONG iel, //@parm Index at which to insert
  130. LONG celIns) //@parm Count of elements to insert
  131. {
  132. char *pel;
  133. _TEST_INVARIANT_
  134. AssertSz(iel <= _cel, "CArrayBase::Insert() - Insert out of range");
  135. if(iel >= _cel)
  136. return ArAdd(celIns, NULL);
  137. if(_cel + celIns > _celMax) // need to grow
  138. {
  139. AssertSz(_prgel, "CArrayBase::Insert() - Growing a non existent array !");
  140. LONG celNew = max(celIns, celGrow) + _cel / 16;
  141. pel = (char*)PvReAlloc(_prgel, (_celMax + celNew) * _cbElem);
  142. if(!pel)
  143. {
  144. TRACEERRORSZ("CArrayBase::Insert() - Couldn't realloc line array");
  145. return NULL;
  146. }
  147. _prgel = pel;
  148. _celMax += celNew;
  149. }
  150. pel = _prgel + iel * _cbElem;
  151. if(iel < _cel) // Nove Elems up to make room for new ones
  152. MoveMemory(pel + celIns*_cbElem, pel, (_cel - iel)*_cbElem);
  153. _cel += celIns;
  154. return pel;
  155. }
  156. /*
  157. * CArrayBase::Remove
  158. *
  159. * @mfunc Removes the <p celFree> elements from the array starting at index
  160. * <p ielFirst>. If <p celFree> is negative, then all elements after
  161. * <p ielFirst> are removed.
  162. *
  163. * @rdesc nothing
  164. */
  165. void CArrayBase::Remove(
  166. LONG ielFirst, //@parm Index at which elements should be removed
  167. LONG celFree) //@parm Count of elements to remove.
  168. {
  169. char *pel;
  170. _TEST_INVARIANT_
  171. if(celFree < 0)
  172. celFree = _cel - ielFirst;
  173. AssertSz(ielFirst + celFree <= _cel, "CArrayBase::Free() - Freeing out of range");
  174. if(_cel > ielFirst + celFree)
  175. {
  176. pel = _prgel + ielFirst * _cbElem;
  177. MoveMemory(pel, pel + celFree * _cbElem,
  178. (_cel - ielFirst - celFree) * _cbElem);
  179. }
  180. _cel -= celFree;
  181. if(_cel < _celMax - celGrow - _cel / 16)
  182. {
  183. // Shrink array
  184. _celMax = max(_cel, celGrow);
  185. _prgel = (char*)PvReAlloc(_prgel, _celMax * _cbElem);
  186. Assert(_prgel);
  187. }
  188. }
  189. /*
  190. * CArrayBase::Clear
  191. *
  192. * @mfunc Clears the entire array, potentially deleting all of the memory
  193. * as well.
  194. *
  195. * @rdesc nothing
  196. */
  197. void CArrayBase::Clear(
  198. ArrayFlag flag) //@parm Indicates what should be done with the memory
  199. //in the array. One of AF_DELETEMEM or AF_KEEPMEM
  200. {
  201. _TEST_INVARIANT_
  202. if( flag == AF_DELETEMEM )
  203. {
  204. FreePv(_prgel);
  205. _prgel = NULL;
  206. _celMax = 0;
  207. }
  208. else if (_prgel)
  209. {
  210. _celMax = min(celGrow, _celMax);
  211. _prgel = (char*) PvReAlloc(_prgel, celGrow * _cbElem);
  212. }
  213. _cel = 0;
  214. }
  215. /*
  216. * CArrayBase::Replace
  217. *
  218. * @mfunc Replaces the <p celRepl> elements at index <p ielRepl> with the
  219. * contents of the array specified by <p par>. If <p celRepl> is negative,
  220. * then the entire contents of <p this> array starting at <p ielRepl> should
  221. * be replaced.
  222. *
  223. * @rdesc Returns TRUE on success, FALSE otherwise.
  224. */
  225. BOOL CArrayBase::Replace(
  226. LONG ielRepl, //@parm index at which replacement should occur
  227. LONG celRepl, //@parm number of elements to replace (may be
  228. // negative, indicating that all
  229. CArrayBase *par) //@parm array to use as the replacement source
  230. {
  231. _TEST_INVARIANT_
  232. LONG celMove = 0;
  233. LONG celIns = par->Count();
  234. if (celRepl < 0)
  235. celRepl = _cel - ielRepl;
  236. AssertSz(ielRepl + celRepl <= _cel, "CArrayBase::ArReplace() - Replacing out of range");
  237. celMove = min(celRepl, celIns);
  238. if (celMove > 0)
  239. {
  240. MoveMemory(Elem(ielRepl), par->Elem(0), celMove * _cbElem);
  241. celIns -= celMove;
  242. celRepl -= celMove;
  243. ielRepl += celMove;
  244. }
  245. Assert(celIns >= 0);
  246. Assert(celRepl >= 0);
  247. Assert(celIns + celMove == par->Count());
  248. if(celIns > 0)
  249. {
  250. Assert(celRepl == 0);
  251. void *pelIns = ArInsert (ielRepl, celIns);
  252. if (!pelIns)
  253. return FALSE;
  254. MoveMemory(pelIns, par->Elem(celMove), celIns * _cbElem);
  255. }
  256. else if(celRepl > 0)
  257. Remove (ielRepl, celRepl);
  258. return TRUE;
  259. }