unit ListExt; {================================================================== Component TListExt / Version 1.0 / 03.1999 ============================================= Description: ============ My own version of managing sorted lists. Author: ======= (c) Ingo Eckel Sodener Weg 38 65812 Bad Soden Germany ==================================================================} {==================================================================} interface {==================================================================} Uses Classes, SysUtils; Const InitSize = 500; ExtendSize = 500; FLess = -1; FEqual = 0; FGreater = 1; Type IntType = Integer; TLxDeleteEvent = Procedure(Sender : TObject; Var P : Pointer; Size : Integer) Of Object; {==================================================================} TListExt = Class(TInterfacedobject) {==================================================================} Private {==================================================================} FCount : IntType; FData : Array of Pointer; FSorted : Boolean; fOnDelete: TLxDeleteEvent; FItemSize: IntType; MaxCount : IntType; Function GetItem ( I : IntType) : Pointer; Procedure FreeItem ( I : IntType); {==================================================================} Public {==================================================================} property data[i : IntType] : Pointer Read GetItem; default; Property Sorted : Boolean Read fSorted; Property Count : IntType Read FCount; Property ItemSize : IntType Read FItemSize; Constructor Create(ItemSize : IntType); Procedure Free; Procedure Clear; Procedure Add(P : Pointer); Function IndexOf(P : Pointer) : IntType; Procedure Sort(Compare : TListSortCompare); Function Find(P : Pointer; Compare : TListSortCompare) : Integer; Function FindSequential(P : Pointer; Compare : TListSortCompare) : Integer; Function First : Pointer; Function Last : Pointer; procedure Delete(I: IntType); {==================================================================} Published {==================================================================} Property OnDelete: TLxDeleteEvent Read fOnDelete Write fOnDelete; End; {==================================================================} implementation {==================================================================} uses Math; Constructor TListExt.Create(ItemSize : IntType); Var i : IntType; Begin IF ItemSize < 0 Then Raise ERangeError.CreateFmt('TListExt: negative itemsize: %u',[ItemSize]); Inherited Create; FCount := 0; MaxCount := InitSize; FSorted := TRUE; FItemSize := ItemSize; SetLength(FData, MaxCount+1); For i := 0 To MaxCount Do FData[i] := NIL; End; {Create} Procedure TListExt.Free; Begin Clear; FData := NIL; Inherited Free; End; Procedure TListExt.Add(P : Pointer); Begin IF Fcount = MaxCount Then Begin INC(MaxCount, ExtendSize); SetLength(FData, MaxCount + 1); End; IF FCount >= MaxCount Then Raise ERangeError.CreateFmt('TListExt: buffer overflow: %u',[Fcount]); INC (FCount); FData[Pred(FCount)] := P; FSorted := FALSE; End; {Add} Function TListExt.IndexOf(P : Pointer) : IntType; Var i : IntType; Begin Result := 0; IF Not Assigned(P) Then Exit; For i := 0 To FCount Do IF P = FData[i] Then Begin Result := i; Exit; End; End; {IndexOf} Procedure TListExt.FreeItem(I : IntType); Begin Begin IF Assigned(FData[i]) Then Begin IF Assigned(fOnDelete) Then Begin fOnDelete(Self, FData[i], FItemSize); IF Assigned(FData[i]) Then FreeMem(FData[i], FItemSize); End Else FreeMem(FData[i], FItemSize); FData[i] := NIL; End; End; End; {FreeItem} Procedure TListExt.Clear; Var i : IntType; Begin For i := 0 To Pred(FCount) Do Begin IF Assigned(FData[i]) Then FreeItem(i) Else Break; End; FCount := 0; FSorted := TRUE; MaxCount := InitSize; SetLength(FData, MaxCount + 1); End; {Clear} Function TListExt.GetItem(I : IntType) : Pointer; Begin IF (i >= FCount) Then Begin Raise ERangeError.CreateFmt('TListExt: index out of range: %u',[i]); Result := NIL; Exit; End; Result := FData[i]; End; {GetItem} Function TListExt.First : Pointer; Begin Result := NIL; IF Count > 0 Then Result := FData[0]; End; {First} Function TListExt.Last : Pointer; Begin Result := NIL; IF Count > 0 Then Result := FData[Pred(FCount)]; End; {Last} Procedure TListExt.Delete(i : IntType); Begin IF (FCount = 0) Or (i > Pred(FCount)) Then Exit; FreeItem(i); IF FCount - Succ(i) > 0 Then Move(FData[Succ(i)], FData[i], ( FCount - Succ(i) ) * SizeOf(Pointer)); Dec(FCount); FData[FCount] := NIL; End; {Delete} Function TListExt.Find(P : Pointer; Compare : TListSortCompare) : Integer; var nResult : integer; nLow : integer; nHigh : integer; nCompare : integer; nCheckPos : integer; Begin Result := -1; IF Not Assigned(P) Or (FCount < 1) Then Exit; IF not Sorted Then Sort(Compare); nLow := 0; nHigh := Count - 1; nResult := - 1; { Perform a binary search:} while (nResult = -1) and (nLow <= nHigh) do begin nCheckPos := (nLow + nHigh) div 2; nCompare := Compare(P, FData[nCheckPos]); if (nCompare = fLess) Then nHigh := nCheckPos - 1 { less than } else if (nCompare = fGreater) then nLow := nCheckPos + 1 { greater than } else nResult := nCheckPos; { equal to } end; Result := nResult; End; {Find} Function TListExt.FindSequential(P : Pointer; Compare : TListSortCompare) : Integer; Var i : Integer; Begin Result := -1; IF Not Assigned(P) Then Exit; IF Sorted Then Result := Find(P, Compare) Else Begin For i := 0 To Pred(FCount) Do Begin IF Compare(P, FData[i]) = 0 Then Begin Result := i; Exit; End; End; End; End; {FindSequential} Procedure TListExt.Sort(Compare : TListSortCompare); PROCEDURE quicksort(VAR a: Array of Pointer; LO,HI: IntType); PROCEDURE sort(L,R: IntType); VAR i,j : IntType; x,y : Pointer; BEGIN i := L; j := R; x := a[(L+R) DIV 2]; REPEAT WHILE Compare(a[i], x) = fLess DO i := i + 1; WHILE Compare(x, a[j]) = FLess DO j := j - 1; IF i <= j THEN BEGIN y:=a[i]; a[i]:=a[j]; a[j]:=y; i:=i+1; j:=j-1; END; UNTIL i>j; IF L 1) And Not Sorted Then QuickSort(Self.FData, 0, Pred(Self.FCount)); FSorted := TRUE; End; {Sort} end.