{
各位使用過 Delphi 以及使用過 Java 應該都知道,在 Delphi 裡面事實上大概只有
兩種容器可以使用:TList 以及 TStringList,其他的容器都是用這兩個容器做出來
的(像TCollection、TComponent、TControl)等等都是。前一陣子由於研究Java 2.0
的 Collection class architecture 不禁感嘆其架構之完美性,回頭看看 Delphi 如
此優秀的語言在此方面卻顯出其缺陷,只有 TList 可以用(又只能存 Pointer ),
我想對初學者而言是相當難以接受的一部份。
而且說穿了,TList 也不是 Linked-List 而比較像是 Vector of pointer ,Delphi 4
出來之後即有了 Dynamic array,不一定要用 TList 才能裝東西,而且 Dynamic array
還是 type-safe 的。在此列出比較:
TList
==============
var
Ar: TList;
I: Integer;
begin
Ar := TList.Create;
Ar.Add(Pointer(123)); // <<--存入時要做此種cast!!
I := Integer(Ar[0]); // <-- 拿出來還要做此種 cast!!! 真是噁爛
end;
Dynamic array:
==============
var Ar: array of Integer;
I: Integer;
begin
SetLength(Ar, 1);
Ar[0] := 123;
I := Ar[0];
end;
不過這和下面要講的沒什麼關係,只是 Delphi 4 雖有了 Dynamic array 卻還是缺少了
很多基本的資料結構如 Doubly-linked-list 、 Hash table 、 Balanced binary
search tree等等。而我有點模仿 Java 2.0 的 Collection classes 架構私下寫了
幾個兩個的容器:TDeque、TTreeMap,以及幾個有用的介面:IMap、ICollection、
IIterator、IListIterator、IMapIterator、IStringList、IStringMap,以及幾個應用
層面的classes,像是 TEventMultiplexer 等,待各位等下看了程式碼,就會發現所有
程式都是用最新版的 Delphi 寫的,必須要用到 COM 的 interface 觀念(雖然私下
覺得 COM 又肥又大又沒用,不過 Delphi compiler 真的把 interface 寫得好好用喔!
),所以別誤會,雖然用到了interface以及GUID,實際上卻跟 COM 沒什麼瓜葛...
這些 class 中大概就屬 TTreeMap 最令人頭疼了,我使用了資料結構課本上的
「紅黑樹」,這實在是極端複雜...課本程式碼錯誤百出,害得我到最後還得去
看 Java 2.0 怎麼寫的,真是...
}
unit Patt;
interface
uses
SysUtils, ComObj, Classes;
type
TBasicObject = class;
EStorableError = class(Exception)
end;
IBasicObject = interface
['{A8DAD303-BAF6-11D2-8A0E-00E098142233}']
function GetObject: TBasicObject;
function Supports(const IID: TGUID): Boolean;
end;
IComparator = interface
['{A8DAD302-BAF6-11D2-8A0E-00E098142233}']
function Compare(a, b: Pointer): Integer;
procedure Finalize(a: Pointer);
function Initialize(a: Pointer): Pointer;
end;
IIterator = interface
['{D7C27BE1-BAC0-11D2-8A0E-00E098142233}']
function HasElement: Boolean;
function Get: Pointer;
procedure Put(Value: Pointer);
procedure Remove;
procedure Next;
end;
IListIterator = interface
['{A8DAD307-BAF6-11D2-8A0E-00E098142233}']
function HasElement: Boolean;
function Get: Pointer;
procedure Remove;
procedure Next;
procedure Prior;
function GetIndex: Integer;
procedure Add(Value: Pointer);
procedure Put(Value: Pointer);
end;
IMapIterator = interface
['{A8DAD308-BAF6-11D2-8A0E-00E098142233}']
function HasElement: Boolean;
procedure Next;
function GetKey: Pointer;
function GetValue: Pointer;
procedure Remove;
procedure SetKey(Key: Pointer);
procedure SetValue(Value: Pointer);
property Value: Pointer read GetValue write SetValue;
property Key: Pointer read GetKey write SetKey;
end;
ICollection = interface(IBasicObject)
['{D7C27BE2-BAC0-11D2-8A0E-00E098142233}']
procedure Add(Value: Pointer);
function Remove(Value: Pointer): Boolean;
procedure AddAll(C: ICollection);
procedure RetainAll(C: ICollection);
procedure RemoveAll(C: ICollection);
procedure Clear;
function Iterator: IIterator;
function IsEmpty: Boolean;
function Contains(Value: Pointer): Boolean;
function ContainsAll(C: ICollection): Boolean;
function CollectionEquals(Value: ICollection): Boolean;
function GetSize: Integer;
property Size: Integer read GetSize;
function GetComparator: IComparator;
procedure SetComparator(Value: IComparator);
property Comparator: IComparator read GetComparator write SetComparator;
end;
IList = interface(ICollection)
['{A8DAD300-BAF6-11D2-8A0E-00E098142233}']
procedure AddFirst(Value: Pointer);
procedure AddLast(Value: Pointer);
function RemoveFirst: Pointer;
function RemoveLast: Pointer;
function ReversedIterator: IIterator;
function ListIterator(Index: Integer): IListIterator;
end;
TBasicObject = class(TInterfacedObject, IBasicObject)
public
constructor CreateEmpty; virtual;
function GetObject: TBasicObject;
function Supports(const IID: TGUID): Boolean;
end;
TBasicClass = class of TBasicObject;
ECollectionError = class(Exception)
end;
TDequeNode = class
Value: Pointer;
Next, Prev: TDequeNode;
constructor Create(Value: Pointer; Next, Prev: TDequeNode);
end;
TAbstractCollection = class(TBasicObject, ICollection)
protected
FComparator: IComparator;
public
function GetComparator: IComparator; virtual;
procedure SetComparator(Value: IComparator); virtual;
public
procedure AddAll(C: ICollection); virtual;
procedure RetainAll(C: ICollection); virtual;
procedure RemoveAll(C: ICollection); virtual;
function ContainsAll(C: ICollection): Boolean; virtual;
function IsEmpty: Boolean; virtual;
public
function Contains(Value: Pointer): Boolean; virtual; abstract;
procedure Clear; virtual; abstract;
procedure Add(Value: Pointer); virtual; abstract;
function Remove(Value: Pointer): Boolean; virtual; abstract;
function Iterator: IIterator; virtual; abstract;
function GetSize: Integer; virtual; abstract;
function CollectionEquals(Value: ICollection): Boolean; virtual;
public
property Size: Integer read GetSize;
property Comparator: IComparator read GetComparator write SetComparator;
end;
TDeque = class(TAbstractCollection, IList)
private
FFirst, FLast: TDequeNode;
FSize: Integer;
function GetNodeAt(Index: Integer): TDequeNode;
public
constructor Create;
procedure AddFirst(Value: Pointer);
procedure AddLast(Value: Pointer);
procedure Add(Value: Pointer); override;
function RemoveFirst: Pointer;
function RemoveLast: Pointer;
function Remove(Value: Pointer): Boolean; override;
function Iterator: IIterator; override;
function ListIterator(Index: Integer): IListIterator;
function ReversedIterator: IIterator;
function GetSize: Integer; override;
function Contains(Value: Pointer): Boolean; override;
procedure Clear; override;
end;
TNodeColor = (ncRED, ncBLACK);
TTreeMap = class;
TTreeNode = class
private
function GetColor: TNodeColor;
function GetLeft: TTreeNode;
function GetParent: TTreeNode;
function GetRight: TTreeNode;
procedure SetColor(const Value: TNodeColor);
procedure SetLeft(const Value: TTreeNode);
procedure SetParent(const Value: TTreeNode);
procedure SetRight(const Value: TTreeNode);
public
FLeft, FRight, FParent: TTreeNode;
FColor: TNodeColor;
Key, Value: Pointer;
constructor Create;
property Parent: TTreeNode read GetParent write SetParent;
property Left: TTreeNode read GetLeft write SetLeft;
property Right: TTreeNode read GetRight write SetRight;
property Color: TNodeColor read GetColor write SetColor;
procedure Clear(TreeMap: TTreeMap);
end;
TTreeMapIterator = class(TBasicObject, IMapIterator, IIterator, IListIterator)
private
Map: TTreeMap;
Cursor: TTreeNode;
Reversed: Boolean;
constructor Create(Cursor: TTreeNode; Map: TTreeMap; Reversed: Boolean);
public
function HasElement: Boolean;
function GetKey: Pointer;
function GetValue: Pointer;
function Get: Pointer; virtual;
procedure Next;
procedure Prior;
procedure Remove;
procedure SetKey(Key: Pointer);
procedure SetValue(Value: Pointer);
function GetIndex: Integer;
procedure Add(Value: Pointer);
procedure Put(Value: Pointer);
public
property Value: Pointer read GetValue write SetValue;
property Key: Pointer read GetKey write SetKey;
end;
TMapKeyIterator = class(TTreeMapIterator)
public
function Get: Pointer; override;
end;
IMap = interface
['{541E3F60-BB72-11D2-8A0E-00E098142233}']
procedure Clear;
procedure Put(Key, Value: Pointer);
function RemoveKey(Key: Pointer): Boolean;
function RemoveValue(Value: Pointer): Boolean;
function GetSize: Integer;
function Get(Key: Pointer): Pointer;
function FindKey(Key: Pointer): IMapIterator;
function Iterator: IIterator;
function MapIterator: IMapIterator;
function ReversedIterator: IIterator;
function GetValueComparator: IComparator;
procedure SetValueComparator(const Value: IComparator);
function GetKeyComparator: IComparator;
procedure SetKeyComparator(const Value: IComparator);
property Size: Integer read GetSize;
property ValueComparator: IComparator read GetValueComparator write SetValueComparator;
property KeyComparator: IComparator read GetKeyComparator write SetKeyComparator;
function ContainsKey(Key: Pointer): Boolean;
function ContainsValue(Value: Pointer): Boolean;
procedure PutAll(M: IMap);
function IsEmpty: Boolean;
function MapEquals(M: IMap): Boolean;
function Keys: ICollection;
function Values: ICollection;
end;
TAbstractMap = class(TBasicObject, IMap)
protected
FKeyOwnership: Boolean;
FValueOwnership: Boolean;
protected
FValueComparator, FKeyComparator: IComparator;
public
constructor Create;
function GetValueComparator: IComparator;
procedure SetValueComparator(const Value: IComparator);
function GetKeyComparator: IComparator;
procedure SetKeyComparator(const Value: IComparator);
public
procedure Clear; virtual; abstract;
procedure Put(Key, Value: Pointer); virtual; abstract;
function RemoveKey(Key: Pointer): Boolean; virtual; abstract;
function RemoveValue(Value: Pointer): Boolean; virtual; abstract;
function GetSize: Integer; virtual; abstract;
function Get(Key: Pointer): Pointer; virtual; abstract;
function FindKey(Key: Pointer): IMapIterator; virtual; abstract;
function Iterator: IIterator; virtual; abstract;
function MapIterator: IMapIterator; virtual; abstract;
function ReversedIterator: IIterator; virtual;
function ContainsKey(Key: Pointer): Boolean; virtual;
function ContainsValue(Value: Pointer): Boolean; virtual;
procedure PutAll(M: IMap); virtual;
function MapEquals(M: IMap): Boolean; virtual;
function Keys: ICollection; virtual; abstract;
function Values: ICollection; virtual; abstract;
function IsEmpty: Boolean;
public
property Size: Integer read GetSize;
property ValueComparator: IComparator read GetValueComparator write SetValueComparator;
property KeyComparator: IComparator read GetKeyComparator write SetKeyComparator;
end;
TTreeMap = class(TAbstractMap)
private
FSize: Integer;
FRoot: TTreeNode;
FKeys: ICollection;
FValues: ICollection;
function TreeMinimum(x: TTreeNode): TTreeNode;
function TreeMaximum(x: TTreeNode): TTreeNode;
procedure LeftRotate(x: TTreeNode);
procedure RightRotate(x: TTreeNode);
procedure TreeInsert(z: TTreeNode);
function TreeSuccessor(x: TTreeNode): TTreeNode;
function TreePredecessor(x: TTreeNode): TTreeNode;
procedure RB_Insert(x: TTreeNode);
procedure RB_Delete(p: TTreeNode);
procedure RB_DeleteFixup(x: TTreeNode);
procedure SwapPosition(x, y: TTreeNode);
function FindNode(Key: Pointer): TTreeNode;
public
procedure Clear; override;
procedure Put(Key, Value: Pointer); override;
function RemoveKey(Key: Pointer): Boolean; override;
function RemoveValue(Value: Pointer): Boolean; override;
function GetSize: Integer; override;
function Get(Key: Pointer): Pointer; override;
function FindKey(Key: Pointer): IMapIterator; override;
function Iterator: IIterator; override;
function MapIterator: IMapIterator; override;
function ReversedIterator: IIterator; override;
function Keys: ICollection; override;
function Values: ICollection; override;
destructor Destroy; override;
end;
TTreeSet = class(TAbstractCollection)
protected
FMap: IMap;
public
constructor Create;
function Contains(Value: Pointer): Boolean; override;
procedure Clear; override;
procedure Add(Value: Pointer); override;
function Remove(Value: Pointer): Boolean; override;
function Iterator: IIterator; override;
function GetSize: Integer; override;
// function CollectionEquals(Value: ICollection): Boolean; override;
function GetComparator: IComparator; override;
procedure SetComparator(Value: IComparator); override;
end;
TBlobComparator = class(TBasicObject, IComparator)
public
Length: Integer;
constructor Create(Length: Integer);
function Compare(a, b: Pointer): Integer;
function Initialize(a: Pointer): Pointer;
procedure Finalize(a: Pointer);
end;
TObjectComparator = class(TBasicObject, IComparator)
public
function Compare(a, b: Pointer): Integer;
function Initialize(a: Pointer): Pointer;
procedure Finalize(a: Pointer);
end;
TEventMultiplexer = class
public
FListeners: IList;
constructor Create;
procedure Add(Method: TNotifyEvent);
procedure Remove(Method: TNotifyEvent);
procedure RemoveSource(Source: TObject);
procedure FireNotifyEvent(Sender: TObject);
function Iterator: IIterator;
end;
TStringComparator = class(TBasicObject, IComparator)
function Compare(a, b: Pointer): Integer;
procedure Finalize(a: Pointer);
function Initialize(a: Pointer): Pointer;
end;
IStringIterator = interface
['{07666934-BDBD-11D2-88CE-000021994143}']
function HasElement: Boolean;
function Get: string;
procedure Next;
end;
IStringList = interface
['{07666933-BDBD-11D2-88CE-000021994143}']
procedure Add(Value: string);
function Remove(Value: string): Boolean;
procedure AddAll(C: IStringList);
procedure RetainAll(C: IStringList);
procedure RemoveAll(C: IStringList);
procedure Clear;
function StringIterator: IStringIterator;
function Iterator: IIterator;
function IsEmpty: Boolean;
function Contains(Value: string): Boolean;
function ContainsAll(C: IStringList): Boolean;
function CollectionEquals(Value: IStringList): Boolean;
function GetSize: Integer;
property Size: Integer read GetSize;
end;
IStringMap = interface
['{07666932-BDBD-11D2-88CE-000021994143}']
procedure Clear;
procedure Put(Key: string; Value: Pointer);
function RemoveKey(Key: string): Boolean;
function RemoveValue(Value: Pointer): Boolean;
function GetSize: Integer;
function Get(Key: string): Pointer;
function FindKey(Key: string): IIterator;
function Iterator: IIterator;
function GetComparator: IComparator;
procedure SetComparator(const Value: IComparator);
property Size: Integer read GetSize;
property Comparator: IComparator read GetComparator write SetComparator;
function ContainsKey(Key: string): Boolean;
function ContainsValue(Key: Pointer): Boolean;
function Keys: IStringList;
function Values: ICollection;
function IsEmpty: Boolean;
end;
TStringMap = class(TBasicObject, IStringMap)
private
FMap: IMap;
FKeys: IStringList;
public
constructor Create;
procedure Clear;
procedure Put(Key: string; Value: Pointer);
function RemoveKey(Key: string): Boolean;
function RemoveValue(Value: Pointer): Boolean;
function GetSize: Integer;
function Get(Key: string): Pointer;
function FindKey(Key: string): IIterator;
function Iterator: IIterator;
function GetComparator: IComparator;
procedure SetComparator(const Value: IComparator);
property Size: Integer read GetSize;
property Comparator: IComparator read GetComparator write SetComparator;
function ContainsKey(Key: string): Boolean;
function ContainsValue(Key: Pointer): Boolean;
function Keys: IStringList;
function Values: ICollection;
function IsEmpty: Boolean;
end;
TCollections = class
class function CreateList: IList;
class function CreateMap: IMap;
class function CreateStringMap: IStringMap;
end;
implementation
type
TDequeIterator = class(TInterfacedObject, IListIterator, IIterator)
public
function HasElement: Boolean;
function Get: Pointer;
procedure Next;
procedure Put(Value: Pointer);
procedure Add(Value: Pointer);
function GetIndex: Integer;
procedure Prior;
procedure Remove;
private
Index: Integer;
Deque: TDeque;
Cursor: TDequeNode;
Reversed: Boolean;
constructor Create(Deque: TDeque; Cursor: TDequeNode; Reversed: Boolean; Index: Integer);
end;
procedure CollectionError(Msg: string);
begin
raise ECollectionError.Create(Msg);
end;
function Supports(Intf: IUnknown; const IID: TGUID): Boolean;
var
Buf: Integer;
begin
Intf.QueryInterface(IID, Buf);
Result := Buf <> 0;
end;
procedure UnsupportedError;
begin
CollectionError('Unsupported operation');
end;
function CompareObject(a, b: Pointer; Cmp: IComparator): Integer;
begin
if Cmp <> nil then
Result := Cmp.Compare(a, b)
else
Result := Integer(a) - Integer(b);
end;
procedure FinalizeObject(a: Pointer; Cmp: IComparator);
begin
if Cmp <> nil then
Cmp.Finalize(a);
end;
function InitializeObject(b: Pointer; Cmp: IComparator): Pointer;
begin
if Cmp <> nil then
Result := Cmp.Initialize(b)
else
Result := b;
end;
procedure ComparasionError;
begin
CollectionError('Cannot perform comparasion on different type of object');
end;
{ TDeque }
procedure TDeque.Add(Value: Pointer);
begin
AddLast(Value);
end;
procedure TDeque.AddLast(Value: Pointer);
var
N: TDequeNode;
begin
N := TDequeNode.Create(InitializeObject(Value, FComparator), nil, FLast);
if FLast <> nil then
FLast.Next := N;
FLast := N;
if FFirst = nil then
FFirst := FLast;
Inc(FSize);
end;
procedure TDeque.AddFirst(Value: Pointer);
var
N: TDequeNode;
begin
N := TDequeNode.Create(InitializeObject(Value, FComparator), FFirst, nil);
if FFirst <> nil then
FFirst.Prev := N;
FFirst := N;
if FLast = nil then
FLast := FFirst;
Inc(FSize);
end;
constructor TDeque.Create;
begin
end;
function TDeque.Iterator: IIterator;
begin
Result := TDequeIterator.Create(Self, FFirst, False, 0);
end;
function TDeque.Remove(Value: Pointer): Boolean;
var
N: TDequeNode;
begin
N := FFirst;
while N <> nil do
begin
if CompareObject(N.Value, Value, FComparator) = 0 then
begin
if N = FFirst then
begin
FFirst := FFirst.Next;
FFirst.Prev := nil;
end
else
begin
N.Prev.Next := N.Next;
N.Next.Prev := N.Prev;
end;
FinalizeObject(N.Value, FComparator);
N.Free;
Result := True;
Dec(FSize);
Exit;
end;
N := N.Next;
end;
Result := False;
end;
function TDeque.RemoveLast: Pointer;
var
N: TDequeNode;
begin
if FSize = 0 then
CollectionError('Cannot not remove any last element in an empty deque');
N := FLast;
FLast := FLast.Prev;
if FLast <> nil then
FLast.Next := nil
else
FFirst := nil;
Result := N.Value;
FinalizeObject(N.Value, FComparator);
N.Free;
Dec(FSize);
end;
function TDeque.RemoveFirst: Pointer;
var
N: TDequeNode;
begin
if FSize = 0 then
CollectionError('Cannot not remove any last element in an empty deque');
N := FFirst;
FFirst := FFirst.Next;
if FFirst <> nil then
FFirst.Prev := nil
else
FLast := nil;
Result := N.Value;
FinalizeObject(N.Value, FComparator);
N.Free;
Dec(FSize);
end;
function TDeque.ReversedIterator: IIterator;
begin
Result := TDequeIterator.Create(Self, FLast, True, FSize-1);
end;
function TDeque.GetSize: Integer;
begin
Result := FSize;
end;
function TDeque.Contains(Value: Pointer): Boolean;
var
N: TDequeNode;
begin
N := FFirst;
while N <> nil do
begin
if CompareObject(N.Value, Value, FComparator) = 0 then
begin
Result := True;
Exit
end;
N := N.Next;
end;
Result := False;
end;
function CompareBasicObject(a, b: Pointer; Comparator: IComparator): Integer;
begin
if Comparator = nil then
Result := Integer(a) - Integer(b) // Pointer comparasion
else
Result := Comparator.Compare(a, b);
end;
procedure TDeque.Clear;
var
p, pp: TDequeNode;
begin
p := FFirst;
while p <> nil do
begin
pp := p.Next;
p.Free;
p := pp;
end;
FFirst := nil;
FLast := nil;
FSize := 0;
end;
function TDeque.ListIterator(Index: Integer): IListIterator;
begin
Result := TDequeIterator.Create(Self, GetNodeAt(Index), False, Index);
end;
function TDeque.GetNodeAt(Index: Integer): TDequeNode;
var
I: Integer;
begin
if (Index >= 0) and (Index < (FSize div 2)) then
begin
I := 0;
Result := FFirst;
while (Result <> nil) and (I <> Index) do
begin
Inc(I);
Result := Result.Next;
end;
if Result = nil then
CollectionError('Deque access out of range');
end
else if (Index >= (FSize div 2)) and (Index < FSize) then
begin
I := FSize-1;
Result := FLast;
while (Result <> nil) and (I <> Index) do
begin
Dec(I);
Result := Result.Next;
end;
if Result = nil then
CollectionError('Deque access out of range');
end else
begin
Result := nil;
CollectionError('Deque access out of range');
end;
end;
{ TDequeNode }
constructor TDequeNode.Create(Value: Pointer; Next, Prev: TDequeNode);
begin
Self.Value := Value;
Self.Next := Next;
Self.Prev := Prev;
end;
{ TDequeIterator }
procedure TDequeIterator.Add(Value: Pointer);
var
Node: TDequeNode;
begin
if Cursor <> nil then
begin
Node := TDequeNode.Create(InitializeObject(Value, Deque.FComparator), nil, nil);
if not Reversed then
begin
Node.Next := Cursor;
Node.Prev := Cursor.Prev;
if Cursor.Prev <> nil then
Cursor.Prev.Next := Node
else
Deque.FFirst := Node;
Cursor.Prev := Node;
end
else
begin
Node.Next := Cursor.Next;
Node.Prev := Cursor;
if Cursor.Next <> nil then
Cursor.Next.Prev := Node
else
Deque.FLast := Node;
Cursor.Next := Node;
end;
Cursor := Node;
end else
begin
if not Reversed then
begin
Deque.AddLast(Value);
Cursor := Deque.FLast;
end
else
begin
Deque.AddFirst(Value);
Cursor := Deque.FFirst;
end;
end;
end;
constructor TDequeIterator.Create(Deque: TDeque; Cursor: TDequeNode; Reversed: Boolean; Index: Integer);
begin
Self.Deque := Deque;
Self.Cursor := Cursor;
Self.Reversed := Reversed;
Self.Index := Index;
end;
function TDequeIterator.Get: Pointer;
begin
if Cursor = nil then
CollectionError('Attempting to get element from an already empty deque iteration. ');
Result := Cursor.Value;
end;
function TDequeIterator.GetIndex: Integer;
begin
Result := Index;
end;
function TDequeIterator.HasElement: Boolean;
begin
Result := Cursor <> nil;
end;
procedure TDequeIterator.Next;
begin
if Cursor = nil then
CollectionError('Deque iteration is out of range');
if Reversed then
begin
Cursor := Cursor.Prev;
Inc(Index)
end
else
begin
Cursor := Cursor.Next;
Dec(Index);
end;
end;
procedure TDequeIterator.Prior;
begin
if Cursor = nil then
CollectionError('Deque iteration is out of range');
if Reversed then
begin
Cursor := Cursor.Next;
Dec(Index)
end
else
begin
Cursor := Cursor.Prev;
Inc(Index);
end;
end;
procedure TDequeIterator.Put(Value: Pointer);
begin
UnsupportedError;
end;
procedure TDequeIterator.Remove;
var
Temp: TDequeNode;
begin
if Cursor = nil then
CollectionError('Cannot remove anything in an empty deque');
if Cursor = Deque.FFirst then
Deque.FFirst := Cursor.Next;
if Cursor = Deque.FLast then
Deque.FLast := Cursor.Prev;
Temp := Cursor;
if not Reversed then
begin
Cursor := Cursor.Next;
if Cursor <> nil then
Cursor.Prev := nil;
end
else
begin
Cursor := Cursor.Prev;
if Cursor <> nil then
Cursor.Next := nil;
end;
FinalizeObject(Temp.Value, Deque.FComparator);
Temp.Free;
end;
{ TAbstractCollection }
procedure TAbstractCollection.AddAll(C: ICollection);
var
I: IIterator;
begin
I := C.Iterator;
while I.HasElement do
begin
Add(I.Get);
I.Next;
end;
end;
// Performs a rough equality comparasion between two abstract collection
function TAbstractCollection.CollectionEquals(Value: ICollection): Boolean;
var
I, J: IIterator;
C: ICollection;
begin
Result := False;
if Value.Supports(ICollection) then
begin
C := Value as ICollection;
if GetSize <> C.Size then
Exit;
I := Iterator;
J := C.Iterator;
while (I <> nil) and (J <> nil) do
begin
if CompareObject(I.Get, J.Get, FComparator) <> 0 then
Exit;
I.Next;
J.Next;
end;
if (I <> nil) or (J <> nil) then
Exit;
Result := True;
end;
end;
procedure TAbstractCollection.RemoveAll(C: ICollection);
var
I: IIterator;
begin
I := C.Iterator;
while I.HasElement do
begin
Remove(I.Get);
I.Next;
end;
end;
procedure TAbstractCollection.RetainAll(C: ICollection);
begin
UnsupportedError;
end;
function TAbstractCollection.ContainsAll(C: ICollection): Boolean;
var
I: IIterator;
begin
I := C.Iterator;
Result := False;
while I.HasElement do
begin
if not Contains(I.Get) then
Exit;
I.Next;
end;
Result := True;
end;
function TAbstractCollection.GetComparator: IComparator;
begin
Result := FComparator;
end;
procedure TAbstractCollection.SetComparator(Value: IComparator);
begin
FComparator := Value;
end;
function TAbstractCollection.IsEmpty: Boolean;
begin
Result := GetSize = 0;
end;
{ TBasicObject }
constructor TBasicObject.CreateEmpty;
begin
end;
function TBasicObject.GetObject: TBasicObject;
begin
Result := Self;
end;
function TBasicObject.Supports(const IID: TGUID): Boolean;
var
Buf: Integer;
begin
QueryInterface(IID, Buf);
Result := Buf <> 0;
_Release;
end;
{ TTreeMap }
procedure TTreeMap.Put(Key, Value: Pointer);
var
x: TTreeNode;
begin
x := FindNode(Key);
if x = nil then
begin
x := TTreeNode.Create;
x.Key := InitializeObject(Key, FKeyComparator);
x.Value := InitializeObject(Value, FValueComparator);
RB_Insert(x);
end
else
begin
FinalizeObject(x.Value, FValueComparator);
x.Value := InitializeObject(Value, FValueComparator);
end;
end;
function TTreeMap.GetSize: Integer;
begin
Result := FSize;
end;
procedure TTreeMap.LeftRotate(x: TTreeNode);
var
y: TTreeNode;
begin
y := x.Right;
x.Right := y.Left;
if y.Left <> nil then
y.Left.Parent := x;
y.Parent := x.Parent;
if x.Parent = nil then
FRoot := y
else
begin
if x = x.Parent.Left then
x.Parent.Left := y
else
x.Parent.Right := y;
end;
y.Left := x;
x.Parent := y;
end;
procedure TTreeMap.RB_Delete(p: TTreeNode);
var
replacement, s: TTreeNode;
begin
Dec(FSize);
// If strictly internal, first swap position with successor.
if (p.left <> nil) and (p.right <> nil) then begin
s := TreeSuccessor(p);
SwapPosition(s, p);
end;
// Start fixup at replacement node, if it exists.
if p.left <> nil then
replacement := p.left
else
replacement := p.right;
if (replacement <> nil) then begin
// Link replacement to parent
replacement.parent := p.parent;
if (p.parent = nil) then
froot := replacement
else if (p = p.parent.left) then
p.parent.left := replacement
else
p.parent.right := replacement;
// nil out links so they are OK to use by fixAfterDeletion.
p.left := nil;
p.right := nil;
p.parent := nil;
// Fix replacement
if (p.color = ncBlack) then
RB_DeleteFixup(replacement);
end else if (p.parent = nil) then begin // return if we are the only node.
froot := nil;
end else begin // No children. Use self as phantom replacement and unlink.
if (p.color = ncBlack) then
RB_DeleteFixup(p);
if (p.parent <> nil) then begin
if (p = p.parent.left) then
p.parent.left := nil
else if (p = p.parent.right) then
p.parent.right := nil;
p.parent := nil;
end
end;
FinalizeObject(p.Key, FKeyComparator);
FinalizeObject(p.Value, FValueComparator);
p.Free;
end;
procedure TTreeMap.SwapPosition(x, y: TTreeNode);
var
px, py, lx, ly, rx, ry: TTreeNode;
xWasLeftChild, yWasLeftChild: Boolean;
c: TNodeColor;
begin
// Save initial values.
px := x.parent;
lx := x.left;
rx := x.right;
py := y.parent;
ly := y.left;
ry := y.right;
xWasLeftChild := (px <> nil) and (x = px.left);
yWasLeftChild := (py <> nil) and (y = py.left);
// Swap, handling special cases of one being the other's parent.
if (x = py) then
begin // x was y's parent
x.parent := y;
if (yWasLeftChild) then begin
y.left := x;
y.right := rx;
end else begin
y.right := x;
y.left := lx;
end
end else
begin
x.parent := py;
if (py <> nil) then begin
if (yWasLeftChild) then
py.left := x
else
py.right := x;
end;
y.left := lx;
y.right := rx;
end;
if (y = px) then begin // y was x's parent
y.parent := x;
if (xWasLeftChild) then begin
x.left := y;
x.right := ry;
end else begin
x.right := y;
x.left := ly;
end
end else begin
y.parent := px;
if (px <> nil) then begin
if (xWasLeftChild) then
px.left := y
else
px.right := y;
end;
x.left := ly;
x.right := ry;
end;
// Fix children's parent pointers
if (x.left <> nil) then
x.left.parent := x;
if (x.right <> nil) then
x.right.parent := x;
if (y.left <> nil) then
y.left.parent := y;
if (y.right <> nil) then
y.right.parent := y;
// Swap colors
c := x.color;
x.color := y.color;
y.color := c;
// Check if root changed
if (froot = x) then
froot := y
else if (froot = y) then
froot := x;
end;
procedure TTreeMap.RB_DeleteFixup(x: TTreeNode);
var
w: TTreeNode;
begin
while (x <> FRoot) and (x.Color = ncBlack) do
begin
if x = x.Parent.Left then
begin
w := x.Parent.Right;
if w.Color = ncRed then
begin
w.Color := ncBlack;
x.Parent.Color := ncRed;
LeftRotate(x.Parent);
w := x.Parent.Right;
end;
if (w.Left.Color = ncBlack) and (w.Right.Color = ncBlack) then
begin
w.Color := ncRed;
x := x.Parent;
end else
begin
if w.Right.Color = ncBlack then
begin
w.Left.Color := ncBlack;
w.Color := ncRed;
RightRotate(w);
w := x.Parent.Right;
end;
w.Color := x.Parent.Color;
x.Parent.Color := ncBlack;
w.Right.Color := ncBlack;
LeftRotate(x.Parent);
x := FRoot;
end;
end
else
begin
w := x.Parent.Left;
if w.Color = ncRed then
begin
w.Color := ncBlack;
x.Parent.Color := ncRed;
RightRotate(x.Parent);
w := x.Parent.Left;
end;
if (w.Right.Color = ncBlack) and (w.Left.Color = ncBlack) then
begin
w.Color := ncRed;
x := x.Parent;
end else
begin
if w.Left.Color = ncBlack then
begin
w.Right.Color := ncBlack;
w.Color := ncRed;
LeftRotate(w);
w := x.Parent.Left;
end;
w.Color := x.Parent.Color;
x.Parent.Color := ncBlack;
w.Left.Color := ncBlack;
RightRotate(x.Parent);
x := FRoot;
end;
end;
end;
x.Color := ncBlack;
end;
procedure TTreeMap.RB_Insert(x: TTreeNode);
var
y: TTreeNode;
begin
TreeInsert(x);
x.Color := ncRed;
while (x <> FRoot) and (x.Parent.Color = ncRed) do
begin
if x.Parent = x.Parent.Parent.Left then
begin
y := x.Parent.Parent.Right;
if y.Color = ncRed then
begin
x.Parent.Color := ncBlack;
y.Color := ncBlack;
x.Parent.Parent.Color := ncRed;
x := x.Parent.Parent;
end else
begin
if x = x.Parent.Right then
begin
x := x.Parent;
LeftRotate(x);
end;
x.Parent.Color := ncBlack;
x.Parent.Parent.Color := ncRed;
RightRotate(x.Parent.Parent);
end;
end else
begin
y := x.Parent.Parent.Left;
if y.Color = ncRed then
begin
x.Parent.Color := ncBlack;
y.Color := ncBlack;
x.Parent.Parent.Color := ncRed;
x := x.Parent.Parent;
end else
begin
if x = x.Parent.Left then
begin
x := x.Parent;
RightRotate(x);
end;
x.Parent.Color := ncBlack;
x.Parent.Parent.Color := ncRed;
LeftRotate(x.Parent.Parent);
end;
end;
end;
FRoot.Color := ncBlack;
Inc(FSize);
end;
function TTreeMap.RemoveKey(Key: Pointer): Boolean;
var
x: TTreeNode;
begin
x := FindNode(Key);
Result := False;
if x <> nil then
begin
RB_Delete(x);
Result := True;
end;
end;
function TTreeMap.RemoveValue(Value: Pointer): Boolean;
var
I: TTreeMapIterator;
begin
Result := False;
I := (Iterator as IBasicObject).GetObject as TTreeMapIterator;
while I.HasElement do
begin
if CompareBasicObject(I.Value, Value, nil) = 0 then
begin
RB_Delete(I.Cursor);
Result := True;
Exit;
end;
I.Next;
end;
end;
procedure TTreeMap.RightRotate(x: TTreeNode);
var
y: TTreeNode;
begin
y := x.Left;
x.Left := y.Right;
if y.Right <> nil then
y.Right.Parent := x;
y.Parent := x.Parent;
if x.Parent = nil then
FRoot := y
else
begin
if x = x.Parent.Right then
x.Parent.Right := y
else
x.Parent.Left := y;
end;
y.Right := x;
x.Parent := y;
end;
procedure TTreeMap.TreeInsert(z: TTreeNode);
var
x, y: TTreeNode;
begin
y := nil;
x := FRoot;
while x <> nil do
begin
y := x;
if CompareObject(z.Key, x.Key, FKeyComparator) < 0 then
x := x.Left
else
x := x.Right;
end;
z.Parent := y;
if y = nil then
FRoot := z
else if CompareObject(z.Key, y.Key, FKeyComparator) < 0 then
y.Left := z
else
y.Right := z;
end;
function TTreeMap.TreeSuccessor(x: TTreeNode): TTreeNode;
var
y: TTreeNode;
begin
if x.Right <> nil then
begin
Result := TreeMinimum(x.Right);
Exit;
end;
y := x.Parent;
while (y <> nil) and (x = y.Right) do
begin
x := y;
y := y.Parent;
end;
Result := y;
end;
function TTreeMap.TreeMinimum(x: TTreeNode): TTreeNode;
begin
while x.Left <> nil do
x := x.Left;
Result := x;
end;
function TTreeMap.FindNode(Key: Pointer): TTreeNode;
var
x: TTreeNode;
begin
x := FRoot;
while (x <> nil) do
begin
if CompareObject(Key, x.Key, FKeyComparator) = 0 then
begin
Result := x;
Exit;
end;
if CompareObject(Key, x.Key, FKeyComparator) < 0 then
x := x.Left
else
x := x.Right;
end;
Result := nil;
end;
function TTreeMap.TreeMaximum(x: TTreeNode): TTreeNode;
begin
while x.Right <> nil do
x := x.Right;
Result := x;
end;
function TTreeMap.TreePredecessor(x: TTreeNode): TTreeNode;
var
y: TTreeNode;
begin
if x.Left <> nil then
begin
Result := TreeMaximum(x.Left);
Exit;
end;
y := x.Parent;
while (y <> nil) and (x = y.Left) do
begin
x := y;
y := y.Parent;
end;
Result := y;
end;
function TTreeMap.FindKey(Key: Pointer): IMapIterator;
begin
Result := TTreeMapIterator.Create(FindNode(Key), Self, False);
end;
function TTreeMap.Iterator: IIterator;
begin
Result := TTreeMapIterator.Create(TreeMinimum(FRoot), Self, False);
end;
function TTreeMap.Get(Key: Pointer): Pointer;
var
x: TTreeNode;
begin
x := FindNode(Key);
if x = nil then
Result := nil
else
Result := x.Value;
end;
procedure TTreeMap.Clear;
begin
if FRoot <> nil then
begin
FRoot.Clear(Self);
FRoot.Free;
FRoot := nil;
end;
end;
destructor TTreeMap.Destroy;
begin
Clear;
inherited Destroy;
end;
type
TMapKeys = class(TAbstractCollection)
public
function Contains(Value: Pointer): Boolean; override;
procedure Add(Value: Pointer); override;
function Remove(Value: Pointer): Boolean; override;
function Iterator: IIterator; override;
function GetSize: Integer; override;
procedure Clear; override;
private
TreeMap: TTreeMap;
constructor Create(TreeMap: TTreeMap);
end;
TMapValues = class(TAbstractCollection)
public
function Contains(Value: Pointer): Boolean; override;
procedure Add(Value: Pointer); override;
function Remove(Value: Pointer): Boolean; override;
function Iterator: IIterator; override;
function GetSize: Integer; override;
procedure Clear; override;
private
TreeMap: TTreeMap;
constructor Create(TreeMap: TTreeMap);
end;
function TTreeMap.Keys: ICollection;
begin
if FKeys = nil then
FKeys := TMapKeys.Create(Self);
Result := FKeys;
end;
function TTreeMap.Values: ICollection;
begin
if FValues = nil then
FValues := TMapValues.Create(Self);
Result := FValues;
end;
function TTreeMap.ReversedIterator: IIterator;
begin
Result := TTreeMapIterator.Create(TreeMinimum(FRoot), Self, True);
end;
function TTreeMap.MapIterator: IMapIterator;
begin
Result := Iterator as IMapIterator;
end;
{ TTreeMapIterator }
procedure TTreeMapIterator.Add(Value: Pointer);
begin
UnsupportedError;
end;
constructor TTreeMapIterator.Create(Cursor: TTreeNode; Map: TTreeMap; Reversed: Boolean);
begin
Self.Cursor := Cursor;
Self.Map := Map;
Self.Reversed := Reversed;
end;
function TTreeMapIterator.Get: Pointer;
begin
Result := GetValue;
end;
function TTreeMapIterator.GetIndex: Integer;
begin
Result := -1;
UnsupportedError;
end;
function TTreeMapIterator.GetKey: Pointer;
begin
Result := Cursor.Key;
end;
function TTreeMapIterator.GetValue: Pointer;
begin
Result := Cursor.Value;
end;
function TTreeMapIterator.HasElement: Boolean;
begin
Result := Cursor <> nil;
end;
procedure TTreeMapIterator.Next;
begin
if Cursor = nil then
CollectionError('No element(s) left');
if not Reversed then
Cursor := Map.TreeSuccessor(Cursor)
else
Cursor := Map.TreePredecessor(Cursor);
end;
procedure TTreeMapIterator.Prior;
begin
if Cursor = nil then
CollectionError('No element(s) left');
if not Reversed then
Cursor := Map.TreePredecessor(Cursor)
else
Cursor := Map.TreeSuccessor(Cursor);
end;
procedure TTreeMapIterator.Put(Value: Pointer);
begin
UnsupportedError;
end;
procedure TTreeMapIterator.Remove;
var
Temp: TTreeNode;
begin
if Cursor = nil then
CollectionError('Cannot remove nothing');
Temp := Cursor;
if not Reversed then
Cursor := Map.TreeSuccessor(Cursor)
else
Cursor := Map.TreePredecessor(Cursor);
Map.RB_Delete(Temp);
end;
procedure TTreeMapIterator.SetKey(Key: Pointer);
begin
UnsupportedError;
end;
procedure TTreeMapIterator.SetValue(Value: Pointer);
begin
UnsupportedError;
end;
{ TTreeNode }
procedure TTreeNode.Clear(TreeMap: TTreeMap);
begin
if Left <> nil then
begin
Left.Clear(TreeMap);
Left.Free;
Left := nil;
end;
if Right <> nil then
begin
Right.Clear(TreeMap);
Right.Free;
Right := nil;
end;
FinalizeObject(Key, TreeMap.FKeyComparator);
FinalizeObject(Value, TreeMap.FValueComparator);
Parent := nil;
end;
constructor TTreeNode.Create;
begin
end;
function TTreeNode.GetColor: TNodeColor;
begin
if Self = nil then
Result := ncBlack
else
Result := FColor;
end;
function TTreeNode.GetLeft: TTreeNode;
begin
if Self = nil then
Result := nil
else
Result := FLeft;
end;
function TTreeNode.GetParent: TTreeNode;
begin
if Self = nil then
Result := nil
else
Result := FParent;
end;
function TTreeNode.GetRight: TTreeNode;
begin
if Self = nil then
Result := nil
else
Result := FRight;
end;
procedure TTreeNode.SetColor(const Value: TNodeColor);
begin
if Self <> nil then
FColor := Value;
end;
procedure TTreeNode.SetLeft(const Value: TTreeNode);
begin
if Self <> nil then
FLeft := Value;
end;
procedure TTreeNode.SetParent(const Value: TTreeNode);
begin
if Self <> nil then
FParent := Value;
end;
procedure TTreeNode.SetRight(const Value: TTreeNode);
begin
if Self <> nil then
FRight := Value;
end;
{ TAbstractMap }
function TAbstractMap.ContainsKey(Key: Pointer): Boolean;
begin
Result := FindKey(Key).HasElement;
end;
function TAbstractMap.ContainsValue(Value: Pointer): Boolean;
var
I: IIterator;
begin
I := Iterator;
while I.HasElement do
begin
if CompareObject(I.Get, Value, FValueComparator) = 0 then
begin
Result := True;
Exit;
end;
I.Next;
end;
Result := False;
end;
function TAbstractMap.MapEquals(M: IMap): Boolean;
begin
Result := False;
UnsupportedError;
end;
procedure TAbstractMap.PutAll(M: IMap);
var
I: IMapIterator;
begin
I := M.Iterator as IMapIterator;
while I.HasElement do
begin
Put(I.GetKey, I.GetValue);
I.Next;
end;
end;
function TAbstractMap.GetKeyComparator: IComparator;
begin
Result := FKeyComparator;
end;
function TAbstractMap.GetValueComparator: IComparator;
begin
Result := FValueComparator;
end;
procedure TAbstractMap.SetKeyComparator(const Value: IComparator);
begin
FKeyComparator := Value;
end;
procedure TAbstractMap.SetValueComparator(const Value: IComparator);
begin
FValueComparator := Value;
end;
constructor TAbstractMap.Create;
begin
FValueOwnership := True;
FKeyOwnership := True;
end;
function TAbstractMap.IsEmpty: Boolean;
begin
Result := GetSize = 0;
end;
function TAbstractMap.ReversedIterator: IIterator;
begin
UnsupportedError;
end;
{ TMapKeys }
procedure TMapKeys.Add(Value: Pointer);
begin
TreeMap.Put(Value, nil);
end;
procedure TMapKeys.Clear;
begin
TreeMap.Clear;
end;
function TMapKeys.Contains(Value: Pointer): Boolean;
begin
Result := TreeMap.ContainsKey(Value);
end;
constructor TMapKeys.Create(TreeMap: TTreeMap);
begin
Self.TreeMap := TreeMap;
end;
function TMapKeys.GetSize: Integer;
begin
Result := TreeMap.GetSize;
end;
function TMapKeys.Iterator: IIterator;
begin
Result := TMapKeyIterator.Create(TreeMap.TreeMinimum(TreeMap.FRoot), TreeMap, False);
end;
function TMapKeys.Remove(Value: Pointer): Boolean;
begin
Result := TreeMap.RemoveKey(Value);
end;
{ TMapKeyIterator }
function TMapKeyIterator.Get: Pointer;
begin
Result := GetKey;
end;
{ TMapValues }
procedure TMapValues.Add(Value: Pointer);
begin
UnsupportedError;
end;
procedure TMapValues.Clear;
begin
TreeMap.Clear;
end;
function TMapValues.Contains(Value: Pointer): Boolean;
begin
Result := TreeMap.ContainsValue(Value);
end;
constructor TMapValues.Create(TreeMap: TTreeMap);
begin
Self.TreeMap := TreeMap;
end;
function TMapValues.GetSize: Integer;
begin
Result := TreeMap.GetSize;
end;
function TMapValues.Iterator: IIterator;
begin
Result := TreeMap.Iterator;
end;
function TMapValues.Remove(Value: Pointer): Boolean;
begin
Result := TreeMap.RemoveValue(Value);
end;
{ TStringComparator }
function TStringComparator.Compare(a, b: Pointer): Integer;
begin
Result := AnsiCompareStr(PString(a)^, PString(b)^);
end;
procedure TStringComparator.Finalize(a: Pointer);
begin
// WriteLn(PString(a)^, ' is being destroyed');
DisposeStr(a);
end;
function TStringComparator.Initialize(a: Pointer): Pointer;
begin
Result := NewStr(PString(a)^);
end;
{ TTreeSet }
procedure TTreeSet.Add(Value: Pointer);
begin
FMap.Put(Value, nil);
end;
procedure TTreeSet.Clear;
begin
FMap.Clear;
end;
function TTreeSet.Contains(Value: Pointer): Boolean;
begin
Result := FMap.ContainsKey(Value);
end;
constructor TTreeSet.Create;
begin
FMap := TTreeMap.Create;
end;
function TTreeSet.GetComparator: IComparator;
begin
Result := FMap.GetKeyComparator;
end;
function TTreeSet.GetSize: Integer;
begin
Result := FMap.GetSize;
end;
function TTreeSet.Iterator: IIterator;
begin
Result := FMap.Keys.Iterator;
end;
function TTreeSet.Remove(Value: Pointer): Boolean;
begin
Result := FMap.RemoveKey(Value);
end;
procedure TTreeSet.SetComparator(Value: IComparator);
begin
FMap.SetKeyComparator(Value);
end;
{ TEventMultiplexer }
procedure TEventMultiplexer.Add(Method: TNotifyEvent);
begin
FListeners.Add(@Method);
end;
constructor TEventMultiplexer.Create;
begin
FListeners := TDeque.Create;
FListeners.Comparator := TBlobComparator.Create(SizeOf(TMethod));
end;
procedure TEventMultiplexer.Remove(Method: TNotifyEvent);
begin
FListeners.Remove(@Method);
end;
procedure TEventMultiplexer.RemoveSource(Source: TObject);
var
I: IIterator;
begin
I := FListeners.Iterator;
while I.HasElement do
begin
if TMethod(I.Get^).Data = Pointer(Source) then
I.Remove
else
I.Next;
end;
end;
procedure TEventMultiplexer.FireNotifyEvent(Sender: TObject);
var
I: IIterator;
begin
I := FListeners.Iterator;
while I.HasElement do
begin
TNotifyEvent(I.Get^)(Self);
I.Next;
end;
end;
{ TPointerComparator }
function TEventMultiplexer.Iterator: IIterator;
begin
Result := FListeners.Iterator;
end;
{ TBlobComparator }
function TBlobComparator.Compare(a, b: Pointer): Integer;
var
pa, pb: PChar;
i: Integer;
begin
Result := 0;
pa := a;
pb := b;
for i:=0 to Length-1 do
Inc(Result, Ord(pa[i]) - Ord(pb[i]));
end;
constructor TBlobComparator.Create(Length: Integer);
begin
Self.Length := Length;
end;
procedure TBlobComparator.Finalize(a: Pointer);
begin
Dispose(a);
end;
type
TStringMapKeys = class(TBasicObject, IStringList)
private
StringMap: TStringMap;
public
constructor Create(StringMap: TStringMap);
procedure Add(Value: string);
function Remove(Value: string): Boolean;
procedure AddAll(C: IStringList);
procedure RetainAll(C: IStringList);
procedure RemoveAll(C: IStringList);
procedure Clear;
function StringIterator: IStringIterator;
function Iterator: IIterator;
function IsEmpty: Boolean;
function Contains(Value: string): Boolean;
function ContainsAll(C: IStringList): Boolean;
function CollectionEquals(Value: IStringList): Boolean;
function GetSize: Integer;
property Size: Integer read GetSize;
end;
TStringMapKeysIterator = class(TBasicObject, IStringIterator)
private
FIter: IMapIterator;
public
constructor Create(StringMap: TStringMap);
function HasElement: Boolean;
function Get: string;
procedure Next;
end;
function TBlobComparator.Initialize(a: Pointer): Pointer;
begin
GetMem(Result, Length);
Move(a^, Result^, Length);
end;
{ TStringMap }
procedure TStringMap.Clear;
begin
FMap.Clear;
end;
function TStringMap.ContainsKey(Key: string): Boolean;
begin
Result := FMap.ContainsKey(@Key);
end;
function TStringMap.ContainsValue(Key: Pointer): Boolean;
begin
Result := FMap.ContainsValue(Key);
end;
constructor TStringMap.Create;
begin
FMap := TTreeMap.Create;
FMap.KeyComparator := TStringComparator.Create;
end;
function TStringMap.FindKey(Key: string): IIterator;
begin
Result := FMap.FindKey(@Key) as IIterator;
end;
function TStringMap.Get(Key: string): Pointer;
begin
Result := FMap.Get(@Key);
end;
function TStringMap.GetComparator: IComparator;
begin
Result := FMap.GetValueComparator;
end;
function TStringMap.GetSize: Integer;
begin
Result := FMap.Size;
end;
function TStringMap.IsEmpty: Boolean;
begin
Result := FMap.IsEmpty;
end;
function TStringMap.Iterator: IIterator;
begin
Result := FMap.Iterator;
end;
function TStringMap.Keys: IStringList;
begin
if FKeys = nil then
FKeys := TStringMapKeys.Create(Self);
Result := FKeys;
end;
procedure TStringMap.Put(Key: string; Value: Pointer);
begin
FMap.Put(NewStr(Key), Value);
end;
function TStringMap.RemoveKey(Key: string): Boolean;
begin
Result := FMap.RemoveKey(@Key);
end;
function TStringMap.RemoveValue(Value: Pointer): Boolean;
begin
Result := FMap.RemoveValue(Value);
end;
procedure TStringMap.SetComparator(const Value: IComparator);
begin
FMap.SetValueComparator(Value);
end;
function TStringMap.Values: ICollection;
begin
Result := FMap.Values;
end;
{ TStringMapKeys }
procedure TStringMapKeys.Add(Value: string);
begin
StringMap.Put(Value, nil);
end;
procedure TStringMapKeys.AddAll(C: IStringList);
var
I: IStringIterator;
begin
I := C.StringIterator;
while I.HasElement do
begin
Add(I.Get);
I.Next;
end;
end;
procedure TStringMapKeys.Clear;
begin
StringMap.Clear;
end;
function TStringMapKeys.CollectionEquals(Value: IStringList): Boolean;
begin
UnsupportedError;
Result := False;
end;
function TStringMapKeys.Contains(Value: string): Boolean;
begin
Result := StringMap.ContainsKey(Value);
end;
function TStringMapKeys.ContainsAll(C: IStringList): Boolean;
var
I: IStringIterator;
begin
I := C.StringIterator;
Result := False;
while I.HasElement do
begin
if not Contains(I.Get) then
Exit;
I.Next;
end;
Result := True;
end;
constructor TStringMapKeys.Create(StringMap: TStringMap);
begin
Self.StringMap := StringMap;
end;
function TStringMapKeys.GetSize: Integer;
begin
Result := StringMap.GetSize;
end;
function TStringMapKeys.IsEmpty: Boolean;
begin
Result := StringMap.IsEmpty;
end;
function TStringMapKeys.Iterator: IIterator;
begin
Result := StringMap.Iterator;
end;
function TStringMapKeys.Remove(Value: string): Boolean;
begin
Result := StringMap.RemoveKey(Value);
end;
procedure TStringMapKeys.RemoveAll(C: IStringList);
var
I: IStringIterator;
begin
I := C.StringIterator;
while I.HasElement do
begin
Remove(I.Get);
I.Next;
end;
end;
procedure TStringMapKeys.RetainAll(C: IStringList);
begin
end;
function TStringMapKeys.StringIterator: IStringIterator;
begin
Result := TStringMapKeysIterator.Create(StringMap);
end;
{ TStringMapKeysIterator }
constructor TStringMapKeysIterator.Create(StringMap: TStringMap);
begin
FIter := StringMap.Iterator as IMapIterator;
end;
function TStringMapKeysIterator.Get: string;
begin
Result := PString(FIter.GetKey)^;
end;
function TStringMapKeysIterator.HasElement: Boolean;
begin
Result := FIter.HasElement;
end;
procedure TStringMapKeysIterator.Next;
begin
FIter.Next;
end;
{ TObjectComparator }
function TObjectComparator.Compare(a, b: Pointer): Integer;
begin
Result := Integer(a) - Integer(b);
end;
procedure TObjectComparator.Finalize(a: Pointer);
begin
TObject(a).Free;
end;
function TObjectComparator.Initialize(a: Pointer): Pointer;
begin
Result := a;
end;
{ TCollections }
class function TCollections.CreateList: IList;
begin
Result := TDeque.Create;
end;
class function TCollections.CreateMap: IMap;
begin
Result := TTreeMap.Create;
end;
class function TCollections.CreateStringMap: IStringMap;
begin
Result := TStringMap.Create;
end;
procedure Test1;
var
Map: IStringMap;
I: IStringIterator;
begin
Map := TCollections.CreateStringMap;
Map.Comparator := TStringComparator.Create;
Map.Put('1pragman', NewStr('value'));
Map.Put('2pragman', NewStr('value'));
Map.Put('3pragman', NewStr('value'));
Map.Put('4pragman', NewStr('value'));
Map.Put('5pragman', NewStr('value'));
Map.Put('6pragman', NewStr('value'));
Map.RemoveKey('1pragman');
Map.RemoveKey('3pragman');
Map.RemoveKey('4pragman');
I := Map.Keys.StringIterator;
while I.HasElement do
begin
WriteLn(I.Get);
I.Next;
end;
end;
initialization
Test1;
end.
--
Chaos is the best description of the constant state of human society.
Therefore, dynamic balance is required for us to to survive when vital fault
occurrs. So in the society, we don't chase for peace and order, but existence
and survival, instead.
--
※ 發信站: 批踢踢實業坊(ptt.twbbs.org)
◆ From: 140.112.3.12