mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 15:59:28 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			2156 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			2156 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    This file is part of the Free Component Library (FCL)
 | 
						|
    Copyright (c) 2002 by Florian Klaempfl
 | 
						|
 | 
						|
    See the file COPYING.FPC, included in this distribution,
 | 
						|
    for details about the copyright.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
						|
 | 
						|
 **********************************************************************}
 | 
						|
{$ifdef fpc}
 | 
						|
{$mode objfpc}
 | 
						|
{$endif}
 | 
						|
{$H+}
 | 
						|
{$ifdef CLASSESINLINE}{$inline on}{$endif}
 | 
						|
 | 
						|
unit contnrs;
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
uses
 | 
						|
  SysUtils,Classes;
 | 
						|
 | 
						|
 | 
						|
Type
 | 
						|
  TObjectListCallback = procedure(data:TObject;arg:pointer) of object;
 | 
						|
  TObjectListStaticCallback = procedure(data:TObject;arg:pointer);
 | 
						|
 | 
						|
  TFPObjectList = class(TObject)
 | 
						|
  private
 | 
						|
    FFreeObjects : Boolean;
 | 
						|
    FList: TFPList;
 | 
						|
    function GetCount: integer;
 | 
						|
    procedure SetCount(const AValue: integer);
 | 
						|
  protected
 | 
						|
    function GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
    procedure SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
    procedure SetCapacity(NewCapacity: Integer);
 | 
						|
    function GetCapacity: integer;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    constructor Create(FreeObjects : Boolean);
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Clear;
 | 
						|
    function Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
    procedure Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
    procedure Exchange(Index1, Index2: Integer);
 | 
						|
    function Expand: TFPObjectList;
 | 
						|
    function Extract(Item: TObject): TObject;
 | 
						|
    function Remove(AObject: TObject): Integer;
 | 
						|
    function IndexOf(AObject: TObject): Integer;
 | 
						|
    function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
 | 
						|
    procedure Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
    function First: TObject;
 | 
						|
    function Last: TObject;
 | 
						|
    procedure Move(CurIndex, NewIndex: Integer);
 | 
						|
    procedure Assign(Obj:TFPObjectList);
 | 
						|
    procedure Pack;
 | 
						|
    procedure Sort(Compare: TListSortCompare);
 | 
						|
    procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer);
 | 
						|
    procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
 | 
						|
    property Capacity: Integer read GetCapacity write SetCapacity;
 | 
						|
    property Count: Integer read GetCount write SetCount;
 | 
						|
    property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
 | 
						|
    property Items[Index: Integer]: TObject read GetItem write SetItem; default;
 | 
						|
    property List: TFPList read FList;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
  TObjectList = class(TList)
 | 
						|
  private
 | 
						|
    ffreeobjects : boolean;
 | 
						|
  Protected
 | 
						|
    Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
 | 
						|
    function GetItem(Index: Integer): TObject;
 | 
						|
    Procedure SetItem(Index: Integer; AObject: TObject);
 | 
						|
  public
 | 
						|
    constructor create;
 | 
						|
    constructor create(freeobjects : boolean);
 | 
						|
    function Add(AObject: TObject): Integer;
 | 
						|
    function Extract(Item: TObject): TObject;
 | 
						|
    function Remove(AObject: TObject): Integer;
 | 
						|
    function IndexOf(AObject: TObject): Integer;
 | 
						|
    function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
 | 
						|
    Procedure Insert(Index: Integer; AObject: TObject);
 | 
						|
    function First: TObject;
 | 
						|
    Function Last: TObject;
 | 
						|
    property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
 | 
						|
    property Items[Index: Integer]: TObject read GetItem write SetItem; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  TComponentList = class(TObjectList)
 | 
						|
  Private
 | 
						|
    FNotifier : TComponent;
 | 
						|
  Protected
 | 
						|
    Procedure Notify(Ptr: Pointer; Action: TListNotification); override;
 | 
						|
    Function GetItems(Index: Integer): TComponent;
 | 
						|
    Procedure SetItems(Index: Integer; AComponent: TComponent);
 | 
						|
    Procedure HandleFreeNotify(Sender: TObject; AComponent: TComponent);
 | 
						|
  public
 | 
						|
    destructor Destroy; override;
 | 
						|
    Function Add(AComponent: TComponent): Integer;
 | 
						|
    Function Extract(Item: TComponent): TComponent;
 | 
						|
    Function Remove(AComponent: TComponent): Integer;
 | 
						|
    Function IndexOf(AComponent: TComponent): Integer;
 | 
						|
    Function First: TComponent;
 | 
						|
    Function Last: TComponent;
 | 
						|
    Procedure Insert(Index: Integer; AComponent: TComponent);
 | 
						|
    property Items[Index: Integer]: TComponent read GetItems write SetItems; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  TClassList = class(TList)
 | 
						|
  protected
 | 
						|
    Function GetItems(Index: Integer): TClass;
 | 
						|
    Procedure SetItems(Index: Integer; AClass: TClass);
 | 
						|
  public
 | 
						|
    Function Add(AClass: TClass): Integer;
 | 
						|
    Function Extract(Item: TClass): TClass;
 | 
						|
    Function Remove(AClass: TClass): Integer;
 | 
						|
    Function IndexOf(AClass: TClass): Integer;
 | 
						|
    Function First: TClass;
 | 
						|
    Function Last: TClass;
 | 
						|
    Procedure Insert(Index: Integer; AClass: TClass);
 | 
						|
    property Items[Index: Integer]: TClass read GetItems write SetItems; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  TOrderedList = class(TObject)
 | 
						|
  private
 | 
						|
    FList: TList;
 | 
						|
  protected
 | 
						|
    Procedure PushItem(AItem: Pointer); virtual; abstract;
 | 
						|
    Function PopItem: Pointer; virtual;
 | 
						|
    Function PeekItem: Pointer; virtual;
 | 
						|
    property List: TList read FList;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    Function Count: Integer;
 | 
						|
    Function AtLeast(ACount: Integer): Boolean;
 | 
						|
    Function Push(AItem: Pointer): Pointer;
 | 
						|
    Function Pop: Pointer;
 | 
						|
    Function Peek: Pointer;
 | 
						|
  end;
 | 
						|
 | 
						|
{ TStack class }
 | 
						|
 | 
						|
  TStack = class(TOrderedList)
 | 
						|
  protected
 | 
						|
    Procedure PushItem(AItem: Pointer); override;
 | 
						|
  end;
 | 
						|
 | 
						|
{ TObjectStack class }
 | 
						|
 | 
						|
  TObjectStack = class(TStack)
 | 
						|
  public
 | 
						|
    Function Push(AObject: TObject): TObject;
 | 
						|
    Function Pop: TObject;
 | 
						|
    Function Peek: TObject;
 | 
						|
  end;
 | 
						|
 | 
						|
{ TQueue class }
 | 
						|
 | 
						|
  TQueue = class(TOrderedList)
 | 
						|
  protected
 | 
						|
    Procedure PushItem(AItem: Pointer); override;
 | 
						|
  end;
 | 
						|
 | 
						|
{ TObjectQueue class }
 | 
						|
 | 
						|
  TObjectQueue = class(TQueue)
 | 
						|
  public
 | 
						|
    Function Push(AObject: TObject): TObject;
 | 
						|
    Function Pop: TObject;
 | 
						|
    Function Peek: TObject;
 | 
						|
  end;
 | 
						|
 | 
						|
{ ---------------------------------------------------------------------
 | 
						|
    TPList with Hash support
 | 
						|
  ---------------------------------------------------------------------}
 | 
						|
 | 
						|
type
 | 
						|
  THashItem=record
 | 
						|
    HashValue : LongWord;
 | 
						|
    StrIndex  : Integer;
 | 
						|
    NextIndex : Integer;
 | 
						|
    Data      : Pointer;
 | 
						|
  end;
 | 
						|
  PHashItem=^THashItem;
 | 
						|
 | 
						|
const
 | 
						|
  MaxHashListSize = Maxint div 16;
 | 
						|
  MaxHashStrSize  = Maxint;
 | 
						|
  MaxHashTableSize = Maxint div 4;
 | 
						|
  MaxItemsPerHash = 3;
 | 
						|
 | 
						|
