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.

595 lines
11 KiB

  1. #ifndef _INC_DSKQUOTA_CARRAY_H
  2. #define _INC_DSKQUOTA_CARRAY_H
  3. ///////////////////////////////////////////////////////////////////////////////
  4. /* File: carray.h
  5. Description: Template class CArray. Implements a dynamic array class.
  6. Much of the functionality is based on the feature set of MFC's
  7. CArray class.
  8. Revision History:
  9. Date Description Programmer
  10. -------- --------------------------------------------------- ----------
  11. 09/16/97 Initial creation. BrianAu
  12. 12/13/97 Changed SetAtGrow to return true/false. True means BrianAu
  13. had to grow array.
  14. */
  15. ///////////////////////////////////////////////////////////////////////////////
  16. #ifndef _INC_DSKQUOTA_DEBUG_H
  17. # include "debug.h"
  18. #endif
  19. #ifndef _INC_DSKQUOTA_THDSYNC_H
  20. # include "thdsync.h"
  21. #endif
  22. #ifndef _INC_DSKQUOTA_EXCEPT_H
  23. # include "except.h"
  24. #endif
  25. template <class T>
  26. class CArray
  27. {
  28. public:
  29. CArray<T>(VOID);
  30. explicit CArray<T>(INT cItems);
  31. CArray<T>(const CArray<T>& rhs);
  32. CArray<T>& operator = (const CArray<T>& rhs);
  33. virtual ~CArray<T>(VOID);
  34. VOID SetAt(const T& item, INT i);
  35. bool SetAtGrow(const T& item, INT i);
  36. T GetAt(INT i) const;
  37. VOID Insert(const T& item, INT i = -1);
  38. VOID Append(const T& item, INT i = -1);
  39. INT Find(const T& key);
  40. VOID Delete(INT i);
  41. T operator [] (INT i) const;
  42. T& operator [] (INT i);
  43. VOID Clear(VOID);
  44. BOOL IsEmpty(VOID) const
  45. { return 0 == m_cItems; }
  46. INT Count(VOID) const
  47. { return m_cItems; }
  48. INT UpperBound(VOID) const
  49. { return m_cItems - 1; }
  50. INT Size(VOID) const
  51. { return m_cAlloc; }
  52. VOID SetGrow(INT cGrow)
  53. { m_cGrow = cGrow; }
  54. VOID Copy(const CArray<T>& rhs);
  55. VOID Append(const CArray<T>& rhs);
  56. VOID SetSize(INT cEntries, INT iShift = -1);
  57. VOID Lock(VOID)
  58. { m_cs.Enter(); }
  59. VOID ReleaseLock(VOID)
  60. { m_cs.Leave(); }
  61. protected:
  62. static INT DEFGROW; // Default growth value.
  63. private:
  64. INT m_cAlloc; // Number of entry allocations.
  65. INT m_cItems; // Number of used entries.
  66. INT m_cGrow;
  67. T *m_rgItems; // Array of entries.
  68. mutable CCriticalSection m_cs; // For multi-threaded access.
  69. template <class U>
  70. const U& MIN(const U& a, const U& b) const
  71. {
  72. return a < b ? a : b;
  73. }
  74. template <class U>
  75. const U& MAX(const U& a, const U& b) const
  76. {
  77. return a > b ? a : b;
  78. }
  79. };
  80. template <class T>
  81. INT CArray<T>::DEFGROW = 8;
  82. template <class T>
  83. CArray<T>::CArray(
  84. void
  85. ) : m_cAlloc(0),
  86. m_cItems(0),
  87. m_cGrow(DEFGROW),
  88. m_rgItems(NULL)
  89. {
  90. }
  91. template <class T>
  92. CArray<T>::CArray(
  93. INT cItems
  94. ) : m_cAlloc(0),
  95. m_cItems(0),
  96. m_cGrow(DEFGROW),
  97. m_rgItems(NULL)
  98. {
  99. SetSize(cItems);
  100. m_cItems = cItems;
  101. }
  102. template <class T>
  103. CArray<T>::CArray(
  104. const CArray& rhs
  105. ) : m_cAlloc(0),
  106. m_cItems(0),
  107. m_cGrow(DEFGROW),
  108. m_rgItems(NULL)
  109. {
  110. *this = rhs;
  111. }
  112. template <class T>
  113. VOID
  114. CArray<T>::Copy(
  115. const CArray<T>& rhs
  116. )
  117. {
  118. AutoLockCs lock1(rhs.m_cs);
  119. AutoLockCs lock2(m_cs);
  120. //
  121. // Place *this in an empty state in case Grow() throws an exception.
  122. // It should still be a valid CArray object.
  123. //
  124. delete[] m_rgItems;
  125. m_rgItems = NULL;
  126. m_cAlloc = 0;
  127. m_cItems = 0;
  128. //
  129. // Size the object to hold the source array.
  130. //
  131. SetSize(rhs.m_cAlloc);
  132. //
  133. // Copy the contents.
  134. //
  135. DBGASSERT((m_cAlloc >= rhs.m_cItems));
  136. for (m_cItems = 0; m_cItems < rhs.m_cItems; m_cItems++)
  137. {
  138. //
  139. // This assignment could throw an exception so only update
  140. // our item count after each successful copy.
  141. //
  142. DBGASSERT((m_cItems < m_cAlloc));
  143. m_rgItems[m_cItems] = rhs.m_rgItems[m_cItems];
  144. }
  145. }
  146. template <class T>
  147. VOID
  148. CArray<T>::Append(
  149. const CArray<T>& rhs
  150. )
  151. {
  152. AutoLockCs lock1(rhs.m_cs);
  153. AutoLockCs lock2(m_cs);
  154. //
  155. // Size the object to hold both arrays.
  156. //
  157. SetSize(m_cAlloc + rhs.m_cItems);
  158. //
  159. // Append the contents.
  160. //
  161. DBGASSERT((m_cAlloc >= (m_cItems + rhs.m_cItems)));
  162. for (int i = 0; i < rhs.m_cItems; i++)
  163. {
  164. DBGASSERT((m_cItems < m_cAlloc));
  165. m_rgItems[m_cItems++] = rhs.m_rgItems[i];
  166. }
  167. }
  168. template <class T>
  169. CArray<T>&
  170. CArray<T>::operator = (
  171. const CArray<T>& rhs
  172. )
  173. {
  174. if (this != &rhs)
  175. {
  176. Copy(rhs);
  177. }
  178. return *this;
  179. }
  180. template <class T>
  181. CArray<T>::~CArray(
  182. VOID
  183. )
  184. {
  185. Clear();
  186. }
  187. template <class T>
  188. T CArray<T>::operator [] (
  189. INT i
  190. ) const
  191. {
  192. return GetAt(i);
  193. }
  194. template <class T>
  195. T& CArray<T>::operator [] (
  196. INT i
  197. )
  198. {
  199. AutoLockCs lock(m_cs);
  200. if (i < 0 || i >= m_cItems)
  201. throw CMemoryException(CMemoryException::index);
  202. return *(m_rgItems + i);
  203. }
  204. template <class T>
  205. VOID
  206. CArray<T>::Clear(
  207. VOID
  208. )
  209. {
  210. AutoLockCs lock(m_cs);
  211. delete[] m_rgItems;
  212. m_rgItems = NULL;
  213. m_cAlloc = 0;
  214. m_cItems = 0;
  215. }
  216. template <class T>
  217. VOID
  218. CArray<T>::Insert(
  219. const T& item,
  220. INT i
  221. )
  222. {
  223. AutoLockCs lock(m_cs);
  224. if (-1 == i)
  225. {
  226. //
  227. // Insert at head of array.
  228. //
  229. i = 0;
  230. }
  231. //
  232. // Can only insert an item before an existing item.
  233. // i cannot be negative.
  234. // If array is empty, i can only be 0.
  235. // If array is not empty, i must be index of a valid item.
  236. //
  237. if ((0 == m_cItems && 0 != i) ||
  238. (0 != m_cItems && (i < 0 || i >= m_cItems)))
  239. {
  240. throw CMemoryException(CMemoryException::index);
  241. }
  242. DBGASSERT((m_cItems <= m_cAlloc));
  243. if (m_cItems >= m_cAlloc)
  244. {
  245. //
  246. // Grow the array if necessary.
  247. // This will also shift the elements, beginning with element 'i',
  248. // one element to the right.
  249. //
  250. SetSize(m_cAlloc + m_cGrow, i);
  251. }
  252. else
  253. {
  254. //
  255. // Growth not necessary.
  256. // Shift the contents of the array following the insertion point
  257. // one element to the right.
  258. //
  259. for (int j = m_cItems; j > i; j--)
  260. {
  261. m_rgItems[j] = m_rgItems[j-1];
  262. }
  263. }
  264. //
  265. // We've now inserted an item.
  266. //
  267. m_cItems++;
  268. //
  269. // Set the value at the inserted location.
  270. // This assignment could throw an exception.
  271. //
  272. SetAt(item, i);
  273. }
  274. template <class T>
  275. VOID
  276. CArray<T>::Append(
  277. const T& item,
  278. INT i
  279. )
  280. {
  281. AutoLockCs lock(m_cs);
  282. if (-1 == i)
  283. {
  284. //
  285. // Append at end of array.
  286. //
  287. i = m_cItems - 1;
  288. }
  289. //
  290. // Can only append an item after an existing item.
  291. // When array is empty, i can only be -1.
  292. // When array is not empty, i must be index of a valid item.
  293. //
  294. // Note: i will be -1 when m_cItems is 0.
  295. //
  296. if ((0 == m_cItems && -1 != i) ||
  297. (0 != m_cItems && (i < 0 || i >= m_cItems)))
  298. {
  299. throw CMemoryException(CMemoryException::index);
  300. }
  301. DBGASSERT((m_cItems <= m_cAlloc));
  302. if (m_cItems >= m_cAlloc)
  303. {
  304. //
  305. // Grow the array if necessary.
  306. // This will also shift the elements, beginning with element 'i + 1',
  307. // one element to the right.
  308. //
  309. SetSize(m_cAlloc + m_cGrow, i+1);
  310. }
  311. else
  312. {
  313. //
  314. // Shift the contents of the array following the insertion
  315. // point, one entry to the right.
  316. //
  317. for (int j = m_cItems; j > (i+1); j--)
  318. {
  319. m_rgItems[j] = m_rgItems[j-1];
  320. }
  321. }
  322. //
  323. // We've now appended an item.
  324. //
  325. m_cItems++;
  326. //
  327. // Set the value at the appended location.
  328. // This assignment could throw an exception.
  329. //
  330. SetAt(item, i+1);
  331. }
  332. template <class T>
  333. VOID
  334. CArray<T>::Delete(
  335. INT i
  336. )
  337. {
  338. AutoLockCs lock(m_cs);
  339. //
  340. // Can only delete a valid item.
  341. //
  342. if (i < 0 || i >= m_cItems)
  343. throw CMemoryException(CMemoryException::index);
  344. //
  345. // Shift memory to remove the item.
  346. //
  347. for (int j = i; j < (m_cItems - 1); j++)
  348. {
  349. m_rgItems[j] = m_rgItems[j+1];
  350. }
  351. //
  352. // Now we have one less item.
  353. //
  354. m_cItems--;
  355. //
  356. // Shrink the array if it's required size is less than 2X the
  357. // array's "growth" amount.
  358. //
  359. if ((m_cAlloc - m_cItems) > (2 * m_cGrow))
  360. {
  361. SetSize(m_cItems);
  362. }
  363. }
  364. template <class T>
  365. INT
  366. CArray<T>::Find(
  367. const T& key
  368. )
  369. {
  370. AutoLockCs lock(m_cs);
  371. for (INT i = 0; i < m_cItems; i++)
  372. {
  373. if (m_rgItems[i] == key)
  374. {
  375. return i;
  376. }
  377. }
  378. return -1;
  379. }
  380. template <class T>
  381. T
  382. CArray<T>::GetAt(
  383. INT i
  384. ) const
  385. {
  386. AutoLockCs lock(m_cs);
  387. if (i < 0 || i >= m_cItems)
  388. throw CMemoryException(CMemoryException::index);
  389. return m_rgItems[i];
  390. }
  391. template <class T>
  392. VOID
  393. CArray<T>::SetAt(
  394. const T& item,
  395. INT i
  396. )
  397. {
  398. AutoLockCs lock(m_cs);
  399. if (i < 0 || i >= m_cAlloc)
  400. throw CMemoryException(CMemoryException::index);
  401. m_rgItems[i] = item;
  402. }
  403. //
  404. // Returns: true = array was extended, false = no extension required.
  405. //
  406. template <class T>
  407. bool
  408. CArray<T>::SetAtGrow(
  409. const T& item,
  410. INT i
  411. )
  412. {
  413. bool bGrow = false;
  414. AutoLockCs lock(m_cs);
  415. if (i >= m_cAlloc)
  416. {
  417. //
  418. // Need to grow the array to accomodate the new item.
  419. //
  420. SetSize(i + m_cGrow);
  421. bGrow = true;
  422. }
  423. //
  424. // Set the new item value.
  425. //
  426. SetAt(item, i);
  427. //
  428. // Extend the count of "valid" items.
  429. //
  430. m_cItems = i + 1;
  431. return bGrow;
  432. }
  433. template <class T>
  434. VOID
  435. CArray<T>::SetSize(
  436. INT cEntries,
  437. INT iShift // Pass -1 for "no shift".
  438. )
  439. {
  440. AutoLockCs lock(m_cs);
  441. //
  442. // Don't allow an array of less than 1 element.
  443. //
  444. cEntries = MAX(1, cEntries);
  445. T *pNew = new T[cEntries];
  446. if (NULL == pNew)
  447. throw CAllocException();
  448. if (NULL != m_rgItems)
  449. {
  450. INT cCopy = MIN(cEntries, m_cItems);
  451. INT j = 0;
  452. for (INT i = 0; i < cCopy; i++, j++)
  453. {
  454. //
  455. // Shift items [i..(n-1)] to [(i+1)..n]
  456. //
  457. if (iShift == j)
  458. j++;
  459. *(pNew + j) = m_rgItems[i];
  460. }
  461. }
  462. delete[] m_rgItems;
  463. m_rgItems = pNew;
  464. m_cAlloc = cEntries;
  465. }
  466. template <class T>
  467. class CQueueAsArray : public CArray<T>
  468. {
  469. public:
  470. CQueueAsArray<T>(VOID) { }
  471. ~CQueueAsArray<T>(VOID) { }
  472. VOID Add(T& item);
  473. BOOL Remove(T& item);
  474. private:
  475. CQueueAsArray<T>(const CQueueAsArray<T>& rhs);
  476. CQueueAsArray<T>& operator = (const CQueueAsArray<T>& rhs);
  477. };
  478. template <class T>
  479. VOID
  480. CQueueAsArray<T>::Add(
  481. T& item
  482. )
  483. {
  484. Append(item);
  485. }
  486. template <class T>
  487. BOOL
  488. CQueueAsArray<T>::Remove(
  489. T& item
  490. )
  491. {
  492. BOOL bResult = FALSE;
  493. if (!IsEmpty())
  494. {
  495. INT i = UpperBound();
  496. item = GetAt(i);
  497. Delete(i);
  498. bResult = TRUE;
  499. }
  500. return bResult;
  501. }
  502. #endif // _INC_DSKQUOTA_CARRAY_H