646 lines
18 KiB
ObjectPascal
646 lines
18 KiB
ObjectPascal
{**************************************************************************************************}
|
|
{ }
|
|
{ Project JEDI Code Library (JCL) }
|
|
{ }
|
|
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
|
|
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
|
|
{ License at http://www.mozilla.org/MPL/ }
|
|
{ }
|
|
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
|
|
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
|
|
{ and limitations under the License. }
|
|
{ }
|
|
{ The Original Code is HashSet.pas. }
|
|
{ }
|
|
{ The Initial Developer of the Original Code is Jean-Philippe BEMPEL aka RDM. Portions created by }
|
|
{ Jean-Philippe BEMPEL are Copyright (C) Jean-Philippe BEMPEL (rdm_30 att yahoo dott com) }
|
|
{ All rights reserved. }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ The Delphi Container Library }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
|
|
// Last modified: $Date: 2005/05/05 20:08:43 $
|
|
// For history see end of file
|
|
|
|
unit JclHashSets;
|
|
|
|
{$I jcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes,
|
|
JclBase, JclAbstractContainers, JclContainerIntf, JclHashMaps;
|
|
|
|
type
|
|
TJclIntfHashSet = class(TJclAbstractContainer, IJclIntfCollection,
|
|
IJclIntfSet, IJclIntfCloneable)
|
|
private
|
|
FMap: IJclIntfIntfMap;
|
|
protected
|
|
{ IJclIntfCollection }
|
|
function Add(AInterface: IInterface): Boolean;
|
|
function AddAll(ACollection: IJclIntfCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(AInterface: IInterface): Boolean;
|
|
function ContainsAll(ACollection: IJclIntfCollection): Boolean;
|
|
function Equals(ACollection: IJclIntfCollection): Boolean;
|
|
function First: IJclIntfIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIntfIterator;
|
|
function Remove(AInterface: IInterface): Boolean;
|
|
function RemoveAll(ACollection: IJclIntfCollection): Boolean;
|
|
function RetainAll(ACollection: IJclIntfCollection): Boolean;
|
|
function Size: Integer;
|
|
{ IJclIntfSet }
|
|
procedure Intersect(ACollection: IJclIntfCollection);
|
|
procedure Subtract(ACollection: IJclIntfCollection);
|
|
procedure Union(ACollection: IJclIntfCollection);
|
|
{ IJclIntfCloneable }
|
|
function Clone: IInterface;
|
|
public
|
|
constructor Create(ACapacity: Integer = DefaultContainerCapacity);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
//Daniele Teti 02/03/2005
|
|
TJclStrHashSet = class(TJclStrCollection, IJclStrSet, IJclCloneable)
|
|
private
|
|
FMap: IJclStrMap;
|
|
protected
|
|
{ IJclStrCollection }
|
|
function Add(const AString: string): Boolean; override;
|
|
function AddAll(ACollection: IJclStrCollection): Boolean; override;
|
|
procedure Clear; override;
|
|
function Contains(const AString: string): Boolean; override;
|
|
function ContainsAll(ACollection: IJclStrCollection): Boolean; override;
|
|
function Equals(ACollection: IJclStrCollection): Boolean; override;
|
|
function First: IJclStrIterator; override;
|
|
function IsEmpty: Boolean; override;
|
|
function Last: IJclStrIterator; override;
|
|
function Remove(const AString: string): Boolean; override;
|
|
function RemoveAll(ACollection: IJclStrCollection): Boolean; override;
|
|
function RetainAll(ACollection: IJclStrCollection): Boolean; override;
|
|
function Size: Integer; override;
|
|
{ IJclIntfSet }
|
|
procedure Intersect(ACollection: IJclStrCollection);
|
|
procedure Subtract(ACollection: IJclStrCollection);
|
|
procedure Union(ACollection: IJclStrCollection);
|
|
{ IJclIntfCloneable }
|
|
function Clone: TObject;
|
|
public
|
|
constructor Create(ACapacity: Integer = DefaultContainerCapacity);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
TJclHashSet = class(TJclAbstractContainer, IJclCollection, IJclSet, IJclCloneable)
|
|
private
|
|
FMap: IJclMap;
|
|
protected
|
|
{ IJclCollection }
|
|
function Add(AObject: TObject): Boolean;
|
|
function AddAll(ACollection: IJclCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(AObject: TObject): Boolean;
|
|
function ContainsAll(ACollection: IJclCollection): Boolean;
|
|
function Equals(ACollection: IJclCollection): Boolean;
|
|
function First: IJclIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIterator;
|
|
function Remove(AObject: TObject): Boolean;
|
|
function RemoveAll(ACollection: IJclCollection): Boolean;
|
|
function RetainAll(ACollection: IJclCollection): Boolean;
|
|
function Size: Integer;
|
|
{ IJclSet }
|
|
procedure Intersect(ACollection: IJclCollection);
|
|
procedure Subtract(ACollection: IJclCollection);
|
|
procedure Union(ACollection: IJclCollection);
|
|
{ IJclCloneable }
|
|
function Clone: TObject;
|
|
public
|
|
constructor Create(ACapacity: Integer = DefaultContainerCapacity;
|
|
AOwnsObject: Boolean = False);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{$IFDEF CLR}
|
|
var
|
|
GlobalRefUnique: TObject = nil;
|
|
|
|
function RefUnique: TObject;
|
|
begin
|
|
// We keep the reference till program end. A unique memory address is not
|
|
// possible under a garbage collector.
|
|
if GlobalRefUnique = nil then
|
|
GlobalRefUnique := TObject.Create;
|
|
Result := GlobalRefUnique;
|
|
end;
|
|
{$ELSE}
|
|
var
|
|
// Here we have TObject reference that points to the data segment. A memory
|
|
// manager cannot return this address.
|
|
RefUnique: TObject {$IFNDEF FPC} = @RefUnique {$ENDIF};
|
|
{$ENDIF CLR}
|
|
|
|
var
|
|
IRefUnique: IInterface = nil;
|
|
|
|
//=== { TJclIntfHashSet } ====================================================
|
|
|
|
constructor TJclIntfHashSet.Create(ACapacity: Integer = DefaultContainerCapacity);
|
|
begin
|
|
inherited Create;
|
|
FMap := TJclIntfIntfHashMap.Create(ACapacity);
|
|
if IRefUnique = nil then
|
|
IRefUnique := TInterfacedObject.Create;
|
|
end;
|
|
|
|
destructor TJclIntfHashSet.Destroy;
|
|
begin
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclIntfHashSet.Add(AInterface: IInterface): Boolean;
|
|
begin
|
|
Result := not FMap.ContainsKey(AInterface);
|
|
if Result then
|
|
FMap.PutValue(AInterface, IRefUnique);
|
|
end;
|
|
|
|
function TJclIntfHashSet.AddAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
Result := ACollection <> nil;
|
|
if Result then
|
|
begin
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfHashSet.Clear;
|
|
begin
|
|
FMap.Clear;
|
|
end;
|
|
|
|
function TJclIntfHashSet.Clone: IInterface;
|
|
var
|
|
NewSet: TJclIntfHashSet;
|
|
begin
|
|
NewSet := TJclIntfHashSet.Create;
|
|
NewSet.FMap := IJclIntfIntfMap(IJclIntfCloneable(FMap).Clone);
|
|
Result := NewSet;
|
|
end;
|
|
|
|
function TJclIntfHashSet.Contains(AInterface: IInterface): Boolean;
|
|
begin
|
|
Result := FMap.ContainsKey(AInterface);
|
|
end;
|
|
|
|
function TJclIntfHashSet.ContainsAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
end;
|
|
|
|
function TJclIntfHashSet.Equals(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
ItMap: IJclIntfIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FMap.Size <> ACollection.Size then
|
|
Exit;
|
|
It := ACollection.First;
|
|
ItMap := FMap.Values.First;
|
|
while ItMap.HasNext do
|
|
if ItMap.Next <> It.Next then
|
|
Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclIntfHashSet.First: IJclIntfIterator;
|
|
begin
|
|
Result := FMap.KeySet.First;
|
|
end;
|
|
|
|
procedure TJclIntfHashSet.Intersect(ACollection: IJclIntfCollection);
|
|
begin
|
|
RetainAll(ACollection);
|
|
end;
|
|
|
|
function TJclIntfHashSet.IsEmpty: Boolean;
|
|
begin
|
|
Result := FMap.IsEmpty;
|
|
end;
|
|
|
|
function TJclIntfHashSet.Last: IJclIntfIterator;
|
|
begin
|
|
Result := FMap.KeySet.Last;
|
|
end;
|
|
|
|
function TJclIntfHashSet.Remove(AInterface: IInterface): Boolean;
|
|
begin
|
|
Result := FMap.Remove(AInterface) = IInterface(IRefUnique);
|
|
end;
|
|
|
|
function TJclIntfHashSet.RemoveAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
end;
|
|
|
|
function TJclIntfHashSet.RetainAll(ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
ItMap: IJclIntfIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
ItMap := FMap.Values.First;
|
|
while ItMap.HasNext do
|
|
if not ACollection.Contains(ItMap.Next) then
|
|
ItMap.Remove;
|
|
end;
|
|
|
|
function TJclIntfHashSet.Size: Integer;
|
|
begin
|
|
Result := FMap.Size;
|
|
end;
|
|
|
|
procedure TJclIntfHashSet.Subtract(ACollection: IJclIntfCollection);
|
|
begin
|
|
RemoveAll(ACollection);
|
|
end;
|
|
|
|
procedure TJclIntfHashSet.Union(ACollection: IJclIntfCollection);
|
|
begin
|
|
AddAll(ACollection);
|
|
end;
|
|
|
|
//=== { TJclStrHashSet } =====================================================
|
|
|
|
constructor TJclStrHashSet.Create(ACapacity: Integer = DefaultContainerCapacity);
|
|
begin
|
|
inherited Create;
|
|
FMap := TJclStrHashMap.Create(ACapacity, False);
|
|
end;
|
|
|
|
destructor TJclStrHashSet.Destroy;
|
|
begin
|
|
Clear;
|
|
// (rom) no Free of FMap?
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclStrHashSet.Add(const AString: string): Boolean;
|
|
begin
|
|
Result := not FMap.ContainsKey(AString);
|
|
if Result then
|
|
FMap.PutValue(AString, RefUnique);
|
|
end;
|
|
|
|
function TJclStrHashSet.AddAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) or Result;
|
|
end;
|
|
|
|
procedure TJclStrHashSet.Clear;
|
|
begin
|
|
FMap.Clear;
|
|
end;
|
|
|
|
function TJclStrHashSet.Clone: TObject;
|
|
var
|
|
NewSet: TJclStrHashSet;
|
|
begin
|
|
NewSet := TJclStrHashSet.Create;
|
|
NewSet.FMap := TJclStrHashMap(IJclCloneable(FMap).Clone);
|
|
Result := NewSet;
|
|
end;
|
|
|
|
function TJclStrHashSet.Contains(const AString: string): Boolean;
|
|
begin
|
|
Result := FMap.ContainsKey(AString);
|
|
end;
|
|
|
|
function TJclStrHashSet.ContainsAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
begin
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
end;
|
|
|
|
function TJclStrHashSet.Equals(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
ItMap: IJclStrIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FMap.Size <> ACollection.Size then
|
|
Exit;
|
|
It := ACollection.First;
|
|
ItMap := FMap.KeySet.First;
|
|
while ItMap.HasNext do
|
|
if ItMap.Next <> It.Next then
|
|
Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclStrHashSet.First: IJclStrIterator;
|
|
begin
|
|
Result := FMap.KeySet.First;
|
|
end;
|
|
|
|
procedure TJclStrHashSet.Intersect(ACollection: IJclStrCollection);
|
|
begin
|
|
RetainAll(ACollection);
|
|
end;
|
|
|
|
function TJclStrHashSet.IsEmpty: Boolean;
|
|
begin
|
|
Result := FMap.IsEmpty;
|
|
end;
|
|
|
|
function TJclStrHashSet.Last: IJclStrIterator;
|
|
begin
|
|
Result := FMap.KeySet.Last;
|
|
end;
|
|
|
|
function TJclStrHashSet.Remove(const AString: string): Boolean;
|
|
begin
|
|
Result := FMap.Remove(AString) = RefUnique;
|
|
end;
|
|
|
|
function TJclStrHashSet.RemoveAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
begin
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
end;
|
|
|
|
function TJclStrHashSet.RetainAll(ACollection: IJclStrCollection): Boolean;
|
|
var
|
|
It: IJclStrIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
if not FMap.ContainsKey(It.Next) then
|
|
FMap.Remove(It.Next);
|
|
end;
|
|
|
|
function TJclStrHashSet.Size: Integer;
|
|
begin
|
|
Result := FMap.Size;
|
|
end;
|
|
|
|
procedure TJclStrHashSet.Subtract(ACollection: IJclStrCollection);
|
|
begin
|
|
RemoveAll(ACollection);
|
|
end;
|
|
|
|
procedure TJclStrHashSet.Union(ACollection: IJclStrCollection);
|
|
begin
|
|
AddAll(ACollection);
|
|
end;
|
|
|
|
//=== { TJclHashSet } ========================================================
|
|
|
|
constructor TJclHashSet.Create(ACapacity: Integer = DefaultContainerCapacity;
|
|
AOwnsObject: Boolean = False);
|
|
begin
|
|
inherited Create;
|
|
FMap := TJclHashMap.Create(ACapacity, AOwnsObject);
|
|
end;
|
|
|
|
destructor TJclHashSet.Destroy;
|
|
begin
|
|
Clear;
|
|
// (rom) no Free of FMap?
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclHashSet.Add(AObject: TObject): Boolean;
|
|
begin
|
|
Result := not FMap.ContainsKey(AObject);
|
|
if Result then
|
|
FMap.PutValue(AObject, RefUnique);
|
|
end;
|
|
|
|
function TJclHashSet.AddAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) or Result;
|
|
end;
|
|
|
|
procedure TJclHashSet.Clear;
|
|
begin
|
|
FMap.Clear;
|
|
end;
|
|
|
|
function TJclHashSet.Clone: TObject;
|
|
var
|
|
NewSet: TJclHashSet;
|
|
begin
|
|
NewSet := TJclHashSet.Create;
|
|
NewSet.FMap := TJclHashMap(IJclCloneable(FMap).Clone);
|
|
Result := NewSet;
|
|
end;
|
|
|
|
function TJclHashSet.Contains(AObject: TObject): Boolean;
|
|
begin
|
|
Result := FMap.ContainsKey(AObject);
|
|
end;
|
|
|
|
function TJclHashSet.ContainsAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
end;
|
|
|
|
function TJclHashSet.Equals(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
ItMap: IJclIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FMap.Size <> ACollection.Size then
|
|
Exit;
|
|
It := ACollection.First;
|
|
ItMap := FMap.Values.First;
|
|
while ItMap.HasNext do
|
|
if ItMap.Next <> It.Next then
|
|
Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function TJclHashSet.First: IJclIterator;
|
|
begin
|
|
Result := FMap.KeySet.First;
|
|
end;
|
|
|
|
procedure TJclHashSet.Intersect(ACollection: IJclCollection);
|
|
begin
|
|
RetainAll(ACollection);
|
|
end;
|
|
|
|
function TJclHashSet.IsEmpty: Boolean;
|
|
begin
|
|
Result := FMap.IsEmpty;
|
|
end;
|
|
|
|
function TJclHashSet.Last: IJclIterator;
|
|
begin
|
|
Result := FMap.KeySet.Last;
|
|
end;
|
|
|
|
function TJclHashSet.Remove(AObject: TObject): Boolean;
|
|
begin
|
|
Result := FMap.Remove(AObject) = RefUnique;
|
|
end;
|
|
|
|
function TJclHashSet.RemoveAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
end;
|
|
|
|
function TJclHashSet.RetainAll(ACollection: IJclCollection): Boolean;
|
|
var
|
|
ItMap: IJclIterator;
|
|
begin
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
ItMap := FMap.Values.First;
|
|
while ItMap.HasNext do
|
|
if not ACollection.Contains(ItMap.Next) then
|
|
ItMap.Remove;
|
|
end;
|
|
|
|
function TJclHashSet.Size: Integer;
|
|
begin
|
|
Result := FMap.Size;
|
|
end;
|
|
|
|
procedure TJclHashSet.Subtract(ACollection: IJclCollection);
|
|
begin
|
|
RemoveAll(ACollection);
|
|
end;
|
|
|
|
procedure TJclHashSet.Union(ACollection: IJclCollection);
|
|
begin
|
|
AddAll(ACollection);
|
|
end;
|
|
|
|
{$IFDEF FPC}
|
|
initialization
|
|
RefUnique := @RefUnique;
|
|
{$ENDIF FPC}
|
|
|
|
// History:
|
|
|
|
// $Log: JclHashSets.pas,v $
|
|
// Revision 1.9 2005/05/05 20:08:43 ahuser
|
|
// JCL.NET support
|
|
//
|
|
// Revision 1.8 2005/04/17 23:00:10 rrossmair
|
|
// - changed to compile with FPC
|
|
//
|
|
// Revision 1.7 2005/03/03 08:02:57 marquardt
|
|
// various style cleanings, bugfixes and improvements
|
|
//
|
|
// Revision 1.6 2005/03/02 17:51:24 rrossmair
|
|
// - removed DCLAppendDelimited from JclAlgorithms, changed uses clauses accordingly
|
|
//
|
|
// Revision 1.5 2005/03/02 09:59:30 dade2004
|
|
// Added
|
|
// -TJclStrCollection in JclContainerIntf
|
|
// Every common methods for IJclStrCollection are implemented here
|
|
//
|
|
// -Every class that implement IJclStrCollection now derive from TJclStrCollection instead of TJclAbstractContainer
|
|
// -Every abstract method in TJclStrCollection has been marked as "override" in descendent classes
|
|
//
|
|
// DCLAppendDelimited has been removed from JclAlgorothms, his body has been fixed for a bug and put into
|
|
// relative method in TJclStrCollection
|
|
//
|
|
// Revision 1.4 2005/02/27 11:36:20 marquardt
|
|
// fixed and secured Capacity/Grow mechanism, raise exceptions with efficient CreateResRec
|
|
//
|
|
// Revision 1.3 2005/02/27 07:27:47 marquardt
|
|
// changed interface names from I to IJcl, moved resourcestrings to JclResource.pas
|
|
//
|
|
// Revision 1.2 2005/02/24 07:36:24 marquardt
|
|
// resolved the compiler warnings, style cleanup, removed code from JclContainerIntf.pas
|
|
//
|
|
// Revision 1.1 2005/02/24 03:57:10 rrossmair
|
|
// - donated DCL code, initial check-in
|
|
//
|
|
|
|
end.
|
|
|