git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.jcl@20 c37d764d-f447-7644-a108-883140d013fb
21282 lines
568 KiB
ObjectPascal
21282 lines
568 KiB
ObjectPascal
{**************************************************************************************************}
|
|
{ WARNING: JEDI preprocessor generated unit. Do not edit. }
|
|
{**************************************************************************************************}
|
|
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ 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 BinaryTree.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. }
|
|
{ }
|
|
{ Contributors: }
|
|
{ Florent Ouchet (outchy) }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ The Delphi Container Library }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
{ }
|
|
{ Last modified: $Date:: 2009-09-12 14:21:23 +0200 (sam., 12 sept. 2009) $ }
|
|
{ Revision: $Rev:: 2997 $ }
|
|
{ Author: $Author:: outchy $ }
|
|
{ }
|
|
{**************************************************************************************************}
|
|
|
|
unit JclBinaryTrees;
|
|
|
|
{$I jcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
Classes,
|
|
{$IFDEF SUPPORTS_GENERICS}
|
|
{$ENDIF SUPPORTS_GENERICS}
|
|
JclBase, JclAbstractContainers, JclAlgorithms, JclContainerIntf, JclSynch;
|
|
|
|
type
|
|
TItrStart = (isFirst, isLast, isRoot);
|
|
|
|
TJclIntfBinaryNode = class
|
|
public
|
|
Value: IInterface;
|
|
Left: TJclIntfBinaryNode;
|
|
Right: TJclIntfBinaryNode;
|
|
Parent: TJclIntfBinaryNode;
|
|
end;
|
|
|
|
TJclIntfBinaryTree = class(TJclIntfAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclIntfEqualityComparer, IJclIntfComparer,
|
|
IJclIntfCollection, IJclIntfTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclIntfBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclIntfBinaryNode; Left, Right: Integer; Parent: TJclIntfBinaryNode;
|
|
Offset: Integer): TJclIntfBinaryNode;
|
|
function CloneNode(Node, Parent: TJclIntfBinaryNode): TJclIntfBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TIntfCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntfCollection }
|
|
function Add(const AInterface: IInterface): Boolean;
|
|
function AddAll(const ACollection: IJclIntfCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(const AInterface: IInterface): Boolean;
|
|
function ContainsAll(const ACollection: IJclIntfCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclIntfCollection): Boolean;
|
|
function Extract(const AInterface: IInterface): Boolean;
|
|
function ExtractAll(const ACollection: IJclIntfCollection): Boolean;
|
|
function First: IJclIntfIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIntfIterator;
|
|
function Remove(const AInterface: IInterface): Boolean;
|
|
function RemoveAll(const ACollection: IJclIntfCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclIntfCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclIntfIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclIntfTree }
|
|
function GetRoot: IJclIntfTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclIntfTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclIntfBinaryTreeIterator = class(TJclAbstractIterator, IJclIntfIterator, IJclIntfTreeIterator, IJclIntfBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclIntfBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclIntfCollection;
|
|
FEqualityComparer: IJclIntfEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclIntfBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclIntfBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclIntfCollection; ACursor: TJclIntfBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclIntfIterator }
|
|
function Add(const AInterface: IInterface): Boolean;
|
|
procedure Extract;
|
|
function GetObject: IInterface;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AInterface: IInterface): Boolean;
|
|
function IteratorEquals(const AIterator: IJclIntfIterator): Boolean;
|
|
function Next: IInterface;
|
|
function NextIndex: Integer;
|
|
function Previous: IInterface;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetObject(const AInterface: IInterface);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: IInterface read GetObject;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclIntfTreeIterator }
|
|
function AddChild(const AInterface: IInterface): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): IInterface;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AInterface: IInterface): Integer;
|
|
function InsertChild(Index: Integer; const AInterface: IInterface): Boolean;
|
|
function Parent: IInterface;
|
|
procedure SetChild(Index: Integer; const AInterface: IInterface);
|
|
{ IJclIntfBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: IInterface;
|
|
function Right: IInterface;
|
|
end;
|
|
|
|
TJclPreOrderIntfBinaryTreeIterator = class(TJclIntfBinaryTreeIterator, IJclIntfIterator, IJclIntfTreeIterator, IJclIntfBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclIntfBinaryNode; override;
|
|
function GetPreviousCursor: TJclIntfBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderIntfBinaryTreeIterator = class(TJclIntfBinaryTreeIterator, IJclIntfIterator, IJclIntfTreeIterator, IJclIntfBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclIntfBinaryNode; override;
|
|
function GetPreviousCursor: TJclIntfBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderIntfBinaryTreeIterator = class(TJclIntfBinaryTreeIterator, IJclIntfIterator, IJclIntfTreeIterator, IJclIntfBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclIntfBinaryNode; override;
|
|
function GetPreviousCursor: TJclIntfBinaryNode; override;
|
|
end;
|
|
|
|
TJclAnsiStrBinaryNode = class
|
|
public
|
|
Value: AnsiString;
|
|
Left: TJclAnsiStrBinaryNode;
|
|
Right: TJclAnsiStrBinaryNode;
|
|
Parent: TJclAnsiStrBinaryNode;
|
|
end;
|
|
|
|
TJclAnsiStrBinaryTree = class(TJclAnsiStrAbstractCollection, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclStrContainer, IJclAnsiStrContainer, IJclAnsiStrFlatContainer, IJclAnsiStrEqualityComparer, IJclAnsiStrComparer,
|
|
IJclAnsiStrCollection, IJclAnsiStrTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclAnsiStrBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclAnsiStrBinaryNode; Left, Right: Integer; Parent: TJclAnsiStrBinaryNode;
|
|
Offset: Integer): TJclAnsiStrBinaryNode;
|
|
function CloneNode(Node, Parent: TJclAnsiStrBinaryNode): TJclAnsiStrBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TAnsiStrCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclAnsiStrCollection }
|
|
function Add(const AString: AnsiString): Boolean; override;
|
|
function AddAll(const ACollection: IJclAnsiStrCollection): Boolean; override;
|
|
procedure Clear; override;
|
|
function Contains(const AString: AnsiString): Boolean; override;
|
|
function ContainsAll(const ACollection: IJclAnsiStrCollection): Boolean; override;
|
|
function CollectionEquals(const ACollection: IJclAnsiStrCollection): Boolean; override;
|
|
function Extract(const AString: AnsiString): Boolean; override;
|
|
function ExtractAll(const ACollection: IJclAnsiStrCollection): Boolean; override;
|
|
function First: IJclAnsiStrIterator; override;
|
|
function IsEmpty: Boolean; override;
|
|
function Last: IJclAnsiStrIterator; override;
|
|
function Remove(const AString: AnsiString): Boolean; override;
|
|
function RemoveAll(const ACollection: IJclAnsiStrCollection): Boolean; override;
|
|
function RetainAll(const ACollection: IJclAnsiStrCollection): Boolean; override;
|
|
function Size: Integer; override;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclAnsiStrIterator; override;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclAnsiStrTree }
|
|
function GetRoot: IJclAnsiStrTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclAnsiStrTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclAnsiStrBinaryTreeIterator = class(TJclAbstractIterator, IJclAnsiStrIterator, IJclAnsiStrTreeIterator, IJclAnsiStrBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclAnsiStrBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclAnsiStrCollection;
|
|
FEqualityComparer: IJclAnsiStrEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclAnsiStrBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclAnsiStrBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclAnsiStrCollection; ACursor: TJclAnsiStrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclAnsiStrIterator }
|
|
function Add(const AString: AnsiString): Boolean;
|
|
procedure Extract;
|
|
function GetString: AnsiString;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AString: AnsiString): Boolean;
|
|
function IteratorEquals(const AIterator: IJclAnsiStrIterator): Boolean;
|
|
function Next: AnsiString;
|
|
function NextIndex: Integer;
|
|
function Previous: AnsiString;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetString(const AString: AnsiString);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: AnsiString read GetString;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclAnsiStrTreeIterator }
|
|
function AddChild(const AString: AnsiString): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): AnsiString;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AString: AnsiString): Integer;
|
|
function InsertChild(Index: Integer; const AString: AnsiString): Boolean;
|
|
function Parent: AnsiString;
|
|
procedure SetChild(Index: Integer; const AString: AnsiString);
|
|
{ IJclAnsiStrBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: AnsiString;
|
|
function Right: AnsiString;
|
|
end;
|
|
|
|
TJclPreOrderAnsiStrBinaryTreeIterator = class(TJclAnsiStrBinaryTreeIterator, IJclAnsiStrIterator, IJclAnsiStrTreeIterator, IJclAnsiStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclAnsiStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclAnsiStrBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderAnsiStrBinaryTreeIterator = class(TJclAnsiStrBinaryTreeIterator, IJclAnsiStrIterator, IJclAnsiStrTreeIterator, IJclAnsiStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclAnsiStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclAnsiStrBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderAnsiStrBinaryTreeIterator = class(TJclAnsiStrBinaryTreeIterator, IJclAnsiStrIterator, IJclAnsiStrTreeIterator, IJclAnsiStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclAnsiStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclAnsiStrBinaryNode; override;
|
|
end;
|
|
|
|
TJclWideStrBinaryNode = class
|
|
public
|
|
Value: WideString;
|
|
Left: TJclWideStrBinaryNode;
|
|
Right: TJclWideStrBinaryNode;
|
|
Parent: TJclWideStrBinaryNode;
|
|
end;
|
|
|
|
TJclWideStrBinaryTree = class(TJclWideStrAbstractCollection, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclStrContainer, IJclWideStrContainer, IJclWideStrFlatContainer, IJclWideStrEqualityComparer, IJclWideStrComparer,
|
|
IJclWideStrCollection, IJclWideStrTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclWideStrBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclWideStrBinaryNode; Left, Right: Integer; Parent: TJclWideStrBinaryNode;
|
|
Offset: Integer): TJclWideStrBinaryNode;
|
|
function CloneNode(Node, Parent: TJclWideStrBinaryNode): TJclWideStrBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TWideStrCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclWideStrCollection }
|
|
function Add(const AString: WideString): Boolean; override;
|
|
function AddAll(const ACollection: IJclWideStrCollection): Boolean; override;
|
|
procedure Clear; override;
|
|
function Contains(const AString: WideString): Boolean; override;
|
|
function ContainsAll(const ACollection: IJclWideStrCollection): Boolean; override;
|
|
function CollectionEquals(const ACollection: IJclWideStrCollection): Boolean; override;
|
|
function Extract(const AString: WideString): Boolean; override;
|
|
function ExtractAll(const ACollection: IJclWideStrCollection): Boolean; override;
|
|
function First: IJclWideStrIterator; override;
|
|
function IsEmpty: Boolean; override;
|
|
function Last: IJclWideStrIterator; override;
|
|
function Remove(const AString: WideString): Boolean; override;
|
|
function RemoveAll(const ACollection: IJclWideStrCollection): Boolean; override;
|
|
function RetainAll(const ACollection: IJclWideStrCollection): Boolean; override;
|
|
function Size: Integer; override;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclWideStrIterator; override;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclWideStrTree }
|
|
function GetRoot: IJclWideStrTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclWideStrTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclWideStrBinaryTreeIterator = class(TJclAbstractIterator, IJclWideStrIterator, IJclWideStrTreeIterator, IJclWideStrBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclWideStrBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclWideStrCollection;
|
|
FEqualityComparer: IJclWideStrEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclWideStrBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclWideStrBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclWideStrCollection; ACursor: TJclWideStrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclWideStrIterator }
|
|
function Add(const AString: WideString): Boolean;
|
|
procedure Extract;
|
|
function GetString: WideString;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AString: WideString): Boolean;
|
|
function IteratorEquals(const AIterator: IJclWideStrIterator): Boolean;
|
|
function Next: WideString;
|
|
function NextIndex: Integer;
|
|
function Previous: WideString;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetString(const AString: WideString);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: WideString read GetString;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclWideStrTreeIterator }
|
|
function AddChild(const AString: WideString): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): WideString;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AString: WideString): Integer;
|
|
function InsertChild(Index: Integer; const AString: WideString): Boolean;
|
|
function Parent: WideString;
|
|
procedure SetChild(Index: Integer; const AString: WideString);
|
|
{ IJclWideStrBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: WideString;
|
|
function Right: WideString;
|
|
end;
|
|
|
|
TJclPreOrderWideStrBinaryTreeIterator = class(TJclWideStrBinaryTreeIterator, IJclWideStrIterator, IJclWideStrTreeIterator, IJclWideStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclWideStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclWideStrBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderWideStrBinaryTreeIterator = class(TJclWideStrBinaryTreeIterator, IJclWideStrIterator, IJclWideStrTreeIterator, IJclWideStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclWideStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclWideStrBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderWideStrBinaryTreeIterator = class(TJclWideStrBinaryTreeIterator, IJclWideStrIterator, IJclWideStrTreeIterator, IJclWideStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclWideStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclWideStrBinaryNode; override;
|
|
end;
|
|
|
|
|
|
{$IFDEF SUPPORTS_UNICODE_STRING}
|
|
TJclUnicodeStrBinaryNode = class
|
|
public
|
|
Value: UnicodeString;
|
|
Left: TJclUnicodeStrBinaryNode;
|
|
Right: TJclUnicodeStrBinaryNode;
|
|
Parent: TJclUnicodeStrBinaryNode;
|
|
end;
|
|
|
|
TJclUnicodeStrBinaryTree = class(TJclUnicodeStrAbstractCollection, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclStrContainer, IJclUnicodeStrContainer, IJclUnicodeStrFlatContainer, IJclUnicodeStrEqualityComparer, IJclUnicodeStrComparer,
|
|
IJclUnicodeStrCollection, IJclUnicodeStrTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclUnicodeStrBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclUnicodeStrBinaryNode; Left, Right: Integer; Parent: TJclUnicodeStrBinaryNode;
|
|
Offset: Integer): TJclUnicodeStrBinaryNode;
|
|
function CloneNode(Node, Parent: TJclUnicodeStrBinaryNode): TJclUnicodeStrBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TUnicodeStrCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclUnicodeStrCollection }
|
|
function Add(const AString: UnicodeString): Boolean; override;
|
|
function AddAll(const ACollection: IJclUnicodeStrCollection): Boolean; override;
|
|
procedure Clear; override;
|
|
function Contains(const AString: UnicodeString): Boolean; override;
|
|
function ContainsAll(const ACollection: IJclUnicodeStrCollection): Boolean; override;
|
|
function CollectionEquals(const ACollection: IJclUnicodeStrCollection): Boolean; override;
|
|
function Extract(const AString: UnicodeString): Boolean; override;
|
|
function ExtractAll(const ACollection: IJclUnicodeStrCollection): Boolean; override;
|
|
function First: IJclUnicodeStrIterator; override;
|
|
function IsEmpty: Boolean; override;
|
|
function Last: IJclUnicodeStrIterator; override;
|
|
function Remove(const AString: UnicodeString): Boolean; override;
|
|
function RemoveAll(const ACollection: IJclUnicodeStrCollection): Boolean; override;
|
|
function RetainAll(const ACollection: IJclUnicodeStrCollection): Boolean; override;
|
|
function Size: Integer; override;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclUnicodeStrIterator; override;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclUnicodeStrTree }
|
|
function GetRoot: IJclUnicodeStrTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclUnicodeStrTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclUnicodeStrBinaryTreeIterator = class(TJclAbstractIterator, IJclUnicodeStrIterator, IJclUnicodeStrTreeIterator, IJclUnicodeStrBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclUnicodeStrBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclUnicodeStrCollection;
|
|
FEqualityComparer: IJclUnicodeStrEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclUnicodeStrBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclUnicodeStrBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclUnicodeStrCollection; ACursor: TJclUnicodeStrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclUnicodeStrIterator }
|
|
function Add(const AString: UnicodeString): Boolean;
|
|
procedure Extract;
|
|
function GetString: UnicodeString;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AString: UnicodeString): Boolean;
|
|
function IteratorEquals(const AIterator: IJclUnicodeStrIterator): Boolean;
|
|
function Next: UnicodeString;
|
|
function NextIndex: Integer;
|
|
function Previous: UnicodeString;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetString(const AString: UnicodeString);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: UnicodeString read GetString;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclUnicodeStrTreeIterator }
|
|
function AddChild(const AString: UnicodeString): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): UnicodeString;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AString: UnicodeString): Integer;
|
|
function InsertChild(Index: Integer; const AString: UnicodeString): Boolean;
|
|
function Parent: UnicodeString;
|
|
procedure SetChild(Index: Integer; const AString: UnicodeString);
|
|
{ IJclUnicodeStrBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: UnicodeString;
|
|
function Right: UnicodeString;
|
|
end;
|
|
|
|
TJclPreOrderUnicodeStrBinaryTreeIterator = class(TJclUnicodeStrBinaryTreeIterator, IJclUnicodeStrIterator, IJclUnicodeStrTreeIterator, IJclUnicodeStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclUnicodeStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclUnicodeStrBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderUnicodeStrBinaryTreeIterator = class(TJclUnicodeStrBinaryTreeIterator, IJclUnicodeStrIterator, IJclUnicodeStrTreeIterator, IJclUnicodeStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclUnicodeStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclUnicodeStrBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderUnicodeStrBinaryTreeIterator = class(TJclUnicodeStrBinaryTreeIterator, IJclUnicodeStrIterator, IJclUnicodeStrTreeIterator, IJclUnicodeStrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclUnicodeStrBinaryNode; override;
|
|
function GetPreviousCursor: TJclUnicodeStrBinaryNode; override;
|
|
end;
|
|
{$ENDIF SUPPORTS_UNICODE_STRING}
|
|
|
|
{$IFDEF CONTAINER_ANSISTR}
|
|
TJclStrBinaryTree = TJclAnsiStrBinaryTree;
|
|
{$ENDIF CONTAINER_ANSISTR}
|
|
{$IFDEF CONTAINER_WIDESTR}
|
|
TJclStrBinaryTree = TJclWideStrBinaryTree;
|
|
{$ENDIF CONTAINER_WIDESTR}
|
|
{$IFDEF CONTAINER_UNICODESTR}
|
|
TJclStrBinaryTree = TJclUnicodeStrBinaryTree;
|
|
{$ENDIF CONTAINER_UNICODESTR}
|
|
|
|
TJclSingleBinaryNode = class
|
|
public
|
|
Value: Single;
|
|
Left: TJclSingleBinaryNode;
|
|
Right: TJclSingleBinaryNode;
|
|
Parent: TJclSingleBinaryNode;
|
|
end;
|
|
|
|
TJclSingleBinaryTree = class(TJclSingleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclSingleContainer, IJclSingleEqualityComparer, IJclSingleComparer,
|
|
IJclSingleCollection, IJclSingleTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclSingleBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclSingleBinaryNode; Left, Right: Integer; Parent: TJclSingleBinaryNode;
|
|
Offset: Integer): TJclSingleBinaryNode;
|
|
function CloneNode(Node, Parent: TJclSingleBinaryNode): TJclSingleBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TSingleCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclSingleCollection }
|
|
function Add(const AValue: Single): Boolean;
|
|
function AddAll(const ACollection: IJclSingleCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(const AValue: Single): Boolean;
|
|
function ContainsAll(const ACollection: IJclSingleCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclSingleCollection): Boolean;
|
|
function Extract(const AValue: Single): Boolean;
|
|
function ExtractAll(const ACollection: IJclSingleCollection): Boolean;
|
|
function First: IJclSingleIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclSingleIterator;
|
|
function Remove(const AValue: Single): Boolean;
|
|
function RemoveAll(const ACollection: IJclSingleCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclSingleCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclSingleIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclSingleTree }
|
|
function GetRoot: IJclSingleTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclSingleTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclSingleBinaryTreeIterator = class(TJclAbstractIterator, IJclSingleIterator, IJclSingleTreeIterator, IJclSingleBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclSingleBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclSingleCollection;
|
|
FEqualityComparer: IJclSingleEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclSingleBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclSingleBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclSingleCollection; ACursor: TJclSingleBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclSingleIterator }
|
|
function Add(const AValue: Single): Boolean;
|
|
procedure Extract;
|
|
function GetValue: Single;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AValue: Single): Boolean;
|
|
function IteratorEquals(const AIterator: IJclSingleIterator): Boolean;
|
|
function Next: Single;
|
|
function NextIndex: Integer;
|
|
function Previous: Single;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetValue(const AValue: Single);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: Single read GetValue;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclSingleTreeIterator }
|
|
function AddChild(const AValue: Single): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): Single;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AValue: Single): Integer;
|
|
function InsertChild(Index: Integer; const AValue: Single): Boolean;
|
|
function Parent: Single;
|
|
procedure SetChild(Index: Integer; const AValue: Single);
|
|
{ IJclSingleBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: Single;
|
|
function Right: Single;
|
|
end;
|
|
|
|
TJclPreOrderSingleBinaryTreeIterator = class(TJclSingleBinaryTreeIterator, IJclSingleIterator, IJclSingleTreeIterator, IJclSingleBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclSingleBinaryNode; override;
|
|
function GetPreviousCursor: TJclSingleBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderSingleBinaryTreeIterator = class(TJclSingleBinaryTreeIterator, IJclSingleIterator, IJclSingleTreeIterator, IJclSingleBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclSingleBinaryNode; override;
|
|
function GetPreviousCursor: TJclSingleBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderSingleBinaryTreeIterator = class(TJclSingleBinaryTreeIterator, IJclSingleIterator, IJclSingleTreeIterator, IJclSingleBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclSingleBinaryNode; override;
|
|
function GetPreviousCursor: TJclSingleBinaryNode; override;
|
|
end;
|
|
|
|
TJclDoubleBinaryNode = class
|
|
public
|
|
Value: Double;
|
|
Left: TJclDoubleBinaryNode;
|
|
Right: TJclDoubleBinaryNode;
|
|
Parent: TJclDoubleBinaryNode;
|
|
end;
|
|
|
|
TJclDoubleBinaryTree = class(TJclDoubleAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclDoubleContainer, IJclDoubleEqualityComparer, IJclDoubleComparer,
|
|
IJclDoubleCollection, IJclDoubleTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclDoubleBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclDoubleBinaryNode; Left, Right: Integer; Parent: TJclDoubleBinaryNode;
|
|
Offset: Integer): TJclDoubleBinaryNode;
|
|
function CloneNode(Node, Parent: TJclDoubleBinaryNode): TJclDoubleBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TDoubleCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclDoubleCollection }
|
|
function Add(const AValue: Double): Boolean;
|
|
function AddAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(const AValue: Double): Boolean;
|
|
function ContainsAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclDoubleCollection): Boolean;
|
|
function Extract(const AValue: Double): Boolean;
|
|
function ExtractAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
function First: IJclDoubleIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclDoubleIterator;
|
|
function Remove(const AValue: Double): Boolean;
|
|
function RemoveAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclDoubleIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclDoubleTree }
|
|
function GetRoot: IJclDoubleTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclDoubleTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclDoubleBinaryTreeIterator = class(TJclAbstractIterator, IJclDoubleIterator, IJclDoubleTreeIterator, IJclDoubleBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclDoubleBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclDoubleCollection;
|
|
FEqualityComparer: IJclDoubleEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclDoubleBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclDoubleBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclDoubleCollection; ACursor: TJclDoubleBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclDoubleIterator }
|
|
function Add(const AValue: Double): Boolean;
|
|
procedure Extract;
|
|
function GetValue: Double;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AValue: Double): Boolean;
|
|
function IteratorEquals(const AIterator: IJclDoubleIterator): Boolean;
|
|
function Next: Double;
|
|
function NextIndex: Integer;
|
|
function Previous: Double;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetValue(const AValue: Double);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: Double read GetValue;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclDoubleTreeIterator }
|
|
function AddChild(const AValue: Double): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): Double;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AValue: Double): Integer;
|
|
function InsertChild(Index: Integer; const AValue: Double): Boolean;
|
|
function Parent: Double;
|
|
procedure SetChild(Index: Integer; const AValue: Double);
|
|
{ IJclDoubleBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: Double;
|
|
function Right: Double;
|
|
end;
|
|
|
|
TJclPreOrderDoubleBinaryTreeIterator = class(TJclDoubleBinaryTreeIterator, IJclDoubleIterator, IJclDoubleTreeIterator, IJclDoubleBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclDoubleBinaryNode; override;
|
|
function GetPreviousCursor: TJclDoubleBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderDoubleBinaryTreeIterator = class(TJclDoubleBinaryTreeIterator, IJclDoubleIterator, IJclDoubleTreeIterator, IJclDoubleBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclDoubleBinaryNode; override;
|
|
function GetPreviousCursor: TJclDoubleBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderDoubleBinaryTreeIterator = class(TJclDoubleBinaryTreeIterator, IJclDoubleIterator, IJclDoubleTreeIterator, IJclDoubleBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclDoubleBinaryNode; override;
|
|
function GetPreviousCursor: TJclDoubleBinaryNode; override;
|
|
end;
|
|
|
|
TJclExtendedBinaryNode = class
|
|
public
|
|
Value: Extended;
|
|
Left: TJclExtendedBinaryNode;
|
|
Right: TJclExtendedBinaryNode;
|
|
Parent: TJclExtendedBinaryNode;
|
|
end;
|
|
|
|
TJclExtendedBinaryTree = class(TJclExtendedAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclExtendedContainer, IJclExtendedEqualityComparer, IJclExtendedComparer,
|
|
IJclExtendedCollection, IJclExtendedTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclExtendedBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclExtendedBinaryNode; Left, Right: Integer; Parent: TJclExtendedBinaryNode;
|
|
Offset: Integer): TJclExtendedBinaryNode;
|
|
function CloneNode(Node, Parent: TJclExtendedBinaryNode): TJclExtendedBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TExtendedCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclExtendedCollection }
|
|
function Add(const AValue: Extended): Boolean;
|
|
function AddAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(const AValue: Extended): Boolean;
|
|
function ContainsAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclExtendedCollection): Boolean;
|
|
function Extract(const AValue: Extended): Boolean;
|
|
function ExtractAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
function First: IJclExtendedIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclExtendedIterator;
|
|
function Remove(const AValue: Extended): Boolean;
|
|
function RemoveAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclExtendedIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclExtendedTree }
|
|
function GetRoot: IJclExtendedTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclExtendedTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclExtendedBinaryTreeIterator = class(TJclAbstractIterator, IJclExtendedIterator, IJclExtendedTreeIterator, IJclExtendedBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclExtendedBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclExtendedCollection;
|
|
FEqualityComparer: IJclExtendedEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclExtendedBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclExtendedBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclExtendedCollection; ACursor: TJclExtendedBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclExtendedIterator }
|
|
function Add(const AValue: Extended): Boolean;
|
|
procedure Extract;
|
|
function GetValue: Extended;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AValue: Extended): Boolean;
|
|
function IteratorEquals(const AIterator: IJclExtendedIterator): Boolean;
|
|
function Next: Extended;
|
|
function NextIndex: Integer;
|
|
function Previous: Extended;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetValue(const AValue: Extended);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: Extended read GetValue;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclExtendedTreeIterator }
|
|
function AddChild(const AValue: Extended): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): Extended;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AValue: Extended): Integer;
|
|
function InsertChild(Index: Integer; const AValue: Extended): Boolean;
|
|
function Parent: Extended;
|
|
procedure SetChild(Index: Integer; const AValue: Extended);
|
|
{ IJclExtendedBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: Extended;
|
|
function Right: Extended;
|
|
end;
|
|
|
|
TJclPreOrderExtendedBinaryTreeIterator = class(TJclExtendedBinaryTreeIterator, IJclExtendedIterator, IJclExtendedTreeIterator, IJclExtendedBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclExtendedBinaryNode; override;
|
|
function GetPreviousCursor: TJclExtendedBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderExtendedBinaryTreeIterator = class(TJclExtendedBinaryTreeIterator, IJclExtendedIterator, IJclExtendedTreeIterator, IJclExtendedBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclExtendedBinaryNode; override;
|
|
function GetPreviousCursor: TJclExtendedBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderExtendedBinaryTreeIterator = class(TJclExtendedBinaryTreeIterator, IJclExtendedIterator, IJclExtendedTreeIterator, IJclExtendedBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclExtendedBinaryNode; override;
|
|
function GetPreviousCursor: TJclExtendedBinaryNode; override;
|
|
end;
|
|
|
|
{$IFDEF MATH_EXTENDED_PRECISION}
|
|
TJclFloatBinaryTree = TJclExtendedBinaryTree;
|
|
{$ENDIF MATH_EXTENDED_PRECISION}
|
|
{$IFDEF MATH_DOUBLE_PRECISION}
|
|
TJclFloatBinaryTree = TJclDoubleBinaryTree;
|
|
{$ENDIF MATH_DOUBLE_PRECISION}
|
|
{$IFDEF MATH_SINGLE_PRECISION}
|
|
TJclFloatBinaryTree = TJclSingleBinaryTree;
|
|
{$ENDIF MATH_SINGLE_PRECISION}
|
|
|
|
TJclIntegerBinaryNode = class
|
|
public
|
|
Value: Integer;
|
|
Left: TJclIntegerBinaryNode;
|
|
Right: TJclIntegerBinaryNode;
|
|
Parent: TJclIntegerBinaryNode;
|
|
end;
|
|
|
|
TJclIntegerBinaryTree = class(TJclIntegerAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclIntegerEqualityComparer, IJclIntegerComparer,
|
|
IJclIntegerCollection, IJclIntegerTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclIntegerBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclIntegerBinaryNode; Left, Right: Integer; Parent: TJclIntegerBinaryNode;
|
|
Offset: Integer): TJclIntegerBinaryNode;
|
|
function CloneNode(Node, Parent: TJclIntegerBinaryNode): TJclIntegerBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TIntegerCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclIntegerCollection }
|
|
function Add(AValue: Integer): Boolean;
|
|
function AddAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(AValue: Integer): Boolean;
|
|
function ContainsAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclIntegerCollection): Boolean;
|
|
function Extract(AValue: Integer): Boolean;
|
|
function ExtractAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
function First: IJclIntegerIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIntegerIterator;
|
|
function Remove(AValue: Integer): Boolean;
|
|
function RemoveAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclIntegerIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclIntegerTree }
|
|
function GetRoot: IJclIntegerTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclIntegerTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclIntegerBinaryTreeIterator = class(TJclAbstractIterator, IJclIntegerIterator, IJclIntegerTreeIterator, IJclIntegerBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclIntegerBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclIntegerCollection;
|
|
FEqualityComparer: IJclIntegerEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclIntegerBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclIntegerBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclIntegerCollection; ACursor: TJclIntegerBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclIntegerIterator }
|
|
function Add(AValue: Integer): Boolean;
|
|
procedure Extract;
|
|
function GetValue: Integer;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(AValue: Integer): Boolean;
|
|
function IteratorEquals(const AIterator: IJclIntegerIterator): Boolean;
|
|
function Next: Integer;
|
|
function NextIndex: Integer;
|
|
function Previous: Integer;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetValue(AValue: Integer);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: Integer read GetValue;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclIntegerTreeIterator }
|
|
function AddChild(AValue: Integer): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): Integer;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(AValue: Integer): Integer;
|
|
function InsertChild(Index: Integer; AValue: Integer): Boolean;
|
|
function Parent: Integer;
|
|
procedure SetChild(Index: Integer; AValue: Integer);
|
|
{ IJclIntegerBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: Integer;
|
|
function Right: Integer;
|
|
end;
|
|
|
|
TJclPreOrderIntegerBinaryTreeIterator = class(TJclIntegerBinaryTreeIterator, IJclIntegerIterator, IJclIntegerTreeIterator, IJclIntegerBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclIntegerBinaryNode; override;
|
|
function GetPreviousCursor: TJclIntegerBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderIntegerBinaryTreeIterator = class(TJclIntegerBinaryTreeIterator, IJclIntegerIterator, IJclIntegerTreeIterator, IJclIntegerBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclIntegerBinaryNode; override;
|
|
function GetPreviousCursor: TJclIntegerBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderIntegerBinaryTreeIterator = class(TJclIntegerBinaryTreeIterator, IJclIntegerIterator, IJclIntegerTreeIterator, IJclIntegerBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclIntegerBinaryNode; override;
|
|
function GetPreviousCursor: TJclIntegerBinaryNode; override;
|
|
end;
|
|
|
|
TJclCardinalBinaryNode = class
|
|
public
|
|
Value: Cardinal;
|
|
Left: TJclCardinalBinaryNode;
|
|
Right: TJclCardinalBinaryNode;
|
|
Parent: TJclCardinalBinaryNode;
|
|
end;
|
|
|
|
TJclCardinalBinaryTree = class(TJclCardinalAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclCardinalEqualityComparer, IJclCardinalComparer,
|
|
IJclCardinalCollection, IJclCardinalTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclCardinalBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclCardinalBinaryNode; Left, Right: Integer; Parent: TJclCardinalBinaryNode;
|
|
Offset: Integer): TJclCardinalBinaryNode;
|
|
function CloneNode(Node, Parent: TJclCardinalBinaryNode): TJclCardinalBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TCardinalCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclCardinalCollection }
|
|
function Add(AValue: Cardinal): Boolean;
|
|
function AddAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(AValue: Cardinal): Boolean;
|
|
function ContainsAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclCardinalCollection): Boolean;
|
|
function Extract(AValue: Cardinal): Boolean;
|
|
function ExtractAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
function First: IJclCardinalIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclCardinalIterator;
|
|
function Remove(AValue: Cardinal): Boolean;
|
|
function RemoveAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclCardinalIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclCardinalTree }
|
|
function GetRoot: IJclCardinalTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclCardinalTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclCardinalBinaryTreeIterator = class(TJclAbstractIterator, IJclCardinalIterator, IJclCardinalTreeIterator, IJclCardinalBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclCardinalBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclCardinalCollection;
|
|
FEqualityComparer: IJclCardinalEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclCardinalBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclCardinalBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclCardinalCollection; ACursor: TJclCardinalBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclCardinalIterator }
|
|
function Add(AValue: Cardinal): Boolean;
|
|
procedure Extract;
|
|
function GetValue: Cardinal;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(AValue: Cardinal): Boolean;
|
|
function IteratorEquals(const AIterator: IJclCardinalIterator): Boolean;
|
|
function Next: Cardinal;
|
|
function NextIndex: Integer;
|
|
function Previous: Cardinal;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetValue(AValue: Cardinal);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: Cardinal read GetValue;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclCardinalTreeIterator }
|
|
function AddChild(AValue: Cardinal): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): Cardinal;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(AValue: Cardinal): Integer;
|
|
function InsertChild(Index: Integer; AValue: Cardinal): Boolean;
|
|
function Parent: Cardinal;
|
|
procedure SetChild(Index: Integer; AValue: Cardinal);
|
|
{ IJclCardinalBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: Cardinal;
|
|
function Right: Cardinal;
|
|
end;
|
|
|
|
TJclPreOrderCardinalBinaryTreeIterator = class(TJclCardinalBinaryTreeIterator, IJclCardinalIterator, IJclCardinalTreeIterator, IJclCardinalBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclCardinalBinaryNode; override;
|
|
function GetPreviousCursor: TJclCardinalBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderCardinalBinaryTreeIterator = class(TJclCardinalBinaryTreeIterator, IJclCardinalIterator, IJclCardinalTreeIterator, IJclCardinalBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclCardinalBinaryNode; override;
|
|
function GetPreviousCursor: TJclCardinalBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderCardinalBinaryTreeIterator = class(TJclCardinalBinaryTreeIterator, IJclCardinalIterator, IJclCardinalTreeIterator, IJclCardinalBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclCardinalBinaryNode; override;
|
|
function GetPreviousCursor: TJclCardinalBinaryNode; override;
|
|
end;
|
|
|
|
TJclInt64BinaryNode = class
|
|
public
|
|
Value: Int64;
|
|
Left: TJclInt64BinaryNode;
|
|
Right: TJclInt64BinaryNode;
|
|
Parent: TJclInt64BinaryNode;
|
|
end;
|
|
|
|
TJclInt64BinaryTree = class(TJclInt64AbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclInt64EqualityComparer, IJclInt64Comparer,
|
|
IJclInt64Collection, IJclInt64Tree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclInt64BinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclInt64BinaryNode; Left, Right: Integer; Parent: TJclInt64BinaryNode;
|
|
Offset: Integer): TJclInt64BinaryNode;
|
|
function CloneNode(Node, Parent: TJclInt64BinaryNode): TJclInt64BinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TInt64Compare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclInt64Collection }
|
|
function Add(const AValue: Int64): Boolean;
|
|
function AddAll(const ACollection: IJclInt64Collection): Boolean;
|
|
procedure Clear;
|
|
function Contains(const AValue: Int64): Boolean;
|
|
function ContainsAll(const ACollection: IJclInt64Collection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclInt64Collection): Boolean;
|
|
function Extract(const AValue: Int64): Boolean;
|
|
function ExtractAll(const ACollection: IJclInt64Collection): Boolean;
|
|
function First: IJclInt64Iterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclInt64Iterator;
|
|
function Remove(const AValue: Int64): Boolean;
|
|
function RemoveAll(const ACollection: IJclInt64Collection): Boolean;
|
|
function RetainAll(const ACollection: IJclInt64Collection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclInt64Iterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclInt64Tree }
|
|
function GetRoot: IJclInt64TreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclInt64TreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclInt64BinaryTreeIterator = class(TJclAbstractIterator, IJclInt64Iterator, IJclInt64TreeIterator, IJclInt64BinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclInt64BinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclInt64Collection;
|
|
FEqualityComparer: IJclInt64EqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclInt64BinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclInt64BinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclInt64Collection; ACursor: TJclInt64BinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclInt64Iterator }
|
|
function Add(const AValue: Int64): Boolean;
|
|
procedure Extract;
|
|
function GetValue: Int64;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AValue: Int64): Boolean;
|
|
function IteratorEquals(const AIterator: IJclInt64Iterator): Boolean;
|
|
function Next: Int64;
|
|
function NextIndex: Integer;
|
|
function Previous: Int64;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetValue(const AValue: Int64);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: Int64 read GetValue;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclInt64TreeIterator }
|
|
function AddChild(const AValue: Int64): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): Int64;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AValue: Int64): Integer;
|
|
function InsertChild(Index: Integer; const AValue: Int64): Boolean;
|
|
function Parent: Int64;
|
|
procedure SetChild(Index: Integer; const AValue: Int64);
|
|
{ IJclInt64BinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: Int64;
|
|
function Right: Int64;
|
|
end;
|
|
|
|
TJclPreOrderInt64BinaryTreeIterator = class(TJclInt64BinaryTreeIterator, IJclInt64Iterator, IJclInt64TreeIterator, IJclInt64BinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclInt64BinaryNode; override;
|
|
function GetPreviousCursor: TJclInt64BinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderInt64BinaryTreeIterator = class(TJclInt64BinaryTreeIterator, IJclInt64Iterator, IJclInt64TreeIterator, IJclInt64BinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclInt64BinaryNode; override;
|
|
function GetPreviousCursor: TJclInt64BinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderInt64BinaryTreeIterator = class(TJclInt64BinaryTreeIterator, IJclInt64Iterator, IJclInt64TreeIterator, IJclInt64BinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclInt64BinaryNode; override;
|
|
function GetPreviousCursor: TJclInt64BinaryNode; override;
|
|
end;
|
|
|
|
TJclPtrBinaryNode = class
|
|
public
|
|
Value: Pointer;
|
|
Left: TJclPtrBinaryNode;
|
|
Right: TJclPtrBinaryNode;
|
|
Parent: TJclPtrBinaryNode;
|
|
end;
|
|
|
|
TJclPtrBinaryTree = class(TJclPtrAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclPtrEqualityComparer, IJclPtrComparer,
|
|
IJclPtrCollection, IJclPtrTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclPtrBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclPtrBinaryNode; Left, Right: Integer; Parent: TJclPtrBinaryNode;
|
|
Offset: Integer): TJclPtrBinaryNode;
|
|
function CloneNode(Node, Parent: TJclPtrBinaryNode): TJclPtrBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TPtrCompare);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclPtrCollection }
|
|
function Add(APtr: Pointer): Boolean;
|
|
function AddAll(const ACollection: IJclPtrCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(APtr: Pointer): Boolean;
|
|
function ContainsAll(const ACollection: IJclPtrCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclPtrCollection): Boolean;
|
|
function Extract(APtr: Pointer): Boolean;
|
|
function ExtractAll(const ACollection: IJclPtrCollection): Boolean;
|
|
function First: IJclPtrIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclPtrIterator;
|
|
function Remove(APtr: Pointer): Boolean;
|
|
function RemoveAll(const ACollection: IJclPtrCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclPtrCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclPtrIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclPtrTree }
|
|
function GetRoot: IJclPtrTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclPtrTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclPtrBinaryTreeIterator = class(TJclAbstractIterator, IJclPtrIterator, IJclPtrTreeIterator, IJclPtrBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclPtrBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclPtrCollection;
|
|
FEqualityComparer: IJclPtrEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclPtrBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclPtrBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclPtrCollection; ACursor: TJclPtrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclPtrIterator }
|
|
function Add(APtr: Pointer): Boolean;
|
|
procedure Extract;
|
|
function GetPointer: Pointer;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(APtr: Pointer): Boolean;
|
|
function IteratorEquals(const AIterator: IJclPtrIterator): Boolean;
|
|
function Next: Pointer;
|
|
function NextIndex: Integer;
|
|
function Previous: Pointer;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetPointer(APtr: Pointer);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: Pointer read GetPointer;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclPtrTreeIterator }
|
|
function AddChild(APtr: Pointer): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): Pointer;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(APtr: Pointer): Integer;
|
|
function InsertChild(Index: Integer; APtr: Pointer): Boolean;
|
|
function Parent: Pointer;
|
|
procedure SetChild(Index: Integer; APtr: Pointer);
|
|
{ IJclPtrBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: Pointer;
|
|
function Right: Pointer;
|
|
end;
|
|
|
|
TJclPreOrderPtrBinaryTreeIterator = class(TJclPtrBinaryTreeIterator, IJclPtrIterator, IJclPtrTreeIterator, IJclPtrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclPtrBinaryNode; override;
|
|
function GetPreviousCursor: TJclPtrBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderPtrBinaryTreeIterator = class(TJclPtrBinaryTreeIterator, IJclPtrIterator, IJclPtrTreeIterator, IJclPtrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclPtrBinaryNode; override;
|
|
function GetPreviousCursor: TJclPtrBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderPtrBinaryTreeIterator = class(TJclPtrBinaryTreeIterator, IJclPtrIterator, IJclPtrTreeIterator, IJclPtrBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclPtrBinaryNode; override;
|
|
function GetPreviousCursor: TJclPtrBinaryNode; override;
|
|
end;
|
|
|
|
TJclBinaryNode = class
|
|
public
|
|
Value: TObject;
|
|
Left: TJclBinaryNode;
|
|
Right: TJclBinaryNode;
|
|
Parent: TJclBinaryNode;
|
|
end;
|
|
|
|
TJclBinaryTree = class(TJclAbstractContainer, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclObjectOwner, IJclEqualityComparer, IJclComparer,
|
|
IJclCollection, IJclTree)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TJclBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TJclBinaryNode; Left, Right: Integer; Parent: TJclBinaryNode;
|
|
Offset: Integer): TJclBinaryNode;
|
|
function CloneNode(Node, Parent: TJclBinaryNode): TJclBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(ACompare: TCompare; AOwnsObjects: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclCollection }
|
|
function Add(AObject: TObject): Boolean;
|
|
function AddAll(const ACollection: IJclCollection): Boolean;
|
|
procedure Clear;
|
|
function Contains(AObject: TObject): Boolean;
|
|
function ContainsAll(const ACollection: IJclCollection): Boolean;
|
|
function CollectionEquals(const ACollection: IJclCollection): Boolean;
|
|
function Extract(AObject: TObject): Boolean;
|
|
function ExtractAll(const ACollection: IJclCollection): Boolean;
|
|
function First: IJclIterator;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIterator;
|
|
function Remove(AObject: TObject): Boolean;
|
|
function RemoveAll(const ACollection: IJclCollection): Boolean;
|
|
function RetainAll(const ACollection: IJclCollection): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclIterator;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclTree }
|
|
function GetRoot: IJclTreeIterator;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclTreeIterator read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclBinaryTreeIterator = class(TJclAbstractIterator, IJclIterator, IJclTreeIterator, IJclBinaryTreeIterator)
|
|
protected
|
|
FCursor: TJclBinaryNode;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclCollection;
|
|
FEqualityComparer: IJclEqualityComparer;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclBinaryNode; virtual; abstract;
|
|
function GetPreviousCursor: TJclBinaryNode; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclCollection; ACursor: TJclBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclIterator }
|
|
function Add(AObject: TObject): Boolean;
|
|
procedure Extract;
|
|
function GetObject: TObject;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(AObject: TObject): Boolean;
|
|
function IteratorEquals(const AIterator: IJclIterator): Boolean;
|
|
function Next: TObject;
|
|
function NextIndex: Integer;
|
|
function Previous: TObject;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetObject(AObject: TObject);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: TObject read GetObject;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclTreeIterator }
|
|
function AddChild(AObject: TObject): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): TObject;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(AObject: TObject): Integer;
|
|
function InsertChild(Index: Integer; AObject: TObject): Boolean;
|
|
function Parent: TObject;
|
|
procedure SetChild(Index: Integer; AObject: TObject);
|
|
{ IJclBinaryTreeIterator }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: TObject;
|
|
function Right: TObject;
|
|
end;
|
|
|
|
TJclPreOrderBinaryTreeIterator = class(TJclBinaryTreeIterator, IJclIterator, IJclTreeIterator, IJclBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclBinaryNode; override;
|
|
function GetPreviousCursor: TJclBinaryNode; override;
|
|
end;
|
|
|
|
TJclInOrderBinaryTreeIterator = class(TJclBinaryTreeIterator, IJclIterator, IJclTreeIterator, IJclBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclBinaryNode; override;
|
|
function GetPreviousCursor: TJclBinaryNode; override;
|
|
end;
|
|
|
|
TJclPostOrderBinaryTreeIterator = class(TJclBinaryTreeIterator, IJclIterator, IJclTreeIterator, IJclBinaryTreeIterator,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclBinaryNode; override;
|
|
function GetPreviousCursor: TJclBinaryNode; override;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_GENERICS}
|
|
TJclBinaryNode<T> = class
|
|
public
|
|
Value: T;
|
|
Left: TJclBinaryNode<T>;
|
|
Right: TJclBinaryNode<T>;
|
|
Parent: TJclBinaryNode<T>;
|
|
end;
|
|
|
|
TJclBinaryTreeIterator<T> = class;
|
|
TJclPreOrderBinaryTreeIterator<T> = class;
|
|
TJclInOrderBinaryTreeIterator<T> = class;
|
|
TJclPostOrderBinaryTreeIterator<T> = class;
|
|
|
|
TJclBinaryTree<T> = class(TJclAbstractContainer<T>, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclPackable, IJclContainer, IJclItemOwner<T>, IJclEqualityComparer<T>, IJclComparer<T>,
|
|
IJclCollection<T>, IJclTree<T>)
|
|
protected
|
|
type
|
|
TBinaryNode = TJclBinaryNode<T>;
|
|
TPreOrderBinaryTreeIterator = TJclPreOrderBinaryTreeIterator<T>;
|
|
TInOrderBinaryTreeIterator = TJclInOrderBinaryTreeIterator<T>;
|
|
TPostOrderBinaryTreeIterator = TJclPostOrderBinaryTreeIterator<T>;
|
|
private
|
|
FMaxDepth: Integer;
|
|
FRoot: TBinaryNode;
|
|
FTraverseOrder: TJclTraverseOrder;
|
|
function BuildTree(const LeafArray: array of TBinaryNode; Left, Right: Integer; Parent: TBinaryNode;
|
|
Offset: Integer): TBinaryNode;
|
|
function CloneNode(Node, Parent: TBinaryNode): TBinaryNode;
|
|
protected
|
|
procedure AssignDataTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
procedure AutoPack; override;
|
|
public
|
|
constructor Create(AOwnsItems: Boolean);
|
|
destructor Destroy; override;
|
|
{ IJclPackable }
|
|
procedure Pack; override;
|
|
procedure SetCapacity(Value: Integer); override;
|
|
{ IJclCollection<T> }
|
|
function Add(const AItem: T): Boolean;
|
|
function AddAll(const ACollection: IJclCollection<T>): Boolean;
|
|
procedure Clear;
|
|
function Contains(const AItem: T): Boolean;
|
|
function ContainsAll(const ACollection: IJclCollection<T>): Boolean;
|
|
function CollectionEquals(const ACollection: IJclCollection<T>): Boolean;
|
|
function Extract(const AItem: T): Boolean;
|
|
function ExtractAll(const ACollection: IJclCollection<T>): Boolean;
|
|
function First: IJclIterator<T>;
|
|
function IsEmpty: Boolean;
|
|
function Last: IJclIterator<T>;
|
|
function Remove(const AItem: T): Boolean;
|
|
function RemoveAll(const ACollection: IJclCollection<T>): Boolean;
|
|
function RetainAll(const ACollection: IJclCollection<T>): Boolean;
|
|
function Size: Integer;
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function GetEnumerator: IJclIterator<T>;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclTree<T> }
|
|
function GetRoot: IJclTreeIterator<T>;
|
|
function GetTraverseOrder: TJclTraverseOrder;
|
|
procedure SetTraverseOrder(Value: TJclTraverseOrder);
|
|
property Root: IJclTreeIterator<T> read GetRoot;
|
|
property TraverseOrder: TJclTraverseOrder read GetTraverseOrder write SetTraverseOrder;
|
|
end;
|
|
|
|
TJclBinaryTreeIterator<T> = class(TJclAbstractIterator, IJclIterator<T>, IJclTreeIterator<T>, IJclBinaryTreeIterator<T>)
|
|
protected
|
|
FCursor: TJclBinaryNode<T>;
|
|
FStart: TItrStart;
|
|
FOwnTree: IJclCollection<T>;
|
|
FEqualityComparer: IJclEqualityComparer<T>;
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractIterator); override;
|
|
function GetNextCursor: TJclBinaryNode<T>; virtual; abstract;
|
|
function GetPreviousCursor: TJclBinaryNode<T>; virtual; abstract;
|
|
public
|
|
constructor Create(const AOwnTree: IJclCollection<T>; ACursor: TJclBinaryNode<T>; AValid: Boolean; AStart: TItrStart);
|
|
{ IJclIterator<T> }
|
|
function Add(const AItem: T): Boolean;
|
|
procedure Extract;
|
|
function GetItem: T;
|
|
function HasNext: Boolean;
|
|
function HasPrevious: Boolean;
|
|
function Insert(const AItem: T): Boolean;
|
|
function IteratorEquals(const AIterator: IJclIterator<T>): Boolean;
|
|
function Next: T;
|
|
function NextIndex: Integer;
|
|
function Previous: T;
|
|
function PreviousIndex: Integer;
|
|
procedure Remove;
|
|
procedure Reset;
|
|
procedure SetItem(const AItem: T);
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function MoveNext: Boolean;
|
|
property Current: T read GetItem;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
{ IJclTreeIterator<T> }
|
|
function AddChild(const AItem: T): Boolean;
|
|
function ChildrenCount: Integer;
|
|
procedure DeleteChild(Index: Integer);
|
|
procedure DeleteChildren;
|
|
procedure ExtractChild(Index: Integer);
|
|
procedure ExtractChildren;
|
|
function GetChild(Index: Integer): T;
|
|
function HasChild(Index: Integer): Boolean;
|
|
function HasParent: Boolean;
|
|
function IndexOfChild(const AItem: T): Integer;
|
|
function InsertChild(Index: Integer; const AItem: T): Boolean;
|
|
function Parent: T;
|
|
procedure SetChild(Index: Integer; const AItem: T);
|
|
{ IJclBinaryTreeIterator<T> }
|
|
function HasLeft: Boolean;
|
|
function HasRight: Boolean;
|
|
function Left: T;
|
|
function Right: T;
|
|
end;
|
|
|
|
TJclPreOrderBinaryTreeIterator<T> = class(TJclBinaryTreeIterator<T>, IJclIterator<T>, IJclTreeIterator<T>, IJclBinaryTreeIterator<T>,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclBinaryNode<T>; override;
|
|
function GetPreviousCursor: TJclBinaryNode<T>; override;
|
|
end;
|
|
|
|
TJclInOrderBinaryTreeIterator<T> = class(TJclBinaryTreeIterator<T>, IJclIterator<T>, IJclTreeIterator<T>, IJclBinaryTreeIterator<T>,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclBinaryNode<T>; override;
|
|
function GetPreviousCursor: TJclBinaryNode<T>; override;
|
|
end;
|
|
|
|
TJclPostOrderBinaryTreeIterator<T> = class(TJclBinaryTreeIterator<T>, IJclIterator<T>, IJclTreeIterator<T>, IJclBinaryTreeIterator<T>,
|
|
{$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE} IJclIntfCloneable, IJclCloneable)
|
|
protected
|
|
function CreateEmptyIterator: TJclAbstractIterator; override;
|
|
function GetNextCursor: TJclBinaryNode<T>; override;
|
|
function GetPreviousCursor: TJclBinaryNode<T>; override;
|
|
end;
|
|
|
|
// E = External helper to compare items
|
|
TJclBinaryTreeE<T> = class(TJclBinaryTree<T>, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclContainer, IJclItemOwner<T>, IJclEqualityComparer<T>, IJclComparer<T>,
|
|
IJclCollection<T>, IJclTree<T>)
|
|
private
|
|
FComparer: IJclComparer<T>;
|
|
protected
|
|
procedure AssignPropertiesTo(Dest: TJclAbstractContainerBase); override;
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
public
|
|
constructor Create(const AComparer: IJclComparer<T>; AOwnsItems: Boolean);
|
|
{ IJclComparer<T> }
|
|
function ItemsCompare(const A, B: T): Integer; override;
|
|
{ IJclEqualityComparer<T> }
|
|
function ItemsEqual(const A, B: T): Boolean; override;
|
|
property Comparer: IJclComparer<T> read FComparer write FComparer;
|
|
end;
|
|
|
|
// F = Function to compare items
|
|
TJclBinaryTreeF<T> = class(TJclBinaryTree<T>, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclContainer, IJclItemOwner<T>, IJclEqualityComparer<T>, IJclComparer<T>,
|
|
IJclCollection<T>, IJclTree<T>)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
public
|
|
constructor Create(ACompare: TCompare<T>; AOwnsItems: Boolean);
|
|
end;
|
|
|
|
// I = Items can compare themselves to an other
|
|
TJclBinaryTreeI<T: IComparable<T>> = class(TJclBinaryTree<T>, {$IFDEF THREADSAFE} IJclLockable, {$ENDIF THREADSAFE}
|
|
IJclIntfCloneable, IJclCloneable, IJclContainer, IJclItemOwner<T>, IJclEqualityComparer<T>, IJclComparer<T>,
|
|
IJclCollection<T>, IJclTree<T>)
|
|
protected
|
|
function CreateEmptyContainer: TJclAbstractContainerBase; override;
|
|
public
|
|
{ IJclComparer<T> }
|
|
function ItemsCompare(const A, B: T): Integer; override;
|
|
{ IJclEqualityComparer<T> }
|
|
function ItemsEqual(const A, B: T): Boolean; override;
|
|
end;
|
|
{$ENDIF SUPPORTS_GENERICS}
|
|
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jcl.svn.sourceforge.net/svnroot/jcl/tags/JCL-2.1-Build3536/jcl/source/common/JclBinaryTrees.pas $';
|
|
Revision: '$Revision: 2997 $';
|
|
Date: '$Date: 2009-09-12 14:21:23 +0200 (sam., 12 sept. 2009) $';
|
|
LogPath: 'JCL\source\common';
|
|
Extra: '';
|
|
Data: nil
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils;
|
|
|
|
//=== { TJclIntfBinaryTree } =================================================
|
|
|
|
constructor TJclIntfBinaryTree.Create(ACompare: TIntfCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclIntfBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Add(const AInterface: IInterface): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclIntfBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AInterface, nil) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AInterface, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclIntfBinaryNode.Create;
|
|
NewNode.Value := AInterface;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.AddAll(const ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclIntfBinaryTree;
|
|
ACollection: IJclIntfCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntfBinaryTree then
|
|
begin
|
|
ADest := TJclIntfBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclIntfCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclIntfBinaryTree then
|
|
TJclIntfBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.BuildTree(const LeafArray: array of TJclIntfBinaryNode; Left, Right: Integer; Parent: TJclIntfBinaryNode;
|
|
Offset: Integer): TJclIntfBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclIntfBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeObject(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.CloneNode(Node, Parent: TJclIntfBinaryNode): TJclIntfBinaryNode;
|
|
begin
|
|
Result := TJclIntfBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.CollectionEquals(const ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclIntfIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Contains(const AInterface: IInterface): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclIntfBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AInterface);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.ContainsAll(const ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Extract(const AInterface: IInterface): Boolean;
|
|
var
|
|
Current, Successor: TJclIntfBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AInterface in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AInterface, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := nil;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.ExtractAll(const ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.First: IJclIntfIterator;
|
|
var
|
|
Start: TJclIntfBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderIntfBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderIntfBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderIntfBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclIntfBinaryTree.GetEnumerator: IJclIntfIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclIntfBinaryTree.GetRoot: IJclIntfTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderIntfBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderIntfBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderIntfBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Last: IJclIntfIterator;
|
|
var
|
|
Start: TJclIntfBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderIntfBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderIntfBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderIntfBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclIntfBinaryNode;
|
|
ANode, BNode: TJclIntfBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Remove(const AInterface: IInterface): Boolean;
|
|
var
|
|
Extracted: IInterface;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AInterface);
|
|
if Result then
|
|
begin
|
|
Extracted := AInterface;
|
|
FreeObject(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.RemoveAll(const ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.RetainAll(const ACollection: IJclIntfCollection): Boolean;
|
|
var
|
|
It: IJclIntfIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntfBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntfBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclIntfBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclIntfBinaryTreeIterator.Create(const AOwnTree: IJclIntfCollection; ACursor: TJclIntfBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclIntfEqualityComparer;
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.Add(const AInterface: IInterface): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AInterface);
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.AddChild(const AInterface: IInterface): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclIntfBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclIntfBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclIntfBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclIntfBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.GetChild(Index: Integer): IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.GetObject: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.IndexOfChild(const AInterface: IInterface): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AInterface) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AInterface) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AInterface) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.Insert(const AInterface: IInterface): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.InsertChild(Index: Integer; const AInterface: IInterface): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.IteratorEquals(const AIterator: IJclIntfIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclIntfBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclIntfBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclIntfBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.Left: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclIntfBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclIntfBinaryTreeIterator.Next: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.Parent: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.Previous: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclIntfBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclIntfBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntfBinaryTreeIterator.Right: IInterface;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.SetChild(Index: Integer; const AInterface: IInterface);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntfBinaryTreeIterator.SetObject(const AInterface: IInterface);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderIntfBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderIntfBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderIntfBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderIntfBinaryTreeIterator.GetNextCursor: TJclIntfBinaryNode;
|
|
var
|
|
LastRet: TJclIntfBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderIntfBinaryTreeIterator.GetPreviousCursor: TJclIntfBinaryNode;
|
|
var
|
|
LastRet: TJclIntfBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderIntfBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderIntfBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderIntfBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderIntfBinaryTreeIterator.GetNextCursor: TJclIntfBinaryNode;
|
|
var
|
|
LastRet: TJclIntfBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderIntfBinaryTreeIterator.GetPreviousCursor: TJclIntfBinaryNode;
|
|
var
|
|
LastRet: TJclIntfBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderIntfBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderIntfBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderIntfBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderIntfBinaryTreeIterator.GetNextCursor: TJclIntfBinaryNode;
|
|
var
|
|
LastRet: TJclIntfBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderIntfBinaryTreeIterator.GetPreviousCursor: TJclIntfBinaryNode;
|
|
var
|
|
LastRet: TJclIntfBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclAnsiStrBinaryTree } =================================================
|
|
|
|
constructor TJclAnsiStrBinaryTree.Create(ACompare: TAnsiStrCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclAnsiStrBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.Add(const AString: AnsiString): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclAnsiStrBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AString, '') then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AString, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclAnsiStrBinaryNode.Create;
|
|
NewNode.Value := AString;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.AddAll(const ACollection: IJclAnsiStrCollection): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclAnsiStrBinaryTree;
|
|
ACollection: IJclAnsiStrCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclAnsiStrBinaryTree then
|
|
begin
|
|
ADest := TJclAnsiStrBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclAnsiStrCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclAnsiStrBinaryTree then
|
|
TJclAnsiStrBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.BuildTree(const LeafArray: array of TJclAnsiStrBinaryNode; Left, Right: Integer; Parent: TJclAnsiStrBinaryNode;
|
|
Offset: Integer): TJclAnsiStrBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclAnsiStrBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeString(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.CloneNode(Node, Parent: TJclAnsiStrBinaryNode): TJclAnsiStrBinaryNode;
|
|
begin
|
|
Result := TJclAnsiStrBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.CollectionEquals(const ACollection: IJclAnsiStrCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclAnsiStrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.Contains(const AString: AnsiString): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclAnsiStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AString);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.ContainsAll(const ACollection: IJclAnsiStrCollection): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.Extract(const AString: AnsiString): Boolean;
|
|
var
|
|
Current, Successor: TJclAnsiStrBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AString in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AString, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := '';
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.ExtractAll(const ACollection: IJclAnsiStrCollection): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.First: IJclAnsiStrIterator;
|
|
var
|
|
Start: TJclAnsiStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderAnsiStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderAnsiStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderAnsiStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclAnsiStrBinaryTree.GetEnumerator: IJclAnsiStrIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclAnsiStrBinaryTree.GetRoot: IJclAnsiStrTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderAnsiStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderAnsiStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderAnsiStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.Last: IJclAnsiStrIterator;
|
|
var
|
|
Start: TJclAnsiStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderAnsiStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderAnsiStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderAnsiStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclAnsiStrBinaryNode;
|
|
ANode, BNode: TJclAnsiStrBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.Remove(const AString: AnsiString): Boolean;
|
|
var
|
|
Extracted: AnsiString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AString);
|
|
if Result then
|
|
begin
|
|
Extracted := AString;
|
|
FreeString(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.RemoveAll(const ACollection: IJclAnsiStrCollection): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.RetainAll(const ACollection: IJclAnsiStrCollection): Boolean;
|
|
var
|
|
It: IJclAnsiStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclAnsiStrBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclAnsiStrBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclAnsiStrBinaryTreeIterator.Create(const AOwnTree: IJclAnsiStrCollection; ACursor: TJclAnsiStrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclAnsiStrEqualityComparer;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.Add(const AString: AnsiString): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AString);
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.AddChild(const AString: AnsiString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclAnsiStrBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclAnsiStrBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclAnsiStrBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclAnsiStrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.GetChild(Index: Integer): AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.GetString: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.IndexOfChild(const AString: AnsiString): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AString) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AString) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AString) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.Insert(const AString: AnsiString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.InsertChild(Index: Integer; const AString: AnsiString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.IteratorEquals(const AIterator: IJclAnsiStrIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclAnsiStrBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclAnsiStrBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclAnsiStrBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.Left: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclAnsiStrBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.Next: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.Parent: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.Previous: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclAnsiStrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclAnsiStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclAnsiStrBinaryTreeIterator.Right: AnsiString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.SetChild(Index: Integer; const AString: AnsiString);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclAnsiStrBinaryTreeIterator.SetString(const AString: AnsiString);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderAnsiStrBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderAnsiStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderAnsiStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderAnsiStrBinaryTreeIterator.GetNextCursor: TJclAnsiStrBinaryNode;
|
|
var
|
|
LastRet: TJclAnsiStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderAnsiStrBinaryTreeIterator.GetPreviousCursor: TJclAnsiStrBinaryNode;
|
|
var
|
|
LastRet: TJclAnsiStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderAnsiStrBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderAnsiStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderAnsiStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderAnsiStrBinaryTreeIterator.GetNextCursor: TJclAnsiStrBinaryNode;
|
|
var
|
|
LastRet: TJclAnsiStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderAnsiStrBinaryTreeIterator.GetPreviousCursor: TJclAnsiStrBinaryNode;
|
|
var
|
|
LastRet: TJclAnsiStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderAnsiStrBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderAnsiStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderAnsiStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderAnsiStrBinaryTreeIterator.GetNextCursor: TJclAnsiStrBinaryNode;
|
|
var
|
|
LastRet: TJclAnsiStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderAnsiStrBinaryTreeIterator.GetPreviousCursor: TJclAnsiStrBinaryNode;
|
|
var
|
|
LastRet: TJclAnsiStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclWideStrBinaryTree } =================================================
|
|
|
|
constructor TJclWideStrBinaryTree.Create(ACompare: TWideStrCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclWideStrBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.Add(const AString: WideString): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclWideStrBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AString, '') then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AString, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclWideStrBinaryNode.Create;
|
|
NewNode.Value := AString;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.AddAll(const ACollection: IJclWideStrCollection): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclWideStrBinaryTree;
|
|
ACollection: IJclWideStrCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclWideStrBinaryTree then
|
|
begin
|
|
ADest := TJclWideStrBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclWideStrCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclWideStrBinaryTree then
|
|
TJclWideStrBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.BuildTree(const LeafArray: array of TJclWideStrBinaryNode; Left, Right: Integer; Parent: TJclWideStrBinaryNode;
|
|
Offset: Integer): TJclWideStrBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclWideStrBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeString(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.CloneNode(Node, Parent: TJclWideStrBinaryNode): TJclWideStrBinaryNode;
|
|
begin
|
|
Result := TJclWideStrBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.CollectionEquals(const ACollection: IJclWideStrCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclWideStrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.Contains(const AString: WideString): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclWideStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AString);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.ContainsAll(const ACollection: IJclWideStrCollection): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.Extract(const AString: WideString): Boolean;
|
|
var
|
|
Current, Successor: TJclWideStrBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AString in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AString, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := '';
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.ExtractAll(const ACollection: IJclWideStrCollection): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.First: IJclWideStrIterator;
|
|
var
|
|
Start: TJclWideStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderWideStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderWideStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderWideStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclWideStrBinaryTree.GetEnumerator: IJclWideStrIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclWideStrBinaryTree.GetRoot: IJclWideStrTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderWideStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderWideStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderWideStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.Last: IJclWideStrIterator;
|
|
var
|
|
Start: TJclWideStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderWideStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderWideStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderWideStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclWideStrBinaryNode;
|
|
ANode, BNode: TJclWideStrBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.Remove(const AString: WideString): Boolean;
|
|
var
|
|
Extracted: WideString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AString);
|
|
if Result then
|
|
begin
|
|
Extracted := AString;
|
|
FreeString(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.RemoveAll(const ACollection: IJclWideStrCollection): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.RetainAll(const ACollection: IJclWideStrCollection): Boolean;
|
|
var
|
|
It: IJclWideStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclWideStrBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclWideStrBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclWideStrBinaryTreeIterator.Create(const AOwnTree: IJclWideStrCollection; ACursor: TJclWideStrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclWideStrEqualityComparer;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.Add(const AString: WideString): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AString);
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.AddChild(const AString: WideString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclWideStrBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclWideStrBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclWideStrBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclWideStrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.GetChild(Index: Integer): WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.GetString: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.IndexOfChild(const AString: WideString): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AString) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AString) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AString) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.Insert(const AString: WideString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.InsertChild(Index: Integer; const AString: WideString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.IteratorEquals(const AIterator: IJclWideStrIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclWideStrBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclWideStrBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclWideStrBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.Left: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclWideStrBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclWideStrBinaryTreeIterator.Next: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.Parent: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.Previous: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclWideStrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclWideStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclWideStrBinaryTreeIterator.Right: WideString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.SetChild(Index: Integer; const AString: WideString);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclWideStrBinaryTreeIterator.SetString(const AString: WideString);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderWideStrBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderWideStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderWideStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderWideStrBinaryTreeIterator.GetNextCursor: TJclWideStrBinaryNode;
|
|
var
|
|
LastRet: TJclWideStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderWideStrBinaryTreeIterator.GetPreviousCursor: TJclWideStrBinaryNode;
|
|
var
|
|
LastRet: TJclWideStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderWideStrBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderWideStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderWideStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderWideStrBinaryTreeIterator.GetNextCursor: TJclWideStrBinaryNode;
|
|
var
|
|
LastRet: TJclWideStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderWideStrBinaryTreeIterator.GetPreviousCursor: TJclWideStrBinaryNode;
|
|
var
|
|
LastRet: TJclWideStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderWideStrBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderWideStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderWideStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderWideStrBinaryTreeIterator.GetNextCursor: TJclWideStrBinaryNode;
|
|
var
|
|
LastRet: TJclWideStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderWideStrBinaryTreeIterator.GetPreviousCursor: TJclWideStrBinaryNode;
|
|
var
|
|
LastRet: TJclWideStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_UNICODE_STRING}
|
|
//=== { TJclUnicodeStrBinaryTree } =================================================
|
|
|
|
constructor TJclUnicodeStrBinaryTree.Create(ACompare: TUnicodeStrCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclUnicodeStrBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.Add(const AString: UnicodeString): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclUnicodeStrBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AString, '') then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AString, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclUnicodeStrBinaryNode.Create;
|
|
NewNode.Value := AString;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.AddAll(const ACollection: IJclUnicodeStrCollection): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclUnicodeStrBinaryTree;
|
|
ACollection: IJclUnicodeStrCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclUnicodeStrBinaryTree then
|
|
begin
|
|
ADest := TJclUnicodeStrBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclUnicodeStrCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclUnicodeStrBinaryTree then
|
|
TJclUnicodeStrBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.BuildTree(const LeafArray: array of TJclUnicodeStrBinaryNode; Left, Right: Integer; Parent: TJclUnicodeStrBinaryNode;
|
|
Offset: Integer): TJclUnicodeStrBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeString(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.CloneNode(Node, Parent: TJclUnicodeStrBinaryNode): TJclUnicodeStrBinaryNode;
|
|
begin
|
|
Result := TJclUnicodeStrBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.CollectionEquals(const ACollection: IJclUnicodeStrCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclUnicodeStrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.Contains(const AString: UnicodeString): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AString);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.ContainsAll(const ACollection: IJclUnicodeStrCollection): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.Extract(const AString: UnicodeString): Boolean;
|
|
var
|
|
Current, Successor: TJclUnicodeStrBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AString in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AString, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := '';
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.ExtractAll(const ACollection: IJclUnicodeStrCollection): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.First: IJclUnicodeStrIterator;
|
|
var
|
|
Start: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderUnicodeStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderUnicodeStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderUnicodeStrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclUnicodeStrBinaryTree.GetEnumerator: IJclUnicodeStrIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclUnicodeStrBinaryTree.GetRoot: IJclUnicodeStrTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderUnicodeStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderUnicodeStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderUnicodeStrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.Last: IJclUnicodeStrIterator;
|
|
var
|
|
Start: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderUnicodeStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderUnicodeStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderUnicodeStrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclUnicodeStrBinaryNode;
|
|
ANode, BNode: TJclUnicodeStrBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.Remove(const AString: UnicodeString): Boolean;
|
|
var
|
|
Extracted: UnicodeString;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AString);
|
|
if Result then
|
|
begin
|
|
Extracted := AString;
|
|
FreeString(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.RemoveAll(const ACollection: IJclUnicodeStrCollection): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.RetainAll(const ACollection: IJclUnicodeStrCollection): Boolean;
|
|
var
|
|
It: IJclUnicodeStrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclUnicodeStrBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclUnicodeStrBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclUnicodeStrBinaryTreeIterator.Create(const AOwnTree: IJclUnicodeStrCollection; ACursor: TJclUnicodeStrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclUnicodeStrEqualityComparer;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.Add(const AString: UnicodeString): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AString);
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.AddChild(const AString: UnicodeString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclUnicodeStrBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclUnicodeStrBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclUnicodeStrBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.GetChild(Index: Integer): UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.GetString: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.IndexOfChild(const AString: UnicodeString): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AString) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AString) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AString) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.Insert(const AString: UnicodeString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.InsertChild(Index: Integer; const AString: UnicodeString): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.IteratorEquals(const AIterator: IJclUnicodeStrIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclUnicodeStrBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclUnicodeStrBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclUnicodeStrBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.Left: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclUnicodeStrBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.Next: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.Parent: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.Previous: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclUnicodeStrBinaryTreeIterator.Right: UnicodeString;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := '';
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.SetChild(Index: Integer; const AString: UnicodeString);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclUnicodeStrBinaryTreeIterator.SetString(const AString: UnicodeString);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderUnicodeStrBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderUnicodeStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderUnicodeStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderUnicodeStrBinaryTreeIterator.GetNextCursor: TJclUnicodeStrBinaryNode;
|
|
var
|
|
LastRet: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderUnicodeStrBinaryTreeIterator.GetPreviousCursor: TJclUnicodeStrBinaryNode;
|
|
var
|
|
LastRet: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderUnicodeStrBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderUnicodeStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderUnicodeStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderUnicodeStrBinaryTreeIterator.GetNextCursor: TJclUnicodeStrBinaryNode;
|
|
var
|
|
LastRet: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderUnicodeStrBinaryTreeIterator.GetPreviousCursor: TJclUnicodeStrBinaryNode;
|
|
var
|
|
LastRet: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderUnicodeStrBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderUnicodeStrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderUnicodeStrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderUnicodeStrBinaryTreeIterator.GetNextCursor: TJclUnicodeStrBinaryNode;
|
|
var
|
|
LastRet: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderUnicodeStrBinaryTreeIterator.GetPreviousCursor: TJclUnicodeStrBinaryNode;
|
|
var
|
|
LastRet: TJclUnicodeStrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
{$ENDIF SUPPORTS_UNICODE_STRING}
|
|
|
|
//=== { TJclSingleBinaryTree } =================================================
|
|
|
|
constructor TJclSingleBinaryTree.Create(ACompare: TSingleCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclSingleBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.Add(const AValue: Single): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclSingleBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AValue, 0.0) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclSingleBinaryNode.Create;
|
|
NewNode.Value := AValue;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.AddAll(const ACollection: IJclSingleCollection): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclSingleBinaryTree;
|
|
ACollection: IJclSingleCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclSingleBinaryTree then
|
|
begin
|
|
ADest := TJclSingleBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclSingleCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclSingleBinaryTree then
|
|
TJclSingleBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.BuildTree(const LeafArray: array of TJclSingleBinaryNode; Left, Right: Integer; Parent: TJclSingleBinaryNode;
|
|
Offset: Integer): TJclSingleBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclSingleBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeSingle(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.CloneNode(Node, Parent: TJclSingleBinaryNode): TJclSingleBinaryNode;
|
|
begin
|
|
Result := TJclSingleBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.CollectionEquals(const ACollection: IJclSingleCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclSingleIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.Contains(const AValue: Single): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclSingleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AValue);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.ContainsAll(const ACollection: IJclSingleCollection): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.Extract(const AValue: Single): Boolean;
|
|
var
|
|
Current, Successor: TJclSingleBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AValue in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := 0.0;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.ExtractAll(const ACollection: IJclSingleCollection): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.First: IJclSingleIterator;
|
|
var
|
|
Start: TJclSingleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderSingleBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderSingleBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderSingleBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclSingleBinaryTree.GetEnumerator: IJclSingleIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclSingleBinaryTree.GetRoot: IJclSingleTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderSingleBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderSingleBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderSingleBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.Last: IJclSingleIterator;
|
|
var
|
|
Start: TJclSingleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderSingleBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderSingleBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderSingleBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclSingleBinaryNode;
|
|
ANode, BNode: TJclSingleBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.Remove(const AValue: Single): Boolean;
|
|
var
|
|
Extracted: Single;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AValue);
|
|
if Result then
|
|
begin
|
|
Extracted := AValue;
|
|
FreeSingle(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.RemoveAll(const ACollection: IJclSingleCollection): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.RetainAll(const ACollection: IJclSingleCollection): Boolean;
|
|
var
|
|
It: IJclSingleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclSingleBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclSingleBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclSingleBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclSingleBinaryTreeIterator.Create(const AOwnTree: IJclSingleCollection; ACursor: TJclSingleBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclSingleEqualityComparer;
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.Add(const AValue: Single): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AValue);
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.AddChild(const AValue: Single): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclSingleBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclSingleBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclSingleBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclSingleBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.GetChild(Index: Integer): Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.GetValue: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.IndexOfChild(const AValue: Single): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AValue) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.Insert(const AValue: Single): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.InsertChild(Index: Integer; const AValue: Single): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.IteratorEquals(const AIterator: IJclSingleIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclSingleBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclSingleBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclSingleBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.Left: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclSingleBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclSingleBinaryTreeIterator.Next: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.Parent: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.Previous: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclSingleBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclSingleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclSingleBinaryTreeIterator.Right: Single;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.SetChild(Index: Integer; const AValue: Single);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclSingleBinaryTreeIterator.SetValue(const AValue: Single);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderSingleBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderSingleBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderSingleBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderSingleBinaryTreeIterator.GetNextCursor: TJclSingleBinaryNode;
|
|
var
|
|
LastRet: TJclSingleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderSingleBinaryTreeIterator.GetPreviousCursor: TJclSingleBinaryNode;
|
|
var
|
|
LastRet: TJclSingleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderSingleBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderSingleBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderSingleBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderSingleBinaryTreeIterator.GetNextCursor: TJclSingleBinaryNode;
|
|
var
|
|
LastRet: TJclSingleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderSingleBinaryTreeIterator.GetPreviousCursor: TJclSingleBinaryNode;
|
|
var
|
|
LastRet: TJclSingleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderSingleBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderSingleBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderSingleBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderSingleBinaryTreeIterator.GetNextCursor: TJclSingleBinaryNode;
|
|
var
|
|
LastRet: TJclSingleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderSingleBinaryTreeIterator.GetPreviousCursor: TJclSingleBinaryNode;
|
|
var
|
|
LastRet: TJclSingleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclDoubleBinaryTree } =================================================
|
|
|
|
constructor TJclDoubleBinaryTree.Create(ACompare: TDoubleCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclDoubleBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.Add(const AValue: Double): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclDoubleBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AValue, 0.0) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclDoubleBinaryNode.Create;
|
|
NewNode.Value := AValue;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.AddAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclDoubleBinaryTree;
|
|
ACollection: IJclDoubleCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclDoubleBinaryTree then
|
|
begin
|
|
ADest := TJclDoubleBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclDoubleCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclDoubleBinaryTree then
|
|
TJclDoubleBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.BuildTree(const LeafArray: array of TJclDoubleBinaryNode; Left, Right: Integer; Parent: TJclDoubleBinaryNode;
|
|
Offset: Integer): TJclDoubleBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclDoubleBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeDouble(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.CloneNode(Node, Parent: TJclDoubleBinaryNode): TJclDoubleBinaryNode;
|
|
begin
|
|
Result := TJclDoubleBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.CollectionEquals(const ACollection: IJclDoubleCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclDoubleIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.Contains(const AValue: Double): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclDoubleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AValue);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.ContainsAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.Extract(const AValue: Double): Boolean;
|
|
var
|
|
Current, Successor: TJclDoubleBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AValue in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := 0.0;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.ExtractAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.First: IJclDoubleIterator;
|
|
var
|
|
Start: TJclDoubleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderDoubleBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderDoubleBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderDoubleBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclDoubleBinaryTree.GetEnumerator: IJclDoubleIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclDoubleBinaryTree.GetRoot: IJclDoubleTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderDoubleBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderDoubleBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderDoubleBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.Last: IJclDoubleIterator;
|
|
var
|
|
Start: TJclDoubleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderDoubleBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderDoubleBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderDoubleBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclDoubleBinaryNode;
|
|
ANode, BNode: TJclDoubleBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.Remove(const AValue: Double): Boolean;
|
|
var
|
|
Extracted: Double;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AValue);
|
|
if Result then
|
|
begin
|
|
Extracted := AValue;
|
|
FreeDouble(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.RemoveAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.RetainAll(const ACollection: IJclDoubleCollection): Boolean;
|
|
var
|
|
It: IJclDoubleIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclDoubleBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclDoubleBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclDoubleBinaryTreeIterator.Create(const AOwnTree: IJclDoubleCollection; ACursor: TJclDoubleBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclDoubleEqualityComparer;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.Add(const AValue: Double): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AValue);
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.AddChild(const AValue: Double): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclDoubleBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclDoubleBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclDoubleBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclDoubleBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.GetChild(Index: Integer): Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.GetValue: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.IndexOfChild(const AValue: Double): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AValue) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.Insert(const AValue: Double): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.InsertChild(Index: Integer; const AValue: Double): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.IteratorEquals(const AIterator: IJclDoubleIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclDoubleBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclDoubleBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclDoubleBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.Left: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclDoubleBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclDoubleBinaryTreeIterator.Next: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.Parent: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.Previous: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclDoubleBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclDoubleBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclDoubleBinaryTreeIterator.Right: Double;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.SetChild(Index: Integer; const AValue: Double);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclDoubleBinaryTreeIterator.SetValue(const AValue: Double);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderDoubleBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderDoubleBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderDoubleBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderDoubleBinaryTreeIterator.GetNextCursor: TJclDoubleBinaryNode;
|
|
var
|
|
LastRet: TJclDoubleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderDoubleBinaryTreeIterator.GetPreviousCursor: TJclDoubleBinaryNode;
|
|
var
|
|
LastRet: TJclDoubleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderDoubleBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderDoubleBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderDoubleBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderDoubleBinaryTreeIterator.GetNextCursor: TJclDoubleBinaryNode;
|
|
var
|
|
LastRet: TJclDoubleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderDoubleBinaryTreeIterator.GetPreviousCursor: TJclDoubleBinaryNode;
|
|
var
|
|
LastRet: TJclDoubleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderDoubleBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderDoubleBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderDoubleBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderDoubleBinaryTreeIterator.GetNextCursor: TJclDoubleBinaryNode;
|
|
var
|
|
LastRet: TJclDoubleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderDoubleBinaryTreeIterator.GetPreviousCursor: TJclDoubleBinaryNode;
|
|
var
|
|
LastRet: TJclDoubleBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclExtendedBinaryTree } =================================================
|
|
|
|
constructor TJclExtendedBinaryTree.Create(ACompare: TExtendedCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclExtendedBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.Add(const AValue: Extended): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclExtendedBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AValue, 0.0) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclExtendedBinaryNode.Create;
|
|
NewNode.Value := AValue;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.AddAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclExtendedBinaryTree;
|
|
ACollection: IJclExtendedCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclExtendedBinaryTree then
|
|
begin
|
|
ADest := TJclExtendedBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclExtendedCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclExtendedBinaryTree then
|
|
TJclExtendedBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.BuildTree(const LeafArray: array of TJclExtendedBinaryNode; Left, Right: Integer; Parent: TJclExtendedBinaryNode;
|
|
Offset: Integer): TJclExtendedBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclExtendedBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeExtended(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.CloneNode(Node, Parent: TJclExtendedBinaryNode): TJclExtendedBinaryNode;
|
|
begin
|
|
Result := TJclExtendedBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.CollectionEquals(const ACollection: IJclExtendedCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclExtendedIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.Contains(const AValue: Extended): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclExtendedBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AValue);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.ContainsAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.Extract(const AValue: Extended): Boolean;
|
|
var
|
|
Current, Successor: TJclExtendedBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AValue in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := 0.0;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.ExtractAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.First: IJclExtendedIterator;
|
|
var
|
|
Start: TJclExtendedBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderExtendedBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderExtendedBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderExtendedBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclExtendedBinaryTree.GetEnumerator: IJclExtendedIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclExtendedBinaryTree.GetRoot: IJclExtendedTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderExtendedBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderExtendedBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderExtendedBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.Last: IJclExtendedIterator;
|
|
var
|
|
Start: TJclExtendedBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderExtendedBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderExtendedBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderExtendedBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclExtendedBinaryNode;
|
|
ANode, BNode: TJclExtendedBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.Remove(const AValue: Extended): Boolean;
|
|
var
|
|
Extracted: Extended;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AValue);
|
|
if Result then
|
|
begin
|
|
Extracted := AValue;
|
|
FreeExtended(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.RemoveAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.RetainAll(const ACollection: IJclExtendedCollection): Boolean;
|
|
var
|
|
It: IJclExtendedIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclExtendedBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclExtendedBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclExtendedBinaryTreeIterator.Create(const AOwnTree: IJclExtendedCollection; ACursor: TJclExtendedBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclExtendedEqualityComparer;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.Add(const AValue: Extended): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AValue);
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.AddChild(const AValue: Extended): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclExtendedBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclExtendedBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclExtendedBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclExtendedBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.GetChild(Index: Integer): Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.GetValue: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.IndexOfChild(const AValue: Extended): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AValue) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.Insert(const AValue: Extended): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.InsertChild(Index: Integer; const AValue: Extended): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.IteratorEquals(const AIterator: IJclExtendedIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclExtendedBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclExtendedBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclExtendedBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.Left: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclExtendedBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclExtendedBinaryTreeIterator.Next: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.Parent: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.Previous: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclExtendedBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclExtendedBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclExtendedBinaryTreeIterator.Right: Extended;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0.0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.SetChild(Index: Integer; const AValue: Extended);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclExtendedBinaryTreeIterator.SetValue(const AValue: Extended);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderExtendedBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderExtendedBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderExtendedBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderExtendedBinaryTreeIterator.GetNextCursor: TJclExtendedBinaryNode;
|
|
var
|
|
LastRet: TJclExtendedBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderExtendedBinaryTreeIterator.GetPreviousCursor: TJclExtendedBinaryNode;
|
|
var
|
|
LastRet: TJclExtendedBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderExtendedBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderExtendedBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderExtendedBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderExtendedBinaryTreeIterator.GetNextCursor: TJclExtendedBinaryNode;
|
|
var
|
|
LastRet: TJclExtendedBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderExtendedBinaryTreeIterator.GetPreviousCursor: TJclExtendedBinaryNode;
|
|
var
|
|
LastRet: TJclExtendedBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderExtendedBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderExtendedBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderExtendedBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderExtendedBinaryTreeIterator.GetNextCursor: TJclExtendedBinaryNode;
|
|
var
|
|
LastRet: TJclExtendedBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderExtendedBinaryTreeIterator.GetPreviousCursor: TJclExtendedBinaryNode;
|
|
var
|
|
LastRet: TJclExtendedBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclIntegerBinaryTree } =================================================
|
|
|
|
constructor TJclIntegerBinaryTree.Create(ACompare: TIntegerCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclIntegerBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.Add(AValue: Integer): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclIntegerBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AValue, 0) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclIntegerBinaryNode.Create;
|
|
NewNode.Value := AValue;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.AddAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclIntegerBinaryTree;
|
|
ACollection: IJclIntegerCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclIntegerBinaryTree then
|
|
begin
|
|
ADest := TJclIntegerBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclIntegerCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclIntegerBinaryTree then
|
|
TJclIntegerBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.BuildTree(const LeafArray: array of TJclIntegerBinaryNode; Left, Right: Integer; Parent: TJclIntegerBinaryNode;
|
|
Offset: Integer): TJclIntegerBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclIntegerBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeInteger(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.CloneNode(Node, Parent: TJclIntegerBinaryNode): TJclIntegerBinaryNode;
|
|
begin
|
|
Result := TJclIntegerBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.CollectionEquals(const ACollection: IJclIntegerCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclIntegerIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.Contains(AValue: Integer): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclIntegerBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AValue);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.ContainsAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.Extract(AValue: Integer): Boolean;
|
|
var
|
|
Current, Successor: TJclIntegerBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AValue in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := 0;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.ExtractAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.First: IJclIntegerIterator;
|
|
var
|
|
Start: TJclIntegerBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderIntegerBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderIntegerBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderIntegerBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclIntegerBinaryTree.GetEnumerator: IJclIntegerIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclIntegerBinaryTree.GetRoot: IJclIntegerTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderIntegerBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderIntegerBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderIntegerBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.Last: IJclIntegerIterator;
|
|
var
|
|
Start: TJclIntegerBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderIntegerBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderIntegerBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderIntegerBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclIntegerBinaryNode;
|
|
ANode, BNode: TJclIntegerBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.Remove(AValue: Integer): Boolean;
|
|
var
|
|
Extracted: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AValue);
|
|
if Result then
|
|
begin
|
|
Extracted := AValue;
|
|
FreeInteger(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.RemoveAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.RetainAll(const ACollection: IJclIntegerCollection): Boolean;
|
|
var
|
|
It: IJclIntegerIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclIntegerBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclIntegerBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclIntegerBinaryTreeIterator.Create(const AOwnTree: IJclIntegerCollection; ACursor: TJclIntegerBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclIntegerEqualityComparer;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.Add(AValue: Integer): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AValue);
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.AddChild(AValue: Integer): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclIntegerBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclIntegerBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclIntegerBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclIntegerBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.GetChild(Index: Integer): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.GetValue: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.IndexOfChild(AValue: Integer): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AValue) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.Insert(AValue: Integer): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.InsertChild(Index: Integer; AValue: Integer): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.IteratorEquals(const AIterator: IJclIntegerIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclIntegerBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclIntegerBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclIntegerBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.Left: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclIntegerBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclIntegerBinaryTreeIterator.Next: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.Parent: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.Previous: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclIntegerBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclIntegerBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclIntegerBinaryTreeIterator.Right: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.SetChild(Index: Integer; AValue: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclIntegerBinaryTreeIterator.SetValue(AValue: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderIntegerBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderIntegerBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderIntegerBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderIntegerBinaryTreeIterator.GetNextCursor: TJclIntegerBinaryNode;
|
|
var
|
|
LastRet: TJclIntegerBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderIntegerBinaryTreeIterator.GetPreviousCursor: TJclIntegerBinaryNode;
|
|
var
|
|
LastRet: TJclIntegerBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderIntegerBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderIntegerBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderIntegerBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderIntegerBinaryTreeIterator.GetNextCursor: TJclIntegerBinaryNode;
|
|
var
|
|
LastRet: TJclIntegerBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderIntegerBinaryTreeIterator.GetPreviousCursor: TJclIntegerBinaryNode;
|
|
var
|
|
LastRet: TJclIntegerBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderIntegerBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderIntegerBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderIntegerBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderIntegerBinaryTreeIterator.GetNextCursor: TJclIntegerBinaryNode;
|
|
var
|
|
LastRet: TJclIntegerBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderIntegerBinaryTreeIterator.GetPreviousCursor: TJclIntegerBinaryNode;
|
|
var
|
|
LastRet: TJclIntegerBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclCardinalBinaryTree } =================================================
|
|
|
|
constructor TJclCardinalBinaryTree.Create(ACompare: TCardinalCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclCardinalBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.Add(AValue: Cardinal): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclCardinalBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AValue, 0) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclCardinalBinaryNode.Create;
|
|
NewNode.Value := AValue;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.AddAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclCardinalBinaryTree;
|
|
ACollection: IJclCardinalCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclCardinalBinaryTree then
|
|
begin
|
|
ADest := TJclCardinalBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclCardinalCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclCardinalBinaryTree then
|
|
TJclCardinalBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.BuildTree(const LeafArray: array of TJclCardinalBinaryNode; Left, Right: Integer; Parent: TJclCardinalBinaryNode;
|
|
Offset: Integer): TJclCardinalBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclCardinalBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeCardinal(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.CloneNode(Node, Parent: TJclCardinalBinaryNode): TJclCardinalBinaryNode;
|
|
begin
|
|
Result := TJclCardinalBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.CollectionEquals(const ACollection: IJclCardinalCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclCardinalIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.Contains(AValue: Cardinal): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclCardinalBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AValue);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.ContainsAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.Extract(AValue: Cardinal): Boolean;
|
|
var
|
|
Current, Successor: TJclCardinalBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AValue in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := 0;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.ExtractAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.First: IJclCardinalIterator;
|
|
var
|
|
Start: TJclCardinalBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderCardinalBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderCardinalBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderCardinalBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclCardinalBinaryTree.GetEnumerator: IJclCardinalIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclCardinalBinaryTree.GetRoot: IJclCardinalTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderCardinalBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderCardinalBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderCardinalBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.Last: IJclCardinalIterator;
|
|
var
|
|
Start: TJclCardinalBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderCardinalBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderCardinalBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderCardinalBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclCardinalBinaryNode;
|
|
ANode, BNode: TJclCardinalBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.Remove(AValue: Cardinal): Boolean;
|
|
var
|
|
Extracted: Cardinal;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AValue);
|
|
if Result then
|
|
begin
|
|
Extracted := AValue;
|
|
FreeCardinal(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.RemoveAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.RetainAll(const ACollection: IJclCardinalCollection): Boolean;
|
|
var
|
|
It: IJclCardinalIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclCardinalBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclCardinalBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclCardinalBinaryTreeIterator.Create(const AOwnTree: IJclCardinalCollection; ACursor: TJclCardinalBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclCardinalEqualityComparer;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.Add(AValue: Cardinal): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AValue);
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.AddChild(AValue: Cardinal): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclCardinalBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclCardinalBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclCardinalBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclCardinalBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.GetChild(Index: Integer): Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.GetValue: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.IndexOfChild(AValue: Cardinal): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AValue) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.Insert(AValue: Cardinal): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.InsertChild(Index: Integer; AValue: Cardinal): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.IteratorEquals(const AIterator: IJclCardinalIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclCardinalBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclCardinalBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclCardinalBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.Left: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclCardinalBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclCardinalBinaryTreeIterator.Next: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.Parent: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.Previous: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclCardinalBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclCardinalBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclCardinalBinaryTreeIterator.Right: Cardinal;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.SetChild(Index: Integer; AValue: Cardinal);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclCardinalBinaryTreeIterator.SetValue(AValue: Cardinal);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderCardinalBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderCardinalBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderCardinalBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderCardinalBinaryTreeIterator.GetNextCursor: TJclCardinalBinaryNode;
|
|
var
|
|
LastRet: TJclCardinalBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderCardinalBinaryTreeIterator.GetPreviousCursor: TJclCardinalBinaryNode;
|
|
var
|
|
LastRet: TJclCardinalBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderCardinalBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderCardinalBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderCardinalBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderCardinalBinaryTreeIterator.GetNextCursor: TJclCardinalBinaryNode;
|
|
var
|
|
LastRet: TJclCardinalBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderCardinalBinaryTreeIterator.GetPreviousCursor: TJclCardinalBinaryNode;
|
|
var
|
|
LastRet: TJclCardinalBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderCardinalBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderCardinalBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderCardinalBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderCardinalBinaryTreeIterator.GetNextCursor: TJclCardinalBinaryNode;
|
|
var
|
|
LastRet: TJclCardinalBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderCardinalBinaryTreeIterator.GetPreviousCursor: TJclCardinalBinaryNode;
|
|
var
|
|
LastRet: TJclCardinalBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInt64BinaryTree } =================================================
|
|
|
|
constructor TJclInt64BinaryTree.Create(ACompare: TInt64Compare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclInt64BinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.Add(const AValue: Int64): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclInt64BinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AValue, 0) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclInt64BinaryNode.Create;
|
|
NewNode.Value := AValue;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.AddAll(const ACollection: IJclInt64Collection): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclInt64BinaryTree;
|
|
ACollection: IJclInt64Collection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclInt64BinaryTree then
|
|
begin
|
|
ADest := TJclInt64BinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclInt64Collection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclInt64BinaryTree then
|
|
TJclInt64BinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.BuildTree(const LeafArray: array of TJclInt64BinaryNode; Left, Right: Integer; Parent: TJclInt64BinaryNode;
|
|
Offset: Integer): TJclInt64BinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclInt64BinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeInt64(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.CloneNode(Node, Parent: TJclInt64BinaryNode): TJclInt64BinaryNode;
|
|
begin
|
|
Result := TJclInt64BinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.CollectionEquals(const ACollection: IJclInt64Collection): Boolean;
|
|
var
|
|
It, ItSelf: IJclInt64Iterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.Contains(const AValue: Int64): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclInt64BinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AValue);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.ContainsAll(const ACollection: IJclInt64Collection): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.Extract(const AValue: Int64): Boolean;
|
|
var
|
|
Current, Successor: TJclInt64BinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AValue in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AValue, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := 0;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.ExtractAll(const ACollection: IJclInt64Collection): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.First: IJclInt64Iterator;
|
|
var
|
|
Start: TJclInt64BinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderInt64BinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderInt64BinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderInt64BinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclInt64BinaryTree.GetEnumerator: IJclInt64Iterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclInt64BinaryTree.GetRoot: IJclInt64TreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderInt64BinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderInt64BinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderInt64BinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.Last: IJclInt64Iterator;
|
|
var
|
|
Start: TJclInt64BinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderInt64BinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderInt64BinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderInt64BinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclInt64BinaryNode;
|
|
ANode, BNode: TJclInt64BinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.Remove(const AValue: Int64): Boolean;
|
|
var
|
|
Extracted: Int64;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AValue);
|
|
if Result then
|
|
begin
|
|
Extracted := AValue;
|
|
FreeInt64(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.RemoveAll(const ACollection: IJclInt64Collection): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.RetainAll(const ACollection: IJclInt64Collection): Boolean;
|
|
var
|
|
It: IJclInt64Iterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclInt64BinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclInt64BinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclInt64BinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclInt64BinaryTreeIterator.Create(const AOwnTree: IJclInt64Collection; ACursor: TJclInt64BinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclInt64EqualityComparer;
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.Add(const AValue: Int64): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AValue);
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.AddChild(const AValue: Int64): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclInt64BinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclInt64BinaryTreeIterator then
|
|
begin
|
|
ADest := TJclInt64BinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclInt64BinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.GetChild(Index: Integer): Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.GetValue: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.IndexOfChild(const AValue: Int64): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AValue) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AValue) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.Insert(const AValue: Int64): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.InsertChild(Index: Integer; const AValue: Int64): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.IteratorEquals(const AIterator: IJclInt64Iterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclInt64BinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclInt64BinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclInt64BinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.Left: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclInt64BinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclInt64BinaryTreeIterator.Next: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.Parent: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.Previous: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclInt64BinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclInt64BinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclInt64BinaryTreeIterator.Right: Int64;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.SetChild(Index: Integer; const AValue: Int64);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclInt64BinaryTreeIterator.SetValue(const AValue: Int64);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderInt64BinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderInt64BinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderInt64BinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderInt64BinaryTreeIterator.GetNextCursor: TJclInt64BinaryNode;
|
|
var
|
|
LastRet: TJclInt64BinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderInt64BinaryTreeIterator.GetPreviousCursor: TJclInt64BinaryNode;
|
|
var
|
|
LastRet: TJclInt64BinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderInt64BinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderInt64BinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderInt64BinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderInt64BinaryTreeIterator.GetNextCursor: TJclInt64BinaryNode;
|
|
var
|
|
LastRet: TJclInt64BinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderInt64BinaryTreeIterator.GetPreviousCursor: TJclInt64BinaryNode;
|
|
var
|
|
LastRet: TJclInt64BinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderInt64BinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderInt64BinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderInt64BinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderInt64BinaryTreeIterator.GetNextCursor: TJclInt64BinaryNode;
|
|
var
|
|
LastRet: TJclInt64BinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderInt64BinaryTreeIterator.GetPreviousCursor: TJclInt64BinaryNode;
|
|
var
|
|
LastRet: TJclInt64BinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPtrBinaryTree } =================================================
|
|
|
|
constructor TJclPtrBinaryTree.Create(ACompare: TPtrCompare);
|
|
begin
|
|
inherited Create();
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclPtrBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.Add(APtr: Pointer): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclPtrBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(APtr, nil) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(APtr, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclPtrBinaryNode.Create;
|
|
NewNode.Value := APtr;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.AddAll(const ACollection: IJclPtrCollection): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclPtrBinaryTree;
|
|
ACollection: IJclPtrCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclPtrBinaryTree then
|
|
begin
|
|
ADest := TJclPtrBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclPtrCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclPtrBinaryTree then
|
|
TJclPtrBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.BuildTree(const LeafArray: array of TJclPtrBinaryNode; Left, Right: Integer; Parent: TJclPtrBinaryNode;
|
|
Offset: Integer): TJclPtrBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclPtrBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreePointer(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.CloneNode(Node, Parent: TJclPtrBinaryNode): TJclPtrBinaryNode;
|
|
begin
|
|
Result := TJclPtrBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.CollectionEquals(const ACollection: IJclPtrCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclPtrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.Contains(APtr: Pointer): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclPtrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, APtr);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.ContainsAll(const ACollection: IJclPtrCollection): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.Extract(APtr: Pointer): Boolean;
|
|
var
|
|
Current, Successor: TJclPtrBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate APtr in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(APtr, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := nil;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.ExtractAll(const ACollection: IJclPtrCollection): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.First: IJclPtrIterator;
|
|
var
|
|
Start: TJclPtrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderPtrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderPtrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderPtrBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclPtrBinaryTree.GetEnumerator: IJclPtrIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclPtrBinaryTree.GetRoot: IJclPtrTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderPtrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderPtrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderPtrBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.Last: IJclPtrIterator;
|
|
var
|
|
Start: TJclPtrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderPtrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderPtrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderPtrBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclPtrBinaryNode;
|
|
ANode, BNode: TJclPtrBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.Remove(APtr: Pointer): Boolean;
|
|
var
|
|
Extracted: Pointer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(APtr);
|
|
if Result then
|
|
begin
|
|
Extracted := APtr;
|
|
FreePointer(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.RemoveAll(const ACollection: IJclPtrCollection): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.RetainAll(const ACollection: IJclPtrCollection): Boolean;
|
|
var
|
|
It: IJclPtrIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclPtrBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclPtrBinaryTree.Create(Compare);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclPtrBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclPtrBinaryTreeIterator.Create(const AOwnTree: IJclPtrCollection; ACursor: TJclPtrBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclPtrEqualityComparer;
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.Add(APtr: Pointer): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(APtr);
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.AddChild(APtr: Pointer): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclPtrBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclPtrBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclPtrBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclPtrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.GetChild(Index: Integer): Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.GetPointer: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.IndexOfChild(APtr: Pointer): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, APtr) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, APtr) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, APtr) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.Insert(APtr: Pointer): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.InsertChild(Index: Integer; APtr: Pointer): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.IteratorEquals(const AIterator: IJclPtrIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclPtrBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclPtrBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclPtrBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.Left: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclPtrBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclPtrBinaryTreeIterator.Next: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.Parent: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.Previous: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclPtrBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclPtrBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclPtrBinaryTreeIterator.Right: Pointer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.SetChild(Index: Integer; APtr: Pointer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclPtrBinaryTreeIterator.SetPointer(APtr: Pointer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderPtrBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderPtrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderPtrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderPtrBinaryTreeIterator.GetNextCursor: TJclPtrBinaryNode;
|
|
var
|
|
LastRet: TJclPtrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderPtrBinaryTreeIterator.GetPreviousCursor: TJclPtrBinaryNode;
|
|
var
|
|
LastRet: TJclPtrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderPtrBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderPtrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderPtrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderPtrBinaryTreeIterator.GetNextCursor: TJclPtrBinaryNode;
|
|
var
|
|
LastRet: TJclPtrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderPtrBinaryTreeIterator.GetPreviousCursor: TJclPtrBinaryNode;
|
|
var
|
|
LastRet: TJclPtrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderPtrBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderPtrBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderPtrBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderPtrBinaryTreeIterator.GetNextCursor: TJclPtrBinaryNode;
|
|
var
|
|
LastRet: TJclPtrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderPtrBinaryTreeIterator.GetPreviousCursor: TJclPtrBinaryNode;
|
|
var
|
|
LastRet: TJclPtrBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclBinaryTree } =================================================
|
|
|
|
constructor TJclBinaryTree.Create(ACompare: TCompare; AOwnsObjects: Boolean);
|
|
begin
|
|
inherited Create(AOwnsObjects);
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
destructor TJclBinaryTree.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclBinaryTree.Add(AObject: TObject): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclBinaryNode;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AObject, nil) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AObject, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclBinaryNode.Create;
|
|
NewNode.Value := AObject;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.AddAll(const ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTree.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclBinaryTree;
|
|
ACollection: IJclCollection;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclBinaryTree then
|
|
begin
|
|
ADest := TJclBinaryTree(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclCollection, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclBinaryTree then
|
|
TJclBinaryTree(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTree.BuildTree(const LeafArray: array of TJclBinaryNode; Left, Right: Integer; Parent: TJclBinaryNode;
|
|
Offset: Integer): TJclBinaryNode;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.Clear;
|
|
var
|
|
Current, Parent: TJclBinaryNode;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeObject(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.CloneNode(Node, Parent: TJclBinaryNode): TJclBinaryNode;
|
|
begin
|
|
Result := TJclBinaryNode.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclBinaryTree.CollectionEquals(const ACollection: IJclCollection): Boolean;
|
|
var
|
|
It, ItSelf: IJclIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.Contains(AObject: TObject): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AObject);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.ContainsAll(const ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.Extract(AObject: TObject): Boolean;
|
|
var
|
|
Current, Successor: TJclBinaryNode;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AObject in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AObject, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := nil;
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.ExtractAll(const ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.First: IJclIterator;
|
|
var
|
|
Start: TJclBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TJclInOrderBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TJclPostOrderBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclBinaryTree.GetEnumerator: IJclIterator;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclBinaryTree.GetRoot: IJclTreeIterator;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TJclPreOrderBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TJclInOrderBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TJclPostOrderBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclBinaryTree.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclBinaryTree.Last: IJclIterator;
|
|
var
|
|
Start: TJclBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TJclPreOrderBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TJclInOrderBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TJclPostOrderBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTree.Pack;
|
|
var
|
|
LeafArray: array of TJclBinaryNode;
|
|
ANode, BNode: TJclBinaryNode;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.Remove(AObject: TObject): Boolean;
|
|
var
|
|
Extracted: TObject;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AObject);
|
|
if Result then
|
|
begin
|
|
Extracted := AObject;
|
|
FreeObject(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.RemoveAll(const ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree.RetainAll(const ACollection: IJclCollection): Boolean;
|
|
var
|
|
It: IJclIterator;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTree.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTree.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclBinaryTree.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
function TJclBinaryTree.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclBinaryTree.Create(Compare, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclBinaryTreeIterator } ===========================================================
|
|
|
|
constructor TJclBinaryTreeIterator.Create(const AOwnTree: IJclCollection; ACursor: TJclBinaryNode; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclEqualityComparer;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.Add(AObject: TObject): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AObject);
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.AddChild(AObject: TObject): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclBinaryTreeIterator;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclBinaryTreeIterator then
|
|
begin
|
|
ADest := TJclBinaryTreeIterator(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.Extract;
|
|
var
|
|
OldCursor: TJclBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.GetChild(Index: Integer): TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.GetObject: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.IndexOfChild(AObject: TObject): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AObject) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AObject) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AObject) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.Insert(AObject: TObject): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.InsertChild(Index: Integer; AObject: TObject): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.IteratorEquals(const AIterator: IJclIterator): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclBinaryTreeIterator;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclBinaryTreeIterator then
|
|
begin
|
|
ItrObj := TJclBinaryTreeIterator(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.Left: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclBinaryTreeIterator.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclBinaryTreeIterator.Next: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.Parent: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.Previous: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.Remove;
|
|
var
|
|
OldCursor: TJclBinaryNode;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.Reset;
|
|
var
|
|
NewCursor: TJclBinaryNode;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator.Right: TObject;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := nil;
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.SetChild(Index: Integer; AObject: TObject);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator.SetObject(AObject: TObject);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderBinaryTreeIterator } ===================================================
|
|
|
|
function TJclPreOrderBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderBinaryTreeIterator.GetNextCursor: TJclBinaryNode;
|
|
var
|
|
LastRet: TJclBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderBinaryTreeIterator.GetPreviousCursor: TJclBinaryNode;
|
|
var
|
|
LastRet: TJclBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderBinaryTreeIterator } ====================================================
|
|
|
|
function TJclInOrderBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderBinaryTreeIterator.GetNextCursor: TJclBinaryNode;
|
|
var
|
|
LastRet: TJclBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderBinaryTreeIterator.GetPreviousCursor: TJclBinaryNode;
|
|
var
|
|
LastRet: TJclBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderBinaryTreeIterator } ==================================================
|
|
|
|
function TJclPostOrderBinaryTreeIterator.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderBinaryTreeIterator.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderBinaryTreeIterator.GetNextCursor: TJclBinaryNode;
|
|
var
|
|
LastRet: TJclBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderBinaryTreeIterator.GetPreviousCursor: TJclBinaryNode;
|
|
var
|
|
LastRet: TJclBinaryNode;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_GENERICS}
|
|
//=== { TJclBinaryTree<T> } =================================================
|
|
|
|
constructor TJclBinaryTree<T>.Create(AOwnsItems: Boolean);
|
|
begin
|
|
inherited Create(AOwnsItems);
|
|
FTraverseOrder := toOrder;
|
|
FMaxDepth := 0;
|
|
FAutoPackParameter := 2;
|
|
end;
|
|
|
|
destructor TJclBinaryTree<T>.Destroy;
|
|
begin
|
|
FReadOnly := False;
|
|
Clear;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.Add(const AItem: T): Boolean;
|
|
var
|
|
NewNode, Current, Save: TJclBinaryNode<T>;
|
|
Comp, Depth: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// Insert into right place
|
|
if FAllowDefaultElements or not ItemsEqual(AItem, Default(T)) then
|
|
begin
|
|
Save := nil;
|
|
Current := FRoot;
|
|
Comp := 1;
|
|
Depth := 0;
|
|
while Current <> nil do
|
|
begin
|
|
Inc(Depth);
|
|
Save := Current;
|
|
Comp := ItemsCompare(AItem, Current.Value);
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Right
|
|
else
|
|
if CheckDuplicate then
|
|
Current := Current.Left // arbitrary decision
|
|
else
|
|
Break;
|
|
end;
|
|
if (Comp <> 0) or CheckDuplicate then
|
|
begin
|
|
NewNode := TJclBinaryNode<T>.Create;
|
|
NewNode.Value := AItem;
|
|
NewNode.Parent := Save;
|
|
if Save = nil then
|
|
FRoot := NewNode
|
|
else
|
|
if ItemsCompare(NewNode.Value, Save.Value) <= 0 then
|
|
Save.Left := NewNode
|
|
else
|
|
Save.Right := NewNode;
|
|
Inc(FSize);
|
|
Inc(Depth);
|
|
if Depth > FMaxDepth then
|
|
FMaxDepth := Depth;
|
|
Result := True;
|
|
AutoPack;
|
|
end
|
|
else
|
|
Result := False;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.AddAll(const ACollection: IJclCollection<T>): Boolean;
|
|
var
|
|
It: IJclIterator<T>;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Add(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTree<T>.AssignDataTo(Dest: TJclAbstractContainerBase);
|
|
var
|
|
ADest: TJclBinaryTree<T>;
|
|
ACollection: IJclCollection<T>;
|
|
begin
|
|
inherited AssignDataTo(Dest);
|
|
if Dest is TJclBinaryTree<T> then
|
|
begin
|
|
ADest := TJclBinaryTree<T>(Dest);
|
|
ADest.Clear;
|
|
ADest.FSize := FSize;
|
|
if FRoot <> nil then
|
|
ADest.FRoot := CloneNode(FRoot, nil);
|
|
end
|
|
else
|
|
if Supports(IInterface(Dest), IJclCollection<T>, ACollection) then
|
|
begin
|
|
ACollection.Clear;
|
|
ACollection.AddAll(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TJclBinaryTree<T>.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesto(Dest);
|
|
if Dest is TJclBinaryTree<T> then
|
|
TJclBinaryTree<T>(Dest).FTraverseOrder := FTraverseOrder;
|
|
end;
|
|
|
|
procedure TJclBinaryTree<T>.AutoPack;
|
|
begin
|
|
case FAutoPackStrategy of
|
|
//apsDisabled: ;
|
|
apsAgressive:
|
|
if (FMaxDepth > 1) and (((1 shl (FMaxDepth - 1)) - 1) > FSize) then
|
|
Pack;
|
|
// apsIncremental: ;
|
|
apsProportional:
|
|
if (FMaxDepth > FAutoPackParameter) and (((1 shl (FMaxDepth - FAutoPackParameter)) - 1) > FSize) then
|
|
Pack;
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.BuildTree(const LeafArray: array of TJclBinaryNode<T>; Left, Right: Integer; Parent: TJclBinaryNode<T>;
|
|
Offset: Integer): TJclBinaryNode<T>;
|
|
var
|
|
Middle: Integer;
|
|
begin
|
|
Middle := (Left + Right + Offset) shr 1;
|
|
Result := LeafArray[Middle];
|
|
Result.Parent := Parent;
|
|
if Middle > Left then
|
|
Result.Left := BuildTree(LeafArray, Left, Middle - 1, Result, 0)
|
|
else
|
|
Result.Left := nil;
|
|
if Middle < Right then
|
|
Result.Right := BuildTree(LeafArray, Middle + 1, Right, Result, 1)
|
|
else
|
|
Result.Right := nil;
|
|
end;
|
|
|
|
procedure TJclBinaryTree<T>.Clear;
|
|
var
|
|
Current, Parent: TJclBinaryNode<T>;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
// postorder
|
|
Current := FRoot;
|
|
if Current = nil then
|
|
Exit;
|
|
// find first in post-order
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
// for all items in the tree in post-order
|
|
repeat
|
|
Parent := Current.Parent;
|
|
// remove reference
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.Left = Current then
|
|
Parent.Left := nil
|
|
else
|
|
if Parent.Right = Current then
|
|
Parent.Right := nil;
|
|
end;
|
|
|
|
// free item
|
|
FreeItem(Current.Value);
|
|
Current.Free;
|
|
|
|
// find next item
|
|
Current := Parent;
|
|
if (Current <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
Current := Current.Right;
|
|
while (Current.Left <> nil) or (Current.Right <> nil) do
|
|
begin
|
|
if Current.Left <> nil then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
end;
|
|
until Current = nil;
|
|
FRoot := nil;
|
|
FSize := 0;
|
|
FMaxDepth := 0;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.CloneNode(Node, Parent: TJclBinaryNode<T>): TJclBinaryNode<T>;
|
|
begin
|
|
Result := TJclBinaryNode<T>.Create;
|
|
Result.Value := Node.Value;
|
|
Result.Parent := Parent;
|
|
if Node.Left <> nil then
|
|
Result.Left := CloneNode(Node.Left, Result); // recursive call
|
|
if Node.Right <> nil then
|
|
Result.Right := CloneNode(Node.Right, Result); // recursive call
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.CollectionEquals(const ACollection: IJclCollection<T>): Boolean;
|
|
var
|
|
It, ItSelf: IJclIterator<T>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
if FSize <> ACollection.Size then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
ItSelf := First;
|
|
while ItSelf.HasNext do
|
|
if not ItemsEqual(ItSelf.Next, It.Next) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.Contains(const AItem: T): Boolean;
|
|
var
|
|
Comp: Integer;
|
|
Current: TJclBinaryNode<T>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
Current := FRoot;
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(Current.Value, AItem);
|
|
if Comp = 0 then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end
|
|
else
|
|
if Comp > 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.ContainsAll(const ACollection: IJclCollection<T>): Boolean;
|
|
var
|
|
It: IJclIterator<T>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := True;
|
|
if ACollection = nil then
|
|
Exit;
|
|
It := ACollection.First;
|
|
while Result and It.HasNext do
|
|
Result := Contains(It.Next);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.Extract(const AItem: T): Boolean;
|
|
var
|
|
Current, Successor: TJclBinaryNode<T>;
|
|
Comp: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
// locate AItem in the tree
|
|
Current := FRoot;
|
|
repeat
|
|
while Current <> nil do
|
|
begin
|
|
Comp := ItemsCompare(AItem, Current.Value);
|
|
if Comp = 0 then
|
|
Break
|
|
else
|
|
if Comp < 0 then
|
|
Current := Current.Left
|
|
else
|
|
Current := Current.Right;
|
|
end;
|
|
if Current = nil then
|
|
Break;
|
|
Result := True;
|
|
// Remove Current from tree
|
|
if (Current.Left = nil) and (Current.Right <> nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Right.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Right
|
|
else
|
|
Current.Parent.Right := Current.Right;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Right;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right = nil) then
|
|
begin
|
|
// remove references to Current
|
|
Current.Left.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Current.Left
|
|
else
|
|
Current.Parent.Right := Current.Left;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Current.Left;
|
|
Successor := Current.Parent;
|
|
if Successor = nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
if (Current.Left <> nil) and (Current.Right <> nil) then
|
|
begin
|
|
// find the successor in tree
|
|
Successor := Current.Right;
|
|
while Successor.Left <> nil do
|
|
Successor := Successor.Left;
|
|
|
|
if Successor <> Current.Right then
|
|
begin
|
|
// remove references to successor
|
|
Successor.Parent.Left := Successor.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor.Parent;
|
|
Successor.Right := Current.Right;
|
|
if Successor.Right <> nil then
|
|
Successor.Right.Parent := Successor;
|
|
end;
|
|
|
|
// insert successor in new position
|
|
Successor.Left := Current.Left;
|
|
if Current.Left <> nil then
|
|
Current.Left.Parent := Successor;
|
|
Successor.Parent := Current.Parent;
|
|
if Current.Parent <> nil then
|
|
begin
|
|
if Current.Parent.Left = Current then
|
|
Current.Parent.Left := Successor
|
|
else
|
|
Current.Parent.Right := Successor;
|
|
end
|
|
else
|
|
// fix root
|
|
FRoot := Successor;
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
Successor := FRoot;
|
|
end
|
|
else
|
|
begin
|
|
// (Current.Left = nil) and (Current.Right = nil)
|
|
Successor := Current.Parent;
|
|
if Successor <> nil then
|
|
begin
|
|
// remove references from parent
|
|
if Successor.Left = Current then
|
|
Successor.Left := nil
|
|
else
|
|
Successor.Right := nil;
|
|
end
|
|
else
|
|
FRoot := nil;
|
|
end;
|
|
Current.Value := Default(T);
|
|
Current.Free;
|
|
Dec(FSize);
|
|
Current := Successor;
|
|
until FRemoveSingleElement or (Current = nil);
|
|
AutoPack;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.ExtractAll(const ACollection: IJclCollection<T>): Boolean;
|
|
var
|
|
It: IJclIterator<T>;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Extract(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.First: IJclIterator<T>;
|
|
var
|
|
Start: TJclBinaryNode<T>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TPreOrderBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Left <> nil do
|
|
Start := Start.Left;
|
|
Result := TInOrderBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
toPostOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Left <> nil then
|
|
Start := Start.Left
|
|
else
|
|
Start := Start.Right;
|
|
end;
|
|
Result := TPostOrderBinaryTreeIterator.Create(Self, Start, False, isFirst);
|
|
end;
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclBinaryTree<T>.GetEnumerator: IJclIterator<T>;
|
|
begin
|
|
Result := First;
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclBinaryTree<T>.GetRoot: IJclTreeIterator<T>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
case GetTraverseOrder of
|
|
toPreOrder:
|
|
Result := TPreOrderBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toOrder:
|
|
Result := TInOrderBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
toPostOrder:
|
|
Result := TPostOrderBinaryTreeIterator.Create(Self, FRoot, False, isRoot);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.GetTraverseOrder: TJclTraverseOrder;
|
|
begin
|
|
Result := FTraverseOrder;
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.IsEmpty: Boolean;
|
|
begin
|
|
Result := FSize = 0;
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.Last: IJclIterator<T>;
|
|
var
|
|
Start: TJclBinaryNode<T>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginRead;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Start := FRoot;
|
|
case FTraverseOrder of
|
|
toPreOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while (Start.Left <> nil) or (Start.Right <> nil) do
|
|
begin
|
|
if Start.Right <> nil then
|
|
Start := Start.Right
|
|
else
|
|
Start := Start.Left;
|
|
end;
|
|
Result := TPreOrderBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toOrder:
|
|
begin
|
|
if Start <> nil then
|
|
while Start.Right <> nil do
|
|
Start := Start.Right;
|
|
Result := TInOrderBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
end;
|
|
toPostOrder:
|
|
Result := TPostOrderBinaryTreeIterator.Create(Self, Start, False, isLast);
|
|
else
|
|
Result := nil;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndRead;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTree<T>.Pack;
|
|
var
|
|
LeafArray: array of TJclBinaryNode<T>;
|
|
ANode, BNode: TJclBinaryNode<T>;
|
|
Index: Integer;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
SetLength(Leafarray, FSize);
|
|
try
|
|
// in order enumeration of nodes
|
|
ANode := FRoot;
|
|
if ANode <> nil then
|
|
begin
|
|
// find first node
|
|
while ANode.Left <> nil do
|
|
ANode := ANode.Left;
|
|
|
|
Index := 0;
|
|
while ANode <> nil do
|
|
begin
|
|
LeafArray[Index] := ANode;
|
|
Inc(Index);
|
|
if ANode.Right <> nil then
|
|
begin
|
|
ANode := ANode.Right;
|
|
while (ANode.Left <> nil) do
|
|
ANode := ANode.Left;
|
|
end
|
|
else
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
while (ANode <> nil) and (ANode.Right = BNode) do
|
|
begin
|
|
BNode := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Index := FSize shr 1;
|
|
FRoot := LeafArray[Index];
|
|
FRoot.Parent := nil;
|
|
if Index > 0 then
|
|
FRoot.Left := BuildTree(LeafArray, 0, Index - 1, FRoot, 0)
|
|
else
|
|
FRoot.Left := nil;
|
|
if Index < (FSize - 1) then
|
|
FRoot.Right := BuildTree(LeafArray, Index + 1, FSize - 1, FRoot, 1)
|
|
else
|
|
FRoot.Right := nil;
|
|
end;
|
|
finally
|
|
SetLength(LeafArray, 0);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.Remove(const AItem: T): Boolean;
|
|
var
|
|
Extracted: T;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Extract(AItem);
|
|
if Result then
|
|
begin
|
|
Extracted := AItem;
|
|
FreeItem(Extracted);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.RemoveAll(const ACollection: IJclCollection<T>): Boolean;
|
|
var
|
|
It: IJclIterator<T>;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := ACollection.First;
|
|
while It.HasNext do
|
|
Result := Remove(It.Next) and Result;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.RetainAll(const ACollection: IJclCollection<T>): Boolean;
|
|
var
|
|
It: IJclIterator<T>;
|
|
begin
|
|
if ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
if FThreadSafe then
|
|
SyncReaderWriter.BeginWrite;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := False;
|
|
if ACollection = nil then
|
|
Exit;
|
|
Result := True;
|
|
It := First;
|
|
while It.HasNext do
|
|
if not ACollection.Contains(It.Next) then
|
|
It.Remove;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
if FThreadSafe then
|
|
SyncReaderWriter.EndWrite;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTree<T>.SetCapacity(Value: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTree<T>.SetTraverseOrder(Value: TJclTraverseOrder);
|
|
begin
|
|
FTraverseOrder := Value;
|
|
end;
|
|
|
|
function TJclBinaryTree<T>.Size: Integer;
|
|
begin
|
|
Result := FSize;
|
|
end;
|
|
|
|
//=== { TJclBinaryTreeIterator<T> } ===========================================================
|
|
|
|
constructor TJclBinaryTreeIterator<T>.Create(const AOwnTree: IJclCollection<T>; ACursor: TJclBinaryNode<T>; AValid: Boolean; AStart: TItrStart);
|
|
begin
|
|
inherited Create(AValid);
|
|
FCursor := ACursor;
|
|
FStart := AStart;
|
|
FOwnTree := AOwnTree;
|
|
FEqualityComparer := AOwnTree as IJclEqualityComparer<T>;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.Add(const AItem: T): Boolean;
|
|
begin
|
|
Result := FOwnTree.Add(AItem);
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.AddChild(const AItem: T): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.AssignPropertiesTo(Dest: TJclAbstractIterator);
|
|
var
|
|
ADest: TJclBinaryTreeIterator<T>;
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclBinaryTreeIterator<T> then
|
|
begin
|
|
ADest := TJclBinaryTreeIterator<T>(Dest);
|
|
ADest.FCursor := FCursor;
|
|
ADest.FOwnTree := FOwnTree;
|
|
ADest.FEqualityComparer := FEqualityComparer;
|
|
ADest.FStart := FStart;
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.ChildrenCount: Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := 0;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
Inc(Result);
|
|
if FCursor.Right <> nil then
|
|
Inc(Result);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.DeleteChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.DeleteChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.Extract;
|
|
var
|
|
OldCursor: TJclBinaryNode<T>;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Extract(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.ExtractChild(Index: Integer);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.ExtractChildren;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.GetChild(Index: Integer): T;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Default(T);
|
|
if (FCursor <> nil) and (Index = 0) and (FCursor.Left <> nil) then
|
|
FCursor := FCursor.Left
|
|
else
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
FCursor := FCursor.Right
|
|
else
|
|
FCursor := nil;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.GetItem: T;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Result := Default(T);
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.HasChild(Index: Integer): Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if (FCursor <> nil) and (Index = 0) then
|
|
Result := (FCursor.Left <> nil) or (FCursor.Right <> nil)
|
|
else
|
|
if (FCursor <> nil) and (Index = 1) then
|
|
Result := (FCursor.Left <> nil) and (FCursor.Right <> nil)
|
|
else
|
|
Result := False;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.HasLeft: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Left <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.HasNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetNextCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.HasParent: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Parent <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.HasPrevious: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
Result := GetPreviousCursor <> nil
|
|
else
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.HasRight: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := (FCursor <> nil) and (FCursor.Right <> nil);
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.IndexOfChild(const AItem: T): Integer;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := -1;
|
|
if FCursor <> nil then
|
|
begin
|
|
if FCursor.Left <> nil then
|
|
begin
|
|
if FEqualityComparer.ItemsEqual(FCursor.Left.Value, AItem) then
|
|
Result := 0
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AItem) then
|
|
Result := 1;
|
|
end
|
|
else
|
|
if (FCursor.Right <> nil) and FEqualityComparer.ItemsEqual(FCursor.Right.Value, AItem) then
|
|
Result := 0;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.Insert(const AItem: T): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.InsertChild(Index: Integer; const AItem: T): Boolean;
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.IteratorEquals(const AIterator: IJclIterator<T>): Boolean;
|
|
var
|
|
Obj: TObject;
|
|
ItrObj: TJclBinaryTreeIterator<T>;
|
|
begin
|
|
Result := False;
|
|
if AIterator = nil then
|
|
Exit;
|
|
Obj := AIterator.GetIteratorReference;
|
|
if Obj is TJclBinaryTreeIterator<T> then
|
|
begin
|
|
ItrObj := TJclBinaryTreeIterator<T>(Obj);
|
|
Result := (FOwnTree = ItrObj.FOwnTree) and (FCursor = ItrObj.FCursor) and (Valid = ItrObj.Valid);
|
|
end;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.Left: T;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Default(T);
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Left;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
{$IFDEF SUPPORTS_FOR_IN}
|
|
function TJclBinaryTreeIterator<T>.MoveNext: Boolean;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := FCursor <> nil;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
{$ENDIF SUPPORTS_FOR_IN}
|
|
|
|
function TJclBinaryTreeIterator<T>.Next: T;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetNextCursor
|
|
else
|
|
Valid := True;
|
|
Result := Default(T);
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.NextIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.Parent: T;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Default(T);
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Parent;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.Previous: T;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
if Valid then
|
|
FCursor := GetPreviousCursor
|
|
else
|
|
Valid := True;
|
|
Result := Default(T);
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.PreviousIndex: Integer;
|
|
begin
|
|
// No index
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.Remove;
|
|
var
|
|
OldCursor: TJclBinaryNode<T>;
|
|
begin
|
|
if FOwnTree.ReadOnly then
|
|
raise EJclReadOnlyError.Create;
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.WriteLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
CheckValid;
|
|
Valid := False;
|
|
OldCursor := FCursor;
|
|
if OldCursor <> nil then
|
|
begin
|
|
repeat
|
|
FCursor := GetNextCursor;
|
|
until (FCursor = nil) or FOwnTree.RemoveSingleElement
|
|
or (not FEqualityComparer.ItemsEqual(OldCursor.Value, FCursor.Value));
|
|
FOwnTree.Remove(OldCursor.Value);
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.WriteUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.Reset;
|
|
var
|
|
NewCursor: TJclBinaryNode<T>;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Valid := False;
|
|
case FStart of
|
|
isFirst:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetPreviousCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isLast:
|
|
begin
|
|
NewCursor := FCursor;
|
|
while NewCursor <> nil do
|
|
begin
|
|
NewCursor := GetNextCursor;
|
|
if NewCursor <> nil then
|
|
FCursor := NewCursor;
|
|
end;
|
|
end;
|
|
isRoot:
|
|
begin
|
|
while (FCursor <> nil) and (FCursor.Parent <> nil) do
|
|
FCursor := FCursor.Parent;
|
|
end;
|
|
end;
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
function TJclBinaryTreeIterator<T>.Right: T;
|
|
begin
|
|
{$IFDEF THREADSAFE}
|
|
FOwnTree.ReadLock;
|
|
try
|
|
{$ENDIF THREADSAFE}
|
|
Result := Default(T);
|
|
if FCursor <> nil then
|
|
FCursor := FCursor.Right;
|
|
if FCursor <> nil then
|
|
Result := FCursor.Value
|
|
else
|
|
if not FOwnTree.ReturnDefaultElements then
|
|
raise EJclNoSuchElementError.Create('');
|
|
{$IFDEF THREADSAFE}
|
|
finally
|
|
FOwnTree.ReadUnlock;
|
|
end;
|
|
{$ENDIF THREADSAFE}
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.SetChild(Index: Integer; const AItem: T);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeIterator<T>.SetItem(const AItem: T);
|
|
begin
|
|
raise EJclOperationNotSupportedError.Create;
|
|
end;
|
|
|
|
//=== { TJclPreOrderBinaryTreeIterator<T> } ===================================================
|
|
|
|
function TJclPreOrderBinaryTreeIterator<T>.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPreOrderBinaryTreeIterator<T>.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPreOrderBinaryTreeIterator<T>.GetNextCursor: TJclBinaryNode<T>;
|
|
var
|
|
LastRet: TJclBinaryNode<T>;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
begin
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Right = nil) or (Result.Right = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
|
|
function TJclPreOrderBinaryTreeIterator<T>.GetPreviousCursor: TJclBinaryNode<T>;
|
|
var
|
|
LastRet: TJclBinaryNode<T>;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Left <> LastRet) and (Result.Left <> nil) then
|
|
// come from Right
|
|
begin
|
|
Result := Result.Left;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do // both childs
|
|
begin
|
|
if Result.Right <> nil then // right child first
|
|
Result := Result.Right
|
|
else
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclInOrderBinaryTreeIterator<T> } ====================================================
|
|
|
|
function TJclInOrderBinaryTreeIterator<T>.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclInOrderBinaryTreeIterator<T>.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclInOrderBinaryTreeIterator<T>.GetNextCursor: TJclBinaryNode<T>;
|
|
var
|
|
LastRet: TJclBinaryNode<T>;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) do
|
|
Result := Result.Left;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right = LastRet) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclInOrderBinaryTreeIterator<T>.GetPreviousCursor: TJclBinaryNode<T>;
|
|
var
|
|
LastRet: TJclBinaryNode<T>;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Left <> nil then
|
|
begin
|
|
Result := Result.Left;
|
|
while Result.Right <> nil do
|
|
Result := Result.Right;
|
|
end
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and (Result.Right <> LastRet) do // Come from Left
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclPostOrderBinaryTreeIterator<T> } ==================================================
|
|
|
|
function TJclPostOrderBinaryTreeIterator<T>.CreateEmptyIterator: TJclAbstractIterator;
|
|
begin
|
|
Result := TJclPostOrderBinaryTreeIterator<T>.Create(FOwnTree, FCursor, Valid, FStart);
|
|
end;
|
|
|
|
function TJclPostOrderBinaryTreeIterator<T>.GetNextCursor: TJclBinaryNode<T>;
|
|
var
|
|
LastRet: TJclBinaryNode<T>;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
if (Result <> nil) and (Result.Right <> nil) and (Result.Right <> LastRet) then
|
|
begin
|
|
Result := Result.Right;
|
|
while (Result.Left <> nil) or (Result.Right <> nil) do
|
|
begin
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
Result := Result.Right;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJclPostOrderBinaryTreeIterator<T>.GetPreviousCursor: TJclBinaryNode<T>;
|
|
var
|
|
LastRet: TJclBinaryNode<T>;
|
|
begin
|
|
Result := FCursor;
|
|
if Result = nil then
|
|
Exit;
|
|
if Result.Right <> nil then
|
|
Result := Result.Right
|
|
else
|
|
if Result.Left <> nil then
|
|
Result := Result.Left
|
|
else
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
while (Result <> nil) and ((Result.Left = nil) or (Result.Left = LastRet)) do
|
|
begin
|
|
LastRet := Result;
|
|
Result := Result.Parent;
|
|
end;
|
|
if Result <> nil then // not root
|
|
Result := Result.Left;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJclBinaryTreeE<T> } =================================================
|
|
|
|
constructor TJclBinaryTreeE<T>.Create(const AComparer: IJclComparer<T>; AOwnsItems: Boolean);
|
|
begin
|
|
inherited Create(AOwnsItems);
|
|
FComparer := AComparer;
|
|
end;
|
|
|
|
procedure TJclBinaryTreeE<T>.AssignPropertiesTo(Dest: TJclAbstractContainerBase);
|
|
begin
|
|
inherited AssignPropertiesTo(Dest);
|
|
if Dest is TJclBinaryTreeE<T> then
|
|
TJclBinaryTreeE<T>(Dest).FComparer := FComparer;
|
|
end;
|
|
|
|
function TJclBinaryTreeE<T>.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclBinaryTreeE<T>.Create(Comparer, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclBinaryTreeE<T>.ItemsCompare(const A, B: T): Integer;
|
|
begin
|
|
if Comparer <> nil then
|
|
Result := Comparer.Compare(A, B)
|
|
else
|
|
Result := inherited ItemsCompare(A, B);
|
|
end;
|
|
|
|
function TJclBinaryTreeE<T>.ItemsEqual(const A, B: T): Boolean;
|
|
begin
|
|
if Comparer <> nil then
|
|
Result := Comparer.Compare(A, B) = 0
|
|
else
|
|
Result := inherited ItemsEqual(A, B);
|
|
end;
|
|
|
|
//=== { TJclBinaryTreeF<T> } =================================================
|
|
|
|
constructor TJclBinaryTreeF<T>.Create(ACompare: TCompare<T>; AOwnsItems: Boolean);
|
|
begin
|
|
inherited Create(AOwnsItems);
|
|
SetCompare(ACompare);
|
|
end;
|
|
|
|
function TJclBinaryTreeF<T>.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclBinaryTreeF<T>.Create(Compare, False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
//=== { TJclBinaryTreeI<T> } =================================================
|
|
|
|
function TJclBinaryTreeI<T>.CreateEmptyContainer: TJclAbstractContainerBase;
|
|
begin
|
|
Result := TJclBinaryTreeI<T>.Create(False);
|
|
AssignPropertiesTo(Result);
|
|
end;
|
|
|
|
function TJclBinaryTreeI<T>.ItemsCompare(const A, B: T): Integer;
|
|
begin
|
|
if Assigned(FCompare) then
|
|
Result := FCompare(A, B)
|
|
else
|
|
Result := A.CompareTo(B);
|
|
end;
|
|
|
|
function TJclBinaryTreeI<T>.ItemsEqual(const A, B: T): Boolean;
|
|
begin
|
|
if Assigned(FEqualityCompare) then
|
|
Result := FEqualityCompare(A, B)
|
|
else
|
|
if Assigned(FCompare) then
|
|
Result := FCompare(A, B) = 0
|
|
else
|
|
Result := A.CompareTo(B) = 0;
|
|
end;
|
|
|
|
{$ENDIF SUPPORTS_GENERICS}
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|
|
|