1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.BOUNDED_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 System; use type System.Address;
32 package body Ada.Containers.Bounded_Doubly_Linked_Lists is
34 List_Iterator_Interfaces.Reversible_Iterator with record
35 Container : List_Access;
39 overriding function First (Object : Iterator) return Cursor;
40 overriding function Last (Object : Iterator) return Cursor;
42 overriding function Next
44 Position : Cursor) return Cursor;
46 overriding function Previous
48 Position : Cursor) return Cursor;
50 -----------------------
51 -- Local Subprograms --
52 -----------------------
55 (Container : in out List;
56 New_Item : Element_Type;
57 New_Node : out Count_Type);
60 (Container : in out List;
61 New_Node : out Count_Type);
64 (Container : in out List;
65 Stream : not null access Root_Stream_Type'Class;
66 New_Node : out Count_Type);
69 (Container : in out List;
72 procedure Insert_Internal
73 (Container : in out List;
75 New_Node : Count_Type);
77 function Vet (Position : Cursor) return Boolean;
83 function "=" (Left, Right : List) return Boolean is
84 LN : Node_Array renames Left.Nodes;
85 RN : Node_Array renames Right.Nodes;
90 if Left'Address = Right'Address then
94 if Left.Length /= Right.Length then
100 for J in 1 .. Left.Length loop
101 if LN (LI).Element /= RN (RI).Element then
117 (Container : in out List;
118 New_Item : Element_Type;
119 New_Node : out Count_Type)
121 N : Node_Array renames Container.Nodes;
124 if Container.Free >= 0 then
125 New_Node := Container.Free;
127 -- We always perform the assignment first, before we
128 -- change container state, in order to defend against
129 -- exceptions duration assignment.
131 N (New_Node).Element := New_Item;
132 Container.Free := N (New_Node).Next;
135 -- A negative free store value means that the links of the nodes
136 -- in the free store have not been initialized. In this case, the
137 -- nodes are physically contiguous in the array, starting at the
138 -- index that is the absolute value of the Container.Free, and
139 -- continuing until the end of the array (Nodes'Last).
141 New_Node := abs Container.Free;
143 -- As above, we perform this assignment first, before modifying
144 -- any container state.
146 N (New_Node).Element := New_Item;
147 Container.Free := Container.Free - 1;
152 (Container : in out List;
153 Stream : not null access Root_Stream_Type'Class;
154 New_Node : out Count_Type)
156 N : Node_Array renames Container.Nodes;
159 if Container.Free >= 0 then
160 New_Node := Container.Free;
162 -- We always perform the assignment first, before we
163 -- change container state, in order to defend against
164 -- exceptions duration assignment.
166 Element_Type'Read (Stream, N (New_Node).Element);
167 Container.Free := N (New_Node).Next;
170 -- A negative free store value means that the links of the nodes
171 -- in the free store have not been initialized. In this case, the
172 -- nodes are physically contiguous in the array, starting at the
173 -- index that is the absolute value of the Container.Free, and
174 -- continuing until the end of the array (Nodes'Last).
176 New_Node := abs Container.Free;
178 -- As above, we perform this assignment first, before modifying
179 -- any container state.
181 Element_Type'Read (Stream, N (New_Node).Element);
182 Container.Free := Container.Free - 1;
187 (Container : in out List;
188 New_Node : out Count_Type)
190 N : Node_Array renames Container.Nodes;
193 if Container.Free >= 0 then
194 New_Node := Container.Free;
195 Container.Free := N (New_Node).Next;
198 -- As explained above, a negative free store value means that the
199 -- links for the nodes in the free store have not been initialized.
201 New_Node := abs Container.Free;
202 Container.Free := Container.Free - 1;
211 (Container : in out List;
212 New_Item : Element_Type;
213 Count : Count_Type := 1)
216 Insert (Container, No_Element, New_Item, Count);
223 procedure Assign (Target : in out List; Source : List) is
224 SN : Node_Array renames Source.Nodes;
228 if Target'Address = Source'Address then
232 if Target.Capacity < Source.Length then
233 raise Capacity_Error -- ???
234 with "Target capacity is less than Source length";
241 Target.Append (SN (J).Element);
250 procedure Clear (Container : in out List) is
251 N : Node_Array renames Container.Nodes;
255 if Container.Length = 0 then
256 pragma Assert (Container.First = 0);
257 pragma Assert (Container.Last = 0);
258 pragma Assert (Container.Busy = 0);
259 pragma Assert (Container.Lock = 0);
263 pragma Assert (Container.First >= 1);
264 pragma Assert (Container.Last >= 1);
265 pragma Assert (N (Container.First).Prev = 0);
266 pragma Assert (N (Container.Last).Next = 0);
268 if Container.Busy > 0 then
269 raise Program_Error with
270 "attempt to tamper with cursors (list is busy)";
273 while Container.Length > 1 loop
274 X := Container.First;
275 pragma Assert (N (N (X).Next).Prev = Container.First);
277 Container.First := N (X).Next;
278 N (Container.First).Prev := 0;
280 Container.Length := Container.Length - 1;
285 X := Container.First;
286 pragma Assert (X = Container.Last);
288 Container.First := 0;
290 Container.Length := 0;
301 Item : Element_Type) return Boolean
304 return Find (Container, Item) /= No_Element;
311 function Copy (Source : List; Capacity : Count_Type := 0) return List is
318 elsif Capacity >= Source.Length then
322 raise Capacity_Error with "Capacity value too small";
325 return Target : List (Capacity => C) do
326 Assign (Target => Target, Source => Source);
335 (Container : in out List;
336 Position : in out Cursor;
337 Count : Count_Type := 1)
339 N : Node_Array renames Container.Nodes;
343 if Position.Node = 0 then
344 raise Constraint_Error with
345 "Position cursor has no element";
348 if Position.Container /= Container'Unrestricted_Access then
349 raise Program_Error with
350 "Position cursor designates wrong container";
353 pragma Assert (Vet (Position), "bad cursor in Delete");
354 pragma Assert (Container.First >= 1);
355 pragma Assert (Container.Last >= 1);
356 pragma Assert (N (Container.First).Prev = 0);
357 pragma Assert (N (Container.Last).Next = 0);
359 if Position.Node = Container.First then
360 Delete_First (Container, Count);
361 Position := No_Element;
366 Position := No_Element;
370 if Container.Busy > 0 then
371 raise Program_Error with
372 "attempt to tamper with cursors (list is busy)";
375 for Index in 1 .. Count loop
376 pragma Assert (Container.Length >= 2);
379 Container.Length := Container.Length - 1;
381 if X = Container.Last then
382 Position := No_Element;
384 Container.Last := N (X).Prev;
385 N (Container.Last).Next := 0;
391 Position.Node := N (X).Next;
393 N (N (X).Next).Prev := N (X).Prev;
394 N (N (X).Prev).Next := N (X).Next;
399 Position := No_Element;
406 procedure Delete_First
407 (Container : in out List;
408 Count : Count_Type := 1)
410 N : Node_Array renames Container.Nodes;
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
429 X := Container.First;
430 pragma Assert (N (N (X).Next).Prev = Container.First);
432 Container.First := N (X).Next;
433 N (Container.First).Prev := 0;
435 Container.Length := Container.Length - 1;
445 procedure Delete_Last
446 (Container : in out List;
447 Count : Count_Type := 1)
449 N : Node_Array renames Container.Nodes;
453 if Count >= Container.Length then
462 if Container.Busy > 0 then
463 raise Program_Error with
464 "attempt to tamper with cursors (list is busy)";
467 for I in 1 .. Count loop
469 pragma Assert (N (N (X).Prev).Next = Container.Last);
471 Container.Last := N (X).Prev;
472 N (Container.Last).Next := 0;
474 Container.Length := Container.Length - 1;
484 function Element (Position : Cursor) return Element_Type is
486 if Position.Node = 0 then
487 raise Constraint_Error with
488 "Position cursor has no element";
491 pragma Assert (Vet (Position), "bad cursor in Element");
493 return Position.Container.Nodes (Position.Node).Element;
503 Position : Cursor := No_Element) return Cursor
505 Nodes : Node_Array renames Container.Nodes;
506 Node : Count_Type := Position.Node;
510 Node := Container.First;
513 if Position.Container /= Container'Unrestricted_Access then
514 raise Program_Error with
515 "Position cursor designates wrong container";
518 pragma Assert (Vet (Position), "bad cursor in Find");
522 if Nodes (Node).Element = Item then
523 return Cursor'(Container'Unrestricted_Access, Node);
526 Node := Nodes (Node).Next;
536 function First (Container : List) return Cursor is
538 if Container.First = 0 then
542 return Cursor'(Container'Unrestricted_Access, Container.First);
545 function First (Object : Iterator) return Cursor is
547 if Object.Container = null then
550 return (Object.Container, Object.Container.First);
558 function First_Element (Container : List) return Element_Type is
560 if Container.First = 0 then
561 raise Constraint_Error with "list is empty";
564 return Container.Nodes (Container.First).Element;
572 (Container : in out List;
575 pragma Assert (X > 0);
576 pragma Assert (X <= Container.Capacity);
578 N : Node_Array renames Container.Nodes;
579 pragma Assert (N (X).Prev >= 0); -- node is active
582 -- The list container actually contains two lists: one for the "active"
583 -- nodes that contain elements that have been inserted onto the list,
584 -- and another for the "inactive" nodes for the free store.
586 -- We desire that merely declaring an object should have only minimal
587 -- cost; specially, we want to avoid having to initialize the free
588 -- store (to fill in the links), especially if the capacity is large.
590 -- The head of the free list is indicated by Container.Free. If its
591 -- value is non-negative, then the free store has been initialized in
592 -- the "normal" way: Container.Free points to the head of the list of
593 -- free (inactive) nodes, and the value 0 means the free list is empty.
594 -- Each node on the free list has been initialized to point to the next
595 -- free node (via its Next component), and the value 0 means that this
596 -- is the last free node.
598 -- If Container.Free is negative, then the links on the free store have
599 -- not been initialized. In this case the link values are implied: the
600 -- free store comprises the components of the node array started with
601 -- the absolute value of Container.Free, and continuing until the end of
602 -- the array (Nodes'Last).
604 -- If the list container is manipulated on one end only (for example if
605 -- the container were being used as a stack), then there is no need to
606 -- initialize the free store, since the inactive nodes are physically
607 -- contiguous (in fact, they lie immediately beyond the logical end
608 -- being manipulated). The only time we need to actually initialize the
609 -- nodes in the free store is if the node that becomes inactive is not
610 -- at the end of the list. The free store would then be discontiguous
611 -- and so its nodes would need to be linked in the traditional way.
614 -- It might be possible to perform an optimization here. Suppose that
615 -- the free store can be represented as having two parts: one comprising
616 -- the non-contiguous inactive nodes linked together in the normal way,
617 -- and the other comprising the contiguous inactive nodes (that are not
618 -- linked together, at the end of the nodes array). This would allow us
619 -- to never have to initialize the free store, except in a lazy way as
620 -- nodes become inactive.
622 -- When an element is deleted from the list container, its node becomes
623 -- inactive, and so we set its Prev component to a negative value, to
624 -- indicate that it is now inactive. This provides a useful way to
625 -- detect a dangling cursor reference.
627 N (X).Prev := -1; -- Node is deallocated (not on active list)
629 if Container.Free >= 0 then
631 -- The free store has previously been initialized. All we need to
632 -- do here is link the newly-free'd node onto the free list.
634 N (X).Next := Container.Free;
637 elsif X + 1 = abs Container.Free then
639 -- The free store has not been initialized, and the node becoming
640 -- inactive immediately precedes the start of the free store. All
641 -- we need to do is move the start of the free store back by one.
643 N (X).Next := 0; -- not strictly necessary, but marginally safer
644 Container.Free := Container.Free + 1;
647 -- The free store has not been initialized, and the node becoming
648 -- inactive does not immediately precede the free store. Here we
649 -- first initialize the free store (meaning the links are given
650 -- values in the traditional way), and then link the newly-free'd
651 -- node onto the head of the free store.
654 -- See the comments above for an optimization opportunity. If the
655 -- next link for a node on the free store is negative, then this
656 -- means the remaining nodes on the free store are physically
657 -- contiguous, starting as the absolute value of that index value.
659 Container.Free := abs Container.Free;
661 if Container.Free > Container.Capacity then
665 for I in Container.Free .. Container.Capacity - 1 loop
669 N (Container.Capacity).Next := 0;
672 N (X).Next := Container.Free;
677 ---------------------
678 -- Generic_Sorting --
679 ---------------------
681 package body Generic_Sorting is
687 function Is_Sorted (Container : List) return Boolean is
688 Nodes : Node_Array renames Container.Nodes;
689 Node : Count_Type := Container.First;
692 for J in 2 .. Container.Length loop
693 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
697 Node := Nodes (Node).Next;
708 (Target : in out List;
709 Source : in out List)
711 LN : Node_Array renames Target.Nodes;
712 RN : Node_Array renames Source.Nodes;
716 if Target'Address = Source'Address then
720 if Target.Busy > 0 then
721 raise Program_Error with
722 "attempt to tamper with cursors of Target (list is busy)";
725 if Source.Busy > 0 then
726 raise Program_Error with
727 "attempt to tamper with cursors of Source (list is busy)";
730 LI := First (Target);
731 RI := First (Source);
732 while RI.Node /= 0 loop
733 pragma Assert (RN (RI.Node).Next = 0
734 or else not (RN (RN (RI.Node).Next).Element <
735 RN (RI.Node).Element));
738 Splice (Target, No_Element, Source);
742 pragma Assert (LN (LI.Node).Next = 0
743 or else not (LN (LN (LI.Node).Next).Element <
744 LN (LI.Node).Element));
746 if RN (RI.Node).Element < LN (LI.Node).Element then
749 pragma Warnings (Off, RJ);
751 RI.Node := RN (RI.Node).Next;
752 Splice (Target, LI, Source, RJ);
756 LI.Node := LN (LI.Node).Next;
765 procedure Sort (Container : in out List) is
766 N : Node_Array renames Container.Nodes;
768 procedure Partition (Pivot, Back : Count_Type);
769 -- What does this do ???
771 procedure Sort (Front, Back : Count_Type);
772 -- Internal procedure, what does it do??? rename it???
778 procedure Partition (Pivot, Back : Count_Type) is
782 Node := N (Pivot).Next;
783 while Node /= Back loop
784 if N (Node).Element < N (Pivot).Element then
786 Prev : constant Count_Type := N (Node).Prev;
787 Next : constant Count_Type := N (Node).Next;
790 N (Prev).Next := Next;
793 Container.Last := Prev;
795 N (Next).Prev := Prev;
798 N (Node).Next := Pivot;
799 N (Node).Prev := N (Pivot).Prev;
801 N (Pivot).Prev := Node;
803 if N (Node).Prev = 0 then
804 Container.First := Node;
806 N (N (Node).Prev).Next := Node;
813 Node := N (Node).Next;
822 procedure Sort (Front, Back : Count_Type) is
823 Pivot : constant Count_Type :=
824 (if Front = 0 then Container.First else N (Front).Next);
826 if Pivot /= Back then
827 Partition (Pivot, Back);
833 -- Start of processing for Sort
836 if Container.Length <= 1 then
840 pragma Assert (N (Container.First).Prev = 0);
841 pragma Assert (N (Container.Last).Next = 0);
843 if Container.Busy > 0 then
844 raise Program_Error with
845 "attempt to tamper with cursors (list is busy)";
848 Sort (Front => 0, Back => 0);
850 pragma Assert (N (Container.First).Prev = 0);
851 pragma Assert (N (Container.Last).Next = 0);
860 function Has_Element (Position : Cursor) return Boolean is
862 pragma Assert (Vet (Position), "bad cursor in Has_Element");
863 return Position.Node /= 0;
871 (Container : in out List;
873 New_Item : Element_Type;
874 Position : out Cursor;
875 Count : Count_Type := 1)
877 New_Node : Count_Type;
880 if Before.Container /= null then
881 if Before.Container /= Container'Unrestricted_Access then
882 raise Program_Error with
883 "Before cursor designates wrong list";
886 pragma Assert (Vet (Before), "bad cursor in Insert");
894 if Container.Length > Container.Capacity - Count then
895 raise Constraint_Error with "new length exceeds capacity";
898 if Container.Busy > 0 then
899 raise Program_Error with
900 "attempt to tamper with cursors (list is busy)";
903 Allocate (Container, New_Item, New_Node);
904 Insert_Internal (Container, Before.Node, New_Node => New_Node);
905 Position := Cursor'(Container'Unchecked_Access, Node => New_Node);
907 for Index in Count_Type'(2) .. Count loop
908 Allocate (Container, New_Item, New_Node => New_Node);
909 Insert_Internal (Container, Before.Node, New_Node => New_Node);
914 (Container : in out List;
916 New_Item : Element_Type;
917 Count : Count_Type := 1)
920 pragma Unreferenced (Position);
922 Insert (Container, Before, New_Item, Position, Count);
926 (Container : in out List;
928 Position : out Cursor;
929 Count : Count_Type := 1)
931 New_Node : Count_Type;
934 if Before.Container /= null then
935 if Before.Container /= Container'Unrestricted_Access then
936 raise Program_Error with
937 "Before cursor designates wrong list";
940 pragma Assert (Vet (Before), "bad cursor in Insert");
948 if Container.Length > Container.Capacity - Count then
949 raise Constraint_Error with "new length exceeds capacity";
952 if Container.Busy > 0 then
953 raise Program_Error with
954 "attempt to tamper with cursors (list is busy)";
957 Allocate (Container, New_Node => New_Node);
958 Insert_Internal (Container, Before.Node, New_Node);
959 Position := Cursor'(Container'Unchecked_Access, New_Node);
961 for Index in Count_Type'(2) .. Count loop
962 Allocate (Container, New_Node => New_Node);
963 Insert_Internal (Container, Before.Node, New_Node);
967 ---------------------
968 -- Insert_Internal --
969 ---------------------
971 procedure Insert_Internal
972 (Container : in out List;
974 New_Node : Count_Type)
976 N : Node_Array renames Container.Nodes;
979 if Container.Length = 0 then
980 pragma Assert (Before = 0);
981 pragma Assert (Container.First = 0);
982 pragma Assert (Container.Last = 0);
984 Container.First := New_Node;
985 N (Container.First).Prev := 0;
987 Container.Last := New_Node;
988 N (Container.Last).Next := 0;
990 elsif Before = 0 then -- means append
991 pragma Assert (N (Container.Last).Next = 0);
993 N (Container.Last).Next := New_Node;
994 N (New_Node).Prev := Container.Last;
996 Container.Last := New_Node;
997 N (Container.Last).Next := 0;
999 elsif Before = Container.First then -- means prepend
1000 pragma Assert (N (Container.First).Prev = 0);
1002 N (Container.First).Prev := New_Node;
1003 N (New_Node).Next := Container.First;
1005 Container.First := New_Node;
1006 N (Container.First).Prev := 0;
1009 pragma Assert (N (Container.First).Prev = 0);
1010 pragma Assert (N (Container.Last).Next = 0);
1012 N (New_Node).Next := Before;
1013 N (New_Node).Prev := N (Before).Prev;
1015 N (N (Before).Prev).Next := New_Node;
1016 N (Before).Prev := New_Node;
1019 Container.Length := Container.Length + 1;
1020 end Insert_Internal;
1026 function Is_Empty (Container : List) return Boolean is
1028 return Container.Length = 0;
1037 Process : not null access procedure (Position : Cursor))
1039 C : List renames Container'Unrestricted_Access.all;
1040 B : Natural renames C.Busy;
1042 Node : Count_Type := Container.First;
1048 while Node /= 0 loop
1049 Process (Cursor'(Container'Unrestricted_Access, Node));
1050 Node := Container.Nodes (Node).Next;
1064 return List_Iterator_Interfaces.Reversible_Iterator'class
1067 if Container.Length = 0 then
1068 return Iterator'(null, Count_Type'First);
1070 return Iterator'(Container'Unrestricted_Access, Container.First);
1077 return List_Iterator_Interfaces.Reversible_Iterator'class
1079 It : constant Iterator := (Container'Unrestricted_Access, Start.Node);
1088 function Last (Container : List) return Cursor is
1090 if Container.Last = 0 then
1094 return Cursor'(Container'Unrestricted_Access, Container.Last);
1097 function Last (Object : Iterator) return Cursor is
1099 if Object.Container = null then
1102 return (Object.Container, Object.Container.Last);
1110 function Last_Element (Container : List) return Element_Type is
1112 if Container.Last = 0 then
1113 raise Constraint_Error with "list is empty";
1116 return Container.Nodes (Container.Last).Element;
1123 function Length (Container : List) return Count_Type is
1125 return Container.Length;
1133 (Target : in out List;
1134 Source : in out List)
1136 N : Node_Array renames Source.Nodes;
1140 if Target'Address = Source'Address then
1144 if Target.Capacity < Source.Length then
1145 raise Capacity_Error with "Source length exceeds Target capacity";
1148 if Source.Busy > 0 then
1149 raise Program_Error with
1150 "attempt to tamper with cursors of Source (list is busy)";
1155 while Source.Length > 0 loop
1157 Append (Target, N (X).Element);
1159 Source.First := N (X).Next;
1160 N (Source.First).Prev := 0;
1162 Source.Length := Source.Length - 1;
1171 procedure Next (Position : in out Cursor) is
1173 Position := Next (Position);
1176 function Next (Position : Cursor) return Cursor is
1178 if Position.Node = 0 then
1182 pragma Assert (Vet (Position), "bad cursor in Next");
1185 Nodes : Node_Array renames Position.Container.Nodes;
1186 Node : constant Count_Type := Nodes (Position.Node).Next;
1192 return Cursor'(Position.Container, Node);
1198 Position : Cursor) return Cursor
1200 Nodes : Node_Array renames Position.Container.Nodes;
1201 Node : constant Count_Type := Nodes (Position.Node).Next;
1203 if Position.Node = Object.Container.Last then
1206 return (Object.Container, Node);
1215 (Container : in out List;
1216 New_Item : Element_Type;
1217 Count : Count_Type := 1)
1220 Insert (Container, First (Container), New_Item, Count);
1227 procedure Previous (Position : in out Cursor) is
1229 Position := Previous (Position);
1232 function Previous (Position : Cursor) return Cursor is
1234 if Position.Node = 0 then
1238 pragma Assert (Vet (Position), "bad cursor in Previous");
1241 Nodes : Node_Array renames Position.Container.Nodes;
1242 Node : constant Count_Type := Nodes (Position.Node).Prev;
1248 return Cursor'(Position.Container, Node);
1254 Position : Cursor) return Cursor
1256 Nodes : Node_Array renames Position.Container.Nodes;
1257 Node : constant Count_Type := Nodes (Position.Node).Prev;
1259 if Position.Node = 0 then
1262 return (Object.Container, Node);
1270 procedure Query_Element
1272 Process : not null access procedure (Element : Element_Type))
1275 if Position.Node = 0 then
1276 raise Constraint_Error with
1277 "Position cursor has no element";
1280 pragma Assert (Vet (Position), "bad cursor in Query_Element");
1283 C : List renames Position.Container.all'Unrestricted_Access.all;
1284 B : Natural renames C.Busy;
1285 L : Natural renames C.Lock;
1292 N : Node_Type renames C.Nodes (Position.Node);
1294 Process (N.Element);
1312 (Stream : not null access Root_Stream_Type'Class;
1315 N : Count_Type'Base;
1320 Count_Type'Base'Read (Stream, N);
1323 raise Program_Error with "bad list length (corrupt stream)";
1330 if N > Item.Capacity then
1331 raise Constraint_Error with "length exceeds capacity";
1334 for Idx in 1 .. N loop
1335 Allocate (Item, Stream, New_Node => X);
1336 Insert_Internal (Item, Before => 0, New_Node => X);
1341 (Stream : not null access Root_Stream_Type'Class;
1345 raise Program_Error with "attempt to stream list cursor";
1349 (Stream : not null access Root_Stream_Type'Class;
1350 Item : out Reference_Type)
1353 raise Program_Error with "attempt to stream reference";
1357 (Stream : not null access Root_Stream_Type'Class;
1358 Item : out Constant_Reference_Type)
1361 raise Program_Error with "attempt to stream reference";
1368 function Constant_Reference (Container : List; Position : Cursor)
1369 return Constant_Reference_Type is
1371 pragma Unreferenced (Container);
1373 if Position.Container = null then
1374 raise Constraint_Error with "Position cursor has no element";
1378 Position.Container.Nodes (Position.Node).Element'Unrestricted_Access);
1379 end Constant_Reference;
1381 function Reference (Container : List; Position : Cursor)
1382 return Reference_Type is
1384 pragma Unreferenced (Container);
1386 if Position.Container = null then
1387 raise Constraint_Error with "Position cursor has no element";
1391 Position.Container.Nodes (Position.Node).Element'Unrestricted_Access);
1394 ---------------------
1395 -- Replace_Element --
1396 ---------------------
1398 procedure Replace_Element
1399 (Container : in out List;
1401 New_Item : Element_Type)
1404 if Position.Container = null then
1405 raise Constraint_Error with "Position cursor has no element";
1408 if Position.Container /= Container'Unchecked_Access then
1409 raise Program_Error with
1410 "Position cursor designates wrong container";
1413 if Container.Lock > 0 then
1414 raise Program_Error with
1415 "attempt to tamper with elements (list is locked)";
1418 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1420 Container.Nodes (Position.Node).Element := New_Item;
1421 end Replace_Element;
1423 ----------------------
1424 -- Reverse_Elements --
1425 ----------------------
1427 procedure Reverse_Elements (Container : in out List) is
1428 N : Node_Array renames Container.Nodes;
1429 I : Count_Type := Container.First;
1430 J : Count_Type := Container.Last;
1432 procedure Swap (L, R : Count_Type);
1438 procedure Swap (L, R : Count_Type) is
1439 LN : constant Count_Type := N (L).Next;
1440 LP : constant Count_Type := N (L).Prev;
1442 RN : constant Count_Type := N (R).Next;
1443 RP : constant Count_Type := N (R).Prev;
1458 pragma Assert (RP = L);
1472 -- Start of processing for Reverse_Elements
1475 if Container.Length <= 1 then
1479 pragma Assert (N (Container.First).Prev = 0);
1480 pragma Assert (N (Container.Last).Next = 0);
1482 if Container.Busy > 0 then
1483 raise Program_Error with
1484 "attempt to tamper with cursors (list is busy)";
1487 Container.First := J;
1488 Container.Last := I;
1490 Swap (L => I, R => J);
1498 Swap (L => J, R => I);
1507 pragma Assert (N (Container.First).Prev = 0);
1508 pragma Assert (N (Container.Last).Next = 0);
1509 end Reverse_Elements;
1515 function Reverse_Find
1517 Item : Element_Type;
1518 Position : Cursor := No_Element) return Cursor
1520 Node : Count_Type := Position.Node;
1524 Node := Container.Last;
1527 if Position.Container /= Container'Unrestricted_Access then
1528 raise Program_Error with
1529 "Position cursor designates wrong container";
1532 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1535 while Node /= 0 loop
1536 if Container.Nodes (Node).Element = Item then
1537 return Cursor'(Container'Unrestricted_Access, Node);
1540 Node := Container.Nodes (Node).Prev;
1546 ---------------------
1547 -- Reverse_Iterate --
1548 ---------------------
1550 procedure Reverse_Iterate
1552 Process : not null access procedure (Position : Cursor))
1554 C : List renames Container'Unrestricted_Access.all;
1555 B : Natural renames C.Busy;
1557 Node : Count_Type := Container.Last;
1563 while Node /= 0 loop
1564 Process (Cursor'(Container'Unrestricted_Access, Node));
1565 Node := Container.Nodes (Node).Prev;
1575 end Reverse_Iterate;
1582 (Target : in out List;
1584 Source : in out List)
1587 if Before.Container /= null then
1588 if Before.Container /= Target'Unrestricted_Access then
1589 raise Program_Error with
1590 "Before cursor designates wrong container";
1593 pragma Assert (Vet (Before), "bad cursor in Splice");
1596 if Target'Address = Source'Address
1597 or else Source.Length = 0
1602 pragma Assert (Source.Nodes (Source.First).Prev = 0);
1603 pragma Assert (Source.Nodes (Source.Last).Next = 0);
1605 if Target.Length > Count_Type'Last - Source.Length then
1606 raise Constraint_Error with "new length exceeds maximum";
1609 if Target.Length + Source.Length > Target.Capacity then
1610 raise Capacity_Error with "new length exceeds target capacity";
1613 if Target.Busy > 0 then
1614 raise Program_Error with
1615 "attempt to tamper with cursors of Target (list is busy)";
1618 if Source.Busy > 0 then
1619 raise Program_Error with
1620 "attempt to tamper with cursors of Source (list is busy)";
1623 while not Is_Empty (Source) loop
1624 Insert (Target, Before, Source.Nodes (Source.First).Element);
1625 Delete_First (Source);
1630 (Container : in out List;
1634 N : Node_Array renames Container.Nodes;
1637 if Before.Container /= null then
1638 if Before.Container /= Container'Unchecked_Access then
1639 raise Program_Error with
1640 "Before cursor designates wrong container";
1643 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1646 if Position.Node = 0 then
1647 raise Constraint_Error with "Position cursor has no element";
1650 if Position.Container /= Container'Unrestricted_Access then
1651 raise Program_Error with
1652 "Position cursor designates wrong container";
1655 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1657 if Position.Node = Before.Node
1658 or else N (Position.Node).Next = Before.Node
1663 pragma Assert (Container.Length >= 2);
1665 if Container.Busy > 0 then
1666 raise Program_Error with
1667 "attempt to tamper with cursors (list is busy)";
1670 if Before.Node = 0 then
1671 pragma Assert (Position.Node /= Container.Last);
1673 if Position.Node = Container.First then
1674 Container.First := N (Position.Node).Next;
1675 N (Container.First).Prev := 0;
1677 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1678 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1681 N (Container.Last).Next := Position.Node;
1682 N (Position.Node).Prev := Container.Last;
1684 Container.Last := Position.Node;
1685 N (Container.Last).Next := 0;
1690 if Before.Node = Container.First then
1691 pragma Assert (Position.Node /= Container.First);
1693 if Position.Node = Container.Last then
1694 Container.Last := N (Position.Node).Prev;
1695 N (Container.Last).Next := 0;
1697 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1698 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1701 N (Container.First).Prev := Position.Node;
1702 N (Position.Node).Next := Container.First;
1704 Container.First := Position.Node;
1705 N (Container.First).Prev := 0;
1710 if Position.Node = Container.First then
1711 Container.First := N (Position.Node).Next;
1712 N (Container.First).Prev := 0;
1714 elsif Position.Node = Container.Last then
1715 Container.Last := N (Position.Node).Prev;
1716 N (Container.Last).Next := 0;
1719 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1720 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1723 N (N (Before.Node).Prev).Next := Position.Node;
1724 N (Position.Node).Prev := N (Before.Node).Prev;
1726 N (Before.Node).Prev := Position.Node;
1727 N (Position.Node).Next := Before.Node;
1729 pragma Assert (N (Container.First).Prev = 0);
1730 pragma Assert (N (Container.Last).Next = 0);
1734 (Target : in out List;
1736 Source : in out List;
1737 Position : in out Cursor)
1739 Target_Position : Cursor;
1742 if Target'Address = Source'Address then
1743 Splice (Target, Before, Position);
1747 if Before.Container /= null then
1748 if Before.Container /= Target'Unrestricted_Access then
1749 raise Program_Error with
1750 "Before cursor designates wrong container";
1753 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1756 if Position.Node = 0 then
1757 raise Constraint_Error with "Position cursor has no element";
1760 if Position.Container /= Source'Unrestricted_Access then
1761 raise Program_Error with
1762 "Position cursor designates wrong container";
1765 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1767 if Target.Length >= Target.Capacity then
1768 raise Capacity_Error with "Target is full";
1771 if Target.Busy > 0 then
1772 raise Program_Error with
1773 "attempt to tamper with cursors of Target (list is busy)";
1776 if Source.Busy > 0 then
1777 raise Program_Error with
1778 "attempt to tamper with cursors of Source (list is busy)";
1782 (Container => Target,
1784 New_Item => Source.Nodes (Position.Node).Element,
1785 Position => Target_Position);
1787 Delete (Source, Position);
1788 Position := Target_Position;
1796 (Container : in out List;
1801 raise Constraint_Error with "I cursor has no element";
1805 raise Constraint_Error with "J cursor has no element";
1808 if I.Container /= Container'Unchecked_Access then
1809 raise Program_Error with "I cursor designates wrong container";
1812 if J.Container /= Container'Unchecked_Access then
1813 raise Program_Error with "J cursor designates wrong container";
1816 if I.Node = J.Node then
1820 if Container.Lock > 0 then
1821 raise Program_Error with
1822 "attempt to tamper with elements (list is locked)";
1825 pragma Assert (Vet (I), "bad I cursor in Swap");
1826 pragma Assert (Vet (J), "bad J cursor in Swap");
1829 EI : Element_Type renames Container.Nodes (I.Node).Element;
1830 EJ : Element_Type renames Container.Nodes (J.Node).Element;
1832 EI_Copy : constant Element_Type := EI;
1844 procedure Swap_Links
1845 (Container : in out List;
1850 raise Constraint_Error with "I cursor has no element";
1854 raise Constraint_Error with "J cursor has no element";
1857 if I.Container /= Container'Unrestricted_Access then
1858 raise Program_Error with "I cursor designates wrong container";
1861 if J.Container /= Container'Unrestricted_Access then
1862 raise Program_Error with "J cursor designates wrong container";
1865 if I.Node = J.Node then
1869 if Container.Busy > 0 then
1870 raise Program_Error with
1871 "attempt to tamper with cursors (list is busy)";
1874 pragma Assert (Vet (I), "bad I cursor in Swap_Links");
1875 pragma Assert (Vet (J), "bad J cursor in Swap_Links");
1878 I_Next : constant Cursor := Next (I);
1882 Splice (Container, Before => I, Position => J);
1886 J_Next : constant Cursor := Next (J);
1890 Splice (Container, Before => J, Position => I);
1893 pragma Assert (Container.Length >= 3);
1895 Splice (Container, Before => I_Next, Position => J);
1896 Splice (Container, Before => J_Next, Position => I);
1903 --------------------
1904 -- Update_Element --
1905 --------------------
1907 procedure Update_Element
1908 (Container : in out List;
1910 Process : not null access procedure (Element : in out Element_Type))
1913 if Position.Node = 0 then
1914 raise Constraint_Error with "Position cursor has no element";
1917 if Position.Container /= Container'Unchecked_Access then
1918 raise Program_Error with
1919 "Position cursor designates wrong container";
1922 pragma Assert (Vet (Position), "bad cursor in Update_Element");
1925 B : Natural renames Container.Busy;
1926 L : Natural renames Container.Lock;
1933 N : Node_Type renames Container.Nodes (Position.Node);
1935 Process (N.Element);
1952 function Vet (Position : Cursor) return Boolean is
1954 if Position.Node = 0 then
1955 return Position.Container = null;
1958 if Position.Container = null then
1963 L : List renames Position.Container.all;
1964 N : Node_Array renames L.Nodes;
1966 if L.Length = 0 then
1971 or L.First > L.Capacity
1977 or L.Last > L.Capacity
1982 if N (L.First).Prev /= 0 then
1986 if N (L.Last).Next /= 0 then
1990 if Position.Node > L.Capacity then
1994 if N (Position.Node).Prev < 0 then -- see Free
1998 if N (Position.Node).Prev > L.Capacity then
2002 if N (Position.Node).Next = Position.Node then
2006 if N (Position.Node).Prev = Position.Node then
2010 if N (Position.Node).Prev = 0
2011 and then Position.Node /= L.First
2016 -- If we get here, we know that this disjunction is true:
2017 -- N (Position.Node).Prev /= 0 or else Position.Node = L.First
2019 if N (Position.Node).Next = 0
2020 and then Position.Node /= L.Last
2025 -- If we get here, we know that this disjunction is true:
2026 -- N (Position.Node).Next /= 0 or else Position.Node = L.Last
2028 if L.Length = 1 then
2029 return L.First = L.Last;
2032 if L.First = L.Last then
2036 if N (L.First).Next = 0 then
2040 if N (L.Last).Prev = 0 then
2044 if N (N (L.First).Next).Prev /= L.First then
2048 if N (N (L.Last).Prev).Next /= L.Last then
2052 if L.Length = 2 then
2053 if N (L.First).Next /= L.Last then
2057 if N (L.Last).Prev /= L.First then
2064 if N (L.First).Next = L.Last then
2068 if N (L.Last).Prev = L.First then
2072 -- Eliminate earlier disjunct
2074 if Position.Node = L.First then
2078 -- If we get here, we know (disjunctive syllogism) that this
2079 -- predicate is true: N (Position.Node).Prev /= 0
2081 if Position.Node = L.Last then -- eliminates earlier disjunct
2085 -- If we get here, we know (disjunctive syllogism) that this
2086 -- predicate is true: N (Position.Node).Next /= 0
2088 if N (N (Position.Node).Next).Prev /= Position.Node then
2092 if N (N (Position.Node).Prev).Next /= Position.Node then
2096 if L.Length = 3 then
2097 if N (L.First).Next /= Position.Node then
2101 if N (L.Last).Prev /= Position.Node then
2115 (Stream : not null access Root_Stream_Type'Class;
2121 Count_Type'Base'Write (Stream, Item.Length);
2124 while Node /= 0 loop
2125 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2126 Node := Item.Nodes (Node).Next;
2131 (Stream : not null access Root_Stream_Type'Class;
2135 raise Program_Error with "attempt to stream list cursor";
2139 (Stream : not null access Root_Stream_Type'Class;
2140 Item : Reference_Type)
2143 raise Program_Error with "attempt to stream reference";
2147 (Stream : not null access Root_Stream_Type'Class;
2148 Item : Constant_Reference_Type)
2151 raise Program_Error with "attempt to stream reference";
2154 end Ada.Containers.Bounded_Doubly_Linked_Lists;