mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 09:19:50 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			210 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
 *****************************************************************************
 | 
						|
 *                                                                           *
 | 
						|
 *  This file is part of the Lazarus Component Library (LCL)                 *
 | 
						|
 *                                                                           *
 | 
						|
 *  See the file COPYING.modifiedLGPL, included in this distribution,        *
 | 
						|
 *  for details about the copyright.                                         *
 | 
						|
 *                                                                           *
 | 
						|
 *  This program is distributed in the hope that it will be useful,          *
 | 
						|
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 | 
						|
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     *
 | 
						|
 *                                                                           *
 | 
						|
 *****************************************************************************
 | 
						|
 
 | 
						|
  Authors: Mattias Gaertner, Jeroen van Iddekinge
 | 
						|
 | 
						|
  Abstract:
 | 
						|
    Defines the simple double connected queue TLinkList.
 | 
						|
    It supports Adding, Deleting, getting First and getting Last in O(1).
 | 
						|
    Finding can be done in time O(n).
 | 
						|
}
 | 
						|
unit LazLinkedList;
 | 
						|
 | 
						|
{$mode objfpc}{$H+}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
uses
 | 
						|
  Classes, SysUtils;
 | 
						|
 | 
						|
type
 | 
						|
  TLinkListItem = class
 | 
						|
    Next  : TLinkListItem;
 | 
						|
    Prior : TLinkListItem;
 | 
						|
    procedure ResetItem; virtual;
 | 
						|
  end;
 | 
						|
 | 
						|
  TLinkList = class
 | 
						|
  private
 | 
						|
    FFirstFree: TLinkListItem;
 | 
						|
    FFreeCount: integer;
 | 
						|
    FFirst: TLinkListItem;
 | 
						|
    FLast: TLinkListItem;
 | 
						|
    FCount: integer;
 | 
						|
    procedure DisposeItem(AnItem: TLinkListItem);
 | 
						|
    procedure Unbind(AnItem: TLinkListItem);
 | 
						|
  protected
 | 
						|
    function CreateItem: TLinkListItem; virtual; abstract;
 | 
						|
    function GetNewItem: TLinkListItem;
 | 
						|
    procedure AddAsLast(AnItem: TLinkListItem);
 | 
						|
  public
 | 
						|
    property First: TLinkListItem read FFirst;
 | 
						|
    property Last: TLinkListItem read FLast;
 | 
						|
    property Count: integer read FCount;
 | 
						|
    procedure Delete(AnItem: TLinkListItem);
 | 
						|
    procedure MoveToLast(AnItem: TLinkListItem);
 | 
						|
    procedure Clear;
 | 
						|
    function ConsistencyCheck: integer;
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
  end;
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
{ TLinkList }
 | 
						|
 | 
						|
procedure TLinkListItem.ResetItem;
 | 
						|
begin
 | 
						|
  Next := nil;
 | 
						|
  Prior := nil;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TLinkList.Create;
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TLinkList.Destroy;
 | 
						|
var AnItem: TLinkListItem;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  // clear the free list
 | 
						|
  while FFirstFree<>nil do begin
 | 
						|
    AnItem:=FFirstFree;
 | 
						|
    FFirstFree:=AnItem.Next;
 | 
						|
    AnItem.Destroy;
 | 
						|
  end;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLinkList.Delete(AnItem: TLinkListItem);
 | 
						|
begin
 | 
						|
  if AnItem=nil then exit;
 | 
						|
  Unbind(AnItem);
 | 
						|
  AnItem.Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLinkList.MoveToLast(AnItem: TLinkListItem);
 | 
						|
begin
 | 
						|
  if AnItem=nil then exit;
 | 
						|
  Unbind(AnItem);
 | 
						|
  AddAsLast(AnItem);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLinkList.Clear;
 | 
						|
begin
 | 
						|
  while First<>nil do Delete(First);
 | 
						|
end;
 | 
						|
 | 
						|
function TLinkList.GetNewItem: TLinkListItem;
 | 
						|
