|
@@ -0,0 +1,260 @@
|
|
|
+{
|
|
|
+ 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.
|