pragma License (Modified_GPL);

------------------------------------------------------------------------------
--                                                                          --
--                      CHARLES CONTAINER LIBRARY                           --
--                                                                          --
--              Copyright (C) 2001-2003 Matthew J Heaney                    --
--                                                                          --
-- The Charles Container Library ("Charles") is free software; you can      --
-- redistribute it and/or modify it under terms of the GNU General Public   --
-- License as published by the Free Software Foundation; either version 2,  --
-- or (at your option) any later version.  Charles is distributed in the    --
-- hope that it will be useful, but WITHOUT ANY WARRANTY; without even the  --
-- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --
-- See the GNU General Public License for more details.  You should have    --
-- received a copy of the GNU General Public License distributed with       --
-- Charles;  see file COPYING.TXT.  If not, write to the Free Software      --
-- Foundation,  59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.    --
--                                                                          --
-- As a special exception, 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 GNU General Public License.  This exception does not      --
-- however invalidate any other reasons why the executable file might be    --
-- covered by the GNU Public License.                                       --
--                                                                          --
-- Charles is maintained by Matthew J Heaney.                               --
--                                                                          --
-- http://home.earthlink.net/~matthewjheaney/index.html                     --
-- mailto:matthewjheaney@earthlink.net                                      --
--                                                                          --
------------------------------------------------------------------------------
with Charles.Hash_Tables;
pragma Elaborate_All (Charles.Hash_Tables);

with Ada.Finalization;

generic

   type Element_Type is private;

   with function Hash
     (Item : Element_Type) return Hash_Type is <>;

   with function Is_Equal_Key
     (Left, Right : Element_Type) return Boolean is "=";

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

package Charles.Sets.Hashed.Unbounded is
   pragma Preelaborate;

   subtype Element_Subtype is Element_Type;

   function Compare_Keys (Left, Right : Element_Type)
      return Boolean renames Is_Equal_Key;

   function Compare_Elements (Left, Right : Element_Type)
      return Boolean renames "=";


   type Container_Type is private;

   type Iterator_Type is private;

   Null_Iterator : constant Iterator_Type;

   procedure Assign
     (Target : in out Container_Type;
      Source : in     Container_Type);

   function "=" (Left, Right : Container_Type) return Boolean;

   function Length (Container : Container_Type) return Natural;

   function Is_Empty (Container : Container_Type) return Boolean;

   procedure Clear (Container : in out Container_Type);

   procedure Swap (Left, Right : in out Container_Type);

   procedure Insert
     (Container : in out Container_Type;
      New_Item  : in     Element_Type;
      Iterator  :    out Iterator_Type;
      Success   :    out Boolean);

   procedure Insert
     (Container : in out Container_Type;
      New_Item  : in     Element_Type);

   procedure Insert_Sans_Resize
     (Container : in out Container_Type;
      New_Item  : in     Element_Type;
      Iterator  :    out Iterator_Type;
      Success   :    out Boolean);

   procedure Insert_Sans_Resize
     (Container : in out Container_Type;
      New_Item  : in     Element_Type);

--     procedure Delete
--       (Container : in out Container_Type;
--        Item      : in     Element_Type;
--        Count     :    out Natural);

   procedure Delete
     (Container : in out Container_Type;
      Item      : in     Element_Type);

   procedure Delete
     (Container : in out Container_Type;
      Iterator  : in out Iterator_Type);

--     procedure Delete
--       (Container : in out Container_Type;
--        First     : in out Iterator_Type;
--        Back      : in     Iterator_Type);

   function Is_In
     (Item      : Element_Type;
      Container : Container_Type) return Boolean;

   function Find
     (Container : Container_Type;
      Item      : Element_Type) return Iterator_Type;

--     function Count
--       (Container : Container_Type;
--        Item      : Element_Type) return Natural;

--     generic
--        with procedure Process (Iterator : Iterator_Type) is <>;
--     procedure Generic_Equal_Range
--       (Container   : in     Container_Type;
--        Item        : in     Element_Type);

   function Size (Container : Container_Type) return Natural;

   procedure Resize
     (Container : in out Container_Type;
      Length    : in     Natural);

--     function Iterator
--       (Container : Container_Type;
--        Index     : Positive) return Iterator_Type;

--     function Index
--       (Container : Container_Type;
--        Item      : Element_Type) return Positive;