type
 | 
						|
  PHashItemList = ^THashItemList;
 | 
						|
  THashItemList = array[0..MaxHashListSize - 1] of THashItem;
 | 
						|
  PHashTable = ^THashTable;
 | 
						|
  THashTable = array[0..MaxHashTableSize - 1] of Integer;
 | 
						|
 | 
						|
{ TFPHashList class }
 | 
						|
 | 
						|
  TFPHashList = class(TObject)
 | 
						|
  private
 | 
						|
    { ItemList }
 | 
						|
    FHashList     : PHashItemList;
 | 
						|
    FCount,
 | 
						|
    FCapacity : Integer;
 | 
						|
    { Hash }
 | 
						|
    FHashTable    : PHashTable;
 | 
						|
    FHashCapacity : Integer;
 | 
						|
    { Strings }
 | 
						|
    FStrs     : PChar;
 | 
						|
    FStrCount,
 | 
						|
    FStrCapacity : Integer;
 | 
						|
  protected
 | 
						|
    function Get(Index: Integer): Pointer;
 | 
						|
    procedure SetCapacity(NewCapacity: Integer);
 | 
						|
    procedure SetCount(NewCount: Integer);
 | 
						|
    Procedure RaiseIndexError(Index : Integer);
 | 
						|
    function  AddStr(const s:shortstring): Integer;
 | 
						|
    procedure AddToHashTable(Index: Integer);
 | 
						|
    procedure StrExpand(MinIncSize:Integer);
 | 
						|
    procedure SetStrCapacity(NewCapacity: Integer);
 | 
						|
    procedure SetHashCapacity(NewCapacity: Integer);
 | 
						|
    procedure ReHash;
 | 
						|
  public
 | 
						|
    constructor Create;
 | 
						|
    destructor Destroy; override;
 | 
						|
    function Add(const AName:shortstring;Item: Pointer): Integer;
 | 
						|
    procedure Clear;
 | 
						|
    function NameOfIndex(Index: Integer): String;
 | 
						|
    procedure Delete(Index: Integer);
 | 
						|
    class procedure Error(const Msg: string; Data: PtrInt);
 | 
						|
    function Expand: TFPHashList;
 | 
						|
    function Extract(item: Pointer): Pointer;
 | 
						|
    function IndexOf(Item: Pointer): Integer;
 | 
						|
    function Find(const s:shortstring): Pointer;
 | 
						|
    function Remove(Item: Pointer): Integer;
 | 
						|
    procedure Pack;
 | 
						|
    procedure ShowStatistics;
 | 
						|
    procedure ForEachCall(proc2call:TListCallback;arg:pointer);
 | 
						|
    procedure ForEachCall(proc2call:TListStaticCallback;arg:pointer);
 | 
						|
    property Capacity: Integer read FCapacity write SetCapacity;
 | 
						|
    property Count: Integer read FCount write SetCount;
 | 
						|
    property Items[Index: Integer]: Pointer read Get; default;
 | 
						|
    property List: PHashItemList read FHashList;
 | 
						|
    property Strs: PChar read FStrs;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
{ TFPHashObjectList class }
 | 
						|
 | 
						|
  TFPHashObjectList = class;
 | 
						|
 | 
						|
  TFPHashObject = class
 | 
						|
  private
 | 
						|
    FOwner : TFPHashObjectList;
 | 
						|
    FCachedStr : pshortstring;
 | 
						|
    FStrIndex  : Integer;
 | 
						|
  protected
 | 
						|
    function GetName:shortstring;
 | 
						|
  public
 | 
						|
    constructor Create(HashObjectList:TFPHashObjectList;const s:shortstring);
 | 
						|
    property Name:shortstring read GetName;
 | 
						|
  end;
 | 
						|
 | 
						|
  TFPHashObjectList = class(TObject)
 | 
						|
  private
 | 
						|
    FFreeObjects : Boolean;
 | 
						|
    FHashList: TFPHashList;
 | 
						|
    function GetCount: integer;
 | 
						|
    procedure SetCount(const AValue: integer);
 | 
						|
  protected
 | 
						|
    function GetItem(Index: Integer): TObject;
 | 
						|
    procedure SetCapacity(NewCapacity: Integer);
 | 
						|
    function GetCapacity: integer;
 | 
						|
  public
 | 
						|
    constructor Create(FreeObjects : boolean = True);
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure Clear;
 | 
						|
    function Add(const AName:shortstring;AObject: TObject): Integer;
 | 
						|
    function NameOfIndex(Index: Integer): shortstring;
 | 
						|
    procedure Delete(Index: Integer);
 | 
						|
    function Expand: TFPHashObjectList;
 | 
						|
    function Extract(Item: TObject): TObject;
 | 
						|
    function Remove(AObject: TObject): Integer;
 | 
						|
    function IndexOf(AObject: TObject): Integer;
 | 
						|
    function Find(const s:shortstring): TObject;
 | 
						|
    function FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt: Integer): Integer;
 | 
						|
    procedure Pack;
 | 
						|
    procedure ShowStatistics;
 | 
						|
    procedure ForEachCall(proc2call:TObjectListCallback;arg:pointer);
 | 
						|
    procedure ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
 | 
						|
    property Capacity: Integer read GetCapacity write SetCapacity;
 | 
						|
    property Count: Integer read GetCount write SetCount;
 | 
						|
    property OwnsObjects: Boolean read FFreeObjects write FFreeObjects;
 | 
						|
    property Items[Index: Integer]: TObject read GetItem; default;
 | 
						|
    property List: TFPHashList read FHashList;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
{ ---------------------------------------------------------------------
 | 
						|
    Hash support, implemented by Dean Zobec
 | 
						|
  ---------------------------------------------------------------------}
 | 
						|
 | 
						|
 | 
						|
  { Must return a Longword value in the range 0..TableSize,
 | 
						|
   usually via a mod operator;  }
 | 
						|
  THashFunction = function(const S: string; const TableSize: Longword): Longword;
 | 
						|
 | 
						|
       
 | 
						|
  { THTNode }
 | 
						|
 | 
						|
  THTCustomNode = class(TObject)
 | 
						|
  private
 | 
						|
    FKey: string;
 | 
						|
  public
 | 
						|
    constructor CreateWith(const AString: String);
 | 
						|
    function HasKey(const AKey: string): boolean;
 | 
						|
    property Key: string read FKey;
 | 
						|
  end;
 | 
						|
  THTCustomNodeClass = Class of THTCustomNode;
 | 
						|
   
 | 
						|
 | 
						|
  { TFPCustomHashTable }
 | 
						|
 | 
						|
  TFPCustomHashTable = class(TObject)
 | 
						|
  private
 | 
						|
    FHashTable: TFPObjectList;
 | 
						|
    FHashTableSize: Longword;
 | 
						|
    FHashFunction: THashFunction;
 | 
						|
    FCount: Longword;
 | 
						|
    function GetDensity: Longword;
 | 
						|
    function GetNumberOfCollisions: Longword;
 | 
						|
    procedure SetHashTableSize(const Value: Longword);
 | 
						|
    procedure InitializeHashTable;
 | 
						|
    function GetVoidSlots: Longword;
 | 
						|
    function GetLoadFactor: double;
 | 
						|
    function GetAVGChainLen: double;
 | 
						|
    function GetMaxChainLength: Longword;
 | 
						|
    function Chain(const index: Longword):TFPObjectList;
 | 
						|
  protected
 | 
						|
    Function CreateNewNode(const aKey : string) : THTCustomNode; virtual; abstract;
 | 
						|
    Procedure AddNode(ANode : THTCustomNode); virtual; abstract;
 | 
						|
    function ChainLength(const ChainIndex: Longword): Longword; virtual;
 | 
						|
    function FindOrCreateNew(const aKey: string): THTCustomNode; virtual;
 | 
						|
    procedure SetHashFunction(AHashFunction: THashFunction); virtual;
 | 
						|
    Function FindChainForAdd(Const aKey : String) : TFPObjectList;
 | 
						|
  public
 | 
						|
    constructor Create; 
 | 
						|
    constructor CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction); 
 | 
						|
    destructor Destroy; override;
 | 
						|
    procedure ChangeTableSize(const ANewSize: Longword); virtual;
 | 
						|
    procedure Clear; virtual;
 | 
						|
    procedure Delete(const aKey: string); virtual;
 | 
						|
    function Find(const aKey: string): THTCustomNode;
 | 
						|
    function IsEmpty: boolean;
 | 
						|
    property HashFunction: THashFunction read FHashFunction write SetHashFunction;
 | 
						|
    property Count: Longword read FCount;
 | 
						|
    property HashTableSize: Longword read FHashTableSize write SetHashTableSize;
 | 
						|
    property HashTable: TFPObjectList read FHashTable;
 | 
						|
    property VoidSlots: Longword read GetVoidSlots;
 | 
						|
    property LoadFactor: double read GetLoadFactor;
 | 
						|
    property AVGChainLen: double read GetAVGChainLen;
 | 
						|
    property MaxChainLength: Longword read GetMaxChainLength;
 | 
						|
    property NumberOfCollisions: Longword read GetNumberOfCollisions;
 | 
						|
    property Density: Longword read GetDensity;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TFPDataHashTable : Hash table with simple data pointers }
 | 
						|
 | 
						|
  THTDataNode = Class(THTCustomNode)
 | 
						|
  Private
 | 
						|
    FData: pointer;
 | 
						|
  public  
 | 
						|
    property Data: pointer read FData write FData;
 | 
						|
  end;
 | 
						|
  // For compatibility  
 | 
						|
  THTNode = THTDataNode;
 | 
						|
 | 
						|
  TDataIteratorMethod = procedure(Item: Pointer; const Key: string; var Continue: Boolean) of object;
 | 
						|
  // For compatibility
 | 
						|
  TIteratorMethod = TDataIteratorMethod;   
 | 
						|
     
 | 
						|
  TFPDataHashTable = Class(TFPCustomHashTable)
 | 
						|
  Protected
 | 
						|
    Function CreateNewNode(const aKey : String) : THTCustomNode; override;
 | 
						|
    Procedure AddNode(ANode : THTCustomNode); override;
 | 
						|
    procedure SetData(const index: string; const AValue: Pointer); virtual;
 | 
						|
    function GetData(const index: string):Pointer; virtual;
 | 
						|
    function ForEachCall(aMethod: TDataIteratorMethod): THTDataNode; virtual;
 | 
						|
  Public
 | 
						|
    procedure Add(const aKey: string; AItem: pointer); virtual;
 | 
						|
    property Items[const index: string]: Pointer read GetData write SetData; default;
 | 
						|
  end;
 | 
						|
 | 
						|
  { TFPStringHashTable : Hash table with simple strings as data }
 | 
						|
  THTStringNode = Class(THTCustomNode)
 | 
						|
  Private
 | 
						|
    FData : String;
 | 
						|
  public  
 | 
						|
    property Data: String read FData write FData;
 | 
						|
  end;
 | 
						|
  TStringIteratorMethod = procedure(Item: String; const Key: string; var Continue: Boolean) of object;
 | 
						|
 | 
						|
  TFPStringHashTable = Class(TFPCustomHashTable)
 | 
						|
  Protected
 | 
						|
    Function CreateNewNode(const aKey : String) : THTCustomNode; override;
 | 
						|
    Procedure AddNode(ANode : THTCustomNode); override;
 | 
						|
    procedure SetData(const Index, AValue: string); virtual;
 | 
						|
    function GetData(const index: string): String; virtual;
 | 
						|
    function ForEachCall(aMethod: TStringIteratorMethod): THTStringNode; virtual;
 | 
						|
  Public
 | 
						|
    procedure Add(const aKey,aItem: string); virtual;
 | 
						|
    property Items[const index: string]: String read GetData write SetData; default;
 | 
						|
  end;
 | 
						|
  
 | 
						|
  { TFPStringHashTable : Hash table with simple strings as data }
 | 
						|
 | 
						|
  
 | 
						|
  THTObjectNode = Class(THTCustomNode)
 | 
						|
  Private
 | 
						|
    FData : TObject;
 | 
						|
  public
 | 
						|
    property Data: TObject read FData write FData;
 | 
						|
  end;
 | 
						|
 | 
						|
  THTOwnedObjectNode = Class(THTObjectNode)
 | 
						|
  public
 | 
						|
    Destructor Destroy; override;
 | 
						|
  end;
 | 
						|
  TObjectIteratorMethod = procedure(Item: TObject; const Key: string; var Continue: Boolean) of object;
 | 
						|
 | 
						|
  TFPObjectHashTable = Class(TFPCustomHashTable)
 | 
						|
  Private
 | 
						|
    FOwnsObjects : Boolean;
 | 
						|
  Protected
 | 
						|
    Function CreateNewNode(const aKey : String) : THTCustomNode; override;
 | 
						|
    Procedure AddNode(ANode : THTCustomNode); override;
 | 
						|
    procedure SetData(const Index: string; AObject : TObject); virtual;
 | 
						|
    function GetData(const index: string): TObject; virtual;
 | 
						|
    function ForEachCall(aMethod: TObjectIteratorMethod): THTObjectNode; virtual;
 | 
						|
  Public
 | 
						|
    constructor Create(AOwnsObjects : Boolean = True); 
 | 
						|
    constructor CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction; AOwnsObjects : Boolean = True); 
 | 
						|
    procedure Add(const aKey: string; AItem : TObject); virtual;
 | 
						|
    property Items[const index: string]: TObject read GetData write SetData; default;
 | 
						|
    Property OwnsObjects : Boolean Read FOwnsObjects Write FOwnsObjects;
 | 
						|
  end;
 | 
						|
 | 
						|
 | 
						|
  EDuplicate = class(Exception);
 | 
						|
  EKeyNotFound = class(Exception);
 | 
						|
 | 
						|
 | 
						|
  function RSHash(const S: string; const TableSize: Longword): Longword;
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
uses
 | 
						|
  RtlConsts;
 | 
						|
 | 
						|
