Generic'и - класснючая вещь ^_^ Можно ещё написать свой Generic для списка - тогда будет и возможность сразу освобождать память на Delete, Remove и Clear с Free'ями. Вот мой вариант, правда требующий, чтобы у классов, конкретизирующих эти списки, обязательно присутствовало свойство ID
Код: Выделить всё
Unit BListsUnit;
{$mode objfpc}{$H+}
Interface
Uses
Classes, SysUtils, syncobjs;
Type
{ BList }
Generic BList<BManagedClass> = Class(TList)
Private
Function BListCompare(Item1, Item2: Pointer): Integer;
Function GetItem(aIndex: Integer): BManagedClass;
Procedure SetItem(aIndex: Integer; Const aValue: BManagedClass);
Procedure BSort(aLeft, aRight: Integer);
Public
Property Item[aIndex: Integer]: BManagedClass
Read GetItem Write SetItem; Default;
Procedure Add(Const aValue: BManagedClass);
Function SafeAdd(Const aValue: BManagedClass;
Const aExceptionOnDuplicate: Boolean = FALSE): Boolean;
Procedure Insert(Const aIndex: Integer; Const aValue: BManagedClass);
Function Remove(Const aValue: BManagedClass): Integer;
Procedure Delete(Const aIndex: Integer);
Procedure Purge;
Function Count: Integer;
Function GetAt(Const aIndex: Integer): BManagedClass;
Function Find(Const aID: Integer): BManagedClass;
Function Present(Const aValue: BManagedClass): Boolean; Inline;
Procedure Load(Const aList: BList);
Procedure AddList(Const aList: TList);
Procedure Sort;
Procedure Compare(Const aTarget: BList; Out aSame, aOver, aLack: BList);
Constructor Build;
Destructor Burn;
End;
Type
{ BThreadList }
Generic BThreadList<BManagedClass> = Class
Type BManagedList = Specialize BList<BManagedClass>;
Protected
bInternal: BManagedList;
bSection: TCriticalSection;
Public
Procedure Add(Const aValue: BManagedClass);
Procedure Remove(Const aValue: BManagedClass);
Procedure Clear; Reintroduce;
Procedure Purge;
Procedure Load(Const aList:BManagedList);
Function LockList: BManagedList;
Procedure UnlockList;
Constructor Build;
Destructor Burn;
End;
Type
{ BLinkedList }
Generic BLinkedList<BManagedClass> = Class
Type BFlatList = Specialize BList<BManagedClass>;
Private
bInternal: TList;
Function GetFirst: BManagedClass; Inline;
Function GetLast: BManagedClass; Inline;
Public
Property First: BManagedClass Read GetFirst;
Property Last: BManagedClass Read GetLast;
Procedure Add(Const aObject: BManagedClass);
Procedure SafeAdd(Const aObject: BManagedClass); Inline;
Procedure Insert(aObject: BManagedClass; Const aNext: BManagedClass = nil);
Procedure Remove(Const aObject: BManagedClass);
Function Present(Const aObject: BManagedClass): Boolean;
Procedure Load(Const aList: BLinkedList);
Function AsList: BFlatList;
Constructor Build;
Destructor Burn;
End;
Type
{ BLinkedThreadList }
Generic BLinkedThreadList<BManagedClass> = Class
Type BManagedList = Specialize BLinkedList<BManagedClass>;
Private
bInternal: BManagedList;
bSection: TCriticalSection;
Public
Procedure Add(Const aObject: BManagedClass);
Procedure Load(Const aList: BManagedList);
Procedure Remove(Const aObject: BManagedClass);
Function LockList: BManagedList;
Procedure UnlockList;
Constructor Build;
Destructor Burn;
End;
Implementation
{ BList }
Function BList.BListCompare(Item1, Item2: Pointer): Integer;
Begin
If (Item1 = nil) Or (Item2 = nil) Then
Begin
If Item1 = nil Then
If Not(Item2 = nil) Then Result := 1
Else Result := 0
Else
Result := -1
End
Else
Result := BManagedClass(Item2).ID - BManagedClass(Item1).ID;
End;
Function BList.GetItem(aIndex: Integer): BManagedClass;
Begin
If Items[aIndex] = nil Then Raise Exception.Create('Definatly here!!!');
Result := BManagedClass(Items[aIndex]);
end;
Procedure BList.SetItem(aIndex: Integer; Const aValue: BManagedClass);
Begin
Items[aIndex] := aValue;
end;
Procedure BList.Add(Const aValue: BManagedClass);
Begin
If aValue = nil Then
Raise Exception.Create('Attempt of Nill adding');
Inherited Add(aValue);
End;
Function BList.SafeAdd(Const aValue: BManagedClass;
Const aExceptionOnDuplicate: Boolean): Boolean;
Var
i: Integer;
aPresent: Boolean;
Begin
Result := FALSE;
aPresent := FALSE;
For i := 0 To Count - 1 Do
If GetAt(i).Equals(aValue) Then
Begin
aPresent := TRUE;
Break;
End;
If aPresent Then
If aExceptionOnDuplicate Then
Raise Exception.Create('Value already present in list')
Else
Exit;
Add(aValue);
Result := TRUE;
End;
Procedure BList.Insert(Const aIndex: Integer; Const aValue: BManagedClass);
Begin
Inherited Insert(aIndex, aValue);
End;
Function BList.Remove(Const aValue: BManagedClass): Integer;
Begin
Result := Inherited Remove(aValue);
End;
Procedure BList.Delete(Const aIndex: Integer);
Begin
Inherited Delete(aIndex);
End;
Procedure BList.Purge;
Var
i: Integer;
Begin
For i := 0 To Count - 1 Do
Item[i].Burn;
Clear;
End;
Function BList.Count: Integer;
Begin
Result := Inherited Count;
End;
Function BList.GetAt(Const aIndex: Integer): BManagedClass;
Begin
If Items[aIndex] = nil Then Raise Exception.Create('HERE!');
Result := BManagedClass(Items[aIndex]);
End;
Function BList.Find(Const aID: Integer): BManagedClass;
Var
i: Integer;
Begin
Result := nil;
For i := 0 To Count - 1 Do
If GetAt(i).ID = aID Then
Begin
Result := GetAt(i);
Break;
End;
End;
Function BList.Present(Const aValue: BManagedClass): Boolean;
Var
i: Integer;
Begin
Result := FALSE;
For i := 0 To Count - 1 Do
If GetAt(i).Equals(aValue) Then Exit(TRUE);
End;
Procedure BList.Load(Const aList: BList);
Begin
Clear;
AddList(aList);
End;
Procedure BList.BSort(aLeft, aRight: Integer);
Var
i, j: Integer;
aFirst, aBuffer: BManagedClass;
Begin
Repeat
i := aLeft;
j := aRight;
aFirst := Item[(aLeft + aRight) div 2];
Repeat
While Item[i].ID < aFirst.ID Do
i += 1;
While Item[j].ID > aFirst.ID Do
j -= 1;
If i <= j Then
Begin
aBuffer := Item[i];
Item[i] := Item[j];
Item[j] := aBuffer;
i += 1;
j -= 1;
End;
Until i > j;
If aLeft < j Then BSort(aLeft, j);
aLeft := i;
Until Not(i < aRight);
End;
Procedure BList.AddList(Const aList: TList);
Begin
Inherited AddList(aList);
End;
Procedure BList.Sort;
Begin
If Count < 2 Then Exit;
BSort(0, Count - 1);
End;
Procedure BList.Compare(Const aTarget: BList; Out aSame, aOver, aLack: BList);
Var
i, j: Integer;
aID, aTargetID: Integer;
Begin
If aTarget = nil Then Raise Exception.Create('Illegal nil Target');
Sort;
aTarget.Sort;
i := 0;
j := 0;
While TRUE Do
Begin
If i = Count Then aID := -1
Else aID := GetAt(i).ID;
If j = aTarget.Count Then aTargetID := -1
Else aTargetID := aTarget.GetAt(j).ID;
If (aID = -1) And (aTargetID = -1) Then Break;
If aID = aTargetID Then
Begin
aSame.Add(GetAt(i));
Inc(i);
Inc(j);
End
Else
Begin
If ((aID < aTargetID) Or (aTargetID = -1)) And Not(aID = -1) Then
Begin
aOver.Add(GetAt(i));
Inc(i)
End;
If ((aID > aTargetID) Or (aID = -1)) And Not(aTargetID = -1) Then
Begin
aLack.Add(aTarget.GetAt(j));
Inc(j);
End;
End;
End;
End;
Constructor BList.Build;
Begin
Inherited Create;
End;
Destructor BList.Burn;
Begin
Inherited Destroy;
End;
{ BThreadList }
Procedure BThreadList.Add(Const aValue: BManagedClass);
Begin
bSection.Enter;
bInternal.Add(aValue);
bSection.Leave;
End;
Procedure BThreadList.Remove(Const aValue: BManagedClass);
Begin
bSection.Enter;
bInternal.Remove(aValue);
bSection.Leave;
End;
Procedure BThreadList.Clear;
Begin
bSection.Enter;
bInternal.Clear;
bSection.Leave;
End;
Procedure BThreadList.Purge;
Var
i: Integer;
Begin
bSection.Enter;
For i := 0 To bInternal.Count - 1 Do
bInternal.GetAt(i).Burn;
bInternal.Clear;
bSection.Leave;
End;
Procedure BThreadList.Load(Const aList: BManagedList);
Begin
bSection.Enter;
bInternal.Load(aList);
bSection.Leave;
End;
Function BThreadList.LockList: BManagedList;
Begin
bSection.Enter;
Result := bInternal;
End;
Procedure BThreadList.UnlockList;
Begin
bSection.Leave;
End;
Constructor BThreadList.Build;
Begin
bSection := TCriticalSection.Create;
bInternal := BManagedList.Build;
End;
Destructor BThreadList.Burn;
Begin
bInternal.Burn;
bSection.Free;
End;
{ BLinkedList }
Function BLinkedList.GetFirst: BManagedClass;
Var
i: Integer;
Begin
Result := nil;
For i := 0 To bInternal.Count - 1 Do
If BManagedClass(bInternal[i]).Prior = nil Then
Exit(BManagedClass(bInternal[i]));
end;
Function BLinkedList.GetLast: BManagedClass;
Var
i: Integer;
Begin
Result := nil;
For i := 0 To bInternal.Count - 1 Do
If BManagedClass(bInternal[i]).Next = nil Then
Exit(BManagedClass(bInternal[i]));
end;
Procedure BLinkedList.Add(Const aObject: BManagedClass);
Begin
bInternal.Add(aObject);
End;
Procedure BLinkedList.SafeAdd(Const aObject: BManagedClass);
Begin
If Not(Present(aObject)) Then Add(aObject);
End;
Procedure BLinkedList.Insert(aObject: BManagedClass;Const aNext: BManagedClass);
Var
aIndex: Integer;
Begin
If aObject = nil Then Raise Exception.Create('Nil insertion attempted');
If (aNext = nil) Or (bInternal.Count = 0) Then Add(aObject)
Else
Begin
aIndex := bInternal.IndexOf(aNext);
If aIndex = -1 Then bInternal.Add(aObject)
Else bInternal.Insert(aIndex, aObject);
End;
End;
Procedure BLinkedList.Remove(Const aObject: BManagedClass);
Begin
If Not(aObject.Prior = nil) Then aObject.Prior.Next := aObject.Next;
If Not(aObject.Next = nil) Then aObject.Next.Prior := aObject.Prior;
bInternal.Remove(aObject);
End;
//Procedure BLinkedList.Delete(Const aIndex: Integer);
//Begin
//
//End;
//
Function BLinkedList.Present(Const aObject: BManagedClass): Boolean;
Begin
End;
Procedure BLinkedList.Load(Const aList: BLinkedList);
Begin
bInternal.Clear;
bInternal.AddList(aList.bInternal);
End;
Function BLinkedList.AsList: BFlatList;
Begin
Result := BFlatList(bInternal);
End;
Constructor BLinkedList.Build;
Begin
bInternal := TList.Create;
End;
Destructor BLinkedList.Burn;
Begin
bInternal.Free;
End;
{ BLinkedThreadList }
Procedure BLinkedThreadList.Add(Const aObject: BManagedClass);
Begin
bSection.Enter;
bInternal.Add(aObject);
bSection.Leave;
End;
Procedure BLinkedThreadList.Load(Const aList: BManagedList);
Begin
bSection.Enter;
bInternal.Load(aList);
bSection.Leave;
End;
Procedure BLinkedThreadList.Remove(Const aObject: BManagedClass);
Begin
bSection.Enter;
bInternal.Remove(aObject);
bSection.Leave;
End;
Function BLinkedThreadList.LockList: BManagedList;
Begin
bSection.Enter;
Result := bInternal;
End;
Procedure BLinkedThreadList.UnlockList;
Begin
bSection.Leave;
End;
Constructor BLinkedThreadList.Build;
Begin
bSection := TCriticalSection.Create;
bInternal := BManagedList.Build;
End;
Destructor BLinkedThreadList.Burn;
Begin
bInternal.Burn;
bSection.Free;
End;
End.
А на кодогенератор - так вообще надышаться не могу - насколько он офигенный вышел ^_^