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.

445 lines
14 KiB

  1. /*************************************************************************
  2. * *
  3. * DYNARRAY.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1994-1995 *
  6. * All Rights reserved. *
  7. * *
  8. * This library implements a robust dynamic array scheme. It replaces the *
  9. * old DRG structure and should probably also replace the MR. *
  10. * The total size of the array is NOT limited to 64K since it uses *
  11. * Binh's threaded block memory manager to add new elements. Therefore it *
  12. * should work correctly on both 16- and 32-bit platforms for any number *
  13. * of elements. *
  14. * * *
  15. * Items in the array are assumed to be of a fixed size, which is defined *
  16. * when the array is first initialized. To speed up the common operation *
  17. * of forward enumeration, the next element function/macro is provided. *
  18. * * *
  19. * There are two types of lists possible: normal, and single-block *
  20. * Use single-block for better space and possible more efficient time *
  21. * usage when you know that your entire array will fit within a block. *
  22. * Allocations beyond the one block limit will return NULL. *
  23. * * *
  24. * The first member of any element in the array MUST be an LPVOID. * *
  25. * UNIMPLEMENTED: Insert into, delete *
  26. **************************************************************************
  27. * *
  28. **************************************************************************
  29. * *
  30. * Written By : KevynCT *
  31. * Current Owner: KevynCT *
  32. * *
  33. **************************************************************************/
  34. #include <mvopsys.h>
  35. #include <orkin.h>
  36. #include <mem.h>
  37. #include <_mvutil.h>
  38. #include <dynarray.h>
  39. #ifdef _DEBUG
  40. static BYTE NEAR s_aszModule[] = __FILE__;
  41. #endif
  42. #define DYN_ARRAY_IS_SINGLEBLOCK(lpdl) ((lpdl)->dwFlags & DYN_ARRAY_SINGLEBLOCK)
  43. #define DYN_ARRAY_SINGLEBLOCK_NEXT(lpdl, lpFoo) (((LPBYTE)lpFoo) + ((lpdl)->cbFoo))
  44. #define DYN_ARRAY_SIZEOF_NEXT(lpdl) ( DYN_ARRAY_IS_SINGLE_BLOCK(lpdl) ? 0: sizeof(LPVOID))
  45. #define NEXT_POINTER(lpFoo) (*(LPVOID FAR *)(lpFoo))
  46. /// These are macros defined in the include file
  47. /*************************************************************************
  48. * @doc INTERNAL RETRIEVAL
  49. *
  50. * @func DWORD | DynArrayGetNumElts |
  51. * Return the number of elements currently in the list
  52. *
  53. * @parm LPDL | lpdl |
  54. * Pointer to DynArray struct
  55. *
  56. * @rdesc None
  57. *
  58. * @comm
  59. *
  60. * Probably a macro
  61. *************************************************************************/
  62. /*************************************************************************
  63. * @doc INTERNAL RETRIEVAL
  64. *
  65. * @func LPVOID | DynArrayGetFirstElt |
  66. * Return a pointer to the head of the list
  67. *
  68. * @parm LPDL | lpdl |
  69. * Pointer to DynArray struct
  70. *
  71. * @rdesc
  72. *
  73. * @comm
  74. *
  75. * Probably a macro
  76. *************************************************************************/
  77. /*************************************************************************
  78. * @doc INTERNAL RETRIEVAL
  79. *
  80. * @func LPVOID | DynArrayGetCurElt |
  81. * Returns the "current" element in the list
  82. *
  83. * @parm LPDL | lpdl |
  84. * Pointer to DynArray struct
  85. *
  86. * @rdesc A valid pointer, or NULL if no current element has been set
  87. *
  88. * @comm
  89. * Any operation ending in "Elt" will set the current elt pointer
  90. * Probably a macro
  91. *************************************************************************/
  92. /*************************************************************************
  93. * @doc INTERNAL RETRIEVAL
  94. *
  95. * @func VOID | DynArraySetCurElt |
  96. * Set the "current" element in the list
  97. *
  98. * @parm LPDL | lpdl |
  99. * Pointer to DynArray struct
  100. * LPVOID | lpvo |
  101. * Pointer to a valid list element returned by one of the other
  102. * element functions.
  103. *
  104. * @rdesc None
  105. *
  106. * @comm
  107. * Probably a macro
  108. *
  109. *************************************************************************/
  110. #ifdef SINGLE_BLOCK
  111. BOOL PASCAL FAR DynArraySingleBlockInit(LPDL lpdl, DWORD BlockSize, WORD wElemSize, DWORD dwFlags)
  112. {
  113. if (lpdl && BlockSize && wElemSize)
  114. {
  115. MEMSET(lpdl, 0, sizeof(DL));
  116. // single-block linked list
  117. if (lpdl->lpBlockHead = BlockInitiate (BlockSize, wElemSize, 1, 0))
  118. {
  119. lpdl->lpFooHead = BlockGetElement(lpdl->lpBlockHead);
  120. lpdl->lpFooFree = lpdl->lpFooHead;
  121. lpdl->cbFoo = wElemSize;
  122. lpdl->cFooPerBlock = BLOCKMGR_BLOCKSIZE(lpdl->lpBlockHead) / wElemSize;
  123. lpdl->dwFlags = dwFlags | DYN_ARRAY_SINGLEBLOCK;
  124. return TRUE;
  125. }
  126. }
  127. return FALSE;
  128. }
  129. #endif
  130. /*************************************************************************
  131. * @doc INTERNAL RETRIEVAL
  132. *
  133. * @func BOOL PASCAL FAR | DynArrayInit |
  134. * Initializes the given DynArray struct to prepare the DynArray for use.
  135. *
  136. * @parm LPDL | lpdl |
  137. * Pointer to uninitialized DynArray struct
  138. *
  139. * DWORD | BlockSize |
  140. * The size of each block in bytes
  141. *
  142. * WORD | cMaxBlock |
  143. * The maximum number of blocks to be allowed
  144. *
  145. * WORD | wElemSize |
  146. * The fixed size of each element of the array
  147. *
  148. * DWORD | dwFlags |
  149. * Specifies attributes of the list
  150. *
  151. * @rdesc TRUE if successful, NULL otherwise
  152. *
  153. * @comm
  154. *
  155. *
  156. *************************************************************************/
  157. BOOL PASCAL FAR DynArrayInit(LPDL lpdl, DWORD BlockSize, WORD cMaxBlock, WORD wElemSize, DWORD dwFlags)
  158. {
  159. if (lpdl && BlockSize && wElemSize && cMaxBlock)
  160. {
  161. MEMSET(lpdl, 0, sizeof(DL));
  162. if (lpdl->lpBlockHead = BlockInitiate (BlockSize, wElemSize, cMaxBlock, 0))
  163. {
  164. lpdl->lpFooHead = NULL;
  165. lpdl->lpFooFree = lpdl->lpFooHead;
  166. lpdl->cbFoo = wElemSize;
  167. lpdl->cFooPerBlock = (WORD) BLOCKMGR_BLOCKSIZE(lpdl->lpBlockHead) / wElemSize;
  168. lpdl->dwFlags = dwFlags;
  169. return TRUE;
  170. }
  171. }
  172. return FALSE;
  173. }
  174. #ifdef SINGLE_BLOCK
  175. LPVOID PASCAL FAR DynArraySingleBlockAppendElt(lpdl)
  176. {
  177. Assert(lpdl);
  178. Assert(lpdl->lpFooFree);
  179. Assert(lpdl->dwFlags & DYN_ARRAY_SINGLEBLOCK);
  180. lpdl->lpFooCache = lpdl->lpFooFree;
  181. lpdl->lpFooFree = BlockGetElement(lpdl->lpBlockHead);
  182. lpdl->cFoo++;
  183. return lpFoo->lpFooCache;
  184. }
  185. #endif
  186. /*************************************************************************
  187. * @doc INTERNAL RETRIEVAL
  188. *
  189. * @func LPVOID PASCAL FAR | DynArrayAppendElt |
  190. * Appends a new element to the end of the list
  191. *
  192. * @parm LPDL | lpdl |
  193. * Pointer to DynArray struct
  194. *
  195. * @rdesc Returns a pointer to the newly created elt, or NULL on failure
  196. *
  197. * @comm
  198. *
  199. *
  200. *************************************************************************/
  201. LPVOID PASCAL FAR DynArrayAppendElt(LPDL lpdl)
  202. {
  203. LPVOID lpFooNext;
  204. Assert(lpdl);
  205. // Assert(lpdl->lpFooFree);
  206. // lpFooFree is always non-NULL and points to the next free element in the list. if this will be the last element in
  207. // a block, then lpFooFree->lpNext will be NULL, and we will need to allocate the next block and link it into the list
  208. if (lpFooNext = BlockGetElement(lpdl->lpBlockHead))
  209. {
  210. if (!lpdl->lpFooHead)
  211. {
  212. lpdl->lpFooHead = lpFooNext;
  213. lpdl->lpFooFree = lpFooNext;
  214. }
  215. else
  216. {
  217. NEXT_POINTER(lpdl->lpFooFree) = lpFooNext;
  218. }
  219. lpdl->lpFooFree = lpFooNext;
  220. lpdl->lpFooCache = lpdl->lpFooFree;
  221. lpdl->cFoo++;
  222. NEXT_POINTER(lpdl->lpFooFree) = NULL;
  223. return lpdl->lpFooCache;
  224. }
  225. return NULL;
  226. }
  227. #ifdef SINGLE_BLOCK
  228. INLINE LPVOID PASCAL FAR DynArraySingleBlockGetOrdinalElt(LPDL lpdl, DWORD dwEltIndex)
  229. {
  230. LPVOID lpv;
  231. Assert(lpdl);
  232. Assert(lpdl->dwFlags & DYN_ARRAY_SINGLEBLOCK);
  233. if (dwEltIndex < lpdl->cFoo)
  234. {
  235. return (((LPBYTE)lpdl->lpFooHead) + (dwEltIndex % lpdl->cFooPerBlock) * lpdl->cbFoo);
  236. }
  237. return NULL;
  238. }
  239. #endif
  240. /*************************************************************************
  241. * @doc INTERNAL RETRIEVAL
  242. *
  243. * @func LPVOID PASCAL FAR | DynArrayGetOrdinalElt |
  244. * Retrieve pointer to the start of i-th element in the list (starting at zero)
  245. *
  246. * @parm LPDL | lpdl |
  247. * Pointer to DynArray struct
  248. * DWORD | dwEltIndex |
  249. * Index of element to retrieve
  250. *
  251. * @rdesc Pointer to elt if successful, NULL otherwise
  252. *
  253. * @comm
  254. * Finds N-th element in the linked list. Zero is first element
  255. * Use this only if the list was NOT created insertable, i.e. append-only
  256. *
  257. *************************************************************************/
  258. LPVOID PASCAL FAR DynArrayGetOrdinalElt(LPDL lpdl, DWORD dwEltIndex)
  259. {
  260. LPBYTE lpb;
  261. Assert(lpdl);
  262. if (dwEltIndex < lpdl->cFoo)
  263. {
  264. // the faster way: calc the block number and the offset within the block, and go directly there.
  265. if (lpb = BlockGetOrdinalBlock(lpdl->lpBlockHead, (WORD)(dwEltIndex / lpdl->cFooPerBlock)))
  266. return (lpdl->lpFooCache = (lpb + (dwEltIndex % lpdl->cFooPerBlock) * lpdl->cbFoo));
  267. }
  268. return NULL;
  269. }
  270. #if 0
  271. /*************************************************************************
  272. * @doc INTERNAL RETRIEVAL
  273. *
  274. * @func LPVOID PASCAL FAR | DynArrayInsertableGetElt |
  275. * Retrieve pointer to the start of i-th element in the list (starting at zero)
  276. *
  277. * @parm LPDL | lpdl |
  278. * Pointer to DynArray struct
  279. * DWORD | dwEltIndex |
  280. * Index of element to retrieve
  281. *
  282. * @rdesc Pointer to elt if successful, NULL otherwise
  283. *
  284. * @comm
  285. * Finds N-th element in the linked list. Zero is first element
  286. * Use this only if the list was NOT created insertable, i.e. append-only
  287. *
  288. *************************************************************************/
  289. LPVOID PASCAL FAR DynInsertableListGetElt(LPDL lpdl, DWORD dwEltIndex)
  290. {
  291. LPVOID lpv;
  292. Assert(lpdl);
  293. // need to find it the long way since pointers may no longer be contiguous within a block after an insertion.
  294. for (lpv = lpdl->lpFooHead; dwEltIndex && lpv; lpv = NEXT_POINTER(lpThis), dwEltIndex--)
  295. ;
  296. if (lpv) lpdl->lpFooCache = lpv;
  297. return lpv;
  298. }
  299. #endif
  300. #ifdef SINGLE_BLOCK
  301. INLINE LPVOID PASCAL FAR DynArraySingleBlockNextElt(LPDL lpdl)
  302. {
  303. Assert(lpdl);
  304. Assert(lpdl->lpFooCache);
  305. Assert(lpdl->dwFlags & DYN_ARRAY_SINGLEBLOCK);
  306. return (lpdl->lpFooCache = DYN_ARRAY_SINGLEBLOCK_NEXT(lpdl, lpdl->lpFooCache));
  307. }
  308. #endif
  309. #if 0
  310. /*************************************************************************
  311. * @doc INTERNAL RETRIEVAL
  312. *
  313. * @func LPVOID PASCAL FAR | DynArrayNextElt |
  314. * Get next element in list after the current one.
  315. *
  316. * @parm LPDL | lpdl |
  317. * Pointer to DynArray struct
  318. *
  319. * @rdesc Pointer to elt if successful, NULL otherwise
  320. *
  321. * @comm
  322. * Responsibility of caller to know when current element is NULL
  323. * This function will execute quickly.
  324. *
  325. *************************************************************************/
  326. _inline LPVOID PASCAL FAR DynArrayNextElt(LPDL lpdl)
  327. {
  328. Assert(lpdl);
  329. Assert(lpdl->lpFooCache);
  330. return (lpdl->lpFooCache = NEXT_POINTER(lpdl->lpFooCache));
  331. }
  332. #endif
  333. #if 1
  334. /*************************************************************************
  335. * @doc INTERNAL RETRIEVAL
  336. *
  337. * @func LPVOID PASCAL FAR | DynArrayClearElt |
  338. * Zero-inits the current element, but does not harm NEXT link of the elt.
  339. *
  340. * @parm LPDL | lpdl |
  341. * Pointer to DynArray struct
  342. *
  343. * @rdesc Pointer to current element if there is one, NULL otherwise.
  344. *
  345. * @comm
  346. *
  347. *
  348. *************************************************************************/
  349. LPVOID PASCAL FAR DynArrayClearElt(LPDL lpdl)
  350. {
  351. Assert(lpdl);
  352. if (lpdl->lpFooCache)
  353. {
  354. MEMSET((LPBYTE)(lpdl->lpFooCache) + sizeof(LPVOID), 0, lpdl->cbFoo - sizeof(LPVOID));
  355. return lpdl->lpFooCache;
  356. }
  357. return NULL;
  358. }
  359. #endif
  360. /*************************************************************************
  361. * @doc INTERNAL RETRIEVAL
  362. *
  363. * @func VOID PASCAL FAR | DynArrayFree |
  364. * Free any memory that was allocated for the given dynlist over the
  365. * course of its life.
  366. *
  367. * @parm LPDL | lpdl |
  368. * Pointer to uninitialized DynArray struct
  369. *
  370. * @rdesc None
  371. *
  372. * @comm
  373. *
  374. *
  375. *************************************************************************/
  376. VOID PASCAL FAR DynArrayFree(LPDL lpdl)
  377. {
  378. Assert(lpdl);
  379. BlockFree(lpdl->lpBlockHead);
  380. MEMSET(lpdl, 0, sizeof(DL));
  381. }
  382. /*************************************************************************
  383. * @doc INTERNAL RETRIEVAL
  384. *
  385. * @func VOID PASCAL FAR | DynArrayReset |
  386. * Pretend we never added any elements to this list, but don't free mem.
  387. *
  388. * @parm LPDL | lpdl |
  389. * Pointer to uninitialized DynArray struct
  390. *
  391. * @rdesc None
  392. *
  393. * @comm
  394. *
  395. *
  396. *************************************************************************/
  397. VOID PASCAL FAR DynArrayReset(LPDL lpdl)
  398. {
  399. Assert(lpdl);
  400. BlockReset(lpdl->lpBlockHead);
  401. lpdl->lpFooHead = NULL;
  402. lpdl->lpFooFree = lpdl->lpFooHead;
  403. lpdl->cFoo = 0;
  404. }
  405. // UNIMPLEMENTED: DELETE and INSERT