1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2004-2011, 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
37 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
39 type Iterator is new Limited_Controlled and
40 List_Iterator_Interfaces.Reversible_Iterator with
42 Container : List_Access;
46 overriding procedure Finalize (Object : in out Iterator);
48 overriding function First (Object : Iterator) return Cursor;
49 overriding function Last (Object : Iterator) return Cursor;
51 overriding function Next
53 Position : Cursor) return Cursor;
55 overriding function Previous
57 Position : Cursor) return Cursor;
59 -----------------------
60 -- Local Subprograms --
61 -----------------------
63 procedure Free (X : in out Node_Access);
65 procedure Insert_Internal
66 (Container : in out List;
68 New_Node : Node_Access);
70 function Vet (Position : Cursor) return Boolean;
76 function "=" (Left, Right : List) return Boolean is
81 if Left'Address = Right'Address then
85 if Left.Length /= Right.Length then
91 for J in 1 .. Left.Length loop
92 if L.Element.all /= R.Element.all then
107 procedure Adjust (Container : in out List) is
108 Src : Node_Access := Container.First;
113 pragma Assert (Container.Last = null);
114 pragma Assert (Container.Length = 0);
115 pragma Assert (Container.Busy = 0);
116 pragma Assert (Container.Lock = 0);
120 pragma Assert (Container.First.Prev = null);
121 pragma Assert (Container.Last.Next = null);
122 pragma Assert (Container.Length > 0);
124 Container.First := null;
125 Container.Last := null;
126 Container.Length := 0;
131 Element : Element_Access := new Element_Type'(Src.Element.all);
133 Dst := new Node_Type'(Element, null, null);
140 Container.First := Dst;
141 Container.Last := Dst;
142 Container.Length := 1;
145 while Src /= null loop
147 Element : Element_Access := new Element_Type'(Src.Element.all);
149 Dst := new Node_Type'(Element, null, Prev => Container.Last);
156 Container.Last.Next := Dst;
157 Container.Last := Dst;
158 Container.Length := Container.Length + 1;
169 (Container : in out List;
170 New_Item : Element_Type;
171 Count : Count_Type := 1)
174 Insert (Container, No_Element, New_Item, Count);
181 procedure Assign (Target : in out List; Source : List) is
185 if Target'Address = Source'Address then
191 Node := Source.First;
192 while Node /= null loop
193 Target.Append (Node.Element.all);
202 procedure Clear (Container : in out List) is
204 pragma Warnings (Off, X);
207 if Container.Length = 0 then
208 pragma Assert (Container.First = null);
209 pragma Assert (Container.Last = null);
210 pragma Assert (Container.Busy = 0);
211 pragma Assert (Container.Lock = 0);
215 pragma Assert (Container.First.Prev = null);
216 pragma Assert (Container.Last.Next = null);
218 if Container.Busy > 0 then
219 raise Program_Error with
220 "attempt to tamper with cursors (list is busy)";
223 while Container.Length > 1 loop
224 X := Container.First;
225 pragma Assert (X.Next.Prev = Container.First);
227 Container.First := X.Next;
228 Container.First.Prev := null;
230 Container.Length := Container.Length - 1;
235 X := Container.First;
236 pragma Assert (X = Container.Last);
238 Container.First := null;
239 Container.Last := null;
240 Container.Length := 0;
251 Item : Element_Type) return Boolean
254 return Find (Container, Item) /= No_Element;
261 function Copy (Source : List) return List is
263 return Target : List do
264 Target.Assign (Source);
273 (Container : in out List;
274 Position : in out Cursor;
275 Count : Count_Type := 1)
280 if Position.Node = null then
281 raise Constraint_Error with
282 "Position cursor has no element";
285 if Position.Node.Element = null then
286 raise Program_Error with
287 "Position cursor has no element";
290 if Position.Container /= Container'Unrestricted_Access then
291 raise Program_Error with
292 "Position cursor designates wrong container";
295 pragma Assert (Vet (Position), "bad cursor in Delete");
297 if Position.Node = Container.First then
298 Delete_First (Container, Count);
299 Position := No_Element; -- Post-York behavior
304 Position := No_Element; -- Post-York behavior
308 if Container.Busy > 0 then
309 raise Program_Error with
310 "attempt to tamper with cursors (list is busy)";
313 for Index in 1 .. Count loop
315 Container.Length := Container.Length - 1;
317 if X = Container.Last then
318 Position := No_Element;
320 Container.Last := X.Prev;
321 Container.Last.Next := null;
327 Position.Node := X.Next;
329 X.Next.Prev := X.Prev;
330 X.Prev.Next := X.Next;
335 Position := No_Element; -- Post-York behavior
342 procedure Delete_First
343 (Container : in out List;
344 Count : Count_Type := 1)
349 if Count >= Container.Length then
358 if Container.Busy > 0 then
359 raise Program_Error with
360 "attempt to tamper with cursors (list is busy)";
363 for I in 1 .. Count loop
364 X := Container.First;
365 pragma Assert (X.Next.Prev = Container.First);
367 Container.First := X.Next;
368 Container.First.Prev := null;
370 Container.Length := Container.Length - 1;
380 procedure Delete_Last
381 (Container : in out List;
382 Count : Count_Type := 1)
387 if Count >= Container.Length then
396 if Container.Busy > 0 then
397 raise Program_Error with
398 "attempt to tamper with cursors (list is busy)";
401 for I in 1 .. Count loop
403 pragma Assert (X.Prev.Next = Container.Last);
405 Container.Last := X.Prev;
406 Container.Last.Next := null;
408 Container.Length := Container.Length - 1;
418 function Element (Position : Cursor) return Element_Type is
420 if Position.Node = null then
421 raise Constraint_Error with
422 "Position cursor has no element";
425 if Position.Node.Element = null then
426 raise Program_Error with
427 "Position cursor has no element";
430 pragma Assert (Vet (Position), "bad cursor in Element");
432 return Position.Node.Element.all;
439 procedure Finalize (Object : in out Iterator) is
441 if Object.Container /= null then
443 B : Natural renames Object.Container.all.Busy;
457 Position : Cursor := No_Element) return Cursor
459 Node : Node_Access := Position.Node;
463 Node := Container.First;
466 if Node.Element = null then
470 if Position.Container /= Container'Unrestricted_Access then
471 raise Program_Error with
472 "Position cursor designates wrong container";
475 pragma Assert (Vet (Position), "bad cursor in Find");
478 while Node /= null loop
479 if Node.Element.all = Item then
480 return Cursor'(Container'Unrestricted_Access, Node);
493 function First (Container : List) return Cursor is
495 if Container.First = null then
499 return Cursor'(Container'Unrestricted_Access, Container.First);
502 function First (Object : Iterator) return Cursor is
504 -- The value of the iterator object's Node component influences the
505 -- behavior of the First (and Last) selector function.
507 -- When the Node component is null, this means the iterator object was
508 -- constructed without a start expression, in which case the (forward)
509 -- iteration starts from the (logical) beginning of the entire sequence
510 -- of items (corresponding to Container.First, for a forward iterator).
512 -- Otherwise, this is iteration over a partial sequence of items. When
513 -- the Node component is non-null, the iterator object was constructed
514 -- with a start expression, that specifies the position from which the
515 -- (forward) partial iteration begins.
517 if Object.Node = null then
518 return Indefinite_Doubly_Linked_Lists.First (Object.Container.all);
520 return Cursor'(Object.Container, Object.Node);
528 function First_Element (Container : List) return Element_Type is
530 if Container.First = null then
531 raise Constraint_Error with "list is empty";
534 return Container.First.Element.all;
541 procedure Free (X : in out Node_Access) is
542 procedure Deallocate is
543 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
561 ---------------------
562 -- Generic_Sorting --
563 ---------------------
565 package body Generic_Sorting is
571 function Is_Sorted (Container : List) return Boolean is
572 Node : Node_Access := Container.First;
575 for I in 2 .. Container.Length loop
576 if Node.Next.Element.all < Node.Element.all then
591 (Target : in out List;
592 Source : in out List)
598 -- The semantics of Merge changed slightly per AI05-0021. It was
599 -- originally the case that if Target and Source denoted the same
600 -- container object, then the GNAT implementation of Merge did
601 -- nothing. However, it was argued that RM05 did not precisely
602 -- specify the semantics for this corner case. The decision of the
603 -- ARG was that if Target and Source denote the same non-empty
604 -- container object, then Program_Error is raised.
606 if Source.Is_Empty then
610 if Target'Address = Source'Address then
611 raise Program_Error with
612 "Target and Source denote same non-empty container";
615 if Target.Busy > 0 then
616 raise Program_Error with
617 "attempt to tamper with cursors of Target (list is busy)";
620 if Source.Busy > 0 then
621 raise Program_Error with
622 "attempt to tamper with cursors of Source (list is busy)";
625 LI := First (Target);
626 RI := First (Source);
627 while RI.Node /= null loop
628 pragma Assert (RI.Node.Next = null
629 or else not (RI.Node.Next.Element.all <
630 RI.Node.Element.all));
632 if LI.Node = null then
633 Splice (Target, No_Element, Source);
637 pragma Assert (LI.Node.Next = null
638 or else not (LI.Node.Next.Element.all <
639 LI.Node.Element.all));
641 if RI.Node.Element.all < LI.Node.Element.all then
644 pragma Warnings (Off, RJ);
646 RI.Node := RI.Node.Next;
647 Splice (Target, LI, Source, RJ);
651 LI.Node := LI.Node.Next;
660 procedure Sort (Container : in out List) is
661 procedure Partition (Pivot : Node_Access; Back : Node_Access);
663 procedure Sort (Front, Back : Node_Access);
669 procedure Partition (Pivot : Node_Access; Back : Node_Access) is
670 Node : Node_Access := Pivot.Next;
673 while Node /= Back loop
674 if Node.Element.all < Pivot.Element.all then
676 Prev : constant Node_Access := Node.Prev;
677 Next : constant Node_Access := Node.Next;
682 Container.Last := Prev;
688 Node.Prev := Pivot.Prev;
692 if Node.Prev = null then
693 Container.First := Node;
695 Node.Prev.Next := Node;
711 procedure Sort (Front, Back : Node_Access) is
712 Pivot : constant Node_Access :=
713 (if Front = null then Container.First else Front.Next);
715 if Pivot /= Back then
716 Partition (Pivot, Back);
722 -- Start of processing for Sort
725 if Container.Length <= 1 then
729 pragma Assert (Container.First.Prev = null);
730 pragma Assert (Container.Last.Next = null);
732 if Container.Busy > 0 then
733 raise Program_Error with
734 "attempt to tamper with cursors (list is busy)";
737 Sort (Front => null, Back => null);
739 pragma Assert (Container.First.Prev = null);
740 pragma Assert (Container.Last.Next = null);
749 function Has_Element (Position : Cursor) return Boolean is
751 pragma Assert (Vet (Position), "bad cursor in Has_Element");
752 return Position.Node /= null;
760 (Container : in out List;
762 New_Item : Element_Type;
763 Position : out Cursor;
764 Count : Count_Type := 1)
766 New_Node : Node_Access;
769 if Before.Container /= null then
770 if Before.Container /= Container'Unrestricted_Access then
771 raise Program_Error with
772 "attempt to tamper with cursors (list is busy)";
775 if Before.Node = null
776 or else Before.Node.Element = null
778 raise Program_Error with
779 "Before cursor has no element";
782 pragma Assert (Vet (Before), "bad cursor in Insert");
790 if Container.Length > Count_Type'Last - Count then
791 raise Constraint_Error with "new length exceeds maximum";
794 if Container.Busy > 0 then
795 raise Program_Error with
796 "attempt to tamper with cursors (list is busy)";
800 Element : Element_Access := new Element_Type'(New_Item);
802 New_Node := new Node_Type'(Element, null, null);
809 Insert_Internal (Container, Before.Node, New_Node);
810 Position := Cursor'(Container'Unchecked_Access, New_Node);
812 for J in Count_Type'(2) .. Count loop
815 Element : Element_Access := new Element_Type'(New_Item);
817 New_Node := new Node_Type'(Element, null, null);
824 Insert_Internal (Container, Before.Node, New_Node);
829 (Container : in out List;
831 New_Item : Element_Type;
832 Count : Count_Type := 1)
835 pragma Unreferenced (Position);
837 Insert (Container, Before, New_Item, Position, Count);
840 ---------------------
841 -- Insert_Internal --
842 ---------------------
844 procedure Insert_Internal
845 (Container : in out List;
846 Before : Node_Access;
847 New_Node : Node_Access)
850 if Container.Length = 0 then
851 pragma Assert (Before = null);
852 pragma Assert (Container.First = null);
853 pragma Assert (Container.Last = null);
855 Container.First := New_Node;
856 Container.Last := New_Node;
858 elsif Before = null then
859 pragma Assert (Container.Last.Next = null);
861 Container.Last.Next := New_Node;
862 New_Node.Prev := Container.Last;
864 Container.Last := New_Node;
866 elsif Before = Container.First then
867 pragma Assert (Container.First.Prev = null);
869 Container.First.Prev := New_Node;
870 New_Node.Next := Container.First;
872 Container.First := New_Node;
875 pragma Assert (Container.First.Prev = null);
876 pragma Assert (Container.Last.Next = null);
878 New_Node.Next := Before;
879 New_Node.Prev := Before.Prev;
881 Before.Prev.Next := New_Node;
882 Before.Prev := New_Node;
885 Container.Length := Container.Length + 1;
892 function Is_Empty (Container : List) return Boolean is
894 return Container.Length = 0;
903 Process : not null access procedure (Position : Cursor))
905 B : Natural renames Container'Unrestricted_Access.all.Busy;
906 Node : Node_Access := Container.First;
912 while Node /= null loop
913 Process (Cursor'(Container'Unrestricted_Access, Node));
927 return List_Iterator_Interfaces.Reversible_Iterator'class
929 B : Natural renames Container'Unrestricted_Access.all.Busy;
932 -- The value of the Node component influences the behavior of the First
933 -- and Last selector functions of the iterator object. When the Node
934 -- component is null (as is the case here), this means the iterator
935 -- object was constructed without a start expression. This is a
936 -- complete iterator, meaning that the iteration starts from the
937 -- (logical) beginning of the sequence of items.
939 -- Note: For a forward iterator, Container.First is the beginning, and
940 -- for a reverse iterator, Container.Last is the beginning.
942 return It : constant Iterator :=
943 Iterator'(Limited_Controlled with
944 Container => Container'Unrestricted_Access,
954 return List_Iterator_Interfaces.Reversible_Iterator'Class
956 B : Natural renames Container'Unrestricted_Access.all.Busy;
959 -- It was formerly the case that when Start = No_Element, the partial
960 -- iterator was defined to behave the same as for a complete iterator,
961 -- and iterate over the entire sequence of items. However, those
962 -- semantics were unintuitive and arguably error-prone (it is too easy
963 -- to accidentally create an endless loop), and so they were changed,
964 -- per the ARG meeting in Denver on 2011/11. However, there was no
965 -- consensus about what positive meaning this corner case should have,
966 -- and so it was decided to simply raise an exception. This does imply,
967 -- however, that it is not possible to use a partial iterator to specify
968 -- an empty sequence of items.
970 if Start = No_Element then
971 raise Constraint_Error with
972 "Start position for iterator equals No_Element";
975 if Start.Container /= Container'Unrestricted_Access then
976 raise Program_Error with
977 "Start cursor of Iterate designates wrong list";
980 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
982 -- The value of the Node component influences the behavior of the First
983 -- and Last selector functions of the iterator object. When the Node
984 -- component is non-null (as is the case here), it means that this
985 -- is a partial iteration, over a subset of the complete sequence of
986 -- items. The iterator object was constructed with a start expression,
987 -- indicating the position from which the iteration begins. Note that
988 -- the start position has the same value irrespective of whether this
989 -- is a forward or reverse iteration.
991 return It : constant Iterator :=
992 Iterator'(Limited_Controlled with
993 Container => Container'Unrestricted_Access,
1004 function Last (Container : List) return Cursor is
1006 if Container.Last = null then
1010 return Cursor'(Container'Unrestricted_Access, Container.Last);
1013 function Last (Object : Iterator) return Cursor is
1015 -- The value of the iterator object's Node component influences the
1016 -- behavior of the Last (and First) selector function.
1018 -- When the Node component is null, this means the iterator object was
1019 -- constructed without a start expression, in which case the (reverse)
1020 -- iteration starts from the (logical) beginning of the entire sequence
1021 -- (corresponding to Container.Last, for a reverse iterator).
1023 -- Otherwise, this is iteration over a partial sequence of items. When
1024 -- the Node component is non-null, the iterator object was constructed
1025 -- with a start expression, that specifies the position from which the
1026 -- (reverse) partial iteration begins.
1028 if Object.Node = null then
1029 return Indefinite_Doubly_Linked_Lists.Last (Object.Container.all);
1031 return Cursor'(Object.Container, Object.Node);
1039 function Last_Element (Container : List) return Element_Type is
1041 if Container.Last = null then
1042 raise Constraint_Error with "list is empty";
1045 return Container.Last.Element.all;
1052 function Length (Container : List) return Count_Type is
1054 return Container.Length;
1061 procedure Move (Target : in out List; Source : in out List) is
1063 if Target'Address = Source'Address then
1067 if Source.Busy > 0 then
1068 raise Program_Error with
1069 "attempt to tamper with cursors of Source (list is busy)";
1074 Target.First := Source.First;
1075 Source.First := null;
1077 Target.Last := Source.Last;
1078 Source.Last := null;
1080 Target.Length := Source.Length;
1088 procedure Next (Position : in out Cursor) is
1090 Position := Next (Position);
1093 function Next (Position : Cursor) return Cursor is
1095 if Position.Node = null then
1099 pragma Assert (Vet (Position), "bad cursor in Next");
1102 Next_Node : constant Node_Access := Position.Node.Next;
1104 if Next_Node = null then
1108 return Cursor'(Position.Container, Next_Node);
1112 function Next (Object : Iterator; Position : Cursor) return Cursor is
1114 if Position.Container = null then
1118 if Position.Container /= Object.Container then
1119 raise Program_Error with
1120 "Position cursor of Next designates wrong list";
1123 return Next (Position);
1131 (Container : in out List;
1132 New_Item : Element_Type;
1133 Count : Count_Type := 1)
1136 Insert (Container, First (Container), New_Item, Count);
1143 procedure Previous (Position : in out Cursor) is
1145 Position := Previous (Position);
1148 function Previous (Position : Cursor) return Cursor is
1150 if Position.Node = null then
1154 pragma Assert (Vet (Position), "bad cursor in Previous");
1157 Prev_Node : constant Node_Access := Position.Node.Prev;
1159 if Prev_Node = null then
1163 return Cursor'(Position.Container, Prev_Node);
1167 function Previous (Object : Iterator; Position : Cursor) return Cursor is
1169 if Position.Container = null then
1173 if Position.Container /= Object.Container then
1174 raise Program_Error with
1175 "Position cursor of Previous designates wrong list";
1178 return Previous (Position);
1185 procedure Query_Element
1187 Process : not null access procedure (Element : Element_Type))
1190 if Position.Node = null then
1191 raise Constraint_Error with
1192 "Position cursor has no element";
1195 if Position.Node.Element = null then
1196 raise Program_Error with
1197 "Position cursor has no element";
1200 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1203 C : List renames Position.Container.all'Unrestricted_Access.all;
1204 B : Natural renames C.Busy;
1205 L : Natural renames C.Lock;
1212 Process (Position.Node.Element.all);
1230 (Stream : not null access Root_Stream_Type'Class;
1233 N : Count_Type'Base;
1239 Count_Type'Base'Read (Stream, N);
1246 Element : Element_Access :=
1247 new Element_Type'(Element_Type'Input (Stream));
1249 Dst := new Node_Type'(Element, null, null);
1260 while Item.Length < N loop
1262 Element : Element_Access :=
1263 new Element_Type'(Element_Type'Input (Stream));
1265 Dst := new Node_Type'(Element, Next => null, Prev => Item.Last);
1272 Item.Last.Next := Dst;
1274 Item.Length := Item.Length + 1;
1279 (Stream : not null access Root_Stream_Type'Class;
1283 raise Program_Error with "attempt to stream list cursor";
1287 (Stream : not null access Root_Stream_Type'Class;
1288 Item : out Reference_Type)
1291 raise Program_Error with "attempt to stream reference";
1295 (Stream : not null access Root_Stream_Type'Class;
1296 Item : out Constant_Reference_Type)
1299 raise Program_Error with "attempt to stream reference";
1306 function Constant_Reference (Container : List; Position : Cursor)
1307 return Constant_Reference_Type is
1309 pragma Unreferenced (Container);
1311 if Position.Container = null then
1312 raise Constraint_Error with "Position cursor has no element";
1315 return (Element => Position.Node.Element.all'Access);
1316 end Constant_Reference;
1318 function Reference (Container : List; Position : Cursor)
1319 return Reference_Type is
1321 pragma Unreferenced (Container);
1323 if Position.Container = null then
1324 raise Constraint_Error with "Position cursor has no element";
1327 return (Element => Position.Node.Element.all'Access);
1330 ---------------------
1331 -- Replace_Element --
1332 ---------------------
1334 procedure Replace_Element
1335 (Container : in out List;
1337 New_Item : Element_Type)
1340 if Position.Container = null then
1341 raise Constraint_Error with "Position cursor has no element";
1344 if Position.Container /= Container'Unchecked_Access then
1345 raise Program_Error with
1346 "Position cursor designates wrong container";
1349 if Container.Lock > 0 then
1350 raise Program_Error with
1351 "attempt to tamper with elements (list is locked)";
1354 if Position.Node.Element = null then
1355 raise Program_Error with
1356 "Position cursor has no element";
1359 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1362 X : Element_Access := Position.Node.Element;
1365 Position.Node.Element := new Element_Type'(New_Item);
1368 end Replace_Element;
1370 ----------------------
1371 -- Reverse_Elements --
1372 ----------------------
1374 procedure Reverse_Elements (Container : in out List) is
1375 I : Node_Access := Container.First;
1376 J : Node_Access := Container.Last;
1378 procedure Swap (L, R : Node_Access);
1384 procedure Swap (L, R : Node_Access) is
1385 LN : constant Node_Access := L.Next;
1386 LP : constant Node_Access := L.Prev;
1388 RN : constant Node_Access := R.Next;
1389 RP : constant Node_Access := R.Prev;
1404 pragma Assert (RP = L);
1418 -- Start of processing for Reverse_Elements
1421 if Container.Length <= 1 then
1425 pragma Assert (Container.First.Prev = null);
1426 pragma Assert (Container.Last.Next = null);
1428 if Container.Busy > 0 then
1429 raise Program_Error with
1430 "attempt to tamper with cursors (list is busy)";
1433 Container.First := J;
1434 Container.Last := I;
1436 Swap (L => I, R => J);
1444 Swap (L => J, R => I);
1453 pragma Assert (Container.First.Prev = null);
1454 pragma Assert (Container.Last.Next = null);
1455 end Reverse_Elements;
1461 function Reverse_Find
1463 Item : Element_Type;
1464 Position : Cursor := No_Element) return Cursor
1466 Node : Node_Access := Position.Node;
1470 Node := Container.Last;
1473 if Node.Element = null then
1474 raise Program_Error with "Position cursor has no element";
1477 if Position.Container /= Container'Unrestricted_Access then
1478 raise Program_Error with
1479 "Position cursor designates wrong container";
1482 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1485 while Node /= null loop
1486 if Node.Element.all = Item then
1487 return Cursor'(Container'Unrestricted_Access, Node);
1496 ---------------------
1497 -- Reverse_Iterate --
1498 ---------------------
1500 procedure Reverse_Iterate
1502 Process : not null access procedure (Position : Cursor))
1504 C : List renames Container'Unrestricted_Access.all;
1505 B : Natural renames C.Busy;
1507 Node : Node_Access := Container.Last;
1513 while Node /= null loop
1514 Process (Cursor'(Container'Unrestricted_Access, Node));
1524 end Reverse_Iterate;
1531 (Target : in out List;
1533 Source : in out List)
1536 if Before.Container /= null then
1537 if Before.Container /= Target'Unrestricted_Access then
1538 raise Program_Error with
1539 "Before cursor designates wrong container";
1542 if Before.Node = null
1543 or else Before.Node.Element = null
1545 raise Program_Error with
1546 "Before cursor has no element";
1549 pragma Assert (Vet (Before), "bad cursor in Splice");
1552 if Target'Address = Source'Address
1553 or else Source.Length = 0
1558 pragma Assert (Source.First.Prev = null);
1559 pragma Assert (Source.Last.Next = null);
1561 if Target.Length > Count_Type'Last - Source.Length then
1562 raise Constraint_Error with "new length exceeds maximum";
1565 if Target.Busy > 0 then
1566 raise Program_Error with
1567 "attempt to tamper with cursors of Target (list is busy)";
1570 if Source.Busy > 0 then
1571 raise Program_Error with
1572 "attempt to tamper with cursors of Source (list is busy)";
1575 if Target.Length = 0 then
1576 pragma Assert (Before = No_Element);
1577 pragma Assert (Target.First = null);
1578 pragma Assert (Target.Last = null);
1580 Target.First := Source.First;
1581 Target.Last := Source.Last;
1583 elsif Before.Node = null then
1584 pragma Assert (Target.Last.Next = null);
1586 Target.Last.Next := Source.First;
1587 Source.First.Prev := Target.Last;
1589 Target.Last := Source.Last;
1591 elsif Before.Node = Target.First then
1592 pragma Assert (Target.First.Prev = null);
1594 Source.Last.Next := Target.First;
1595 Target.First.Prev := Source.Last;
1597 Target.First := Source.First;
1600 pragma Assert (Target.Length >= 2);
1601 Before.Node.Prev.Next := Source.First;
1602 Source.First.Prev := Before.Node.Prev;
1604 Before.Node.Prev := Source.Last;
1605 Source.Last.Next := Before.Node;
1608 Source.First := null;
1609 Source.Last := null;
1611 Target.Length := Target.Length + Source.Length;
1616 (Container : in out List;
1621 if Before.Container /= null then
1622 if Before.Container /= Container'Unchecked_Access then
1623 raise Program_Error with
1624 "Before cursor designates wrong container";
1627 if Before.Node = null
1628 or else Before.Node.Element = null
1630 raise Program_Error with
1631 "Before cursor has no element";
1634 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1637 if Position.Node = null then
1638 raise Constraint_Error with "Position cursor has no element";
1641 if Position.Node.Element = null then
1642 raise Program_Error with "Position cursor has no element";
1645 if Position.Container /= Container'Unrestricted_Access then
1646 raise Program_Error with
1647 "Position cursor designates wrong container";
1650 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1652 if Position.Node = Before.Node
1653 or else Position.Node.Next = Before.Node
1658 pragma Assert (Container.Length >= 2);
1660 if Container.Busy > 0 then
1661 raise Program_Error with
1662 "attempt to tamper with cursors (list is busy)";
1665 if Before.Node = null then
1666 pragma Assert (Position.Node /= Container.Last);
1668 if Position.Node = Container.First then
1669 Container.First := Position.Node.Next;
1670 Container.First.Prev := null;
1672 Position.Node.Prev.Next := Position.Node.Next;
1673 Position.Node.Next.Prev := Position.Node.Prev;
1676 Container.Last.Next := Position.Node;
1677 Position.Node.Prev := Container.Last;
1679 Container.Last := Position.Node;
1680 Container.Last.Next := null;
1685 if Before.Node = Container.First then
1686 pragma Assert (Position.Node /= Container.First);
1688 if Position.Node = Container.Last then
1689 Container.Last := Position.Node.Prev;
1690 Container.Last.Next := null;
1692 Position.Node.Prev.Next := Position.Node.Next;
1693 Position.Node.Next.Prev := Position.Node.Prev;
1696 Container.First.Prev := Position.Node;
1697 Position.Node.Next := Container.First;
1699 Container.First := Position.Node;
1700 Container.First.Prev := null;
1705 if Position.Node = Container.First then
1706 Container.First := Position.Node.Next;
1707 Container.First.Prev := null;
1709 elsif Position.Node = Container.Last then
1710 Container.Last := Position.Node.Prev;
1711 Container.Last.Next := null;
1714 Position.Node.Prev.Next := Position.Node.Next;
1715 Position.Node.Next.Prev := Position.Node.Prev;
1718 Before.Node.Prev.Next := Position.Node;
1719 Position.Node.Prev := Before.Node.Prev;
1721 Before.Node.Prev := Position.Node;
1722 Position.Node.Next := Before.Node;
1724 pragma Assert (Container.First.Prev = null);
1725 pragma Assert (Container.Last.Next = null);
1729 (Target : in out List;
1731 Source : in out List;
1732 Position : in out Cursor)
1735 if Target'Address = Source'Address then
1736 Splice (Target, Before, Position);
1740 if Before.Container /= null then
1741 if Before.Container /= Target'Unrestricted_Access then
1742 raise Program_Error with
1743 "Before cursor designates wrong container";
1746 if Before.Node = null
1747 or else Before.Node.Element = null
1749 raise Program_Error with
1750 "Before cursor has no element";
1753 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1756 if Position.Node = null then
1757 raise Constraint_Error with "Position cursor has no element";
1760 if Position.Node.Element = null then
1761 raise Program_Error with
1762 "Position cursor has no element";
1765 if Position.Container /= Source'Unrestricted_Access then
1766 raise Program_Error with
1767 "Position cursor designates wrong container";
1770 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1772 if Target.Length = Count_Type'Last then
1773 raise Constraint_Error with "Target is full";
1776 if Target.Busy > 0 then
1777 raise Program_Error with
1778 "attempt to tamper with cursors of Target (list is busy)";
1781 if Source.Busy > 0 then
1782 raise Program_Error with
1783 "attempt to tamper with cursors of Source (list is busy)";
1786 if Position.Node = Source.First then
1787 Source.First := Position.Node.Next;
1789 if Position.Node = Source.Last then
1790 pragma Assert (Source.First = null);
1791 pragma Assert (Source.Length = 1);
1792 Source.Last := null;
1795 Source.First.Prev := null;
1798 elsif Position.Node = Source.Last then
1799 pragma Assert (Source.Length >= 2);
1800 Source.Last := Position.Node.Prev;
1801 Source.Last.Next := null;
1804 pragma Assert (Source.Length >= 3);
1805 Position.Node.Prev.Next := Position.Node.Next;
1806 Position.Node.Next.Prev := Position.Node.Prev;
1809 if Target.Length = 0 then
1810 pragma Assert (Before = No_Element);
1811 pragma Assert (Target.First = null);
1812 pragma Assert (Target.Last = null);
1814 Target.First := Position.Node;
1815 Target.Last := Position.Node;
1817 Target.First.Prev := null;
1818 Target.Last.Next := null;
1820 elsif Before.Node = null then
1821 pragma Assert (Target.Last.Next = null);
1822 Target.Last.Next := Position.Node;
1823 Position.Node.Prev := Target.Last;
1825 Target.Last := Position.Node;
1826 Target.Last.Next := null;
1828 elsif Before.Node = Target.First then
1829 pragma Assert (Target.First.Prev = null);
1830 Target.First.Prev := Position.Node;
1831 Position.Node.Next := Target.First;
1833 Target.First := Position.Node;
1834 Target.First.Prev := null;
1837 pragma Assert (Target.Length >= 2);
1838 Before.Node.Prev.Next := Position.Node;
1839 Position.Node.Prev := Before.Node.Prev;
1841 Before.Node.Prev := Position.Node;
1842 Position.Node.Next := Before.Node;
1845 Target.Length := Target.Length + 1;
1846 Source.Length := Source.Length - 1;
1848 Position.Container := Target'Unchecked_Access;
1856 (Container : in out List;
1860 if I.Node = null then
1861 raise Constraint_Error with "I cursor has no element";
1864 if J.Node = null then
1865 raise Constraint_Error with "J cursor has no element";
1868 if I.Container /= Container'Unchecked_Access then
1869 raise Program_Error with "I cursor designates wrong container";
1872 if J.Container /= Container'Unchecked_Access then
1873 raise Program_Error with "J cursor designates wrong container";
1876 if I.Node = J.Node then
1880 if Container.Lock > 0 then
1881 raise Program_Error with
1882 "attempt to tamper with elements (list is locked)";
1885 pragma Assert (Vet (I), "bad I cursor in Swap");
1886 pragma Assert (Vet (J), "bad J cursor in Swap");
1889 EI_Copy : constant Element_Access := I.Node.Element;
1892 I.Node.Element := J.Node.Element;
1893 J.Node.Element := EI_Copy;
1901 procedure Swap_Links
1902 (Container : in out List;
1906 if I.Node = null then
1907 raise Constraint_Error with "I cursor has no element";
1910 if J.Node = null then
1911 raise Constraint_Error with "J cursor has no element";
1914 if I.Container /= Container'Unrestricted_Access then
1915 raise Program_Error with "I cursor designates wrong container";
1918 if J.Container /= Container'Unrestricted_Access then
1919 raise Program_Error with "J cursor designates wrong container";
1922 if I.Node = J.Node then
1926 if Container.Busy > 0 then
1927 raise Program_Error with
1928 "attempt to tamper with cursors (list is busy)";
1931 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
1932 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
1935 I_Next : constant Cursor := Next (I);
1939 Splice (Container, Before => I, Position => J);
1943 J_Next : constant Cursor := Next (J);
1947 Splice (Container, Before => J, Position => I);
1950 pragma Assert (Container.Length >= 3);
1952 Splice (Container, Before => I_Next, Position => J);
1953 Splice (Container, Before => J_Next, Position => I);
1959 pragma Assert (Container.First.Prev = null);
1960 pragma Assert (Container.Last.Next = null);
1963 --------------------
1964 -- Update_Element --
1965 --------------------
1967 procedure Update_Element
1968 (Container : in out List;
1970 Process : not null access procedure (Element : in out Element_Type))
1973 if Position.Node = null then
1974 raise Constraint_Error with "Position cursor has no element";
1977 if Position.Node.Element = null then
1978 raise Program_Error with
1979 "Position cursor has no element";
1982 if Position.Container /= Container'Unchecked_Access then
1983 raise Program_Error with
1984 "Position cursor designates wrong container";
1987 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1990 B : Natural renames Container.Busy;
1991 L : Natural renames Container.Lock;
1998 Process (Position.Node.Element.all);
2015 function Vet (Position : Cursor) return Boolean is
2017 if Position.Node = null then
2018 return Position.Container = null;
2021 if Position.Container = null then
2025 if Position.Node.Next = Position.Node then
2029 if Position.Node.Prev = Position.Node then
2033 if Position.Node.Element = null then
2038 L : List renames Position.Container.all;
2040 if L.Length = 0 then
2044 if L.First = null then
2048 if L.Last = null then
2052 if L.First.Prev /= null then
2056 if L.Last.Next /= null then
2060 if Position.Node.Prev = null
2061 and then Position.Node /= L.First
2066 if Position.Node.Next = null
2067 and then Position.Node /= L.Last
2072 if L.Length = 1 then
2073 return L.First = L.Last;
2076 if L.First = L.Last then
2080 if L.First.Next = null then
2084 if L.Last.Prev = null then
2088 if L.First.Next.Prev /= L.First then
2092 if L.Last.Prev.Next /= L.Last then
2096 if L.Length = 2 then
2097 if L.First.Next /= L.Last then
2101 if L.Last.Prev /= L.First then
2108 if L.First.Next = L.Last then
2112 if L.Last.Prev = L.First then
2116 if Position.Node = L.First then
2120 if Position.Node = L.Last then
2124 if Position.Node.Next = null then
2128 if Position.Node.Prev = null then
2132 if Position.Node.Next.Prev /= Position.Node then
2136 if Position.Node.Prev.Next /= Position.Node then
2140 if L.Length = 3 then
2141 if L.First.Next /= Position.Node then
2145 if L.Last.Prev /= Position.Node then
2159 (Stream : not null access Root_Stream_Type'Class;
2162 Node : Node_Access := Item.First;
2165 Count_Type'Base'Write (Stream, Item.Length);
2167 while Node /= null loop
2168 Element_Type'Output (Stream, Node.Element.all);
2174 (Stream : not null access Root_Stream_Type'Class;
2178 raise Program_Error with "attempt to stream list cursor";
2182 (Stream : not null access Root_Stream_Type'Class;
2183 Item : Reference_Type)
2186 raise Program_Error with "attempt to stream reference";
2190 (Stream : not null access Root_Stream_Type'Class;
2191 Item : Constant_Reference_Type)
2194 raise Program_Error with "attempt to stream reference";
2197 end Ada.Containers.Indefinite_Doubly_Linked_Lists;