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.

480 lines
13 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Template Array Implementation
  4. // Copyright (C) Microsoft Corporation, 1996, 1997
  5. //
  6. // File: tarray.h
  7. //
  8. // Contents: Template for resizeable arrays. Allows for the creation
  9. // and manipulation of arrays of any type. Arrays can
  10. // be dynamically reallocated, and thus can "grow and shrink".
  11. // Constructors and destructors of array elements is
  12. // automatically handles, even when the size of the array is
  13. // changed.
  14. // Templates: TSTDArray
  15. //
  16. //------------------------------------------------------------------------
  17. #ifndef _TARRAY_H_
  18. #define _TARRAY_H_
  19. //+-----------------------------------------------------------------------
  20. //
  21. // Class: TSTDArray
  22. //
  23. // Synopsis: Contains an array of "type". Allows array to grow
  24. // dynamically. During debug, can check bounds on indices.
  25. // Array is indexed 0 to _cArraySize-1. _cArraySize holds
  26. // number of elements.
  27. //
  28. // Methods: Init allocate memory for array
  29. // Passivate
  30. // [] allows indexing of array
  31. // GetSize returns size of array
  32. // InsertElems insert elements anywhere in array
  33. // DeleteElems delete elements anywhere in array
  34. //
  35. //------------------------------------------------------------------------
  36. template <class TYPE>
  37. class TSTDArray
  38. {
  39. public:
  40. TSTDArray();
  41. #if DBG == 1
  42. ~TSTDArray();
  43. #endif
  44. HRESULT Init(const size_t cSize); // initialize data structures
  45. void Passivate();
  46. TYPE& operator[](const size_t iElement);
  47. const TYPE& operator[](const size_t iElement) const; // constant reference
  48. size_t GetSize() const { return _cArraySize; }
  49. HRESULT InsertElems(const size_t iElem, const size_t cElems);
  50. void DeleteElems(const size_t iElem, const size_t cElems);
  51. private:
  52. #if DBG == 1
  53. void IsValidObject() const;
  54. #else
  55. void IsValidObject() const
  56. { }
  57. #endif
  58. // All elements are packaged inside a class CElem. This allows us to
  59. // overload the new operator so that we can manually invoke the
  60. // constructors.
  61. class CElem
  62. {
  63. friend TSTDArray;
  64. private:
  65. // Now we overload the new operator to allow placement argument
  66. void *operator new(size_t uSize, void *pv) { return pv; }
  67. // Internal data:
  68. TYPE _Element; // actual element
  69. };
  70. // Internal data:
  71. CElem *_paArray; // pointer to actual data
  72. size_t _cArraySize;
  73. size_t _cAllocSize; // the size of allocated object
  74. #if DBG == 1
  75. // Ensure we call constructors and destructors right number of times.
  76. // Used only as a check.
  77. size_t _cNumElems;
  78. #endif
  79. };
  80. //+---------------------------------------------------------------------------
  81. //
  82. // Member: IsValidObject
  83. //
  84. // Synopsis: Validation method. Checks that array structure is valid.
  85. // It is usefull to call this member function at the beginning
  86. // of each member function that uses the internal array to
  87. // ensure that the array is not corrupt before attempting to
  88. // modify it.
  89. //
  90. #if DBG == 1
  91. template <class TYPE>
  92. void
  93. TSTDArray<TYPE>::IsValidObject() const
  94. {
  95. _ASSERT("Must have valid this pointer" &&
  96. this );
  97. _ASSERT("Array has no memory" &&
  98. _paArray );
  99. _ASSERT("destructors called wrong number of times" &&
  100. (_cNumElems == _cArraySize) );
  101. }
  102. #endif
  103. //+-----------------------------------------------------------------------
  104. //
  105. // Constructor for TSTDArray
  106. //
  107. // Synopsis: Doesn't do anything. Must call member function init to
  108. // actually initialize. Only call init once.
  109. //
  110. // Arguments: None.
  111. //
  112. // Returns: Nothing.
  113. //
  114. template <class TYPE>
  115. TSTDArray<TYPE>::TSTDArray()
  116. {
  117. // We null the internal data, so that they are not actually used
  118. // until the init member function is called.
  119. _paArray = 0;
  120. _cArraySize = 0;
  121. _cAllocSize = 0;
  122. #if DBG == 1
  123. _cNumElems = 0;
  124. #endif
  125. }
  126. //+-----------------------------------------------------------------------
  127. //
  128. // Destructor for TSTDArray
  129. //
  130. // Synopsis: Must call member function passivate
  131. // to actually de-initialize.
  132. //
  133. // Arguments: None.
  134. //
  135. // Returns: Nothing.
  136. //
  137. #if DBG == 1
  138. template <class TYPE>
  139. TSTDArray<TYPE>::~TSTDArray()
  140. {
  141. _ASSERT("Passivate must be called first" &&
  142. !_paArray );
  143. _ASSERT("Destructors called wrong number of times" &&
  144. (_cNumElems == 0) );
  145. }
  146. #endif
  147. //+-----------------------------------------------------------------------
  148. //
  149. // Member: Init
  150. //
  151. // Synopsis: Initializes the array abstract data type. Allocates
  152. // memory for the array. Also sets the cArraySize to
  153. // the number of elements.
  154. //
  155. // Arguments: cSize initial size of array (# of elements)
  156. //
  157. // Returns: Success if memory can be allocated for table.
  158. // Returns E_OUTOFMEMORY if can't get memory.
  159. //
  160. template <class TYPE>
  161. HRESULT
  162. TSTDArray<TYPE>::Init(const size_t cSize)
  163. {
  164. HRESULT hr;
  165. _ASSERT(this);
  166. _ASSERT("Only call init once" &&
  167. !_paArray );
  168. // Get memory:
  169. // 0 element array is made into 1 element array so that it functions
  170. // normally.
  171. {
  172. //;begin_internal
  173. // BUGBUG:
  174. // MSVC 2.0 has a bug in it. Evaluating the expression sizeof(CElem)
  175. // seems to confuse it. CElem is a class containing a variable
  176. // whose size can only be calculated when the template containing it
  177. // is instantiated. In addition to this, CElem is a member of that
  178. // template. Placing the sizeof(CElem) expression within a more
  179. // complicated expression is not possible.
  180. //;end_internal
  181. size_t uCElemSize;
  182. uCElemSize = sizeof(CElem);
  183. uCElemSize *= (cSize == 0 ? 1 : cSize);
  184. _paArray = (CElem *) CoTaskMemAlloc(uCElemSize);
  185. }
  186. if (!_paArray)
  187. {
  188. hr = E_OUTOFMEMORY;
  189. }
  190. else
  191. {
  192. CElem *pTemp; // index used to call constructors
  193. // We need to call the constructors manually for each element:
  194. for (pTemp = _paArray; pTemp < _paArray + cSize; pTemp++)
  195. {
  196. new (pTemp) CElem;
  197. #if DBG == 1
  198. _cNumElems++;
  199. #endif
  200. }
  201. _cArraySize = cSize;
  202. _cAllocSize = (cSize == 0 ? 1 : cSize);
  203. hr = S_OK;
  204. }
  205. return hr;
  206. }
  207. //+-----------------------------------------------------------------------
  208. //
  209. // Member: Passivate
  210. //
  211. // Synopsis: Releases memory held in array. Should be called before
  212. // the object is destroyed. Should only be called once on an
  213. // object.
  214. //
  215. // Arguments: None.
  216. //
  217. // Returns: Nothing.
  218. //
  219. //------------------------------------------------------------------------
  220. template <class TYPE>
  221. void
  222. TSTDArray<TYPE>::Passivate()
  223. {
  224. IsValidObject();
  225. _ASSERT("Only call Passivate once" &&
  226. _paArray );
  227. // We need to call the destructors manually for each element:
  228. {
  229. CElem *pTemp; // index used to call destructors
  230. for (pTemp = _paArray; pTemp < _paArray + _cArraySize; pTemp++)
  231. {
  232. pTemp->CElem::~CElem();
  233. #if DBG == 1
  234. _cNumElems--;
  235. #endif
  236. }
  237. }
  238. CoTaskMemFree(_paArray);
  239. _paArray = 0; // make sure we don't call Passivate again
  240. _cArraySize = 0;
  241. _cAllocSize = 0;
  242. }
  243. //+-----------------------------------------------------------------------
  244. //
  245. // Member: operator[]
  246. //
  247. // Synopsis: Allows indexing of array's elements. Use this to either
  248. // store an element in the array or read an element from
  249. // the array. It is the user's responsibility to ensure
  250. // that the index is within the proper range, 0.._cArraySize-1.
  251. // During debugging, the index range is checked.
  252. //
  253. // Arguments: iElement Element index
  254. //
  255. // Returns: Reference to element.
  256. //
  257. template <class TYPE>
  258. inline
  259. TYPE&
  260. TSTDArray<TYPE>::operator[](const size_t iElement)
  261. {
  262. IsValidObject();
  263. _ASSERT("Index is out of range" &&
  264. (iElement < _cArraySize) );
  265. return _paArray[iElement]._Element;
  266. }
  267. //+-----------------------------------------------------------------------
  268. //
  269. // Member: operator[] const
  270. //
  271. // Synopsis: Same as previous [] operator, but returns a constant
  272. // reference so that it can't be used as an l-value.
  273. //
  274. // Arguments: iElement Element index
  275. //
  276. // Returns: Constant reference to element.
  277. //
  278. template <class TYPE>
  279. inline
  280. const TYPE&
  281. TSTDArray<TYPE>::operator[](const size_t iElement) const
  282. {
  283. IsValidObject(this);
  284. _ASSERT("Index is out of range" &&
  285. (iElement < _cArraySize) );
  286. return _paArray[iElement]._Element;
  287. }
  288. //+-----------------------------------------------------------------------
  289. //
  290. // Member: InsertElems
  291. //
  292. // Synopsis: Changes the size of the array by using MemRealloc().
  293. // Inserts a number of elements cElems into the array at
  294. // iElem. This can be used to add new elements to the end of
  295. // the array by specifying iElem equal to _cArraySize. It is
  296. // the responsibility of the user to make sure that iElem is
  297. // within the proper bounds of the array, although this will
  298. // be checked during debug mode.
  299. //
  300. // Arguments: iElem place to insert first element
  301. // cElems number of new elements
  302. //
  303. // Returns: Returns success if elements can be added.
  304. // Returns E_OUTOFMEMORY if request cannot be met.
  305. // Array retains its old size if the request cannot be met.
  306. //
  307. template<class TYPE>
  308. HRESULT
  309. TSTDArray<TYPE>::InsertElems(const size_t iElem, const size_t cElems)
  310. {
  311. HRESULT hr = S_OK;
  312. // Note that you can insert past the END of an array (appending to it):
  313. _ASSERT("iElem is too large" &&
  314. (iElem <= _cArraySize) );
  315. if (_cArraySize + cElems > _cAllocSize)
  316. {
  317. // Resize the current array we have:
  318. ULONG cAllocSize = _cAllocSize ? _cAllocSize : 8;
  319. CElem * paArray; // new array
  320. // Double alloc size until it's big enough. This will, I suppose, loop
  321. // forever if someone asks to allocate more than 2^31 elements.
  322. _ASSERT(_cArraySize + cElems < MAXLONG);
  323. while (_cArraySize + cElems > cAllocSize) cAllocSize <<= 1;
  324. paArray = (CElem *)CoTaskMemRealloc(_paArray, sizeof(CElem) * cAllocSize);
  325. if (!paArray)
  326. {
  327. hr = E_OUTOFMEMORY;
  328. goto Error;
  329. }
  330. _paArray = paArray;
  331. _cAllocSize = cAllocSize;
  332. }
  333. IsValidObject();
  334. // Now we have to shift elements to allow space for the new elements:
  335. memmove(_paArray + iElem + cElems, // dest
  336. _paArray + iElem,
  337. (_cArraySize - iElem) * sizeof(CElem));
  338. // Call constructors on all new elements:
  339. {
  340. CElem *pTemp; // index used to call constructors
  341. for (pTemp = _paArray + iElem;
  342. pTemp < _paArray + iElem + cElems;
  343. pTemp++)
  344. {
  345. new (pTemp) CElem;
  346. #if DBG == 1
  347. _cNumElems++;
  348. #endif
  349. }
  350. }
  351. _cArraySize += cElems;
  352. Error:
  353. return hr;
  354. }
  355. //+-----------------------------------------------------------------------
  356. //
  357. // Member: DeleteElems
  358. //
  359. // Synopsis: Deletes a number of elements cElems from the array at
  360. // iElem. It is the responsibility of the user to make sure
  361. // that the region to be deleted is within the proper bounds
  362. // of the array, although this will be checked during
  363. // debug mode.
  364. //
  365. // Arguments: iElem place to delete first element
  366. // cElems number of elements to delete
  367. //
  368. // Returns: Returns success.
  369. //
  370. template<class TYPE>
  371. void
  372. TSTDArray<TYPE>::DeleteElems(const size_t iElem, const size_t cElems)
  373. {
  374. IsValidObject();
  375. _ASSERT("Region to delete is too large" &&
  376. (iElem+cElems-1 < _cArraySize) );
  377. // First we need to call destructors on elements:
  378. {
  379. CElem *pTemp; // index used to call destructors
  380. for (pTemp = _paArray + iElem;
  381. pTemp < _paArray + iElem + cElems;
  382. pTemp++)
  383. {
  384. pTemp->CElem::~CElem();
  385. #if DBG == 1
  386. _cNumElems--;
  387. #endif
  388. }
  389. }
  390. // Now we need to shift the remaining elements in:
  391. memmove(_paArray + iElem, // dest
  392. _paArray + iElem + cElems,
  393. (_cArraySize - (iElem + cElems)) * sizeof(CElem));
  394. _cArraySize -= cElems;
  395. }
  396. #endif // _TARRAY_H_