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.

592 lines
13 KiB

  1. //+------------------------------------------------------------------------
  2. //
  3. // File: formsary.cxx
  4. //
  5. // Contents: Generic dynamic array class
  6. //
  7. // Classes: CImplAry
  8. //
  9. //-------------------------------------------------------------------------
  10. #include <headers.hxx>
  11. // CImplAry class
  12. //+------------------------------------------------------------------------
  13. //
  14. // Member: CImplAry::~CImplAry
  15. //
  16. // Synopsis: Resizeable array destructor. Frees storage allocated for the
  17. // array.
  18. //
  19. //-------------------------------------------------------------------------
  20. CImplAry::~CImplAry( )
  21. {
  22. if (!UsingStackArray())
  23. {
  24. MemFree(PData());
  25. }
  26. }
  27. //+---------------------------------------------------------------------------
  28. //
  29. // Member: CImplAry::GetAlloced, public
  30. //
  31. // Synopsis: Returns the number of bytes that have been allocated.
  32. //
  33. // Arguments: [cb] -- Size of each element
  34. //
  35. // Notes: For the CStackAry classes the value returned is _cStack*cb if
  36. // we're still using the stack-allocated array.
  37. //
  38. //----------------------------------------------------------------------------
  39. ULONG
  40. CImplAry::GetAlloced(size_t cb)
  41. {
  42. if (UsingStackArray())
  43. {
  44. return GetStackSize() * cb;
  45. }
  46. else
  47. {
  48. return MemGetSize(PData());
  49. }
  50. }
  51. //+------------------------------------------------------------------------
  52. //
  53. // Member: CImplAry::EnsureSize
  54. //
  55. // Synopsis: Ensures that the array is at least the given size. That is,
  56. // if EnsureSize(c) succeeds, then (c-1) is a valid index. Note
  57. // that the array maintains a separate count of the number of
  58. // elements logically in the array, which is obtained with the
  59. // Size/SetSize methods. The logical size of the array is never
  60. // larger than the allocated size of the array.
  61. //
  62. // Arguments: cb Element size
  63. // c New allocated size for the array.
  64. //
  65. // Returns: HRESULT
  66. //
  67. //-------------------------------------------------------------------------
  68. HRESULT
  69. CImplAry::EnsureSize ( size_t cb, long c )
  70. {
  71. HRESULT hr = S_OK;
  72. unsigned long cbAlloc;
  73. if (UsingStackArray() && (long)(c * cb) <= (long)GetAlloced(cb))
  74. goto Cleanup;
  75. Assert( c >= 0 );
  76. cbAlloc = ((c < 8) ? c : ((c + 7) & ~7)) * cb;
  77. if (UsingStackArray() ||
  78. (((unsigned long) c > ((_c < 8) ? _c : ((_c + 7) & ~7))) && cbAlloc > MemGetSize(PData())))
  79. {
  80. Assert(!_fCheckLock && "CDataAry changing while CImplAryLock is on");
  81. if (UsingStackArray())
  82. {
  83. //
  84. // We have to switch from the stack-based array to an allocated
  85. // one, so allocate the memory and copy the data over.
  86. //
  87. void * pbDataOld = PData();
  88. int cbOld = GetAlloced( cb );
  89. PData() = MemAlloc( cbAlloc );
  90. if (!PData())
  91. {
  92. hr = E_OUTOFMEMORY;
  93. goto Cleanup;
  94. }
  95. memcpy( PData(), pbDataOld, cbOld );
  96. }
  97. else
  98. {
  99. hr = MemRealloc( (void **) & PData(), cbAlloc );
  100. if (hr)
  101. goto Cleanup;
  102. }
  103. _fDontFree = FALSE;
  104. }
  105. Cleanup:
  106. RRETURN( hr );
  107. }
  108. //+---------------------------------------------------------------------------
  109. //
  110. // Member: CImplAry::Grow, public
  111. //
  112. // Synopsis: Ensures enough memory is allocated for c elements and then
  113. // sets the size of the array to that much.
  114. //
  115. // Arguments: [cb] -- Element Size
  116. // [c] -- Number of elements to grow array to.
  117. //
  118. // Returns: HRESULT
  119. //
  120. //----------------------------------------------------------------------------
  121. HRESULT
  122. CImplAry::Grow(size_t cb, int c)
  123. {
  124. HRESULT hr = EnsureSize(cb, c);
  125. if (!hr)
  126. {
  127. SetSize(c);
  128. }
  129. RRETURN(hr);
  130. }
  131. //+------------------------------------------------------------------------
  132. //
  133. // Member: CImplAry::AppendIndirect
  134. //
  135. // Synopsis: Appends the given element to the end of the array,
  136. // incrementing the array's logical size, and growing the
  137. // array's allocated size if necessary. Note that the element
  138. // is passed with a pointer, rather than directly.
  139. //
  140. // Arguments: cb Element size
  141. // pv Pointer to the element to be appended
  142. // ppvPlaced Pointer to the element that's inside the array
  143. //
  144. // Returns: HRESULT
  145. //
  146. // Notes: If pv is NULL, the element is appended and initialized to
  147. // zero.
  148. //
  149. //-------------------------------------------------------------------------
  150. HRESULT
  151. CImplAry::AppendIndirect(size_t cb, void * pv, void ** ppvPlaced)
  152. {
  153. HRESULT hr;
  154. hr = EnsureSize(cb, _c + 1);
  155. if (hr)
  156. RRETURN(hr);
  157. if (ppvPlaced)
  158. {
  159. *ppvPlaced = Deref(cb, _c);
  160. }
  161. if (!pv)
  162. {
  163. memset(Deref(cb, _c), 0, cb);
  164. }
  165. else
  166. {
  167. memcpy(Deref(cb, _c), pv, cb);
  168. }
  169. _c++;
  170. return NOERROR;
  171. }
  172. //+------------------------------------------------------------------------
  173. //
  174. // Member: CImplAry::Delete
  175. //
  176. // Synopsis: Removes the i'th element of the array, shuffling all
  177. // elements that follow one slot towards the beginning of the
  178. // array.
  179. //
  180. // Arguments: cb Element size
  181. // i Element to delete
  182. //
  183. //-------------------------------------------------------------------------
  184. void
  185. CImplAry::Delete(size_t cb, int i)
  186. {
  187. Assert(i >= 0);
  188. Assert(i < (int)_c);
  189. Assert(!_fCheckLock && "CDataAry changing while CImplAryLock is on");
  190. memmove(((BYTE *) PData()) + (i * cb),
  191. ((BYTE *) PData()) + ((i + 1) * cb),
  192. (_c - i - 1) * cb);
  193. _c--;
  194. }
  195. //+------------------------------------------------------------------------
  196. //
  197. // Member: CImplAry::DeleteByValueIndirect
  198. //
  199. // Synopsis: Removes the element matching the given value.
  200. //
  201. // Arguments: cb Element size
  202. // pv Element to delete
  203. //
  204. // Returuns: True if found & deleted.
  205. //
  206. //-------------------------------------------------------------------------
  207. BOOL
  208. CImplAry::DeleteByValueIndirect(size_t cb, void *pv)
  209. {
  210. int i = FindIndirect(cb, pv);
  211. if (i >= 0)
  212. {
  213. Delete(cb, i);
  214. return TRUE;
  215. }
  216. else
  217. {
  218. return FALSE;
  219. }
  220. }
  221. //+------------------------------------------------------------------------
  222. //
  223. // Member: CImplAry::DeleteMultiple
  224. //
  225. // Synopsis: Removes a range of elements of the array, shuffling all
  226. // elements that follow the last element being deleted slot
  227. // towards the beginning of the array.
  228. //
  229. // Arguments: cb Element size
  230. // start First element to delete
  231. // end Last element to delete
  232. //
  233. //-------------------------------------------------------------------------
  234. void
  235. CImplAry::DeleteMultiple(size_t cb, int start, int end)
  236. {
  237. Assert((start >= 0) && (end >= 0));
  238. Assert((start < (int)_c) && (end < (int)_c));
  239. Assert(end >= start);
  240. if ((unsigned)end < (_c - 1))
  241. {
  242. memmove(((BYTE *) PData()) + (start * cb),
  243. ((BYTE *) PData()) + ((end + 1) * cb),
  244. (_c - end - 1) * cb);
  245. }
  246. _c -= (end - start) + 1;
  247. }
  248. //+------------------------------------------------------------------------
  249. //
  250. // Member: CImplAry::DeleteAll
  251. //
  252. // Synopsis: Efficient method for emptying array of any contents
  253. //
  254. //-------------------------------------------------------------------------
  255. void
  256. CImplAry::DeleteAll(void)
  257. {
  258. Assert(!_fCheckLock && "CDataAry changing while CImplAryLock is on");
  259. if (!UsingStackArray())
  260. {
  261. MemFree(PData());
  262. if (_fStack)
  263. {
  264. PData() = GetStackPtr();
  265. _fDontFree = TRUE;
  266. }
  267. else
  268. {
  269. PData() = NULL;
  270. }
  271. }
  272. _c = 0;
  273. }
  274. //+------------------------------------------------------------------------
  275. //
  276. // Member: CImplAry::InsertIndirect
  277. //
  278. // Synopsis: Inserts a pointer pv at index i. The element previously at
  279. // index i, and all elements that follow it, are shuffled one
  280. // slot away towards the end of the array.Note that the
  281. // clement is passed with a pointer, rather than directly.
  282. //
  283. // Arguments: cb Element size
  284. // i Index to insert...
  285. // pv ...this pointer at
  286. //
  287. // if pv is NULL then the element is initialized to all zero.
  288. //
  289. //-------------------------------------------------------------------------
  290. HRESULT
  291. CImplAry::InsertIndirect(size_t cb, int i, void *pv)
  292. {
  293. HRESULT hr;
  294. hr = EnsureSize(cb, _c + 1);
  295. if (hr)
  296. RRETURN(hr);
  297. memmove(((BYTE *) PData()) + ((i + 1) * cb),
  298. ((BYTE *) PData()) + (i * cb),
  299. (_c - i ) * cb);
  300. if (!pv)
  301. {
  302. memset(Deref(cb, i), 0, cb);
  303. }
  304. else
  305. {
  306. memcpy(Deref(cb, i), pv, cb);
  307. }
  308. _c++;
  309. return NOERROR;
  310. }
  311. //+---------------------------------------------------------------------------
  312. //
  313. // Member: CImplAry::FindIndirect
  314. //
  315. // Synopsis: Finds an element of a non-pointer array.
  316. //
  317. // Arguments: cb The size of the element.
  318. // pv Pointer to the element.
  319. //
  320. // Returns: The index of the element if found, otherwise -1.
  321. //
  322. //----------------------------------------------------------------------------
  323. int
  324. CImplAry::FindIndirect(size_t cb, void * pv)
  325. {
  326. int i;
  327. void * pvT;
  328. pvT = PData();
  329. for (i = _c; i > 0; i--)
  330. {
  331. if (!memcmp(pv, pvT, cb))
  332. return _c - i;
  333. pvT = (char *) pvT + cb;
  334. }
  335. return -1;
  336. }
  337. //+---------------------------------------------------------------------------
  338. //
  339. // Member: CImplAry::Copy
  340. //
  341. // Synopsis: Creates a copy from another CImplAry object.
  342. //
  343. // Arguments: ary Object to copy.
  344. // fAddRef Addref the elements on copy?
  345. //
  346. //----------------------------------------------------------------------------
  347. HRESULT
  348. CImplAry::Copy(size_t cb, const CImplAry& ary, BOOL fAddRef)
  349. {
  350. RRETURN(CopyIndirect(cb, ary._c, ((CImplAry *)&ary)->PData(), fAddRef));
  351. }
  352. //+------------------------------------------------------------------------
  353. //
  354. // Member: CImplAry::CopyIndirect
  355. //
  356. // Synopsis: Fills a forms array from a C-style array of raw data
  357. //
  358. // Arguments: [cb]
  359. // [c]
  360. // [pv]
  361. // [fAddRef]
  362. //
  363. // Returns: HRESULT
  364. //
  365. //-------------------------------------------------------------------------
  366. HRESULT
  367. CImplAry::CopyIndirect(size_t cb, int c, void * pv, BOOL fAddRef)
  368. {
  369. IUnknown ** ppUnk;
  370. if (pv == PData())
  371. return S_OK;
  372. DeleteAll();
  373. if (pv)
  374. {
  375. if (EnsureSize(cb, c))
  376. RRETURN(E_OUTOFMEMORY);
  377. memcpy(PData(), pv, c * cb);
  378. }
  379. _c = c;
  380. if (fAddRef)
  381. {
  382. for (ppUnk = (IUnknown **) PData(); c > 0; c--, ppUnk++)
  383. {
  384. (*ppUnk)->AddRef();
  385. }
  386. }
  387. return S_OK;
  388. }
  389. HRESULT
  390. CImplPtrAry::ClearAndReset()
  391. {
  392. // BUGBUG why does this function reallocate memory, rather than
  393. // just memset'ing to 0? (chrisz)
  394. // BUGBUG -- Do not use this method! Use DeleteAll to clear the array.
  395. Assert(!PData());
  396. PData() = NULL;
  397. HRESULT hr = EnsureSize(_c);
  398. _c = 0;
  399. RRETURN(hr);
  400. }
  401. //+------------------------------------------------------------------------
  402. //
  403. // Member: CImplPtrAry::*
  404. //
  405. // Synopsis: CImplPtrAry elements are always of size four.
  406. // The following functions encode this knowledge.
  407. //
  408. //-------------------------------------------------------------------------
  409. HRESULT
  410. CImplPtrAry::EnsureSize(long c)
  411. {
  412. return CImplAry::EnsureSize(sizeof(void *), c);
  413. }
  414. HRESULT
  415. CImplPtrAry::Grow(int c)
  416. {
  417. return CImplAry::Grow(sizeof(void *), c);
  418. }
  419. HRESULT
  420. CImplPtrAry::Append(void * pv)
  421. {
  422. return CImplAry::AppendIndirect(sizeof(void *), &pv);
  423. }
  424. HRESULT
  425. CImplPtrAry::Insert(int i, void * pv)
  426. {
  427. return CImplAry::InsertIndirect(sizeof(void *), i, &pv);
  428. }
  429. int
  430. CImplPtrAry::Find(void * pv)
  431. {
  432. int i;
  433. void ** ppv;
  434. for (i = 0, ppv = (void **) PData(); (unsigned)i < _c; i++, ppv++)
  435. {
  436. if (pv == *ppv)
  437. return i;
  438. }
  439. return -1;
  440. }
  441. void
  442. CImplPtrAry::Delete(int i)
  443. {
  444. CImplAry::Delete(sizeof(void *), i);
  445. }
  446. BOOL
  447. CImplPtrAry::DeleteByValue(void *pv)
  448. {
  449. int i = Find(pv);
  450. if (i >= 0)
  451. {
  452. CImplAry::Delete(sizeof(void *), i);
  453. return TRUE;
  454. }
  455. else
  456. {
  457. return FALSE;
  458. }
  459. }
  460. void
  461. CImplPtrAry::DeleteMultiple(int start, int end)
  462. {
  463. CImplAry::DeleteMultiple(sizeof(void*), start, end);
  464. }
  465. void
  466. CImplPtrAry::ReleaseAndDelete(int idx)
  467. {
  468. IUnknown * pUnk;
  469. Assert(idx < (int)_c);
  470. // grab element at idx
  471. pUnk = ((IUnknown **) PData())[idx];
  472. Delete(idx);
  473. if (pUnk)
  474. (pUnk)->Release();
  475. }
  476. void
  477. CImplPtrAry::ReleaseAll(void)
  478. {
  479. int i;
  480. IUnknown ** ppUnk;
  481. for (i = 0, ppUnk = (IUnknown **) PData(); (unsigned)i < _c; i++, ppUnk++)
  482. {
  483. if (*ppUnk)
  484. (*ppUnk)->Release();
  485. }
  486. DeleteAll();
  487. }
  488. HRESULT
  489. CImplPtrAry::CopyIndirect(int c, void * pv, BOOL fAddRef)
  490. {
  491. return CImplAry::CopyIndirect(sizeof(void *), c, pv, fAddRef);
  492. }
  493. HRESULT
  494. CImplPtrAry::Copy(const CImplAry& ary, BOOL fAddRef)
  495. {
  496. return CImplAry::Copy(sizeof(void *), ary, fAddRef);
  497. }