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.

449 lines
13 KiB

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