home *** CD-ROM | disk | FTP | other *** search
-
- { Copyright (c) 1989,90 by Borland International, Inc. }
-
- unit TCHash;
- { Turbo Pascal 6.0 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.
-