File : elists.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                         GNAT COMPILER COMPONENTS                         --
   4 --                                                                          --
   5 --                               E L I S T S                                --
   6 --                                                                          --
   7 --                                 B o d y                                  --
   8 --                                                                          --
   9 --          Copyright (C) 1992-2015, Free Software Foundation, Inc.         --
  10 --                                                                          --
  11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  12 -- terms of the  GNU General Public License as published  by the Free Soft- --
  13 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  16 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  17 --                                                                          --
  18 --                                                                          --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 -- You should have received a copy of the GNU General Public License and    --
  23 -- a copy of the GCC Runtime Library Exception along with this program;     --
  24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  25 -- <http://www.gnu.org/licenses/>.                                          --
  26 --                                                                          --
  27 -- GNAT was originally developed  by the GNAT team at  New York University. --
  28 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
  29 --                                                                          --
  30 ------------------------------------------------------------------------------
  31 
  32 --  WARNING: There is a C version of this package. Any changes to this
  33 --  source file must be properly reflected in the C header a-elists.h.
  34 
  35 with Alloc;
  36 with Debug;  use Debug;
  37 with Output; use Output;
  38 with Table;
  39 
  40 package body Elists is
  41 
  42    -------------------------------------
  43    -- Implementation of Element Lists --
  44    -------------------------------------
  45 
  46    --  Element lists are composed of three types of entities. The element
  47    --  list header, which references the first and last elements of the
  48    --  list, the elements themselves which are singly linked and also
  49    --  reference the nodes on the list, and finally the nodes themselves.
  50    --  The following diagram shows how an element list is represented:
  51 
  52    --       +----------------------------------------------------+
  53    --       |  +------------------------------------------+      |
  54    --       |  |                                          |      |
  55    --       V  |                                          V      |
  56    --    +-----|--+    +-------+    +-------+         +-------+  |
  57    --    |  Elmt  |    |  1st  |    |  2nd  |         |  Last |  |
  58    --    |  List  |--->|  Elmt |--->|  Elmt  ---...-->|  Elmt ---+
  59    --    | Header |    |   |   |    |   |   |         |   |   |
  60    --    +--------+    +---|---+    +---|---+         +---|---+
  61    --                      |            |                 |
  62    --                      V            V                 V
  63    --                  +-------+    +-------+         +-------+
  64    --                  |       |    |       |         |       |
  65    --                  | Node1 |    | Node2 |         | Node3 |
  66    --                  |       |    |       |         |       |
  67    --                  +-------+    +-------+         +-------+
  68 
  69    --  The list header is an entry in the Elists table. The values used for
  70    --  the type Elist_Id are subscripts into this table. The First_Elmt field
  71    --  (Lfield1) points to the first element on the list, or to No_Elmt in the
  72    --  case of an empty list. Similarly the Last_Elmt field (Lfield2) points to
  73    --  the last element on the list or to No_Elmt in the case of an empty list.
  74 
  75    --  The elements themselves are entries in the Elmts table. The Next field
  76    --  of each entry points to the next element, or to the Elist header if this
  77    --  is the last item in the list. The Node field points to the node which
  78    --  is referenced by the corresponding list entry.
  79 
  80    -------------------------
  81    -- Element List Tables --
  82    -------------------------
  83 
  84    type Elist_Header is record
  85       First : Elmt_Id;
  86       Last  : Elmt_Id;
  87    end record;
  88 
  89    package Elists is new Table.Table (
  90      Table_Component_Type => Elist_Header,
  91      Table_Index_Type     => Elist_Id'Base,
  92      Table_Low_Bound      => First_Elist_Id,
  93      Table_Initial        => Alloc.Elists_Initial,
  94      Table_Increment      => Alloc.Elists_Increment,
  95      Table_Name           => "Elists");
  96 
  97    type Elmt_Item is record
  98       Node : Node_Or_Entity_Id;
  99       Next : Union_Id;
 100    end record;
 101 
 102    package Elmts is new Table.Table (
 103      Table_Component_Type => Elmt_Item,
 104      Table_Index_Type     => Elmt_Id'Base,
 105      Table_Low_Bound      => First_Elmt_Id,
 106      Table_Initial        => Alloc.Elmts_Initial,
 107      Table_Increment      => Alloc.Elmts_Increment,
 108      Table_Name           => "Elmts");
 109 
 110    -----------------
 111    -- Append_Elmt --
 112    -----------------
 113 
 114    procedure Append_Elmt (N : Node_Or_Entity_Id; To : Elist_Id) is
 115       L : constant Elmt_Id := Elists.Table (To).Last;
 116 
 117    begin
 118       Elmts.Increment_Last;
 119       Elmts.Table (Elmts.Last).Node := N;
 120       Elmts.Table (Elmts.Last).Next := Union_Id (To);
 121 
 122       if L = No_Elmt then
 123          Elists.Table (To).First := Elmts.Last;
 124       else
 125          Elmts.Table (L).Next := Union_Id (Elmts.Last);
 126       end if;
 127 
 128       Elists.Table (To).Last  := Elmts.Last;
 129 
 130       if Debug_Flag_N then
 131          Write_Str ("Append new element Elmt_Id = ");
 132          Write_Int (Int (Elmts.Last));
 133          Write_Str (" to list Elist_Id = ");
 134          Write_Int (Int (To));
 135          Write_Str (" referencing Node_Or_Entity_Id = ");
 136          Write_Int (Int (N));
 137          Write_Eol;
 138       end if;
 139    end Append_Elmt;
 140 
 141    ---------------------
 142    -- Append_New_Elmt --
 143    ---------------------
 144 
 145    procedure Append_New_Elmt (N : Node_Or_Entity_Id; To : in out Elist_Id) is
 146    begin
 147       if To = No_Elist then
 148          To := New_Elmt_List;
 149       end if;
 150 
 151       Append_Elmt (N, To);
 152    end Append_New_Elmt;
 153 
 154    ------------------------
 155    -- Append_Unique_Elmt --
 156    ------------------------
 157 
 158    procedure Append_Unique_Elmt (N : Node_Or_Entity_Id; To : Elist_Id) is
 159       Elmt : Elmt_Id;
 160    begin
 161       Elmt := First_Elmt (To);
 162       loop
 163          if No (Elmt) then
 164             Append_Elmt (N, To);
 165             return;
 166          elsif Node (Elmt) = N then
 167             return;
 168          else
 169             Next_Elmt (Elmt);
 170          end if;
 171       end loop;
 172    end Append_Unique_Elmt;
 173 
 174    --------------
 175    -- Contains --
 176    --------------
 177 
 178    function Contains (List : Elist_Id; N : Node_Or_Entity_Id) return Boolean is
 179       Elmt : Elmt_Id;
 180 
 181    begin
 182       if Present (List) then
 183          Elmt := First_Elmt (List);
 184          while Present (Elmt) loop
 185             if Node (Elmt) = N then
 186                return True;
 187             end if;
 188 
 189             Next_Elmt (Elmt);
 190          end loop;
 191       end if;
 192 
 193       return False;
 194    end Contains;
 195 
 196    --------------------
 197    -- Elists_Address --
 198    --------------------
 199 
 200    function Elists_Address return System.Address is
 201    begin
 202       return Elists.Table (First_Elist_Id)'Address;
 203    end Elists_Address;
 204 
 205    -------------------
 206    -- Elmts_Address --
 207    -------------------
 208 
 209    function Elmts_Address return System.Address is
 210    begin
 211       return Elmts.Table (First_Elmt_Id)'Address;
 212    end Elmts_Address;
 213 
 214    ----------------
 215    -- First_Elmt --
 216    ----------------
 217 
 218    function First_Elmt (List : Elist_Id) return Elmt_Id is
 219    begin
 220       pragma Assert (List > Elist_Low_Bound);
 221       return Elists.Table (List).First;
 222    end First_Elmt;
 223 
 224    ----------------
 225    -- Initialize --
 226    ----------------
 227 
 228    procedure Initialize is
 229    begin
 230       Elists.Init;
 231       Elmts.Init;
 232    end Initialize;
 233 
 234    -----------------------
 235    -- Insert_Elmt_After --
 236    -----------------------
 237 
 238    procedure Insert_Elmt_After (N : Node_Or_Entity_Id; Elmt : Elmt_Id) is
 239       Nxt : constant Union_Id := Elmts.Table (Elmt).Next;
 240 
 241    begin
 242       pragma Assert (Elmt /= No_Elmt);
 243 
 244       Elmts.Increment_Last;
 245       Elmts.Table (Elmts.Last).Node := N;
 246       Elmts.Table (Elmts.Last).Next := Nxt;
 247 
 248       Elmts.Table (Elmt).Next := Union_Id (Elmts.Last);
 249 
 250       if Nxt in Elist_Range then
 251          Elists.Table (Elist_Id (Nxt)).Last := Elmts.Last;
 252       end if;
 253    end Insert_Elmt_After;
 254 
 255    ------------------------
 256    -- Is_Empty_Elmt_List --
 257    ------------------------
 258 
 259    function Is_Empty_Elmt_List (List : Elist_Id) return Boolean is
 260    begin
 261       return Elists.Table (List).First = No_Elmt;
 262    end Is_Empty_Elmt_List;
 263 
 264    -------------------
 265    -- Last_Elist_Id --
 266    -------------------
 267 
 268    function Last_Elist_Id return Elist_Id is
 269    begin
 270       return Elists.Last;
 271    end Last_Elist_Id;
 272 
 273    ---------------
 274    -- Last_Elmt --
 275    ---------------
 276 
 277    function Last_Elmt (List : Elist_Id) return Elmt_Id is
 278    begin
 279       return Elists.Table (List).Last;
 280    end Last_Elmt;
 281 
 282    ------------------
 283    -- Last_Elmt_Id --
 284    ------------------
 285 
 286    function Last_Elmt_Id return Elmt_Id is
 287    begin
 288       return Elmts.Last;
 289    end Last_Elmt_Id;
 290 
 291    -----------------
 292    -- List_Length --
 293    -----------------
 294 
 295    function List_Length (List : Elist_Id) return Nat is
 296       Elmt : Elmt_Id;
 297       N    : Nat;
 298 
 299    begin
 300       if List = No_Elist then
 301          return 0;
 302 
 303       else
 304          N := 0;
 305          Elmt := First_Elmt (List);
 306          loop
 307             if No (Elmt) then
 308                return N;
 309             else
 310                N := N + 1;
 311                Next_Elmt (Elmt);
 312             end if;
 313          end loop;
 314       end if;
 315    end List_Length;
 316 
 317    ----------
 318    -- Lock --
 319    ----------
 320 
 321    procedure Lock is
 322    begin
 323       Elists.Locked := True;
 324       Elmts.Locked := True;
 325       Elists.Release;
 326       Elmts.Release;
 327    end Lock;
 328 
 329    --------------------
 330    -- New_Copy_Elist --
 331    --------------------
 332 
 333    function New_Copy_Elist (List : Elist_Id) return Elist_Id is
 334       Result : Elist_Id;
 335       Elmt   : Elmt_Id;
 336 
 337    begin
 338       if List = No_Elist then
 339          return No_Elist;
 340 
 341       --  Replicate the contents of the input list while preserving the
 342       --  original order.
 343 
 344       else
 345          Result := New_Elmt_List;
 346 
 347          Elmt := First_Elmt (List);
 348          while Present (Elmt) loop
 349             Append_Elmt (Node (Elmt), Result);
 350             Next_Elmt (Elmt);
 351          end loop;
 352 
 353          return Result;
 354       end if;
 355    end New_Copy_Elist;
 356 
 357    -------------------
 358    -- New_Elmt_List --
 359    -------------------
 360 
 361    function New_Elmt_List return Elist_Id is
 362    begin
 363       Elists.Increment_Last;
 364       Elists.Table (Elists.Last).First := No_Elmt;
 365       Elists.Table (Elists.Last).Last  := No_Elmt;
 366 
 367       if Debug_Flag_N then
 368          Write_Str ("Allocate new element list, returned ID = ");
 369          Write_Int (Int (Elists.Last));
 370          Write_Eol;
 371       end if;
 372 
 373       return Elists.Last;
 374    end New_Elmt_List;
 375 
 376    ---------------
 377    -- Next_Elmt --
 378    ---------------
 379 
 380    function Next_Elmt (Elmt : Elmt_Id) return Elmt_Id is
 381       N : constant Union_Id := Elmts.Table (Elmt).Next;
 382 
 383    begin
 384       if N in Elist_Range then
 385          return No_Elmt;
 386       else
 387          return Elmt_Id (N);
 388       end if;
 389    end Next_Elmt;
 390 
 391    procedure Next_Elmt (Elmt : in out Elmt_Id) is
 392    begin
 393       Elmt := Next_Elmt (Elmt);
 394    end Next_Elmt;
 395 
 396    --------
 397    -- No --
 398    --------
 399 
 400    function No (List : Elist_Id) return Boolean is
 401    begin
 402       return List = No_Elist;
 403    end No;
 404 
 405    function No (Elmt : Elmt_Id) return Boolean is
 406    begin
 407       return Elmt = No_Elmt;
 408    end No;
 409 
 410    ----------
 411    -- Node --
 412    ----------
 413 
 414    function Node (Elmt : Elmt_Id) return Node_Or_Entity_Id is
 415    begin
 416       if Elmt = No_Elmt then
 417          return Empty;
 418       else
 419          return Elmts.Table (Elmt).Node;
 420       end if;
 421    end Node;
 422 
 423    ----------------
 424    -- Num_Elists --
 425    ----------------
 426 
 427    function Num_Elists return Nat is
 428    begin
 429       return Int (Elmts.Last) - Int (Elmts.First) + 1;
 430    end Num_Elists;
 431 
 432    ------------------
 433    -- Prepend_Elmt --
 434    ------------------
 435 
 436    procedure Prepend_Elmt (N : Node_Or_Entity_Id; To : Elist_Id) is
 437       F : constant Elmt_Id := Elists.Table (To).First;
 438 
 439    begin
 440       Elmts.Increment_Last;
 441       Elmts.Table (Elmts.Last).Node := N;
 442 
 443       if F = No_Elmt then
 444          Elists.Table (To).Last := Elmts.Last;
 445          Elmts.Table (Elmts.Last).Next := Union_Id (To);
 446       else
 447          Elmts.Table (Elmts.Last).Next := Union_Id (F);
 448       end if;
 449 
 450       Elists.Table (To).First  := Elmts.Last;
 451    end Prepend_Elmt;
 452 
 453    -------------
 454    -- Present --
 455    -------------
 456 
 457    function Present (List : Elist_Id) return Boolean is
 458    begin
 459       return List /= No_Elist;
 460    end Present;
 461 
 462    function Present (Elmt : Elmt_Id) return Boolean is
 463    begin
 464       return Elmt /= No_Elmt;
 465    end Present;
 466 
 467    ------------
 468    -- Remove --
 469    ------------
 470 
 471    procedure Remove (List : Elist_Id; N : Node_Or_Entity_Id) is
 472       Elmt : Elmt_Id;
 473 
 474    begin
 475       if Present (List) then
 476          Elmt := First_Elmt (List);
 477          while Present (Elmt) loop
 478             if Node (Elmt) = N then
 479                Remove_Elmt (List, Elmt);
 480                exit;
 481             end if;
 482 
 483             Next_Elmt (Elmt);
 484          end loop;
 485       end if;
 486    end Remove;
 487 
 488    -----------------
 489    -- Remove_Elmt --
 490    -----------------
 491 
 492    procedure Remove_Elmt (List : Elist_Id; Elmt : Elmt_Id) is
 493       Nxt : Elmt_Id;
 494       Prv : Elmt_Id;
 495 
 496    begin
 497       Nxt := Elists.Table (List).First;
 498 
 499       --  Case of removing only element in the list
 500 
 501       if Elmts.Table (Nxt).Next in Elist_Range then
 502          pragma Assert (Nxt = Elmt);
 503 
 504          Elists.Table (List).First := No_Elmt;
 505          Elists.Table (List).Last  := No_Elmt;
 506 
 507       --  Case of removing the first element in the list
 508 
 509       elsif Nxt = Elmt then
 510          Elists.Table (List).First := Elmt_Id (Elmts.Table (Nxt).Next);
 511 
 512       --  Case of removing second or later element in the list
 513 
 514       else
 515          loop
 516             Prv := Nxt;
 517             Nxt := Elmt_Id (Elmts.Table (Prv).Next);
 518             exit when Nxt = Elmt
 519               or else Elmts.Table (Nxt).Next in Elist_Range;
 520          end loop;
 521 
 522          pragma Assert (Nxt = Elmt);
 523 
 524          Elmts.Table (Prv).Next := Elmts.Table (Nxt).Next;
 525 
 526          if Elmts.Table (Prv).Next in Elist_Range then
 527             Elists.Table (List).Last := Prv;
 528          end if;
 529       end if;
 530    end Remove_Elmt;
 531 
 532    ----------------------
 533    -- Remove_Last_Elmt --
 534    ----------------------
 535 
 536    procedure Remove_Last_Elmt (List : Elist_Id) is
 537       Nxt : Elmt_Id;
 538       Prv : Elmt_Id;
 539 
 540    begin
 541       Nxt := Elists.Table (List).First;
 542 
 543       --  Case of removing only element in the list
 544 
 545       if Elmts.Table (Nxt).Next in Elist_Range then
 546          Elists.Table (List).First := No_Elmt;
 547          Elists.Table (List).Last  := No_Elmt;
 548 
 549       --  Case of at least two elements in list
 550 
 551       else
 552          loop
 553             Prv := Nxt;
 554             Nxt := Elmt_Id (Elmts.Table (Prv).Next);
 555             exit when Elmts.Table (Nxt).Next in Elist_Range;
 556          end loop;
 557 
 558          Elmts.Table (Prv).Next   := Elmts.Table (Nxt).Next;
 559          Elists.Table (List).Last := Prv;
 560       end if;
 561    end Remove_Last_Elmt;
 562 
 563    ------------------
 564    -- Replace_Elmt --
 565    ------------------
 566 
 567    procedure Replace_Elmt (Elmt : Elmt_Id; New_Node : Node_Or_Entity_Id) is
 568    begin
 569       Elmts.Table (Elmt).Node := New_Node;
 570    end Replace_Elmt;
 571 
 572    ---------------
 573    -- Tree_Read --
 574    ---------------
 575 
 576    procedure Tree_Read is
 577    begin
 578       Elists.Tree_Read;
 579       Elmts.Tree_Read;
 580    end Tree_Read;
 581 
 582    ----------------
 583    -- Tree_Write --
 584    ----------------
 585 
 586    procedure Tree_Write is
 587    begin
 588       Elists.Tree_Write;
 589       Elmts.Tree_Write;
 590    end Tree_Write;
 591 
 592    ------------
 593    -- Unlock --
 594    ------------
 595 
 596    procedure Unlock is
 597    begin
 598       Elists.Locked := False;
 599       Elmts.Locked := False;
 600    end Unlock;
 601 
 602 end Elists;