1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 1992-2023, Free Software Foundation, Inc. --
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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 -- WARNING: There is a C version of this package. Any changes to this
27 -- source file must be properly reflected in the C header a-elists.h.
30 with Debug
; use Debug
;
31 with Output
; use Output
;
34 package body Elists
is
36 -------------------------------------
37 -- Implementation of Element Lists --
38 -------------------------------------
40 -- Element lists are composed of three types of entities. The element
41 -- list header, which references the first and last elements of the
42 -- list, the elements themselves which are singly linked and also
43 -- reference the nodes on the list, and finally the nodes themselves.
44 -- The following diagram shows how an element list is represented:
46 -- +----------------------------------------------------+
47 -- | +------------------------------------------+ |
50 -- +-----|--+ +-------+ +-------+ +-------+ |
51 -- | Elmt | | 1st | | 2nd | | Last | |
52 -- | List |--->| Elmt |--->| Elmt ---...-->| Elmt ---+
53 -- | Header | | | | | | | | | |
54 -- +--------+ +---|---+ +---|---+ +---|---+
57 -- +-------+ +-------+ +-------+
59 -- | Node1 | | Node2 | | Node3 |
61 -- +-------+ +-------+ +-------+
63 -- The list header is an entry in the Elists table. The values used for
64 -- the type Elist_Id are subscripts into this table. The First_Elmt field
65 -- (Lfield1) points to the first element on the list, or to No_Elmt in the
66 -- case of an empty list. Similarly the Last_Elmt field (Lfield2) points to
67 -- the last element on the list or to No_Elmt in the case of an empty list.
69 -- The elements themselves are entries in the Elmts table. The Next field
70 -- of each entry points to the next element, or to the Elist header if this
71 -- is the last item in the list. The Node field points to the node which
72 -- is referenced by the corresponding list entry.
74 -------------------------
75 -- Element List Tables --
76 -------------------------
78 type Elist_Header
is record
83 package Elists
is new Table
.Table
(
84 Table_Component_Type
=> Elist_Header
,
85 Table_Index_Type
=> Elist_Id
'Base,
86 Table_Low_Bound
=> First_Elist_Id
,
87 Table_Initial
=> Alloc
.Elists_Initial
,
88 Table_Increment
=> Alloc
.Elists_Increment
,
89 Table_Name
=> "Elists");
91 type Elmt_Item
is record
92 Node
: Node_Or_Entity_Id
;
96 package Elmts
is new Table
.Table
(
97 Table_Component_Type
=> Elmt_Item
,
98 Table_Index_Type
=> Elmt_Id
'Base,
99 Table_Low_Bound
=> First_Elmt_Id
,
100 Table_Initial
=> Alloc
.Elmts_Initial
,
101 Table_Increment
=> Alloc
.Elmts_Increment
,
102 Table_Name
=> "Elmts");
108 procedure Append_Elmt
(N
: Node_Or_Entity_Id
; To
: Elist_Id
) is
109 L
: constant Elmt_Id
:= Elists
.Table
(To
).Last
;
112 Elmts
.Increment_Last
;
113 Elmts
.Table
(Elmts
.Last
).Node
:= N
;
114 Elmts
.Table
(Elmts
.Last
).Next
:= Union_Id
(To
);
117 Elists
.Table
(To
).First
:= Elmts
.Last
;
119 Elmts
.Table
(L
).Next
:= Union_Id
(Elmts
.Last
);
122 Elists
.Table
(To
).Last
:= Elmts
.Last
;
125 Write_Str
("Append new element Elmt_Id = ");
126 Write_Int
(Int
(Elmts
.Last
));
127 Write_Str
(" to list Elist_Id = ");
128 Write_Int
(Int
(To
));
129 Write_Str
(" referencing Node_Or_Entity_Id = ");
135 ---------------------
136 -- Append_New_Elmt --
137 ---------------------
139 procedure Append_New_Elmt
(N
: Node_Or_Entity_Id
; To
: in out Elist_Id
) is
141 if To
= No_Elist
then
148 ------------------------
149 -- Append_Unique_Elmt --
150 ------------------------
152 procedure Append_Unique_Elmt
(N
: Node_Or_Entity_Id
; To
: Elist_Id
) is
155 Elmt
:= First_Elmt
(To
);
160 elsif Node
(Elmt
) = N
then
166 end Append_Unique_Elmt
;
172 function Contains
(List
: Elist_Id
; N
: Node_Or_Entity_Id
) return Boolean is
176 if Present
(List
) then
177 Elmt
:= First_Elmt
(List
);
178 while Present
(Elmt
) loop
179 if Node
(Elmt
) = N
then
194 function Elists_Address
return System
.Address
is
196 return Elists
.Table
(First_Elist_Id
)'Address;
203 function Elmts_Address
return System
.Address
is
205 return Elmts
.Table
(First_Elmt_Id
)'Address;
212 function First_Elmt
(List
: Elist_Id
) return Elmt_Id
is
214 pragma Assert
(List
> Elist_Low_Bound
);
215 return Elists
.Table
(List
).First
;
222 procedure Initialize
is
228 -----------------------
229 -- Insert_Elmt_After --
230 -----------------------
232 procedure Insert_Elmt_After
(N
: Node_Or_Entity_Id
; Elmt
: Elmt_Id
) is
233 Nxt
: constant Union_Id
:= Elmts
.Table
(Elmt
).Next
;
236 pragma Assert
(Elmt
/= No_Elmt
);
238 Elmts
.Increment_Last
;
239 Elmts
.Table
(Elmts
.Last
).Node
:= N
;
240 Elmts
.Table
(Elmts
.Last
).Next
:= Nxt
;
242 Elmts
.Table
(Elmt
).Next
:= Union_Id
(Elmts
.Last
);
244 if Nxt
in Elist_Range
then
245 Elists
.Table
(Elist_Id
(Nxt
)).Last
:= Elmts
.Last
;
247 end Insert_Elmt_After
;
249 ------------------------
250 -- Is_Empty_Elmt_List --
251 ------------------------
253 function Is_Empty_Elmt_List
(List
: Elist_Id
) return Boolean is
255 return Elists
.Table
(List
).First
= No_Elmt
;
256 end Is_Empty_Elmt_List
;
262 function Last_Elist_Id
return Elist_Id
is
271 function Last_Elmt
(List
: Elist_Id
) return Elmt_Id
is
273 return Elists
.Table
(List
).Last
;
280 function Last_Elmt_Id
return Elmt_Id
is
289 function List_Length
(List
: Elist_Id
) return Nat
is
294 if List
= No_Elist
then
299 Elmt
:= First_Elmt
(List
);
318 Elists
.Locked
:= True;
320 Elmts
.Locked
:= True;
327 function New_Copy_Elist
(List
: Elist_Id
) return Elist_Id
is
332 if List
= No_Elist
then
335 -- Replicate the contents of the input list while preserving the
339 Result
:= New_Elmt_List
;
341 Elmt
:= First_Elmt
(List
);
342 while Present
(Elmt
) loop
343 Append_Elmt
(Node
(Elmt
), Result
);
355 function New_Elmt_List
return Elist_Id
is
357 Elists
.Increment_Last
;
358 Elists
.Table
(Elists
.Last
).First
:= No_Elmt
;
359 Elists
.Table
(Elists
.Last
).Last
:= No_Elmt
;
362 Write_Str
("Allocate new element list, returned ID = ");
363 Write_Int
(Int
(Elists
.Last
));
374 function New_Elmt_List
(Elmt1
: Node_Or_Entity_Id
)
377 L
: constant Elist_Id
:= New_Elmt_List
;
379 Append_Elmt
(Elmt1
, L
);
387 function New_Elmt_List
388 (Elmt1
: Node_Or_Entity_Id
;
389 Elmt2
: Node_Or_Entity_Id
) return Elist_Id
391 L
: constant Elist_Id
:= New_Elmt_List
(Elmt1
);
393 Append_Elmt
(Elmt2
, L
);
401 function New_Elmt_List
402 (Elmt1
: Node_Or_Entity_Id
;
403 Elmt2
: Node_Or_Entity_Id
;
404 Elmt3
: Node_Or_Entity_Id
) return Elist_Id
406 L
: constant Elist_Id
:= New_Elmt_List
(Elmt1
, Elmt2
);
408 Append_Elmt
(Elmt3
, L
);
416 function New_Elmt_List
417 (Elmt1
: Node_Or_Entity_Id
;
418 Elmt2
: Node_Or_Entity_Id
;
419 Elmt3
: Node_Or_Entity_Id
;
420 Elmt4
: Node_Or_Entity_Id
) return Elist_Id
422 L
: constant Elist_Id
:= New_Elmt_List
(Elmt1
, Elmt2
, Elmt3
);
424 Append_Elmt
(Elmt4
, L
);
432 function Next_Elmt
(Elmt
: Elmt_Id
) return Elmt_Id
is
433 N
: constant Union_Id
:= Elmts
.Table
(Elmt
).Next
;
436 if N
in Elist_Range
then
443 procedure Next_Elmt
(Elmt
: in out Elmt_Id
) is
445 Elmt
:= Next_Elmt
(Elmt
);
452 function No
(List
: Elist_Id
) return Boolean is
454 return List
= No_Elist
;
457 function No
(Elmt
: Elmt_Id
) return Boolean is
459 return Elmt
= No_Elmt
;
466 function Node
(Elmt
: Elmt_Id
) return Node_Or_Entity_Id
is
468 if Elmt
= No_Elmt
then
471 return Elmts
.Table
(Elmt
).Node
;
479 function Num_Elists
return Nat
is
481 return Int
(Elmts
.Last
) - Int
(Elmts
.First
) + 1;
488 procedure Prepend_Elmt
(N
: Node_Or_Entity_Id
; To
: Elist_Id
) is
489 F
: constant Elmt_Id
:= Elists
.Table
(To
).First
;
492 Elmts
.Increment_Last
;
493 Elmts
.Table
(Elmts
.Last
).Node
:= N
;
496 Elists
.Table
(To
).Last
:= Elmts
.Last
;
497 Elmts
.Table
(Elmts
.Last
).Next
:= Union_Id
(To
);
499 Elmts
.Table
(Elmts
.Last
).Next
:= Union_Id
(F
);
502 Elists
.Table
(To
).First
:= Elmts
.Last
;
505 -------------------------
506 -- Prepend_Unique_Elmt --
507 -------------------------
509 procedure Prepend_Unique_Elmt
(N
: Node_Or_Entity_Id
; To
: Elist_Id
) is
511 if not Contains
(To
, N
) then
512 Prepend_Elmt
(N
, To
);
514 end Prepend_Unique_Elmt
;
520 function Present
(List
: Elist_Id
) return Boolean is
522 return List
/= No_Elist
;
525 function Present
(Elmt
: Elmt_Id
) return Boolean is
527 return Elmt
/= No_Elmt
;
534 procedure Remove
(List
: Elist_Id
; N
: Node_Or_Entity_Id
) is
538 if Present
(List
) then
539 Elmt
:= First_Elmt
(List
);
540 while Present
(Elmt
) loop
541 if Node
(Elmt
) = N
then
542 Remove_Elmt
(List
, Elmt
);
555 procedure Remove_Elmt
(List
: Elist_Id
; Elmt
: Elmt_Id
) is
560 Nxt
:= Elists
.Table
(List
).First
;
562 -- Case of removing only element in the list
564 if Elmts
.Table
(Nxt
).Next
in Elist_Range
then
565 pragma Assert
(Nxt
= Elmt
);
567 Elists
.Table
(List
).First
:= No_Elmt
;
568 Elists
.Table
(List
).Last
:= No_Elmt
;
570 -- Case of removing the first element in the list
572 elsif Nxt
= Elmt
then
573 Elists
.Table
(List
).First
:= Elmt_Id
(Elmts
.Table
(Nxt
).Next
);
575 -- Case of removing second or later element in the list
580 Nxt
:= Elmt_Id
(Elmts
.Table
(Prv
).Next
);
582 or else Elmts
.Table
(Nxt
).Next
in Elist_Range
;
585 pragma Assert
(Nxt
= Elmt
);
587 Elmts
.Table
(Prv
).Next
:= Elmts
.Table
(Nxt
).Next
;
589 if Elmts
.Table
(Prv
).Next
in Elist_Range
then
590 Elists
.Table
(List
).Last
:= Prv
;
595 ----------------------
596 -- Remove_Last_Elmt --
597 ----------------------
599 procedure Remove_Last_Elmt
(List
: Elist_Id
) is
604 Nxt
:= Elists
.Table
(List
).First
;
606 -- Case of removing only element in the list
608 if Elmts
.Table
(Nxt
).Next
in Elist_Range
then
609 Elists
.Table
(List
).First
:= No_Elmt
;
610 Elists
.Table
(List
).Last
:= No_Elmt
;
612 -- Case of at least two elements in list
617 Nxt
:= Elmt_Id
(Elmts
.Table
(Prv
).Next
);
618 exit when Elmts
.Table
(Nxt
).Next
in Elist_Range
;
621 Elmts
.Table
(Prv
).Next
:= Elmts
.Table
(Nxt
).Next
;
622 Elists
.Table
(List
).Last
:= Prv
;
624 end Remove_Last_Elmt
;
630 procedure Replace_Elmt
(Elmt
: Elmt_Id
; New_Node
: Node_Or_Entity_Id
) is
632 Elmts
.Table
(Elmt
).Node
:= New_Node
;
641 Elists
.Locked
:= False;
642 Elmts
.Locked
:= False;