File : g-htable.adb


     ------------------------------------------------------------------------------
     --                                                                          --
     --                         GNAT RUNTIME COMPONENTS                          --
     --                                                                          --
   5 --                          G N A T . H T A B L E                           --
     --                                                                          --
     --                                 B o d y                                  --
     --                                                                          --
     --                            $Revision: 1.14 $
  10 --                                                                          --
     --           Copyright (C) 1995-1999 Ada Core Technologies, Inc.            --
     --                                                                          --
     -- GNAT is free software;  you can  redistribute it  and/or modify it under --
     -- terms of the  GNU General Public License as published  by the Free Soft- --
  15 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
     -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
     -- OUT 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 --
  20 -- Public License  distributed with GNAT;  see file COPYING.  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 --
  25 -- 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.                                      --
  30 --                                                                          --
     -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com).   --
     --                                                                          --
     ------------------------------------------------------------------------------
     
  35 with Ada.Unchecked_Deallocation;
     package body GNAT.HTable is
     
        --------------------
        --  Static_HTable --
  40    --------------------
     
        package body Static_HTable is
     
           Table : array (Header_Num) of Elmt_Ptr;
  45 
           Iterator_Index   : Header_Num;
           Iterator_Ptr     : Elmt_Ptr;
           Iterator_Started : Boolean := False;
     
  50       function Get_Non_Null return Elmt_Ptr;
           --  Returns Null_Ptr if Iterator_Started is false of the Table is
           --  empty. Returns Iterator_Ptr if non null, or the next non null
           --  element in table if any.
     
  55       ---------
           -- Get --
           ---------
     
           function  Get (K : Key) return Elmt_Ptr is
  60          Elmt  : Elmt_Ptr;
     
           begin
              Elmt := Table (Hash (K));
     
  65          loop
                 if Elmt = Null_Ptr then
                    return Null_Ptr;
     
                 elsif Equal (Get_Key (Elmt), K) then
  70                return Elmt;
     
                 else
                    Elmt := Next (Elmt);
                 end if;
  75          end loop;
           end Get;
     
           ---------------
           -- Get_First --
  80       ---------------
     
           function Get_First return Elmt_Ptr is
           begin
              Iterator_Started := True;
  85          Iterator_Index := Table'First;
              Iterator_Ptr := Table (Iterator_Index);
              return Get_Non_Null;
           end Get_First;
     
  90       --------------
           -- Get_Next --
           --------------
     
           function Get_Next return Elmt_Ptr is
  95       begin
              if not Iterator_Started then
                 return Null_Ptr;
              end if;
     
 100          Iterator_Ptr := Next (Iterator_Ptr);
              return Get_Non_Null;
           end Get_Next;
     
           ------------------
 105       -- Get_Non_Null --
           ------------------
     
           function Get_Non_Null return Elmt_Ptr is
           begin
 110          while Iterator_Ptr = Null_Ptr  loop
                 if Iterator_Index = Table'Last then
                    Iterator_Started := False;
                    return Null_Ptr;
                 end if;
 115 
                 Iterator_Index := Iterator_Index + 1;
                 Iterator_Ptr   := Table (Iterator_Index);
              end loop;
     
 120          return Iterator_Ptr;
           end Get_Non_Null;
     
           ------------
           -- Remove --
 125       ------------
     
           procedure Remove  (K : Key) is
              Index     : constant Header_Num := Hash (K);
              Elmt      : Elmt_Ptr;
 130          Next_Elmt : Elmt_Ptr;
     
           begin
              Elmt := Table (Index);
     
 135          if Elmt = Null_Ptr then
                 return;
     
              elsif Equal (Get_Key (Elmt), K) then
                 Table (Index) := Next (Elmt);
 140 
              else
                 loop
                    Next_Elmt :=  Next (Elmt);
     
 145                if Next_Elmt = Null_Ptr then
                       return;
     
                    elsif Equal (Get_Key (Next_Elmt), K) then
                       Set_Next (Elmt, Next (Next_Elmt));
 150                   return;
     
                    else
                       Elmt := Next_Elmt;
                    end if;
 155             end loop;
              end if;
           end Remove;
     
           -----------
 160       -- Reset --
           -----------
     
           procedure Reset is
           begin
 165          for J in Table'Range loop
                 Table (J) := Null_Ptr;
              end loop;
           end Reset;
     
 170       ---------
           -- Set --
           ---------
     
           procedure Set (E : Elmt_Ptr) is
 175          Index : Header_Num;
     
           begin
              Index := Hash (Get_Key (E));
              Set_Next (E, Table (Index));
 180          Table (Index) := E;
           end Set;
     
        end Static_HTable;
     
 185    --------------------
        --  Simple_HTable --
        --------------------
     
        package body Simple_HTable is
 190 
           type Element_Wrapper;
           type Elmt_Ptr is access all Element_Wrapper;
           type Element_Wrapper is record
              K    : Key;
 195          E    : Element;
              Next : Elmt_Ptr;
           end record;
     
           procedure Free is new
 200         Ada.Unchecked_Deallocation (Element_Wrapper, Elmt_Ptr);
     
           procedure Set_Next (E : Elmt_Ptr; Next : Elmt_Ptr);
           function  Next     (E : Elmt_Ptr) return Elmt_Ptr;
           function  Get_Key  (E : Elmt_Ptr) return Key;
 205 
           package Tab is new Static_HTable (
             Header_Num => Header_Num,
             Element    => Element_Wrapper,
             Elmt_Ptr   => Elmt_Ptr,
 210         Null_Ptr   => null,
             Set_Next   => Set_Next,
             Next       => Next,
             Key        => Key,
             Get_Key    => Get_Key,
 215         Hash       => Hash,
             Equal      => Equal);
     
           ---------
           -- Get --
 220       ---------
     
           function  Get (K : Key) return Element is
              Tmp : constant Elmt_Ptr := Tab.Get (K);
     
 225       begin
              if Tmp = null then
                 return No_Element;
              else
                 return Tmp.E;
 230          end if;
           end Get;
     
           ---------------
           -- Get_First --
 235       ---------------
     
           function Get_First return Element is
              Tmp : constant Elmt_Ptr := Tab.Get_First;
     
 240       begin
              if Tmp = null then
                 return No_Element;
              else
                 return Tmp.E;
 245          end if;
           end Get_First;
     
           -------------
           -- Get_Key --
 250       -------------
     
           function Get_Key (E : Elmt_Ptr) return Key is
           begin
              return E.K;
 255       end Get_Key;
     
           --------------
           -- Get_Next --
           --------------
 260 
           function Get_Next return Element is
              Tmp : constant Elmt_Ptr := Tab.Get_Next;
     
           begin
 265          if Tmp = null then
                 return No_Element;
              else
                 return Tmp.E;
              end if;
 270       end Get_Next;
     
           ----------
           -- Next --
           ----------
 275 
           function Next (E : Elmt_Ptr) return Elmt_Ptr is
           begin
              return E.Next;
           end Next;
 280 
           ------------
           -- Remove --
           ------------
     
 285       procedure Remove  (K : Key) is
              Tmp : Elmt_Ptr;
     
           begin
              Tmp := Tab.Get (K);
 290 
              if Tmp /= null then
                 Tab.Remove (K);
                 Free (Tmp);
              end if;
 295       end Remove;
     
           -----------
           -- Reset --
           -----------
 300 
           procedure Reset is
              E1, E2 : Elmt_Ptr;
     
           begin
 305          E1 := Tab.Get_First;
              while E1 /= null loop
                 E2 := Tab.Get_Next;
                 Free (E1);
                 E1 := E2;
 310          end loop;
     
              Tab.Reset;
           end Reset;
     
 315       ---------
           -- Set --
           ---------
     
           procedure Set (K : Key; E : Element) is
 320          Tmp : constant Elmt_Ptr := Tab.Get (K);
     
           begin
              if Tmp = null then
                 Tab.Set (new Element_Wrapper'(K, E, null));
 325          else
                 Tmp.E := E;
              end if;
           end Set;
     
 330       --------------
           -- Set_Next --
           --------------
     
           procedure Set_Next (E : Elmt_Ptr; Next : Elmt_Ptr) is
 335       begin
              E.Next := Next;
           end Set_Next;
        end Simple_HTable;
     
 340    ----------
        -- Hash --
        ----------
     
        function Hash (Key : String) return Header_Num is
 345 
           type Uns is mod 2 ** 32;
     
           function Rotate_Left (Value : Uns; Amount : Natural) return Uns;
           pragma Import (Intrinsic, Rotate_Left);
 350 
           Tmp : Uns := 0;
     
        begin
           for J in Key'Range loop
 355          Tmp := Rotate_Left (Tmp, 1) + Character'Pos (Key (J));
           end loop;
     
           return Header_Num'First +
                    Header_Num'Base (Tmp mod Header_Num'Range_Length);
 360    end Hash;
     
     end GNAT.HTable;