------------------------------------------------------------------------------ -- -- -- GNAT COMPILER COMPONENTS -- -- -- -- E L I S T S -- -- -- -- B o d y -- -- -- -- Copyright (C) 1992-2022, Free Software Foundation, 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- -- -- ware Foundation; either version 3, 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 -- -- Public License distributed with GNAT; see file COPYING3. If not, go to -- -- http://www.gnu.org/licenses for a complete copy of the license. -- -- -- -- GNAT was originally developed by the GNAT team at New York University. -- -- Extensive contributions were provided by Ada Core Technologies Inc. -- -- -- ------------------------------------------------------------------------------ -- WARNING: There is a C version of this package. Any changes to this -- source file must be properly reflected in the C header a-elists.h. with Alloc; with Debug; use Debug; with Output; use Output; with Table; package body Elists is ------------------------------------- -- Implementation of Element Lists -- ------------------------------------- -- Element lists are composed of three types of entities. The element -- list header, which references the first and last elements of the -- list, the elements themselves which are singly linked and also -- reference the nodes on the list, and finally the nodes themselves. -- The following diagram shows how an element list is represented: -- +----------------------------------------------------+ -- | +------------------------------------------+ | -- | | | | -- V | V | -- +-----|--+ +-------+ +-------+ +-------+ | -- | Elmt | | 1st | | 2nd | | Last | | -- | List |--->| Elmt |--->| Elmt ---...-->| Elmt ---+ -- | Header | | | | | | | | | | -- +--------+ +---|---+ +---|---+ +---|---+ -- | | | -- V V V -- +-------+ +-------+ +-------+ -- | | | | | | -- | Node1 | | Node2 | | Node3 | -- | | | | | | -- +-------+ +-------+ +-------+ -- The list header is an entry in the Elists table. The values used for -- the type Elist_Id are subscripts into this table. The First_Elmt field -- (Lfield1) points to the first element on the list, or to No_Elmt in the -- case of an empty list. Similarly the Last_Elmt field (Lfield2) points to -- the last element on the list or to No_Elmt in the case of an empty list. -- The elements themselves are entries in the Elmts table. The Next field -- of each entry points to the next element, or to the Elist header if this -- is the last item in the list. The Node field points to the node which -- is referenced by the corresponding list entry. ------------------------- -- Element List Tables -- ------------------------- type Elist_Header is record First : Elmt_Id; Last : Elmt_Id; end record; package Elists is new Table.Table ( Table_Component_Type => Elist_Header, Table_Index_Type => Elist_Id'Base, Table_Low_Bound => First_Elist_Id, Table_Initial => Alloc.Elists_Initial, Table_Increment => Alloc.Elists_Increment, Table_Name => "Elists"); type Elmt_Item is record Node : Node_Or_Entity_Id; Next : Union_Id; end record; package Elmts is new Table.Table ( Table_Component_Type => Elmt_Item, Table_Index_Type => Elmt_Id'Base, Table_Low_Bound => First_Elmt_Id, Table_Initial => Alloc.Elmts_Initial, Table_Increment => Alloc.Elmts_Increment, Table_Name => "Elmts"); ----------------- -- Append_Elmt -- ----------------- procedure Append_Elmt (N : Node_Or_Entity_Id; To : Elist_Id) is L : constant Elmt_Id := Elists.Table (To).Last; begin Elmts.Increment_Last; Elmts.Table (Elmts.Last).Node := N; Elmts.Table (Elmts.Last).Next := Union_Id (To); if L = No_Elmt then Elists.Table (To).First := Elmts.Last; else Elmts.Table (L).Next := Union_Id (Elmts.Last); end if; Elists.Table (To).Last := Elmts.Last; if Debug_Flag_N then Write_Str ("Append new element Elmt_Id = "); Write_Int (Int (Elmts.Last)); Write_Str (" to list Elist_Id = "); Write_Int (Int (To)); Write_Str (" referencing Node_Or_Entity_Id = "); Write_Int (Int (N)); Write_Eol; end if; end Append_Elmt; --------------------- -- Append_New_Elmt -- --------------------- procedure Append_New_Elmt (N : Node_Or_Entity_Id; To : in out Elist_Id) is begin if To = No_Elist then To := New_Elmt_List; end if; Append_Elmt (N, To); end Append_New_Elmt; ------------------------ -- Append_Unique_Elmt -- ------------------------ procedure Append_Unique_Elmt (N : Node_Or_Entity_Id; To : Elist_Id) is Elmt : Elmt_Id; begin Elmt := First_Elmt (To); loop if No (Elmt) then Append_Elmt (N, To); return; elsif Node (Elmt) = N then return; else Next_Elmt (Elmt); end if; end loop; end Append_Unique_Elmt; -------------- -- Contains -- -------------- function Contains (List : Elist_Id; N : Node_Or_Entity_Id) return Boolean is Elmt : Elmt_Id; begin if Present (List) then Elmt := First_Elmt (List); while Present (Elmt) loop if Node (Elmt) = N then return True; end if; Next_Elmt (Elmt); end loop; end if; return False; end Contains; -------------------- -- Elists_Address -- -------------------- function Elists_Address return System.Address is begin return Elists.Table (First_Elist_Id)'Address; end Elists_Address; ------------------- -- Elmts_Address -- ------------------- function Elmts_Address return System.Address is begin return Elmts.Table (First_Elmt_Id)'Address; end Elmts_Address; ---------------- -- First_Elmt -- ---------------- function First_Elmt (List : Elist_Id) return Elmt_Id is begin pragma Assert (List > Elist_Low_Bound); return Elists.Table (List).First; end First_Elmt; ---------------- -- Initialize -- ---------------- procedure Initialize is begin Elists.Init; Elmts.Init; end Initialize; ----------------------- -- Insert_Elmt_After -- ----------------------- procedure Insert_Elmt_After (N : Node_Or_Entity_Id; Elmt : Elmt_Id) is Nxt : constant Union_Id := Elmts.Table (Elmt).Next; begin pragma Assert (Elmt /= No_Elmt); Elmts.Increment_Last; Elmts.Table (Elmts.Last).Node := N; Elmts.Table (Elmts.Last).Next := Nxt; Elmts.Table (Elmt).Next := Union_Id (Elmts.Last); if Nxt in Elist_Range then Elists.Table (Elist_Id (Nxt)).Last := Elmts.Last; end if; end Insert_Elmt_After; ------------------------ -- Is_Empty_Elmt_List -- ------------------------ function Is_Empty_Elmt_List (List : Elist_Id) return Boolean is begin return Elists.Table (List).First = No_Elmt; end Is_Empty_Elmt_List; ------------------- -- Last_Elist_Id -- ------------------- function Last_Elist_Id return Elist_Id is begin return Elists.Last; end Last_Elist_Id; --------------- -- Last_Elmt -- --------------- function Last_Elmt (List : Elist_Id) return Elmt_Id is begin return Elists.Table (List).Last; end Last_Elmt; ------------------ -- Last_Elmt_Id -- ------------------ function Last_Elmt_Id return Elmt_Id is begin return Elmts.Last; end Last_Elmt_Id; ----------------- -- List_Length -- ----------------- function List_Length (List : Elist_Id) return Nat is Elmt : Elmt_Id; N : Nat; begin if List = No_Elist then return 0; else N := 0; Elmt := First_Elmt (List); loop if No (Elmt) then return N; else N := N + 1; Next_Elmt (Elmt); end if; end loop; end if; end List_Length; ---------- -- Lock -- ---------- procedure Lock is begin Elists.Release; Elists.Locked := True; Elmts.Release; Elmts.Locked := True; end Lock; -------------------- -- New_Copy_Elist -- -------------------- function New_Copy_Elist (List : Elist_Id) return Elist_Id is Result : Elist_Id; Elmt : Elmt_Id; begin if List = No_Elist then return No_Elist; -- Replicate the contents of the input list while preserving the -- original order. else Result := New_Elmt_List; Elmt := First_Elmt (List); while Present (Elmt) loop Append_Elmt (Node (Elmt), Result); Next_Elmt (Elmt); end loop; return Result; end if; end New_Copy_Elist; ------------------- -- New_Elmt_List -- ------------------- function New_Elmt_List return Elist_Id is begin Elists.Increment_Last; Elists.Table (Elists.Last).First := No_Elmt; Elists.Table (Elists.Last).Last := No_Elmt; if Debug_Flag_N then Write_Str ("Allocate new element list, returned ID = "); Write_Int (Int (Elists.Last)); Write_Eol; end if; return Elists.Last; end New_Elmt_List; ------------------- -- New_Elmt_List -- ------------------- function New_Elmt_List (Elmt1 : Node_Or_Entity_Id) return Elist_Id is L : constant Elist_Id := New_Elmt_List; begin Append_Elmt (Elmt1, L); return L; end New_Elmt_List; ------------------- -- New_Elmt_List -- ------------------- function New_Elmt_List (Elmt1 : Node_Or_Entity_Id; Elmt2 : Node_Or_Entity_Id) return Elist_Id is L : constant Elist_Id := New_Elmt_List (Elmt1); begin Append_Elmt (Elmt2, L); return L; end New_Elmt_List; ------------------- -- New_Elmt_List -- ------------------- function New_Elmt_List (Elmt1 : Node_Or_Entity_Id; Elmt2 : Node_Or_Entity_Id; Elmt3 : Node_Or_Entity_Id) return Elist_Id is L : constant Elist_Id := New_Elmt_List (Elmt1, Elmt2); begin Append_Elmt (Elmt3, L); return L; end New_Elmt_List; ------------------- -- New_Elmt_List -- ------------------- function New_Elmt_List (Elmt1 : Node_Or_Entity_Id; Elmt2 : Node_Or_Entity_Id; Elmt3 : Node_Or_Entity_Id; Elmt4 : Node_Or_Entity_Id) return Elist_Id is L : constant Elist_Id := New_Elmt_List (Elmt1, Elmt2, Elmt3); begin Append_Elmt (Elmt4, L); return L; end New_Elmt_List; --------------- -- Next_Elmt -- --------------- function Next_Elmt (Elmt : Elmt_Id) return Elmt_Id is N : constant Union_Id := Elmts.Table (Elmt).Next; begin if N in Elist_Range then return No_Elmt; else return Elmt_Id (N); end if; end Next_Elmt; procedure Next_Elmt (Elmt : in out Elmt_Id) is begin Elmt := Next_Elmt (Elmt); end Next_Elmt; -------- -- No -- -------- function No (List : Elist_Id) return Boolean is begin return List = No_Elist; end No; function No (Elmt : Elmt_Id) return Boolean is begin return Elmt = No_Elmt; end No; ---------- -- Node -- ---------- function Node (Elmt : Elmt_Id) return Node_Or_Entity_Id is begin if Elmt = No_Elmt then return Empty; else return Elmts.Table (Elmt).Node; end if; end Node; ---------------- -- Num_Elists -- ---------------- function Num_Elists return Nat is begin return Int (Elmts.Last) - Int (Elmts.First) + 1; end Num_Elists; ------------------ -- Prepend_Elmt -- ------------------ procedure Prepend_Elmt (N : Node_Or_Entity_Id; To : Elist_Id) is F : constant Elmt_Id := Elists.Table (To).First; begin Elmts.Increment_Last; Elmts.Table (Elmts.Last).Node := N; if F = No_Elmt then Elists.Table (To).Last := Elmts.Last; Elmts.Table (Elmts.Last).Next := Union_Id (To); else Elmts.Table (Elmts.Last).Next := Union_Id (F); end if; Elists.Table (To).First := Elmts.Last; end Prepend_Elmt; ------------------------- -- Prepend_Unique_Elmt -- ------------------------- procedure Prepend_Unique_Elmt (N : Node_Or_Entity_Id; To : Elist_Id) is begin if not Contains (To, N) then Prepend_Elmt (N, To); end if; end Prepend_Unique_Elmt; ------------- -- Present -- ------------- function Present (List : Elist_Id) return Boolean is begin return List /= No_Elist; end Present; function Present (Elmt : Elmt_Id) return Boolean is begin return Elmt /= No_Elmt; end Present; ------------ -- Remove -- ------------ procedure Remove (List : Elist_Id; N : Node_Or_Entity_Id) is Elmt : Elmt_Id; begin if Present (List) then Elmt := First_Elmt (List); while Present (Elmt) loop if Node (Elmt) = N then Remove_Elmt (List, Elmt); exit; end if; Next_Elmt (Elmt); end loop; end if; end Remove; ----------------- -- Remove_Elmt -- ----------------- procedure Remove_Elmt (List : Elist_Id; Elmt : Elmt_Id) is Nxt : Elmt_Id; Prv : Elmt_Id; begin Nxt := Elists.Table (List).First; -- Case of removing only element in the list if Elmts.Table (Nxt).Next in Elist_Range then pragma Assert (Nxt = Elmt); Elists.Table (List).First := No_Elmt; Elists.Table (List).Last := No_Elmt; -- Case of removing the first element in the list elsif Nxt = Elmt then Elists.Table (List).First := Elmt_Id (Elmts.Table (Nxt).Next); -- Case of removing second or later element in the list else loop Prv := Nxt; Nxt := Elmt_Id (Elmts.Table (Prv).Next); exit when Nxt = Elmt or else Elmts.Table (Nxt).Next in Elist_Range; end loop; pragma Assert (Nxt = Elmt); Elmts.Table (Prv).Next := Elmts.Table (Nxt).Next; if Elmts.Table (Prv).Next in Elist_Range then Elists.Table (List).Last := Prv; end if; end if; end Remove_Elmt; ---------------------- -- Remove_Last_Elmt -- ---------------------- procedure Remove_Last_Elmt (List : Elist_Id) is Nxt : Elmt_Id; Prv : Elmt_Id; begin Nxt := Elists.Table (List).First; -- Case of removing only element in the list if Elmts.Table (Nxt).Next in Elist_Range then Elists.Table (List).First := No_Elmt; Elists.Table (List).Last := No_Elmt; -- Case of at least two elements in list else loop Prv := Nxt; Nxt := Elmt_Id (Elmts.Table (Prv).Next); exit when Elmts.Table (Nxt).Next in Elist_Range; end loop; Elmts.Table (Prv).Next := Elmts.Table (Nxt).Next; Elists.Table (List).Last := Prv; end if; end Remove_Last_Elmt; ------------------ -- Replace_Elmt -- ------------------ procedure Replace_Elmt (Elmt : Elmt_Id; New_Node : Node_Or_Entity_Id) is begin Elmts.Table (Elmt).Node := New_Node; end Replace_Elmt; ------------ -- Unlock -- ------------ procedure Unlock is begin Elists.Locked := False; Elmts.Locked := False; end Unlock; end Elists;