home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / arrays / generics / genlist / genlist.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-07-24  |  10.8 KB  |  336 lines

  1. Unit GenList;  {Generic Fully Dynamic Doubly-Linked List w/ArrayLike extras}
  2. {$R-,O+}
  3.  
  4. { Unit GenList  written by Eric C. Wentz -- Last Mod Data 7/8/89 }
  5.  
  6. { Unit GenList introduces the LinkedList equivalent of the FlexArray datatype }
  7. { Lists are allocated dynamically on the Heap, but as they are allocated on a }
  8. { node-by-node basis, they can grow to occupy the entire Heap.  This is their }
  9. { only superiority over the FlexArray type.  FlexArray's will perform quite a }
  10. { bit faster for all operations, and take up much less overhead (since there  }
  11. { are TWO pointers associated with each element in a List).  Nevertheless,    }
  12. { for Lists/Arrays of LARGE data structures, or simply huge lists of smaller  }
  13. { structures, Lists should prove quite handy.                                 }
  14.  
  15. { All Lists (and descendant objects) MUST be CREATEd before any other         }
  16. { operations are performed upon them.  Using CREATE to re-initialize          }
  17. { may well lead to system crashes, so DON'T do it!  By using DESTROY and      }
  18. { then INITting again, you can re-use the List type for whatever purpose      }
  19. { deemed appropriate.  As ListS use Untyped Variables to achieve Genericity,  }
  20. { you MUST tell the List how many bytes to expect -- use SizeOf.              }
  21. { Procedures RESETELEMENT_N and GETELEMENT_N provide Array-like access to     }
  22. { Established Lists, and DO check current bounds of List.  Attempting to      }
  23. { Access beyond these bounds is an error and will terminate the program!      }
  24. { Procedures APPEND, DELETE and INSERTAFTER_N are more ListSpecific .         }
  25. { APPEND is used to add new elements to the "end" of the List.  Insertion at  }
  26. { a particular index is accomplished with INSERTAFTER_N, and deletion of a    }
  27. { given element is similarly handled by DELETE.  REMEMBER: For DELETE and     }
  28. { methods ending in "_N", it is a program-terminating error to attempt to     }
  29. { access the List outside of it's (Current) boundaries!! Procedure LISTCOPY   }
  30. { will copy one list to another (if enough memory) and is of necessity very   }
  31. { slow. Finally, Functions ElemSize and CurrentLength provide important info  }
  32. { as to (Current) List status.  Procedure ReWind is provided only to speed up }
  33. { those List Accesses which will be sequential, starting from the "Top", and  }
  34. { is generally not particularly useful or needed.  It merely goes directly to }
  35. { the "Top", where the "_N" methods must run down the pointers to reach the   }
  36. { "Top".  Calling it once will suffice to speed up sequential accesses.       }
  37. { Note, here I am using Top in the sense of a FIFO Queue, NOT as in a Stack!  }
  38.  
  39. { LAST MOD: Added Function Node_N for more direct access to Nodes, as needed  }
  40. { in Unit GenHeap, which defines the Heap structured variant of this List.    }
  41.  
  42. { NOTE: Lists (as defined here) are "indexed" 1..CurrentLength }
  43. {       CurrentLength = 0 equates to Empty List                }
  44.  
  45. INTERFACE
  46.  
  47. Uses DoubLink,FlexPntr;
  48.  
  49. Type
  50.   List = Object
  51.     (**********************************************************************)
  52.     { GENERAL NOTE: Every time the parameter "Size" is specified, you MUST }
  53.     {               use SizeOf(<inputvariable>) to ensure correctness!!    }
  54.     (**********************************************************************)
  55.  
  56.     NumElems  : LongInt; { It would be best if Turbo provided a PRIVATE   }
  57.     DatumSize : Word;    { declaration (ala ADA) as no code outside this  }
  58.     CurElem   : Word;    { unit has any business mucking about with these }
  59.     Head      : DPtr;    { six instance variables. Unfortunately, Turbo   }
  60.     Tail      : DPtr;    { does not, so these must remain "visible" to    }
  61.     Cursor    : DPtr;    { external code.  DON'T ACCESS 'EM DIRECTLY !!   }
  62.  
  63.     Procedure Create;{ List Must be CREATEd EXACTLY once, and before all else }
  64.  
  65.     Procedure Init (Size : Word);  { Once CREATEd, you may Re-Use a List }
  66.     Procedure Destroy;             { by DESTROYing and then Re-INITting  }
  67.  
  68.     Function CurrentLength : LongInt;   { Report Current Length of List }
  69.     Function ElemSize : Word;           { Report Size of List Elements  }
  70.     Function Current : LongInt;         { Where is "Cursor" ?           }
  71.     Procedure ReWind;                   { Go To the "Top" of the List   }
  72.  
  73.     Procedure Append (Var InData; Size : Word); { Add InData to END of List  }
  74.                                                 { automatically "grows" List }
  75.  
  76.     Procedure GetElement_N (Var OutData; N : LongInt; Size : Word);
  77.  
  78.                            { Return value of Nth member of List    }
  79.                            { legal N's are from 1..CurrentLength   }
  80.                            { Only legal size is equal to ElemSize. }
  81.  
  82.     Procedure ReSetElement_N (Var InData; N : LongInt; Size : Word);
  83.  
  84.                            { Re-Assign value of Nth member of List }
  85.                            { legal N's are form 1..CurrentLength   }
  86.                            { Only legal size is equal to ElemSize. }
  87.  
  88.     Procedure Delete (N : LongInt); { Delete Nth Element }
  89.  
  90.     Procedure InsertAfter_N (Var InData; N : LongInt; Size : Word);
  91.  
  92.                            { Insert new value into list AFTER Nth element }
  93.  
  94.     Procedure Copy (L : List); { Target List MUST be CREATEd or DESTROYed }
  95.  
  96.     Function Node_N (N : LongInt) : DPtr; { Returns a Pointer to the Nth Node }
  97.                                         { See Unit LGenHeap for correct usage }
  98.   End;
  99.  
  100.  
  101. IMPLEMENTATION
  102.  
  103. Procedure ListError (Num : Byte);
  104. Begin
  105.   WriteLn;
  106.   Write ('ListArray ERROR: ');
  107.   Case Num of
  108.            0 : WriteLn ('Attempted to Insert wrong size data Element.');
  109.            1 : WriteLn ('Attempted GetElement with wrong size variable.');
  110.            2 : WriteLn ('Attempted to index past current end of List.');
  111.            3 : WriteLn ('Attempted ReSetElement with wrong size variable.');
  112.            4 : WriteLn ('Attempted to delete past current bounds of List.');
  113.            5 : WriteLn ('Attempted to insert past current bounds of List.');
  114.            6 : WriteLn ('Attempted InsertAfter with wrong size data Element.');
  115.            7 : WriteLn ('Attempted Function Node_N beyond Current Length.');
  116.            8 : WriteLn ('**** OUT OF MEMORY ERROR ****');
  117.           End;
  118.   WriteLn ('**** PROGRAM TERMINATED ****');
  119.   WriteLn;
  120.   Write ('Press <Return> to Continue.... ');
  121.   ReadLn;
  122.   HALT (0)
  123. End;
  124.  
  125. Procedure List.Create;
  126. Begin
  127.   Head := Nil;
  128.   Tail := Nil;
  129.   Cursor := Nil;
  130.   CurElem := 0;
  131.   DatumSize := 0;
  132.   NumElems := 0
  133. End;
  134.  
  135. Procedure List.Init (Size : Word);
  136. Begin
  137.   DatumSize := Size;
  138.   NumElems := 0
  139. End;
  140.  
  141. Procedure List.Destroy;
  142. Var
  143.   Temp : DPtr;
  144. Begin
  145.   Temp := Tail;
  146.   While Tail <> Head do
  147.     Begin
  148.       Cursor := Tail^.Prev;
  149.       Temp^.Prev := Nil;
  150.       Temp^.Destroy;
  151.       Tail := Cursor;
  152.       Tail^.Next := Nil;
  153.       Temp := Tail
  154.     End;
  155.   Head^.Destroy;
  156.   Dispose (Temp);
  157.   Dispose (Cursor);
  158.   Dispose (Head);
  159.   Dispose (Tail);
  160.   CurElem := 0;
  161.   DatumSize := 0;
  162.   NumElems := 0
  163. End;
  164.  
  165. Function List.CurrentLength : LongInt;
  166. Begin
  167.   CurrentLength := NumElems
  168. End;
  169.  
  170. Function List.ElemSize : Word;
  171. Begin
  172.   ElemSize := DatumSize
  173. End;
  174.  
  175. Function List.Current : LongInt;
  176. Begin
  177.   Current := CurElem
  178. End;
  179.  
  180. Procedure List.Append (Var InData; Size : Word);
  181. Var
  182.   Temp : DPtr;
  183. Begin
  184.   If Size <> DatumSize Then ListError (0);
  185.   New (Temp);
  186.   If Temp = Nil Then ListError (8);
  187.   Temp^.Create;
  188.   Temp^.Init (DatumSize);
  189.   Temp^.Set_Data (InData,Size);
  190.   If NumElems = 0
  191.     Then
  192.       Begin
  193.         Head := Temp;
  194.         Tail := Head;
  195.         Cursor := Head;
  196.         CurElem := 1;
  197.         NumElems := 1
  198.       End
  199.     Else
  200.       Begin
  201.         Tail^.Next := Temp;
  202.         Temp^.Prev := Tail;
  203.         Tail := Temp;
  204.         NumElems := NumElems + 1
  205.       End
  206. End;
  207.  
  208. Procedure GoTo_N (Var L : List; N : LongInt);  {This is NOT an exported}
  209. Begin                                          {method, to prevent abuse!}
  210.   With L do
  211.     If CurElem <> N Then
  212.       Begin
  213.         While N < CurElem do
  214.             Begin
  215.               Cursor := Cursor^.Prev;
  216.               CurElem := CurElem - 1
  217.             End;
  218.         While N > CurElem do
  219.             Begin
  220.               Cursor := Cursor^.Next;
  221.               CurElem := CurElem + 1
  222.             End
  223.       End
  224. End;
  225.  
  226. Procedure List.ReWind;
  227. Begin
  228.   CurElem := 1;
  229.   Cursor := Head
  230. End;
  231.  
  232. Procedure List.GetElement_N (Var OutData; N : LongInt; Size : Word);
  233. Begin
  234.   If Size <> DatumSize Then ListError (1);
  235.   If ((N > NumElems) or (N < 1)) Then ListError (2);
  236.   GoTo_N (Self,N);
  237.   Cursor^.Get_Data (OutData,Size)
  238. End;
  239.  
  240. Procedure List.ReSetElement_N (Var InData; N : LongInt; Size : Word);
  241. Begin
  242.   If Size <> DatumSize Then ListError (3);
  243.   If ((N > NumElems) or (N < 1)) Then ListError (2);
  244.   GoTo_N (Self,N);
  245.   Cursor^.Set_Data (InData,Size)
  246. End;
  247.  
  248. Procedure List.Delete (N : LongInt);
  249. Var
  250.   Temp : DPtr;
  251. Begin
  252.   If ((N > NumElems) or (N < 1)) Then ListError (4);
  253.   GoTo_N (Self,N);
  254.   Temp := Cursor;
  255.   NumElems := NumElems - 1;
  256.   If ((Cursor <> Tail) and (Cursor <> Head))
  257.     Then
  258.       Begin
  259.         Cursor^.Prev^.Next := Cursor^.Next;
  260.         Cursor^.Next^.Prev := Cursor^.Prev;
  261.         Cursor := Cursor^.Next;
  262.         Temp^.Next := Nil;
  263.         Temp^.Prev := Nil;
  264.         Temp^.Destroy
  265.       End
  266.     Else
  267.       If (Cursor = Head)
  268.         Then
  269.           Begin
  270.             Head := Head^.Next;
  271.             Head^.Prev := Nil;
  272.             Cursor := Head;
  273.             Temp^.Next := Nil;
  274.             Temp^.Destroy
  275.           End
  276.         Else    {Cursor = Tail}
  277.           Begin
  278.             Tail := Tail^.Prev;
  279.             Tail^.Next := Nil;
  280.             Cursor := Tail;
  281.             Temp^.Prev := Nil;
  282.             Temp^.Destroy
  283.           End;
  284.   Dispose (Temp)
  285. End;
  286.  
  287.  
  288. Procedure List.InsertAfter_N (Var InData; N : LongInt; Size : Word);
  289. Var
  290.   Temp : DPtr;
  291. Begin
  292.   If ((N > NumElems) or (N < 1)) Then ListError (5);
  293.   If Size <> DatumSize Then ListError (6);
  294.   GoTo_N (Self,N);
  295.   NumElems := NumElems + 1;
  296.   New (Temp);
  297.   If Temp = Nil Then ListError (8);
  298.   Temp^.Create;
  299.   Temp^.Init (Size);
  300.   Temp^.Set_Data (InData,Size);
  301.   Temp^.Next := Cursor^.Next;
  302.   Temp^.Prev := Cursor;
  303.   Cursor^.Next^.Prev := Temp;
  304.   Cursor^.Next := Temp
  305. End;
  306.  
  307. Procedure List.Copy (L : List);
  308. Var
  309.   I : LongInt;
  310.   D : FlexPtr;
  311.   W : Word;
  312. Begin
  313.   Init (L.ElemSize);
  314.   L.ReWind;
  315.   GetMem (D,SizeOf(FlexCount) + L.ElemSize);
  316.   If D = Nil Then ListError (8);
  317.   For I := 1 to L.CurrentLength do
  318.     Begin
  319.       L.GetElement_N (D^.Flex,I,L.ElemSize);
  320.       Append (D^.Flex,L.ElemSize)
  321.     End;
  322.   FreeMem (D,SizeOf(FlexCount) + L.ElemSize)
  323. End;
  324.  
  325. Function List.Node_N (N : LongInt) : DPtr;
  326. Begin
  327.   If N > CurrentLength Then ListError (7);
  328.   GoTo_N (Self,N);
  329.   Node_N := Cursor
  330. End;
  331.  
  332. BEGIN
  333.   HeapError := @HeapErrorTrap  {Exported from FlexPntr}
  334. END.
  335.  
  336.