home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / list.h < prev    next >
Text File  |  1997-10-05  |  17KB  |  365 lines

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