1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.INDEFINITE_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2004-2009, 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 System; use type System.Address;
31 with Ada.Unchecked_Deallocation;
33 package body Ada.Containers.Indefinite_Doubly_Linked_Lists is
36 new Ada.Unchecked_Deallocation (Element_Type, Element_Access);
38 -----------------------
39 -- Local Subprograms --
40 -----------------------
42 procedure Free (X : in out Node_Access);
44 procedure Insert_Internal
45 (Container : in out List;
47 New_Node : Node_Access);
49 function Vet (Position : Cursor) return Boolean;
55 function "=" (Left, Right : List) return Boolean is
60 if Left'Address = Right'Address then
64 if Left.Length /= Right.Length then
70 for J in 1 .. Left.Length loop
71 if L.Element.all /= R.Element.all then
86 procedure Adjust (Container : in out List) is
87 Src : Node_Access := Container.First;
92 pragma Assert (Container.Last = null);
93 pragma Assert (Container.Length = 0);
94 pragma Assert (Container.Busy = 0);
95 pragma Assert (Container.Lock = 0);
99 pragma Assert (Container.First.Prev = null);
100 pragma Assert (Container.Last.Next = null);
101 pragma Assert (Container.Length > 0);
103 Container.First := null;
104 Container.Last := null;
105 Container.Length := 0;
110 Element : Element_Access := new Element_Type'(Src.Element.all);
112 Dst := new Node_Type'(Element, null, null);
119 Container.First := Dst;
120 Container.Last := Dst;
121 Container.Length := 1;
124 while Src /= null loop
126 Element : Element_Access := new Element_Type'(Src.Element.all);
128 Dst := new Node_Type'(Element, null, Prev => Container.Last);
135 Container.Last.Next := Dst;
136 Container.Last := Dst;
137 Container.Length := Container.Length + 1;
148 (Container : in out List;
149 New_Item : Element_Type;
150 Count : Count_Type := 1)
153 Insert (Container, No_Element, New_Item, Count);
160 procedure Clear (Container : in out List) is
162 pragma Warnings (Off, X);
165 if Container.Length = 0 then
166 pragma Assert (Container.First = null);
167 pragma Assert (Container.Last = null);
168 pragma Assert (Container.Busy = 0);
169 pragma Assert (Container.Lock = 0);
173 pragma Assert (Container.First.Prev = null);
174 pragma Assert (Container.Last.Next = null);
176 if Container.Busy > 0 then
177 raise Program_Error with
178 "attempt to tamper with elements (list is busy)";
181 while Container.Length > 1 loop
182 X := Container.First;
183 pragma Assert (X.Next.Prev = Container.First);
185 Container.First := X.Next;
186 Container.First.Prev := null;
188 Container.Length := Container.Length - 1;
193 X := Container.First;
194 pragma Assert (X = Container.Last);
196 Container.First := null;
197 Container.Last := null;
198 Container.Length := 0;
209 Item : Element_Type) return Boolean
212 return Find (Container, Item) /= No_Element;
220 (Container : in out List;
221 Position : in out Cursor;
222 Count : Count_Type := 1)
227 if Position.Node = null then
228 raise Constraint_Error with
229 "Position cursor has no element";
232 if Position.Node.Element = null then
233 raise Program_Error with
234 "Position cursor has no element";
237 if Position.Container /= Container'Unrestricted_Access then
238 raise Program_Error with
239 "Position cursor designates wrong container";
242 pragma Assert (Vet (Position), "bad cursor in Delete");
244 if Position.Node = Container.First then
245 Delete_First (Container, Count);
246 Position := No_Element; -- Post-York behavior
251 Position := No_Element; -- Post-York behavior
255 if Container.Busy > 0 then
256 raise Program_Error with
257 "attempt to tamper with elements (list is busy)";
260 for Index in 1 .. Count loop
262 Container.Length := Container.Length - 1;
264 if X = Container.Last then
265 Position := No_Element;
267 Container.Last := X.Prev;
268 Container.Last.Next := null;
274 Position.Node := X.Next;
276 X.Next.Prev := X.Prev;
277 X.Prev.Next := X.Next;
282 Position := No_Element; -- Post-York behavior
289 procedure Delete_First
290 (Container : in out List;
291 Count : Count_Type := 1)
296 if Count >= Container.Length then
305 if Container.Busy > 0 then
306 raise Program_Error with
307 "attempt to tamper with elements (list is busy)";
310 for I in 1 .. Count loop
311 X := Container.First;
312 pragma Assert (X.Next.Prev = Container.First);
314 Container.First := X.Next;
315 Container.First.Prev := null;
317 Container.Length := Container.Length - 1;
327 procedure Delete_Last
328 (Container : in out List;
329 Count : Count_Type := 1)
334 if Count >= Container.Length then
343 if Container.Busy > 0 then
344 raise Program_Error with
345 "attempt to tamper with elements (list is busy)";
348 for I in 1 .. Count loop
350 pragma Assert (X.Prev.Next = Container.Last);
352 Container.Last := X.Prev;
353 Container.Last.Next := null;
355 Container.Length := Container.Length - 1;
365 function Element (Position : Cursor) return Element_Type is
367 if Position.Node = null then
368 raise Constraint_Error with
369 "Position cursor has no element";
372 if Position.Node.Element = null then
373 raise Program_Error with
374 "Position cursor has no element";
377 pragma Assert (Vet (Position), "bad cursor in Element");
379 return Position.Node.Element.all;
389 Position : Cursor := No_Element) return Cursor
391 Node : Node_Access := Position.Node;
395 Node := Container.First;
398 if Node.Element = null then
402 if Position.Container /= Container'Unrestricted_Access then
403 raise Program_Error with
404 "Position cursor designates wrong container";
407 pragma Assert (Vet (Position), "bad cursor in Find");
410 while Node /= null loop
411 if Node.Element.all = Item then
412 return Cursor'(Container'Unchecked_Access, Node);
425 function First (Container : List) return Cursor is
427 if Container.First = null then
431 return Cursor'(Container'Unchecked_Access, Container.First);
438 function First_Element (Container : List) return Element_Type is
440 if Container.First = null then
441 raise Constraint_Error with "list is empty";
444 return Container.First.Element.all;
451 procedure Free (X : in out Node_Access) is
452 procedure Deallocate is
453 new Ada.Unchecked_Deallocation (Node_Type, Node_Access);
471 ---------------------
472 -- Generic_Sorting --
473 ---------------------
475 package body Generic_Sorting is
481 function Is_Sorted (Container : List) return Boolean is
482 Node : Node_Access := Container.First;
485 for I in 2 .. Container.Length loop
486 if Node.Next.Element.all < Node.Element.all then
501 (Target : in out List;
502 Source : in out List)
507 if Target'Address = Source'Address then
511 if Target.Busy > 0 then
512 raise Program_Error with
513 "attempt to tamper with elements of Target (list is busy)";
516 if Source.Busy > 0 then
517 raise Program_Error with
518 "attempt to tamper with elements of Source (list is busy)";
521 LI := First (Target);
522 RI := First (Source);
523 while RI.Node /= null loop
524 pragma Assert (RI.Node.Next = null
525 or else not (RI.Node.Next.Element.all <
526 RI.Node.Element.all));
528 if LI.Node = null then
529 Splice (Target, No_Element, Source);
533 pragma Assert (LI.Node.Next = null
534 or else not (LI.Node.Next.Element.all <
535 LI.Node.Element.all));
537 if RI.Node.Element.all < LI.Node.Element.all then
540 pragma Warnings (Off, RJ);
542 RI.Node := RI.Node.Next;
543 Splice (Target, LI, Source, RJ);
547 LI.Node := LI.Node.Next;
556 procedure Sort (Container : in out List) is
557 procedure Partition (Pivot : Node_Access; Back : Node_Access);
559 procedure Sort (Front, Back : Node_Access);
565 procedure Partition (Pivot : Node_Access; Back : Node_Access) is
566 Node : Node_Access := Pivot.Next;
569 while Node /= Back loop
570 if Node.Element.all < Pivot.Element.all then
572 Prev : constant Node_Access := Node.Prev;
573 Next : constant Node_Access := Node.Next;
578 Container.Last := Prev;
584 Node.Prev := Pivot.Prev;
588 if Node.Prev = null then
589 Container.First := Node;
591 Node.Prev.Next := Node;
607 procedure Sort (Front, Back : Node_Access) is
612 Pivot := Container.First;
617 if Pivot /= Back then
618 Partition (Pivot, Back);
624 -- Start of processing for Sort
627 if Container.Length <= 1 then
631 pragma Assert (Container.First.Prev = null);
632 pragma Assert (Container.Last.Next = null);
634 if Container.Busy > 0 then
635 raise Program_Error with
636 "attempt to tamper with elements (list is busy)";
639 Sort (Front => null, Back => null);
641 pragma Assert (Container.First.Prev = null);
642 pragma Assert (Container.Last.Next = null);
651 function Has_Element (Position : Cursor) return Boolean is
653 pragma Assert (Vet (Position), "bad cursor in Has_Element");
654 return Position.Node /= null;
662 (Container : in out List;
664 New_Item : Element_Type;
665 Position : out Cursor;
666 Count : Count_Type := 1)
668 New_Node : Node_Access;
671 if Before.Container /= null then
672 if Before.Container /= Container'Unrestricted_Access then
673 raise Program_Error with
674 "attempt to tamper with elements (list is busy)";
677 if Before.Node = null
678 or else Before.Node.Element = null
680 raise Program_Error with
681 "Before cursor has no element";
684 pragma Assert (Vet (Before), "bad cursor in Insert");
692 if Container.Length > Count_Type'Last - Count then
693 raise Constraint_Error with "new length exceeds maximum";
696 if Container.Busy > 0 then
697 raise Program_Error with
698 "attempt to tamper with elements (list is busy)";
702 Element : Element_Access := new Element_Type'(New_Item);
704 New_Node := new Node_Type'(Element, null, null);
711 Insert_Internal (Container, Before.Node, New_Node);
712 Position := Cursor'(Container'Unchecked_Access, New_Node);
714 for J in Count_Type'(2) .. Count loop
717 Element : Element_Access := new Element_Type'(New_Item);
719 New_Node := new Node_Type'(Element, null, null);
726 Insert_Internal (Container, Before.Node, New_Node);
731 (Container : in out List;
733 New_Item : Element_Type;
734 Count : Count_Type := 1)
737 pragma Unreferenced (Position);
739 Insert (Container, Before, New_Item, Position, Count);
742 ---------------------
743 -- Insert_Internal --
744 ---------------------
746 procedure Insert_Internal
747 (Container : in out List;
748 Before : Node_Access;
749 New_Node : Node_Access)
752 if Container.Length = 0 then
753 pragma Assert (Before = null);
754 pragma Assert (Container.First = null);
755 pragma Assert (Container.Last = null);
757 Container.First := New_Node;
758 Container.Last := New_Node;
760 elsif Before = null then
761 pragma Assert (Container.Last.Next = null);
763 Container.Last.Next := New_Node;
764 New_Node.Prev := Container.Last;
766 Container.Last := New_Node;
768 elsif Before = Container.First then
769 pragma Assert (Container.First.Prev = null);
771 Container.First.Prev := New_Node;
772 New_Node.Next := Container.First;
774 Container.First := New_Node;
777 pragma Assert (Container.First.Prev = null);
778 pragma Assert (Container.Last.Next = null);
780 New_Node.Next := Before;
781 New_Node.Prev := Before.Prev;
783 Before.Prev.Next := New_Node;
784 Before.Prev := New_Node;
787 Container.Length := Container.Length + 1;
794 function Is_Empty (Container : List) return Boolean is
796 return Container.Length = 0;
805 Process : not null access procedure (Position : Cursor))
807 C : List renames Container'Unrestricted_Access.all;
808 B : Natural renames C.Busy;
810 Node : Node_Access := Container.First;
816 while Node /= null loop
817 Process (Cursor'(Container'Unchecked_Access, Node));
833 function Last (Container : List) return Cursor is
835 if Container.Last = null then
839 return Cursor'(Container'Unchecked_Access, Container.Last);
846 function Last_Element (Container : List) return Element_Type is
848 if Container.Last = null then
849 raise Constraint_Error with "list is empty";
852 return Container.Last.Element.all;
859 function Length (Container : List) return Count_Type is
861 return Container.Length;
868 procedure Move (Target : in out List; Source : in out List) is
870 if Target'Address = Source'Address then
874 if Source.Busy > 0 then
875 raise Program_Error with
876 "attempt to tamper with elements of Source (list is busy)";
881 Target.First := Source.First;
882 Source.First := null;
884 Target.Last := Source.Last;
887 Target.Length := Source.Length;
895 procedure Next (Position : in out Cursor) is
897 Position := Next (Position);
900 function Next (Position : Cursor) return Cursor is
902 if Position.Node = null then
906 pragma Assert (Vet (Position), "bad cursor in Next");
909 Next_Node : constant Node_Access := Position.Node.Next;
911 if Next_Node = null then
915 return Cursor'(Position.Container, Next_Node);
924 (Container : in out List;
925 New_Item : Element_Type;
926 Count : Count_Type := 1)
929 Insert (Container, First (Container), New_Item, Count);
936 procedure Previous (Position : in out Cursor) is
938 Position := Previous (Position);
941 function Previous (Position : Cursor) return Cursor is
943 if Position.Node = null then
947 pragma Assert (Vet (Position), "bad cursor in Previous");
950 Prev_Node : constant Node_Access := Position.Node.Prev;
952 if Prev_Node = null then
956 return Cursor'(Position.Container, Prev_Node);
964 procedure Query_Element
966 Process : not null access procedure (Element : Element_Type))
969 if Position.Node = null then
970 raise Constraint_Error with
971 "Position cursor has no element";
974 if Position.Node.Element = null then
975 raise Program_Error with
976 "Position cursor has no element";
979 pragma Assert (Vet (Position), "bad cursor in Query_Element");
982 C : List renames Position.Container.all'Unrestricted_Access.all;
983 B : Natural renames C.Busy;
984 L : Natural renames C.Lock;
991 Process (Position.Node.Element.all);
1009 (Stream : not null access Root_Stream_Type'Class;
1012 N : Count_Type'Base;
1018 Count_Type'Base'Read (Stream, N);
1025 Element : Element_Access :=
1026 new Element_Type'(Element_Type'Input (Stream));
1028 Dst := new Node_Type'(Element, null, null);
1039 while Item.Length < N loop
1041 Element : Element_Access :=
1042 new Element_Type'(Element_Type'Input (Stream));
1044 Dst := new Node_Type'(Element, Next => null, Prev => Item.Last);
1051 Item.Last.Next := Dst;
1053 Item.Length := Item.Length + 1;
1058 (Stream : not null access Root_Stream_Type'Class;
1062 raise Program_Error with "attempt to stream list cursor";
1065 ---------------------
1066 -- Replace_Element --
1067 ---------------------
1069 procedure Replace_Element
1070 (Container : in out List;
1072 New_Item : Element_Type)
1075 if Position.Container = null then
1076 raise Constraint_Error with "Position cursor has no element";
1079 if Position.Container /= Container'Unchecked_Access then
1080 raise Program_Error with
1081 "Position cursor designates wrong container";
1084 if Container.Lock > 0 then
1085 raise Program_Error with
1086 "attempt to tamper with cursors (list is locked)";
1089 if Position.Node.Element = null then
1090 raise Program_Error with
1091 "Position cursor has no element";
1094 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1097 X : Element_Access := Position.Node.Element;
1100 Position.Node.Element := new Element_Type'(New_Item);
1103 end Replace_Element;
1105 ----------------------
1106 -- Reverse_Elements --
1107 ----------------------
1109 procedure Reverse_Elements (Container : in out List) is
1110 I : Node_Access := Container.First;
1111 J : Node_Access := Container.Last;
1113 procedure Swap (L, R : Node_Access);
1119 procedure Swap (L, R : Node_Access) is
1120 LN : constant Node_Access := L.Next;
1121 LP : constant Node_Access := L.Prev;
1123 RN : constant Node_Access := R.Next;
1124 RP : constant Node_Access := R.Prev;
1139 pragma Assert (RP = L);
1153 -- Start of processing for Reverse_Elements
1156 if Container.Length <= 1 then
1160 pragma Assert (Container.First.Prev = null);
1161 pragma Assert (Container.Last.Next = null);
1163 if Container.Busy > 0 then
1164 raise Program_Error with
1165 "attempt to tamper with elements (list is busy)";
1168 Container.First := J;
1169 Container.Last := I;
1171 Swap (L => I, R => J);
1179 Swap (L => J, R => I);
1188 pragma Assert (Container.First.Prev = null);
1189 pragma Assert (Container.Last.Next = null);
1190 end Reverse_Elements;
1196 function Reverse_Find
1198 Item : Element_Type;
1199 Position : Cursor := No_Element) return Cursor
1201 Node : Node_Access := Position.Node;
1205 Node := Container.Last;
1208 if Node.Element = null then
1209 raise Program_Error with "Position cursor has no element";
1212 if Position.Container /= Container'Unrestricted_Access then
1213 raise Program_Error with
1214 "Position cursor designates wrong container";
1217 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1220 while Node /= null loop
1221 if Node.Element.all = Item then
1222 return Cursor'(Container'Unchecked_Access, Node);
1231 ---------------------
1232 -- Reverse_Iterate --
1233 ---------------------
1235 procedure Reverse_Iterate
1237 Process : not null access procedure (Position : Cursor))
1239 C : List renames Container'Unrestricted_Access.all;
1240 B : Natural renames C.Busy;
1242 Node : Node_Access := Container.Last;
1248 while Node /= null loop
1249 Process (Cursor'(Container'Unchecked_Access, Node));
1259 end Reverse_Iterate;
1266 (Target : in out List;
1268 Source : in out List)
1271 if Before.Container /= null then
1272 if Before.Container /= Target'Unrestricted_Access then
1273 raise Program_Error with
1274 "Before cursor designates wrong container";
1277 if Before.Node = null
1278 or else Before.Node.Element = null
1280 raise Program_Error with
1281 "Before cursor has no element";
1284 pragma Assert (Vet (Before), "bad cursor in Splice");
1287 if Target'Address = Source'Address
1288 or else Source.Length = 0
1293 pragma Assert (Source.First.Prev = null);
1294 pragma Assert (Source.Last.Next = null);
1296 if Target.Length > Count_Type'Last - Source.Length then
1297 raise Constraint_Error with "new length exceeds maximum";
1300 if Target.Busy > 0 then
1301 raise Program_Error with
1302 "attempt to tamper with elements of Target (list is busy)";
1305 if Source.Busy > 0 then
1306 raise Program_Error with
1307 "attempt to tamper with elements of Source (list is busy)";
1310 if Target.Length = 0 then
1311 pragma Assert (Before = No_Element);
1312 pragma Assert (Target.First = null);
1313 pragma Assert (Target.Last = null);
1315 Target.First := Source.First;
1316 Target.Last := Source.Last;
1318 elsif Before.Node = null then
1319 pragma Assert (Target.Last.Next = null);
1321 Target.Last.Next := Source.First;
1322 Source.First.Prev := Target.Last;
1324 Target.Last := Source.Last;
1326 elsif Before.Node = Target.First then
1327 pragma Assert (Target.First.Prev = null);
1329 Source.Last.Next := Target.First;
1330 Target.First.Prev := Source.Last;
1332 Target.First := Source.First;
1335 pragma Assert (Target.Length >= 2);
1336 Before.Node.Prev.Next := Source.First;
1337 Source.First.Prev := Before.Node.Prev;
1339 Before.Node.Prev := Source.Last;
1340 Source.Last.Next := Before.Node;
1343 Source.First := null;
1344 Source.Last := null;
1346 Target.Length := Target.Length + Source.Length;
1351 (Container : in out List;
1356 if Before.Container /= null then
1357 if Before.Container /= Container'Unchecked_Access then
1358 raise Program_Error with
1359 "Before cursor designates wrong container";
1362 if Before.Node = null
1363 or else Before.Node.Element = null
1365 raise Program_Error with
1366 "Before cursor has no element";
1369 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1372 if Position.Node = null then
1373 raise Constraint_Error with "Position cursor has no element";
1376 if Position.Node.Element = null then
1377 raise Program_Error with "Position cursor has no element";
1380 if Position.Container /= Container'Unrestricted_Access then
1381 raise Program_Error with
1382 "Position cursor designates wrong container";
1385 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1387 if Position.Node = Before.Node
1388 or else Position.Node.Next = Before.Node
1393 pragma Assert (Container.Length >= 2);
1395 if Container.Busy > 0 then
1396 raise Program_Error with
1397 "attempt to tamper with elements (list is busy)";
1400 if Before.Node = null then
1401 pragma Assert (Position.Node /= Container.Last);
1403 if Position.Node = Container.First then
1404 Container.First := Position.Node.Next;
1405 Container.First.Prev := null;
1407 Position.Node.Prev.Next := Position.Node.Next;
1408 Position.Node.Next.Prev := Position.Node.Prev;
1411 Container.Last.Next := Position.Node;
1412 Position.Node.Prev := Container.Last;
1414 Container.Last := Position.Node;
1415 Container.Last.Next := null;
1420 if Before.Node = Container.First then
1421 pragma Assert (Position.Node /= Container.First);
1423 if Position.Node = Container.Last then
1424 Container.Last := Position.Node.Prev;
1425 Container.Last.Next := null;
1427 Position.Node.Prev.Next := Position.Node.Next;
1428 Position.Node.Next.Prev := Position.Node.Prev;
1431 Container.First.Prev := Position.Node;
1432 Position.Node.Next := Container.First;
1434 Container.First := Position.Node;
1435 Container.First.Prev := null;
1440 if Position.Node = Container.First then
1441 Container.First := Position.Node.Next;
1442 Container.First.Prev := null;
1444 elsif Position.Node = Container.Last then
1445 Container.Last := Position.Node.Prev;
1446 Container.Last.Next := null;
1449 Position.Node.Prev.Next := Position.Node.Next;
1450 Position.Node.Next.Prev := Position.Node.Prev;
1453 Before.Node.Prev.Next := Position.Node;
1454 Position.Node.Prev := Before.Node.Prev;
1456 Before.Node.Prev := Position.Node;
1457 Position.Node.Next := Before.Node;
1459 pragma Assert (Container.First.Prev = null);
1460 pragma Assert (Container.Last.Next = null);
1464 (Target : in out List;
1466 Source : in out List;
1467 Position : in out Cursor)
1470 if Target'Address = Source'Address then
1471 Splice (Target, Before, Position);
1475 if Before.Container /= null then
1476 if Before.Container /= Target'Unrestricted_Access then
1477 raise Program_Error with
1478 "Before cursor designates wrong container";
1481 if Before.Node = null
1482 or else Before.Node.Element = null
1484 raise Program_Error with
1485 "Before cursor has no element";
1488 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1491 if Position.Node = null then
1492 raise Constraint_Error with "Position cursor has no element";
1495 if Position.Node.Element = null then
1496 raise Program_Error with
1497 "Position cursor has no element";
1500 if Position.Container /= Source'Unrestricted_Access then
1501 raise Program_Error with
1502 "Position cursor designates wrong container";
1505 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1507 if Target.Length = Count_Type'Last then
1508 raise Constraint_Error with "Target is full";
1511 if Target.Busy > 0 then
1512 raise Program_Error with
1513 "attempt to tamper with elements of Target (list is busy)";
1516 if Source.Busy > 0 then
1517 raise Program_Error with
1518 "attempt to tamper with elements of Source (list is busy)";
1521 if Position.Node = Source.First then
1522 Source.First := Position.Node.Next;
1524 if Position.Node = Source.Last then
1525 pragma Assert (Source.First = null);
1526 pragma Assert (Source.Length = 1);
1527 Source.Last := null;
1530 Source.First.Prev := null;
1533 elsif Position.Node = Source.Last then
1534 pragma Assert (Source.Length >= 2);
1535 Source.Last := Position.Node.Prev;
1536 Source.Last.Next := null;
1539 pragma Assert (Source.Length >= 3);
1540 Position.Node.Prev.Next := Position.Node.Next;
1541 Position.Node.Next.Prev := Position.Node.Prev;
1544 if Target.Length = 0 then
1545 pragma Assert (Before = No_Element);
1546 pragma Assert (Target.First = null);
1547 pragma Assert (Target.Last = null);
1549 Target.First := Position.Node;
1550 Target.Last := Position.Node;
1552 Target.First.Prev := null;
1553 Target.Last.Next := null;
1555 elsif Before.Node = null then
1556 pragma Assert (Target.Last.Next = null);
1557 Target.Last.Next := Position.Node;
1558 Position.Node.Prev := Target.Last;
1560 Target.Last := Position.Node;
1561 Target.Last.Next := null;
1563 elsif Before.Node = Target.First then
1564 pragma Assert (Target.First.Prev = null);
1565 Target.First.Prev := Position.Node;
1566 Position.Node.Next := Target.First;
1568 Target.First := Position.Node;
1569 Target.First.Prev := null;
1572 pragma Assert (Target.Length >= 2);
1573 Before.Node.Prev.Next := Position.Node;
1574 Position.Node.Prev := Before.Node.Prev;
1576 Before.Node.Prev := Position.Node;
1577 Position.Node.Next := Before.Node;
1580 Target.Length := Target.Length + 1;
1581 Source.Length := Source.Length - 1;
1583 Position.Container := Target'Unchecked_Access;
1591 (Container : in out List;
1595 if I.Node = null then
1596 raise Constraint_Error with "I cursor has no element";
1599 if J.Node = null then
1600 raise Constraint_Error with "J cursor has no element";
1603 if I.Container /= Container'Unchecked_Access then
1604 raise Program_Error with "I cursor designates wrong container";
1607 if J.Container /= Container'Unchecked_Access then
1608 raise Program_Error with "J cursor designates wrong container";
1611 if I.Node = J.Node then
1615 if Container.Lock > 0 then
1616 raise Program_Error with
1617 "attempt to tamper with cursors (list is locked)";
1620 pragma Assert (Vet (I), "bad I cursor in Swap");
1621 pragma Assert (Vet (J), "bad J cursor in Swap");
1624 EI_Copy : constant Element_Access := I.Node.Element;
1627 I.Node.Element := J.Node.Element;
1628 J.Node.Element := EI_Copy;
1636 procedure Swap_Links
1637 (Container : in out List;
1641 if I.Node = null then
1642 raise Constraint_Error with "I cursor has no element";
1645 if J.Node = null then
1646 raise Constraint_Error with "J cursor has no element";
1649 if I.Container /= Container'Unrestricted_Access then
1650 raise Program_Error with "I cursor designates wrong container";
1653 if J.Container /= Container'Unrestricted_Access then
1654 raise Program_Error with "J cursor designates wrong container";
1657 if I.Node = J.Node then
1661 if Container.Busy > 0 then
1662 raise Program_Error with
1663 "attempt to tamper with elements (list is busy)";
1666 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
1667 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
1670 I_Next : constant Cursor := Next (I);
1674 Splice (Container, Before => I, Position => J);
1678 J_Next : constant Cursor := Next (J);
1682 Splice (Container, Before => J, Position => I);
1685 pragma Assert (Container.Length >= 3);
1687 Splice (Container, Before => I_Next, Position => J);
1688 Splice (Container, Before => J_Next, Position => I);
1694 pragma Assert (Container.First.Prev = null);
1695 pragma Assert (Container.Last.Next = null);
1698 --------------------
1699 -- Update_Element --
1700 --------------------
1702 procedure Update_Element
1703 (Container : in out List;
1705 Process : not null access procedure (Element : in out Element_Type))
1708 if Position.Node = null then
1709 raise Constraint_Error with "Position cursor has no element";
1712 if Position.Node.Element = null then
1713 raise Program_Error with
1714 "Position cursor has no element";
1717 if Position.Container /= Container'Unchecked_Access then
1718 raise Program_Error with
1719 "Position cursor designates wrong container";
1722 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1725 B : Natural renames Container.Busy;
1726 L : Natural renames Container.Lock;
1733 Process (Position.Node.Element.all);
1750 function Vet (Position : Cursor) return Boolean is
1752 if Position.Node = null then
1753 return Position.Container = null;
1756 if Position.Container = null then
1760 if Position.Node.Next = Position.Node then
1764 if Position.Node.Prev = Position.Node then
1768 if Position.Node.Element = null then
1773 L : List renames Position.Container.all;
1775 if L.Length = 0 then
1779 if L.First = null then
1783 if L.Last = null then
1787 if L.First.Prev /= null then
1791 if L.Last.Next /= null then
1795 if Position.Node.Prev = null
1796 and then Position.Node /= L.First
1801 if Position.Node.Next = null
1802 and then Position.Node /= L.Last
1807 if L.Length = 1 then
1808 return L.First = L.Last;
1811 if L.First = L.Last then
1815 if L.First.Next = null then
1819 if L.Last.Prev = null then
1823 if L.First.Next.Prev /= L.First then
1827 if L.Last.Prev.Next /= L.Last then
1831 if L.Length = 2 then
1832 if L.First.Next /= L.Last then
1836 if L.Last.Prev /= L.First then
1843 if L.First.Next = L.Last then
1847 if L.Last.Prev = L.First then
1851 if Position.Node = L.First then
1855 if Position.Node = L.Last then
1859 if Position.Node.Next = null then
1863 if Position.Node.Prev = null then
1867 if Position.Node.Next.Prev /= Position.Node then
1871 if Position.Node.Prev.Next /= Position.Node then
1875 if L.Length = 3 then
1876 if L.First.Next /= Position.Node then
1880 if L.Last.Prev /= Position.Node then
1894 (Stream : not null access Root_Stream_Type'Class;
1897 Node : Node_Access := Item.First;
1900 Count_Type'Base'Write (Stream, Item.Length);
1902 while Node /= null loop
1903 Element_Type'Output (Stream, Node.Element.all);
1909 (Stream : not null access Root_Stream_Type'Class;
1913 raise Program_Error with "attempt to stream list cursor";
1916 end Ada.Containers.Indefinite_Doubly_Linked_Lists;