ResourceString
 | 
						|
  DuplicateMsg = 'An item with key %0:s already exists';
 | 
						|
  KeyNotFoundMsg = 'Method: %0:s key [''%1:s''] not found in container';
 | 
						|
  NotEmptyMsg = 'Hash table not empty.';
 | 
						|
 | 
						|
const
 | 
						|
  NPRIMES = 28;
 | 
						|
 | 
						|
  PRIMELIST: array[0 .. NPRIMES-1] of Longword =
 | 
						|
  ( 53,         97,         193,       389,       769,
 | 
						|
    1543,       3079,       6151,      12289,     24593,
 | 
						|
    49157,      98317,      196613,    393241,    786433,
 | 
						|
    1572869,    3145739,    6291469,   12582917,  25165843,
 | 
						|
    50331653,   100663319,  201326611, 402653189, 805306457,
 | 
						|
    1610612741, 3221225473, 4294967291 );
 | 
						|
 | 
						|
constructor TFPObjectList.Create(FreeObjects : boolean);
 | 
						|
begin
 | 
						|
  Create;
 | 
						|
  FFreeObjects := Freeobjects;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TFPObjectList.Destroy;
 | 
						|
begin
 | 
						|
  if (FList <> nil) then
 | 
						|
  begin
 | 
						|
    Clear;
 | 
						|
    FList.Destroy;
 | 
						|
  end;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Clear;
 | 
						|
var
 | 
						|
  i: integer;
 | 
						|
begin
 | 
						|
  if FFreeObjects then
 | 
						|
    for i := 0 to FList.Count - 1 do
 | 
						|
      TObject(FList[i]).Free;
 | 
						|
  FList.Clear;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TFPObjectList.Create;
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FList := TFPList.Create;
 | 
						|
  FFreeObjects := True;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.GetCount: integer;
 | 
						|
begin
 | 
						|
  Result := FList.Count;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.SetCount(const AValue: integer);
 | 
						|
