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.

427 lines
12 KiB

  1. //depot/Lab01_N/base/win32/fusion/inc/fusionarray.h#10 - edit change 14845 (text)
  2. #if !defined(FUSION_FUSIONARRAY_H_INCLUDED_)
  3. #define FUSION_FUSIONARRAY_H_INCLUDED_
  4. #if _MSC_VER > 1000
  5. #pragma once
  6. #endif // _MSC_VER > 1000
  7. //
  8. // fusionarray.h
  9. //
  10. // Fusion C++ array class. Functionally similar to ever other array
  11. // class out there, but since we do not throw exceptions, instead this
  12. // implementation does not define all the funky operators and
  13. // instead defines member functions to access elements of the array
  14. // which may return HRESULTs.
  15. //
  16. #if !defined(FUSION_UNUSED)
  17. #define FUSION_UNUSED(x) (x)
  18. #endif
  19. #include <arrayhelp.h>
  20. #include "CFusionArrayTypedefs.h"
  21. template <typename TStored, typename TPassed = TStored, bool fExponentialGrowth = false, int nDefaultSize = 0, int nGrowthParam = 1>
  22. class CFusionArray : public CFusionArrayTypedefs<TStored>
  23. {
  24. public:
  25. ConstIterator Begin() const
  26. {
  27. return m_prgtElements;
  28. }
  29. ConstIterator End() const
  30. {
  31. return m_prgtElements + GetSize();
  32. }
  33. Iterator Begin()
  34. {
  35. return m_prgtElements;
  36. }
  37. Iterator End()
  38. {
  39. return m_prgtElements + GetSize();
  40. }
  41. template <typename Integer>
  42. Reference operator[](Integer index)
  43. {
  44. return *(Begin() + index);
  45. }
  46. template <typename Integer>
  47. ConstReference operator[](Integer index) const
  48. {
  49. return *(Begin() + index);
  50. }
  51. CFusionArray() : m_prgtElements(NULL), m_cElements(0), m_iHighWaterMark(0) { }
  52. ~CFusionArray()
  53. {
  54. ::FusionFreeArray(m_cElements, m_prgtElements);
  55. m_prgtElements = NULL;
  56. m_cElements = 0;
  57. m_iHighWaterMark = 0;
  58. }
  59. BOOL Win32Initialize(SIZE_T nSize = nDefaultSize)
  60. {
  61. FN_PROLOG_WIN32
  62. INTERNAL_ERROR_CHECK(m_cElements == 0);
  63. if (nSize != 0)
  64. {
  65. IFW32FALSE_EXIT(::FusionWin32ResizeArray( m_prgtElements, m_cElements, nSize));
  66. m_cElements = nSize;
  67. }
  68. FN_EPILOG
  69. }
  70. BOOL Win32Access(SIZE_T iElement, TStored *&rptOut, bool fExtendIfNecessary = false)
  71. {
  72. FN_PROLOG_WIN32
  73. rptOut = NULL;
  74. if ( iElement >= m_cElements )
  75. {
  76. PARAMETER_CHECK(fExtendIfNecessary);
  77. }
  78. if ( iElement >= m_cElements )
  79. {
  80. IFW32FALSE_EXIT(this->Win32InternalExpand(iElement));
  81. }
  82. rptOut = &m_prgtElements[iElement];
  83. if ( iElement >= m_iHighWaterMark )
  84. m_iHighWaterMark = iElement + 1;
  85. FN_EPILOG
  86. }
  87. // HRESULT GetSize(SIZE_T &rcElementsOut) const { rcElementsOut = m_cElements; return NOERROR; }
  88. SIZE_T GetSize() const { return m_cElements; }
  89. DWORD GetSizeAsDWORD() const { if (m_cElements > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cElements); }
  90. ULONG GetSizeAsULONG() const { if (m_cElements > ULONG_MAX) return ULONG_MAX; return static_cast<ULONG>(m_cElements); }
  91. //
  92. // Enumeration used to control the behavior of CFusionArray::SetSize().
  93. // if eSetSizeModeExact is passed, the internal array is set to exactly
  94. // the cElements passed in; if eSetSizeModeApplyRounding is passed (the
  95. // default), we apply the normal expansion/shrinking algorithm for the
  96. // array.
  97. //
  98. enum SetSizeMode
  99. {
  100. eSetSizeModeExact = 0,
  101. eSetSizeModeApplyRounding = 1,
  102. };
  103. //
  104. // Member function to manually set the size of the internal array stored
  105. // by the CFusionArray. Default behavior is to find an appropriate rounded
  106. // size (based on the exponential vs. linear growth characteristic of the
  107. // array) and resize to that. Alternately, the caller may supply an
  108. // exact size and the internal size is set to that. Note that explicitly
  109. // setting the array size may have interesting side-effects on future
  110. // growth of the array; for example if an array is set to grow exponentially
  111. // at a factor of 2^1 (nGrowthFactor == 1; doubling on each growth pass),
  112. // its size will normally be a power of two. However, explicitly setting the
  113. // size to, for example, 10 and then trying to access element 11 will cause
  114. // the exponential growth factor to grow the array to 20 elements, rather than
  115. // a power of two.
  116. //
  117. BOOL Win32SetSize(SIZE_T cElements, SetSizeMode ssm = eSetSizeModeApplyRounding)
  118. {
  119. FN_PROLOG_WIN32
  120. if (ssm == eSetSizeModeExact)
  121. {
  122. IFW32FALSE_EXIT(::FusionWin32ResizeArray(m_prgtElements, m_cElements, cElements));
  123. if (cElements < m_iHighWaterMark)
  124. m_iHighWaterMark = cElements;
  125. m_cElements = cElements;
  126. }
  127. else
  128. {
  129. if (cElements > m_cElements)
  130. {
  131. IFW32FALSE_EXIT(this->Win32InternalExpand(cElements - 1));
  132. }
  133. else
  134. {
  135. // For now, since it's inexact, we'll punt non-exact shrinking.
  136. }
  137. }
  138. FN_EPILOG
  139. }
  140. const TStored *GetArrayPtr() const { return m_prgtElements; }
  141. TStored *GetArrayPtr() { return m_prgtElements; }
  142. //
  143. // Member function to reset the array to its size and storage associated with
  144. // its initial construction.
  145. //
  146. enum ResetMode {
  147. eResetModeZeroSize = 0,
  148. eResetModeDefaultSize = 1,
  149. };
  150. BOOL Win32Reset( ResetMode rm = eResetModeDefaultSize )
  151. {
  152. FN_PROLOG_WIN32
  153. if ( rm == eResetModeDefaultSize )
  154. {
  155. if ( m_cElements != nDefaultSize )
  156. {
  157. IFW32FALSE_EXIT(::FusionWin32ResizeArray( m_prgtElements, m_cElements, nDefaultSize ));
  158. m_cElements = nDefaultSize;
  159. }
  160. if ( m_iHighWaterMark > nDefaultSize )
  161. m_iHighWaterMark = nDefaultSize;
  162. }
  163. else if ( rm == eResetModeZeroSize )
  164. {
  165. ::FusionFreeArray(m_cElements, m_prgtElements);
  166. m_prgtElements = NULL;
  167. m_cElements = m_iHighWaterMark = 0;
  168. }
  169. FN_EPILOG
  170. }
  171. enum AppendMode {
  172. eAppendModeExtendArray = 0,
  173. eAppendModeNoExtendArray = 1,
  174. };
  175. BOOL Win32Append(const TPassed& tNew, AppendMode am = eAppendModeExtendArray)
  176. {
  177. BOOL fSuccess = FALSE;
  178. FN_TRACE_WIN32(fSuccess);
  179. ASSERT(m_iHighWaterMark <= m_cElements);
  180. if (m_iHighWaterMark >= m_cElements)
  181. {
  182. PARAMETER_CHECK(am != eAppendModeNoExtendArray);
  183. SIZE_T cElementsOld = m_cElements;
  184. IFW32FALSE_EXIT(this->Win32InternalExpand(m_cElements));
  185. m_iHighWaterMark = cElementsOld;
  186. }
  187. // Clients of this class should provide explicit overrides for FusionCopyContents()
  188. // for their types as appropriate.
  189. IFW32FALSE_EXIT(::FusionWin32CopyContents(m_prgtElements[m_iHighWaterMark++], tNew));
  190. fSuccess = TRUE;
  191. Exit:
  192. return fSuccess;
  193. }
  194. BOOL Win32Remove(SIZE_T i)
  195. {
  196. FN_PROLOG_WIN32
  197. SIZE_T j;
  198. PARAMETER_CHECK(i < m_cElements);
  199. for (j = (i + 1); j < m_cElements; j++)
  200. IFW32FALSE_EXIT(::FusionWin32CopyContents(m_prgtElements[j-1], m_prgtElements[j]));
  201. m_cElements--;
  202. FN_EPILOG
  203. }
  204. // 03/14/2001 - Added constness
  205. BOOL Win32Assign(SIZE_T celt, const TPassed *prgtelt)
  206. {
  207. BOOL fSuccess = FALSE;
  208. FN_TRACE_WIN32(fSuccess);
  209. SIZE_T i;
  210. // So that we can fail gracefully, we need to copy our state off, attempt
  211. // the population of the array and then revert if necessary.
  212. TStored *prgtElementsSaved = m_prgtElements;
  213. SIZE_T cElementsSaved = m_cElements;
  214. SIZE_T iHighWaterMarkSaved = m_iHighWaterMark;
  215. m_prgtElements = NULL;
  216. m_cElements = 0;
  217. m_iHighWaterMark = 0;
  218. IFW32FALSE_EXIT(this->Win32Initialize(celt));
  219. for (i=0; i<celt; i++)
  220. {
  221. IFW32FALSE_EXIT(::FusionWin32CopyContents(m_prgtElements[i], prgtelt[i]));
  222. }
  223. m_iHighWaterMark = celt;
  224. // We can drop the old contents...
  225. ::FusionFreeArray(cElementsSaved, prgtElementsSaved);
  226. cElementsSaved = 0;
  227. prgtElementsSaved = NULL;
  228. fSuccess = TRUE;
  229. Exit:
  230. if (!fSuccess)
  231. {
  232. // Revert to previous state...
  233. ::FusionFreeArray(m_cElements, m_prgtElements);
  234. m_prgtElements = prgtElementsSaved;
  235. m_cElements = cElementsSaved;
  236. m_iHighWaterMark = iHighWaterMarkSaved;
  237. }
  238. return fSuccess;
  239. }
  240. // Xiaoyu 01/24/00 : copy this to prgDest
  241. //
  242. // jonwis 20-Sept-2000 : Update to be a little cleaner and 'const'
  243. //
  244. BOOL Win32Clone(CFusionArray<TStored, TPassed> &prgDest) const
  245. {
  246. BOOL fSuccess = FALSE;
  247. FN_TRACE_WIN32(fSuccess);
  248. SIZE_T i;
  249. //
  250. // Cloning an empty array shouldn't break things.
  251. //
  252. if ( m_prgtElements == NULL )
  253. {
  254. IFW32FALSE_EXIT(prgDest.Win32Reset(eResetModeZeroSize));
  255. }
  256. else
  257. {
  258. //
  259. // Resize the destiny array to what it should be
  260. //
  261. if ( prgDest.m_cElements != m_cElements )
  262. IFW32FALSE_EXIT(::FusionWin32ResizeArray(prgDest.m_prgtElements, prgDest.m_cElements, m_cElements));
  263. //
  264. // Copy the elements from point A to point B
  265. //
  266. for ( i = 0; i < m_cElements; i++ )
  267. {
  268. IFW32FALSE_EXIT(::FusionWin32CopyContents(prgDest.m_prgtElements[i], m_prgtElements[i]));
  269. }
  270. prgDest.m_cElements = m_cElements;
  271. prgDest.m_iHighWaterMark = m_iHighWaterMark;
  272. }
  273. fSuccess = TRUE;
  274. Exit:
  275. if ( !fSuccess )
  276. {
  277. prgDest.Win32Reset(eResetModeZeroSize);
  278. }
  279. return fSuccess;
  280. }
  281. protected:
  282. BOOL Win32InternalExpand(SIZE_T iElement)
  283. {
  284. BOOL fSuccess = FALSE;
  285. FN_TRACE_WIN32(fSuccess);
  286. SIZE_T nNewElements = 0;
  287. if (fExponentialGrowth)
  288. {
  289. if (m_cElements == 0)
  290. {
  291. if (nDefaultSize == 0)
  292. nNewElements = (1 << nGrowthParam);
  293. else
  294. nNewElements = nDefaultSize;
  295. }
  296. else
  297. {
  298. nNewElements = m_cElements * (1 << nGrowthParam);
  299. }
  300. while ((nNewElements != 0) && (nNewElements <= iElement))
  301. nNewElements = nNewElements << nGrowthParam;
  302. // Ok, it's possible that nGrowthParam was something crazy like 10
  303. // (meaning to grow the array by a factor of 2^10 each time), so we
  304. // never really found a size that was appropriate. We'll be slightly
  305. // less crazy and find the power-of-two that's big enough. We still
  306. // have a possibility here that the user is asking for an index between
  307. // 2^31 and ((2^32)-1), which of course will fail because we can't
  308. // allocate that much storage.
  309. if (nNewElements == 0)
  310. {
  311. nNewElements = 1;
  312. while ((nNewElements != 0) && (nNewElements <= iElement))
  313. nNewElements = nNewElements << 1;
  314. }
  315. }
  316. else
  317. {
  318. // In the linear growth case, we can use simple division to do all the
  319. // work done above for exponential growth.
  320. nNewElements = iElement + nGrowthParam - 1;
  321. if (nGrowthParam > 1)
  322. nNewElements = nNewElements - (nNewElements % nGrowthParam);
  323. // We'll handle overflow in the generic checking below...
  324. }
  325. // fallback; we'll try to make it just big enough. It's true we lose the
  326. // growth pattern etc. that the caller requested, but it's pretty clear that
  327. // the caller messed up by either specifying a wacky nGrowthParam or there's
  328. // an outlandishly large iElement coming in.
  329. if (nNewElements <= iElement)
  330. nNewElements = iElement + 1;
  331. IFW32FALSE_EXIT(::FusionWin32ResizeArray(m_prgtElements, m_cElements, nNewElements));
  332. m_cElements = nNewElements;
  333. fSuccess = TRUE;
  334. Exit:
  335. return fSuccess;
  336. }
  337. TStored *m_prgtElements;
  338. SIZE_T m_cElements;
  339. SIZE_T m_iHighWaterMark;
  340. };
  341. #endif // !defined(FUSION_FUSIONARRAY_H_INCLUDED_)