Files
lazarus-ccr/applications/cactusjukebox/source/MGList.pas

708 lines
19 KiB
ObjectPascal
Raw Normal View History

//******************************************************************************
//*** COMMON DELPHI FUNCTIONS ***
//*** ***
//*** (c) Beppe Grimaldi, Massimo Magnano 11-11-2004. ***
//*** ***
//*** ***
//******************************************************************************
// File : MGList.pas REV. 1.6 (13-09-2006)
//
// Description : Implementation of an Optimazed and Polimorphic List.
//
//******************************************************************************
unit MGList;
{$mode delphi}{$H+}
interface
Type
PDataExt = ^TDataExt;
TDataExt = record
Data :Pointer;
Prev :PDataExt;
Next :PDataExt;
end;
//I Tag sono necessari xche' Non posso leggere le variabili che stanno nello Stack
//quindi devo passare le variabile necessarie alle funzioni locali di compare cos�
//EN the Tags are needed because i cannot read variables from the Stack
//so i must pass the variables that i need in the local compare function int this way
TLocalCompareFunction = function (Tag :Pointer; ptData1, ptData2 :Pointer) :Boolean;
TLocalWalkFunction = procedure (Tag :Integer; ptData :Pointer);
TObjCompareFunction = function (Tag :Pointer; ptData1, ptData2 :Pointer) :Boolean of object;
PObjCompareFunction = ^TObjCompareFunction;
TObjWalkFunction = procedure (Tag :Integer; ptData :Pointer) of object;
{ TMGList }
TMGList = class
protected
rListInit,
rListEnd,
rCurrent :PDataExt;
rCount :Integer;
function Get(Index: Integer): Pointer;
function InternalDelete(Item :PDataExt) :PDataExt; overload;
function InternalFind(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil) :PDataExt; virtual;
function PutInRightPosition(newElem :PDataExt; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil) :Integer; overload; virtual;
function PutInRightPosition(newElem :PDataExt; ATag :Pointer; CompareFunction : TObjCompareFunction) :Integer; overload; virtual;
function allocData :Pointer; virtual;
procedure deallocData(pData :Pointer); virtual;
function RefreshOK(pData :Pointer) : Boolean; virtual;
public
constructor Create; virtual;
destructor Destroy; override;
function Find(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil): Integer; overload;
function Find(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction): Integer; overload;
function Find(const Args: array of Variant): Pointer; overload; virtual;
function ExtFind(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil): Pointer; overload;
function ExtFind(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction): Pointer; overload;
procedure Walk(ATag :Integer; WalkFunction : TLocalWalkFunction); overload;
procedure Walk(ATag :Integer; WalkFunction : TObjWalkFunction); overload;
procedure WalkAndRefresh(ATag :Integer; WalkFunction : TLocalWalkFunction); overload;
procedure WalkAndRefresh(ATag :Integer; WalkFunction : TObjWalkFunction); overload;
function Add :Pointer; overload;
function Insert(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil) :Integer; overload;
function Insert(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction) :Integer; overload;
function DeleteFirst :Boolean;
function DeleteLast :Boolean;
function Delete(Index :Integer) :Boolean; overload;
function Delete(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=Nil) :Boolean; overload;
function Delete(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction) :Boolean; overload;
procedure Exchange(pData1, pData2 :Pointer); overload; virtual;
procedure Clear;
procedure Refresh;
function FindFirst: Pointer; virtual;
function FindNext : Pointer; virtual;
function GetFirst : Pointer;
function GetLast : Pointer;
function GetCurrent : Pointer; virtual;
function GetData(DataPointer :Pointer; DataName :String) :Variant; virtual;
function DeleteCurrent :Boolean;
procedure FindClose; virtual;
property Count :Integer read rCount;
property Items [Index :Integer] :Pointer read Get;
end;
TMGListClass = class of TMGList;
TMGObjectWithCreate = class(TObject)
public
constructor Create(dummy :Boolean); virtual;
end;
TObjectWCClass = class of TMGObjectWithCreate;
TMGObject_List = class(TMGList)
protected
function allocData :Pointer; override;
procedure deallocData(pData :Pointer); override;
function GetObjectClass :TObjectWCClass; virtual; abstract;
end;
TMGList_List = class(TMGList)
protected
function allocData :Pointer; override;
procedure deallocData(pData :Pointer); override;
function GetObjectClass :TMGListClass; virtual; abstract;
end;
implementation
Type
TLocalToObjData_Compare = record
Tag :Pointer;
Func :TObjCompareFunction;
end;
PLocalToObjData_Compare = ^TLocalToObjData_Compare;
TLocalToObjData_Walk = record
Tag :Integer;
Func :TObjWalkFunction;
end;
PLocalToObjData_Walk = ^TLocalToObjData_Walk;
function _localToObj_Compare(xTag :Pointer; ptData1, ptData2 :Pointer) :Boolean;
begin
// try
Result := PLocalToObjData_Compare(xTag).Func(
PLocalToObjData_Compare(xTag).Tag,
ptData1, ptData2);
(* except
Result :=False;
end;*)
end;
procedure _localToObj_Walk(xTag :Integer; ptData :Pointer);
begin
PLocalToObjData_Walk(xTag).Func(PLocalToObjData_Walk(xTag).Tag, ptData);
end;
function AllocData_Compare(Tag :Pointer; Func :TObjCompareFunction) :PLocalToObjData_Compare;
begin
GetMem(Result, sizeOf(TLocalToObjData_Compare));
Result^.Tag :=Tag;
Result^.Func :=Func;
end;
function AllocData_Walk(Tag :Integer; Func :TObjWalkFunction) :PLocalToObjData_Walk;
begin
GetMem(Result, sizeOf(TLocalToObjData_Walk));
Result^.Tag :=Tag;
Result^.Func :=Func;
end;
function CompByData(xTag :Pointer; ptData1, ptData2 :Pointer) :Boolean;
begin
Result := (ptData1 = ptData2);
end;
// =============================================================================
constructor TMGList.Create;
begin
rCount := 0;
rListInit := Nil;
rListEnd := Nil;
rCurrent := Nil;
end;
destructor TMGList.Destroy;
begin
Clear;
end;
function TMGList.allocData :Pointer;
begin
Result :=Nil;
end;
procedure TMGList.deallocData(pData :Pointer);
begin
end;
function TMGList.RefreshOK(pData :Pointer) : Boolean;
begin
Result :=True;
end;
procedure TMGList.Clear;
var
pIndex :PDataExt;
begin
while (rListInit <> Nil) do
begin
pIndex := rListInit;
rListInit := rListInit^.Next;
deallocData(pIndex^.Data);
Dispose(pIndex);
end;
rListInit := Nil;
rListEnd := Nil;
rCount := 0;
end;
procedure TMGList.Refresh;
var
pIndex :PDataExt;
begin
pIndex := rListInit;
while (pIndex <> Nil) do
begin
if RefreshOK(pIndex^.Data)
then pIndex := pIndex^.Next
else begin
if (pIndex^.Next = Nil) // se � l'ultimo elemento..
then rListEnd := pIndex^.Prev;
pIndex := InternalDelete(pIndex);
end;
end;
end;
function TMGList.FindFirst: Pointer;
begin
if (rCurrent=Nil)
then begin
rCurrent :=rListInit;
Result :=GetCurrent;
end
else Result :=Nil;
end;
function TMGList.FindNext : Pointer;
begin
if (rCurrent<>Nil)
then begin
rCurrent :=rCurrent^.Next;
Result :=GetCurrent;
end
else Result :=Nil;
end;
function TMGList.GetFirst: Pointer;
begin
Result :=rListInit^.Data;
end;
function TMGList.GetLast: Pointer;
begin
Result :=rListEnd^.Data;
end;
function TMGList.GetCurrent : Pointer;
begin
if (rCurrent=Nil)
then Result :=Nil
else Result :=rCurrent^.Data;
end;
function TMGList.GetData(DataPointer :Pointer; DataName :String) :Variant;
begin
Result :=Variant(Integer(DataPointer));
end;
function TMGList.DeleteCurrent :Boolean;
begin
Result := False;
if (rCurrent <> Nil) then
begin
rCurrent := InternalDelete(rCurrent);
Result := True;
end;
end;
procedure TMGList.FindClose;
begin
rCurrent :=Nil;
end;
function TMGList.Get(Index: Integer): Pointer;
var
I :Integer;
pIndex :PDataExt;
begin
Result := Nil;
if ((Index >= 0) and (Index < rCount)) then
begin
pIndex := rListInit;
for i:=0 to Index-1 do
pIndex := pIndex^.Next;
Result := pIndex^.Data;
end;
end;
function TMGList.Find(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil): Integer;
var
i :Integer;
Found :Boolean;
pIndex :PDataExt;
begin
if not(Assigned(CompareFunction))
then CompareFunction :=CompByData;
Result := -1;
i := 0;
Found := False;
pIndex := rListInit;
while ((i < rCount) and not Found) do
if CompareFunction(ATag, pData, pIndex^.Data)
then begin
Result := i;
Found := True;
end
else begin
Inc(i);
pIndex := pIndex^.Next;
end;
end;
function TMGList.Find(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction): Integer;
Var
auxPointer :PLocalToObjData_Compare;
begin
auxPointer :=AllocData_Compare(ATag, CompareFunction);
Result := Find(pData, auxPointer, _LocalToObj_Compare);
FreeMem(auxPointer);
end;
function TMGList.Find(const Args: array of Variant): Pointer;
begin
Result :=Nil;
end;
function TMGList.ExtFind(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil): Pointer;
var
Found :Boolean;
pIndex :PDataExt;
begin
if not(Assigned(CompareFunction))
then CompareFunction :=CompByData;
Result := Nil;
Found := False;
pIndex := rListInit;
while ((pIndex <> Nil) and not Found) do
if CompareFunction(ATag, pData, pIndex^.Data)
then begin
Result := pIndex^.Data;
Found := True;
end
else pIndex := pIndex^.Next;
end;
function TMGList.ExtFind(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction): Pointer;
Var
auxPointer :PLocalToObjData_Compare;
begin
auxPointer :=AllocData_Compare(ATag, CompareFunction);
Result := ExtFind(pData, auxPointer, _LocalToObj_Compare);
FreeMem(auxPointer);
end;
procedure TMGList.Walk(ATag :Integer; WalkFunction : TLocalWalkFunction);
var
pIndex :PDataExt;
begin
pIndex := rListInit;
while (pIndex <> Nil) do
begin
WalkFunction(ATag, pIndex^.Data);
pIndex := pIndex^.Next;
end;
end;
procedure TMGList.Walk(ATag :Integer; WalkFunction : TObjWalkFunction);
Var
auxPointer :PLocalToObjData_Walk;
begin
auxPointer :=AllocData_Walk(ATag, WalkFunction);
Walk(Integer(auxPointer), _LocalToObj_Walk);
FreeMem(auxPointer);
end;
procedure TMGList.WalkAndRefresh(ATag :Integer; WalkFunction : TLocalWalkFunction);
var
pIndex :PDataExt;
begin
pIndex := rListInit;
while (pIndex <> Nil) do
begin
if RefreshOk(pIndex^.Data)
then begin
WalkFunction(ATag, pIndex^.Data);
pIndex := pIndex^.Next;
end
else begin
if (pIndex^.Next = Nil) // se � l'ultimo elemento..
then rListEnd := pIndex^.Prev;
pIndex := InternalDelete(pIndex);
end;
end;
end;
procedure TMGList.WalkAndRefresh(ATag :Integer; WalkFunction : TObjWalkFunction);
Var
auxPointer :PLocalToObjData_Walk;
begin
auxPointer :=AllocData_Walk(ATag, WalkFunction);
WalkAndRefresh(Integer(auxPointer), _LocalToObj_Walk);
FreeMem(auxPointer);
end;
function TMGList.Add :Pointer;
var
newElem :PDataExt;
begin
new(newElem);
fillchar(newElem^, sizeof(TDataExt), 0);
newElem^.Data := allocData;
if (rListEnd = Nil)
then begin
rListInit := newElem;
rListEnd := newElem;
end
else begin
rListEnd^.Next := newElem;
newElem^.Prev := rListEnd;
rListEnd := newElem;
end;
Inc(rCount);
Result := newElem^.Data;
end;
function TMGList.PutInRightPosition(newElem :PDataExt; ATag :Pointer; CompareFunction : TLocalCompareFunction) :Integer;
var
Found :Boolean;
pIndex :PDataExt;
begin
if not(Assigned(CompareFunction))
then CompareFunction :=CompByData;
Result := 0;
if (rListInit = Nil)
then begin
rListInit := newElem;
rListEnd := newElem;
end
else begin
Found := False;
pIndex := rListInit;
repeat
if CompareFunction(ATag, newElem^.Data, pIndex^.Data)
then begin
// uso 'newElem^.Prev' per conservare il puntatore al record precedente..
newElem^.Prev := pIndex;
pIndex := pIndex^.Next;
end
else Found := True;
Inc(Result);
until ((pIndex = Nil) or Found);
if (newElem^.Prev = Nil) // inserisco in prima posizione..
then rListInit := newElem
else newElem^.Prev^.Next := newElem;
newElem^.Next := pIndex;
if (pIndex <> Nil)
then pIndex^.Prev := newElem
else rListEnd := newElem; // inserisco in ultima posizione..
end;
end;
function TMGList.PutInRightPosition(newElem :PDataExt; ATag :Pointer; CompareFunction : TObjCompareFunction) :Integer;
Var
auxPointer :PLocalToObjData_Compare;
begin
auxPointer :=AllocData_Compare(ATag, CompareFunction);
Result := PutInRightPosition(newElem, auxPointer, _LocalToObj_Compare);
FreeMem(auxPointer);
end;
function TMGList.Insert(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=Nil) :Integer;
var
newElem :PDataExt;
begin
if not(Assigned(CompareFunction))
then CompareFunction :=CompByData;
new(newElem);
fillchar(newElem^, sizeof(TDataExt), 0);
newElem^.Data :=pData;
Result := PutInRightPosition(pData, ATag, CompareFunction);
Inc(rCount);
end;
function TMGList.Insert(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction) :Integer;
Var
auxPointer :PLocalToObjData_Compare;
begin
auxPointer :=AllocData_Compare(ATag, CompareFunction);
Result := Insert(pData, auxPointer, _LocalToObj_Compare);
FreeMem(auxPointer);
end;
function TMGList.DeleteFirst: Boolean;
begin
try
InternalDelete(rListInit);
Result :=True;
except
Result :=False;
end;
end;
function TMGList.DeleteLast: Boolean;
begin
try
InternalDelete(rListEnd);
Result :=True;
except
Result :=False;
end;
end;
function TMGList.Delete(Index :Integer) :Boolean;
var
i :Integer;
pIndex :PDataExt;
begin
Result := False;
if ((Index >= 0) and (Index < rCount)) then
begin
pIndex := rListInit;
for i:=0 to Index-1 do
pIndex := pIndex^.Next;
if (pIndex = Nil)
then InternalDelete(rListEnd)
else InternalDelete(pIndex);
Result := True;
end;
end;
function TMGList.Delete(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=Nil) :Boolean;
Var
toDel :PDataExt;
begin
if not(Assigned(CompareFunction))
then CompareFunction :=CompByData;
toDel := InternalFind(pData, ATag, CompareFunction);
Result := (toDel<>Nil);
if Result
then InternalDelete(toDel);
end;
function TMGList.Delete(pData :Pointer; ATag :Pointer; CompareFunction : TObjCompareFunction) :Boolean;
Var
auxPointer :PLocalToObjData_Compare;
begin
auxPointer :=AllocData_Compare(ATag, CompareFunction);
Result := Delete(pData, auxPointer, _LocalToObj_Compare);
FreeMem(auxPointer);
end;
procedure TMGList.Exchange(pData1, pData2 :Pointer);
var
pIndex,
pIndexData1,
pIndexData2 :PDataExt;
xData :Pointer;
begin
pIndex := rListInit;
pIndexData1 :=Nil;
pIndexData2 :=Nil;
while ((pIndex <> Nil) and ((pIndexData1=Nil) or (pIndexData2=Nil))) do
begin
if (pIndex^.Data=pData1)
then pIndexData1 :=pIndex
else if (pIndex^.Data=pData2)
then pIndexData2 :=pIndex;
pIndex := pIndex^.Next;
end;
if ((pIndexData1<>Nil) and (pIndexData2<>Nil)) then
begin
xData := pIndexData1^.Data;
pIndexData1^.Data := pIndexData2^.Data;
pIndexData2^.Data := xData;
end;
end;
function TMGList.InternalDelete(Item :PDataExt) :PDataExt;
var
P :PDataExt;
begin
Result := Nil;
P := PDataExt(Item);
if (P <> Nil) then
begin
if (P^.Prev <> Nil)
then P^.Prev^.Next := P^.Next
else rListInit := P^.Next;
if (P^.Next <> Nil)
then P^.Next^.Prev := P^.Prev
else rListEnd := P^.Prev; // sto cancellando l'ultimo elemento..
Result := P^.Prev;
deallocData(P^.Data);
Dispose(P);
Dec(rCount);
end;
end;
function TMGList.InternalFind(pData :Pointer; ATag :Pointer; CompareFunction : TLocalCompareFunction=nil) :PDataExt;
var
Found :Boolean;
pIndex :PDataExt;
begin
if not(Assigned(CompareFunction))
then CompareFunction :=CompByData;
Result := Nil;
Found := False;
pIndex := rListInit;
while ((pIndex <> Nil) and not Found) do
if CompareFunction(ATag, pData, pIndex^.Data)
then begin
Result := pIndex;
Found := True;
end
else pIndex := pIndex^.Next;
end;
//==============================================================================
// TMGObject_List = class(TMGList)
constructor TMGObjectWithCreate.Create(dummy :Boolean);
begin
inherited Create;
end;
function TMGObject_List.allocData :Pointer;
begin
Result :=GetObjectClass.Create(true); //Why Tobject.Create is not virtual???
end;
procedure TMGObject_List.deallocData(pData :Pointer);
begin
TObject(pData).Free;
end;
//==============================================================================
// TMGList_List = class(TMGList)
function TMGList_List.allocData :Pointer;
begin
Result :=GetObjectClass.Create;
end;
procedure TMGList_List.deallocData(pData :Pointer);
begin
TMGList(pData).Free;
end;
end.