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;
245 ------------------------
246 -- Constant_Reference --
247 ------------------------
249 function Constant_Reference
250 (Container : aliased List;
251 Position : Cursor) return Constant_Reference_Type
254 if Position.Container = null then
255 raise Constraint_Error with "Position cursor has no element";
258 if Position.Container /= Container'Unrestricted_Access then
259 raise Program_Error with
260 "Position cursor designates wrong container";
263 if Position.Node.Element = null then
264 raise Program_Error with "Node has no element";
267 pragma Assert (Vet (Position), "bad cursor in Constant_Reference");
269 return (Element => Position.Node.Element.all'Access);
270 end Constant_Reference;
278 Item : Element_Type) return Boolean
281 return Find (Container, Item) /= No_Element;
288 function Copy (Source : List) return List is
290 return Target : List do
291 Target.Assign (Source);
300 (Container : in out List;
301 Position : in out Cursor;
302 Count : Count_Type := 1)
307 if Position.Node = null then
308 raise Constraint_Error with
309 "Position cursor has no element";
312 if Position.Node.Element = null then
313 raise Program_Error with
314 "Position cursor has no element";
317 if Position.Container /= Container'Unrestricted_Access then
318 raise Program_Error with
319 "Position cursor designates wrong container";
322 pragma Assert (Vet (Position), "bad cursor in Delete");
324 if Position.Node = Container.First then
325 Delete_First (Container, Count);
326 Position := No_Element; -- Post-York behavior
331 Position := No_Element; -- Post-York behavior
335 if Container.Busy > 0 then
336 raise Program_Error with
337 "attempt to tamper with cursors (list is busy)";
340 for Index in 1 .. Count loop
342 Container.Length := Container.Length - 1;
344 if X = Container.Last then
345 Position := No_Element;
347 Container.Last := X.Prev;
348 Container.Last.Next := null;
354 Position.Node := X.Next;
356 X.Next.Prev := X.Prev;
357 X.Prev.Next := X.Next;
362 Position := No_Element; -- Post-York behavior
369 procedure Delete_First
370 (Container : in out List;
371 Count : Count_Type := 1)
376 if Count >= Container.Length then
385 if Container.Busy > 0 then
386 raise Program_Error with
387 "attempt to tamper with cursors (list is busy)";
390 for I in 1 .. Count loop
391 X := Container.First;
392 pragma Assert (X.Next.Prev = Container.First);
394 Container.First := X.Next;
395 Container.First.Prev := null;
397 Container.Length := Container.Length - 1;
407 procedure Delete_Last
408 (Container : in out List;
409 Count : Count_Type := 1)
414 if Count >= Container.Length then
423 if Container.Busy > 0 then
424 raise Program_Error with
425 "attempt to tamper with cursors (list is busy)";
428 for I in 1 .. Count loop
430 pragma Assert (X.Prev.Next = Container.Last);
432 Container.Last := X.Prev;
433 Container.Last.Next := null;
435 Container.Length := Container.Length - 1;
445 function Element (Position : Cursor) return Element_Type is
447 if Position.Node = null then
448 raise Constraint_Error with
449 "Position cursor has no element";
452 if Position.Node.Element = null then
453 raise Program_Error with
454 "Position cursor has no element";
457 pragma Assert (Vet (Position), "bad cursor in Element");
459 return Position.Node.Element.all;
466 procedure Finalize (Object : in out Iterator) is
468 if Object.Container /= null then
470 B : Natural renames Object.Container.all.Busy;
484 Position : Cursor := No_Element) return Cursor
486 Node : Node_Access := Position.Node;
490 Node := Container.First;
493 if Node.Element = null then
497 if Position.Container /= Container'Unrestricted_Access then
498 raise Program_Error with
499 "Position cursor designates wrong container";
502 pragma Assert (Vet (Position), "bad cursor in Find");
505 while Node /= null loop
506 if Node.Element.all = Item then
507 return Cursor'(Container'Unrestricted_Access, Node);
520 function First (Container : List) return Cursor is
522 if Container.First = null then
526 return Cursor'(Container'Unrestricted_Access, Container.First);
529 function First (Object : Iterator) return Cursor is
531 -- The value of the iterator object's Node component influences the
532 -- behavior of the First (and Last) selector function.
534 -- When the Node component is null, this means the iterator object was
535 -- constructed without a start expression, in which case the (forward)
536 -- iteration starts from the (logical) beginning of the entire sequence
537 -- of items (corresponding to Container.First, for a forward iterator).
539 -- Otherwise, this is iteration over a partial sequence of items. When
540 -- the Node component is non-null, the iterator object was constructed
541 -- with a start expression, that specifies the position from which the
542 -- (forward) partial iteration begins.
544 if Object.Node = null then
545 return Indefinite_Doubly_Linked_Lists.First (Object.Container.all);
547 return Cursor'(Object.Container, Object.Node);
555 function First_Element (Container : List) return Element_Type is
557 if Container.First = null then
558 raise Constraint_Error with "list is empty";
561 return Container.First.Element.all;
568 procedure Free (X : in out Node_Access) is
569 procedure Deallocate is
570 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
588 ---------------------
589 -- Generic_Sorting --
590 ---------------------
592 package body Generic_Sorting is
598 function Is_Sorted (Container : List) return Boolean is
599 Node : Node_Access := Container.First;
602 for I in 2 .. Container.Length loop
603 if Node.Next.Element.all < Node.Element.all then
618 (Target : in out List;
619 Source : in out List)
625 -- The semantics of Merge changed slightly per AI05-0021. It was
626 -- originally the case that if Target and Source denoted the same
627 -- container object, then the GNAT implementation of Merge did
628 -- nothing. However, it was argued that RM05 did not precisely
629 -- specify the semantics for this corner case. The decision of the
630 -- ARG was that if Target and Source denote the same non-empty
631 -- container object, then Program_Error is raised.
633 if Source.Is_Empty then
637 if Target'Address = Source'Address then
638 raise Program_Error with
639 "Target and Source denote same non-empty container";
642 if Target.Busy > 0 then
643 raise Program_Error with
644 "attempt to tamper with cursors of Target (list is busy)";
647 if Source.Busy > 0 then
648 raise Program_Error with
649 "attempt to tamper with cursors of Source (list is busy)";
652 LI := First (Target);
653 RI := First (Source);
654 while RI.Node /= null loop
655 pragma Assert (RI.Node.Next = null
656 or else not (RI.Node.Next.Element.all <
657 RI.Node.Element.all));
659 if LI.Node = null then
660 Splice (Target, No_Element, Source);
664 pragma Assert (LI.Node.Next = null
665 or else not (LI.Node.Next.Element.all <
666 LI.Node.Element.all));
668 if RI.Node.Element.all < LI.Node.Element.all then
671 pragma Warnings (Off, RJ);
673 RI.Node := RI.Node.Next;
674 Splice (Target, LI, Source, RJ);
678 LI.Node := LI.Node.Next;
687 procedure Sort (Container : in out List) is
688 procedure Partition (Pivot : Node_Access; Back : Node_Access);
690 procedure Sort (Front, Back : Node_Access);
696 procedure Partition (Pivot : Node_Access; Back : Node_Access) is
697 Node : Node_Access := Pivot.Next;
700 while Node /= Back loop
701 if Node.Element.all < Pivot.Element.all then
703 Prev : constant Node_Access := Node.Prev;
704 Next : constant Node_Access := Node.Next;
709 Container.Last := Prev;
715 Node.Prev := Pivot.Prev;
719 if Node.Prev = null then
720 Container.First := Node;
722 Node.Prev.Next := Node;
738 procedure Sort (Front, Back : Node_Access) is
739 Pivot : constant Node_Access :=
740 (if Front = null then Container.First else Front.Next);
742 if Pivot /= Back then
743 Partition (Pivot, Back);
749 -- Start of processing for Sort
752 if Container.Length <= 1 then
756 pragma Assert (Container.First.Prev = null);
757 pragma Assert (Container.Last.Next = null);
759 if Container.Busy > 0 then
760 raise Program_Error with
761 "attempt to tamper with cursors (list is busy)";
764 Sort (Front => null, Back => null);
766 pragma Assert (Container.First.Prev = null);
767 pragma Assert (Container.Last.Next = null);
776 function Has_Element (Position : Cursor) return Boolean is
778 pragma Assert (Vet (Position), "bad cursor in Has_Element");
779 return Position.Node /= null;
787 (Container : in out List;
789 New_Item : Element_Type;
790 Position : out Cursor;
791 Count : Count_Type := 1)
793 New_Node : Node_Access;
796 if Before.Container /= null then
797 if Before.Container /= Container'Unrestricted_Access then
798 raise Program_Error with
799 "attempt to tamper with cursors (list is busy)";
802 if Before.Node = null
803 or else Before.Node.Element = null
805 raise Program_Error with
806 "Before cursor has no element";
809 pragma Assert (Vet (Before), "bad cursor in Insert");
817 if Container.Length > Count_Type'Last - Count then
818 raise Constraint_Error with "new length exceeds maximum";
821 if Container.Busy > 0 then
822 raise Program_Error with
823 "attempt to tamper with cursors (list is busy)";
827 Element : Element_Access := new Element_Type'(New_Item);
829 New_Node := new Node_Type'(Element, null, null);
836 Insert_Internal (Container, Before.Node, New_Node);
837 Position := Cursor'(Container'Unchecked_Access, New_Node);
839 for J in Count_Type'(2) .. Count loop
842 Element : Element_Access := new Element_Type'(New_Item);
844 New_Node := new Node_Type'(Element, null, null);
851 Insert_Internal (Container, Before.Node, New_Node);
856 (Container : in out List;
858 New_Item : Element_Type;
859 Count : Count_Type := 1)
862 pragma Unreferenced (Position);
864 Insert (Container, Before, New_Item, Position, Count);
867 ---------------------
868 -- Insert_Internal --
869 ---------------------
871 procedure Insert_Internal
872 (Container : in out List;
873 Before : Node_Access;
874 New_Node : Node_Access)
877 if Container.Length = 0 then
878 pragma Assert (Before = null);
879 pragma Assert (Container.First = null);
880 pragma Assert (Container.Last = null);
882 Container.First := New_Node;
883 Container.Last := New_Node;
885 elsif Before = null then
886 pragma Assert (Container.Last.Next = null);
888 Container.Last.Next := New_Node;
889 New_Node.Prev := Container.Last;
891 Container.Last := New_Node;
893 elsif Before = Container.First then
894 pragma Assert (Container.First.Prev = null);
896 Container.First.Prev := New_Node;
897 New_Node.Next := Container.First;
899 Container.First := New_Node;
902 pragma Assert (Container.First.Prev = null);
903 pragma Assert (Container.Last.Next = null);
905 New_Node.Next := Before;
906 New_Node.Prev := Before.Prev;
908 Before.Prev.Next := New_Node;
909 Before.Prev := New_Node;
912 Container.Length := Container.Length + 1;
919 function Is_Empty (Container : List) return Boolean is
921 return Container.Length = 0;
930 Process : not null access procedure (Position : Cursor))
932 B : Natural renames Container'Unrestricted_Access.all.Busy;
933 Node : Node_Access := Container.First;
939 while Node /= null loop
940 Process (Cursor'(Container'Unrestricted_Access, Node));
954 return List_Iterator_Interfaces.Reversible_Iterator'class
956 B : Natural renames Container'Unrestricted_Access.all.Busy;
959 -- The value of the Node component influences the behavior of the First
960 -- and Last selector functions of the iterator object. When the Node
961 -- component is null (as is the case here), this means the iterator
962 -- object was constructed without a start expression. This is a
963 -- complete iterator, meaning that the iteration starts from the
964 -- (logical) beginning of the sequence of items.
966 -- Note: For a forward iterator, Container.First is the beginning, and
967 -- for a reverse iterator, Container.Last is the beginning.
969 return It : constant Iterator :=
970 Iterator'(Limited_Controlled with
971 Container => Container'Unrestricted_Access,
981 return List_Iterator_Interfaces.Reversible_Iterator'Class
983 B : Natural renames Container'Unrestricted_Access.all.Busy;
986 -- It was formerly the case that when Start = No_Element, the partial
987 -- iterator was defined to behave the same as for a complete iterator,
988 -- and iterate over the entire sequence of items. However, those
989 -- semantics were unintuitive and arguably error-prone (it is too easy
990 -- to accidentally create an endless loop), and so they were changed,
991 -- per the ARG meeting in Denver on 2011/11. However, there was no
992 -- consensus about what positive meaning this corner case should have,
993 -- and so it was decided to simply raise an exception. This does imply,
994 -- however, that it is not possible to use a partial iterator to specify
995 -- an empty sequence of items.
997 if Start = No_Element then
998 raise Constraint_Error with
999 "Start position for iterator equals No_Element";
1002 if Start.Container /= Container'Unrestricted_Access then
1003 raise Program_Error with
1004 "Start cursor of Iterate designates wrong list";
1007 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1009 -- The value of the Node component influences the behavior of the First
1010 -- and Last selector functions of the iterator object. When the Node
1011 -- component is non-null (as is the case here), it means that this
1012 -- is a partial iteration, over a subset of the complete sequence of
1013 -- items. The iterator object was constructed with a start expression,
1014 -- indicating the position from which the iteration begins. Note that
1015 -- the start position has the same value irrespective of whether this
1016 -- is a forward or reverse iteration.
1018 return It : constant Iterator :=
1019 Iterator'(Limited_Controlled with
1020 Container => Container'Unrestricted_Access,
1031 function Last (Container : List) return Cursor is
1033 if Container.Last = null then
1037 return Cursor'(Container'Unrestricted_Access, Container.Last);
1040 function Last (Object : Iterator) return Cursor is
1042 -- The value of the iterator object's Node component influences the
1043 -- behavior of the Last (and First) selector function.
1045 -- When the Node component is null, this means the iterator object was
1046 -- constructed without a start expression, in which case the (reverse)
1047 -- iteration starts from the (logical) beginning of the entire sequence
1048 -- (corresponding to Container.Last, for a reverse iterator).
1050 -- Otherwise, this is iteration over a partial sequence of items. When
1051 -- the Node component is non-null, the iterator object was constructed
1052 -- with a start expression, that specifies the position from which the
1053 -- (reverse) partial iteration begins.
1055 if Object.Node = null then
1056 return Indefinite_Doubly_Linked_Lists.Last (Object.Container.all);
1058 return Cursor'(Object.Container, Object.Node);
1066 function Last_Element (Container : List) return Element_Type is
1068 if Container.Last = null then
1069 raise Constraint_Error with "list is empty";
1072 return Container.Last.Element.all;
1079 function Length (Container : List) return Count_Type is
1081 return Container.Length;
1088 procedure Move (Target : in out List; Source : in out List) is
1090 if Target'Address = Source'Address then
1094 if Source.Busy > 0 then
1095 raise Program_Error with
1096 "attempt to tamper with cursors of Source (list is busy)";
1101 Target.First := Source.First;
1102 Source.First := null;
1104 Target.Last := Source.Last;
1105 Source.Last := null;
1107 Target.Length := Source.Length;
1115 procedure Next (Position : in out Cursor) is
1117 Position := Next (Position);
1120 function Next (Position : Cursor) return Cursor is
1122 if Position.Node = null then
1126 pragma Assert (Vet (Position), "bad cursor in Next");
1129 Next_Node : constant Node_Access := Position.Node.Next;
1131 if Next_Node = null then
1135 return Cursor'(Position.Container, Next_Node);
1139 function Next (Object : Iterator; Position : Cursor) return Cursor is
1141 if Position.Container = null then
1145 if Position.Container /= Object.Container then
1146 raise Program_Error with
1147 "Position cursor of Next designates wrong list";
1150 return Next (Position);
1158 (Container : in out List;
1159 New_Item : Element_Type;
1160 Count : Count_Type := 1)
1163 Insert (Container, First (Container), New_Item, Count);
1170 procedure Previous (Position : in out Cursor) is
1172 Position := Previous (Position);
1175 function Previous (Position : Cursor) return Cursor is
1177 if Position.Node = null then
1181 pragma Assert (Vet (Position), "bad cursor in Previous");
1184 Prev_Node : constant Node_Access := Position.Node.Prev;
1186 if Prev_Node = null then
1190 return Cursor'(Position.Container, Prev_Node);
1194 function Previous (Object : Iterator; Position : Cursor) return Cursor is
1196 if Position.Container = null then
1200 if Position.Container /= Object.Container then
1201 raise Program_Error with
1202 "Position cursor of Previous designates wrong list";
1205 return Previous (Position);
1212 procedure Query_Element
1214 Process : not null access procedure (Element : Element_Type))
1217 if Position.Node = null then
1218 raise Constraint_Error with
1219 "Position cursor has no element";
1222 if Position.Node.Element = null then
1223 raise Program_Error with
1224 "Position cursor has no element";
1227 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1230 C : List renames Position.Container.all'Unrestricted_Access.all;
1231 B : Natural renames C.Busy;
1232 L : Natural renames C.Lock;
1239 Process (Position.Node.Element.all);
1257 (Stream : not null access Root_Stream_Type'Class;
1260 N : Count_Type'Base;
1266 Count_Type'Base'Read (Stream, N);
1273 Element : Element_Access :=
1274 new Element_Type'(Element_Type'Input (Stream));
1276 Dst := new Node_Type'(Element, null, null);
1287 while Item.Length < N loop
1289 Element : Element_Access :=
1290 new Element_Type'(Element_Type'Input (Stream));
1292 Dst := new Node_Type'(Element, Next => null, Prev => Item.Last);
1299 Item.Last.Next := Dst;
1301 Item.Length := Item.Length + 1;
1306 (Stream : not null access Root_Stream_Type'Class;
1310 raise Program_Error with "attempt to stream list cursor";
1314 (Stream : not null access Root_Stream_Type'Class;
1315 Item : out Reference_Type)
1318 raise Program_Error with "attempt to stream reference";
1322 (Stream : not null access Root_Stream_Type'Class;
1323 Item : out Constant_Reference_Type)
1326 raise Program_Error with "attempt to stream reference";
1334 (Container : aliased in out List;
1335 Position : Cursor) return Reference_Type
1338 if Position.Container = null then
1339 raise Constraint_Error with "Position cursor has no element";
1342 if Position.Container /= Container'Unrestricted_Access then
1343 raise Program_Error with
1344 "Position cursor designates wrong container";
1347 if Position.Node.Element = null then
1348 raise Program_Error with "Node has no element";
1351 pragma Assert (Vet (Position), "bad cursor in function Reference");
1353 return (Element => Position.Node.Element.all'Access);
1356 ---------------------
1357 -- Replace_Element --
1358 ---------------------
1360 procedure Replace_Element
1361 (Container : in out List;
1363 New_Item : Element_Type)
1366 if Position.Container = null then
1367 raise Constraint_Error with "Position cursor has no element";
1370 if Position.Container /= Container'Unchecked_Access then
1371 raise Program_Error with
1372 "Position cursor designates wrong container";
1375 if Container.Lock > 0 then
1376 raise Program_Error with
1377 "attempt to tamper with elements (list is locked)";
1380 if Position.Node.Element = null then
1381 raise Program_Error with
1382 "Position cursor has no element";
1385 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1388 X : Element_Access := Position.Node.Element;
1391 Position.Node.Element := new Element_Type'(New_Item);
1394 end Replace_Element;
1396 ----------------------
1397 -- Reverse_Elements --
1398 ----------------------
1400 procedure Reverse_Elements (Container : in out List) is
1401 I : Node_Access := Container.First;
1402 J : Node_Access := Container.Last;
1404 procedure Swap (L, R : Node_Access);
1410 procedure Swap (L, R : Node_Access) is
1411 LN : constant Node_Access := L.Next;
1412 LP : constant Node_Access := L.Prev;
1414 RN : constant Node_Access := R.Next;
1415 RP : constant Node_Access := R.Prev;
1430 pragma Assert (RP = L);
1444 -- Start of processing for Reverse_Elements
1447 if Container.Length <= 1 then
1451 pragma Assert (Container.First.Prev = null);
1452 pragma Assert (Container.Last.Next = null);
1454 if Container.Busy > 0 then
1455 raise Program_Error with
1456 "attempt to tamper with cursors (list is busy)";
1459 Container.First := J;
1460 Container.Last := I;
1462 Swap (L => I, R => J);
1470 Swap (L => J, R => I);
1479 pragma Assert (Container.First.Prev = null);
1480 pragma Assert (Container.Last.Next = null);
1481 end Reverse_Elements;
1487 function Reverse_Find
1489 Item : Element_Type;
1490 Position : Cursor := No_Element) return Cursor
1492 Node : Node_Access := Position.Node;
1496 Node := Container.Last;
1499 if Node.Element = null then
1500 raise Program_Error with "Position cursor has no element";
1503 if Position.Container /= Container'Unrestricted_Access then
1504 raise Program_Error with
1505 "Position cursor designates wrong container";
1508 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1511 while Node /= null loop
1512 if Node.Element.all = Item then
1513 return Cursor'(Container'Unrestricted_Access, Node);
1522 ---------------------
1523 -- Reverse_Iterate --
1524 ---------------------
1526 procedure Reverse_Iterate
1528 Process : not null access procedure (Position : Cursor))
1530 C : List renames Container'Unrestricted_Access.all;
1531 B : Natural renames C.Busy;
1533 Node : Node_Access := Container.Last;
1539 while Node /= null loop
1540 Process (Cursor'(Container'Unrestricted_Access, Node));
1550 end Reverse_Iterate;
1557 (Target : in out List;
1559 Source : in out List)
1562 if Before.Container /= null then
1563 if Before.Container /= Target'Unrestricted_Access then
1564 raise Program_Error with
1565 "Before cursor designates wrong container";
1568 if Before.Node = null
1569 or else Before.Node.Element = null
1571 raise Program_Error with
1572 "Before cursor has no element";
1575 pragma Assert (Vet (Before), "bad cursor in Splice");
1578 if Target'Address = Source'Address
1579 or else Source.Length = 0
1584 pragma Assert (Source.First.Prev = null);
1585 pragma Assert (Source.Last.Next = null);
1587 if Target.Length > Count_Type'Last - Source.Length then
1588 raise Constraint_Error with "new length exceeds maximum";
1591 if Target.Busy > 0 then
1592 raise Program_Error with
1593 "attempt to tamper with cursors of Target (list is busy)";
1596 if Source.Busy > 0 then
1597 raise Program_Error with
1598 "attempt to tamper with cursors of Source (list is busy)";
1601 if Target.Length = 0 then
1602 pragma Assert (Before = No_Element);
1603 pragma Assert (Target.First = null);
1604 pragma Assert (Target.Last = null);
1606 Target.First := Source.First;
1607 Target.Last := Source.Last;
1609 elsif Before.Node = null then
1610 pragma Assert (Target.Last.Next = null);
1612 Target.Last.Next := Source.First;
1613 Source.First.Prev := Target.Last;
1615 Target.Last := Source.Last;
1617 elsif Before.Node = Target.First then
1618 pragma Assert (Target.First.Prev = null);
1620 Source.Last.Next := Target.First;
1621 Target.First.Prev := Source.Last;
1623 Target.First := Source.First;
1626 pragma Assert (Target.Length >= 2);
1627 Before.Node.Prev.Next := Source.First;
1628 Source.First.Prev := Before.Node.Prev;
1630 Before.Node.Prev := Source.Last;
1631 Source.Last.Next := Before.Node;
1634 Source.First := null;
1635 Source.Last := null;
1637 Target.Length := Target.Length + Source.Length;
1642 (Container : in out List;
1647 if Before.Container /= null then
1648 if Before.Container /= Container'Unchecked_Access then
1649 raise Program_Error with
1650 "Before cursor designates wrong container";
1653 if Before.Node = null
1654 or else Before.Node.Element = null
1656 raise Program_Error with
1657 "Before cursor has no element";
1660 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1663 if Position.Node = null then
1664 raise Constraint_Error with "Position cursor has no element";
1667 if Position.Node.Element = null then
1668 raise Program_Error with "Position cursor has no element";
1671 if Position.Container /= Container'Unrestricted_Access then
1672 raise Program_Error with
1673 "Position cursor designates wrong container";
1676 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1678 if Position.Node = Before.Node
1679 or else Position.Node.Next = Before.Node
1684 pragma Assert (Container.Length >= 2);
1686 if Container.Busy > 0 then
1687 raise Program_Error with
1688 "attempt to tamper with cursors (list is busy)";
1691 if Before.Node = null then
1692 pragma Assert (Position.Node /= Container.Last);
1694 if Position.Node = Container.First then
1695 Container.First := Position.Node.Next;
1696 Container.First.Prev := null;
1698 Position.Node.Prev.Next := Position.Node.Next;
1699 Position.Node.Next.Prev := Position.Node.Prev;
1702 Container.Last.Next := Position.Node;
1703 Position.Node.Prev := Container.Last;
1705 Container.Last := Position.Node;
1706 Container.Last.Next := null;
1711 if Before.Node = Container.First then
1712 pragma Assert (Position.Node /= Container.First);
1714 if Position.Node = Container.Last then
1715 Container.Last := Position.Node.Prev;
1716 Container.Last.Next := null;
1718 Position.Node.Prev.Next := Position.Node.Next;
1719 Position.Node.Next.Prev := Position.Node.Prev;
1722 Container.First.Prev := Position.Node;
1723 Position.Node.Next := Container.First;
1725 Container.First := Position.Node;
1726 Container.First.Prev := null;
1731 if Position.Node = Container.First then
1732 Container.First := Position.Node.Next;
1733 Container.First.Prev := null;
1735 elsif Position.Node = Container.Last then
1736 Container.Last := Position.Node.Prev;
1737 Container.Last.Next := null;
1740 Position.Node.Prev.Next := Position.Node.Next;
1741 Position.Node.Next.Prev := Position.Node.Prev;
1744 Before.Node.Prev.Next := Position.Node;
1745 Position.Node.Prev := Before.Node.Prev;
1747 Before.Node.Prev := Position.Node;
1748 Position.Node.Next := Before.Node;
1750 pragma Assert (Container.First.Prev = null);
1751 pragma Assert (Container.Last.Next = null);
1755 (Target : in out List;
1757 Source : in out List;
1758 Position : in out Cursor)
1761 if Target'Address = Source'Address then
1762 Splice (Target, Before, Position);
1766 if Before.Container /= null then
1767 if Before.Container /= Target'Unrestricted_Access then
1768 raise Program_Error with
1769 "Before cursor designates wrong container";
1772 if Before.Node = null
1773 or else Before.Node.Element = null
1775 raise Program_Error with
1776 "Before cursor has no element";
1779 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1782 if Position.Node = null then
1783 raise Constraint_Error with "Position cursor has no element";
1786 if Position.Node.Element = null then
1787 raise Program_Error with
1788 "Position cursor has no element";
1791 if Position.Container /= Source'Unrestricted_Access then
1792 raise Program_Error with
1793 "Position cursor designates wrong container";
1796 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1798 if Target.Length = Count_Type'Last then
1799 raise Constraint_Error with "Target is full";
1802 if Target.Busy > 0 then
1803 raise Program_Error with
1804 "attempt to tamper with cursors of Target (list is busy)";
1807 if Source.Busy > 0 then
1808 raise Program_Error with
1809 "attempt to tamper with cursors of Source (list is busy)";
1812 if Position.Node = Source.First then
1813 Source.First := Position.Node.Next;
1815 if Position.Node = Source.Last then
1816 pragma Assert (Source.First = null);
1817 pragma Assert (Source.Length = 1);
1818 Source.Last := null;
1821 Source.First.Prev := null;
1824 elsif Position.Node = Source.Last then
1825 pragma Assert (Source.Length >= 2);
1826 Source.Last := Position.Node.Prev;
1827 Source.Last.Next := null;
1830 pragma Assert (Source.Length >= 3);
1831 Position.Node.Prev.Next := Position.Node.Next;
1832 Position.Node.Next.Prev := Position.Node.Prev;
1835 if Target.Length = 0 then
1836 pragma Assert (Before = No_Element);
1837 pragma Assert (Target.First = null);
1838 pragma Assert (Target.Last = null);
1840 Target.First := Position.Node;
1841 Target.Last := Position.Node;
1843 Target.First.Prev := null;
1844 Target.Last.Next := null;
1846 elsif Before.Node = null then
1847 pragma Assert (Target.Last.Next = null);
1848 Target.Last.Next := Position.Node;
1849 Position.Node.Prev := Target.Last;
1851 Target.Last := Position.Node;
1852 Target.Last.Next := null;
1854 elsif Before.Node = Target.First then
1855 pragma Assert (Target.First.Prev = null);
1856 Target.First.Prev := Position.Node;
1857 Position.Node.Next := Target.First;
1859 Target.First := Position.Node;
1860 Target.First.Prev := null;
1863 pragma Assert (Target.Length >= 2);
1864 Before.Node.Prev.Next := Position.Node;
1865 Position.Node.Prev := Before.Node.Prev;
1867 Before.Node.Prev := Position.Node;
1868 Position.Node.Next := Before.Node;
1871 Target.Length := Target.Length + 1;
1872 Source.Length := Source.Length - 1;
1874 Position.Container := Target'Unchecked_Access;
1882 (Container : in out List;
1886 if I.Node = null then
1887 raise Constraint_Error with "I cursor has no element";
1890 if J.Node = null then
1891 raise Constraint_Error with "J cursor has no element";
1894 if I.Container /= Container'Unchecked_Access then
1895 raise Program_Error with "I cursor designates wrong container";
1898 if J.Container /= Container'Unchecked_Access then
1899 raise Program_Error with "J cursor designates wrong container";
1902 if I.Node = J.Node then
1906 if Container.Lock > 0 then
1907 raise Program_Error with
1908 "attempt to tamper with elements (list is locked)";
1911 pragma Assert (Vet (I), "bad I cursor in Swap");
1912 pragma Assert (Vet (J), "bad J cursor in Swap");
1915 EI_Copy : constant Element_Access := I.Node.Element;
1918 I.Node.Element := J.Node.Element;
1919 J.Node.Element := EI_Copy;
1927 procedure Swap_Links
1928 (Container : in out List;
1932 if I.Node = null then
1933 raise Constraint_Error with "I cursor has no element";
1936 if J.Node = null then
1937 raise Constraint_Error with "J cursor has no element";
1940 if I.Container /= Container'Unrestricted_Access then
1941 raise Program_Error with "I cursor designates wrong container";
1944 if J.Container /= Container'Unrestricted_Access then
1945 raise Program_Error with "J cursor designates wrong container";
1948 if I.Node = J.Node then
1952 if Container.Busy > 0 then
1953 raise Program_Error with
1954 "attempt to tamper with cursors (list is busy)";
1957 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
1958 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
1961 I_Next : constant Cursor := Next (I);
1965 Splice (Container, Before => I, Position => J);
1969 J_Next : constant Cursor := Next (J);
1973 Splice (Container, Before => J, Position => I);
1976 pragma Assert (Container.Length >= 3);
1978 Splice (Container, Before => I_Next, Position => J);
1979 Splice (Container, Before => J_Next, Position => I);
1985 pragma Assert (Container.First.Prev = null);
1986 pragma Assert (Container.Last.Next = null);
1989 --------------------
1990 -- Update_Element --
1991 --------------------
1993 procedure Update_Element
1994 (Container : in out List;
1996 Process : not null access procedure (Element : in out Element_Type))
1999 if Position.Node = null then
2000 raise Constraint_Error with "Position cursor has no element";
2003 if Position.Node.Element = null then
2004 raise Program_Error with
2005 "Position cursor has no element";
2008 if Position.Container /= Container'Unchecked_Access then
2009 raise Program_Error with
2010 "Position cursor designates wrong container";
2013 pragma Assert (Vet (Position), "bad cursor in Update_Element");
2016 B : Natural renames Container.Busy;
2017 L : Natural renames Container.Lock;
2024 Process (Position.Node.Element.all);
2041 function Vet (Position : Cursor) return Boolean is
2043 if Position.Node = null then
2044 return Position.Container = null;
2047 if Position.Container = null then
2051 if Position.Node.Next = Position.Node then
2055 if Position.Node.Prev = Position.Node then
2059 if Position.Node.Element = null then
2064 L : List renames Position.Container.all;
2066 if L.Length = 0 then
2070 if L.First = null then
2074 if L.Last = null then
2078 if L.First.Prev /= null then
2082 if L.Last.Next /= null then
2086 if Position.Node.Prev = null
2087 and then Position.Node /= L.First
2092 if Position.Node.Next = null
2093 and then Position.Node /= L.Last
2098 if L.Length = 1 then
2099 return L.First = L.Last;
2102 if L.First = L.Last then
2106 if L.First.Next = null then
2110 if L.Last.Prev = null then
2114 if L.First.Next.Prev /= L.First then
2118 if L.Last.Prev.Next /= L.Last then
2122 if L.Length = 2 then
2123 if L.First.Next /= L.Last then
2127 if L.Last.Prev /= L.First then
2134 if L.First.Next = L.Last then
2138 if L.Last.Prev = L.First then
2142 if Position.Node = L.First then
2146 if Position.Node = L.Last then
2150 if Position.Node.Next = null then
2154 if Position.Node.Prev = null then
2158 if Position.Node.Next.Prev /= Position.Node then
2162 if Position.Node.Prev.Next /= Position.Node then
2166 if L.Length = 3 then
2167 if L.First.Next /= Position.Node then
2171 if L.Last.Prev /= Position.Node then
2185 (Stream : not null access Root_Stream_Type'Class;
2188 Node : Node_Access := Item.First;
2191 Count_Type'Base'Write (Stream, Item.Length);
2193 while Node /= null loop
2194 Element_Type'Output (Stream, Node.Element.all);
2200 (Stream : not null access Root_Stream_Type'Class;
2204 raise Program_Error with "attempt to stream list cursor";
2208 (Stream : not null access Root_Stream_Type'Class;
2209 Item : Reference_Type)
2212 raise Program_Error with "attempt to stream reference";
2216 (Stream : not null access Root_Stream_Type'Class;
2217 Item : Constant_Reference_Type)
2220 raise Program_Error with "attempt to stream reference";
2223 end Ada.Containers.Indefinite_Doubly_Linked_Lists;