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.

531 lines
16 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: DynamicArray.cpp
  3. //
  4. // Copyright (c) 1999-2000, Microsoft Corporation
  5. //
  6. // This file contains related classes to manage dynamic arrays. The array is
  7. // grown as required but never shrunk. The base class handles struct arrays.
  8. // Subclasses handle special cases of these arrays (such as pointer or
  9. // CCountedObject arrays).
  10. //
  11. // History: 1999-11-16 vtan created
  12. // 2000-02-01 vtan moved from Neptune to Whistler
  13. // --------------------------------------------------------------------------
  14. #include "StandardHeader.h"
  15. #include "DynamicArray.h"
  16. #include "CountedObject.h"
  17. // --------------------------------------------------------------------------
  18. // CDynamicArray::CDynamicArray
  19. //
  20. // Arguments: iElementSize = Size of each array element.
  21. //
  22. // Returns: <none>
  23. //
  24. // Purpose: Constructor for CDynamicArray. Stores the element size and
  25. // initializes the memory used to NULL.
  26. //
  27. // History: 1999-11-16 vtan created
  28. // --------------------------------------------------------------------------
  29. CDynamicArray::CDynamicArray (int iElementSize) :
  30. _iElementSize(iElementSize),
  31. _iArraySize(0),
  32. _pvArray(NULL)
  33. {
  34. ASSERTMSG(iElementSize > 0, "Cannot have negative or zero length element size in CDynamicArray::CDynamicArray");
  35. }
  36. // --------------------------------------------------------------------------
  37. // CDynamicArray::~CDynamicArray
  38. //
  39. // Arguments: <none>
  40. //
  41. // Returns: <none>
  42. //
  43. // Purpose: Destructor for CDynamicArray. Frees the memory used by the
  44. // array.
  45. //
  46. // History: 1999-11-16 vtan created
  47. // --------------------------------------------------------------------------
  48. CDynamicArray::~CDynamicArray (void)
  49. {
  50. ReleaseMemory(_pvArray);
  51. }
  52. // --------------------------------------------------------------------------
  53. // CDynamicArray::Add
  54. //
  55. // Arguments: pvData = Pointer to the data to copy to the array.
  56. //
  57. // Returns: NTSTATUS
  58. //
  59. // Purpose: Allocates memory for the element to be added to the array. If
  60. // there is no memory block it allocates an initial block. If
  61. // there isn't enough memory in the block to hold the next
  62. // element then it allocates a new larger block.
  63. //
  64. // History: 1999-11-16 vtan created
  65. // --------------------------------------------------------------------------
  66. NTSTATUS CDynamicArray::Add (const void *pvData)
  67. {
  68. NTSTATUS status;
  69. static const int DEFAULT_ELEMENTS_PER_ALLOCATE = 16;
  70. status = STATUS_NO_MEMORY;
  71. // If no array exists then allocate the first
  72. // block of memory for this array.
  73. if (_pvArray == NULL)
  74. {
  75. _iArraySize = 0;
  76. _iArrayAllocatedSize = DEFAULT_ELEMENTS_PER_ALLOCATE;
  77. _pvArray = LocalAlloc(LPTR, _iElementSize * _iArrayAllocatedSize);
  78. }
  79. // If the array exists but the limit of the allocated size has
  80. // been reached then allocate a new block, copy the current
  81. // block contents and fall thru.
  82. if (_pvArray != NULL)
  83. {
  84. if (_iArraySize == _iArrayAllocatedSize)
  85. {
  86. void *pvNewArray;
  87. pvNewArray = LocalAlloc(LPTR, _iElementSize * (_iArrayAllocatedSize + DEFAULT_ELEMENTS_PER_ALLOCATE));
  88. if (pvNewArray != NULL)
  89. {
  90. _iArrayAllocatedSize += DEFAULT_ELEMENTS_PER_ALLOCATE;
  91. CopyMemory(pvNewArray, _pvArray, _iElementSize * _iArraySize);
  92. _pvArray = pvNewArray;
  93. }
  94. }
  95. // Otherwise there is a spare slot in the array. Copy the
  96. // data to the array. Increment the array size.
  97. if (_iArraySize < _iArrayAllocatedSize)
  98. {
  99. CopyMemory(static_cast<char*>(_pvArray) + (_iElementSize * _iArraySize), pvData, _iElementSize);
  100. ++_iArraySize;
  101. status = STATUS_SUCCESS;
  102. }
  103. }
  104. return(status);
  105. }
  106. // --------------------------------------------------------------------------
  107. // CDynamicArray::Remove
  108. //
  109. // Arguments: iElementIndex = Index of the element to remove.
  110. //
  111. // Returns: NTSTATUS
  112. //
  113. // Purpose: Removes the element from the array. Slides down all the
  114. // members but does not reduce the size of the memory block used
  115. // by the array.
  116. //
  117. // History: 1999-11-16 vtan created
  118. // --------------------------------------------------------------------------
  119. NTSTATUS CDynamicArray::Remove (int iElementIndex)
  120. {
  121. NTSTATUS status;
  122. status = STATUS_SUCCESS;
  123. if (_pvArray != NULL)
  124. {
  125. // Make sure the index is valid.
  126. if (iElementIndex < _iArraySize)
  127. {
  128. int iMoveSize;
  129. // Determine the amount of bytes to move when deleting this
  130. // element and move the memory. Don't resize the array when
  131. // shrinking. Just leave it alone.
  132. iMoveSize = _iElementSize * (_iArraySize - iElementIndex - 1);
  133. ASSERTMSG(iMoveSize >= 0, "Negative move memory size in CDynamicArray::Remove");
  134. if (iMoveSize > 0)
  135. {
  136. MoveMemory(static_cast<char*>(_pvArray) + (_iElementSize * iElementIndex), static_cast<char*>(_pvArray) + (_iElementSize * (iElementIndex + 1)), iMoveSize);
  137. }
  138. ZeroMemory(static_cast<char*>(_pvArray) + (_iElementSize * (_iArraySize - 1)), _iElementSize);
  139. --_iArraySize;
  140. }
  141. else
  142. {
  143. status = STATUS_INVALID_PARAMETER;
  144. }
  145. }
  146. return(status);
  147. }
  148. // --------------------------------------------------------------------------
  149. // CDynamicArray::GetCount
  150. //
  151. // Arguments: <none>
  152. //
  153. // Returns: int
  154. //
  155. // Purpose: Returns the number of elements in the array.
  156. //
  157. // History: 1999-11-16 vtan created
  158. // --------------------------------------------------------------------------
  159. int CDynamicArray::GetCount (void) const
  160. {
  161. return(_iArraySize);
  162. }
  163. // --------------------------------------------------------------------------
  164. // CDynamicArray::Get
  165. //
  166. // Arguments: pvData = Pointer to memory to receive element.
  167. // iElementIndex = Index of element to retrieve in array.
  168. //
  169. // Returns: NTSTATUS
  170. //
  171. // Purpose: Copies the data for the specified element by index to the
  172. // block of memory given. No checks for access violations.
  173. //
  174. // History: 1999-11-16 vtan created
  175. // --------------------------------------------------------------------------
  176. NTSTATUS CDynamicArray::Get (void *pvData, int iElementIndex)
  177. {
  178. NTSTATUS status;
  179. if ((_pvArray != NULL) && (iElementIndex < _iArraySize))
  180. {
  181. CopyMemory(pvData, static_cast<char*>(_pvArray) + (_iElementSize * iElementIndex), _iElementSize);
  182. status = STATUS_SUCCESS;
  183. }
  184. else
  185. {
  186. status = STATUS_INVALID_PARAMETER;
  187. }
  188. return(status);
  189. }
  190. // --------------------------------------------------------------------------
  191. // CDynamicArray::Set
  192. //
  193. // Arguments: pvData = Pointer to memory to receive element.
  194. // iElementIndex = Index of element to retrieve in array.
  195. //
  196. // Returns: NTSTATUS
  197. //
  198. // Purpose: Copies the data for the specified element by index from the
  199. // block of memory given. No checks for access violations.
  200. //
  201. // History: 2000-11-11 vtan created
  202. // --------------------------------------------------------------------------
  203. NTSTATUS CDynamicArray::Set (const void* pvData, int iElementIndex)
  204. {
  205. NTSTATUS status;
  206. status = STATUS_SUCCESS;
  207. if (_pvArray != NULL)
  208. {
  209. if (iElementIndex < _iArraySize)
  210. {
  211. CopyMemory(static_cast<char*>(_pvArray) + (_iElementSize * iElementIndex), pvData, _iElementSize);
  212. }
  213. else
  214. {
  215. status = STATUS_INVALID_PARAMETER;
  216. }
  217. }
  218. return(status);
  219. }
  220. // --------------------------------------------------------------------------
  221. // CDynamicArray::Iterate
  222. //
  223. // Arguments: pDynamicArrayCallback = Interface containing callback.
  224. //
  225. // Returns: NTSTATUS
  226. //
  227. // Purpose: Iterate the elements of the array. Call the callback function
  228. // specified in the interface and give it a pointer to the
  229. // element and the index. Adhere to the NTSTATUS returned from
  230. // the callback and terminate on an unsuccessful result.
  231. //
  232. // History: 1999-11-16 vtan created
  233. // --------------------------------------------------------------------------
  234. NTSTATUS CDynamicArray::Iterate (CDynamicArrayCallback *pDynamicArrayCallback)
  235. {
  236. NTSTATUS status;
  237. status = STATUS_SUCCESS;
  238. if (_pvArray != NULL)
  239. {
  240. int i;
  241. for (i = _iArraySize - 1; NT_SUCCESS(status) && (i >= 0); --i)
  242. {
  243. status = pDynamicArrayCallback->Callback(static_cast<char*>(_pvArray) + (_iElementSize * i), i);
  244. }
  245. }
  246. return(status);
  247. }
  248. // --------------------------------------------------------------------------
  249. // CDynamicPointerArray::CDynamicPointerArray
  250. //
  251. // Arguments: <none>
  252. //
  253. // Returns: <none>
  254. //
  255. // Purpose: Constructor for CDynamicPointerArray. All elements of this
  256. // class are pointers that are allocated with LocalAlloc.
  257. //
  258. // History: 1999-11-16 vtan created
  259. // --------------------------------------------------------------------------
  260. CDynamicPointerArray::CDynamicPointerArray (void) :
  261. CDynamicArray(sizeof(void*))
  262. {
  263. }
  264. // --------------------------------------------------------------------------
  265. // CDynamicPointerArray::~CDynamicPointerArray
  266. //
  267. // Arguments: <none>
  268. //
  269. // Returns: <none>
  270. //
  271. // Purpose: Destructor for CDynamicPointerArray. Walk the entire array
  272. // and free each pointer in the array before allowing the base
  273. // class destructor to release the memory allocated for the
  274. // actual array itself.
  275. //
  276. // History: 1999-11-16 vtan created
  277. // --------------------------------------------------------------------------
  278. CDynamicPointerArray::~CDynamicPointerArray (void)
  279. {
  280. if (_pvArray != NULL)
  281. {
  282. int i;
  283. for (i = _iArraySize - 1; i >= 0; --i)
  284. {
  285. ReleaseMemory(static_cast<void**>(_pvArray)[i]);
  286. }
  287. }
  288. }
  289. // --------------------------------------------------------------------------
  290. // CDynamicPointerArray::Add
  291. //
  292. // Arguments: pvData = Pointer to add to the array.
  293. //
  294. // Returns: NTSTATUS
  295. //
  296. // Purpose: Add the given pointer to the array. The pointer is passed in
  297. // to this function not a pointer to the pointer.
  298. //
  299. // History: 1999-11-16 vtan created
  300. // --------------------------------------------------------------------------
  301. NTSTATUS CDynamicPointerArray::Add (const void *pvData)
  302. {
  303. return(CDynamicArray::Add(&pvData));
  304. }
  305. // --------------------------------------------------------------------------
  306. // CDynamicPointerArray::Remove
  307. //
  308. // Arguments: iElementIndex = Index of the element to remove.
  309. //
  310. // Returns: NTSTATUS
  311. //
  312. // Purpose: Releases the memory occupied by the element and then removes
  313. // the element from the array.
  314. //
  315. // History: 1999-11-16 vtan created
  316. // --------------------------------------------------------------------------
  317. NTSTATUS CDynamicPointerArray::Remove (int iElementIndex)
  318. {
  319. if ((_pvArray != NULL) && (iElementIndex < _iArraySize))
  320. {
  321. ReleaseMemory(static_cast<void**>(_pvArray)[iElementIndex]);
  322. }
  323. return(CDynamicArray::Remove(iElementIndex));
  324. }
  325. // --------------------------------------------------------------------------
  326. // CDynamicPointerArray::Get
  327. //
  328. // Arguments: iElementIndex = Index of the element to get.
  329. //
  330. // Returns: void*
  331. //
  332. // Purpose: Returns the address of the given element in the array. This
  333. // applies only to pointer arrays.
  334. //
  335. // History: 1999-11-16 vtan created
  336. // --------------------------------------------------------------------------
  337. void* CDynamicPointerArray::Get (int iElementIndex)
  338. {
  339. void* pvData;
  340. if (!NT_SUCCESS(CDynamicArray::Get(&pvData, iElementIndex)))
  341. {
  342. pvData = NULL;
  343. }
  344. return(pvData);
  345. }
  346. // --------------------------------------------------------------------------
  347. // CDynamicCountedObjectArray::CDynamicCountedObjectArray
  348. //
  349. // Arguments: <none>
  350. //
  351. // Returns: <none>
  352. //
  353. // Purpose: Constructor for the CDynamicCountedObjectArray. All elements
  354. // should be a subclass of CCountedObject in some way.
  355. //
  356. // History: 1999-11-16 vtan created
  357. // --------------------------------------------------------------------------
  358. CDynamicCountedObjectArray::CDynamicCountedObjectArray (void) :
  359. CDynamicArray(sizeof(CCountedObject*))
  360. {
  361. }
  362. // --------------------------------------------------------------------------
  363. // CDynamicCountedObjectArray::~CDynamicCountedObjectArray
  364. //
  365. // Arguments: <none>
  366. //
  367. // Returns: <none>
  368. //
  369. // Purpose: Destructor for CDynamicCountedObjectArray. Walk the entire
  370. // array and release each CCountedObject in the array before
  371. // allowing the base class destructor to release the memory
  372. // allocated for the actual array itself.
  373. //
  374. // History: 1999-11-16 vtan created
  375. // --------------------------------------------------------------------------
  376. CDynamicCountedObjectArray::~CDynamicCountedObjectArray (void)
  377. {
  378. if (_pvArray != NULL)
  379. {
  380. int i;
  381. for (i = _iArraySize - 1; i >= 0; --i)
  382. {
  383. reinterpret_cast<CCountedObject**>(_pvArray)[i]->Release();
  384. }
  385. }
  386. }
  387. // --------------------------------------------------------------------------
  388. // CDynamicCountedObjectArray::Add
  389. //
  390. // Arguments: pvData = CCountedObject* to add to the array.
  391. //
  392. // Returns: NTSTATUS
  393. //
  394. // Purpose: Adds the CCountedObject* to the array. Calls
  395. // CCountedObject::AddRef to incremenet the reference count on
  396. // the object. If the object cannot be added the reference is
  397. // released.
  398. //
  399. // History: 1999-11-16 vtan created
  400. // --------------------------------------------------------------------------
  401. NTSTATUS CDynamicCountedObjectArray::Add (CCountedObject *pvData)
  402. {
  403. NTSTATUS status;
  404. pvData->AddRef();
  405. status = CDynamicArray::Add(&pvData);
  406. if (!NT_SUCCESS(status))
  407. {
  408. pvData->Release();
  409. }
  410. return(status);
  411. }
  412. // --------------------------------------------------------------------------
  413. // CDynamicCountedObjectArray::Remove
  414. //
  415. // Arguments: iElementIndex = Index of the element to remove.
  416. //
  417. // Returns: NTSTATUS
  418. //
  419. // Purpose: Releases the reference held on the CCountedObject* and then
  420. // removes the element from the array.
  421. //
  422. // History: 1999-11-16 vtan created
  423. // --------------------------------------------------------------------------
  424. NTSTATUS CDynamicCountedObjectArray::Remove (int iElementIndex)
  425. {
  426. if ((_pvArray != NULL) && (iElementIndex < _iArraySize))
  427. {
  428. reinterpret_cast<CCountedObject**>(_pvArray)[iElementIndex]->Release();
  429. }
  430. return(CDynamicArray::Remove(iElementIndex));
  431. }
  432. // --------------------------------------------------------------------------
  433. // CDynamicCountedObjectArray::Get
  434. //
  435. // Arguments: iElementIndex = Index of the element to get.
  436. //
  437. // Returns: CCountedObject*
  438. //
  439. // Purpose: Returns the address of the given element in the array. This
  440. // applies only to CCountedObject* arrays. This does NOT call
  441. // CCountedObject::AddRef on the returned pointer.
  442. //
  443. // History: 1999-11-16 vtan created
  444. // --------------------------------------------------------------------------
  445. CCountedObject* CDynamicCountedObjectArray::Get (int iElementIndex)
  446. {
  447. CCountedObject* pObject;
  448. pObject = NULL;
  449. (NTSTATUS)CDynamicArray::Get(&pObject, iElementIndex);
  450. return(pObject);
  451. }