| ------------------------------------------------------------------------------ |
| -- -- |
| -- 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; |