dos_compilers/Borland Turbo Pascal v55/TCHASH.PAS

262 lines
6.8 KiB
Plaintext
Raw Normal View History

2024-07-02 15:49:04 +02:00
{ Copyright (c) 1989 by Borland International, Inc. }
unit TCHash;
{ Turbo Pascal 5.5 object-oriented example hash tables.
This unit is used by TCALC.PAS.
See TCALC.DOC for an more information about this example.
}
{$S-}
interface
uses TCUtil;
{ This unit allows you to implement hash tables. Each hash table is composed
of a number of "buckets", each of which points to a linked list of data
entries. The bucket that a particular data entry goes into is determined
by the HashValue function. }
const
MaxBuckets = 1000;
MaxHashItemSize = 256;
type
BucketRange = 1..MaxBuckets;
HashItemSizeRange = 1..MaxHashItemSize;
HashItemData = array[0..Pred(MaxHashItemSize)] of Byte;
HashItemDataPtr = ^HashItemData;
HashItemPtr = ^HashItem;
HashItem = record
Next : HashItemPtr;
Data : HashItemData;
end;
HashItemArray = array[BucketRange] of HashItemPtr;
HashTable = object
Buckets : BucketRange;
Items : Longint;
CurrItem : HashItemPtr;
CurrBucket : BucketRange;
HashData : ^HashItemArray;
constructor Init(InitBuckets : BucketRange);
destructor Done;
function Add : Boolean;
procedure Delete(Deleted : Pointer);
function FirstItem : HashItemPtr;
function NextItem : HashItemPtr;
function Change : Boolean;
function Search : HashItemPtr;
function HashValue : Word; virtual;
function Found(Item : HashItemPtr) : Boolean; virtual;
procedure CreateItem(var Item : HashItemPtr); virtual;
function ItemSize : HashItemSizeRange; virtual;
function CurrItemSize(Item : HashItemPtr) : HashItemSizeRange; virtual;
end;
implementation
constructor HashTable.Init(InitBuckets : BucketRange);
{ Initialize a new hash table with a certain number of buckets }
begin
GetMem(HashData, InitBuckets * SizeOf(HashItemPtr));
if HashData = nil then
Fail;
Buckets := InitBuckets;
FillChar(HashData^, Buckets * SizeOf(HashItemPtr), 0);
Items := 0;
end; { HashTable.Init }
destructor HashTable.Done;
{ Removes a hash table from memory }
var
P, D : HashItemPtr;
Counter : Word;
begin
for Counter := 1 to Buckets do
begin
P := HashData^[Counter];
while P <> nil do
begin
D := P;
P := P^.Next;
FreeMem(D, CurrItemSize(D) + SizeOf(HashItemPtr));
end;
end;
FreeMem(HashData, Buckets * SizeOf(HashItemPtr));
end; { HashTable.Done }
function HashTable.Add : Boolean;
{ Adds a new item to a hash table }
var
H, A : HashItemPtr;
V : BucketRange;
begin
Add := False;
V := Succ(HashValue mod Buckets);
H := HashData^[V];
A := H;
while H <> nil do
begin
H := H^.Next;
if H <> nil then
A := H;
end;
if A = nil then { Item will be the first element in the list }
begin
GetMem(HashData^[V], ItemSize + SizeOf(HashItemPtr));
A := HashData^[V];
if A = nil then
Exit;
end
else begin { Add item and end of list }
GetMem(A^.Next, ItemSize + SizeOf(HashItemPtr));
if A^.Next = nil then
Exit;
A := A^.Next;
end;
CreateItem(A);
A^.Next := nil;
Inc(Items);
Add := True;
end; { HashTable.Add }
procedure HashTable.Delete(Deleted : Pointer);
{ Deletes an item from a hash table, and returns the deleted item }
var
H, D : HashItemPtr;
V : BucketRange;
begin
V := Succ(HashValue mod Buckets);
H := HashData^[V];
D := H;
while (H <> nil) and (not Found(H)) do
begin
H := H^.Next;
if not Found(H) then
D := H;
end;
if H = nil then { The item was not found }
begin
if Deleted <> nil then
FillChar(Deleted^, ItemSize, 0);
Exit;
end
else begin
if H = HashData^[V] then
HashData^[V] := HashData^[V]^.Next
else
D^.Next := H^.Next;
if Deleted <> nil then { Fill Deleted with the item's data }
Move(H^.Data, Deleted^, ItemSize);
FreeMem(H, CurrItemSize(H) + SizeOf(HashItemPtr));
end;
Dec(Items);
end; { HashTable.Delete }
function HashTable.FirstItem : HashItemPtr;
{ Returns the first item in a hash table. to find all of the items in a
hash table, call FirstItem to get the first one and then call NextItem to
get the rest }
var
Counter : Word;
begin
for Counter := 1 to Buckets do
begin
CurrBucket := Counter;
CurrItem := HashData^[Counter];
if CurrItem <> nil then
begin
FirstItem := CurrItem;
Exit;
end;
end;
FirstItem := nil;
end; { HashTable.FirstItem }
function HashTable.NextItem : HashItemPtr;
{ Returns the next item in a hash table - called after FirstItem }
begin
CurrItem := CurrItem^.Next;
if CurrItem <> nil then
begin
NextItem := CurrItem;
Exit;
end;
while CurrBucket < Buckets do
begin
Inc(CurrBucket);
CurrItem := HashData^[CurrBucket];
if CurrItem <> nil then
begin
NextItem := CurrItem;
Exit;
end;
end;
NextItem := nil;
end; { HashTable.NextItem }
function HashTable.Change : Boolean;
{ Changes the data of a hash item }
var
H : HashItemPtr;
begin
H := HashData^[Succ(HashValue mod Buckets)];
while (H <> nil) and (not Found(H)) do
H := H^.Next;
if H <> nil then
begin
CreateItem(H);
Change := True;
end
else
Change := Add;
end; { HashTable.Change }
function HashTable.Search : HashItemPtr;
{ Searches for a particular hash item }
var
H : HashItemPtr;
begin
H := HashData^[Succ(HashValue mod Buckets)];
while (H <> nil) and (not Found(H)) do
H := H^.Next;
Search := H;
end; { HashTable.Search }
function HashTable.HashValue : Word;
{ Returns a hash value - must be written by the user }
begin
Abstract('HashTable.HashValue');
end; { HashTable.HashValue }
function HashTable.Found(Item : HashItemPtr) : Boolean;
{ Returns a boolean value indicating whether the current hash item is the
one being searched for - must be written by the user }
begin
Abstract('HashTable.Found');
end; { HashTable.Found }
procedure HashTable.CreateItem(var Item : HashItemPtr);
{ Creates a hash item - must be written by the user }
begin
Abstract('HashTable.CreateItem');
end; { HashTable.CreateItem }
function HashTable.ItemSize : HashItemSizeRange;
{ Returns the size of a hash item. If the hash item size is variable, this
is based on whatever the item being searched for, added, or deleted is -
must be written by the user }
begin
Abstract('HashTable.ItemSize');
end; { HashTable.ItemSize }
function HashTable.CurrItemSize(Item : HashItemPtr) : HashItemSizeRange;
{ Returns the size of a particular item. This needs to be written only if
the size of hash items is variable (strings, etc.) }
begin
CurrItemSize := ItemSize;
end; { HashTable.CurrItemSize }
end.