--     function Index
--       (Container : Container_Type;
--        Iterator  : Iterator_Type) return Positive;

   function First (Container : Container_Type)
     return Iterator_Type;

   function First_Element (Container : Container_Type)
     return Element_Type;

   function Back (Container : Container_Type)
     return Iterator_Type;

   function Succ
     (Container : Container_Type;
      Iterator  : Iterator_Type) return Iterator_Type;

   procedure Increment
     (Container : in     Container_Type;
      Iterator  : in out Iterator_Type);

   function Is_Equal_Key
     (Left, Right : Iterator_Type) return Boolean;

   function Is_Equal_Key
     (Left  : Iterator_Type;
      Right : Element_Type) return Boolean;

   function Is_Equal_Key
     (Left  : Element_Type;
      Right : Iterator_Type) return Boolean;

   function Is_Equal
     (Left, Right : Iterator_Type) return Boolean;

   function Is_Equal
     (Left  : Iterator_Type;
      Right : Element_Type) return Boolean;

   function Is_Equal
     (Left  : Element_Type;
      Right : Iterator_Type) return Boolean;

   generic
      with function Compare
        (Left, Right : Element_Type) return Boolean is <>;
   function Generic_Compare_Elements
     (Left, Right : Iterator_Type) return Boolean;

   function Element (Iterator : Iterator_Type) return Element_Type;

   generic
      type Element_Access is access constant Element_Type;
   function Generic_Element
     (Iterator : Iterator_Type) return Element_Access;

   generic
      type Element_Access is access all Element_Type;
   function Generic_Modify_Element
     (Iterator : Iterator_Type) return Element_Access;

   procedure Copy_Element
     (Iterator : in     Iterator_Type;
      Item     :    out Element_Type);

   procedure Swap_Iterator (Left, Right : in out Iterator_Type);

   generic
      with procedure Process (Element : in Element_Type) is <>;
   procedure Generic_Select_Element
     (Iterator : in Iterator_Type);

   generic
      with procedure Process (Iterator : in Iterator_Type) is <>;
   procedure Generic_Iteration
     (Container : in Container_Type);

   generic
      with procedure Process
        (Element : in Element_Type) is <>;
   procedure Generic_Select_Elements
     (Container : in Container_Type);

   generic

      type Key_Type (<>) is limited private;

      with function Hash (Key : Key_Type) return Hash_Type is <>;

      with function Is_Equal_Key
        (Item : Element_Type;
         Key  : Key_Type) return Boolean is <>;

   package Generic_Keys is

      function Is_In
        (Key       : Key_Type;
         Container : Container_Type) return Boolean;

      function Find
        (Container : Container_Type;
         Key       : Key_Type) return Iterator_Type;

--        function Count
--          (Container : Container_Type;
--           Key       : Key_Type) return Natural;

      function Element
        (Container : Container_Type;
         Key       : Key_Type) return Element_Type;

      generic
         with procedure Process (Iterator : Iterator_Type) is <>;
      procedure Generic_Equal_Range
        (Container   : in     Container_Type;
         Key         : in     Key_Type);

      function Is_Equal_Key
        (Left  : Iterator_Type;
         Right : Key_Type) return Boolean;

      function Is_Equal_Key
        (Left  : Key_Type;
         Right : Iterator_Type) return Boolean;

--        function Index
--          (Container : Container_Type;
--           Key       : Key_Type) return Positive;

--        procedure Delete
--          (Container : in out Container_Type;
--           Key       : in     Key_Type;
--           Count     :    out Natural);

      procedure Delete
        (Container : in out Container_Type;
         Key       : in     Key_Type);

      generic

         with procedure Set_Key
           (Element : in out Element_Type;
            Key     : in     Key_Type) is <>;

      package Generic_Insertion is

         procedure Insert
           (Container : in out Container_Type;
            Key       : in     Key_Type;
            Iterator  :    out Iterator_Type;
            Success   :    out Boolean);

         procedure Insert_Sans_Resize
           (Container : in out Container_Type;
            Key       : in     Key_Type;
            Iterator  :    out Iterator_Type;
            Success   :    out Boolean);

      end Generic_Insertion;

   end Generic_Keys;

private

   type Node_Type;
   type Node_Access is access Node_Type;

   function Next (Node : Node_Access) return Node_Access;

   procedure Set_Next (Node : Node_Access; Next : Node_Access);

   function Hash (Node : Node_Access) return Hash_Type;

   procedure Free (X : in out Node_Access);

   package Hash_Table_Types is
     new Charles.Hash_Tables
     (Node_Access,
      null);

   use Hash_Table_Types;


   type Container_Type is
      new Ada.Finalization.Controlled with record
         Hash_Table : Hash_Table_Type := (Buckets => null, Length => 0);
      end record;

   procedure Adjust (Container : in out Container_Type);

   procedure Finalize (Container : in out Container_Type);


   type Iterator_Type is
      record
         Node : Node_Access;
      end record;

   Null_Iterator : constant Iterator_Type := (Node => null);


end Charles.Sets.Hashed.Unbounded;