begin
 | 
						|
  if FList.Count <> AValue then
 | 
						|
    FList.Count := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.GetItem(Index: Integer): TObject; {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
begin
 | 
						|
  Result := TObject(FList[Index]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.SetItem(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
begin
 | 
						|
  if OwnsObjects then
 | 
						|
    TObject(FList[Index]).Free;
 | 
						|
  FList[index] := AObject;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.SetCapacity(NewCapacity: Integer);
 | 
						|
begin
 | 
						|
  FList.Capacity := NewCapacity;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.GetCapacity: integer;
 | 
						|
begin
 | 
						|
  Result := FList.Capacity;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.Add(AObject: TObject): Integer; {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
begin
 | 
						|
  Result := FList.Add(AObject);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Delete(Index: Integer); {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
begin
 | 
						|
  if OwnsObjects then
 | 
						|
    TObject(FList[Index]).Free;
 | 
						|
  FList.Delete(Index);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Exchange(Index1, Index2: Integer);
 | 
						|
begin
 | 
						|
  FList.Exchange(Index1, Index2);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.Expand: TFPObjectList;
 | 
						|
begin
 | 
						|
  FList.Expand;
 | 
						|
  Result := Self;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.Extract(Item: TObject): TObject;
 | 
						|
begin
 | 
						|
  Result := TObject(FList.Extract(Item));
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.Remove(AObject: TObject): Integer;
 | 
						|
begin
 | 
						|
  Result := IndexOf(AObject);
 | 
						|
  if (Result <> -1) then
 | 
						|
  begin
 | 
						|
    if OwnsObjects then
 | 
						|
      TObject(FList[Result]).Free;
 | 
						|
    FList.Delete(Result);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.IndexOf(AObject: TObject): Integer;
 | 
						|
begin
 | 
						|
  Result := FList.IndexOf(Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
 | 
						|
var
 | 
						|
  I : Integer;
 | 
						|
begin
 | 
						|
  I:=AStartAt;
 | 
						|
  Result:=-1;
 | 
						|
  If AExact then
 | 
						|
    while (I<Count) and (Result=-1) do
 | 
						|
      If Items[i].ClassType=AClass then
 | 
						|
        Result:=I
 | 
						|
      else
 | 
						|
        Inc(I)
 | 
						|
  else
 | 
						|
    while (I<Count) and (Result=-1) do
 | 
						|
      If Items[i].InheritsFrom(AClass) then
 | 
						|
        Result:=I
 | 
						|
      else
 | 
						|
        Inc(I);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Insert(Index: Integer; AObject: TObject); {$ifdef CLASSESINLINE}inline;{$endif}
 | 
						|
begin
 | 
						|
  FList.Insert(Index, Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Move(CurIndex, NewIndex: Integer);
 | 
						|
begin
 | 
						|
  FList.Move(CurIndex, NewIndex);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Assign(Obj: TFPObjectList);
 | 
						|
var
 | 
						|
  i: Integer;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  for I := 0 to Obj.Count - 1 do
 | 
						|
    Add(Obj[i]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Pack;
 | 
						|
begin
 | 
						|
  FList.Pack;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.Sort(Compare: TListSortCompare);
 | 
						|
begin
 | 
						|
  FList.Sort(Compare);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.First: TObject;
 | 
						|
begin
 | 
						|
  Result := TObject(FList.First);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectList.Last: TObject;
 | 
						|
begin
 | 
						|
  Result := TObject(FList.Last);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
 | 
						|
begin
 | 
						|
  FList.ForEachCall(TListCallBack(proc2call),arg);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
 | 
						|
begin
 | 
						|
  FList.ForEachCall(TListStaticCallBack(proc2call),arg);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{ TObjectList }
 | 
						|
 | 
						|
constructor tobjectlist.create(freeobjects : boolean);
 | 
						|
 | 
						|
begin
 | 
						|
  inherited create;
 | 
						|
  ffreeobjects:=freeobjects;
 | 
						|
end;
 | 
						|
 | 
						|
Constructor tobjectlist.create;
 | 
						|
 | 
						|
begin
 | 
						|
  inherited create;
 | 
						|
  ffreeobjects:=True;
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
 | 
						|
 | 
						|
begin
 | 
						|
  if FFreeObjects then
 | 
						|
    if (Action=lnDeleted) then
 | 
						|
      TObject(Ptr).Free;
 | 
						|
  inherited Notify(Ptr,Action);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
Function TObjectList.GetItem(Index: Integer): TObject;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=TObject(Inherited Get(Index));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
Procedure TObjectList.SetItem(Index: Integer; AObject: TObject);
 | 
						|
 | 
						|
Var
 | 
						|
  O : TObject;
 | 
						|
 | 
						|
begin
 | 
						|
  if OwnsObjects then
 | 
						|
    begin
 | 
						|
    O:=GetItem(Index);
 | 
						|
    O.Free;
 | 
						|
    end;
 | 
						|
  Put(Index,Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
Function TObjectList.Add(AObject: TObject): Integer;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=Inherited Add(Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
Function TObjectList.Extract(Item: TObject): TObject;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=Tobject(Inherited Extract(Pointer(Item)));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
Function TObjectList.Remove(AObject: TObject): Integer;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=Inherited Remove(Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
Function TObjectList.IndexOf(AObject: TObject): Integer;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=Inherited indexOF(Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
Function TObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
 | 
						|
 | 
						|
Var
 | 
						|
  I : Integer;
 | 
						|
 | 
						|
begin
 | 
						|
  I:=AStartAt;
 | 
						|
  Result:=-1;
 | 
						|
  If AExact then
 | 
						|
    While (I<Count) and (Result=-1) do
 | 
						|
      If Items[i].ClassType=AClass then
 | 
						|
        Result:=I
 | 
						|
      else
 | 
						|
        Inc(I)
 | 
						|
  else
 | 
						|
    While (I<Count) and (Result=-1) do
 | 
						|
      If Items[i].InheritsFrom(AClass) then
 | 
						|
        Result:=I
 | 
						|
      else
 | 
						|
        Inc(I);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TObjectList.Insert(Index: Integer; AObject: TObject);
 | 
						|
begin
 | 
						|
  Inherited Insert(Index,Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TObjectList.First: TObject;
 | 
						|
 | 
						|
begin
 | 
						|
  Result := TObject(Inherited First);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TObjectList.Last: TObject;
 | 
						|
 | 
						|
begin
 | 
						|
  Result := TObject(Inherited Last);
 | 
						|
end;
 | 
						|
 | 
						|
{ TListComponent }
 | 
						|
 | 
						|
Type
 | 
						|
  TlistComponent = Class(TComponent)
 | 
						|
  Private
 | 
						|
    Flist : TComponentList;
 | 
						|
  Public
 | 
						|
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
 | 
						|
  end;
 | 
						|
 | 
						|
procedure TlistComponent.Notification(AComponent: TComponent;
 | 
						|
  Operation: TOperation);
 | 
						|
begin
 | 
						|
  If (Operation=opremove) then
 | 
						|
    Flist.HandleFreeNotify(Self,AComponent);
 | 
						|
  inherited;
 | 
						|
end;
 | 
						|
 | 
						|
{ TComponentList }
 | 
						|
 | 
						|
Function TComponentList.Add(AComponent: TComponent): Integer;
 | 
						|
begin
 | 
						|
  Result:=Inherited Add(AComponent);
 | 
						|
end;
 | 
						|
 | 
						|
destructor TComponentList.Destroy;
 | 
						|
begin
 | 
						|
  inherited;
 | 
						|
  FreeAndNil(FNotifier);
 | 
						|
end;
 | 
						|
 | 
						|
Function TComponentList.Extract(Item: TComponent): TComponent;
 | 
						|
begin
 | 
						|
  Result:=TComponent(Inherited Extract(Item));
 | 
						|
end;
 | 
						|
 | 
						|
Function TComponentList.First: TComponent;
 | 
						|
begin
 | 
						|
  Result:=TComponent(Inherited First);
 | 
						|
end;
 | 
						|
 | 
						|
Function TComponentList.GetItems(Index: Integer): TComponent;
 | 
						|
begin
 | 
						|
  Result:=TComponent(Inherited Items[Index]);
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TComponentList.HandleFreeNotify(Sender: TObject;
 | 
						|
  AComponent: TComponent);
 | 
						|
begin
 | 
						|
  Extract(Acomponent);
 | 
						|
end;
 | 
						|
 | 
						|
Function TComponentList.IndexOf(AComponent: TComponent): Integer;
 | 
						|
begin
 | 
						|
  Result:=Inherited IndexOf(AComponent);
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TComponentList.Insert(Index: Integer; AComponent: TComponent);
 | 
						|
begin
 | 
						|
  Inherited Insert(Index,Acomponent)
 | 
						|
end;
 | 
						|
 | 
						|
Function TComponentList.Last: TComponent;
 | 
						|
begin
 | 
						|
  Result:=TComponent(Inherited Last);
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TComponentList.Notify(Ptr: Pointer; Action: TListNotification);
 | 
						|
begin
 | 
						|
  If FNotifier=NIl then
 | 
						|
    begin
 | 
						|
    FNotifier:=TlistComponent.Create(nil);
 | 
						|
    TlistComponent(FNotifier).FList:=Self;
 | 
						|
    end;
 | 
						|
  If Assigned(Ptr) then
 | 
						|
    With TComponent(Ptr) do
 | 
						|
      case Action of
 | 
						|
        lnAdded : FreeNotification(FNotifier);
 | 
						|
        lnExtracted, lnDeleted: RemoveFreeNotification(FNotifier);
 | 
						|
      end;
 | 
						|
  inherited Notify(Ptr, Action);
 | 
						|
end;
 | 
						|
 | 
						|
Function TComponentList.Remove(AComponent: TComponent): Integer;
 | 
						|
begin
 | 
						|
  Result:=Inherited Remove(AComponent);
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TComponentList.SetItems(Index: Integer; AComponent: TComponent);
 | 
						|
begin
 | 
						|
  Put(Index,AComponent);
 | 
						|
end;
 | 
						|
 | 
						|
{ TClassList }
 | 
						|
 | 
						|
Function TClassList.Add(AClass: TClass): Integer;
 | 
						|
begin
 | 
						|
  Result:=Inherited Add(Pointer(AClass));
 | 
						|
end;
 | 
						|
 | 
						|
Function TClassList.Extract(Item: TClass): TClass;
 | 
						|
begin
 | 
						|
  Result:=TClass(Inherited Extract(Pointer(Item)));
 | 
						|
end;
 | 
						|
 | 
						|
Function TClassList.First: TClass;
 | 
						|
begin
 | 
						|
  Result:=TClass(Inherited First);
 | 
						|
end;
 | 
						|
 | 
						|
Function TClassList.GetItems(Index: Integer): TClass;
 | 
						|
begin
 | 
						|
  Result:=TClass(Inherited Items[Index]);
 | 
						|
end;
 | 
						|
 | 
						|
Function TClassList.IndexOf(AClass: TClass): Integer;
 | 
						|
begin
 | 
						|
  Result:=Inherited IndexOf(Pointer(AClass));
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TClassList.Insert(Index: Integer; AClass: TClass);
 | 
						|
begin
 | 
						|
  Inherited Insert(index,Pointer(AClass));
 | 
						|
end;
 | 
						|
 | 
						|
Function TClassList.Last: TClass;
 | 
						|
begin
 | 
						|
  Result:=TClass(Inherited Last);
 | 
						|
end;
 | 
						|
 | 
						|
Function TClassList.Remove(AClass: TClass): Integer;
 | 
						|
begin
 | 
						|
  Result:=Inherited Remove(Pointer(AClass));
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TClassList.SetItems(Index: Integer; AClass: TClass);
 | 
						|
begin
 | 
						|
  Put(Index,Pointer(Aclass));
 | 
						|
end;
 | 
						|
 | 
						|
{ TOrderedList }
 | 
						|
 | 
						|
Function TOrderedList.AtLeast(ACount: Integer): Boolean;
 | 
						|
begin
 | 
						|
  Result:=(FList.Count>=Acount)
 | 
						|
end;
 | 
						|
 | 
						|
Function TOrderedList.Count: Integer;
 | 
						|
begin
 | 
						|
  Result:=FList.Count;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TOrderedList.Create;
 | 
						|
begin
 | 
						|
  FList:=Tlist.Create;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TOrderedList.Destroy;
 | 
						|
begin
 | 
						|
  FList.Free;
 | 
						|
end;
 | 
						|
 | 
						|
Function TOrderedList.Peek: Pointer;
 | 
						|
begin
 | 
						|
  If AtLeast(1) then
 | 
						|
    Result:=PeekItem
 | 
						|
  else
 | 
						|
    Result:=Nil;
 | 
						|
end;
 | 
						|
 | 
						|
Function TOrderedList.PeekItem: Pointer;
 | 
						|
begin
 | 
						|
  With Flist do
 | 
						|
    Result:=Items[Count-1]
 | 
						|
end;
 | 
						|
 | 
						|
Function TOrderedList.Pop: Pointer;
 | 
						|
begin
 | 
						|
  If Atleast(1) then
 | 
						|
    Result:=PopItem
 | 
						|
  else
 | 
						|
    Result:=Nil;
 | 
						|
end;
 | 
						|
 | 
						|
Function TOrderedList.PopItem: Pointer;
 | 
						|
begin
 | 
						|
  With FList do
 | 
						|
    If Count>0 then
 | 
						|
      begin
 | 
						|
      Result:=Items[Count-1];
 | 
						|
      Delete(Count-1);
 | 
						|
      end
 | 
						|
    else
 | 
						|
      Result:=Nil;
 | 
						|
end;
 | 
						|
 | 
						|
Function TOrderedList.Push(AItem: Pointer): Pointer;
 | 
						|
begin
 | 
						|
  PushItem(Aitem);
 | 
						|
  Result:=AItem;
 | 
						|
end;
 | 
						|
 | 
						|
{ TStack }
 | 
						|
 | 
						|
Procedure TStack.PushItem(AItem: Pointer);
 | 
						|
begin
 | 
						|
  FList.Add(Aitem);
 | 
						|
end;
 | 
						|
 | 
						|
{ TObjectStack }
 | 
						|
 | 
						|
Function TObjectStack.Peek: TObject;
 | 
						|
begin
 | 
						|
  Result:=TObject(Inherited Peek);
 | 
						|
end;
 | 
						|
 | 
						|
Function TObjectStack.Pop: TObject;
 | 
						|
begin
 | 
						|
  Result:=TObject(Inherited Pop);
 | 
						|
end;
 | 
						|
 | 
						|
Function TObjectStack.Push(AObject: TObject): TObject;
 | 
						|
begin
 | 
						|
  Result:=TObject(Inherited Push(Pointer(AObject)));
 | 
						|
end;
 | 
						|
 | 
						|
{ TQueue }
 | 
						|
 | 
						|
Procedure TQueue.PushItem(AItem: Pointer);
 | 
						|
begin
 | 
						|
  With Flist Do
 | 
						|
    Insert(0,AItem);
 | 
						|
end;
 | 
						|
 | 
						|
{ TObjectQueue }
 | 
						|
 | 
						|
Function TObjectQueue.Peek: TObject;
 | 
						|
begin
 | 
						|
  Result:=TObject(Inherited Peek);
 | 
						|
end;
 | 
						|
 | 
						|
Function TObjectQueue.Pop: TObject;
 | 
						|
begin
 | 
						|
  Result:=TObject(Inherited Pop);
 | 
						|
end;
 | 
						|
 | 
						|
Function TObjectQueue.Push(AObject: TObject): TObject;
 | 
						|
begin
 | 
						|
  Result:=TObject(Inherited Push(Pointer(Aobject)));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                            TFPHashList
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
    function FPHash1(const s:string):LongWord;
 | 
						|
      Var
 | 
						|
        g : LongWord;
 | 
						|
        p,pmax : pchar;
 | 
						|
      begin
 | 
						|
        result:=0;
 | 
						|
        p:=@s[1];
 | 
						|
        pmax:=@s[length(s)+1];
 | 
						|
        while (p<pmax) do
 | 
						|
          begin
 | 
						|
            result:=result shl 4 + LongWord(p^);
 | 
						|
            g:=result and LongWord($F0000000);
 | 
						|
            if g<>0 then
 | 
						|
              result:=result xor (g shr 24) xor g;
 | 
						|
            inc(p);
 | 
						|
          end;
 | 
						|
        If result=0 then
 | 
						|
          result:=$ffffffff;
 | 
						|
      end;
 | 
						|
 | 
						|
    function FPHash(const s:string):LongWord;
 | 
						|
      Var
 | 
						|
        p,pmax : pchar;
 | 
						|
      begin
 | 
						|
{$ifopt Q+}
 | 
						|
{$define overflowon}
 | 
						|
{$Q-}
 | 
						|
{$endif}
 | 
						|
        result:=0;
 | 
						|
        p:=@s[1];
 | 
						|
        pmax:=@s[length(s)+1];
 | 
						|
        while (p<pmax) do
 | 
						|
          begin
 | 
						|
            result:=LongWord((result shl 5) - result) xor LongWord(P^);
 | 
						|
            inc(p);
 | 
						|
          end;
 | 
						|
{$ifdef overflowon}
 | 
						|
{$Q+}
 | 
						|
{$undef overflowon}
 | 
						|
{$endif}
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.RaiseIndexError(Index : Integer);
 | 
						|
begin
 | 
						|
  Error(SListIndexError, Index);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashList.Get(Index: Integer): Pointer;
 | 
						|
begin
 | 
						|
  If (Index < 0) or (Index >= FCount) then
 | 
						|
    RaiseIndexError(Index);
 | 
						|
  Result:=FHashList^[Index].Data;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashList.NameOfIndex(Index: Integer): String;
 | 
						|
begin
 | 
						|
  If (Index < 0) or (Index >= FCount) then
 | 
						|
    RaiseIndexError(Index);
 | 
						|
  with FHashList^[Index] do
 | 
						|
    begin
 | 
						|
      if StrIndex>=0 then
 | 
						|
        Result:=PShortString(@FStrs[StrIndex])^
 | 
						|
      else
 | 
						|
        Result:='';
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashList.Extract(item: Pointer): Pointer;
 | 
						|
var
 | 
						|
  i : Integer;
 | 
						|
begin
 | 
						|
  result := nil;
 | 
						|
  i := IndexOf(item);
 | 
						|
  if i >= 0 then
 | 
						|
   begin
 | 
						|
     Result := item;
 | 
						|
     Delete(i);
 | 
						|
   end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.SetCapacity(NewCapacity: Integer);
 | 
						|
begin
 | 
						|
  If (NewCapacity < FCount) or (NewCapacity > MaxHashListSize) then
 | 
						|
     Error (SListCapacityError, NewCapacity);
 | 
						|
  if NewCapacity = FCapacity then
 | 
						|
    exit;
 | 
						|
  ReallocMem(FHashList, NewCapacity*SizeOf(THashItem));
 | 
						|
  FCapacity := NewCapacity;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.SetCount(NewCount: Integer);
 | 
						|
begin
 | 
						|
  if (NewCount < 0) or (NewCount > MaxHashListSize)then
 | 
						|
    Error(SListCountError, NewCount);
 | 
						|
  If NewCount > FCount then
 | 
						|
    begin
 | 
						|
      If NewCount > FCapacity then
 | 
						|
        SetCapacity(NewCount);
 | 
						|
      If FCount < NewCount then
 | 
						|
        FillChar(FHashList^[FCount], (NewCount-FCount) div Sizeof(THashItem), 0);
 | 
						|
    end;
 | 
						|
  FCount := Newcount;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.SetStrCapacity(NewCapacity: Integer);
 | 
						|
begin
 | 
						|
  If (NewCapacity < FStrCount) or (NewCapacity > MaxHashStrSize) then
 | 
						|
     Error (SListCapacityError, NewCapacity);
 | 
						|
  if NewCapacity = FStrCapacity then
 | 
						|
    exit;
 | 
						|
  ReallocMem(FStrs, NewCapacity);
 | 
						|
  FStrCapacity := NewCapacity;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.SetHashCapacity(NewCapacity: Integer);
 | 
						|
begin
 | 
						|
  If (NewCapacity < 1) then
 | 
						|
    Error (SListCapacityError, NewCapacity);
 | 
						|
  if FHashCapacity=NewCapacity then
 | 
						|
    exit;
 | 
						|
  FHashCapacity:=NewCapacity;
 | 
						|
  ReallocMem(FHashTable, FHashCapacity*sizeof(Integer));
 | 
						|
  ReHash;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.ReHash;
 | 
						|
var
 | 
						|
  i : Integer;
 | 
						|
begin
 | 
						|
  FillDword(FHashTable^,FHashCapacity,LongWord(-1));
 | 
						|
  For i:=0 To FCount-1 Do
 | 
						|
    AddToHashTable(i);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
constructor TFPHashList.Create;
 | 
						|
begin
 | 
						|
  SetHashCapacity(1);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
destructor TFPHashList.Destroy;
 | 
						|
begin
 | 
						|
  Clear;
 | 
						|
  if assigned(FHashTable) then
 | 
						|
    FreeMem(FHashTable);
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashList.AddStr(const s:shortstring): Integer;
 | 
						|
var
 | 
						|
  Len : Integer;
 | 
						|
begin
 | 
						|
  len:=length(s)+1;
 | 
						|
  if FStrCount+Len >= FStrCapacity then
 | 
						|
    StrExpand(Len);
 | 
						|
  System.Move(s[0],FStrs[FStrCount],Len);
 | 
						|
  result:=FStrCount;
 | 
						|
  inc(FStrCount,Len);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.AddToHashTable(Index: Integer);
 | 
						|
var
 | 
						|
  HashIndex : Integer;
 | 
						|
begin
 | 
						|
  with FHashList^[Index] do
 | 
						|
    begin
 | 
						|
      if not assigned(Data) then
 | 
						|
        exit;
 | 
						|
      HashIndex:=HashValue mod LongWord(FHashCapacity);
 | 
						|
      NextIndex:=FHashTable^[HashIndex];
 | 
						|
      FHashTable^[HashIndex]:=Index;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashList.Add(const AName:shortstring;Item: Pointer): Integer;
 | 
						|
begin
 | 
						|
  if FCount = FCapacity then
 | 
						|
    Expand;
 | 
						|
  with FHashList^[FCount] do
 | 
						|
    begin
 | 
						|
      HashValue:=FPHash(AName);
 | 
						|
      Data:=Item;
 | 
						|
      StrIndex:=AddStr(AName);
 | 
						|
    end;
 | 
						|
  AddToHashTable(FCount);
 | 
						|
  Result := FCount;
 | 
						|
  inc(FCount);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashList.Clear;
 | 
						|
begin
 | 
						|
  if Assigned(FHashList) then
 | 
						|
    begin
 | 
						|
      FCount:=0;
 | 
						|
      SetCapacity(0);
 | 
						|
      FHashList := nil;
 | 
						|
    end;
 | 
						|
  SetHashCapacity(1);
 | 
						|
  if Assigned(FStrs) then
 | 
						|
    begin
 | 
						|
      FStrCount:=0;
 | 
						|
      SetStrCapacity(0);
 | 
						|
      FStrs := nil;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashList.Delete(Index: Integer);
 | 
						|
begin
 | 
						|
  If (Index<0) or (Index>=FCount) then
 | 
						|
    Error (SListIndexError, Index);
 | 
						|
  with FHashList^[Index] do
 | 
						|
    begin
 | 
						|
      Data:=nil;
 | 
						|
      StrIndex:=-1;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
class procedure TFPHashList.Error(const Msg: string; Data: PtrInt);
 | 
						|
begin
 | 
						|
  Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashList.Expand: TFPHashList;
 | 
						|
var
 | 
						|
  IncSize : Longint;
 | 
						|
begin
 | 
						|
  Result := Self;
 | 
						|
  if FCount < FCapacity then
 | 
						|
    exit;
 | 
						|
  IncSize := 4;
 | 
						|
  if FCapacity > 127 then
 | 
						|
    Inc(IncSize, FCapacity shr 2)
 | 
						|
  else if FCapacity > 8 then
 | 
						|
    inc(IncSize,8)
 | 
						|
  else if FCapacity > 3 then
 | 
						|
    inc(IncSize,4);
 | 
						|
  SetCapacity(FCapacity + IncSize);
 | 
						|
  { Maybe expand hash also }
 | 
						|
  if FCount>FHashCapacity*MaxItemsPerHash then
 | 
						|
    SetHashCapacity(FCount div MaxItemsPerHash);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashList.StrExpand(MinIncSize:Integer);
 | 
						|
var
 | 
						|
  IncSize : Longint;
 | 
						|
begin
 | 
						|
  if FStrCount+MinIncSize < FStrCapacity then
 | 
						|
    exit;
 | 
						|
  IncSize := 64+MinIncSize;
 | 
						|
  if FStrCapacity > 255 then
 | 
						|
    Inc(IncSize, FStrCapacity shr 2);
 | 
						|
  SetStrCapacity(FStrCapacity + IncSize);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashList.IndexOf(Item: Pointer): Integer;
 | 
						|
begin
 | 
						|
  Result := 0;
 | 
						|
  while(Result < FCount) and (FHashList^[Result].Data <> Item) do
 | 
						|
    inc(Result);
 | 
						|
  If Result = FCount then
 | 
						|
    Result := -1;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashList.Find(const s:shortstring): Pointer;
 | 
						|
var
 | 
						|
  CurrHash : LongWord;
 | 
						|
  Index,
 | 
						|
  HashIndex : Integer;
 | 
						|
  Len,
 | 
						|
  LastChar  : Char;
 | 
						|
begin
 | 
						|
  CurrHash:=FPHash(s);
 | 
						|
  HashIndex:=CurrHash mod LongWord(FHashCapacity);
 | 
						|
  Index:=FHashTable^[HashIndex];
 | 
						|
  Len:=Char(Length(s));
 | 
						|
  LastChar:=s[Byte(Len)];
 | 
						|
  while Index<>-1 do
 | 
						|
    begin
 | 
						|
      with FHashList^[Index] do
 | 
						|
        begin
 | 
						|
          if assigned(Data) and
 | 
						|
             (HashValue=CurrHash) and
 | 
						|
             (Len=FStrs[StrIndex]) and
 | 
						|
             (LastChar=FStrs[StrIndex+Byte(Len)]) and
 | 
						|
             (s=PShortString(@FStrs[StrIndex])^) then
 | 
						|
            begin
 | 
						|
              Result:=Data;
 | 
						|
              exit;
 | 
						|
            end;
 | 
						|
          Index:=NextIndex;
 | 
						|
        end;
 | 
						|
    end;
 | 
						|
  Result:=nil;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashList.Remove(Item: Pointer): Integer;
 | 
						|
begin
 | 
						|
  Result := IndexOf(Item);
 | 
						|
  If Result <> -1 then
 | 
						|
    Self.Delete(Result);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashList.Pack;
 | 
						|
var
 | 
						|
  NewCount,
 | 
						|
  i : integer;
 | 
						|
  pdest,
 | 
						|
  psrc : PHashItem;
 | 
						|
begin
 | 
						|
  NewCount:=0;
 | 
						|
  psrc:=FHashList[0];
 | 
						|
  pdest:=psrc;
 | 
						|
  For I:=0 To FCount-1 Do
 | 
						|
    begin
 | 
						|
      if assigned(psrc^.Data) then
 | 
						|
        begin
 | 
						|
          pdest^:=psrc^;
 | 
						|
          inc(pdest);
 | 
						|
          inc(NewCount);
 | 
						|
        end;
 | 
						|
      inc(psrc);
 | 
						|
    end;
 | 
						|
  FCount:=NewCount;
 | 
						|
  { We need to ReHash to update the IndexNext }
 | 
						|
  ReHash;
 | 
						|
  { Release over-capacity }
 | 
						|
  SetCapacity(FCount);
 | 
						|
  SetStrCapacity(FStrCount);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.ShowStatistics;
 | 
						|
var
 | 
						|
  HashMean,
 | 
						|
  HashStdDev : Double;
 | 
						|
  Index,
 | 
						|
  i,j : Integer;
 | 
						|
begin
 | 
						|
  { Calculate Mean and StdDev }
 | 
						|
  HashMean:=0;
 | 
						|
  HashStdDev:=0;
 | 
						|
  for i:=0 to FHashCapacity-1 do
 | 
						|
    begin
 | 
						|
      j:=0;
 | 
						|
      Index:=FHashTable^[i];
 | 
						|
      while (Index<>-1) do
 | 
						|
        begin
 | 
						|
          inc(j);
 | 
						|
          Index:=FHashList^[Index].NextIndex;
 | 
						|
        end;
 | 
						|
      HashMean:=HashMean+j;
 | 
						|
      HashStdDev:=HashStdDev+Sqr(j);
 | 
						|
    end;
 | 
						|
  HashMean:=HashMean/FHashCapacity;
 | 
						|
  HashStdDev:=(HashStdDev-FHashCapacity*Sqr(HashMean));
 | 
						|
  If FHashCapacity>1 then
 | 
						|
    HashStdDev:=Sqrt(HashStdDev/(FHashCapacity-1))
 | 
						|
  else
 | 
						|
    HashStdDev:=0;
 | 
						|
  { Print info to stdout }
 | 
						|
  Writeln('HashSize   : ',FHashCapacity);
 | 
						|
  Writeln('HashMean   : ',HashMean:1:4);
 | 
						|
  Writeln('HashStdDev : ',HashStdDev:1:4);
 | 
						|
  Writeln('ListSize   : ',FCount,'/',FCapacity);
 | 
						|
  Writeln('StringSize : ',FStrCount,'/',FStrCapacity);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.ForEachCall(proc2call:TListCallback;arg:pointer);
 | 
						|
var
 | 
						|
  i : integer;
 | 
						|
  p : pointer;
 | 
						|
begin
 | 
						|
  For I:=0 To Count-1 Do
 | 
						|
    begin
 | 
						|
      p:=FHashList^[i].Data;
 | 
						|
      if assigned(p) then
 | 
						|
        proc2call(p,arg);
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
 | 
						|
var
 | 
						|
  i : integer;
 | 
						|
  p : pointer;
 | 
						|
begin
 | 
						|
  For I:=0 To Count-1 Do
 | 
						|
    begin
 | 
						|
      p:=FHashList^[i].Data;
 | 
						|
      if assigned(p) then
 | 
						|
        proc2call(p,arg);
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                               TFPHashObject
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
constructor TFPHashObject.Create(HashObjectList:TFPHashObjectList;const s:shortstring);
 | 
						|
var
 | 
						|
  Index : Integer;
 | 
						|
begin
 | 
						|
  FOwner:=HashObjectList;
 | 
						|
  Index:=HashObjectList.Add(s,Self);
 | 
						|
  FStrIndex:=HashObjectList.List.List^[Index].StrIndex;
 | 
						|
  FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashObject.GetName:shortstring;
 | 
						|
begin
 | 
						|
  FCachedStr:=PShortString(@FOwner.List.Strs[FStrIndex]);
 | 
						|
  Result:=FCachedStr^;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
            TFPHashObjectList (Copied from rtl/objpas/classes/lists.inc)
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
constructor TFPHashObjectList.Create(FreeObjects : boolean = True);
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FHashList := TFPHashList.Create;
 | 
						|
  FFreeObjects := Freeobjects;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TFPHashObjectList.Destroy;
 | 
						|
begin
 | 
						|
  if (FHashList <> nil) then
 | 
						|
  begin
 | 
						|
    Clear;
 | 
						|
    FHashList.Destroy;
 | 
						|
  end;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashObjectList.Clear;
 | 
						|
var
 | 
						|
  i: integer;
 | 
						|
begin
 | 
						|
  if FFreeObjects then
 | 
						|
    for i := 0 to FHashList.Count - 1 do
 | 
						|
      TObject(FHashList[i]).Free;
 | 
						|
  FHashList.Clear;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.GetCount: integer;
 | 
						|
begin
 | 
						|
  Result := FHashList.Count;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashObjectList.SetCount(const AValue: integer);
 | 
						|
begin
 | 
						|
  if FHashList.Count <> AValue then
 | 
						|
    FHashList.Count := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.GetItem(Index: Integer): TObject;
 | 
						|
begin
 | 
						|
  Result := TObject(FHashList[Index]);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashObjectList.SetCapacity(NewCapacity: Integer);
 | 
						|
begin
 | 
						|
  FHashList.Capacity := NewCapacity;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.GetCapacity: integer;
 | 
						|
begin
 | 
						|
  Result := FHashList.Capacity;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.Add(const AName:shortstring;AObject: TObject): Integer;
 | 
						|
begin
 | 
						|
  Result := FHashList.Add(AName,AObject);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.NameOfIndex(Index: Integer): shortString;
 | 
						|
begin
 | 
						|
  Result := FHashList.NameOfIndex(Index);
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPHashObjectList.Delete(Index: Integer);
 | 
						|
begin
 | 
						|
  if OwnsObjects then
 | 
						|
    TObject(FHashList[Index]).Free;
 | 
						|
  FHashList.Delete(Index);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.Expand: TFPHashObjectList;
 | 
						|
begin
 | 
						|
  FHashList.Expand;
 | 
						|
  Result := Self;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.Extract(Item: TObject): TObject;
 | 
						|
begin
 | 
						|
  Result := TObject(FHashList.Extract(Item));
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.Remove(AObject: TObject): Integer;
 | 
						|
begin
 | 
						|
  Result := IndexOf(AObject);
 | 
						|
  if (Result <> -1) then
 | 
						|
  begin
 | 
						|
    if OwnsObjects then
 | 
						|
      TObject(FHashList[Result]).Free;
 | 
						|
    FHashList.Delete(Result);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPHashObjectList.IndexOf(AObject: TObject): Integer;
 | 
						|
begin
 | 
						|
  Result := FHashList.IndexOf(Pointer(AObject));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashObjectList.Find(const s:shortstring): TObject;
 | 
						|
begin
 | 
						|
  result:=TObject(FHashList.Find(s));
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPHashObjectList.FindInstanceOf(AClass: TClass; AExact: Boolean; AStartAt : Integer): Integer;
 | 
						|
var
 | 
						|
  I : Integer;
 | 
						|
begin
 | 
						|
  I:=AStartAt;
 | 
						|
  Result:=-1;
 | 
						|
  If AExact then
 | 
						|
    while (I<Count) and (Result=-1) do
 | 
						|
      If Items[i].ClassType=AClass then
 | 
						|
        Result:=I
 | 
						|
      else
 | 
						|
        Inc(I)
 | 
						|
  else
 | 
						|
    while (I<Count) and (Result=-1) do
 | 
						|
      If Items[i].InheritsFrom(AClass) then
 | 
						|
        Result:=I
 | 
						|
      else
 | 
						|
        Inc(I);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashObjectList.Pack;
 | 
						|
begin
 | 
						|
  FHashList.Pack;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashObjectList.ShowStatistics;
 | 
						|
begin
 | 
						|
  FHashList.ShowStatistics;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListCallback;arg:pointer);
 | 
						|
begin
 | 
						|
  FHashList.ForEachCall(TListCallBack(proc2call),arg);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPHashObjectList.ForEachCall(proc2call:TObjectListStaticCallback;arg:pointer);
 | 
						|
begin
 | 
						|
  FHashList.ForEachCall(TListStaticCallBack(proc2call),arg);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{ ---------------------------------------------------------------------
 | 
						|
    Hash support, by Dean Zobec
 | 
						|
  ---------------------------------------------------------------------}
 | 
						|
 | 
						|
{ Default hash function }
 | 
						|
 | 
						|
function RSHash(const S: string; const TableSize: Longword): Longword;
 | 
						|
const
 | 
						|
  b = 378551;
 | 
						|
var
 | 
						|
  a: Longword;
 | 
						|
  i: Longword;
 | 
						|
begin
 | 
						|
 a := 63689;
 | 
						|
 Result := 0;
 | 
						|
 if length(s)>0 then
 | 
						|
   for i := 1 to Length(S) do
 | 
						|
   begin
 | 
						|
     Result := Result * a + Ord(S[i]);
 | 
						|
     a := a * b;
 | 
						|
   end;
 | 
						|
 Result := (Result and $7FFFFFFF) mod TableSize;
 | 
						|
end;
 | 
						|
 | 
						|
{ THTNode }
 | 
						|
 | 
						|
constructor THTCustomNode.CreateWith(const AString: string);
 | 
						|
begin
 | 
						|
  inherited Create;
 | 
						|
  FKey := AString;
 | 
						|
end;
 | 
						|
 | 
						|
function THTCustomNode.HasKey(const AKey: string): boolean;
 | 
						|
begin
 | 
						|
  if Length(AKey) <> Length(FKey) then
 | 
						|
  begin
 | 
						|
    Result := false;
 | 
						|
    exit;
 | 
						|
  end
 | 
						|
  else
 | 
						|
    Result := CompareMem(PChar(FKey), PChar(AKey), length(AKey));
 | 
						|
end;
 | 
						|
 | 
						|
{ TFPCustomHashTable }
 | 
						|
 | 
						|
constructor TFPCustomHashTable.Create;
 | 
						|
begin
 | 
						|
  CreateWith(196613,@RSHash);
 | 
						|
end;
 | 
						|
 | 
						|
constructor TFPCustomHashTable.CreateWith(AHashTableSize: Longword;
 | 
						|
  aHashFunc: THashFunction);
 | 
						|
begin
 | 
						|
  Inherited Create;
 | 
						|
  FHashTable := TFPObjectList.Create(True);
 | 
						|
  HashTableSize := AHashTableSize;
 | 
						|
  FHashFunction := aHashFunc;
 | 
						|
end;
 | 
						|
 | 
						|
destructor TFPCustomHashTable.Destroy;
 | 
						|
begin
 | 
						|
  FHashTable.Free;
 | 
						|
  inherited Destroy;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.GetDensity: Longword;
 | 
						|
begin
 | 
						|
  Result := FHashTableSize - VoidSlots
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.GetNumberOfCollisions: Longword;
 | 
						|
begin
 | 
						|
  Result := FCount -(FHashTableSize - VoidSlots)
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPCustomHashTable.SetHashTableSize(const Value: Longword);
 | 
						|
var
 | 
						|
  i: Longword;
 | 
						|
  newSize: Longword;
 | 
						|
begin
 | 
						|
  if Value <> FHashTableSize then
 | 
						|
  begin
 | 
						|
    i := 0;
 | 
						|
    while (PRIMELIST[i] < Value) and (i < 27) do
 | 
						|
     inc(i);
 | 
						|
    newSize := PRIMELIST[i];
 | 
						|
    if Count = 0 then
 | 
						|
    begin
 | 
						|
      FHashTableSize := newSize;
 | 
						|
      InitializeHashTable;
 | 
						|
    end
 | 
						|
    else
 | 
						|
      ChangeTableSize(newSize);
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPCustomHashTable.InitializeHashTable;
 | 
						|
var
 | 
						|
  i: LongWord;
 | 
						|
begin
 | 
						|
  if FHashTableSize>0 Then
 | 
						|
    for i := 0 to FHashTableSize-1 do
 | 
						|
     FHashTable.Add(nil);
 | 
						|
  FCount := 0;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPCustomHashTable.ChangeTableSize(const ANewSize: Longword);
 | 
						|
var
 | 
						|
  SavedTable: TFPObjectList;
 | 
						|
  SavedTableSize: Longword;
 | 
						|
  i, j: Longword;
 | 
						|
  temp: THTCustomNode;
 | 
						|
begin
 | 
						|
  SavedTable := FHashTable;
 | 
						|
  SavedTableSize := FHashTableSize;
 | 
						|
  FHashTableSize := ANewSize;
 | 
						|
  FHashTable := TFPObjectList.Create(True);
 | 
						|
  InitializeHashTable;
 | 
						|
  If SavedTableSize>0 Then
 | 
						|
    for i := 0 to SavedTableSize-1 do
 | 
						|
    begin
 | 
						|
      if Assigned(SavedTable[i]) then
 | 
						|
      for j := 0 to TFPObjectList(SavedTable[i]).Count -1 do
 | 
						|
      begin
 | 
						|
        temp := THTCustomNode(TFPObjectList(SavedTable[i])[j]);
 | 
						|
        AddNode(temp);
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
  SavedTable.Free;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPCustomHashTable.SetHashFunction(AHashFunction: THashFunction);
 | 
						|
begin
 | 
						|
  if IsEmpty then
 | 
						|
    FHashFunction := AHashFunction
 | 
						|
  else
 | 
						|
    raise Exception.Create(NotEmptyMsg);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.Find(const aKey: string): THTCustomNode;
 | 
						|
var
 | 
						|
  hashCode: Longword;
 | 
						|
  chn: TFPObjectList;
 | 
						|
  i: Longword;
 | 
						|
begin
 | 
						|
  hashCode := FHashFunction(aKey, FHashTableSize);
 | 
						|
  chn := Chain(hashCode);
 | 
						|
  if Assigned(chn) then
 | 
						|
  begin
 | 
						|
    if chn.count>0 then
 | 
						|
     for i := 0 to chn.Count - 1 do
 | 
						|
      if THTCustomNode(chn[i]).HasKey(aKey) then
 | 
						|
      begin
 | 
						|
        result := THTCustomNode(chn[i]);
 | 
						|
        exit;
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
  Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
Function TFPCustomHashTable.FindChainForAdd(Const aKey : String) : TFPObjectList;
 | 
						|
 | 
						|
var
 | 
						|
  hashCode: Longword;
 | 
						|
  i: Longword;
 | 
						|
 | 
						|
begin
 | 
						|
  hashCode := FHashFunction(aKey, FHashTableSize);
 | 
						|
  Result := Chain(hashCode);
 | 
						|
  if Assigned(Result)  then
 | 
						|
    begin
 | 
						|
    if Result.count>0 then
 | 
						|
      for i := 0 to Result.Count - 1 do
 | 
						|
        if THTCustomNode(Result[i]).HasKey(aKey) then
 | 
						|
          Raise EDuplicate.CreateFmt(DuplicateMsg, [aKey]);
 | 
						|
    end
 | 
						|
  else
 | 
						|
    begin
 | 
						|
    FHashTable[hashcode] := TFPObjectList.Create(true);
 | 
						|
    Result := Chain(hashcode);
 | 
						|
    end;
 | 
						|
  inc(FCount);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TFPCustomHashTable.Delete(const aKey: string);
 | 
						|
var
 | 
						|
  hashCode: Longword;
 | 
						|
  chn: TFPObjectList;
 | 
						|
  i: Longword;
 | 
						|
begin
 | 
						|
  hashCode := FHashFunction(aKey, FHashTableSize);
 | 
						|
  chn := Chain(hashCode);
 | 
						|
  if Assigned(chn) then
 | 
						|
  begin
 | 
						|
    if chn.count>0 then
 | 
						|
    for i := 0 to chn.Count - 1 do
 | 
						|
      if THTCustomNode(chn[i]).HasKey(aKey) then
 | 
						|
      begin
 | 
						|
        chn.Delete(i);
 | 
						|
        dec(FCount);
 | 
						|
        exit;
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
  raise EKeyNotFound.CreateFmt(KeyNotFoundMsg, ['Delete', aKey]);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.IsEmpty: boolean;
 | 
						|
begin
 | 
						|
  Result := (FCount = 0);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.Chain(const index: Longword): TFPObjectList;
 | 
						|
begin
 | 
						|
  Result := TFPObjectList(FHashTable[index]);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.GetVoidSlots: Longword;
 | 
						|
var
 | 
						|
  i: Longword;
 | 
						|
  num: Longword;
 | 
						|
begin
 | 
						|
  num := 0;
 | 
						|
  if FHashTableSize>0 Then
 | 
						|
    for i:= 0 to FHashTableSize-1 do
 | 
						|
      if Not Assigned(Chain(i)) then
 | 
						|
        inc(num);
 | 
						|
  result := num;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.GetLoadFactor: double;
 | 
						|
begin
 | 
						|
  Result := Count / FHashTableSize;
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.GetAVGChainLen: double;
 | 
						|
begin
 | 
						|
  result := Count / (FHashTableSize - VoidSlots);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.GetMaxChainLength: Longword;
 | 
						|
var
 | 
						|
  i: Longword;
 | 
						|
begin
 | 
						|
  Result := 0;
 | 
						|
  if FHashTableSize>0 Then
 | 
						|
   for i := 0 to FHashTableSize-1 do
 | 
						|
      if ChainLength(i) > Result then
 | 
						|
        Result := ChainLength(i);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.FindOrCreateNew(const aKey: string): THTCustomNode;
 | 
						|
var
 | 
						|
  hashCode: Longword;
 | 
						|
  chn: TFPObjectList;
 | 
						|
  i: Longword;
 | 
						|
begin
 | 
						|
  hashCode := FHashFunction(aKey, FHashTableSize);
 | 
						|
  chn := Chain(hashCode);
 | 
						|
  if Assigned(chn)  then
 | 
						|
  begin
 | 
						|
    if chn.count>0 then
 | 
						|
     for i := 0 to chn.Count - 1 do
 | 
						|
      if THTCustomNode(chn[i]).HasKey(aKey) then
 | 
						|
        begin
 | 
						|
          Result := THTNode(chn[i]);
 | 
						|
          exit;
 | 
						|
        end
 | 
						|
  end
 | 
						|
  else
 | 
						|
    begin
 | 
						|
      FHashTable[hashcode] := TFPObjectList.Create(true);
 | 
						|
      chn := Chain(hashcode);
 | 
						|
    end;
 | 
						|
  inc(FCount);
 | 
						|
  Result := CreateNewNode(aKey);
 | 
						|
  chn.Add(Result);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPCustomHashTable.ChainLength(const ChainIndex: Longword): Longword;
 | 
						|
begin
 | 
						|
  if Assigned(Chain(ChainIndex)) then
 | 
						|
    Result := Chain(ChainIndex).Count
 | 
						|
  else
 | 
						|
    Result := 0;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPCustomHashTable.Clear;
 | 
						|
var
 | 
						|
  i: Longword;
 | 
						|
begin
 | 
						|
  if FHashTableSize>0 Then
 | 
						|
    for i := 0 to FHashTableSize - 1 do
 | 
						|
      begin
 | 
						|
        if Assigned(Chain(i)) then
 | 
						|
          Chain(i).Clear;
 | 
						|
      end;
 | 
						|
  FCount := 0;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
{ TFPDataHashTable }
 | 
						|
 | 
						|
procedure TFPDataHashTable.Add(const aKey: string; aItem: pointer);
 | 
						|
var
 | 
						|
  chn: TFPObjectList;
 | 
						|
  NewNode: THtDataNode;
 | 
						|
begin
 | 
						|
  chn:=FindChainForAdd(akey);
 | 
						|
  NewNode := THtDataNode(CreateNewNode(aKey));
 | 
						|
  NewNode.Data := aItem;
 | 
						|
  chn.Add(NewNode);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDataHashTable.GetData(const Index: string): Pointer;
 | 
						|
var
 | 
						|
  node: THTDataNode;
 | 
						|
begin
 | 
						|
  node := THTDataNode(Find(Index));
 | 
						|
  if Assigned(node) then
 | 
						|
    Result := node.Data
 | 
						|
  else
 | 
						|
    Result := nil;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPDataHashTable.SetData(const index: string; const AValue: Pointer);
 | 
						|
begin
 | 
						|
  THTDataNode(FindOrCreateNew(index)).Data := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
Function TFPDataHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=THTDataNode.CreateWith(aKey);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPDataHashTable.ForEachCall(aMethod: TDataIteratorMethod): THTDataNode;
 | 
						|
var
 | 
						|
  i, j: Longword;
 | 
						|
  continue: boolean;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  continue := true;
 | 
						|
  if FHashTableSize>0 then
 | 
						|
   for i := 0 to FHashTableSize-1 do
 | 
						|
    begin
 | 
						|
      if assigned(Chain(i)) then
 | 
						|
      begin
 | 
						|
       if chain(i).count>0 then
 | 
						|
        for j := 0 to Chain(i).Count-1 do
 | 
						|
        begin
 | 
						|
          aMethod(THTDataNode(Chain(i)[j]).Data, THTDataNode(Chain(i)[j]).Key, continue);
 | 
						|
          if not continue then
 | 
						|
          begin
 | 
						|
            Result := THTDataNode(Chain(i)[j]);
 | 
						|
            Exit;
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
Procedure TFPDataHashTable.AddNode(ANode : THTCustomNode);
 | 
						|
 | 
						|
begin
 | 
						|
  With THTDataNode(ANode) do
 | 
						|
    Add(Key,Data);
 | 
						|
end;
 | 
						|
 | 
						|
{ TFPStringHashTable }
 | 
						|
 | 
						|
Procedure TFPStringHashTable.AddNode(ANode : THTCustomNode);
 | 
						|
 | 
						|
begin
 | 
						|
  With THTStringNode(ANode) do
 | 
						|
    Add(Key,Data);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPStringHashTable.GetData(const Index: string): String;
 | 
						|
var
 | 
						|
  node: THTStringNode;
 | 
						|
begin
 | 
						|
  node := THTStringNode(Find(Index));
 | 
						|
  if Assigned(node) then
 | 
						|
    Result := node.Data
 | 
						|
  else
 | 
						|
    Result := '';
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPStringHashTable.SetData(const index, AValue: string);
 | 
						|
begin
 | 
						|
  THTStringNode(FindOrCreateNew(index)).Data := AValue;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPStringHashTable.Add(const aKey, aItem: string);
 | 
						|
var
 | 
						|
  chn: TFPObjectList;
 | 
						|
  NewNode: THtStringNode;
 | 
						|
  
 | 
						|
begin
 | 
						|
  chn:=FindChainForAdd(akey);
 | 
						|
  NewNode := THtStringNode(CreateNewNode(aKey));
 | 
						|
  NewNode.Data := aItem;
 | 
						|
  chn.Add(NewNode);
 | 
						|
end;
 | 
						|
 | 
						|
Function TFPStringHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
 | 
						|
 | 
						|
begin
 | 
						|
  Result:=THTStringNode.CreateWith(aKey);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPStringHashTable.ForEachCall(aMethod: TStringIteratorMethod): THTStringNode;
 | 
						|
var
 | 
						|
  i, j: Longword;
 | 
						|
  continue: boolean;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  continue := true;
 | 
						|
  if FHashTableSize>0 then
 | 
						|
   for i := 0 to FHashTableSize-1 do
 | 
						|
    begin
 | 
						|
      if assigned(Chain(i)) then
 | 
						|
      begin
 | 
						|
       if chain(i).count>0 then
 | 
						|
        for j := 0 to Chain(i).Count-1 do
 | 
						|
        begin
 | 
						|
          aMethod(THTStringNode(Chain(i)[j]).Data, THTStringNode(Chain(i)[j]).Key, continue);
 | 
						|
          if not continue then
 | 
						|
          begin
 | 
						|
            Result := THTStringNode(Chain(i)[j]);
 | 
						|
            Exit;
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
{ TFPObjectHashTable }
 | 
						|
 | 
						|
Procedure TFPObjectHashTable.AddNode(ANode : THTCustomNode);
 | 
						|
 | 
						|
begin
 | 
						|
  With THTObjectNode(ANode) do
 | 
						|
    Add(Key,Data);
 | 
						|
end;
 | 
						|
 | 
						|
function TFPObjectHashTable.GetData(const Index: string): TObject;
 | 
						|
var
 | 
						|
  node: THTObjectNode;
 | 
						|
begin
 | 
						|
  node := THTObjectNode(Find(Index));
 | 
						|
  if Assigned(node) then
 | 
						|
    Result := node.Data
 | 
						|
  else
 | 
						|
    Result := Nil;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectHashTable.SetData(const index : string; AObject : TObject);
 | 
						|
begin
 | 
						|
  THTObjectNode(FindOrCreateNew(index)).Data := AObject;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TFPObjectHashTable.Add(const aKey: string; AItem : TObject);
 | 
						|
var
 | 
						|
  chn: TFPObjectList;
 | 
						|
  NewNode: THTObjectNode;
 | 
						|
  
 | 
						|
begin
 | 
						|
  chn:=FindChainForAdd(akey);
 | 
						|
  NewNode := THTObjectNode(CreateNewNode(aKey));
 | 
						|
  NewNode.Data := aItem;
 | 
						|
  chn.Add(NewNode);
 | 
						|
end;
 | 
						|
 | 
						|
Function TFPObjectHashTable.CreateNewNode(const aKey : string) : THTCustomNode;
 | 
						|
 | 
						|
begin
 | 
						|
  If OwnsObjects then
 | 
						|
    Result:=THTOwnedObjectNode.CreateWith(aKey)
 | 
						|
  else
 | 
						|
    Result:=THTObjectNode.CreateWith(aKey);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function TFPObjectHashTable.ForEachCall(aMethod: TObjectIteratorMethod): THTObjectNode;
 | 
						|
var
 | 
						|
  i, j: Longword;
 | 
						|
  continue: boolean;
 | 
						|
begin
 | 
						|
  Result := nil;
 | 
						|
  continue := true;
 | 
						|
  if FHashTableSize>0 then
 | 
						|
   for i := 0 to FHashTableSize-1 do
 | 
						|
    begin
 | 
						|
      if assigned(Chain(i)) then
 | 
						|
      begin
 | 
						|
       if chain(i).count>0 then
 | 
						|
        for j := 0 to Chain(i).Count-1 do
 | 
						|
        begin
 | 
						|
          aMethod(THTObjectNode(Chain(i)[j]).Data, THTObjectNode(Chain(i)[j]).Key, continue);
 | 
						|
          if not continue then
 | 
						|
          begin
 | 
						|
            Result := THTObjectNode(Chain(i)[j]);
 | 
						|
            Exit;
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
    end;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TFPObjectHashTable.Create(AOwnsObjects : Boolean = True); 
 | 
						|
 | 
						|
begin
 | 
						|
  Inherited Create;
 | 
						|
  FOwnsObjects:=AOwnsObjects;
 | 
						|
end;
 | 
						|
    
 | 
						|
constructor TFPObjectHashTable.CreateWith(AHashTableSize: Longword; aHashFunc: THashFunction; AOwnsObjects : Boolean = True); 
 | 
						|
 | 
						|
begin
 | 
						|
  Inherited CreateWith(AHashTableSize,AHashFunc);
 | 
						|
  FOwnsObjects:=AOwnsObjects; 
 | 
						|
end;
 | 
						|
 | 
						|
Destructor THTOwnedObjectNode.Destroy;
 | 
						|
 | 
						|
begin
 | 
						|
  FreeAndNil(FData);
 | 
						|
  Inherited;
 | 
						|
end;
 | 
						|
  
 | 
						|
end.
 |