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.

386 lines
17 KiB

  1. /*----------------------
  2. | List |
  3. ----------------------*/
  4. /* Laurie Griffiths, C version 5/12/91 */
  5. /* worth also looking at nt\public\sdk\inc\ntrtl.h which also has some
  6. | low level list pointer chaining stuff in it
  7. */
  8. /* Note here that Modula-2 style comments (*like this*) are used
  9. within examples which are already within C comments to indicate
  10. where comments should go in the examples
  11. */
  12. /*------------------------------------------------------------------------
  13. | Abstract data type LIST OF (*untyped*) object.
  14. | Different lists can have different types of object in them
  15. | Different items in a list can have different types of object in them.
  16. | The price of this lack of typing is that you have a slightly more
  17. | awkward syntax and you get no help from the compiler if you try to
  18. | put the wrong type of data into the list.
  19. |
  20. | The list is implemented as a collection of items. Within the item
  21. | somewhere is the object.
  22. |
  23. | Objects are stored UNALIGNED within items.
  24. |
  25. | Use:
  26. |
  27. | #include <list.h>
  28. | . . .
  29. | LIST MyList; (* or LIST liMyList for Hungarians *)
  30. | . . .
  31. | MyList = List_Create();
  32. | List_AddLast(MyList,&MyObject,sizeof(OBJECT));
  33. |
  34. | In the abstract a LIST is a list of objects. The representation
  35. | is a linked collection of items. The manner of the linking is
  36. | implementation dependent (as I write this it's linear but when you
  37. | read it it might be a tree (See Knuth for why a tree)).
  38. |
  39. | A LIST is a "handle" for a list which may be thought of as a POINTER
  40. | (whether it is really a pointer or not is implementation dependent)
  41. | so that it can be copied at the risk of creating an alias. e.g.
  42. |
  43. | L = List_Create();
  44. | L1 = L; (* L and L1 are both healthy and empty *)
  45. | List_AddFirst(L, &elem, sizeof(elem));
  46. | (* L1 may also appear to have one object, there again it may be sick *)
  47. | L1 = L; (* Now they both surely see the one element *)
  48. | List_Destroy(&L1); (* L is almost certainly sick now too *)
  49. | L1 = List_Create(); (* All bets off as to what L is like now
  50. | but L1 is empty and healthy
  51. | *)
  52. |
  53. | If two handles compare equal then the lists must be equal, but
  54. | unequal handles could address two similar lists i.e. the same list
  55. | of objects held in two different LISTs of items (like pointers).
  56. |
  57. | A LIST can be transferred from one variable to another like this:
  58. |
  59. | NewList = OldList; (* copy the handle *)
  60. | OldList = List_Create(); (* kill the old alias *)
  61. |
  62. | and the Create statement can be omitted if OldList is never touched again.
  63. |
  64. | Items are identified by Cursors. A cursor is the address of an object
  65. | within an item in the list. i.e. it is the address of the piece of your
  66. | data that you had inserted. (It is probably NOT the address of the item).
  67. | It is typed as pointer to void here, but you should declare it as a pointer
  68. | to whatever sort of object you are putting in the LIST.
  69. |
  70. | The operations AddFirst, AddLast, AddAfter and AddBefore
  71. | all copy elements by direct assignment. If an element is itself
  72. | a complex structure (say a tree) then this will only copy a pointer
  73. | or an anchor block or whatever and give all the usual problems of
  74. | aliases. Clear will make the list empty, but will only free the
  75. | storage that it can "see" directly. SplitBefore or Split After may
  76. | also perform a Clear operation. To deal with fancy data structures
  77. | use New rather than Add calls and copy the data yourself
  78. | e.g. P = List_NewLast(MyList, sizeof(MyArray[14])*(23-14+1));
  79. | CopyArraySlice(P, MyArray, 14, 23);
  80. |
  81. | The operations NewFirst, NewLast, NewAfter, NewBefore, First and Last
  82. | all return pointers to elements and thus allow you to do any copying.
  83. | This is how you might copy a whole list of fancy structures:
  84. |
  85. | void CopyFancyList(LIST * To, LIST From)
  86. | (* Assumes that To has been Created and is empty *)
  87. | { PELEMENT Cursor;
  88. | PELEMENT P;
  89. |
  90. | List_TRAVERSE(From, Cursor);
  91. | { P = List_NewLast(To, sizeof(element) );
  92. | FancyCopy(P, Cursor); (* Copy so that *Cursor==*P afterwords *)
  93. | }
  94. | }
  95. --------------------------------------------------------------------*/
  96. typedef struct item_tag FAR * LIST;
  97. typedef LIST FAR * PLIST;
  98. void APIENTRY List_Init(void);
  99. /* MUST BE CALLED BEFORE ANY OF THE OTHER FUNCTIONS. Don't ask, just do it */
  100. void APIENTRY List_Term(void);
  101. /* Call at end of application (does some checking and resource freeing) */
  102. void APIENTRY List_Dump(LPSTR Header, LIST lst);
  103. /* Dump the internals to current output stream -- debug only */
  104. void APIENTRY List_Show(LIST lst);
  105. /* Dump hex representation of handle to current out stream -- debug only */
  106. LIST APIENTRY List_Create(void);
  107. /* Create a list. It will be initially empty */
  108. void APIENTRY List_Destroy(PLIST plst);
  109. /* Destroy *plst. It does not need to be empty first.
  110. | All storage directly in the list wil be freed.
  111. */
  112. void APIENTRY List_AddFirst(LIST lst, LPVOID pObject, UINT uLen);
  113. /* Add an item holding Object to the beginning of * plst */
  114. LPVOID APIENTRY List_NewFirst(LIST lst, UINT uLen);
  115. /* Return the address of the place for Len bytes of data in a new
  116. | item at the start of *plst.
  117. | The storage is zeroed BEFORE chaining it in.
  118. */
  119. void APIENTRY List_DeleteFirst(LIST lst);
  120. /* Delete the first item in lst. Error if lst is empty */
  121. void APIENTRY List_AddLast(LIST lst, LPVOID pObject, UINT uLen);
  122. /* Add an item holding Object to the end of lst */
  123. LPVOID APIENTRY List_NewLast(LIST lst, UINT uLen);
  124. /* Return the address of the place for uLen bytes of data in a new
  125. | item at the end of lst
  126. | The storage is zeroed BEFORE chaining it in.
  127. */
  128. void APIENTRY List_DeleteLast(LIST lst);
  129. /* Delete the last item in lst. Error if lst is empty */
  130. void APIENTRY List_AddAfter( LIST lst
  131. , LPVOID Curs
  132. , LPVOID pObject
  133. , UINT uLen
  134. );
  135. /*--------------------------------------------------------------------
  136. | Add an item holding *pObject to lst immediately after Curs.
  137. | List_AddAfter(lst, NULL, pObject, Len) adds it to the start of the lst
  138. ---------------------------------------------------------------------*/
  139. LPVOID APIENTRY List_NewAfter(LIST lst, LPVOID Curs, UINT uLen);
  140. /*--------------------------------------------------------------------
  141. | Return the address of the place for uLen bytes of data in a new
  142. | item immediately after Curs.
  143. | List_NewAfter(Lst, NULL, uLen) returns a pointer
  144. | to space for uLen bytes in a new first element.
  145. | The storage is zeroed BEFORE chaining it in.
  146. ---------------------------------------------------------------------*/
  147. void APIENTRY List_AddBefore( LIST lst
  148. , LPVOID Curs
  149. , LPVOID pObject
  150. , UINT uLen
  151. );
  152. /*--------------------------------------------------------------------
  153. | Add an item holding Object to lst immediately before Curs.
  154. | List_AddBefore(Lst, NULL, Object, uLen) adds it to the end of the list
  155. ---------------------------------------------------------------------*/
  156. LPVOID APIENTRY List_NewBefore(LIST lst, LPVOID Curs, UINT uLen );
  157. /*--------------------------------------------------------------------
  158. | Return the address of the place for uLen bytes of data in a new
  159. | item immediately before Curs.
  160. | List_NewBefore(Lst, NULL, uLen) returns a pointer
  161. | to space for uLen bytes in a new last element.
  162. | The storage is zeroed BEFORE chaining it in.
  163. ---------------------------------------------------------------------*/
  164. #if 0
  165. // these functions are not actually defined...
  166. void APIENTRY List_DeleteAndNext(LPVOID * pCurs);
  167. /* Delete the item that *pCurs identifies and move *pCurs to the Next item */
  168. void APIENTRY List_DeleteAndPrev(LPVOID * pCurs);
  169. /* Delete the item that *pCurs identifies and move *pCurs to the Prev item */
  170. #endif
  171. void APIENTRY List_Delete(LPVOID Curs);
  172. /*------------------------------------------------------------------
  173. | Delete the item that Curs identifies.
  174. | I'm not too sure about this:
  175. | This will be only a few (maybe as little as 3) machine instructions
  176. | quicker than DeleteAndNext or DeleteAndPrev but leaves Curs dangling.
  177. | It is therefore NOT usually to be preferred.
  178. | It may be useful when you have a function which returns an LPVOID
  179. | since the argument does not need to be a variable.
  180. | Trivial example: List_Delete(List_First(L));
  181. | I am not sure which is more damaging, a dangling pointer which points
  182. | at garbage or one that points at something that is real live data.
  183. -------------------------------------------------------------------*/
  184. int APIENTRY List_ItemLength(LPVOID Curs);
  185. /* Return the length of the object identified by the cursor Curs */
  186. /*------------------------------------------------------------------
  187. | TRAVERSING THE ULIST
  188. |
  189. | LIST lst;
  190. | object * Curs;
  191. | . . .
  192. | Curs = List_First(lst);
  193. | while (Curs!=NULL)
  194. | { DoSomething(*Curs); (* Curs points to YOUR data not to chain ptrs *)
  195. | Curs = List_Next(Curs);
  196. | }
  197. |
  198. | This is identically equal to
  199. | List_TRAVERSE(lst, Curs) // note NO SEMI COLON!
  200. | { DoSomething(*Curs); }
  201. -------------------------------------------------------------------*/
  202. #define List_TRAVERSE(lst, curs) for( curs=List_First(lst) \
  203. ; curs!=NULL \
  204. ; curs = List_Next((LPVOID)curs) \
  205. )
  206. #define List_REVERSETRAVERSE(lst, curs) for( curs=List_Last(lst) \
  207. ; curs!=NULL \
  208. ; curs = List_Prev((LPVOID)curs) \
  209. )
  210. LPVOID APIENTRY List_First(LIST lst);
  211. /*------------------------------------------------------------------
  212. | Return the address of the first object in lst
  213. | If lst is empty then Return NULL.
  214. --------------------------------------------------------------------*/
  215. LPVOID APIENTRY List_Last(LIST lst);
  216. /*------------------------------------------------------------------
  217. | Return the address of the last object in lst
  218. | If lst is empty then return NULL.
  219. --------------------------------------------------------------------*/
  220. LPVOID APIENTRY List_Next(LPVOID Curs);
  221. /*------------------------------------------------------------------
  222. | Return the address of the object after Curs^.
  223. | List_Next(List_Last(lst)) == NULL; List_Next(NULL) is an error.
  224. | List_Next(List_Prev(curs)) is illegal if curs identifies first el
  225. --------------------------------------------------------------------*/
  226. LPVOID APIENTRY List_Prev(LPVOID Curs);
  227. /*------------------------------------------------------------------
  228. | Return the address of the object after Curs^.
  229. | List_Prev(List_First(L)) == NULL; List_Prev(NULL) is an error.
  230. | List_Prev(List_Next(curs)) is illegal if curs identifies last el
  231. --------------------------------------------------------------------*/
  232. /*------------------------------------------------------------------
  233. | Whole list operations
  234. -----------------------------------------------------------------*/
  235. void APIENTRY List_Clear(LIST lst);
  236. /* arrange that lst is empty after this */
  237. BOOL APIENTRY List_IsEmpty(LIST lst);
  238. /* Return TRUE if and only if lst is empty */
  239. void APIENTRY List_Join(LIST l1, LIST l2);
  240. /*-----------------------------------------------------------------------
  241. | l1 := l1||l2; l2 := empty
  242. | The elements themselves are not moved, so pointers to them remain valid.
  243. |
  244. | l1 gets all the elements of l1 in their original order followed by
  245. | all the elements of l2 in the order they were in in l2.
  246. | l2 becomes empty.
  247. ------------------------------------------------------------------------*/
  248. void APIENTRY List_InsertListAfter(LIST l1, LIST l2, LPVOID Curs);
  249. /*-----------------------------------------------------------------------
  250. | l1 := l1[...Curs] || l2 || l1[Curs+1...]; l2 := empty
  251. | Curs=NULL means insert l2 at the start of l1
  252. | The elements themselves are not moved, so pointers to them remain valid.
  253. |
  254. | l1 gets the elements of l1 from the start up to and including the element
  255. | that Curs points at, in their original order,
  256. | followed by all the elements that were in l2, in their original order,
  257. | followed by the rest of l1
  258. ------------------------------------------------------------------------*/
  259. void APIENTRY List_InsertListBefore(LIST l1, LIST l2, LPVOID Curs);
  260. /*-----------------------------------------------------------------------
  261. | l1 := l1[...Curs-1] || l2 || l1[Curs...]; l2 := empty
  262. | Curs=NULL means insert l2 at the end of l1
  263. | The elements themselves are not moved, so pointers to them remain valid.
  264. |
  265. | l1 gets the elements of l1 from the start up to but not including the
  266. | element that Curs points at, in their original order,
  267. | followed by all the elements that were in l2, in their original order,
  268. | followed by the rest of l1.
  269. ------------------------------------------------------------------------*/
  270. void APIENTRY List_SplitAfter(LIST l1, LIST l2, LPVOID Curs);
  271. /*-----------------------------------------------------------------------
  272. | Let l1 be l1 and l2 be l2
  273. | Split l2 off from the front of l1: final l2,l1 = original l1
  274. |
  275. | Split l1 into l2: objects of l1 up to and including Curs object
  276. | l1: objects of l1 after Curs
  277. | Any original contents of l2 are freed.
  278. | List_Spilt(l1, l2, NULL) splits l1 before the first object so l1 gets all.
  279. | The elements themselves are not moved.
  280. ------------------------------------------------------------------------*/
  281. void APIENTRY List_SplitBefore(LIST l1, LIST l2, LPVOID Curs);
  282. /*----------------------------------------------------------------------
  283. | Split l2 off from the back of l1: final l1,l2 = original l1
  284. |
  285. | Split l1 into l1: objects of l1 up to but not including Curs object
  286. | l2: objects of l1 from Curs onwards
  287. | Any original contants of l2 are freed.
  288. | List_Spilt(l1, l2, NULL) splits l1 after the last object so l1 gets all.
  289. | The elements themselves are not moved.
  290. -----------------------------------------------------------------------*/
  291. int APIENTRY List_Card(LIST lst);
  292. /* Return the number of items in L */
  293. /*------------------------------------------------------------------
  294. | Error handling.
  295. |
  296. | Each list has within it a flag which indicates whether any illegal
  297. | operation has been detected (e.g. DeleteFirst when empty).
  298. | Rather than have a flag on every operation, there is a flag held
  299. | within the list that can be queried when convenient. Many operations
  300. | do not have enough redundancy to allow any meaningful check. This
  301. | is a design compromise (for instance to allow P = List_Next(P);
  302. | rather than P = List_Next(L, P); which is more awkward, especially
  303. | if L is actually a lengthy phrase).
  304. |
  305. | List_IsOK tests this flag (so is a very simple, quick operation).
  306. | MakeOK sets the flag to TRUE, in other words to accept the current
  307. | state of the list.
  308. |
  309. | It is possible for a list to be damaged (whether or not the flag
  310. | says OK) for instance by the storage being overwritten.
  311. |
  312. | List_Check attempts to verify that the list is sound (for instance where
  313. | there are both forward and backward pointers they should agree).
  314. |
  315. | List_Recover attempts to make a sound list out of whatever debris is left.
  316. | If the list is damaged, Recover may trap (e.g. address error) but
  317. | if the list was damaged then ANY operation on it may trap.
  318. | If Check succeeds without trapping then so will Recover.
  319. -----------------------------------------------------------------*/
  320. BOOL APIENTRY List_IsOK(LIST lst);
  321. /* Check return code */
  322. void APIENTRY List_MakeOK(LIST lst);
  323. /* Set return code to good */
  324. BOOL APIENTRY List_Check(LIST lst);
  325. /* Attempt to validate the chains */
  326. void APIENTRY List_Recover(PLIST plst);
  327. /* Desperate stuff. Attempt to reconstruct something */
  328. /*------------------------------------------------------------------
  329. | It is designed to be as easy to USE as possible, consistent
  330. | only with being an opaque type.
  331. |
  332. | In particular, the decision to use the address of an object a list cursor
  333. | means that there is a small amount of extra arithmetic (in the
  334. | IMPLEMENTATION) in cursor operations (e.g. Next and Prev).
  335. | and spurious arguments are avoided whenever possible, even though
  336. | it would allow greater error checking.
  337. |
  338. | Of the "whole list" operations, Clear is given because it seems to be
  339. | a common operation, even though the caller can implement it with almost
  340. | the same efficiency as the List implementation module.
  341. | Join, Split and InsertListXxx cannot be implemented efficiently without
  342. | knowing the representation.
  343. --------------------------------------------------------------------*/