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.

301 lines
8.0 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * dynarray.hpp
  8. *
  9. * Abstract:
  10. *
  11. * Dynamic array template classes. See DynamicArrays.doc in the Specs
  12. * directory.
  13. *
  14. * DynArray is a container which keeps its contents in a contiguous buffer,
  15. * reallocating memory as necessary. It accepts an optional initial
  16. * allocation, which is used unless it is too small to accommodate the
  17. * elements.
  18. *
  19. * DynArrayIA is a cosmetic wrapper which encapsulates the intial allocation,
  20. * allowing the dynamic array to be treated like a normal class.
  21. *
  22. * Revision History:
  23. *
  24. * 12/02/1998 davidx
  25. * Created it.
  26. * 02/26/1999 agodfrey
  27. * Revamped it to use an implementation class (DynArrayImpl).
  28. * Now the template part of it can compile to nothing, or be small enough
  29. * to inline efficiently, so that using the template with many different
  30. * types doesn't cause code bloat.
  31. *
  32. * Also, I added a version (DynArrayIA) which makes using an initial
  33. * allocation much easier.
  34. *
  35. * Notes:
  36. *
  37. * 12/02/1998 davidx
  38. * Changes from the previous version in gdiplus prototype:
  39. * + getData: Use &dynarr[index] instead.
  40. * + increaseCount: Use addMultiple instead (2nd variation).
  41. * + replace: Use dynarr[index] = newItem.
  42. * + attachData: Use dynarr.replaceWith(dynarr2).
  43. * + constructor: No longer takes initialCapacity, use ReserveSpace instead
  44. * + new constructor: Takes a stack array which is used for buffer (faster).
  45. *
  46. * 02/26/1999 agodfrey
  47. * + Use the 'implementation class' to avoid code bloat for out-of-line
  48. * functions.
  49. * + GetCapacity: Unused, not useful - removed.
  50. * + Reset: Added 'shrink' flag (default true). If it's false, Reset sets the
  51. * count to zero but doesn't free the memory. This is preferable to
  52. * SetCount(0).
  53. * + Made ShrinkToSize() reuse the initial allocation. This also makes the
  54. * growing and shrinking logic simpler - 'no initial allocation' is treated
  55. * like an initial allocation of size zero (at memory location 'NULL').
  56. *
  57. \**************************************************************************/
  58. #ifndef _DYNARRAY_HPP
  59. #define _DYNARRAY_HPP
  60. template <class T> class DynArray : public DynArrayImpl
  61. {
  62. public:
  63. // Default allocation step size
  64. enum
  65. {
  66. DEFAULT_STEPSIZE = 512
  67. };
  68. // Constructor
  69. //
  70. // initalAllocation - the initial allocation, which can be global,
  71. // static or dynamic memory (or NULL)
  72. // allocSize - size of the initial allocation
  73. // (0 if there is none)
  74. // stepSize - number of elements added each time the buffer grows
  75. DynArray(
  76. T *initialAllocation,
  77. UINT allocSize,
  78. UINT stepSize = DEFAULT_STEPSIZE
  79. ):
  80. DynArrayImpl(initialAllocation, allocSize, stepSize)
  81. {
  82. }
  83. // Constructor (no initial allocation)
  84. //
  85. // stepSize - number of elements added each time the buffer grows
  86. DynArray(UINT stepSize = DEFAULT_STEPSIZE):
  87. DynArrayImpl(NULL, 0, stepSize)
  88. {
  89. }
  90. // Destructor
  91. ~DynArray()
  92. {
  93. if (DataBuffer != InitialAllocation)
  94. {
  95. GpFree(DataBuffer);
  96. }
  97. }
  98. // Change the step size to the specified value
  99. VOID SetStepSize(UINT stepSize = DEFAULT_STEPSIZE)
  100. {
  101. ASSERT(stepSize > 0);
  102. StepSize = stepSize;
  103. }
  104. // Return a pointer to the array data
  105. // NOTE: We intentionally avoid type conversion operator here
  106. // to reduce the chances for confusion.
  107. T *GetDataBuffer() const
  108. {
  109. return static_cast<T *>(DataBuffer);
  110. }
  111. // Index operator
  112. T &operator[](INT n) const
  113. {
  114. ASSERT(n >= 0 && (UINT)n < Count);
  115. return GetDataBuffer()[n];
  116. }
  117. // First/last element of the array
  118. T &First() const
  119. {
  120. ASSERT(Count > 0);
  121. return GetDataBuffer()[0];
  122. }
  123. T &Last() const
  124. {
  125. ASSERT(Count > 0);
  126. return GetDataBuffer()[Count-1];
  127. }
  128. // Number of elements in the array
  129. INT GetCount() const
  130. {
  131. return Count;
  132. }
  133. // Reset the dynamic array to empty state
  134. //
  135. // shrink - If FALSE, don't free the current buffer.
  136. VOID Reset(BOOL shrink=TRUE)
  137. {
  138. Count = 0;
  139. if (shrink)
  140. {
  141. ShrinkToSize();
  142. }
  143. }
  144. // Shrink the dynamic array capacity to be just big enough
  145. // for the number of existing elements in the array.
  146. //
  147. // This reuses the initial allocation if possible.
  148. VOID ShrinkToSize()
  149. {
  150. DynArrayImpl::ShrinkToSize(sizeof(T));
  151. }
  152. // Add a new element to the end of the dynamic array
  153. GpStatus Add(const T& newItem)
  154. {
  155. return DynArrayImpl::AddMultiple(sizeof(T), 1, &newItem);
  156. }
  157. // Add multiple items to the end of the dynamic array
  158. GpStatus AddMultiple(const T* newItems, INT n)
  159. {
  160. return DynArrayImpl::AddMultiple(sizeof(T), n, newItems);
  161. }
  162. // Another variation of addMultiple above
  163. //
  164. // In this case, the data for the new elements are
  165. // not available. Instead, we'll do the following:
  166. // (1) reserve the space for additional elements
  167. // (2) increase the Count by the number of additional elements
  168. // (3) return a pointer to the first new elements
  169. T *AddMultiple(INT n)
  170. {
  171. return static_cast<T *>(DynArrayImpl::AddMultiple(sizeof(T), n));
  172. }
  173. // Detach the data buffer from the dynamic array
  174. // Cannot be used if there is an initial allocation
  175. T *DetachData()
  176. {
  177. return static_cast<T *>(DynArrayImpl::DetachData());
  178. }
  179. // Detatch the buffer from another array, and set this array
  180. // to point to it. NOTE: This modifies the other array.
  181. VOID ReplaceWith(DynArray<T> *dynarr)
  182. {
  183. if (DataBuffer != InitialAllocation)
  184. {
  185. GpFree(DataBuffer);
  186. }
  187. Count = dynarr->Count;
  188. Capacity = dynarr->Capacity;
  189. DataBuffer = dynarr->DetachData();
  190. }
  191. // More dangerous interface:
  192. //
  193. // These functions are alternatives to Add/AddMultiple.
  194. // They can be used to reduce overhead, but you have to know what
  195. // you're doing.
  196. //
  197. // AdjustCount/SetCount - modify the count directly, without growing or
  198. // shrinking the array.
  199. // ReserveSpace - grow the buffer, but don't actually add any elements to
  200. // the array.
  201. VOID AdjustCount(UINT addElts)
  202. {
  203. Count += addElts;
  204. }
  205. VOID SetCount(UINT count)
  206. {
  207. Count = count;
  208. }
  209. GpStatus ReserveSpace(UINT newElements)
  210. {
  211. return Grow(sizeof(T), newElements);
  212. }
  213. // !! This is added as a hack to allow bitwise cloning
  214. // of DynArray types.
  215. GpStatus RenewDataBuffer()
  216. {
  217. void *oldDataBuffer = DataBuffer;
  218. void *oldInitialAllocation = InitialAllocation;
  219. InitialAllocation = NULL;
  220. AllocSize = 0;
  221. DataBuffer = (VOID*) malloc(Capacity*sizeof(T));
  222. memcpy(DataBuffer, oldDataBuffer, Capacity*sizeof(T));
  223. return Ok;
  224. }
  225. };
  226. // DynArrayIA: A version of DynArray which encapsulates the initial allocation.
  227. //
  228. // For example:
  229. //
  230. // DynArrayIA<MyType, 10> array(16);
  231. //
  232. // This declares a DynArray of MyType objects, with an initial allocation of
  233. // 10 elements, and a step size of 16. Such a declaration can be used on
  234. // the stack or in another object.
  235. template <class T, int ALLOCSIZE> class DynArrayIA : public DynArray<T>
  236. {
  237. public:
  238. // Constructor
  239. //
  240. // stepSize - number of elements added each time the buffer grows
  241. DynArrayIA(UINT stepSize = DEFAULT_STEPSIZE):
  242. DynArray<T>(InitialAllocationBuffer, ALLOCSIZE, stepSize)
  243. {
  244. }
  245. private:
  246. T InitialAllocationBuffer[ALLOCSIZE];
  247. };
  248. #endif // !_DYNARRAY_HPP