1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2004-2018, 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. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
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/>. --
27 -- This unit was originally developed by Matthew J Heaney. --
28 ------------------------------------------------------------------------------
30 with Ada
.Unchecked_Deallocation
;
32 with System
; use type System
.Address
;
34 package body Ada
.Containers
.Indefinite_Doubly_Linked_Lists
is
36 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
37 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
38 -- See comment in Ada.Containers.Helpers
41 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
43 -----------------------
44 -- Local Subprograms --
45 -----------------------
47 procedure Free
(X
: in out Node_Access
);
49 procedure Insert_Internal
50 (Container
: in out List
;
52 New_Node
: Node_Access
);
54 procedure Splice_Internal
55 (Target
: in out List
;
57 Source
: in out List
);
59 procedure Splice_Internal
60 (Target
: in out List
;
63 Position
: Node_Access
);
65 function Vet
(Position
: Cursor
) return Boolean;
66 -- Checks invariants of the cursor and its designated container, as a
67 -- simple way of detecting dangling references (see operation Free for a
68 -- description of the detection mechanism), returning True if all checks
69 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
70 -- so the checks are performed only when assertions are enabled.
76 function "=" (Left
, Right
: List
) return Boolean is
78 if Left
.Length
/= Right
.Length
then
82 if Left
.Length
= 0 then
87 -- Per AI05-0022, the container implementation is required to detect
88 -- element tampering by a generic actual subprogram.
90 Lock_Left
: With_Lock
(Left
.TC
'Unrestricted_Access);
91 Lock_Right
: With_Lock
(Right
.TC
'Unrestricted_Access);
93 L
: Node_Access
:= Left
.First
;
94 R
: Node_Access
:= Right
.First
;
96 for J
in 1 .. Left
.Length
loop
97 if L
.Element
.all /= R
.Element
.all then
113 procedure Adjust
(Container
: in out List
) is
114 Src
: Node_Access
:= Container
.First
;
118 -- If the counts are nonzero, execution is technically erroneous, but
119 -- it seems friendly to allow things like concurrent "=" on shared
122 Zero_Counts
(Container
.TC
);
125 pragma Assert
(Container
.Last
= null);
126 pragma Assert
(Container
.Length
= 0);
130 pragma Assert
(Container
.First
.Prev
= null);
131 pragma Assert
(Container
.Last
.Next
= null);
132 pragma Assert
(Container
.Length
> 0);
134 Container
.First
:= null;
135 Container
.Last
:= null;
136 Container
.Length
:= 0;
139 Element
: Element_Access
:= new Element_Type
'(Src.Element.all);
141 Dst := new Node_Type'(Element
, null, null);
148 Container
.First
:= Dst
;
149 Container
.Last
:= Dst
;
150 Container
.Length
:= 1;
153 while Src
/= null loop
155 Element
: Element_Access
:= new Element_Type
'(Src.Element.all);
157 Dst := new Node_Type'(Element
, null, Prev
=> Container
.Last
);
164 Container
.Last
.Next
:= Dst
;
165 Container
.Last
:= Dst
;
166 Container
.Length
:= Container
.Length
+ 1;
177 (Container
: in out List
;
178 New_Item
: Element_Type
;
179 Count
: Count_Type
:= 1)
182 Insert
(Container
, No_Element
, New_Item
, Count
);
189 procedure Assign
(Target
: in out List
; Source
: List
) is
193 if Target
'Address = Source
'Address then
199 Node
:= Source
.First
;
200 while Node
/= null loop
201 Target
.Append
(Node
.Element
.all);
211 procedure Clear
(Container
: in out List
) is
213 pragma Warnings
(Off
, X
);
216 if Container
.Length
= 0 then
217 pragma Assert
(Container
.First
= null);
218 pragma Assert
(Container
.Last
= null);
219 pragma Assert
(Container
.TC
= (Busy
=> 0, Lock
=> 0));
223 pragma Assert
(Container
.First
.Prev
= null);
224 pragma Assert
(Container
.Last
.Next
= null);
226 TC_Check
(Container
.TC
);
228 while Container
.Length
> 1 loop
229 X
:= Container
.First
;
230 pragma Assert
(X
.Next
.Prev
= Container
.First
);
232 Container
.First
:= X
.Next
;
233 Container
.First
.Prev
:= null;
235 Container
.Length
:= Container
.Length
- 1;
240 X
:= Container
.First
;
241 pragma Assert
(X
= Container
.Last
);
243 Container
.First
:= null;
244 Container
.Last
:= null;
245 Container
.Length
:= 0;
250 ------------------------
251 -- Constant_Reference --
252 ------------------------
254 function Constant_Reference
255 (Container
: aliased List
;
256 Position
: Cursor
) return Constant_Reference_Type
259 if Checks
and then Position
.Container
= null then
260 raise Constraint_Error
with "Position cursor has no element";
263 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
265 raise Program_Error
with
266 "Position cursor designates wrong container";
269 if Checks
and then Position
.Node
.Element
= null then
270 raise Program_Error
with "Node has no element";
273 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
276 TC
: constant Tamper_Counts_Access
:=
277 Container
.TC
'Unrestricted_Access;
279 return R
: constant Constant_Reference_Type
:=
280 (Element
=> Position
.Node
.Element
,
281 Control
=> (Controlled
with TC
))
286 end Constant_Reference
;
294 Item
: Element_Type
) return Boolean
297 return Find
(Container
, Item
) /= No_Element
;
304 function Copy
(Source
: List
) return List
is
306 return Target
: List
do
307 Target
.Assign
(Source
);
316 (Container
: in out List
;
317 Position
: in out Cursor
;
318 Count
: Count_Type
:= 1)
323 if Checks
and then Position
.Node
= null then
324 raise Constraint_Error
with
325 "Position cursor has no element";
328 if Checks
and then Position
.Node
.Element
= null then
329 raise Program_Error
with
330 "Position cursor has no element";
333 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
335 raise Program_Error
with
336 "Position cursor designates wrong container";
339 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
341 if Position
.Node
= Container
.First
then
342 Delete_First
(Container
, Count
);
343 Position
:= No_Element
; -- Post-York behavior
348 Position
:= No_Element
; -- Post-York behavior
352 TC_Check
(Container
.TC
);
354 for Index
in 1 .. Count
loop
356 Container
.Length
:= Container
.Length
- 1;
358 if X
= Container
.Last
then
359 Position
:= No_Element
;
361 Container
.Last
:= X
.Prev
;
362 Container
.Last
.Next
:= null;
368 Position
.Node
:= X
.Next
;
370 X
.Next
.Prev
:= X
.Prev
;
371 X
.Prev
.Next
:= X
.Next
;
376 -- Fix this junk comment ???
378 Position
:= No_Element
; -- Post-York behavior
385 procedure Delete_First
386 (Container
: in out List
;
387 Count
: Count_Type
:= 1)
392 if Count
>= Container
.Length
then
401 TC_Check
(Container
.TC
);
403 for J
in 1 .. Count
loop
404 X
:= Container
.First
;
405 pragma Assert
(X
.Next
.Prev
= Container
.First
);
407 Container
.First
:= X
.Next
;
408 Container
.First
.Prev
:= null;
410 Container
.Length
:= Container
.Length
- 1;
420 procedure Delete_Last
421 (Container
: in out List
;
422 Count
: Count_Type
:= 1)
427 if Count
>= Container
.Length
then
436 TC_Check
(Container
.TC
);
438 for J
in 1 .. Count
loop
440 pragma Assert
(X
.Prev
.Next
= Container
.Last
);
442 Container
.Last
:= X
.Prev
;
443 Container
.Last
.Next
:= null;
445 Container
.Length
:= Container
.Length
- 1;
455 function Element
(Position
: Cursor
) return Element_Type
is
457 if Checks
and then Position
.Node
= null then
458 raise Constraint_Error
with
459 "Position cursor has no element";
462 if Checks
and then Position
.Node
.Element
= null then
463 raise Program_Error
with
464 "Position cursor has no element";
467 pragma Assert
(Vet
(Position
), "bad cursor in Element");
469 return Position
.Node
.Element
.all;
476 procedure Finalize
(Object
: in out Iterator
) is
478 if Object
.Container
/= null then
479 Unbusy
(Object
.Container
.TC
);
490 Position
: Cursor
:= No_Element
) return Cursor
492 Node
: Node_Access
:= Position
.Node
;
496 Node
:= Container
.First
;
499 if Checks
and then Node
.Element
= null then
503 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
505 raise Program_Error
with
506 "Position cursor designates wrong container";
509 pragma Assert
(Vet
(Position
), "bad cursor in Find");
512 -- Per AI05-0022, the container implementation is required to detect
513 -- element tampering by a generic actual subprogram.
516 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
518 while Node
/= null loop
519 if Node
.Element
.all = Item
then
520 return Cursor
'(Container'Unrestricted_Access, Node);
534 function First (Container : List) return Cursor is
536 if Container.First = null then
539 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
543 function First
(Object
: Iterator
) return Cursor
is
545 -- The value of the iterator object's Node component influences the
546 -- behavior of the First (and Last) selector function.
548 -- When the Node component is null, this means the iterator object was
549 -- constructed without a start expression, in which case the (forward)
550 -- iteration starts from the (logical) beginning of the entire sequence
551 -- of items (corresponding to Container.First, for a forward iterator).
553 -- Otherwise, this is iteration over a partial sequence of items. When
554 -- the Node component is non-null, the iterator object was constructed
555 -- with a start expression, that specifies the position from which the
556 -- (forward) partial iteration begins.
558 if Object
.Node
= null then
559 return Indefinite_Doubly_Linked_Lists
.First
(Object
.Container
.all);
561 return Cursor
'(Object.Container, Object.Node);
569 function First_Element (Container : List) return Element_Type is
571 if Checks and then Container.First = null then
572 raise Constraint_Error with "list is empty";
575 return Container.First.Element.all;
582 procedure Free (X : in out Node_Access) is
583 procedure Deallocate is
584 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
587 -- While a node is in use, as an active link in a list, its Previous and
588 -- Next components must be null, or designate a different node; this is
589 -- a node invariant. For this indefinite list, there is an additional
590 -- invariant: that the element access value be non-null. Before actually
591 -- deallocating the node, we set the node access value components of the
592 -- node to point to the node itself, and set the element access value to
593 -- null (by deallocating the node's element), thus falsifying the node
594 -- invariant. Subprogram Vet inspects the value of the node components
595 -- when interrogating the node, in order to detect whether the cursor's
596 -- node access value is dangling.
598 -- Note that we have no guarantee that the storage for the node isn't
599 -- modified when it is deallocated, but there are other tests that Vet
600 -- does if node invariants appear to be satisifed. However, in practice
601 -- this simple test works well enough, detecting dangling references
602 -- immediately, without needing further interrogation.
619 ---------------------
620 -- Generic_Sorting --
621 ---------------------
623 package body Generic_Sorting is
629 function Is_Sorted (Container : List) return Boolean is
630 -- Per AI05-0022, the container implementation is required to detect
631 -- element tampering by a generic actual subprogram.
633 Lock : With_Lock (Container.TC'Unrestricted_Access);
637 Node := Container.First;
638 for J in 2 .. Container.Length loop
639 if Node.Next.Element.all < Node.Element.all then
654 (Target : in out List;
655 Source : in out List)
658 -- The semantics of Merge changed slightly per AI05-0021. It was
659 -- originally the case that if Target and Source denoted the same
660 -- container object, then the GNAT implementation of Merge did
661 -- nothing. However, it was argued that RM05 did not precisely
662 -- specify the semantics for this corner case. The decision of the
663 -- ARG was that if Target and Source denote the same non-empty
664 -- container object, then Program_Error is raised.
666 if Source.Is_Empty then
670 if Checks and then Target'Address = Source'Address then
671 raise Program_Error with
672 "Target and Source denote same non-empty container";
675 if Checks and then Target.Length > Count_Type'Last - Source.Length
677 raise Constraint_Error with "new length exceeds maximum";
680 TC_Check (Target.TC);
681 TC_Check (Source.TC);
684 Lock_Target : With_Lock (Target.TC'Unchecked_Access);
685 Lock_Source : With_Lock (Source.TC'Unchecked_Access);
687 LI, RI, RJ : Node_Access;
692 while RI /= null loop
693 pragma Assert (RI.Next = null
694 or else not (RI.Next.Element.all <
698 Splice_Internal (Target, null, Source);
702 pragma Assert (LI.Next = null
703 or else not (LI.Next.Element.all <
706 if RI.Element.all < LI.Element.all then
709 Splice_Internal (Target, LI, Source, RJ);
722 procedure Sort (Container : in out List) is
723 procedure Partition (Pivot : Node_Access; Back : Node_Access);
726 procedure Sort (Front, Back : Node_Access);
727 -- Comment??? Confusing name??? change name???
733 procedure Partition (Pivot : Node_Access; Back : Node_Access) is
738 while Node /= Back loop
739 if Node.Element.all < Pivot.Element.all then
741 Prev : constant Node_Access := Node.Prev;
742 Next : constant Node_Access := Node.Next;
748 Container.Last := Prev;
754 Node.Prev := Pivot.Prev;
758 if Node.Prev = null then
759 Container.First := Node;
761 Node.Prev.Next := Node;
777 procedure Sort (Front, Back : Node_Access) is
778 Pivot : constant Node_Access :=
779 (if Front = null then Container.First else Front.Next);
781 if Pivot /= Back then
782 Partition (Pivot, Back);
788 -- Start of processing for Sort
791 if Container.Length <= 1 then
795 pragma Assert (Container.First.Prev = null);
796 pragma Assert (Container.Last.Next = null);
798 TC_Check (Container.TC);
800 -- Per AI05-0022, the container implementation is required to detect
801 -- element tampering by a generic actual subprogram.
804 Lock : With_Lock (Container.TC'Unchecked_Access);
806 Sort (Front => null, Back => null);
809 pragma Assert (Container.First.Prev = null);
810 pragma Assert (Container.Last.Next = null);
815 ------------------------
816 -- Get_Element_Access --
817 ------------------------
819 function Get_Element_Access
820 (Position : Cursor) return not null Element_Access is
822 return Position.Node.Element;
823 end Get_Element_Access;
829 function Has_Element (Position : Cursor) return Boolean is
831 pragma Assert (Vet (Position), "bad cursor in Has_Element");
832 return Position.Node /= null;
840 (Container : in out List;
842 New_Item : Element_Type;
843 Position : out Cursor;
844 Count : Count_Type := 1)
846 First_Node : Node_Access;
847 New_Node : Node_Access;
850 if Before.Container /= null then
851 if Checks and then Before.Container /= Container'Unrestricted_Access
853 raise Program_Error with
854 "Before cursor designates wrong list";
858 (Before.Node = null or else Before.Node.Element = null)
860 raise Program_Error with
861 "Before cursor has no element";
864 pragma Assert (Vet (Before), "bad cursor in Insert");
872 if Checks and then Container.Length > Count_Type'Last - Count then
873 raise Constraint_Error with "new length exceeds maximum";
876 TC_Check (Container.TC);
879 -- The element allocator may need an accessibility check in the case
880 -- the actual type is class-wide or has access discriminants (see
881 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
882 -- allocator in the loop below, because the one in this block would
883 -- have failed already.
885 pragma Unsuppress (Accessibility_Check);
887 Element : Element_Access := new Element_Type'(New_Item
);
890 New_Node
:= new Node_Type
'(Element, null, null);
891 First_Node := New_Node;
899 Insert_Internal (Container, Before.Node, New_Node);
901 for J in 2 .. Count loop
903 Element : Element_Access := new Element_Type'(New_Item
);
905 New_Node
:= new Node_Type
'(Element, null, null);
912 Insert_Internal (Container, Before.Node, New_Node);
915 Position := Cursor'(Container
'Unchecked_Access, First_Node
);
919 (Container
: in out List
;
921 New_Item
: Element_Type
;
922 Count
: Count_Type
:= 1)
925 pragma Unreferenced
(Position
);
927 Insert
(Container
, Before
, New_Item
, Position
, Count
);
930 ---------------------
931 -- Insert_Internal --
932 ---------------------
934 procedure Insert_Internal
935 (Container
: in out List
;
936 Before
: Node_Access
;
937 New_Node
: Node_Access
)
940 if Container
.Length
= 0 then
941 pragma Assert
(Before
= null);
942 pragma Assert
(Container
.First
= null);
943 pragma Assert
(Container
.Last
= null);
945 Container
.First
:= New_Node
;
946 Container
.Last
:= New_Node
;
948 elsif Before
= null then
949 pragma Assert
(Container
.Last
.Next
= null);
951 Container
.Last
.Next
:= New_Node
;
952 New_Node
.Prev
:= Container
.Last
;
954 Container
.Last
:= New_Node
;
956 elsif Before
= Container
.First
then
957 pragma Assert
(Container
.First
.Prev
= null);
959 Container
.First
.Prev
:= New_Node
;
960 New_Node
.Next
:= Container
.First
;
962 Container
.First
:= New_Node
;
965 pragma Assert
(Container
.First
.Prev
= null);
966 pragma Assert
(Container
.Last
.Next
= null);
968 New_Node
.Next
:= Before
;
969 New_Node
.Prev
:= Before
.Prev
;
971 Before
.Prev
.Next
:= New_Node
;
972 Before
.Prev
:= New_Node
;
975 Container
.Length
:= Container
.Length
+ 1;
982 function Is_Empty
(Container
: List
) return Boolean is
984 return Container
.Length
= 0;
993 Process
: not null access procedure (Position
: Cursor
))
995 Busy
: With_Busy
(Container
.TC
'Unrestricted_Access);
996 Node
: Node_Access
:= Container
.First
;
999 while Node
/= null loop
1000 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1007 return List_Iterator_Interfaces.Reversible_Iterator'class
1010 -- The value of the Node component influences the behavior of the First
1011 -- and Last selector functions of the iterator object. When the Node
1012 -- component is null (as is the case here), this means the iterator
1013 -- object was constructed without a start expression. This is a
1014 -- complete iterator, meaning that the iteration starts from the
1015 -- (logical) beginning of the sequence of items.
1017 -- Note: For a forward iterator, Container.First is the beginning, and
1018 -- for a reverse iterator, Container.Last is the beginning.
1020 return It : constant Iterator :=
1021 Iterator'(Limited_Controlled
with
1022 Container
=> Container
'Unrestricted_Access,
1025 Busy
(Container
.TC
'Unrestricted_Access.all);
1032 return List_Iterator_Interfaces
.Reversible_Iterator
'Class
1035 -- It was formerly the case that when Start = No_Element, the partial
1036 -- iterator was defined to behave the same as for a complete iterator,
1037 -- and iterate over the entire sequence of items. However, those
1038 -- semantics were unintuitive and arguably error-prone (it is too easy
1039 -- to accidentally create an endless loop), and so they were changed,
1040 -- per the ARG meeting in Denver on 2011/11. However, there was no
1041 -- consensus about what positive meaning this corner case should have,
1042 -- and so it was decided to simply raise an exception. This does imply,
1043 -- however, that it is not possible to use a partial iterator to specify
1044 -- an empty sequence of items.
1046 if Checks
and then Start
= No_Element
then
1047 raise Constraint_Error
with
1048 "Start position for iterator equals No_Element";
1051 if Checks
and then Start
.Container
/= Container
'Unrestricted_Access then
1052 raise Program_Error
with
1053 "Start cursor of Iterate designates wrong list";
1056 pragma Assert
(Vet
(Start
), "Start cursor of Iterate is bad");
1058 -- The value of the Node component influences the behavior of the
1059 -- First and Last selector functions of the iterator object. When
1060 -- the Node component is non-null (as is the case here), it means
1061 -- that this is a partial iteration, over a subset of the complete
1062 -- sequence of items. The iterator object was constructed with
1063 -- a start expression, indicating the position from which the
1064 -- iteration begins. Note that the start position has the same value
1065 -- irrespective of whether this is a forward or reverse iteration.
1067 return It
: constant Iterator
:=
1068 Iterator
'(Limited_Controlled with
1069 Container => Container'Unrestricted_Access,
1072 Busy (Container.TC'Unrestricted_Access.all);
1080 function Last (Container : List) return Cursor is
1082 if Container.Last = null then
1085 return Cursor'(Container
'Unrestricted_Access, Container
.Last
);
1089 function Last
(Object
: Iterator
) return Cursor
is
1091 -- The value of the iterator object's Node component influences the
1092 -- behavior of the Last (and First) selector function.
1094 -- When the Node component is null, this means the iterator object was
1095 -- constructed without a start expression, in which case the (reverse)
1096 -- iteration starts from the (logical) beginning of the entire sequence
1097 -- (corresponding to Container.Last, for a reverse iterator).
1099 -- Otherwise, this is iteration over a partial sequence of items. When
1100 -- the Node component is non-null, the iterator object was constructed
1101 -- with a start expression, that specifies the position from which the
1102 -- (reverse) partial iteration begins.
1104 if Object
.Node
= null then
1105 return Indefinite_Doubly_Linked_Lists
.Last
(Object
.Container
.all);
1107 return Cursor
'(Object.Container, Object.Node);
1115 function Last_Element (Container : List) return Element_Type is
1117 if Checks and then Container.Last = null then
1118 raise Constraint_Error with "list is empty";
1121 return Container.Last.Element.all;
1128 function Length (Container : List) return Count_Type is
1130 return Container.Length;
1137 procedure Move (Target : in out List; Source : in out List) is
1139 if Target'Address = Source'Address then
1143 TC_Check (Source.TC);
1147 Target.First := Source.First;
1148 Source.First := null;
1150 Target.Last := Source.Last;
1151 Source.Last := null;
1153 Target.Length := Source.Length;
1161 procedure Next (Position : in out Cursor) is
1163 Position := Next (Position);
1166 function Next (Position : Cursor) return Cursor is
1168 if Position.Node = null then
1172 pragma Assert (Vet (Position), "bad cursor in Next");
1175 Next_Node : constant Node_Access := Position.Node.Next;
1177 if Next_Node = null then
1180 return Cursor'(Position
.Container
, Next_Node
);
1186 function Next
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
1188 if Position
.Container
= null then
1192 if Checks
and then Position
.Container
/= Object
.Container
then
1193 raise Program_Error
with
1194 "Position cursor of Next designates wrong list";
1197 return Next
(Position
);
1205 (Container
: in out List
;
1206 New_Item
: Element_Type
;
1207 Count
: Count_Type
:= 1)
1210 Insert
(Container
, First
(Container
), New_Item
, Count
);
1217 procedure Previous
(Position
: in out Cursor
) is
1219 Position
:= Previous
(Position
);
1222 function Previous
(Position
: Cursor
) return Cursor
is
1224 if Position
.Node
= null then
1228 pragma Assert
(Vet
(Position
), "bad cursor in Previous");
1231 Prev_Node
: constant Node_Access
:= Position
.Node
.Prev
;
1233 if Prev_Node
= null then
1236 return Cursor
'(Position.Container, Prev_Node);
1242 function Previous (Object : Iterator; Position : Cursor) return Cursor is
1244 if Position.Container = null then
1248 if Checks and then Position.Container /= Object.Container then
1249 raise Program_Error with
1250 "Position cursor of Previous designates wrong list";
1253 return Previous (Position);
1256 ----------------------
1257 -- Pseudo_Reference --
1258 ----------------------
1260 function Pseudo_Reference
1261 (Container : aliased List'Class) return Reference_Control_Type
1263 TC : constant Tamper_Counts_Access := Container.TC'Unrestricted_Access;
1265 return R : constant Reference_Control_Type := (Controlled with TC) do
1268 end Pseudo_Reference;
1274 procedure Query_Element
1276 Process : not null access procedure (Element : Element_Type))
1279 if Checks and then Position.Node = null then
1280 raise Constraint_Error with
1281 "Position cursor has no element";
1284 if Checks and then Position.Node.Element = null then
1285 raise Program_Error with
1286 "Position cursor has no element";
1289 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1292 Lock : With_Lock (Position.Container.TC'Unrestricted_Access);
1294 Process (Position.Node.Element.all);
1303 (Stream : not null access Root_Stream_Type'Class;
1306 N : Count_Type'Base;
1312 Count_Type'Base'Read
(Stream
, N
);
1319 Element
: Element_Access
:=
1320 new Element_Type
'(Element_Type'Input (Stream));
1322 Dst := new Node_Type'(Element
, null, null);
1333 while Item
.Length
< N
loop
1335 Element
: Element_Access
:=
1336 new Element_Type
'(Element_Type'Input (Stream));
1338 Dst := new Node_Type'(Element
, Next
=> null, Prev
=> Item
.Last
);
1345 Item
.Last
.Next
:= Dst
;
1347 Item
.Length
:= Item
.Length
+ 1;
1352 (Stream
: not null access Root_Stream_Type
'Class;
1356 raise Program_Error
with "attempt to stream list cursor";
1360 (Stream
: not null access Root_Stream_Type
'Class;
1361 Item
: out Reference_Type
)
1364 raise Program_Error
with "attempt to stream reference";
1368 (Stream
: not null access Root_Stream_Type
'Class;
1369 Item
: out Constant_Reference_Type
)
1372 raise Program_Error
with "attempt to stream reference";
1380 (Container
: aliased in out List
;
1381 Position
: Cursor
) return Reference_Type
1384 if Checks
and then Position
.Container
= null then
1385 raise Constraint_Error
with "Position cursor has no element";
1388 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1390 raise Program_Error
with
1391 "Position cursor designates wrong container";
1394 if Checks
and then Position
.Node
.Element
= null then
1395 raise Program_Error
with "Node has no element";
1398 pragma Assert
(Vet
(Position
), "bad cursor in function Reference");
1401 TC
: constant Tamper_Counts_Access
:=
1402 Container
.TC
'Unrestricted_Access;
1404 return R
: constant Reference_Type
:=
1405 (Element
=> Position
.Node
.Element
,
1406 Control
=> (Controlled
with TC
))
1413 ---------------------
1414 -- Replace_Element --
1415 ---------------------
1417 procedure Replace_Element
1418 (Container
: in out List
;
1420 New_Item
: Element_Type
)
1423 if Checks
and then Position
.Container
= null then
1424 raise Constraint_Error
with "Position cursor has no element";
1427 if Checks
and then Position
.Container
/= Container
'Unchecked_Access then
1428 raise Program_Error
with
1429 "Position cursor designates wrong container";
1432 TE_Check
(Container
.TC
);
1434 if Checks
and then Position
.Node
.Element
= null then
1435 raise Program_Error
with
1436 "Position cursor has no element";
1439 pragma Assert
(Vet
(Position
), "bad cursor in Replace_Element");
1442 -- The element allocator may need an accessibility check in the
1443 -- case the actual type is class-wide or has access discriminants
1444 -- (see RM 4.8(10.1) and AI12-0035).
1446 pragma Unsuppress
(Accessibility_Check
);
1448 X
: Element_Access
:= Position
.Node
.Element
;
1451 Position
.Node
.Element
:= new Element_Type
'(New_Item);
1454 end Replace_Element;
1456 ----------------------
1457 -- Reverse_Elements --
1458 ----------------------
1460 procedure Reverse_Elements (Container : in out List) is
1461 I : Node_Access := Container.First;
1462 J : Node_Access := Container.Last;
1464 procedure Swap (L, R : Node_Access);
1470 procedure Swap (L, R : Node_Access) is
1471 LN : constant Node_Access := L.Next;
1472 LP : constant Node_Access := L.Prev;
1474 RN : constant Node_Access := R.Next;
1475 RP : constant Node_Access := R.Prev;
1490 pragma Assert (RP = L);
1504 -- Start of processing for Reverse_Elements
1507 if Container.Length <= 1 then
1511 pragma Assert (Container.First.Prev = null);
1512 pragma Assert (Container.Last.Next = null);
1514 TC_Check (Container.TC);
1516 Container.First := J;
1517 Container.Last := I;
1519 Swap (L => I, R => J);
1527 Swap (L => J, R => I);
1536 pragma Assert (Container.First.Prev = null);
1537 pragma Assert (Container.Last.Next = null);
1538 end Reverse_Elements;
1544 function Reverse_Find
1546 Item : Element_Type;
1547 Position : Cursor := No_Element) return Cursor
1549 Node : Node_Access := Position.Node;
1553 Node := Container.Last;
1556 if Checks and then Node.Element = null then
1557 raise Program_Error with "Position cursor has no element";
1560 if Checks and then Position.Container /= Container'Unrestricted_Access
1562 raise Program_Error with
1563 "Position cursor designates wrong container";
1566 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1569 -- Per AI05-0022, the container implementation is required to detect
1570 -- element tampering by a generic actual subprogram.
1573 Lock : With_Lock (Container.TC'Unrestricted_Access);
1575 while Node /= null loop
1576 if Node.Element.all = Item then
1577 return Cursor'(Container
'Unrestricted_Access, Node
);
1587 ---------------------
1588 -- Reverse_Iterate --
1589 ---------------------
1591 procedure Reverse_Iterate
1593 Process
: not null access procedure (Position
: Cursor
))
1595 Busy
: With_Busy
(Container
.TC
'Unrestricted_Access);
1596 Node
: Node_Access
:= Container
.Last
;
1599 while Node
/= null loop
1600 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1603 end Reverse_Iterate;
1610 (Target : in out List;
1612 Source : in out List)
1615 if Before.Container /= null then
1616 if Checks and then Before.Container /= Target'Unrestricted_Access then
1617 raise Program_Error with
1618 "Before cursor designates wrong container";
1622 (Before.Node = null or else Before.Node.Element = null)
1624 raise Program_Error with
1625 "Before cursor has no element";
1628 pragma Assert (Vet (Before), "bad cursor in Splice");
1631 if Target'Address = Source'Address or else Source.Length = 0 then
1635 if Checks and then Target.Length > Count_Type'Last - Source.Length then
1636 raise Constraint_Error with "new length exceeds maximum";
1639 TC_Check (Target.TC);
1640 TC_Check (Source.TC);
1642 Splice_Internal (Target, Before.Node, Source);
1646 (Container : in out List;
1651 if Before.Container /= null then
1652 if Checks and then Before.Container /= Container'Unchecked_Access then
1653 raise Program_Error with
1654 "Before cursor designates wrong container";
1658 (Before.Node = null or else Before.Node.Element = null)
1660 raise Program_Error with
1661 "Before cursor has no element";
1664 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1667 if Checks and then Position.Node = null then
1668 raise Constraint_Error with "Position cursor has no element";
1671 if Checks and then Position.Node.Element = null then
1672 raise Program_Error with "Position cursor has no element";
1675 if Checks and then Position.Container /= Container'Unrestricted_Access
1677 raise Program_Error with
1678 "Position cursor designates wrong container";
1681 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1683 if Position.Node = Before.Node
1684 or else Position.Node.Next = Before.Node
1689 pragma Assert (Container.Length >= 2);
1691 TC_Check (Container.TC);
1693 if Before.Node = null then
1694 pragma Assert (Position.Node /= Container.Last);
1696 if Position.Node = Container.First then
1697 Container.First := Position.Node.Next;
1698 Container.First.Prev := null;
1700 Position.Node.Prev.Next := Position.Node.Next;
1701 Position.Node.Next.Prev := Position.Node.Prev;
1704 Container.Last.Next := Position.Node;
1705 Position.Node.Prev := Container.Last;
1707 Container.Last := Position.Node;
1708 Container.Last.Next := null;
1713 if Before.Node = Container.First then
1714 pragma Assert (Position.Node /= Container.First);
1716 if Position.Node = Container.Last then
1717 Container.Last := Position.Node.Prev;
1718 Container.Last.Next := null;
1720 Position.Node.Prev.Next := Position.Node.Next;
1721 Position.Node.Next.Prev := Position.Node.Prev;
1724 Container.First.Prev := Position.Node;
1725 Position.Node.Next := Container.First;
1727 Container.First := Position.Node;
1728 Container.First.Prev := null;
1733 if Position.Node = Container.First then
1734 Container.First := Position.Node.Next;
1735 Container.First.Prev := null;
1737 elsif Position.Node = Container.Last then
1738 Container.Last := Position.Node.Prev;
1739 Container.Last.Next := null;
1742 Position.Node.Prev.Next := Position.Node.Next;
1743 Position.Node.Next.Prev := Position.Node.Prev;
1746 Before.Node.Prev.Next := Position.Node;
1747 Position.Node.Prev := Before.Node.Prev;
1749 Before.Node.Prev := Position.Node;
1750 Position.Node.Next := Before.Node;
1752 pragma Assert (Container.First.Prev = null);
1753 pragma Assert (Container.Last.Next = null);
1757 (Target : in out List;
1759 Source : in out List;
1760 Position : in out Cursor)
1763 if Target'Address = Source'Address then
1764 Splice (Target, Before, Position);
1768 if Before.Container /= null then
1769 if Checks and then Before.Container /= Target'Unrestricted_Access then
1770 raise Program_Error with
1771 "Before cursor designates wrong container";
1775 (Before.Node = null or else Before.Node.Element = null)
1777 raise Program_Error with
1778 "Before cursor has no element";
1781 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1784 if Checks and then Position.Node = null then
1785 raise Constraint_Error with "Position cursor has no element";
1788 if Checks and then Position.Node.Element = null then
1789 raise Program_Error with
1790 "Position cursor has no element";
1793 if Checks and then Position.Container /= Source'Unrestricted_Access then
1794 raise Program_Error with
1795 "Position cursor designates wrong container";
1798 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1800 if Checks and then Target.Length = Count_Type'Last then
1801 raise Constraint_Error with "Target is full";
1804 TC_Check (Target.TC);
1805 TC_Check (Source.TC);
1807 Splice_Internal (Target, Before.Node, Source, Position.Node);
1808 Position.Container := Target'Unchecked_Access;
1811 ---------------------
1812 -- Splice_Internal --
1813 ---------------------
1815 procedure Splice_Internal
1816 (Target : in out List;
1817 Before : Node_Access;
1818 Source : in out List)
1821 -- This implements the corresponding Splice operation, after the
1822 -- parameters have been vetted, and corner-cases disposed of.
1824 pragma Assert (Target'Address /= Source'Address);
1825 pragma Assert (Source.Length > 0);
1826 pragma Assert (Source.First /= null);
1827 pragma Assert (Source.First.Prev = null);
1828 pragma Assert (Source.Last /= null);
1829 pragma Assert (Source.Last.Next = null);
1830 pragma Assert (Target.Length <= Count_Type'Last - Source.Length);
1832 if Target.Length = 0 then
1833 pragma Assert (Before = null);
1834 pragma Assert (Target.First = null);
1835 pragma Assert (Target.Last = null);
1837 Target.First := Source.First;
1838 Target.Last := Source.Last;
1840 elsif Before = null then
1841 pragma Assert (Target.Last.Next = null);
1843 Target.Last.Next := Source.First;
1844 Source.First.Prev := Target.Last;
1846 Target.Last := Source.Last;
1848 elsif Before = Target.First then
1849 pragma Assert (Target.First.Prev = null);
1851 Source.Last.Next := Target.First;
1852 Target.First.Prev := Source.Last;
1854 Target.First := Source.First;
1857 pragma Assert (Target.Length >= 2);
1858 Before.Prev.Next := Source.First;
1859 Source.First.Prev := Before.Prev;
1861 Before.Prev := Source.Last;
1862 Source.Last.Next := Before;
1865 Source.First := null;
1866 Source.Last := null;
1868 Target.Length := Target.Length + Source.Length;
1870 end Splice_Internal;
1872 procedure Splice_Internal
1873 (Target : in out List;
1874 Before : Node_Access; -- node of Target
1875 Source : in out List;
1876 Position : Node_Access) -- node of Source
1879 -- This implements the corresponding Splice operation, after the
1880 -- parameters have been vetted.
1882 pragma Assert (Target'Address /= Source'Address);
1883 pragma Assert (Target.Length < Count_Type'Last);
1884 pragma Assert (Source.Length > 0);
1885 pragma Assert (Source.First /= null);
1886 pragma Assert (Source.First.Prev = null);
1887 pragma Assert (Source.Last /= null);
1888 pragma Assert (Source.Last.Next = null);
1889 pragma Assert (Position /= null);
1891 if Position = Source.First then
1892 Source.First := Position.Next;
1894 if Position = Source.Last then
1895 pragma Assert (Source.First = null);
1896 pragma Assert (Source.Length = 1);
1897 Source.Last := null;
1900 Source.First.Prev := null;
1903 elsif Position = Source.Last then
1904 pragma Assert (Source.Length >= 2);
1905 Source.Last := Position.Prev;
1906 Source.Last.Next := null;
1909 pragma Assert (Source.Length >= 3);
1910 Position.Prev.Next := Position.Next;
1911 Position.Next.Prev := Position.Prev;
1914 if Target.Length = 0 then
1915 pragma Assert (Before = null);
1916 pragma Assert (Target.First = null);
1917 pragma Assert (Target.Last = null);
1919 Target.First := Position;
1920 Target.Last := Position;
1922 Target.First.Prev := null;
1923 Target.Last.Next := null;
1925 elsif Before = null then
1926 pragma Assert (Target.Last.Next = null);
1927 Target.Last.Next := Position;
1928 Position.Prev := Target.Last;
1930 Target.Last := Position;
1931 Target.Last.Next := null;
1933 elsif Before = Target.First then
1934 pragma Assert (Target.First.Prev = null);
1935 Target.First.Prev := Position;
1936 Position.Next := Target.First;
1938 Target.First := Position;
1939 Target.First.Prev := null;
1942 pragma Assert (Target.Length >= 2);
1943 Before.Prev.Next := Position;
1944 Position.Prev := Before.Prev;
1946 Before.Prev := Position;
1947 Position.Next := Before;
1950 Target.Length := Target.Length + 1;
1951 Source.Length := Source.Length - 1;
1952 end Splice_Internal;
1959 (Container : in out List;
1963 if Checks and then I.Node = null then
1964 raise Constraint_Error with "I cursor has no element";
1967 if Checks and then J.Node = null then
1968 raise Constraint_Error with "J cursor has no element";
1971 if Checks and then I.Container /= Container'Unchecked_Access then
1972 raise Program_Error with "I cursor designates wrong container";
1975 if Checks and then J.Container /= Container'Unchecked_Access then
1976 raise Program_Error with "J cursor designates wrong container";
1979 if I.Node = J.Node then
1983 TE_Check (Container.TC);
1985 pragma Assert (Vet (I), "bad I cursor in Swap");
1986 pragma Assert (Vet (J), "bad J cursor in Swap");
1989 EI_Copy : constant Element_Access := I.Node.Element;
1992 I.Node.Element := J.Node.Element;
1993 J.Node.Element := EI_Copy;
2001 procedure Swap_Links
2002 (Container : in out List;
2006 if Checks and then I.Node = null then
2007 raise Constraint_Error with "I cursor has no element";
2010 if Checks and then J.Node = null then
2011 raise Constraint_Error with "J cursor has no element";
2014 if Checks and then I.Container /= Container'Unrestricted_Access then
2015 raise Program_Error with "I cursor designates wrong container";
2018 if Checks and then J.Container /= Container'Unrestricted_Access then
2019 raise Program_Error with "J cursor designates wrong container";
2022 if I.Node = J.Node then
2026 TC_Check (Container.TC);
2028 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
2029 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
2032 I_Next : constant Cursor := Next (I);
2036 Splice (Container, Before => I, Position => J);
2040 J_Next : constant Cursor := Next (J);
2044 Splice (Container, Before => J, Position => I);
2047 pragma Assert (Container.Length >= 3);
2049 Splice (Container, Before => I_Next, Position => J);
2050 Splice (Container, Before => J_Next, Position => I);
2056 pragma Assert (Container.First.Prev = null);
2057 pragma Assert (Container.Last.Next = null);
2060 --------------------
2061 -- Update_Element --
2062 --------------------
2064 procedure Update_Element
2065 (Container : in out List;
2067 Process : not null access procedure (Element : in out Element_Type))
2070 if Checks and then Position.Node = null then
2071 raise Constraint_Error with "Position cursor has no element";
2074 if Checks and then Position.Node.Element = null then
2075 raise Program_Error with
2076 "Position cursor has no element";
2079 if Checks and then Position.Container /= Container'Unchecked_Access then
2080 raise Program_Error with
2081 "Position cursor designates wrong container";
2084 pragma Assert (Vet (Position), "bad cursor in Update_Element");
2087 Lock : With_Lock (Container.TC'Unchecked_Access);
2089 Process (Position.Node.Element.all);
2097 function Vet (Position : Cursor) return Boolean is
2099 if Position.Node = null then
2100 return Position.Container = null;
2103 if Position.Container = null then
2107 -- An invariant of a node is that its Previous and Next components can
2108 -- be null, or designate a different node. Also, its element access
2109 -- value must be non-null. Operation Free sets the node access value
2110 -- components of the node to designate the node itself, and the element
2111 -- access value to null, before actually deallocating the node, thus
2112 -- deliberately violating the node invariant. This gives us a simple way
2113 -- to detect a dangling reference to a node.
2115 if Position.Node.Next = Position.Node then
2119 if Position.Node.Prev = Position.Node then
2123 if Position.Node.Element = null then
2127 -- In practice the tests above will detect most instances of a dangling
2128 -- reference. If we get here, it means that the invariants of the
2129 -- designated node are satisfied (they at least appear to be satisfied),
2130 -- so we perform some more tests, to determine whether invariants of the
2131 -- designated list are satisfied too.
2134 L : List renames Position.Container.all;
2137 if L.Length = 0 then
2141 if L.First = null then
2145 if L.Last = null then
2149 if L.First.Prev /= null then
2153 if L.Last.Next /= null then
2157 if Position.Node.Prev = null and then Position.Node /= L.First then
2161 if Position.Node.Next = null and then Position.Node /= L.Last then
2165 if L.Length = 1 then
2166 return L.First = L.Last;
2169 if L.First = L.Last then
2173 if L.First.Next = null then
2177 if L.Last.Prev = null then
2181 if L.First.Next.Prev /= L.First then
2185 if L.Last.Prev.Next /= L.Last then
2189 if L.Length = 2 then
2190 if L.First.Next /= L.Last then
2194 if L.Last.Prev /= L.First then
2201 if L.First.Next = L.Last then
2205 if L.Last.Prev = L.First then
2209 if Position.Node = L.First then
2213 if Position.Node = L.Last then
2217 if Position.Node.Next = null then
2221 if Position.Node.Prev = null then
2225 if Position.Node.Next.Prev /= Position.Node then
2229 if Position.Node.Prev.Next /= Position.Node then
2233 if L.Length = 3 then
2234 if L.First.Next /= Position.Node then
2238 if L.Last.Prev /= Position.Node then
2252 (Stream : not null access Root_Stream_Type'Class;
2255 Node : Node_Access := Item.First;
2258 Count_Type'Base'Write
(Stream
, Item
.Length
);
2260 while Node
/= null loop
2261 Element_Type
'Output (Stream
, Node
.Element
.all);
2267 (Stream
: not null access Root_Stream_Type
'Class;
2271 raise Program_Error
with "attempt to stream list cursor";
2275 (Stream
: not null access Root_Stream_Type
'Class;
2276 Item
: Reference_Type
)
2279 raise Program_Error
with "attempt to stream reference";
2283 (Stream
: not null access Root_Stream_Type
'Class;
2284 Item
: Constant_Reference_Type
)
2287 raise Program_Error
with "attempt to stream reference";
2290 end Ada
.Containers
.Indefinite_Doubly_Linked_Lists
;