home *** CD-ROM | disk | FTP | other *** search
/ Delphi Programming Unleashed / Delphi_Programming_Unleashed_SAMS_Publishing_1995.iso / units / dblist.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-03-21  |  7.0 KB  |  333 lines

  1. unit DBList;
  2. {
  3.   A doubly linked list
  4.   Right now this puppy works with any normal record.
  5.   If you want to work with strings, then use TStringList,
  6.   which is shown below.
  7. }
  8.  
  9. interface
  10. {$ifndef Windows}
  11. uses
  12.   Objects;
  13. {$EndIf}
  14. const
  15.   ALLOCATE_ERROR = 'Dynamic allocation error';
  16.  
  17. type
  18.   PString = ^String;
  19.  
  20.   DListPtr = ^DListRec;
  21.   DListRec = record
  22.     ListData : Pointer;
  23.     PrevPtr,
  24.     NextPtr : DListPtr
  25.   end;
  26.  
  27.   PDbList = ^TDbList;
  28.   {$IfDef Windows}
  29.   TDBList = class
  30.   {$Else}
  31.   TDbList = Object(TObject)
  32.   {$EndIf}
  33.       NodePtr, Head, Tail: DListPtr;
  34.       ErrorMessage: String;
  35.       ListSize: Integer;
  36.     {$IfDef Windows}
  37.     constructor Create;
  38.     destructor Destroy;
  39.     {$Else}
  40.     constructor Init;
  41.     destructor Done; virtual;
  42.     {$EndIf}
  43.     function DeleteNode(X : Pointer; Occur : Word) : Boolean;
  44.     function InsertNode(X : Pointer ) : Boolean; virtual;
  45.     function GoToHead: Boolean;
  46.     function Search(var ThisPtr: DListPtr; X: Pointer) : Boolean;
  47.     function First: Boolean; virtual;
  48.     function GotoPrevious(var X : Pointer) : Boolean; virtual;
  49.     function GotoNextNode(var X : Pointer) : Boolean; virtual;
  50.     function GotoLast(var X : Pointer) : Boolean; virtual;
  51.     function At(i: LongInt): Pointer;
  52.     procedure DisposeElement(P: Pointer); virtual;
  53.     procedure Clear; virtual;
  54.     function CompFunc(X, Y: Pointer): Boolean; virtual;
  55.   end;
  56.  
  57.   PStringList = ^TStringList;
  58.   {$IfDef Windows}
  59.   TStringList = class(TDbList)
  60.   {$Else}
  61.   TStringList = Object(TDbList)
  62.   {$EndIf}
  63.     function AddString(S: String): Boolean;
  64.     function GetStringAt(i: Integer): String;
  65.     procedure DisposeElement(P: Pointer); virtual;
  66.   end;
  67.  
  68. implementation
  69.  
  70. function NewString(const S: String): PString;
  71. var
  72.   P: PString;
  73. begin
  74.   if S = '' then P := nil else
  75.   begin
  76.     GetMem(P, Length(S) + 1);
  77.     P^ := S;
  78.   end;
  79.   NewString := P;
  80. end;
  81.  
  82. procedure DisposeString(P: PString);
  83. begin
  84.   if P <> nil then FreeMem(P, Length(P^) + 1);
  85. end;
  86.  
  87. {$IfDef Windows}
  88. constructor TDbList.Create;
  89. begin
  90.   inherited Create;
  91.   ListSize := 0;
  92.   NodePtr := nil;
  93.   Head := nil;
  94.   Tail := nil;
  95. end;
  96.  
  97. destructor TDBList.Destroy;
  98. begin
  99.   Clear;
  100.   NodePtr := nil;
  101.   Head := nil;
  102.   Tail := nil;
  103.   ListSize := 0;
  104.   ErrorMessage := '';
  105.   inherited Destroy;
  106. end;
  107. {$Else}
  108. constructor TDbList.Init;
  109. begin
  110.   inherited Init;
  111.   ListSize := 0;
  112.   NodePtr := nil;
  113.   Head := nil;
  114.   Tail := nil;
  115. end;
  116.  
  117. destructor TDBList.Done;
  118. begin
  119.   Clear;
  120.   NodePtr := nil;
  121.   Head := nil;
  122.   Tail := nil;
  123.   ListSize := 0;
  124.   ErrorMessage := '';
  125.   inherited Done;
  126. end;
  127. {$EndIf}
  128.  
  129. function TDBList.GoToHead;
  130. begin
  131.   NodePtr := Head;
  132. end;
  133.  
  134. function TDBList.DeleteNode(X : Pointer; Occur : Word) : Boolean;
  135. var
  136.   ThisPtr, p : DListPtr;
  137.   match : Boolean;
  138.  
  139. begin
  140.   ErrorMessage := '';
  141.   if Head = nil then begin
  142.     DeleteNode := False;
  143.     Exit;
  144.   end;
  145.  
  146.   { search for item to delete }
  147.   match := Search(ThisPtr, X);
  148.  
  149.   if match then begin           { found item in list }
  150.     if ListSize = 1 then begin
  151.       DisposeElement(ThisPtr^.ListData);
  152.       Dispose(Head);
  153.       Head := nil;
  154.       Tail := nil
  155.     end
  156.     else if ThisPtr^.NextPtr = nil then begin
  157.       { delete the last list member }
  158.       p := ThisPtr^.PrevPtr;
  159.       p^.NextPtr := nil;
  160.       DisposeElement(Tail^.ListData);
  161.       Dispose(Tail);
  162.       Tail := p;                { link tail pointer with new last element }
  163.     end
  164.     else if ThisPtr^.PrevPtr = nil then begin
  165.       { delete the list head }
  166.       p := ThisPtr^.NextPtr;
  167.       p^.PrevPtr := nil;
  168.       DisposeElement(Head^.ListData);
  169.       Dispose(Head);
  170.       Head := p;                { link head with new first element }
  171.     end
  172.     else begin
  173.       ThisPtr^.PrevPtr^.NextPtr := ThisPtr^.NextPtr;
  174.       ThisPtr^.NextPtr^.PrevPtr := ThisPtr^.PrevPtr;
  175.       DisposeElement(ThisPtr^.ListData);
  176.       Dispose(ThisPtr)
  177.     end;                        { IF }
  178.     Dec(ListSize);
  179.   end;                          { IF }
  180.   DeleteNode := match           { return function value }
  181. end;
  182.  
  183. function TDBList.InsertNode(X : Pointer) : Boolean;
  184. var
  185.   ThisPtr : DListPtr;
  186.  
  187. begin
  188.   New(ThisPtr);
  189.   if ThisPtr = nil then begin
  190.     ErrorMessage := ALLOCATE_ERROR;
  191.     InsertNode := False;
  192.     Exit
  193.   end;
  194.   ThisPtr^.NextPtr := nil;
  195.   ThisPtr^.PrevPtr := Tail;
  196.   { assign key and other fields }
  197.   ThisPtr^.ListData := X;
  198.   if (Head = nil) then begin
  199.     Head := ThisPtr;
  200.     Tail := Head;
  201.   end
  202.   else begin
  203.     Tail^.NextPtr := ThisPtr;
  204.     Tail := ThisPtr;            { reassign pointer to new tail }
  205.   end;
  206.   Inc(ListSize);
  207.   InsertNode := True
  208. end;
  209.  
  210. function TDBlist.At(i: LongInt): Pointer;
  211. var
  212.   P: Pointer;
  213.   j: LongInt;
  214. begin
  215.   First;
  216.   P := Head^.ListData;
  217.   for j := 1 to i do
  218.     GotoNextNode(P);
  219.   At := P;
  220. end;
  221.  
  222. function TDbList.First: Boolean;
  223. var
  224.   X: Pointer;
  225. begin
  226.   if Head <> nil then begin
  227.     X := Head^.ListData;
  228.     NodePtr := Head^.NextPtr;
  229.     First := True
  230.   end else
  231.     First := False
  232. end;
  233.  
  234. function TDbList.CompFunc(X, Y: Pointer): Boolean;
  235. begin
  236.   if X = Y then
  237.     CompFunc := True
  238.   else
  239.     CompFunc := False;
  240. end;
  241.  
  242. function TDbList.Search(var ThisPtr : DListPtr; X : Pointer) : Boolean;
  243. var
  244.   OutCome: Boolean;
  245.  
  246. begin
  247.   ErrorMessage := '';
  248.  
  249.   ThisPtr := Head;
  250.   if Head = nil then begin
  251.     Search := False;
  252.     Exit;
  253.   end;
  254.  
  255.   OutCome := CompFunc(X, ThisPtr^.ListData);
  256.   while (ThisPtr <> nil) and (not OutCome) do begin
  257.     ThisPtr := ThisPtr^.NextPtr;
  258.     OutCome := CompFunc(X, ThisPtr^.ListData);
  259.   end;
  260.   Search := OutCome;
  261. end;
  262.  
  263. function TDbList.GotoLast(var X : Pointer) : Boolean;
  264. begin
  265.   if Tail <> nil then begin
  266.     X := Tail^.ListData;
  267.     NodePtr := Tail^.PrevPtr;
  268.     GotoLast := True
  269.   end
  270.   else
  271.     GotoLast := False
  272. end;
  273.  
  274. function TDbList.GotoNextNode(var X : Pointer) : Boolean;
  275. begin
  276.   GotonextNode := False;
  277.   if NodePtr <> nil then begin
  278.     X := NodePtr^.ListData;
  279.     if NodePtr^.NextPtr <> nil then begin
  280.       NodePtr := NodePtr^.NextPtr;
  281.       GotoNextNode := True
  282.     end;
  283.   end
  284. end;
  285.  
  286. function TDbList.GotoPrevious(var X : Pointer) : Boolean;
  287. begin
  288.   if NodePtr <> nil then begin
  289.     X := NodePtr^.ListData;
  290.     if NodePtr^.PrevPtr <> nil then
  291.       NodePtr := NodePtr^.PrevPtr;
  292.     GotoPrevious := True
  293.   end
  294.   else
  295.     GotoPrevious := False
  296. end;
  297.  
  298. procedure TDbList.DisposeElement(P: Pointer);
  299. begin
  300.   if P <> nil then Dispose(P);
  301. end;
  302.  
  303. procedure TDbList.Clear;
  304. var
  305.   p : DListPtr;
  306. begin
  307.   while Head <> nil do begin
  308.     p := Head;
  309.     Head := Head^.NextPtr;
  310.     DisposeElement(p^.ListData);
  311.     Dispose(p);
  312.     Dec(ListSize);
  313.   end;                          { WHILE }
  314.   Tail := nil;
  315.   ErrorMessage := ''
  316. end;
  317.  
  318. procedure TStringList.DisposeElement(P: Pointer);
  319. begin
  320.   DisposeString(P);
  321. end;
  322.  
  323. function TStringList.AddString(S: String): Boolean;
  324. begin
  325.   InsertNode(NewString(S));
  326. end;
  327.  
  328. function TStringList.GetStringAt(i: Integer): String;
  329. begin
  330.   GetStringAt := PString(At(i))^;
  331. end;
  332.  
  333. end.