Repository URL to install this package:
Version:
3.0.0 ▾
|
{
Copyright 2005, Micha Nelissen, converted from C, originally from
"simple_hash.h":
}
unit simple_hash;
{$mode objfpc}
{$inline on}
interface
const
ht_num_primes = 28;
ht_prime_list: array[0 .. ht_num_primes-1] of dword =
( 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 );
type
ht_ppnode = ^ht_pnode;
ht_pnode = ^ht_node;
ht_node = record
key: pchar;
val: integer;
next: ht_pnode;
end;
ht_pht = ^ht_ht;
ht_ht = record
size: dword;
tbl: ht_ppnode;
iter_index: dword;
iter_next: ht_pnode;
items: integer;
{$ifdef HT_DEBUG}
collisions: integer;
{$endif}
end;
function ht_val(node: ht_pnode): integer; {inline;}
function ht_key(node: ht_pnode): pchar; {inline;}
function ht_hashcode(ht: ht_pht; key: pchar): integer; {inline;}
function ht_node_create(key: pchar): ht_pnode;
function ht_create(size: dword): ht_pht;
procedure ht_destroy(ht: ht_pht);
function ht_find(ht: ht_pht; key: pchar): ht_pnode; {inline;}
function ht_find_new(ht: ht_pht; key: pchar): ht_pnode; {inline;}
function ht_next(ht: ht_pht): ht_pnode; {inline;}
function ht_first(ht: ht_pht): ht_pnode; {inline;}
function ht_count(ht: ht_pht): integer; {inline;}
implementation
uses
strings;
function ht_val(node: ht_pnode): integer; {inline;}
begin
result := node^.val;
end;
function ht_key(node: ht_pnode): pchar; {inline;}
begin
result := node^.key;
end;
function ht_hashcode(ht: ht_pht; key: pchar): integer; {inline;}
var
val: dword;
begin
val := 0;
while key^ <> #0 do
begin
val := 5 * val + byte(key^);
inc(key);
end;
result := val mod ht^.size;
end;
function ht_node_create(key: pchar): ht_pnode;
var
newkey: pchar;
node: ht_pnode;
begin
new(node);
newkey := strnew(key);
with node^ do
begin
key := newkey;
val := 0;
next := nil;
end;
result := node;
end;
function ht_create(size: dword): ht_pht;
var
i: integer;
ht: ht_pht;
begin
i := 0;
new(ht);
while ht_prime_list[i] < size do inc(i);
ht^.size := ht_prime_list[i];
ht^.tbl := allocmem(sizeof(ht_pnode) * ht^.size);
ht^.iter_index := 0;
ht^.iter_next := nil;
ht^.items := 0;
{$ifdef HT_DEBUG}
ht^.collisions := 0;
{$endif}
result := ht;
end;
procedure ht_destroy(ht: ht_pht);
var
cur, next: ht_pnode;
i: integer;
{$ifdef HT_DEBUG}
chain_len, max_chain_len, density: integer;
{$endif}
begin
{$ifdef HT_DEBUG}
max_chain_len := 0;
density := 0;
writeln(' HT: size ', ht^.size);
writeln(' HT: items ', ht^.items);
writeln(' HT: collisions ', ht^.collisions);
{$endif}
for i := 0 to ht^.size-1 do
begin
next := ht^.tbl[i];
{$ifdef HT_DEBUG}
if next <> nil then
inc(density);
chain_len := 0;
{$endif}
while next <> nil do
begin
cur := next;
next := next^.next;
strdispose(cur^.key);
dispose(cur);
{$ifdef HT_DEBUG}
inc(chain_len);
{$endif}
end;
{$ifdef HT_DEBUG}
if chain_len > max_chain_len then
max_chain_len := chain_len;
{$endif}
end;
freemem(ht^.tbl);
dispose(ht);
{$ifdef HT_DEBUG}
writeln(' HT: density ', density);
writeln(' HT: max chain len ', max_chain_len);
{$endif}
end;
function ht_find(ht: ht_pht; key: pchar): ht_pnode; {inline;}
var
hash_code: integer;
node: ht_pnode;
begin
hash_code := ht_hashcode(ht, key);
node := ht^.tbl[hash_code];
while node <> nil do
begin
if strcomp(key, node^.key) = 0 then
begin
result := node;
exit;
end;
node := node^.next;
end;
result := nil;
end;
function ht_find_new(ht: ht_pht; key: pchar): ht_pnode; {inline;}
var
hash_code: integer;
prev, node: ht_pnode;
begin
hash_code := ht_hashcode(ht, key);
prev := nil;
node := ht^.tbl[hash_code];
while node <> nil do
begin
if strcomp(key, node^.key) = 0 then
begin
result := node;
exit;
end;
prev := node;
node := node^.next;
{$ifdef HT_DEBUG}
inc(ht^.collisions);
{$endif}
end;
inc(ht^.items);
result := ht_node_create(key);
if prev <> nil then
begin
prev^.next := result;
end else begin
ht^.tbl[hash_code] := result;
end;
end;
{
Hash Table iterator data / functions
}
function ht_next(ht: ht_pht): ht_pnode; {inline;}
var
index: dword;
node: ht_pnode;
begin
node := ht^.iter_next;
if node <> nil then
begin
ht^.iter_next := node^.next;
result := node;
exit;
end else begin
while ht^.iter_index < ht^.size do
begin
index := ht^.iter_index;
inc(ht^.iter_index);
if ht^.tbl[index] <> nil then
begin
ht^.iter_next := ht^.tbl[index]^.next;
result := ht^.tbl[index];
exit;
end;
end;
end;
result := nil;
end;
function ht_first(ht: ht_pht): ht_pnode; {inline;}
begin
ht^.iter_index := 0;
ht^.iter_next := nil;
result := ht_next(ht);
end;
function ht_count(ht: ht_pht): integer; {inline;}
begin
result := ht^.items;
end;
end.