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.

419 lines
12 KiB

  1. /*
  2. * Dynamic array
  3. */
  4. #ifndef DUI_BASE_DYNAMICARRAY_H_INCLUDED
  5. #define DUI_BASE_DYNAMICARRAY_H_INCLUDED
  6. #pragma once
  7. namespace DirectUI
  8. {
  9. //-------------------------------------------------------------------------
  10. //
  11. // DyanamicArray
  12. //
  13. // Stores values in an array the double size when it reaches capacity
  14. //
  15. // Compile DEBUG for bounds checking and other DUIAsserts, see public class
  16. // declarations for API
  17. //
  18. // Values are stored natively. Type is chosen at compile time. For example
  19. // (Value is type BYTE, initial capacity is 10):
  20. //
  21. // DynamicArray<BYTE>* pda;
  22. // DynamicArray<BYTE>::Create(10, &pda);
  23. //
  24. // pda->Add(4);
  25. // pda->Insert(0, 7);
  26. //
  27. // DUITrace("0: %d\n", pda->GetItem(0)); // a[0] = 7
  28. // DUITrace("1: %d\n", pda->GetItem(1)); // a[1] = 4
  29. //
  30. // pda->Remove(0);
  31. //
  32. // DUITrace("0: %d\n", pda->GetItem(0)); // a[0] = 4
  33. //
  34. // The Value type must support the following operation:
  35. // Assignment (=)
  36. //
  37. //-------------------------------------------------------------------------
  38. template <typename T> class DynamicArray
  39. {
  40. public: // API
  41. static HRESULT Create(UINT uCapacity, bool fZeroData, OUT DynamicArray<T>** ppArray);
  42. virtual ~DynamicArray();
  43. void Destroy() { HDelete< DynamicArray<T> >(this); }
  44. // 'Ptr' methods return addesses, note that Add and Insert may cause the array
  45. // to be reallocated and moved in memory. Be sure not to use pointers after
  46. // an Add or Insert operation
  47. typedef int (__cdecl *QSORTCMP )(const void*, const void*);
  48. HRESULT Add(T tItem); // Insert Item at end of list (double capacity if needed)
  49. HRESULT AddPtr(OUT T** ppNewItem); // Allocate room for Item at end of list and return pointer (double capacity if needed)
  50. HRESULT Insert(UINT uIndex, T tItem); // Insert Item at location (double capacity if needed)
  51. HRESULT InsertPtr(UINT uIndex, OUT T** pNewItem); // Allocate room at insertion point and return pointer (double capacity if needed)
  52. void SetItem(UINT uIndex, T tItem); // Overwrite Item at location
  53. T GetItem(UINT uIndex); // Get Item at location
  54. T* GetItemPtr(UINT uIndex); // Get pointer to Item at location
  55. UINT GetSize(); // Return size of array (not current capacity)
  56. UINT GetIndexPtr(T* pItem); // Return index of Item based on its pointer
  57. int GetIndexOf(T tItem); // Return index of Item
  58. void Remove(UINT uIndex); // Remove Item at location
  59. void Reset(); // Reset array to be reused (make zero size)
  60. bool WasMoved(); // May be called right after Add or Insert to determine if da was moved in memory
  61. HRESULT Clone(OUT DynamicArray<T>** ppClone); // Make exact copy of array
  62. bool IsEqual(DynamicArray<T>* pda); // Return true if contents are equal to da
  63. void Sort(QSORTCMP fpCmp); // Sort the array
  64. void MakeImmutable(); // Write-once, make so can only do read-only operations
  65. void MakeWritable(); // Make read/write
  66. bool fLock : 1;
  67. DynamicArray() { }
  68. HRESULT Initialize(UINT uCapacity, bool fZeroData);
  69. private:
  70. UINT _uSize;
  71. UINT _uCapacity;
  72. T* _pData;
  73. bool _fZeroData : 1; // Zero memory for data if InsertPtr is used
  74. bool _fWasMoved : 1; // On a reallocation (via Add or Insert), true if fLock was moved
  75. bool _fImmutable : 1; // If true, can only do read-only operations
  76. };
  77. template <typename T> HRESULT DynamicArray<T>::Create(UINT uCapacity, bool fZeroData, OUT DynamicArray<T>** ppArray)
  78. {
  79. *ppArray = NULL;
  80. // Instantiate
  81. DynamicArray<T>* pda = HNew< DynamicArray<T> >();
  82. if (!pda)
  83. return E_OUTOFMEMORY;
  84. HRESULT hr = pda->Initialize(uCapacity, fZeroData);
  85. if (FAILED(hr))
  86. {
  87. pda->Destroy();
  88. return hr;
  89. }
  90. *ppArray = pda;
  91. return S_OK;
  92. }
  93. template <typename T> HRESULT DynamicArray<T>::Initialize(UINT uCapacity, bool fZeroData)
  94. {
  95. _uCapacity = uCapacity;
  96. _uSize = 0;
  97. if (_uCapacity) // Allocate only if have an initial capacity
  98. {
  99. _pData = (T*)HAlloc(sizeof(T) * _uCapacity);
  100. if (!_pData)
  101. return E_OUTOFMEMORY;
  102. }
  103. else
  104. _pData = NULL;
  105. _fZeroData = fZeroData;
  106. _fWasMoved = false;
  107. _fImmutable = false;
  108. fLock = false;
  109. return S_OK;
  110. }
  111. template <typename T> DynamicArray<T>::~DynamicArray()
  112. {
  113. if (_pData)
  114. HFree(_pData);
  115. }
  116. // Copy data into array
  117. template <typename T> HRESULT DynamicArray<T>::Add(T tItem)
  118. {
  119. return Insert(_uSize, tItem);
  120. }
  121. template <typename T> HRESULT DynamicArray<T>::AddPtr(OUT T** ppNewItem)
  122. {
  123. return InsertPtr(_uSize, ppNewItem);
  124. }
  125. template <typename T> HRESULT DynamicArray<T>::Insert(UINT uIndex, T tItem)
  126. {
  127. DUIAssert(!_fImmutable, "Only read operations allowed on immutable DynamicArray");
  128. _fWasMoved = false;
  129. DUIAssert(uIndex <= _uSize, "DynamicArray index out of bounds");
  130. // Resize if needed
  131. if (_uSize == _uCapacity)
  132. {
  133. // Double capacity of list
  134. UINT uNewCapacity = _uCapacity;
  135. if (uNewCapacity == 0)
  136. {
  137. uNewCapacity = 1;
  138. }
  139. else
  140. {
  141. uNewCapacity *= 2;
  142. }
  143. // Reallocate current fLock
  144. UINT_PTR pOld = (UINT_PTR)_pData;
  145. if (_pData)
  146. {
  147. T* pNewData = (T*)HReAlloc(_pData, sizeof(T) * uNewCapacity);
  148. if (!pNewData)
  149. return E_OUTOFMEMORY;
  150. _pData = pNewData;
  151. }
  152. else
  153. {
  154. _pData = (T*)HAlloc(sizeof(T) * uNewCapacity);
  155. if (!_pData)
  156. return E_OUTOFMEMORY;
  157. }
  158. // Update capacity field
  159. _uCapacity = uNewCapacity;
  160. if (pOld != (UINT_PTR)_pData)
  161. _fWasMoved = true;
  162. }
  163. // Shift data at index down one slot
  164. MoveMemory(_pData + (uIndex + 1), _pData + uIndex, (_uSize - uIndex) * sizeof(T));
  165. // Copy new data at insertion point
  166. _pData[uIndex] = tItem;
  167. _uSize++;
  168. return S_OK;
  169. }
  170. template <typename T> HRESULT DynamicArray<T>::InsertPtr(UINT uIndex, T** pNewItem)
  171. {
  172. DUIAssert(!_fImmutable, "Only read operations allowed on immutable DynamicArray");
  173. _fWasMoved = false;
  174. DUIAssert(uIndex <= _uSize, "DynamicArray index out of bounds");
  175. // Resize if needed
  176. if (_uSize == _uCapacity)
  177. {
  178. // Double capacity of list
  179. UINT uNewCapacity = _uCapacity;
  180. if (uNewCapacity == 0)
  181. {
  182. uNewCapacity = 1;
  183. }
  184. else
  185. {
  186. uNewCapacity *= 2;
  187. }
  188. // Reallocate current fLock
  189. UINT_PTR pOld = (UINT_PTR)_pData;
  190. if (_pData)
  191. {
  192. T* pNewData = (T*)HReAlloc(_pData, sizeof(T) * uNewCapacity);
  193. if (!pNewData)
  194. return E_OUTOFMEMORY;
  195. _pData = pNewData;
  196. }
  197. else
  198. {
  199. _pData = (T*)HAlloc(sizeof(T) * uNewCapacity);
  200. if (!_pData)
  201. return E_OUTOFMEMORY;
  202. }
  203. // Update capacity field
  204. _uCapacity = uNewCapacity;
  205. if (pOld != (UINT_PTR)_pData)
  206. _fWasMoved = true;
  207. }
  208. // Shift data at index down one slot
  209. MoveMemory(_pData + (uIndex + 1), _pData + uIndex, (_uSize - uIndex) * sizeof(T));
  210. _uSize++;
  211. if (_fZeroData)
  212. ZeroMemory(_pData + uIndex, sizeof(T));
  213. *pNewItem = _pData + uIndex;
  214. return S_OK;
  215. }
  216. template <typename T> void DynamicArray<T>::SetItem(UINT uIndex, T tItem)
  217. {
  218. DUIAssert(!_fImmutable, "Only read operations allowed on immutable DynamicArray");
  219. DUIAssert(uIndex < _uSize, "DynamicArray index out of bounds");
  220. // Copy new data at insertion point
  221. _pData[uIndex] = tItem;
  222. }
  223. template <typename T> T DynamicArray<T>::GetItem(UINT uIndex)
  224. {
  225. DUIAssert(uIndex < _uSize, "DynamicArray index out of bounds");
  226. return _pData[uIndex];
  227. }
  228. template <typename T> T* DynamicArray<T>::GetItemPtr(UINT uIndex)
  229. {
  230. DUIAssert(!_fImmutable, "Only read operations allowed on immutable DynamicArray");
  231. DUIAssert(uIndex < _uSize, "DynamicArray index out of bounds");
  232. return _pData + uIndex;
  233. }
  234. template <typename T> UINT DynamicArray<T>::GetIndexPtr(T* pItem)
  235. {
  236. DUIAssert((((UINT_PTR)pItem - (UINT_PTR)_pData) / sizeof(T)) >= 0 && (((UINT_PTR)pItem - (UINT_PTR)_pData) / sizeof(T)) < _uSize, "GetIndexPtr out of bounds");
  237. return (UINT)(((UINT_PTR)pItem - (UINT_PTR)_pData) / sizeof(T));
  238. }
  239. template <typename T> int DynamicArray<T>::GetIndexOf(T tItem)
  240. {
  241. for (UINT i = 0; i < _uSize; i++)
  242. {
  243. if (_pData[i] == tItem)
  244. return i;
  245. }
  246. return -1;
  247. }
  248. template <typename T> UINT DynamicArray<T>::GetSize()
  249. {
  250. return _uSize;
  251. }
  252. template <typename T> void DynamicArray<T>::Remove(UINT uIndex)
  253. {
  254. DUIAssert(!_fImmutable, "Only read operations allowed on immutable DynamicArray");
  255. DUIAssert(uIndex < _uSize, "DynamicArray index out of bounds");
  256. // Shift memory
  257. MoveMemory(_pData + uIndex, _pData + (uIndex + 1), (_uSize - uIndex - 1) * sizeof(T));
  258. _uSize--;
  259. }
  260. template <typename T> void DynamicArray<T>::Reset()
  261. {
  262. DUIAssert(!_fImmutable, "Only read operations allowed on immutable DynamicArray");
  263. _uSize = 0;
  264. _fWasMoved = false;
  265. fLock = false;
  266. }
  267. template <typename T> bool DynamicArray<T>::WasMoved()
  268. {
  269. return _fWasMoved;
  270. }
  271. template <typename T> HRESULT DynamicArray<T>::Clone(OUT DynamicArray<T>** ppClone) // New instance returned
  272. {
  273. // Validate parameters
  274. DUIAssert(ppClone, "Invalid parameter: ppClone == NULL");
  275. *ppClone = NULL;
  276. DynamicArray<T>* pda = HNew< DynamicArray<T> >();
  277. if (!pda)
  278. return E_OUTOFMEMORY;
  279. pda->_uSize = _uSize;
  280. pda->_uCapacity = _uCapacity;
  281. pda->_fZeroData = _fZeroData;
  282. pda->_fWasMoved = _fWasMoved;
  283. pda->_fImmutable = false;
  284. pda->_pData = NULL;
  285. if (_pData)
  286. {
  287. pda->_pData = (T*)HAlloc(sizeof(T) * _uCapacity);
  288. if (!pda->_pData)
  289. {
  290. pda->Destroy();
  291. return E_OUTOFMEMORY;
  292. }
  293. CopyMemory(pda->_pData, _pData, sizeof(T) * _uSize);
  294. }
  295. *ppClone = pda;
  296. return S_OK;
  297. }
  298. template <typename T> bool DynamicArray<T>::IsEqual(DynamicArray<T>* pda)
  299. {
  300. if (!pda)
  301. return false;
  302. if (_uSize != pda->_uSize)
  303. return false;
  304. DUIAssert(!((_pData && !pda->_pData) || (!_pData && pda->_pData)), "Invalid comparison");
  305. if (_pData && memcmp(_pData, pda->_pData, sizeof(T) * _uSize) != 0)
  306. return false;
  307. return true;
  308. }
  309. template <typename T> void DynamicArray<T>::Sort(QSORTCMP fpCmp)
  310. {
  311. if (_uSize)
  312. {
  313. qsort(_pData, _uSize, sizeof(T), fpCmp);
  314. }
  315. }
  316. template <typename T> void DynamicArray<T>::MakeImmutable()
  317. {
  318. #if DBG
  319. _fImmutable = true;
  320. #endif
  321. }
  322. template <typename T> void DynamicArray<T>::MakeWritable()
  323. {
  324. #if DBG
  325. _fImmutable = false;
  326. #endif
  327. }
  328. } // namespace DirectUI
  329. #endif // DUI_BASE_DYNAMICARRAY_H_INCLUDED