-------------------------------------------------------------------------------
--
-- <STRONG>Copyright (c) 2001, 2002 by Thomas Wolf.</STRONG>
-- <BLOCKQUOTE>
--    This piece of software is free software; you can redistribute it and/or
--    modify it under the terms of the  GNU General Public License as published
--    by the Free Software  Foundation; either version 2, or (at your option)
--    any later version. This unit is distributed in the hope that it will be
--    useful, but <EM>without any warranty</EM>; without even the implied
--    warranty of <EM>merchantability or fitness for a particular purpose.</EM>
--    See the GNU General Public License for  more details. You should have
--    received a copy of the GNU General Public License with this distribution,
--    see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
--    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
--    USA.
-- </BLOCKQUOTE>
-- <BLOCKQUOTE>
--   As a special exception from the GPL, if other files instantiate generics
--   from this unit, or you link this unit with other files to produce an
--   executable, this unit does not by itself cause the resulting executable
--   to be covered by the GPL. This exception does not however invalidate any
--   other reasons why the executable file might be covered by the GPL.
-- </BLOCKQUOTE>
--
-- <DL><DT><STRONG>
-- Author:</STRONG><DD>
--   Thomas Wolf  (TW)
--   <ADDRESS><A HREF="mailto:twolf@acm.org">twolf@acm.org</A></ADDRESS></DL>
--
-- <DL><DT><STRONG>
-- Purpose:</STRONG><DD>
--   Utilities for hashing.</DL>
--
-- <DL><DT><STRONG>
-- Tasking semantics:</STRONG><DD>
--   N/A. Not abortion-safe.</DL>
--
-- <DL><DT><STRONG>
-- Storage semantics:</STRONG><DD>
--   No dynamic storage allocation.</DL>
--
-- <!--
-- Revision History
--
--   31-DEC-2001   TW  Initial version.
--   18-JUN-2003   TW  Added 'Hash_Case_Insensitive'.
-- -->
-------------------------------------------------------------------------------

pragma License (Modified_GPL);

package GAL.Support.Hashing is

   pragma Elaborate_Body;

   type Hash_Type is mod 2 ** 32;
   --  The hash type used by GAL.ADT.Hash_Tables. If you want to use other
   --  hash types, use GAL.Containers.Hash_Tables.

   subtype Size_Type is Hash_Type range 1 .. Hash_Type'Last;

   function Next_Prime
     (After : in Hash_Type)
     return Hash_Type;
   --  Returns the next prime number >= 'After'.

   function Is_Prime
     (X : in Hash_Type)
     return Boolean;
   --  returns @True@ if @X@ is a prime number.

   function Hash
     (S : in String)
     return Hash_Type;
   --  This is the hash function from the dragon book: Aho, Sethi, Ullman:
   --  "Compilers -- Principles, Techniques, and Tools", Addison Wesley 1986;
   --  p. 436.

   function Hash_Case_Insensitive
     (S : in String)
     return Hash_Type;
   --  Same as @Hash@, but disregards case differences; i.e. "AAA" and "aaa"
   --  hash to the same value.

   type Load_Factor is delta 0.1 range 0.0 .. 100.0;

   ----------------------------------------------------------------------------

   type Growth_Policy is abstract tagged private;

   function Increase
     (Policy       : access Growth_Policy;
      Current_Size : in     Size_Type)
     return Size_Type
     is abstract;
   --  If a hash table needs to grow, and a growth policy is set, @Increase@
   --  of the table's growth policy is invoked to determine the new size of
   --  the hash table.
   --
   --  The function should return a value strictly greater than
   --  @Current_Size@, otherwise, the hash table will not be resized!

   type Linear_Growth_Policy (Increment : Size_Type) is
     new Growth_Policy with private;

   function Increase
     (Policy       : access Linear_Growth_Policy;
      Current_Size : in     Size_Type)
     return Size_Type;
   --  Returns <CODE>Current_Size + Policy.Increment</CODE>.

   type Double_Growth_Policy (Maximum_Increment : Size_Type) is
     new Growth_Policy with private;

   function Increase
     (Policy       : access Double_Growth_Policy;
      Current_Size : in     Size_Type)
     return Size_Type;
   --  <CODE>Current_Size + Min (Policy.Maximum_Increment, Current_Size)</CODE>

   ----------------------------------------------------------------------------

   type Collision_Policy is abstract tagged private;

   function Next
     (Policy     : access Collision_Policy;
      Current    : in     Size_Type;
      Hash       : in     Hash_Type;
      Table_Size : in     Size_Type;
      Count      : in     Positive)
     return Hash_Type
     is abstract;
   --  Supposed to return the @Count@th index in the collision chain (in the
   --  range 1 .. @Table_Size@) or zero if no next index can be determined.
   --
   --  Hash table indexing starts at 1!

   type Default_Collision_Policy is new Collision_Policy with private;

   function Next
     (Policy     : access Default_Collision_Policy;
      Current    : in     Size_Type;
      Hash       : in     Hash_Type;
      Table_Size : in     Size_Type;
      Count      : in     Positive)
     return Hash_Type;
   --  The @Default_Collision_Policy@ does double hashing, using
   --  Hash mod (Table_Size - 2) as the step.

private

   type Growth_Policy    is abstract tagged null record;

   type Linear_Growth_Policy (Increment : Size_Type) is
     new Growth_Policy with null record;

   type Double_Growth_Policy (Maximum_Increment : Size_Type) is
     new Growth_Policy with null record;

   type Collision_Policy is abstract tagged null record;

   type Default_Collision_Policy is new Collision_Policy with
      record
         Step : Hash_Type := 1;
      end record;

end GAL.Support.Hashing;
