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.

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