| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- 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<j THEN sort(L,j);
- IF i<R THEN sort(i,R);
- END; (* Sort *)
- BEGIN
- sort(LO,HI);
- END; (* QuickSort *)
- Begin
- IF (Self.FCount > 1) And Not Sorted Then
- QuickSort(Self.FData, 0, Pred(Self.FCount));
- FSorted := TRUE;
- End; {Sort}
- end.
|