dos_compilers/Borland Turbo Pascal v55/TCHASH.PAS
2024-07-02 06:49:04 -07:00

262 lines
6.8 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ 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.