Componentes.Terceros.jcl/official/1.100/source/common/JclHashSets.pas

633 lines
17 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: 2006-07-24 07:34:39 +0200 (lun., 24 juil. 2006) $
unit JclHashSets;
{$I jcl.inc}
interface
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
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;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jcl.svn.sourceforge.net:443/svnroot/jcl/tags/JCL-1.100-Build2646/jcl/source/common/JclHashSets.pas $';
Revision: '$Revision: 1694 $';
Date: '$Date: 2006-07-24 07:34:39 +0200 (lun., 24 juil. 2006) $';
LogPath: 'JCL\source\common'
);
{$ENDIF UNITVERSIONING}
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;
{$IFDEF UNITVERSIONING}
RegisterUnitVersion(HInstance, UnitVersioning);
{$ENDIF UNITVERSIONING}
{$ELSE}
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
{$ENDIF UNITVERSIONING}
{$ENDIF FPC}
{$IFDEF UNITVERSIONING}
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.