/src/ghdldrv/

28'>28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
--  Lists data type.
--  Copyright (C) 2002, 2003, 2004, 2005 Tristan Gingold
--
--  GHDL 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.
--
--  GHDL 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
--  along with GHDL; see the file COPYING.  If not, write to the Free
--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
--  02111-1307, USA.
with System;
with Tables;

package body Lists is
   type Node_Array_Fat is array (Natural) of Node_Type;
   type Node_Array_Fat_Acc is access Node_Array_Fat;

   type List_Record is record
      Max : Natural;
      Nbr : Natural;
      Next : List_Type;
      Els : Node_Array_Fat_Acc;
   end record;

   package Listt is new Tables
     (Table_Component_Type => List_Record,
      Table_Index_Type => List_Type,
      Table_Low_Bound => 4,
      Table_Initial => 128);

   --function Get_Max_Nbr_Elements (List : List_Type) return Natural;
   --pragma Inline (Get_Max_Nbr_Elements);

   --procedure Set_Max_Nbr_Elements (List : List_Type; Max : Natural);
   --pragma Inline (Set_Max_Nbr_Elements);

   procedure List_Set_Nbr_Elements (List : List_Type; Nbr : Natural);
   pragma Inline (List_Set_Nbr_Elements);

   function Get_Nbr_Elements (List: List_Type) return Natural is
   begin
      return Listt.Table (List).Nbr;
   end Get_Nbr_Elements;

   procedure List_Set_Nbr_Elements (List : List_Type; Nbr : Natural) is
   begin
      Listt.Table (List).Nbr := Nbr;
   end List_Set_Nbr_Elements;

   --function Get_Max_Nbr_Elements (List : List_Type) return Natural is
   --begin
   --   return Listt.Table (List).Max;
   --end Get_Max_Nbr_Elements;

   --procedure Set_Max_Nbr_Elements (List : List_Type; Max : Natural) is
   --begin
   --   Listt.Table (List).Max := Max;
   --end Set_Max_Nbr_Elements;

   function Get_Nth_Element (List: List_Type; N: Natural)
     return Node_Type
   is
   begin
      if N >= Listt.Table (List).Nbr then
         return Null_Node;
      end if;
      return Listt.Table (List).Els (N);
   end Get_Nth_Element;

   -- Replace an element selected by position.
   procedure Replace_Nth_Element (List: List_Type; N: Natural; El: Node_Type)
   is
   begin
      if N >= Listt.Table (List).Nbr then
         raise Program_Error;
      end if;
      Listt.Table (List).Els (N) := El;
   end Replace_Nth_Element;

   -- Be sure an element can be added to LIST.
   -- It doesn't change the number of elements.
   procedure List_Grow (List: List_Type)
   is
      L : List_Record renames Listt.Table (List);

      --  Be careful: size in bytes.
      function Alloc (Size : Natural) return Node_Array_Fat_Acc;
      pragma Import (C, Alloc, "malloc");

      function Realloc (Ptr : Node_Array_Fat_Acc; Size : Natural)
        return Node_Array_Fat_Acc;
      pragma Import (C, Realloc, "realloc");

      Tmp : Node_Array_Fat_Acc;
      N : Natural;
   begin
      if L.Nbr < L.Max then
         return;
      end if;
      if L.Max = 0 then
         N := 8;
         Tmp := Alloc (N * Node_Type'Size / System.Storage_Unit);
      else
         N := L.Max * 2;
         Tmp := Realloc (L.Els, N * Node_Type'Size / System.Storage_Unit);
      end if;
      L.Els := Tmp;
      L.Max := N;
   end List_Grow;

   procedure Append_Element (List: List_Type; Element: Node_Type)
   is
      L : List_Record renames Listt.Table (List);
   begin
      if L.Nbr >= L.Max then
         List_Grow (List);
      end if;
      L.Els (L.Nbr) := Element;
      L.Nbr := L.Nbr + 1;
   end Append_Element;

   -- Return the last element of the list, or null.
   function Get_Last_Element (List: List_Type) return Node_Type
   is
      L : List_Record renames Listt.Table (List);
   begin
      if L.Nbr = 0 then
         return Null_Node;
      else
         return L.Els (L.Nbr - 1);
      end if;
   end Get_Last_Element;

   -- Return the first element of the list, or null.
   function Get_First_Element (List: List_Type) return Node_Type is
   begin
      if Listt.Table (List).Nbr = 0 then
         return Null_Node;
      else
         return Listt.Table (List).Els (0);
      end if;
   end Get_First_Element;

   -- Add (append) an element only if it was not already present in the list.
   procedure Add_Element (List: List_Type; El: Node_Type)
   is
      Nbr : constant Natural := Get_Nbr_Elements (List);
   begin
      for I in 0 .. Nbr - 1 loop
         if Listt.Table (List).Els (I) = El then
            return;
         end if;
      end loop;

      Append_Element (List, El);
   end Add_Element;

   procedure Remove_Nth_Element (List: List_Type; N: Natural)
   is
      Nbr : constant Natural := Get_Nbr_Elements (List);
   begin
      if N >= Nbr then
         raise Program_Error;
      end if;
      for I in N .. Nbr - 2 loop
         Listt.Table (List).Els (I) := Listt.Table (List).Els (I + 1);
      end loop;
      Listt.Table (List).Nbr := Nbr - 1;
   end Remove_Nth_Element;

   procedure Set_Nbr_Elements (List: List_Type; N: Natural) is
   begin
      if N > Get_Nbr_Elements (List) then
         raise Program_Error;
      end if;
      List_Set_Nbr_Elements (List, N);
   end Set_Nbr_Elements;

   -- Return the position of the last element.
   -- Return -1 if the list is empty.
   function Get_Last_Element_Position (List: List_Type) return Integer is
   begin
      return Get_Nbr_Elements (List) - 1;
   end Get_Last_Element_Position;

   function Get_Nbr_Elements_Safe (List: List_Type) return Natural is
   begin
      if List = Null_List then
         return 0;
      else
         return Get_Nbr_Elements (List);
      end if;
   end Get_Nbr_Elements_Safe;

   -- Empty the list
   procedure Empty_List (List: List_Type) is
   begin
      Set_Nbr_Elements (List, 0);
   end Empty_List;

   --  Chain of unused lists.
   Free_Chain : List_Type := Null_List;

   function Create_List return List_Type
   is
      Res : List_Type;
   begin
      if Free_Chain = Null_List then
         Listt.Increment_Last;
         Res := Listt.Last;
      else
         Res := Free_Chain;
         Free_Chain := Listt.Table (Res).Next;
      end if;
      Listt.Table (Res) := List_Record'(Max => 0, Nbr => 0,
                                        Next => Null_List, Els => null);
      return Res;
   end Create_List;

   procedure Free (Ptr : Node_Array_Fat_Acc);
   pragma Import (C, Free, "free");

   procedure Destroy_List (List : in out List_Type)
   is
   begin
      if List = Null_List then
         return;
      end if;
      if Listt.Table (List).Max > 0 then
         Free (Listt.Table (List).Els);
         Listt.Table (List).Els := null;
      end if;
      Listt.Table (List).Next := Free_Chain;
      Free_Chain := List;
      List := Null_List;
   end Destroy_List;

   procedure Initialize is
   begin
      for I in Listt.First .. Listt.Last loop
         if Listt.Table (I).Els /= null then
            Free (Listt.Table (I).Els);
         end if;
      end loop;
      Listt.Free;
      Listt.Init;
   end Initialize;

end Lists;