begin
 | 
						|
  if FFirstFree<>nil then begin
 | 
						|
    Result:=FFirstFree;
 | 
						|
    FFirstFree:=FFirstFree.Next;
 | 
						|
    if FFirstFree<>nil then
 | 
						|
      FFirstFree.Prior:=nil;
 | 
						|
    dec(FFreeCount);
 | 
						|
  end else begin
 | 
						|
    Result := CreateItem;
 | 
						|
  end;
 | 
						|
  Result.Next:=nil;
 | 
						|
  Result.Prior:=nil;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLinkList.DisposeItem(AnItem: TLinkListItem);
 | 
						|
var i: integer;
 | 
						|
begin
 | 
						|
  if FFreeCount<=2*FCount then begin
 | 
						|
    AnItem.ResetItem;
 | 
						|
    AnItem.Next:=FFirstFree;
 | 
						|
    FFirstFree:=AnItem;
 | 
						|
    if AnItem.Next<>nil then AnItem.Next.Prior:=AnItem;
 | 
						|
    inc(FFreeCount);
 | 
						|
  end else begin
 | 
						|
    AnItem.Destroy;
 | 
						|
    if (FCount+5)<2*FFreeCount then begin
 | 
						|
      for i:=1 to 2 do begin
 | 
						|
        if FFirstFree<>nil then begin
 | 
						|
          AnItem:=FFirstFree;
 | 
						|
          FFirstFree:=FFirstFree.Next;
 | 
						|
          if FFirstFree<>nil then
 | 
						|
            FFirstFree.Prior:=nil;
 | 
						|
	  AnItem.Destroy;
 | 
						|
          dec(FFreeCount);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLinkList.Unbind(AnItem: TLinkListItem);
 | 
						|
begin
 | 
						|
  if AnItem=nil then exit;
 | 
						|
  if FFirst=AnItem then FFirst:=FFirst.Next;
 | 
						|
  if FLast=AnItem then FLast:=FLast.Prior;
 | 
						|
  if AnItem.Prior<>nil then AnItem.Prior.Next:=AnItem.Next;
 | 
						|
  if AnItem.Next<>nil then AnItem.Next.Prior:=AnItem.Prior;
 | 
						|
  AnItem.Prior:=nil;
 | 
						|
  AnItem.Next:=nil;
 | 
						|
  dec(FCount);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TLinkList.AddAsLast(AnItem: TLinkListItem);
 | 
						|
begin
 | 
						|
  AnItem.Prior:=FLast;
 | 
						|
  AnItem.Next:=nil;
 | 
						|
  FLast:=AnItem;
 | 
						|
  if AnItem.Prior<>nil then
 | 
						|
    AnItem.Prior.Next:=AnItem
 | 
						|
  else
 | 
						|
    FFirst:=AnItem;
 | 
						|
  inc(FCount);
 | 
						|
end;
 | 
						|
 | 
						|
function TLinkList.ConsistencyCheck: integer;
 | 
						|
var RealCount: integer;
 | 
						|
  AnItem: TLinkListItem;
 | 
						|
begin
 | 
						|
  // test free list
 | 
						|
  RealCount:=0;
 | 
						|
  AnItem:=FFirstFree;
 | 
						|
  while AnItem<>nil do begin
 | 
						|
    inc(RealCount);
 | 
						|
    AnItem:=AnItem.Next;
 | 
						|
  end;
 | 
						|
  if FFreeCount<>RealCount then begin
 | 
						|
    Result:=-1;  exit;
 | 
						|
  end;
 | 
						|
  // test items
 | 
						|
  RealCount:=0;
 | 
						|
  AnItem:=FFirst;
 | 
						|
  while AnItem<>nil do begin
 | 
						|
    if (AnItem.Next<>nil) and (AnItem.Next.Prior<>AnItem) then begin
 | 
						|
      Result:=-2;  exit;
 | 
						|
    end;
 | 
						|
    if (AnItem.Prior<>nil) and (AnItem.Prior.Next<>AnItem) then begin
 | 
						|
      Result:=-3;  exit;
 | 
						|
    end;
 | 
						|
    inc(RealCount);
 | 
						|
    AnItem:=AnItem.Next;
 | 
						|
  end;
 | 
						|
  if FCount<>RealCount then begin
 | 
						|
    Result:=-4;  exit;
 | 
						|
  end;
 | 
						|
  Result:=0;
 | 
						|
end;
 | 
						|
 | 
						|
end.
 | 
						|
 |