1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2004-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. --
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 Ada
.Containers
.Stable_Sorting
; use Ada
.Containers
.Stable_Sorting
;
34 with System
; use type System
.Address
;
35 with System
.Put_Images
;
37 package body Ada
.Containers
.Indefinite_Doubly_Linked_Lists
with
41 pragma Warnings
(Off
, "variable ""Busy*"" is not referenced");
42 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
43 -- See comment in Ada.Containers.Helpers
46 new Ada
.Unchecked_Deallocation
(Element_Type
, Element_Access
);
48 -----------------------
49 -- Local Subprograms --
50 -----------------------
52 procedure Free
(X
: in out Node_Access
);
54 procedure Insert_Internal
55 (Container
: in out List
;
57 New_Node
: Node_Access
);
59 procedure Splice_Internal
60 (Target
: in out List
;
62 Source
: in out List
);
64 procedure Splice_Internal
65 (Target
: in out List
;
68 Position
: Node_Access
);
70 function Vet
(Position
: Cursor
) return Boolean with Inline
;
71 -- Checks invariants of the cursor and its designated container, as a
72 -- simple way of detecting dangling references (see operation Free for a
73 -- description of the detection mechanism), returning True if all checks
74 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
75 -- so the checks are performed only when assertions are enabled.
81 function "=" (Left
, Right
: List
) return Boolean is
83 if Left
.Length
/= Right
.Length
then
87 if Left
.Length
= 0 then
92 -- Per AI05-0022, the container implementation is required to detect
93 -- element tampering by a generic actual subprogram.
95 Lock_Left
: With_Lock
(Left
.TC
'Unrestricted_Access);
96 Lock_Right
: With_Lock
(Right
.TC
'Unrestricted_Access);
98 L
: Node_Access
:= Left
.First
;
99 R
: Node_Access
:= Right
.First
;
101 for J
in 1 .. Left
.Length
loop
102 if L
.Element
.all /= R
.Element
.all then
118 procedure Adjust
(Container
: in out List
) is
119 Src
: Node_Access
:= Container
.First
;
123 -- If the counts are nonzero, execution is technically erroneous, but
124 -- it seems friendly to allow things like concurrent "=" on shared
127 Zero_Counts
(Container
.TC
);
130 pragma Assert
(Container
.Last
= null);
131 pragma Assert
(Container
.Length
= 0);
135 pragma Assert
(Container
.First
.Prev
= null);
136 pragma Assert
(Container
.Last
.Next
= null);
137 pragma Assert
(Container
.Length
> 0);
139 Container
.First
:= null;
140 Container
.Last
:= null;
141 Container
.Length
:= 0;
144 Element
: Element_Access
:= new Element_Type
'(Src.Element.all);
146 Dst := new Node_Type'(Element
, null, null);
153 Container
.First
:= Dst
;
154 Container
.Last
:= Dst
;
155 Container
.Length
:= 1;
158 while Src
/= null loop
160 Element
: Element_Access
:= new Element_Type
'(Src.Element.all);
162 Dst := new Node_Type'(Element
, null, Prev
=> Container
.Last
);
169 Container
.Last
.Next
:= Dst
;
170 Container
.Last
:= Dst
;
171 Container
.Length
:= Container
.Length
+ 1;
182 (Container
: in out List
;
183 New_Item
: Element_Type
;
187 Insert
(Container
, No_Element
, New_Item
, Count
);
191 (Container
: in out List
;
192 New_Item
: Element_Type
)
195 Insert
(Container
, No_Element
, New_Item
, 1);
202 procedure Assign
(Target
: in out List
; Source
: List
) is
206 if Target
'Address = Source
'Address then
212 Node
:= Source
.First
;
213 while Node
/= null loop
214 Target
.Append
(Node
.Element
.all);
224 procedure Clear
(Container
: in out List
) is
226 pragma Warnings
(Off
, X
);
229 if Container
.Length
= 0 then
230 pragma Assert
(Container
.First
= null);
231 pragma Assert
(Container
.Last
= null);
232 pragma Assert
(Container
.TC
= (Busy
=> 0, Lock
=> 0));
236 pragma Assert
(Container
.First
.Prev
= null);
237 pragma Assert
(Container
.Last
.Next
= null);
239 TC_Check
(Container
.TC
);
241 while Container
.Length
> 1 loop
242 X
:= Container
.First
;
243 pragma Assert
(X
.Next
.Prev
= Container
.First
);
245 Container
.First
:= X
.Next
;
246 Container
.First
.Prev
:= null;
248 Container
.Length
:= Container
.Length
- 1;
253 X
:= Container
.First
;
254 pragma Assert
(X
= Container
.Last
);
256 Container
.First
:= null;
257 Container
.Last
:= null;
258 Container
.Length
:= 0;
263 ------------------------
264 -- Constant_Reference --
265 ------------------------
267 function Constant_Reference
268 (Container
: aliased List
;
269 Position
: Cursor
) return Constant_Reference_Type
272 if Checks
and then Position
.Container
= null then
273 raise Constraint_Error
with "Position cursor has no element";
276 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
278 raise Program_Error
with
279 "Position cursor designates wrong container";
282 if Checks
and then Position
.Node
.Element
= null then
283 raise Program_Error
with "Node has no element";
286 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
289 TC
: constant Tamper_Counts_Access
:=
290 Container
.TC
'Unrestricted_Access;
292 return R
: constant Constant_Reference_Type
:=
293 (Element
=> Position
.Node
.Element
,
294 Control
=> (Controlled
with TC
))
299 end Constant_Reference
;
307 Item
: Element_Type
) return Boolean
310 return Find
(Container
, Item
) /= No_Element
;
317 function Copy
(Source
: List
) return List
is
319 return Target
: List
do
320 Target
.Assign
(Source
);
329 (Container
: in out List
;
330 Position
: in out Cursor
;
331 Count
: Count_Type
:= 1)
336 TC_Check
(Container
.TC
);
338 if Checks
and then Position
.Node
= null then
339 raise Constraint_Error
with
340 "Position cursor has no element";
343 if Checks
and then Position
.Node
.Element
= null then
344 raise Program_Error
with
345 "Position cursor has no element";
348 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
350 raise Program_Error
with
351 "Position cursor designates wrong container";
354 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
356 if Position
.Node
= Container
.First
then
357 Delete_First
(Container
, Count
);
358 Position
:= No_Element
; -- Post-York behavior
363 Position
:= No_Element
; -- Post-York behavior
367 for Index
in 1 .. Count
loop
369 Container
.Length
:= Container
.Length
- 1;
371 if X
= Container
.Last
then
372 Position
:= No_Element
;
374 Container
.Last
:= X
.Prev
;
375 Container
.Last
.Next
:= null;
381 Position
.Node
:= X
.Next
;
383 X
.Next
.Prev
:= X
.Prev
;
384 X
.Prev
.Next
:= X
.Next
;
389 -- Fix this junk comment ???
391 Position
:= No_Element
; -- Post-York behavior
398 procedure Delete_First
399 (Container
: in out List
;
400 Count
: Count_Type
:= 1)
405 if Count
>= Container
.Length
then
414 TC_Check
(Container
.TC
);
416 for J
in 1 .. Count
loop
417 X
:= Container
.First
;
418 pragma Assert
(X
.Next
.Prev
= Container
.First
);
420 Container
.First
:= X
.Next
;
421 Container
.First
.Prev
:= null;
423 Container
.Length
:= Container
.Length
- 1;
433 procedure Delete_Last
434 (Container
: in out List
;
435 Count
: Count_Type
:= 1)
440 if Count
>= Container
.Length
then
449 TC_Check
(Container
.TC
);
451 for J
in 1 .. Count
loop
453 pragma Assert
(X
.Prev
.Next
= Container
.Last
);
455 Container
.Last
:= X
.Prev
;
456 Container
.Last
.Next
:= null;
458 Container
.Length
:= Container
.Length
- 1;
468 function Element
(Position
: Cursor
) return Element_Type
is
470 if Checks
and then Position
.Node
= null then
471 raise Constraint_Error
with
472 "Position cursor has no element";
475 if Checks
and then Position
.Node
.Element
= null then
476 raise Program_Error
with
477 "Position cursor has no element";
480 pragma Assert
(Vet
(Position
), "bad cursor in Element");
482 return Position
.Node
.Element
.all;
489 procedure Finalize
(Object
: in out Iterator
) is
491 if Object
.Container
/= null then
492 Unbusy
(Object
.Container
.TC
);
503 Position
: Cursor
:= No_Element
) return Cursor
505 Node
: Node_Access
:= Position
.Node
;
509 Node
:= Container
.First
;
512 if Checks
and then Node
.Element
= null then
516 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
518 raise Program_Error
with
519 "Position cursor designates wrong container";
522 pragma Assert
(Vet
(Position
), "bad cursor in Find");
525 -- Per AI05-0022, the container implementation is required to detect
526 -- element tampering by a generic actual subprogram.
529 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
531 while Node
/= null loop
532 if Node
.Element
.all = Item
then
533 return Cursor
'(Container'Unrestricted_Access, Node);
547 function First (Container : List) return Cursor is
549 if Container.First = null then
552 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
556 function First
(Object
: Iterator
) return Cursor
is
558 -- The value of the iterator object's Node component influences the
559 -- behavior of the First (and Last) selector function.
561 -- When the Node component is null, this means the iterator object was
562 -- constructed without a start expression, in which case the (forward)
563 -- iteration starts from the (logical) beginning of the entire sequence
564 -- of items (corresponding to Container.First, for a forward iterator).
566 -- Otherwise, this is iteration over a partial sequence of items. When
567 -- the Node component is non-null, the iterator object was constructed
568 -- with a start expression, that specifies the position from which the
569 -- (forward) partial iteration begins.
571 if Object
.Node
= null then
572 return Indefinite_Doubly_Linked_Lists
.First
(Object
.Container
.all);
574 return Cursor
'(Object.Container, Object.Node);
582 function First_Element (Container : List) return Element_Type is
584 if Checks and then Container.First = null then
585 raise Constraint_Error with "list is empty";
588 return Container.First.Element.all;
595 procedure Free (X : in out Node_Access) is
596 procedure Deallocate is
597 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
600 -- While a node is in use, as an active link in a list, its Previous and
601 -- Next components must be null, or designate a different node; this is
602 -- a node invariant. For this indefinite list, there is an additional
603 -- invariant: that the element access value be non-null. Before actually
604 -- deallocating the node, we set the node access value components of the
605 -- node to point to the node itself, and set the element access value to
606 -- null (by deallocating the node's element), thus falsifying the node
607 -- invariant. Subprogram Vet inspects the value of the node components
608 -- when interrogating the node, in order to detect whether the cursor's
609 -- node access value is dangling.
611 -- Note that we have no guarantee that the storage for the node isn't
612 -- modified when it is deallocated, but there are other tests that Vet
613 -- does if node invariants appear to be satisifed. However, in practice
614 -- this simple test works well enough, detecting dangling references
615 -- immediately, without needing further interrogation.
632 ---------------------
633 -- Generic_Sorting --
634 ---------------------
636 package body Generic_Sorting is
642 function Is_Sorted (Container : List) return Boolean is
643 -- Per AI05-0022, the container implementation is required to detect
644 -- element tampering by a generic actual subprogram.
646 Lock : With_Lock (Container.TC'Unrestricted_Access);
650 Node := Container.First;
651 for J in 2 .. Container.Length loop
652 if Node.Next.Element.all < Node.Element.all then
667 (Target : in out List;
668 Source : in out List)
671 -- The semantics of Merge changed slightly per AI05-0021. It was
672 -- originally the case that if Target and Source denoted the same
673 -- container object, then the GNAT implementation of Merge did
674 -- nothing. However, it was argued that RM05 did not precisely
675 -- specify the semantics for this corner case. The decision of the
676 -- ARG was that if Target and Source denote the same non-empty
677 -- container object, then Program_Error is raised.
679 if Source.Is_Empty then
683 TC_Check (Target.TC);
684 TC_Check (Source.TC);
686 if Checks and then Target'Address = Source'Address then
687 raise Program_Error with
688 "Target and Source denote same non-empty container";
691 if Checks and then Target.Length > Count_Type'Last - Source.Length
693 raise Constraint_Error with "new length exceeds maximum";
697 Lock_Target : With_Lock (Target.TC'Unchecked_Access);
698 Lock_Source : With_Lock (Source.TC'Unchecked_Access);
700 LI, RI, RJ : Node_Access;
705 while RI /= null loop
706 pragma Assert (RI.Next = null
707 or else not (RI.Next.Element.all <
711 Splice_Internal (Target, null, Source);
715 pragma Assert (LI.Next = null
716 or else not (LI.Next.Element.all <
719 if RI.Element.all < LI.Element.all then
722 Splice_Internal (Target, LI, Source, RJ);
735 procedure Sort (Container : in out List) is
737 if Container.Length <= 1 then
741 pragma Assert (Container.First.Prev = null);
742 pragma Assert (Container.Last.Next = null);
744 TC_Check (Container.TC);
746 -- Per AI05-0022, the container implementation is required to detect
747 -- element tampering by a generic actual subprogram.
750 Lock : With_Lock (Container.TC'Unchecked_Access);
752 package Descriptors is new List_Descriptors
753 (Node_Ref => Node_Access, Nil => null);
756 function Next (N : Node_Access) return Node_Access is (N.Next);
757 procedure Set_Next (N : Node_Access; Next : Node_Access)
759 procedure Set_Prev (N : Node_Access; Prev : Node_Access)
761 function "<" (L, R : Node_Access) return Boolean is
762 (L.Element.all < R.Element.all);
763 procedure Update_Container (List : List_Descriptor) with Inline;
765 procedure Set_Next (N : Node_Access; Next : Node_Access) is
770 procedure Set_Prev (N : Node_Access; Prev : Node_Access) is
775 procedure Update_Container (List : List_Descriptor) is
777 Container.First := List.First;
778 Container.Last := List.Last;
779 Container.Length := List.Length;
780 end Update_Container;
782 procedure Sort_List is new Doubly_Linked_List_Sort;
784 Sort_List (List_Descriptor'(First
=> Container
.First
,
785 Last
=> Container
.Last
,
786 Length
=> Container
.Length
));
789 pragma Assert
(Container
.First
.Prev
= null);
790 pragma Assert
(Container
.Last
.Next
= null);
795 ------------------------
796 -- Get_Element_Access --
797 ------------------------
799 function Get_Element_Access
800 (Position
: Cursor
) return not null Element_Access
is
802 return Position
.Node
.Element
;
803 end Get_Element_Access
;
809 function Has_Element
(Position
: Cursor
) return Boolean is
811 pragma Assert
(Vet
(Position
), "bad cursor in Has_Element");
812 return Position
.Node
/= null;
820 (Container
: in out List
;
822 New_Item
: Element_Type
;
823 Position
: out Cursor
;
824 Count
: Count_Type
:= 1)
826 First_Node
: Node_Access
;
827 New_Node
: Node_Access
;
830 TC_Check
(Container
.TC
);
832 if Before
.Container
/= null then
833 if Checks
and then Before
.Container
/= Container
'Unrestricted_Access
835 raise Program_Error
with
836 "Before cursor designates wrong list";
840 (Before
.Node
= null or else Before
.Node
.Element
= null)
842 raise Program_Error
with
843 "Before cursor has no element";
846 pragma Assert
(Vet
(Before
), "bad cursor in Insert");
854 if Checks
and then Container
.Length
> Count_Type
'Last - Count
then
855 raise Constraint_Error
with "new length exceeds maximum";
859 -- The element allocator may need an accessibility check in the case
860 -- the actual type is class-wide or has access discriminants (see
861 -- RM 4.8(10.1) and AI12-0035). We don't unsuppress the check on the
862 -- allocator in the loop below, because the one in this block would
863 -- have failed already.
865 pragma Unsuppress
(Accessibility_Check
);
867 Element
: Element_Access
:= new Element_Type
'(New_Item);
870 New_Node := new Node_Type'(Element
, null, null);
871 First_Node
:= New_Node
;
879 Insert_Internal
(Container
, Before
.Node
, New_Node
);
881 for J
in 2 .. Count
loop
883 Element
: Element_Access
:= new Element_Type
'(New_Item);
885 New_Node := new Node_Type'(Element
, null, null);
892 Insert_Internal
(Container
, Before
.Node
, New_Node
);
895 Position
:= Cursor
'(Container'Unchecked_Access, First_Node);
899 (Container : in out List;
901 New_Item : Element_Type;
902 Count : Count_Type := 1)
906 Insert (Container, Before, New_Item, Position, Count);
909 ---------------------
910 -- Insert_Internal --
911 ---------------------
913 procedure Insert_Internal
914 (Container : in out List;
915 Before : Node_Access;
916 New_Node : Node_Access)
919 if Container.Length = 0 then
920 pragma Assert (Before = null);
921 pragma Assert (Container.First = null);
922 pragma Assert (Container.Last = null);
924 Container.First := New_Node;
925 Container.Last := New_Node;
927 elsif Before = null then
928 pragma Assert (Container.Last.Next = null);
930 Container.Last.Next := New_Node;
931 New_Node.Prev := Container.Last;
933 Container.Last := New_Node;
935 elsif Before = Container.First then
936 pragma Assert (Container.First.Prev = null);
938 Container.First.Prev := New_Node;
939 New_Node.Next := Container.First;
941 Container.First := New_Node;
944 pragma Assert (Container.First.Prev = null);
945 pragma Assert (Container.Last.Next = null);
947 New_Node.Next := Before;
948 New_Node.Prev := Before.Prev;
950 Before.Prev.Next := New_Node;
951 Before.Prev := New_Node;
954 Container.Length := Container.Length + 1;
961 function Is_Empty (Container : List) return Boolean is
963 return Container.Length = 0;
972 Process : not null access procedure (Position : Cursor))
974 Busy : With_Busy (Container.TC'Unrestricted_Access);
975 Node : Node_Access := Container.First;
978 while Node /= null loop
979 Process (Cursor'(Container
'Unrestricted_Access, Node
));
986 return List_Iterator_Interfaces
.Reversible_Iterator
'class
989 -- The value of the Node component influences the behavior of the First
990 -- and Last selector functions of the iterator object. When the Node
991 -- component is null (as is the case here), this means the iterator
992 -- object was constructed without a start expression. This is a
993 -- complete iterator, meaning that the iteration starts from the
994 -- (logical) beginning of the sequence of items.
996 -- Note: For a forward iterator, Container.First is the beginning, and
997 -- for a reverse iterator, Container.Last is the beginning.
999 return It
: constant Iterator
:=
1000 Iterator
'(Limited_Controlled with
1001 Container => Container'Unrestricted_Access,
1004 Busy (Container.TC'Unrestricted_Access.all);
1011 return List_Iterator_Interfaces.Reversible_Iterator'Class
1014 -- It was formerly the case that when Start = No_Element, the partial
1015 -- iterator was defined to behave the same as for a complete iterator,
1016 -- and iterate over the entire sequence of items. However, those
1017 -- semantics were unintuitive and arguably error-prone (it is too easy
1018 -- to accidentally create an endless loop), and so they were changed,
1019 -- per the ARG meeting in Denver on 2011/11. However, there was no
1020 -- consensus about what positive meaning this corner case should have,
1021 -- and so it was decided to simply raise an exception. This does imply,
1022 -- however, that it is not possible to use a partial iterator to specify
1023 -- an empty sequence of items.
1025 if Checks and then Start = No_Element then
1026 raise Constraint_Error with
1027 "Start position for iterator equals No_Element";
1030 if Checks and then Start.Container /= Container'Unrestricted_Access then
1031 raise Program_Error with
1032 "Start cursor of Iterate designates wrong list";
1035 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1037 -- The value of the Node component influences the behavior of the
1038 -- First and Last selector functions of the iterator object. When
1039 -- the Node component is non-null (as is the case here), it means
1040 -- that this is a partial iteration, over a subset of the complete
1041 -- sequence of items. The iterator object was constructed with
1042 -- a start expression, indicating the position from which the
1043 -- iteration begins. Note that the start position has the same value
1044 -- irrespective of whether this is a forward or reverse iteration.
1046 return It : constant Iterator :=
1047 Iterator'(Limited_Controlled
with
1048 Container
=> Container
'Unrestricted_Access,
1051 Busy
(Container
.TC
'Unrestricted_Access.all);
1059 function Last
(Container
: List
) return Cursor
is
1061 if Container
.Last
= null then
1064 return Cursor
'(Container'Unrestricted_Access, Container.Last);
1068 function Last (Object : Iterator) return Cursor is
1070 -- The value of the iterator object's Node component influences the
1071 -- behavior of the Last (and First) selector function.
1073 -- When the Node component is null, this means the iterator object was
1074 -- constructed without a start expression, in which case the (reverse)
1075 -- iteration starts from the (logical) beginning of the entire sequence
1076 -- (corresponding to Container.Last, for a reverse iterator).
1078 -- Otherwise, this is iteration over a partial sequence of items. When
1079 -- the Node component is non-null, the iterator object was constructed
1080 -- with a start expression, that specifies the position from which the
1081 -- (reverse) partial iteration begins.
1083 if Object.Node = null then
1084 return Indefinite_Doubly_Linked_Lists.Last (Object.Container.all);
1086 return Cursor'(Object
.Container
, Object
.Node
);
1094 function Last_Element
(Container
: List
) return Element_Type
is
1096 if Checks
and then Container
.Last
= null then
1097 raise Constraint_Error
with "list is empty";
1100 return Container
.Last
.Element
.all;
1107 function Length
(Container
: List
) return Count_Type
is
1109 return Container
.Length
;
1116 procedure Move
(Target
: in out List
; Source
: in out List
) is
1118 if Target
'Address = Source
'Address then
1122 TC_Check
(Source
.TC
);
1126 Target
.First
:= Source
.First
;
1127 Source
.First
:= null;
1129 Target
.Last
:= Source
.Last
;
1130 Source
.Last
:= null;
1132 Target
.Length
:= Source
.Length
;
1140 procedure Next
(Position
: in out Cursor
) is
1142 Position
:= Next
(Position
);
1145 function Next
(Position
: Cursor
) return Cursor
is
1147 if Position
.Node
= null then
1151 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1154 Next_Node
: constant Node_Access
:= Position
.Node
.Next
;
1156 if Next_Node
= null then
1159 return Cursor
'(Position.Container, Next_Node);
1165 function Next (Object : Iterator; Position : Cursor) return Cursor is
1167 if Position.Container = null then
1171 if Checks and then Position.Container /= Object.Container then
1172 raise Program_Error with
1173 "Position cursor of Next designates wrong list";
1176 return Next (Position);
1184 (Container : in out List;
1185 New_Item : Element_Type;
1186 Count : Count_Type := 1)
1189 Insert (Container, First (Container), New_Item, Count);
1196 procedure Previous (Position : in out Cursor) is
1198 Position := Previous (Position);
1201 function Previous (Position : Cursor) return Cursor is
1203 if Position.Node = null then
1207 pragma Assert (Vet (Position), "bad cursor in Previous");
1210 Prev_Node : constant Node_Access := Position.Node.Prev;
1212 if Prev_Node = null then
1215 return Cursor'(Position
.Container
, Prev_Node
);
1221 function Previous
(Object
: Iterator
; Position
: Cursor
) return Cursor
is
1223 if Position
.Container
= null then
1227 if Checks
and then Position
.Container
/= Object
.Container
then
1228 raise Program_Error
with
1229 "Position cursor of Previous designates wrong list";
1232 return Previous
(Position
);
1235 ----------------------
1236 -- Pseudo_Reference --
1237 ----------------------
1239 function Pseudo_Reference
1240 (Container
: aliased List
'Class) return Reference_Control_Type
1242 TC
: constant Tamper_Counts_Access
:= Container
.TC
'Unrestricted_Access;
1244 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
1247 end Pseudo_Reference
;
1253 procedure Query_Element
1255 Process
: not null access procedure (Element
: Element_Type
))
1258 if Checks
and then Position
.Node
= null then
1259 raise Constraint_Error
with
1260 "Position cursor has no element";
1263 if Checks
and then Position
.Node
.Element
= null then
1264 raise Program_Error
with
1265 "Position cursor has no element";
1268 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1271 Lock
: With_Lock
(Position
.Container
.TC
'Unrestricted_Access);
1273 Process
(Position
.Node
.Element
.all);
1282 (S
: in out Ada
.Strings
.Text_Buffers
.Root_Buffer_Type
'Class; V
: List
)
1284 First_Time
: Boolean := True;
1285 use System
.Put_Images
;
1291 First_Time
:= False;
1293 Simple_Array_Between
(S
);
1296 Element_Type
'Put_Image (S
, X
);
1307 (Stream
: not null access Root_Stream_Type
'Class;
1310 N
: Count_Type
'Base;
1316 Count_Type
'Base'Read (Stream, N);
1323 Element : Element_Access :=
1324 new Element_Type'(Element_Type
'Input (Stream
));
1326 Dst
:= new Node_Type
'(Element, null, null);
1337 while Item.Length < N loop
1339 Element : Element_Access :=
1340 new Element_Type'(Element_Type
'Input (Stream
));
1342 Dst
:= new Node_Type
'(Element, Next => null, Prev => Item.Last);
1349 Item.Last.Next := Dst;
1351 Item.Length := Item.Length + 1;
1356 (Stream : not null access Root_Stream_Type'Class;
1360 raise Program_Error with "attempt to stream list cursor";
1364 (Stream : not null access Root_Stream_Type'Class;
1365 Item : out Reference_Type)
1368 raise Program_Error with "attempt to stream reference";
1372 (Stream : not null access Root_Stream_Type'Class;
1373 Item : out Constant_Reference_Type)
1376 raise Program_Error with "attempt to stream reference";
1384 (Container : aliased in out List;
1385 Position : Cursor) return Reference_Type
1388 if Checks and then Position.Container = null then
1389 raise Constraint_Error with "Position cursor has no element";
1392 if Checks and then Position.Container /= Container'Unrestricted_Access
1394 raise Program_Error with
1395 "Position cursor designates wrong container";
1398 if Checks and then Position.Node.Element = null then
1399 raise Program_Error with "Node has no element";
1402 pragma Assert (Vet (Position), "bad cursor in function Reference");
1405 TC : constant Tamper_Counts_Access :=
1406 Container.TC'Unrestricted_Access;
1408 return R : constant Reference_Type :=
1409 (Element => Position.Node.Element,
1410 Control => (Controlled with TC))
1417 ---------------------
1418 -- Replace_Element --
1419 ---------------------
1421 procedure Replace_Element
1422 (Container : in out List;
1424 New_Item : Element_Type)
1427 TE_Check (Container.TC);
1429 if Checks and then Position.Container = null then
1430 raise Constraint_Error with "Position cursor has no element";
1433 if Checks and then Position.Container /= Container'Unchecked_Access then
1434 raise Program_Error with
1435 "Position cursor designates wrong container";
1438 if Checks and then Position.Node.Element = null then
1439 raise Program_Error with
1440 "Position cursor has no element";
1443 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1446 -- The element allocator may need an accessibility check in the
1447 -- case the actual type is class-wide or has access discriminants
1448 -- (see RM 4.8(10.1) and AI12-0035).
1450 pragma Unsuppress (Accessibility_Check);
1452 X : Element_Access := Position.Node.Element;
1455 Position.Node.Element := new Element_Type'(New_Item
);
1458 end Replace_Element
;
1460 ----------------------
1461 -- Reverse_Elements --
1462 ----------------------
1464 procedure Reverse_Elements
(Container
: in out List
) is
1465 I
: Node_Access
:= Container
.First
;
1466 J
: Node_Access
:= Container
.Last
;
1468 procedure Swap
(L
, R
: Node_Access
);
1474 procedure Swap
(L
, R
: Node_Access
) is
1475 LN
: constant Node_Access
:= L
.Next
;
1476 LP
: constant Node_Access
:= L
.Prev
;
1478 RN
: constant Node_Access
:= R
.Next
;
1479 RP
: constant Node_Access
:= R
.Prev
;
1494 pragma Assert
(RP
= L
);
1508 -- Start of processing for Reverse_Elements
1511 if Container
.Length
<= 1 then
1515 pragma Assert
(Container
.First
.Prev
= null);
1516 pragma Assert
(Container
.Last
.Next
= null);
1518 TC_Check
(Container
.TC
);
1520 Container
.First
:= J
;
1521 Container
.Last
:= I
;
1523 Swap
(L
=> I
, R
=> J
);
1531 Swap
(L
=> J
, R
=> I
);
1540 pragma Assert
(Container
.First
.Prev
= null);
1541 pragma Assert
(Container
.Last
.Next
= null);
1542 end Reverse_Elements
;
1548 function Reverse_Find
1550 Item
: Element_Type
;
1551 Position
: Cursor
:= No_Element
) return Cursor
1553 Node
: Node_Access
:= Position
.Node
;
1557 Node
:= Container
.Last
;
1560 if Checks
and then Node
.Element
= null then
1561 raise Program_Error
with "Position cursor has no element";
1564 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1566 raise Program_Error
with
1567 "Position cursor designates wrong container";
1570 pragma Assert
(Vet
(Position
), "bad cursor in Reverse_Find");
1573 -- Per AI05-0022, the container implementation is required to detect
1574 -- element tampering by a generic actual subprogram.
1577 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
1579 while Node
/= null loop
1580 if Node
.Element
.all = Item
then
1581 return Cursor
'(Container'Unrestricted_Access, Node);
1591 ---------------------
1592 -- Reverse_Iterate --
1593 ---------------------
1595 procedure Reverse_Iterate
1597 Process : not null access procedure (Position : Cursor))
1599 Busy : With_Busy (Container.TC'Unrestricted_Access);
1600 Node : Node_Access := Container.Last;
1603 while Node /= null loop
1604 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1607 end Reverse_Iterate
;
1614 (Target
: in out List
;
1616 Source
: in out List
)
1619 TC_Check
(Target
.TC
);
1620 TC_Check
(Source
.TC
);
1622 if Before
.Container
/= null then
1623 if Checks
and then Before
.Container
/= Target
'Unrestricted_Access then
1624 raise Program_Error
with
1625 "Before cursor designates wrong container";
1629 (Before
.Node
= null or else Before
.Node
.Element
= null)
1631 raise Program_Error
with
1632 "Before cursor has no element";
1635 pragma Assert
(Vet
(Before
), "bad cursor in Splice");
1638 if Target
'Address = Source
'Address or else Source
.Length
= 0 then
1642 if Checks
and then Target
.Length
> Count_Type
'Last - Source
.Length
then
1643 raise Constraint_Error
with "new length exceeds maximum";
1646 Splice_Internal
(Target
, Before
.Node
, Source
);
1650 (Container
: in out List
;
1655 TC_Check
(Container
.TC
);
1657 if Before
.Container
/= null then
1658 if Checks
and then Before
.Container
/= Container
'Unchecked_Access then
1659 raise Program_Error
with
1660 "Before cursor designates wrong container";
1664 (Before
.Node
= null or else Before
.Node
.Element
= null)
1666 raise Program_Error
with
1667 "Before cursor has no element";
1670 pragma Assert
(Vet
(Before
), "bad Before cursor in Splice");
1673 if Checks
and then Position
.Node
= null then
1674 raise Constraint_Error
with "Position cursor has no element";
1677 if Checks
and then Position
.Node
.Element
= null then
1678 raise Program_Error
with "Position cursor has no element";
1681 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
1683 raise Program_Error
with
1684 "Position cursor designates wrong container";
1687 pragma Assert
(Vet
(Position
), "bad Position cursor in Splice");
1689 if Position
.Node
= Before
.Node
1690 or else Position
.Node
.Next
= Before
.Node
1695 pragma Assert
(Container
.Length
>= 2);
1697 if Before
.Node
= null then
1698 pragma Assert
(Position
.Node
/= Container
.Last
);
1700 if Position
.Node
= Container
.First
then
1701 Container
.First
:= Position
.Node
.Next
;
1702 Container
.First
.Prev
:= null;
1704 Position
.Node
.Prev
.Next
:= Position
.Node
.Next
;
1705 Position
.Node
.Next
.Prev
:= Position
.Node
.Prev
;
1708 Container
.Last
.Next
:= Position
.Node
;
1709 Position
.Node
.Prev
:= Container
.Last
;
1711 Container
.Last
:= Position
.Node
;
1712 Container
.Last
.Next
:= null;
1717 if Before
.Node
= Container
.First
then
1718 pragma Assert
(Position
.Node
/= Container
.First
);
1720 if Position
.Node
= Container
.Last
then
1721 Container
.Last
:= Position
.Node
.Prev
;
1722 Container
.Last
.Next
:= null;
1724 Position
.Node
.Prev
.Next
:= Position
.Node
.Next
;
1725 Position
.Node
.Next
.Prev
:= Position
.Node
.Prev
;
1728 Container
.First
.Prev
:= Position
.Node
;
1729 Position
.Node
.Next
:= Container
.First
;
1731 Container
.First
:= Position
.Node
;
1732 Container
.First
.Prev
:= null;
1737 if Position
.Node
= Container
.First
then
1738 Container
.First
:= Position
.Node
.Next
;
1739 Container
.First
.Prev
:= null;
1741 elsif Position
.Node
= Container
.Last
then
1742 Container
.Last
:= Position
.Node
.Prev
;
1743 Container
.Last
.Next
:= null;
1746 Position
.Node
.Prev
.Next
:= Position
.Node
.Next
;
1747 Position
.Node
.Next
.Prev
:= Position
.Node
.Prev
;
1750 Before
.Node
.Prev
.Next
:= Position
.Node
;
1751 Position
.Node
.Prev
:= Before
.Node
.Prev
;
1753 Before
.Node
.Prev
:= Position
.Node
;
1754 Position
.Node
.Next
:= Before
.Node
;
1756 pragma Assert
(Container
.First
.Prev
= null);
1757 pragma Assert
(Container
.Last
.Next
= null);
1761 (Target
: in out List
;
1763 Source
: in out List
;
1764 Position
: in out Cursor
)
1767 if Target
'Address = Source
'Address then
1768 Splice
(Target
, Before
, Position
);
1772 TC_Check
(Target
.TC
);
1773 TC_Check
(Source
.TC
);
1775 if Before
.Container
/= null then
1776 if Checks
and then Before
.Container
/= Target
'Unrestricted_Access then
1777 raise Program_Error
with
1778 "Before cursor designates wrong container";
1782 (Before
.Node
= null or else Before
.Node
.Element
= null)
1784 raise Program_Error
with
1785 "Before cursor has no element";
1788 pragma Assert
(Vet
(Before
), "bad Before cursor in Splice");
1791 if Checks
and then Position
.Node
= null then
1792 raise Constraint_Error
with "Position cursor has no element";
1795 if Checks
and then Position
.Node
.Element
= null then
1796 raise Program_Error
with
1797 "Position cursor has no element";
1800 if Checks
and then Position
.Container
/= Source
'Unrestricted_Access then
1801 raise Program_Error
with
1802 "Position cursor designates wrong container";
1805 pragma Assert
(Vet
(Position
), "bad Position cursor in Splice");
1807 if Checks
and then Target
.Length
= Count_Type
'Last then
1808 raise Constraint_Error
with "Target is full";
1811 Splice_Internal
(Target
, Before
.Node
, Source
, Position
.Node
);
1812 Position
.Container
:= Target
'Unchecked_Access;
1815 ---------------------
1816 -- Splice_Internal --
1817 ---------------------
1819 procedure Splice_Internal
1820 (Target
: in out List
;
1821 Before
: Node_Access
;
1822 Source
: in out List
)
1825 -- This implements the corresponding Splice operation, after the
1826 -- parameters have been vetted, and corner-cases disposed of.
1828 pragma Assert
(Target
'Address /= Source
'Address);
1829 pragma Assert
(Source
.Length
> 0);
1830 pragma Assert
(Source
.First
/= null);
1831 pragma Assert
(Source
.First
.Prev
= null);
1832 pragma Assert
(Source
.Last
/= null);
1833 pragma Assert
(Source
.Last
.Next
= null);
1834 pragma Assert
(Target
.Length
<= Count_Type
'Last - Source
.Length
);
1836 if Target
.Length
= 0 then
1837 pragma Assert
(Before
= null);
1838 pragma Assert
(Target
.First
= null);
1839 pragma Assert
(Target
.Last
= null);
1841 Target
.First
:= Source
.First
;
1842 Target
.Last
:= Source
.Last
;
1844 elsif Before
= null then
1845 pragma Assert
(Target
.Last
.Next
= null);
1847 Target
.Last
.Next
:= Source
.First
;
1848 Source
.First
.Prev
:= Target
.Last
;
1850 Target
.Last
:= Source
.Last
;
1852 elsif Before
= Target
.First
then
1853 pragma Assert
(Target
.First
.Prev
= null);
1855 Source
.Last
.Next
:= Target
.First
;
1856 Target
.First
.Prev
:= Source
.Last
;
1858 Target
.First
:= Source
.First
;
1861 pragma Assert
(Target
.Length
>= 2);
1862 Before
.Prev
.Next
:= Source
.First
;
1863 Source
.First
.Prev
:= Before
.Prev
;
1865 Before
.Prev
:= Source
.Last
;
1866 Source
.Last
.Next
:= Before
;
1869 Source
.First
:= null;
1870 Source
.Last
:= null;
1872 Target
.Length
:= Target
.Length
+ Source
.Length
;
1874 end Splice_Internal
;
1876 procedure Splice_Internal
1877 (Target
: in out List
;
1878 Before
: Node_Access
; -- node of Target
1879 Source
: in out List
;
1880 Position
: Node_Access
) -- node of Source
1883 -- This implements the corresponding Splice operation, after the
1884 -- parameters have been vetted.
1886 pragma Assert
(Target
'Address /= Source
'Address);
1887 pragma Assert
(Target
.Length
< Count_Type
'Last);
1888 pragma Assert
(Source
.Length
> 0);
1889 pragma Assert
(Source
.First
/= null);
1890 pragma Assert
(Source
.First
.Prev
= null);
1891 pragma Assert
(Source
.Last
/= null);
1892 pragma Assert
(Source
.Last
.Next
= null);
1893 pragma Assert
(Position
/= null);
1895 if Position
= Source
.First
then
1896 Source
.First
:= Position
.Next
;
1898 if Position
= Source
.Last
then
1899 pragma Assert
(Source
.First
= null);
1900 pragma Assert
(Source
.Length
= 1);
1901 Source
.Last
:= null;
1904 Source
.First
.Prev
:= null;
1907 elsif Position
= Source
.Last
then
1908 pragma Assert
(Source
.Length
>= 2);
1909 Source
.Last
:= Position
.Prev
;
1910 Source
.Last
.Next
:= null;
1913 pragma Assert
(Source
.Length
>= 3);
1914 Position
.Prev
.Next
:= Position
.Next
;
1915 Position
.Next
.Prev
:= Position
.Prev
;
1918 if Target
.Length
= 0 then
1919 pragma Assert
(Before
= null);
1920 pragma Assert
(Target
.First
= null);
1921 pragma Assert
(Target
.Last
= null);
1923 Target
.First
:= Position
;
1924 Target
.Last
:= Position
;
1926 Target
.First
.Prev
:= null;
1927 Target
.Last
.Next
:= null;
1929 elsif Before
= null then
1930 pragma Assert
(Target
.Last
.Next
= null);
1931 Target
.Last
.Next
:= Position
;
1932 Position
.Prev
:= Target
.Last
;
1934 Target
.Last
:= Position
;
1935 Target
.Last
.Next
:= null;
1937 elsif Before
= Target
.First
then
1938 pragma Assert
(Target
.First
.Prev
= null);
1939 Target
.First
.Prev
:= Position
;
1940 Position
.Next
:= Target
.First
;
1942 Target
.First
:= Position
;
1943 Target
.First
.Prev
:= null;
1946 pragma Assert
(Target
.Length
>= 2);
1947 Before
.Prev
.Next
:= Position
;
1948 Position
.Prev
:= Before
.Prev
;
1950 Before
.Prev
:= Position
;
1951 Position
.Next
:= Before
;
1954 Target
.Length
:= Target
.Length
+ 1;
1955 Source
.Length
:= Source
.Length
- 1;
1956 end Splice_Internal
;
1963 (Container
: in out List
;
1967 TE_Check
(Container
.TC
);
1969 if Checks
and then I
.Node
= null then
1970 raise Constraint_Error
with "I cursor has no element";
1973 if Checks
and then J
.Node
= null then
1974 raise Constraint_Error
with "J cursor has no element";
1977 if Checks
and then I
.Container
/= Container
'Unchecked_Access then
1978 raise Program_Error
with "I cursor designates wrong container";
1981 if Checks
and then J
.Container
/= Container
'Unchecked_Access then
1982 raise Program_Error
with "J cursor designates wrong container";
1985 if I
.Node
= J
.Node
then
1989 pragma Assert
(Vet
(I
), "bad I cursor in Swap");
1990 pragma Assert
(Vet
(J
), "bad J cursor in Swap");
1993 EI_Copy
: constant Element_Access
:= I
.Node
.Element
;
1996 I
.Node
.Element
:= J
.Node
.Element
;
1997 J
.Node
.Element
:= EI_Copy
;
2005 procedure Swap_Links
2006 (Container
: in out List
;
2010 TC_Check
(Container
.TC
);
2012 if Checks
and then I
.Node
= null then
2013 raise Constraint_Error
with "I cursor has no element";
2016 if Checks
and then J
.Node
= null then
2017 raise Constraint_Error
with "J cursor has no element";
2020 if Checks
and then I
.Container
/= Container
'Unrestricted_Access then
2021 raise Program_Error
with "I cursor designates wrong container";
2024 if Checks
and then J
.Container
/= Container
'Unrestricted_Access then
2025 raise Program_Error
with "J cursor designates wrong container";
2028 if I
.Node
= J
.Node
then
2032 pragma Assert
(Vet
(I
), "bad I cursor in Swap_Links");
2033 pragma Assert
(Vet
(J
), "bad J cursor in Swap_Links");
2036 I_Next
: constant Cursor
:= Next
(I
);
2040 Splice
(Container
, Before
=> I
, Position
=> J
);
2044 J_Next
: constant Cursor
:= Next
(J
);
2048 Splice
(Container
, Before
=> J
, Position
=> I
);
2051 pragma Assert
(Container
.Length
>= 3);
2053 Splice
(Container
, Before
=> I_Next
, Position
=> J
);
2054 Splice
(Container
, Before
=> J_Next
, Position
=> I
);
2060 pragma Assert
(Container
.First
.Prev
= null);
2061 pragma Assert
(Container
.Last
.Next
= null);
2064 --------------------
2065 -- Update_Element --
2066 --------------------
2068 procedure Update_Element
2069 (Container
: in out List
;
2071 Process
: not null access procedure (Element
: in out Element_Type
))
2074 if Checks
and then Position
.Node
= null then
2075 raise Constraint_Error
with "Position cursor has no element";
2078 if Checks
and then Position
.Node
.Element
= null then
2079 raise Program_Error
with
2080 "Position cursor has no element";
2083 if Checks
and then Position
.Container
/= Container
'Unchecked_Access then
2084 raise Program_Error
with
2085 "Position cursor designates wrong container";
2088 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
2091 Lock
: With_Lock
(Container
.TC
'Unchecked_Access);
2093 Process
(Position
.Node
.Element
.all);
2101 function Vet
(Position
: Cursor
) return Boolean is
2103 if not Container_Checks
'Enabled then
2107 if Position
.Node
= null then
2108 return Position
.Container
= null;
2111 if Position
.Container
= null then
2115 -- An invariant of a node is that its Previous and Next components can
2116 -- be null, or designate a different node. Also, its element access
2117 -- value must be non-null. Operation Free sets the node access value
2118 -- components of the node to designate the node itself, and the element
2119 -- access value to null, before actually deallocating the node, thus
2120 -- deliberately violating the node invariant. This gives us a simple way
2121 -- to detect a dangling reference to a node.
2123 if Position
.Node
.Next
= Position
.Node
then
2127 if Position
.Node
.Prev
= Position
.Node
then
2131 if Position
.Node
.Element
= null then
2135 -- In practice the tests above will detect most instances of a dangling
2136 -- reference. If we get here, it means that the invariants of the
2137 -- designated node are satisfied (they at least appear to be satisfied),
2138 -- so we perform some more tests, to determine whether invariants of the
2139 -- designated list are satisfied too.
2142 L
: List
renames Position
.Container
.all;
2145 if L
.Length
= 0 then
2149 if L
.First
= null then
2153 if L
.Last
= null then
2157 if L
.First
.Prev
/= null then
2161 if L
.Last
.Next
/= null then
2165 if Position
.Node
.Prev
= null and then Position
.Node
/= L
.First
then
2169 if Position
.Node
.Next
= null and then Position
.Node
/= L
.Last
then
2173 if L
.Length
= 1 then
2174 return L
.First
= L
.Last
;
2177 if L
.First
= L
.Last
then
2181 if L
.First
.Next
= null then
2185 if L
.Last
.Prev
= null then
2189 if L
.First
.Next
.Prev
/= L
.First
then
2193 if L
.Last
.Prev
.Next
/= L
.Last
then
2197 if L
.Length
= 2 then
2198 if L
.First
.Next
/= L
.Last
then
2202 if L
.Last
.Prev
/= L
.First
then
2209 if L
.First
.Next
= L
.Last
then
2213 if L
.Last
.Prev
= L
.First
then
2217 if Position
.Node
= L
.First
then
2221 if Position
.Node
= L
.Last
then
2225 if Position
.Node
.Next
= null then
2229 if Position
.Node
.Prev
= null then
2233 if Position
.Node
.Next
.Prev
/= Position
.Node
then
2237 if Position
.Node
.Prev
.Next
/= Position
.Node
then
2241 if L
.Length
= 3 then
2242 if L
.First
.Next
/= Position
.Node
then
2246 if L
.Last
.Prev
/= Position
.Node
then
2260 (Stream
: not null access Root_Stream_Type
'Class;
2263 Node
: Node_Access
:= Item
.First
;
2266 Count_Type
'Base'Write (Stream, Item.Length);
2268 while Node /= null loop
2269 Element_Type'Output (Stream, Node.Element.all);
2275 (Stream : not null access Root_Stream_Type'Class;
2279 raise Program_Error with "attempt to stream list cursor";
2283 (Stream : not null access Root_Stream_Type'Class;
2284 Item : Reference_Type)
2287 raise Program_Error with "attempt to stream reference";
2291 (Stream : not null access Root_Stream_Type'Class;
2292 Item : Constant_Reference_Type)
2295 raise Program_Error with "attempt to stream reference";
2298 end Ada.Containers.Indefinite_Doubly_Linked_Lists;