-- $Date: 2004/01/06 06:08:42 $
-- $Revision: 1.10 $
-- $Author: jcrocholl $

generic

   -- Generic type of keys to access items.
   type Key_Type is private;

   -- Generic type of the items to be stored.
   type Item_Type is private;

   with function Hash
     (Key : in Key_Type;
      Max : in Positive)
     return Positive;

   with function "="
     (Left, Right : in Key_Type)
     return Boolean
     is <>;

-- Versatile implementation of hash tables.
-- - Generic to allow all kinds of content.
-- - Variable size (always prime).
package Hash_Tables is

   Default_Start_Size  : constant := 13;
   Max_Fill_Percentage : constant := 60;

   -- Instance of a hash table.
   --
   -- No need to call a constructor. Uninitialized hash tables behave
   -- like regular empty ones.
   type Hash_Table is private;

   -- The given key already exists in the hash table.
   --
   -- Raised by Put(Hash_Table, Key_Type, Item_Type).
   Key_Exists : exception;

   -- Check for available space in the table, grow if necessary, then
   -- insert the key item pair into the table.
   --
   -- Raises Key_Exists if the key is already in use.
   procedure Put
     (Table : in out Hash_Table-- Add pair to this hash table.
      Key   : in Key_Type;       -- The new key to be added.
      Item  : in Item_Type);     -- The new item to be added.

   -- Retrieve an item from the table.
   --
   -- Output parameter Found tells you whether the item was found in
   -- the table.
   procedure Get
     (Table : in Hash_Table-- Get value from this hash table.
      Key   : in Key_Type;   -- Look up this key.
      Item  : out Item_Type-- The item associated with the key.
      Found : out Boolean);  -- Was the item actually found?

   -- The given key was not found in the hash table.
   --
   -- Raised by Get(Hash_Table, Key_Type).
   Key_Not_Found : exception;

   -- Retrieve an item from the table.
   --
   -- Raises Key_Not_Found if the key is not in the table.
   function Get
     (Table : in Hash_Table-- Get value from this hash table.
      Key   : in Key_Type)   -- Look up this key.
     return Item_Type;       -- The item associated with the key.

   -- Iterate over the items in the table.
   --
   -- You should start with an Index of 0 and stop iterating as soon
   -- as Index is 0 again.
   procedure Get_Next
     (Table : in Hash_Table;  -- Get pair from this hash table.
      Index : in out Natural-- Iteration pointer to the current field.
      Key   : out Key_Type;   -- The key at the current field.
      Item  : out Item_Type); -- The item at the current field.

   -- Print a visual representation of the hash table's usage.
   --
   -- Empty fields are represented by a '-' character, used fields by
   -- '#'.
   procedure Print_Usage
     (Table : in Hash_Table); -- Print usage of this hash table.

private

   type Pair is record
      Empty : Boolean := True;
      Key   : Key_Type;
      Item  : Item_Type;
   end record;

   type Pair_Array is array(Natural range <>) of Pair;

   type Hash_Table_Record(Size : Positive) is
      record
         Count : Natural;
         Pairs : Pair_Array(1 .. Size);
      end record;

   type Hash_Table is access Hash_Table_Record;

end Hash_Tables;