1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.BOUNDED_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2004-2013, 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 -----------------------
35 -- Local Subprograms --
36 -----------------------
39 (Container
: in out List
;
40 New_Item
: Element_Type
;
41 New_Node
: out Count_Type
);
44 (Container
: in out List
;
45 New_Node
: out Count_Type
);
48 (Container
: in out List
;
49 Stream
: not null access Root_Stream_Type
'Class;
50 New_Node
: out Count_Type
);
53 (Container
: in out List
;
56 procedure Insert_Internal
57 (Container
: in out List
;
59 New_Node
: Count_Type
);
61 procedure Splice_Internal
62 (Target
: in out List
;
64 Source
: in out List
);
66 procedure Splice_Internal
67 (Target
: in out List
;
71 Tgt_Pos
: out Count_Type
);
73 function Vet
(Position
: Cursor
) return Boolean;
74 -- Checks invariants of the cursor and its designated container, as a
75 -- simple way of detecting dangling references (see operation Free for a
76 -- description of the detection mechanism), returning True if all checks
77 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
78 -- so the checks are performed only when assertions are enabled.
84 function "=" (Left
, Right
: List
) return Boolean is
85 BL
: Natural renames Left
'Unrestricted_Access.Busy
;
86 LL
: Natural renames Left
'Unrestricted_Access.Lock
;
88 BR
: Natural renames Right
'Unrestricted_Access.Busy
;
89 LR
: Natural renames Right
'Unrestricted_Access.Lock
;
91 LN
: Node_Array
renames Left
.Nodes
;
92 RN
: Node_Array
renames Right
.Nodes
;
100 if Left
'Address = Right
'Address then
104 if Left
.Length
/= Right
.Length
then
108 -- Per AI05-0022, the container implementation is required to detect
109 -- element tampering by a generic actual subprogram.
120 for J
in 1 .. Left
.Length
loop
121 if LN
(LI
).Element
/= RN
(RI
).Element
then
154 (Container
: in out List
;
155 New_Item
: Element_Type
;
156 New_Node
: out Count_Type
)
158 N
: Node_Array
renames Container
.Nodes
;
161 if Container
.Free
>= 0 then
162 New_Node
:= Container
.Free
;
164 -- We always perform the assignment first, before we change container
165 -- state, in order to defend against exceptions duration assignment.
167 N
(New_Node
).Element
:= New_Item
;
168 Container
.Free
:= N
(New_Node
).Next
;
171 -- A negative free store value means that the links of the nodes in
172 -- the free store have not been initialized. In this case, the nodes
173 -- are physically contiguous in the array, starting at the index that
174 -- is the absolute value of the Container.Free, and continuing until
175 -- the end of the array (Nodes'Last).
177 New_Node
:= abs Container
.Free
;
179 -- As above, we perform this assignment first, before modifying any
182 N
(New_Node
).Element
:= New_Item
;
183 Container
.Free
:= Container
.Free
- 1;
188 (Container
: in out List
;
189 Stream
: not null access Root_Stream_Type
'Class;
190 New_Node
: out Count_Type
)
192 N
: Node_Array
renames Container
.Nodes
;
195 if Container
.Free
>= 0 then
196 New_Node
:= Container
.Free
;
198 -- We always perform the assignment first, before we change container
199 -- state, in order to defend against exceptions duration assignment.
201 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
202 Container
.Free
:= N
(New_Node
).Next
;
205 -- A negative free store value means that the links of the nodes in
206 -- the free store have not been initialized. In this case, the nodes
207 -- are physically contiguous in the array, starting at the index that
208 -- is the absolute value of the Container.Free, and continuing until
209 -- the end of the array (Nodes'Last).
211 New_Node
:= abs Container
.Free
;
213 -- As above, we perform this assignment first, before modifying any
216 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
217 Container
.Free
:= Container
.Free
- 1;
222 (Container
: in out List
;
223 New_Node
: out Count_Type
)
225 N
: Node_Array
renames Container
.Nodes
;
228 if Container
.Free
>= 0 then
229 New_Node
:= Container
.Free
;
230 Container
.Free
:= N
(New_Node
).Next
;
233 -- As explained above, a negative free store value means that the
234 -- links for the nodes in the free store have not been initialized.
236 New_Node
:= abs Container
.Free
;
237 Container
.Free
:= Container
.Free
- 1;
246 (Container
: in out List
;
247 New_Item
: Element_Type
;
248 Count
: Count_Type
:= 1)
251 Insert
(Container
, No_Element
, New_Item
, Count
);
258 procedure Assign
(Target
: in out List
; Source
: List
) is
259 SN
: Node_Array
renames Source
.Nodes
;
263 if Target
'Address = Source
'Address then
267 if Target
.Capacity
< Source
.Length
then
268 raise Capacity_Error
-- ???
269 with "Target capacity is less than Source length";
276 Target
.Append
(SN
(J
).Element
);
285 procedure Clear
(Container
: in out List
) is
286 N
: Node_Array
renames Container
.Nodes
;
290 if Container
.Length
= 0 then
291 pragma Assert
(Container
.First
= 0);
292 pragma Assert
(Container
.Last
= 0);
293 pragma Assert
(Container
.Busy
= 0);
294 pragma Assert
(Container
.Lock
= 0);
298 pragma Assert
(Container
.First
>= 1);
299 pragma Assert
(Container
.Last
>= 1);
300 pragma Assert
(N
(Container
.First
).Prev
= 0);
301 pragma Assert
(N
(Container
.Last
).Next
= 0);
303 if Container
.Busy
> 0 then
304 raise Program_Error
with
305 "attempt to tamper with cursors (list is busy)";
308 while Container
.Length
> 1 loop
309 X
:= Container
.First
;
310 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
312 Container
.First
:= N
(X
).Next
;
313 N
(Container
.First
).Prev
:= 0;
315 Container
.Length
:= Container
.Length
- 1;
320 X
:= Container
.First
;
321 pragma Assert
(X
= Container
.Last
);
323 Container
.First
:= 0;
325 Container
.Length
:= 0;
330 ------------------------
331 -- Constant_Reference --
332 ------------------------
334 function Constant_Reference
335 (Container
: aliased List
;
336 Position
: Cursor
) return Constant_Reference_Type
339 if Position
.Container
= null then
340 raise Constraint_Error
with "Position cursor has no element";
342 elsif Position
.Container
/= Container
'Unrestricted_Access then
343 raise Program_Error
with
344 "Position cursor designates wrong container";
347 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
350 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
352 return (Element
=> N
.Element
'Access);
355 end Constant_Reference
;
363 Item
: Element_Type
) return Boolean
366 return Find
(Container
, Item
) /= No_Element
;
373 function Copy
(Source
: List
; Capacity
: Count_Type
:= 0) return List
is
379 elsif Capacity
>= Source
.Length
then
382 raise Capacity_Error
with "Capacity value too small";
385 return Target
: List
(Capacity
=> C
) do
386 Assign
(Target
=> Target
, Source
=> Source
);
395 (Container
: in out List
;
396 Position
: in out Cursor
;
397 Count
: Count_Type
:= 1)
399 N
: Node_Array
renames Container
.Nodes
;
403 if Position
.Node
= 0 then
404 raise Constraint_Error
with
405 "Position cursor has no element";
408 if Position
.Container
/= Container
'Unrestricted_Access then
409 raise Program_Error
with
410 "Position cursor designates wrong container";
413 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
414 pragma Assert
(Container
.First
>= 1);
415 pragma Assert
(Container
.Last
>= 1);
416 pragma Assert
(N
(Container
.First
).Prev
= 0);
417 pragma Assert
(N
(Container
.Last
).Next
= 0);
419 if Position
.Node
= Container
.First
then
420 Delete_First
(Container
, Count
);
421 Position
:= No_Element
;
426 Position
:= No_Element
;
430 if Container
.Busy
> 0 then
431 raise Program_Error
with
432 "attempt to tamper with cursors (list is busy)";
435 for Index
in 1 .. Count
loop
436 pragma Assert
(Container
.Length
>= 2);
439 Container
.Length
:= Container
.Length
- 1;
441 if X
= Container
.Last
then
442 Position
:= No_Element
;
444 Container
.Last
:= N
(X
).Prev
;
445 N
(Container
.Last
).Next
:= 0;
451 Position
.Node
:= N
(X
).Next
;
453 N
(N
(X
).Next
).Prev
:= N
(X
).Prev
;
454 N
(N
(X
).Prev
).Next
:= N
(X
).Next
;
459 Position
:= No_Element
;
466 procedure Delete_First
467 (Container
: in out List
;
468 Count
: Count_Type
:= 1)
470 N
: Node_Array
renames Container
.Nodes
;
474 if Count
>= Container
.Length
then
483 if Container
.Busy
> 0 then
484 raise Program_Error
with
485 "attempt to tamper with cursors (list is busy)";
488 for J
in 1 .. Count
loop
489 X
:= Container
.First
;
490 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
492 Container
.First
:= N
(X
).Next
;
493 N
(Container
.First
).Prev
:= 0;
495 Container
.Length
:= Container
.Length
- 1;
505 procedure Delete_Last
506 (Container
: in out List
;
507 Count
: Count_Type
:= 1)
509 N
: Node_Array
renames Container
.Nodes
;
513 if Count
>= Container
.Length
then
522 if Container
.Busy
> 0 then
523 raise Program_Error
with
524 "attempt to tamper with cursors (list is busy)";
527 for J
in 1 .. Count
loop
529 pragma Assert
(N
(N
(X
).Prev
).Next
= Container
.Last
);
531 Container
.Last
:= N
(X
).Prev
;
532 N
(Container
.Last
).Next
:= 0;
534 Container
.Length
:= Container
.Length
- 1;
544 function Element
(Position
: Cursor
) return Element_Type
is
546 if Position
.Node
= 0 then
547 raise Constraint_Error
with
548 "Position cursor has no element";
551 pragma Assert
(Vet
(Position
), "bad cursor in Element");
553 return Position
.Container
.Nodes
(Position
.Node
).Element
;
561 procedure Finalize
(Object
: in out Iterator
) is
563 if Object
.Container
/= null then
565 B
: Natural renames Object
.Container
.all.Busy
;
579 Position
: Cursor
:= No_Element
) return Cursor
581 Nodes
: Node_Array
renames Container
.Nodes
;
582 Node
: Count_Type
:= Position
.Node
;
586 Node
:= Container
.First
;
589 if Position
.Container
/= Container
'Unrestricted_Access then
590 raise Program_Error
with
591 "Position cursor designates wrong container";
594 pragma Assert
(Vet
(Position
), "bad cursor in Find");
597 -- Per AI05-0022, the container implementation is required to detect
598 -- element tampering by a generic actual subprogram.
601 B
: Natural renames Container
'Unrestricted_Access.Busy
;
602 L
: Natural renames Container
'Unrestricted_Access.Lock
;
612 if Nodes
(Node
).Element
= Item
then
617 Node
:= Nodes
(Node
).Next
;
626 return Cursor
'(Container'Unrestricted_Access, Result);
641 function First (Container : List) return Cursor is
643 if Container.First = 0 then
646 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
650 function First
(Object
: Iterator
) return Cursor
is
652 -- The value of the iterator object's Node component influences the
653 -- behavior of the First (and Last) selector function.
655 -- When the Node component is 0, this means the iterator object was
656 -- constructed without a start expression, in which case the (forward)
657 -- iteration starts from the (logical) beginning of the entire sequence
658 -- of items (corresponding to Container.First, for a forward iterator).
660 -- Otherwise, this is iteration over a partial sequence of items. When
661 -- the Node component is positive, the iterator object was constructed
662 -- with a start expression, that specifies the position from which the
663 -- (forward) partial iteration begins.
665 if Object
.Node
= 0 then
666 return Bounded_Doubly_Linked_Lists
.First
(Object
.Container
.all);
668 return Cursor
'(Object.Container, Object.Node);
676 function First_Element (Container : List) return Element_Type is
678 if Container.First = 0 then
679 raise Constraint_Error with "list is empty";
681 return Container.Nodes (Container.First).Element;
690 (Container : in out List;
693 pragma Assert (X > 0);
694 pragma Assert (X <= Container.Capacity);
696 N : Node_Array renames Container.Nodes;
697 pragma Assert (N (X).Prev >= 0); -- node is active
700 -- The list container actually contains two lists: one for the "active"
701 -- nodes that contain elements that have been inserted onto the list,
702 -- and another for the "inactive" nodes for the free store.
704 -- We desire that merely declaring an object should have only minimal
705 -- cost; specially, we want to avoid having to initialize the free
706 -- store (to fill in the links), especially if the capacity is large.
708 -- The head of the free list is indicated by Container.Free. If its
709 -- value is non-negative, then the free store has been initialized in
710 -- the "normal" way: Container.Free points to the head of the list of
711 -- free (inactive) nodes, and the value 0 means the free list is empty.
712 -- Each node on the free list has been initialized to point to the next
713 -- free node (via its Next component), and the value 0 means that this
714 -- is the last free node.
716 -- If Container.Free is negative, then the links on the free store have
717 -- not been initialized. In this case the link values are implied: the
718 -- free store comprises the components of the node array started with
719 -- the absolute value of Container.Free, and continuing until the end of
720 -- the array (Nodes'Last).
722 -- If the list container is manipulated on one end only (for example if
723 -- the container were being used as a stack), then there is no need to
724 -- initialize the free store, since the inactive nodes are physically
725 -- contiguous (in fact, they lie immediately beyond the logical end
726 -- being manipulated). The only time we need to actually initialize the
727 -- nodes in the free store is if the node that becomes inactive is not
728 -- at the end of the list. The free store would then be discontiguous
729 -- and so its nodes would need to be linked in the traditional way.
732 -- It might be possible to perform an optimization here. Suppose that
733 -- the free store can be represented as having two parts: one comprising
734 -- the non-contiguous inactive nodes linked together in the normal way,
735 -- and the other comprising the contiguous inactive nodes (that are not
736 -- linked together, at the end of the nodes array). This would allow us
737 -- to never have to initialize the free store, except in a lazy way as
738 -- nodes become inactive.
740 -- When an element is deleted from the list container, its node becomes
741 -- inactive, and so we set its Prev component to a negative value, to
742 -- indicate that it is now inactive. This provides a useful way to
743 -- detect a dangling cursor reference (and which is used in Vet).
745 N (X).Prev := -1; -- Node is deallocated (not on active list)
747 if Container.Free >= 0 then
749 -- The free store has previously been initialized. All we need to
750 -- do here is link the newly-free'd node onto the free list.
752 N (X).Next := Container.Free;
755 elsif X + 1 = abs Container.Free then
757 -- The free store has not been initialized, and the node becoming
758 -- inactive immediately precedes the start of the free store. All
759 -- we need to do is move the start of the free store back by one.
761 -- Note: initializing Next to zero is not strictly necessary but
762 -- seems cleaner and marginally safer.
765 Container.Free := Container.Free + 1;
768 -- The free store has not been initialized, and the node becoming
769 -- inactive does not immediately precede the free store. Here we
770 -- first initialize the free store (meaning the links are given
771 -- values in the traditional way), and then link the newly-free'd
772 -- node onto the head of the free store.
775 -- See the comments above for an optimization opportunity. If the
776 -- next link for a node on the free store is negative, then this
777 -- means the remaining nodes on the free store are physically
778 -- contiguous, starting as the absolute value of that index value.
780 Container.Free := abs Container.Free;
782 if Container.Free > Container.Capacity then
786 for I in Container.Free .. Container.Capacity - 1 loop
790 N (Container.Capacity).Next := 0;
793 N (X).Next := Container.Free;
798 ---------------------
799 -- Generic_Sorting --
800 ---------------------
802 package body Generic_Sorting is
808 function Is_Sorted (Container : List) return Boolean is
809 B : Natural renames Container'Unrestricted_Access.Busy;
810 L : Natural renames Container'Unrestricted_Access.Lock;
812 Nodes : Node_Array renames Container.Nodes;
818 -- Per AI05-0022, the container implementation is required to detect
819 -- element tampering by a generic actual subprogram.
824 Node := Container.First;
826 for J in 2 .. Container.Length loop
827 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
832 Node := Nodes (Node).Next;
852 (Target : in out List;
853 Source : in out List)
856 -- The semantics of Merge changed slightly per AI05-0021. It was
857 -- originally the case that if Target and Source denoted the same
858 -- container object, then the GNAT implementation of Merge did
859 -- nothing. However, it was argued that RM05 did not precisely
860 -- specify the semantics for this corner case. The decision of the
861 -- ARG was that if Target and Source denote the same non-empty
862 -- container object, then Program_Error is raised.
864 if Source.Is_Empty then
868 if Target'Address = Source'Address then
869 raise Program_Error with
870 "Target and Source denote same non-empty container";
873 if Target.Length > Count_Type'Last - Source.Length then
874 raise Constraint_Error with "new length exceeds maximum";
877 if Target.Length + Source.Length > Target.Capacity then
878 raise Capacity_Error with "new length exceeds target capacity";
881 if Target.Busy > 0 then
882 raise Program_Error with
883 "attempt to tamper with cursors of Target (list is busy)";
886 if Source.Busy > 0 then
887 raise Program_Error with
888 "attempt to tamper with cursors of Source (list is busy)";
891 -- Per AI05-0022, the container implementation is required to detect
892 -- element tampering by a generic actual subprogram.
895 TB : Natural renames Target.Busy;
896 TL : Natural renames Target.Lock;
898 SB : Natural renames Source.Busy;
899 SL : Natural renames Source.Lock;
901 LN : Node_Array renames Target.Nodes;
902 RN : Node_Array renames Source.Nodes;
904 LI, LJ, RI, RJ : Count_Type;
916 pragma Assert (RN (RI).Next = 0
917 or else not (RN (RN (RI).Next).Element <
921 Splice_Internal (Target, 0, Source);
925 pragma Assert (LN (LI).Next = 0
926 or else not (LN (LN (LI).Next).Element <
929 if RN (RI).Element < LN (LI).Element then
932 Splice_Internal (Target, LI, Source, RJ, LJ);
961 procedure Sort (Container : in out List) is
962 N : Node_Array renames Container.Nodes;
964 procedure Partition (Pivot, Back : Count_Type);
965 -- What does this do ???
967 procedure Sort (Front, Back : Count_Type);
968 -- Internal procedure, what does it do??? rename it???
974 procedure Partition (Pivot, Back : Count_Type) is
978 Node := N (Pivot).Next;
979 while Node /= Back loop
980 if N (Node).Element < N (Pivot).Element then
982 Prev : constant Count_Type := N (Node).Prev;
983 Next : constant Count_Type := N (Node).Next;
986 N (Prev).Next := Next;
989 Container.Last := Prev;
991 N (Next).Prev := Prev;
994 N (Node).Next := Pivot;
995 N (Node).Prev := N (Pivot).Prev;
997 N (Pivot).Prev := Node;
999 if N (Node).Prev = 0 then
1000 Container.First := Node;
1002 N (N (Node).Prev).Next := Node;
1009 Node := N (Node).Next;
1018 procedure Sort (Front, Back : Count_Type) is
1019 Pivot : constant Count_Type :=
1020 (if Front = 0 then Container.First else N (Front).Next);
1022 if Pivot /= Back then
1023 Partition (Pivot, Back);
1024 Sort (Front, Pivot);
1029 -- Start of processing for Sort
1032 if Container.Length <= 1 then
1036 pragma Assert (N (Container.First).Prev = 0);
1037 pragma Assert (N (Container.Last).Next = 0);
1039 if Container.Busy > 0 then
1040 raise Program_Error with
1041 "attempt to tamper with cursors (list is busy)";
1044 -- Per AI05-0022, the container implementation is required to detect
1045 -- element tampering by a generic actual subprogram.
1048 B : Natural renames Container.Busy;
1049 L : Natural renames Container.Lock;
1055 Sort (Front => 0, Back => 0);
1067 pragma Assert (N (Container.First).Prev = 0);
1068 pragma Assert (N (Container.Last).Next = 0);
1071 end Generic_Sorting;
1077 function Has_Element (Position : Cursor) return Boolean is
1079 pragma Assert (Vet (Position), "bad cursor in Has_Element");
1080 return Position.Node /= 0;
1088 (Container : in out List;
1090 New_Item : Element_Type;
1091 Position : out Cursor;
1092 Count : Count_Type := 1)
1094 New_Node : Count_Type;
1097 if Before.Container /= null then
1098 if Before.Container /= Container'Unrestricted_Access then
1099 raise Program_Error with
1100 "Before cursor designates wrong list";
1103 pragma Assert (Vet (Before), "bad cursor in Insert");
1111 if Container.Length > Container.Capacity - Count then
1112 raise Constraint_Error with "new length exceeds capacity";
1115 if Container.Busy > 0 then
1116 raise Program_Error with
1117 "attempt to tamper with cursors (list is busy)";
1120 Allocate (Container, New_Item, New_Node);
1121 Insert_Internal (Container, Before.Node, New_Node => New_Node);
1122 Position := Cursor'(Container
'Unchecked_Access, Node
=> New_Node
);
1124 for Index
in Count_Type
'(2) .. Count loop
1125 Allocate (Container, New_Item, New_Node => New_Node);
1126 Insert_Internal (Container, Before.Node, New_Node => New_Node);
1131 (Container : in out List;
1133 New_Item : Element_Type;
1134 Count : Count_Type := 1)
1137 pragma Unreferenced (Position);
1139 Insert (Container, Before, New_Item, Position, Count);
1143 (Container : in out List;
1145 Position : out Cursor;
1146 Count : Count_Type := 1)
1148 New_Node : Count_Type;
1151 if Before.Container /= null then
1152 if Before.Container /= Container'Unrestricted_Access then
1153 raise Program_Error with
1154 "Before cursor designates wrong list";
1157 pragma Assert (Vet (Before), "bad cursor in Insert");
1165 if Container.Length > Container.Capacity - Count then
1166 raise Constraint_Error with "new length exceeds capacity";
1169 if Container.Busy > 0 then
1170 raise Program_Error with
1171 "attempt to tamper with cursors (list is busy)";
1174 Allocate (Container, New_Node => New_Node);
1175 Insert_Internal (Container, Before.Node, New_Node);
1176 Position := Cursor'(Container
'Unchecked_Access, New_Node
);
1178 for Index
in Count_Type
'(2) .. Count loop
1179 Allocate (Container, New_Node => New_Node);
1180 Insert_Internal (Container, Before.Node, New_Node);
1184 ---------------------
1185 -- Insert_Internal --
1186 ---------------------
1188 procedure Insert_Internal
1189 (Container : in out List;
1190 Before : Count_Type;
1191 New_Node : Count_Type)
1193 N : Node_Array renames Container.Nodes;
1196 if Container.Length = 0 then
1197 pragma Assert (Before = 0);
1198 pragma Assert (Container.First = 0);
1199 pragma Assert (Container.Last = 0);
1201 Container.First := New_Node;
1202 N (Container.First).Prev := 0;
1204 Container.Last := New_Node;
1205 N (Container.Last).Next := 0;
1207 -- Before = zero means append
1209 elsif Before = 0 then
1210 pragma Assert (N (Container.Last).Next = 0);
1212 N (Container.Last).Next := New_Node;
1213 N (New_Node).Prev := Container.Last;
1215 Container.Last := New_Node;
1216 N (Container.Last).Next := 0;
1218 -- Before = Container.First means prepend
1220 elsif Before = Container.First then
1221 pragma Assert (N (Container.First).Prev = 0);
1223 N (Container.First).Prev := New_Node;
1224 N (New_Node).Next := Container.First;
1226 Container.First := New_Node;
1227 N (Container.First).Prev := 0;
1230 pragma Assert (N (Container.First).Prev = 0);
1231 pragma Assert (N (Container.Last).Next = 0);
1233 N (New_Node).Next := Before;
1234 N (New_Node).Prev := N (Before).Prev;
1236 N (N (Before).Prev).Next := New_Node;
1237 N (Before).Prev := New_Node;
1240 Container.Length := Container.Length + 1;
1241 end Insert_Internal;
1247 function Is_Empty (Container : List) return Boolean is
1249 return Container.Length = 0;
1258 Process : not null access procedure (Position : Cursor))
1260 B : Natural renames Container'Unrestricted_Access.all.Busy;
1261 Node : Count_Type := Container.First;
1267 while Node /= 0 loop
1268 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1269 Node
:= Container
.Nodes
(Node
).Next
;
1282 return List_Iterator_Interfaces
.Reversible_Iterator
'Class
1284 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1287 -- The value of the Node component influences the behavior of the First
1288 -- and Last selector functions of the iterator object. When the Node
1289 -- component is 0 (as is the case here), this means the iterator
1290 -- object was constructed without a start expression. This is a
1291 -- complete iterator, meaning that the iteration starts from the
1292 -- (logical) beginning of the sequence of items.
1294 -- Note: For a forward iterator, Container.First is the beginning, and
1295 -- for a reverse iterator, Container.Last is the beginning.
1297 return It
: constant Iterator
:=
1298 Iterator
'(Limited_Controlled with
1299 Container => Container'Unrestricted_Access,
1309 return List_Iterator_Interfaces.Reversible_Iterator'class
1311 B : Natural renames Container'Unrestricted_Access.all.Busy;
1314 -- It was formerly the case that when Start = No_Element, the partial
1315 -- iterator was defined to behave the same as for a complete iterator,
1316 -- and iterate over the entire sequence of items. However, those
1317 -- semantics were unintuitive and arguably error-prone (it is too easy
1318 -- to accidentally create an endless loop), and so they were changed,
1319 -- per the ARG meeting in Denver on 2011/11. However, there was no
1320 -- consensus about what positive meaning this corner case should have,
1321 -- and so it was decided to simply raise an exception. This does imply,
1322 -- however, that it is not possible to use a partial iterator to specify
1323 -- an empty sequence of items.
1325 if Start = No_Element then
1326 raise Constraint_Error with
1327 "Start position for iterator equals No_Element";
1330 if Start.Container /= Container'Unrestricted_Access then
1331 raise Program_Error with
1332 "Start cursor of Iterate designates wrong list";
1335 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1337 -- The value of the Node component influences the behavior of the First
1338 -- and Last selector functions of the iterator object. When the Node
1339 -- component is positive (as is the case here), it means that this
1340 -- is a partial iteration, over a subset of the complete sequence of
1341 -- items. The iterator object was constructed with a start expression,
1342 -- indicating the position from which the iteration begins. Note that
1343 -- the start position has the same value irrespective of whether this
1344 -- is a forward or reverse iteration.
1346 return It : constant Iterator :=
1347 Iterator'(Limited_Controlled
with
1348 Container
=> Container
'Unrestricted_Access,
1359 function Last
(Container
: List
) return Cursor
is
1361 if Container
.Last
= 0 then
1364 return Cursor
'(Container'Unrestricted_Access, Container.Last);
1368 function Last (Object : Iterator) return Cursor is
1370 -- The value of the iterator object's Node component influences the
1371 -- behavior of the Last (and First) selector function.
1373 -- When the Node component is 0, this means the iterator object was
1374 -- constructed without a start expression, in which case the (reverse)
1375 -- iteration starts from the (logical) beginning of the entire sequence
1376 -- (corresponding to Container.Last, for a reverse iterator).
1378 -- Otherwise, this is iteration over a partial sequence of items. When
1379 -- the Node component is positive, the iterator object was constructed
1380 -- with a start expression, that specifies the position from which the
1381 -- (reverse) partial iteration begins.
1383 if Object.Node = 0 then
1384 return Bounded_Doubly_Linked_Lists.Last (Object.Container.all);
1386 return Cursor'(Object
.Container
, Object
.Node
);
1394 function Last_Element
(Container
: List
) return Element_Type
is
1396 if Container
.Last
= 0 then
1397 raise Constraint_Error
with "list is empty";
1399 return Container
.Nodes
(Container
.Last
).Element
;
1407 function Length
(Container
: List
) return Count_Type
is
1409 return Container
.Length
;
1417 (Target
: in out List
;
1418 Source
: in out List
)
1420 N
: Node_Array
renames Source
.Nodes
;
1424 if Target
'Address = Source
'Address then
1428 if Target
.Capacity
< Source
.Length
then
1429 raise Capacity_Error
with "Source length exceeds Target capacity";
1432 if Source
.Busy
> 0 then
1433 raise Program_Error
with
1434 "attempt to tamper with cursors of Source (list is busy)";
1437 -- Clear target, note that this checks busy bits of Target
1441 while Source
.Length
> 1 loop
1442 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1443 pragma Assert
(Source
.Last
/= Source
.First
);
1444 pragma Assert
(N
(Source
.First
).Prev
= 0);
1445 pragma Assert
(N
(Source
.Last
).Next
= 0);
1447 -- Copy first element from Source to Target
1450 Append
(Target
, N
(X
).Element
);
1452 -- Unlink first node of Source
1454 Source
.First
:= N
(X
).Next
;
1455 N
(Source
.First
).Prev
:= 0;
1457 Source
.Length
:= Source
.Length
- 1;
1459 -- The representation invariants for Source have been restored. It is
1460 -- now safe to free the unlinked node, without fear of corrupting the
1461 -- active links of Source.
1463 -- Note that the algorithm we use here models similar algorithms used
1464 -- in the unbounded form of the doubly-linked list container. In that
1465 -- case, Free is an instantation of Unchecked_Deallocation, which can
1466 -- fail (because PE will be raised if controlled Finalize fails), so
1467 -- we must defer the call until the last step. Here in the bounded
1468 -- form, Free merely links the node we have just "deallocated" onto a
1469 -- list of inactive nodes, so technically Free cannot fail. However,
1470 -- for consistency, we handle Free the same way here as we do for the
1471 -- unbounded form, with the pessimistic assumption that it can fail.
1476 if Source
.Length
= 1 then
1477 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1478 pragma Assert
(Source
.Last
= Source
.First
);
1479 pragma Assert
(N
(Source
.First
).Prev
= 0);
1480 pragma Assert
(N
(Source
.Last
).Next
= 0);
1482 -- Copy element from Source to Target
1485 Append
(Target
, N
(X
).Element
);
1487 -- Unlink node of Source
1493 -- Return the unlinked node to the free store
1503 procedure Next
(Position
: in out Cursor
) is
1505 Position
:= Next
(Position
);
1508 function Next
(Position
: Cursor
) return Cursor
is
1510 if Position
.Node
= 0 then
1514 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1517 Nodes
: Node_Array
renames Position
.Container
.Nodes
;
1518 Node
: constant Count_Type
:= Nodes
(Position
.Node
).Next
;
1523 return Cursor
'(Position.Container, Node);
1530 Position : Cursor) return Cursor
1533 if Position.Container = null then
1535 elsif Position.Container /= Object.Container then
1536 raise Program_Error with
1537 "Position cursor of Next designates wrong list";
1539 return Next (Position);
1548 (Container : in out List;
1549 New_Item : Element_Type;
1550 Count : Count_Type := 1)
1553 Insert (Container, First (Container), New_Item, Count);
1560 procedure Previous (Position : in out Cursor) is
1562 Position := Previous (Position);
1565 function Previous (Position : Cursor) return Cursor is
1567 if Position.Node = 0 then
1571 pragma Assert (Vet (Position), "bad cursor in Previous");
1574 Nodes : Node_Array renames Position.Container.Nodes;
1575 Node : constant Count_Type := Nodes (Position.Node).Prev;
1580 return Cursor'(Position
.Container
, Node
);
1587 Position
: Cursor
) return Cursor
1590 if Position
.Container
= null then
1592 elsif Position
.Container
/= Object
.Container
then
1593 raise Program_Error
with
1594 "Position cursor of Previous designates wrong list";
1596 return Previous
(Position
);
1604 procedure Query_Element
1606 Process
: not null access procedure (Element
: Element_Type
))
1609 if Position
.Node
= 0 then
1610 raise Constraint_Error
with
1611 "Position cursor has no element";
1614 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1617 C
: List
renames Position
.Container
.all'Unrestricted_Access.all;
1618 B
: Natural renames C
.Busy
;
1619 L
: Natural renames C
.Lock
;
1626 N
: Node_Type
renames C
.Nodes
(Position
.Node
);
1628 Process
(N
.Element
);
1646 (Stream
: not null access Root_Stream_Type
'Class;
1649 N
: Count_Type
'Base;
1654 Count_Type
'Base'Read (Stream, N);
1657 raise Program_Error with "bad list length (corrupt stream)";
1662 elsif N > Item.Capacity then
1663 raise Constraint_Error with "length exceeds capacity";
1666 for Idx in 1 .. N loop
1667 Allocate (Item, Stream, New_Node => X);
1668 Insert_Internal (Item, Before => 0, New_Node => X);
1674 (Stream : not null access Root_Stream_Type'Class;
1678 raise Program_Error with "attempt to stream list cursor";
1682 (Stream : not null access Root_Stream_Type'Class;
1683 Item : out Reference_Type)
1686 raise Program_Error with "attempt to stream reference";
1690 (Stream : not null access Root_Stream_Type'Class;
1691 Item : out Constant_Reference_Type)
1694 raise Program_Error with "attempt to stream reference";
1702 (Container : aliased in out List;
1703 Position : Cursor) return Reference_Type
1706 if Position.Container = null then
1707 raise Constraint_Error with "Position cursor has no element";
1709 elsif Position.Container /= Container'Unrestricted_Access then
1710 raise Program_Error with
1711 "Position cursor designates wrong container";
1714 pragma Assert (Vet (Position), "bad cursor in function Reference");
1717 N : Node_Type renames Container.Nodes (Position.Node);
1719 return (Element => N.Element'Access);
1724 ---------------------
1725 -- Replace_Element --
1726 ---------------------
1728 procedure Replace_Element
1729 (Container : in out List;
1731 New_Item : Element_Type)
1734 if Position.Container = null then
1735 raise Constraint_Error with "Position cursor has no element";
1737 elsif Position.Container /= Container'Unchecked_Access then
1738 raise Program_Error with
1739 "Position cursor designates wrong container";
1741 elsif Container.Lock > 0 then
1742 raise Program_Error with
1743 "attempt to tamper with elements (list is locked)";
1746 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1748 Container.Nodes (Position.Node).Element := New_Item;
1750 end Replace_Element;
1752 ----------------------
1753 -- Reverse_Elements --
1754 ----------------------
1756 procedure Reverse_Elements (Container : in out List) is
1757 N : Node_Array renames Container.Nodes;
1758 I : Count_Type := Container.First;
1759 J : Count_Type := Container.Last;
1761 procedure Swap (L, R : Count_Type);
1767 procedure Swap (L, R : Count_Type) is
1768 LN : constant Count_Type := N (L).Next;
1769 LP : constant Count_Type := N (L).Prev;
1771 RN : constant Count_Type := N (R).Next;
1772 RP : constant Count_Type := N (R).Prev;
1787 pragma Assert (RP = L);
1801 -- Start of processing for Reverse_Elements
1804 if Container.Length <= 1 then
1808 pragma Assert (N (Container.First).Prev = 0);
1809 pragma Assert (N (Container.Last).Next = 0);
1811 if Container.Busy > 0 then
1812 raise Program_Error with
1813 "attempt to tamper with cursors (list is busy)";
1816 Container.First := J;
1817 Container.Last := I;
1819 Swap (L => I, R => J);
1827 Swap (L => J, R => I);
1836 pragma Assert (N (Container.First).Prev = 0);
1837 pragma Assert (N (Container.Last).Next = 0);
1838 end Reverse_Elements;
1844 function Reverse_Find
1846 Item : Element_Type;
1847 Position : Cursor := No_Element) return Cursor
1849 Node : Count_Type := Position.Node;
1853 Node := Container.Last;
1856 if Position.Container /= Container'Unrestricted_Access then
1857 raise Program_Error with
1858 "Position cursor designates wrong container";
1861 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1864 -- Per AI05-0022, the container implementation is required to detect
1865 -- element tampering by a generic actual subprogram.
1868 B : Natural renames Container'Unrestricted_Access.Busy;
1869 L : Natural renames Container'Unrestricted_Access.Lock;
1871 Result : Count_Type;
1878 while Node /= 0 loop
1879 if Container.Nodes (Node).Element = Item then
1884 Node := Container.Nodes (Node).Prev;
1893 return Cursor'(Container
'Unrestricted_Access, Result
);
1904 ---------------------
1905 -- Reverse_Iterate --
1906 ---------------------
1908 procedure Reverse_Iterate
1910 Process
: not null access procedure (Position
: Cursor
))
1912 C
: List
renames Container
'Unrestricted_Access.all;
1913 B
: Natural renames C
.Busy
;
1915 Node
: Count_Type
:= Container
.Last
;
1921 while Node
/= 0 loop
1922 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1923 Node := Container.Nodes (Node).Prev;
1932 end Reverse_Iterate;
1939 (Target : in out List;
1941 Source : in out List)
1944 if Before.Container /= null then
1945 if Before.Container /= Target'Unrestricted_Access then
1946 raise Program_Error with
1947 "Before cursor designates wrong container";
1950 pragma Assert (Vet (Before), "bad cursor in Splice");
1953 if Target'Address = Source'Address or else Source.Length = 0 then
1956 elsif Target.Length > Count_Type'Last - Source.Length then
1957 raise Constraint_Error with "new length exceeds maximum";
1959 elsif Target.Length + Source.Length > Target.Capacity then
1960 raise Capacity_Error with "new length exceeds target capacity";
1962 elsif Target.Busy > 0 then
1963 raise Program_Error with
1964 "attempt to tamper with cursors of Target (list is busy)";
1966 elsif Source.Busy > 0 then
1967 raise Program_Error with
1968 "attempt to tamper with cursors of Source (list is busy)";
1971 Splice_Internal (Target, Before.Node, Source);
1976 (Container : in out List;
1980 N : Node_Array renames Container.Nodes;
1983 if Before.Container /= null then
1984 if Before.Container /= Container'Unchecked_Access then
1985 raise Program_Error with
1986 "Before cursor designates wrong container";
1989 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1992 if Position.Node = 0 then
1993 raise Constraint_Error with "Position cursor has no element";
1996 if Position.Container /= Container'Unrestricted_Access then
1997 raise Program_Error with
1998 "Position cursor designates wrong container";
2001 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2003 if Position.Node = Before.Node
2004 or else N (Position.Node).Next = Before.Node
2009 pragma Assert (Container.Length >= 2);
2011 if Container.Busy > 0 then
2012 raise Program_Error with
2013 "attempt to tamper with cursors (list is busy)";
2016 if Before.Node = 0 then
2017 pragma Assert (Position.Node /= Container.Last);
2019 if Position.Node = Container.First then
2020 Container.First := N (Position.Node).Next;
2021 N (Container.First).Prev := 0;
2023 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2024 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2027 N (Container.Last).Next := Position.Node;
2028 N (Position.Node).Prev := Container.Last;
2030 Container.Last := Position.Node;
2031 N (Container.Last).Next := 0;
2036 if Before.Node = Container.First then
2037 pragma Assert (Position.Node /= Container.First);
2039 if Position.Node = Container.Last then
2040 Container.Last := N (Position.Node).Prev;
2041 N (Container.Last).Next := 0;
2043 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2044 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2047 N (Container.First).Prev := Position.Node;
2048 N (Position.Node).Next := Container.First;
2050 Container.First := Position.Node;
2051 N (Container.First).Prev := 0;
2056 if Position.Node = Container.First then
2057 Container.First := N (Position.Node).Next;
2058 N (Container.First).Prev := 0;
2060 elsif Position.Node = Container.Last then
2061 Container.Last := N (Position.Node).Prev;
2062 N (Container.Last).Next := 0;
2065 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2066 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2069 N (N (Before.Node).Prev).Next := Position.Node;
2070 N (Position.Node).Prev := N (Before.Node).Prev;
2072 N (Before.Node).Prev := Position.Node;
2073 N (Position.Node).Next := Before.Node;
2075 pragma Assert (N (Container.First).Prev = 0);
2076 pragma Assert (N (Container.Last).Next = 0);
2080 (Target : in out List;
2082 Source : in out List;
2083 Position : in out Cursor)
2085 Target_Position : Count_Type;
2088 if Target'Address = Source'Address then
2089 Splice (Target, Before, Position);
2093 if Before.Container /= null then
2094 if Before.Container /= Target'Unrestricted_Access then
2095 raise Program_Error with
2096 "Before cursor designates wrong container";
2099 pragma Assert (Vet (Before), "bad Before cursor in Splice");
2102 if Position.Node = 0 then
2103 raise Constraint_Error with "Position cursor has no element";
2106 if Position.Container /= Source'Unrestricted_Access then
2107 raise Program_Error with
2108 "Position cursor designates wrong container";
2111 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2113 if Target.Length >= Target.Capacity then
2114 raise Capacity_Error with "Target is full";
2117 if Target.Busy > 0 then
2118 raise Program_Error with
2119 "attempt to tamper with cursors of Target (list is busy)";
2122 if Source.Busy > 0 then
2123 raise Program_Error with
2124 "attempt to tamper with cursors of Source (list is busy)";
2129 Before => Before.Node,
2131 Src_Pos => Position.Node,
2132 Tgt_Pos => Target_Position);
2134 Position := Cursor'(Target
'Unrestricted_Access, Target_Position
);
2137 ---------------------
2138 -- Splice_Internal --
2139 ---------------------
2141 procedure Splice_Internal
2142 (Target
: in out List
;
2143 Before
: Count_Type
;
2144 Source
: in out List
)
2146 N
: Node_Array
renames Source
.Nodes
;
2150 -- This implements the corresponding Splice operation, after the
2151 -- parameters have been vetted, and corner-cases disposed of.
2153 pragma Assert
(Target
'Address /= Source
'Address);
2154 pragma Assert
(Source
.Length
> 0);
2155 pragma Assert
(Source
.First
/= 0);
2156 pragma Assert
(N
(Source
.First
).Prev
= 0);
2157 pragma Assert
(Source
.Last
/= 0);
2158 pragma Assert
(N
(Source
.Last
).Next
= 0);
2159 pragma Assert
(Target
.Length
<= Count_Type
'Last - Source
.Length
);
2160 pragma Assert
(Target
.Length
+ Source
.Length
<= Target
.Capacity
);
2162 while Source
.Length
> 1 loop
2163 -- Copy first element of Source onto Target
2165 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2166 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2168 -- Unlink the first node from Source
2171 pragma Assert
(N
(N
(X
).Next
).Prev
= X
);
2173 Source
.First
:= N
(X
).Next
;
2174 N
(Source
.First
).Prev
:= 0;
2176 Source
.Length
:= Source
.Length
- 1;
2178 -- Return the Source node to its free store
2183 -- Copy first (and only remaining) element of Source onto Target
2185 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2186 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2188 -- Unlink the node from Source
2191 pragma Assert
(X
= Source
.Last
);
2198 -- Return the Source node to its free store
2201 end Splice_Internal
;
2203 procedure Splice_Internal
2204 (Target
: in out List
;
2205 Before
: Count_Type
; -- node of Target
2206 Source
: in out List
;
2207 Src_Pos
: Count_Type
; -- node of Source
2208 Tgt_Pos
: out Count_Type
)
2210 N
: Node_Array
renames Source
.Nodes
;
2213 -- This implements the corresponding Splice operation, after the
2214 -- parameters have been vetted, and corner-cases handled.
2216 pragma Assert
(Target
'Address /= Source
'Address);
2217 pragma Assert
(Target
.Length
< Target
.Capacity
);
2218 pragma Assert
(Source
.Length
> 0);
2219 pragma Assert
(Source
.First
/= 0);
2220 pragma Assert
(N
(Source
.First
).Prev
= 0);
2221 pragma Assert
(Source
.Last
/= 0);
2222 pragma Assert
(N
(Source
.Last
).Next
= 0);
2223 pragma Assert
(Src_Pos
/= 0);
2225 Allocate
(Target
, N
(Src_Pos
).Element
, New_Node
=> Tgt_Pos
);
2226 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> Tgt_Pos
);
2228 if Source
.Length
= 1 then
2229 pragma Assert
(Source
.First
= Source
.Last
);
2230 pragma Assert
(Src_Pos
= Source
.First
);
2235 elsif Src_Pos
= Source
.First
then
2236 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2238 Source
.First
:= N
(Src_Pos
).Next
;
2239 N
(Source
.First
).Prev
:= 0;
2241 elsif Src_Pos
= Source
.Last
then
2242 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2244 Source
.Last
:= N
(Src_Pos
).Prev
;
2245 N
(Source
.Last
).Next
:= 0;
2248 pragma Assert
(Source
.Length
>= 3);
2249 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2250 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2252 N
(N
(Src_Pos
).Next
).Prev
:= N
(Src_Pos
).Prev
;
2253 N
(N
(Src_Pos
).Prev
).Next
:= N
(Src_Pos
).Next
;
2256 Source
.Length
:= Source
.Length
- 1;
2257 Free
(Source
, Src_Pos
);
2258 end Splice_Internal
;
2265 (Container
: in out List
;
2270 raise Constraint_Error
with "I cursor has no element";
2274 raise Constraint_Error
with "J cursor has no element";
2277 if I
.Container
/= Container
'Unchecked_Access then
2278 raise Program_Error
with "I cursor designates wrong container";
2281 if J
.Container
/= Container
'Unchecked_Access then
2282 raise Program_Error
with "J cursor designates wrong container";
2285 if I
.Node
= J
.Node
then
2289 if Container
.Lock
> 0 then
2290 raise Program_Error
with
2291 "attempt to tamper with elements (list is locked)";
2294 pragma Assert
(Vet
(I
), "bad I cursor in Swap");
2295 pragma Assert
(Vet
(J
), "bad J cursor in Swap");
2298 EI
: Element_Type
renames Container
.Nodes
(I
.Node
).Element
;
2299 EJ
: Element_Type
renames Container
.Nodes
(J
.Node
).Element
;
2301 EI_Copy
: constant Element_Type
:= EI
;
2313 procedure Swap_Links
2314 (Container
: in out List
;
2319 raise Constraint_Error
with "I cursor has no element";
2323 raise Constraint_Error
with "J cursor has no element";
2326 if I
.Container
/= Container
'Unrestricted_Access then
2327 raise Program_Error
with "I cursor designates wrong container";
2330 if J
.Container
/= Container
'Unrestricted_Access then
2331 raise Program_Error
with "J cursor designates wrong container";
2334 if I
.Node
= J
.Node
then
2338 if Container
.Busy
> 0 then
2339 raise Program_Error
with
2340 "attempt to tamper with cursors (list is busy)";
2343 pragma Assert
(Vet
(I
), "bad I cursor in Swap_Links");
2344 pragma Assert
(Vet
(J
), "bad J cursor in Swap_Links");
2347 I_Next
: constant Cursor
:= Next
(I
);
2351 Splice
(Container
, Before
=> I
, Position
=> J
);
2355 J_Next
: constant Cursor
:= Next
(J
);
2359 Splice
(Container
, Before
=> J
, Position
=> I
);
2362 pragma Assert
(Container
.Length
>= 3);
2364 Splice
(Container
, Before
=> I_Next
, Position
=> J
);
2365 Splice
(Container
, Before
=> J_Next
, Position
=> I
);
2372 --------------------
2373 -- Update_Element --
2374 --------------------
2376 procedure Update_Element
2377 (Container
: in out List
;
2379 Process
: not null access procedure (Element
: in out Element_Type
))
2382 if Position
.Node
= 0 then
2383 raise Constraint_Error
with "Position cursor has no element";
2386 if Position
.Container
/= Container
'Unchecked_Access then
2387 raise Program_Error
with
2388 "Position cursor designates wrong container";
2391 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
2394 B
: Natural renames Container
.Busy
;
2395 L
: Natural renames Container
.Lock
;
2402 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
2404 Process
(N
.Element
);
2421 function Vet
(Position
: Cursor
) return Boolean is
2423 if Position
.Node
= 0 then
2424 return Position
.Container
= null;
2427 if Position
.Container
= null then
2432 L
: List
renames Position
.Container
.all;
2433 N
: Node_Array
renames L
.Nodes
;
2436 if L
.Length
= 0 then
2440 if L
.First
= 0 or L
.First
> L
.Capacity
then
2444 if L
.Last
= 0 or L
.Last
> L
.Capacity
then
2448 if N
(L
.First
).Prev
/= 0 then
2452 if N
(L
.Last
).Next
/= 0 then
2456 if Position
.Node
> L
.Capacity
then
2460 -- An invariant of an active node is that its Previous and Next
2461 -- components are non-negative. Operation Free sets the Previous
2462 -- component of the node to the value -1 before actually deallocating
2463 -- the node, to mark the node as inactive. (By "dellocating" we mean
2464 -- only that the node is linked onto a list of inactive nodes used
2465 -- for storage.) This marker gives us a simple way to detect a
2466 -- dangling reference to a node.
2468 if N
(Position
.Node
).Prev
< 0 then -- see Free
2472 if N
(Position
.Node
).Prev
> L
.Capacity
then
2476 if N
(Position
.Node
).Next
= Position
.Node
then
2480 if N
(Position
.Node
).Prev
= Position
.Node
then
2484 if N
(Position
.Node
).Prev
= 0
2485 and then Position
.Node
/= L
.First
2490 pragma Assert
(N
(Position
.Node
).Prev
/= 0
2491 or else Position
.Node
= L
.First
);
2493 if N
(Position
.Node
).Next
= 0
2494 and then Position
.Node
/= L
.Last
2499 pragma Assert
(N
(Position
.Node
).Next
/= 0
2500 or else Position
.Node
= L
.Last
);
2502 if L
.Length
= 1 then
2503 return L
.First
= L
.Last
;
2506 if L
.First
= L
.Last
then
2510 if N
(L
.First
).Next
= 0 then
2514 if N
(L
.Last
).Prev
= 0 then
2518 if N
(N
(L
.First
).Next
).Prev
/= L
.First
then
2522 if N
(N
(L
.Last
).Prev
).Next
/= L
.Last
then
2526 if L
.Length
= 2 then
2527 if N
(L
.First
).Next
/= L
.Last
then
2531 if N
(L
.Last
).Prev
/= L
.First
then
2538 if N
(L
.First
).Next
= L
.Last
then
2542 if N
(L
.Last
).Prev
= L
.First
then
2546 -- Eliminate earlier possibility
2548 if Position
.Node
= L
.First
then
2552 pragma Assert
(N
(Position
.Node
).Prev
/= 0);
2554 -- Eliminate another possibility
2556 if Position
.Node
= L
.Last
then
2560 pragma Assert
(N
(Position
.Node
).Next
/= 0);
2562 if N
(N
(Position
.Node
).Next
).Prev
/= Position
.Node
then
2566 if N
(N
(Position
.Node
).Prev
).Next
/= Position
.Node
then
2570 if L
.Length
= 3 then
2571 if N
(L
.First
).Next
/= Position
.Node
then
2575 if N
(L
.Last
).Prev
/= Position
.Node
then
2589 (Stream
: not null access Root_Stream_Type
'Class;
2595 Count_Type
'Base'Write (Stream, Item.Length);
2598 while Node /= 0 loop
2599 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2600 Node := Item.Nodes (Node).Next;
2605 (Stream : not null access Root_Stream_Type'Class;
2609 raise Program_Error with "attempt to stream list cursor";
2613 (Stream : not null access Root_Stream_Type'Class;
2614 Item : Reference_Type)
2617 raise Program_Error with "attempt to stream reference";
2621 (Stream : not null access Root_Stream_Type'Class;
2622 Item : Constant_Reference_Type)
2625 raise Program_Error with "attempt to stream reference";
2628 end Ada.Containers.Bounded_Doubly_Linked_Lists;