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 Stream
: not null access Root_Stream_Type
'Class;
46 New_Node
: out Count_Type
);
49 (Container
: in out List
;
52 procedure Insert_Internal
53 (Container
: in out List
;
55 New_Node
: Count_Type
);
57 procedure Splice_Internal
58 (Target
: in out List
;
60 Source
: in out List
);
62 procedure Splice_Internal
63 (Target
: in out List
;
67 Tgt_Pos
: out Count_Type
);
69 function Vet
(Position
: Cursor
) return Boolean;
70 -- Checks invariants of the cursor and its designated container, as a
71 -- simple way of detecting dangling references (see operation Free for a
72 -- description of the detection mechanism), returning True if all checks
73 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
74 -- so the checks are performed only when assertions are enabled.
80 function "=" (Left
, Right
: List
) return Boolean is
81 BL
: Natural renames Left
'Unrestricted_Access.Busy
;
82 LL
: Natural renames Left
'Unrestricted_Access.Lock
;
84 BR
: Natural renames Right
'Unrestricted_Access.Busy
;
85 LR
: Natural renames Right
'Unrestricted_Access.Lock
;
87 LN
: Node_Array
renames Left
.Nodes
;
88 RN
: Node_Array
renames Right
.Nodes
;
96 if Left
'Address = Right
'Address then
100 if Left
.Length
/= Right
.Length
then
104 -- Per AI05-0022, the container implementation is required to detect
105 -- element tampering by a generic actual subprogram.
116 for J
in 1 .. Left
.Length
loop
117 if LN
(LI
).Element
/= RN
(RI
).Element
then
150 (Container
: in out List
;
151 New_Item
: Element_Type
;
152 New_Node
: out Count_Type
)
154 N
: Node_Array
renames Container
.Nodes
;
157 if Container
.Free
>= 0 then
158 New_Node
:= Container
.Free
;
160 -- We always perform the assignment first, before we change container
161 -- state, in order to defend against exceptions duration assignment.
163 N
(New_Node
).Element
:= New_Item
;
164 Container
.Free
:= N
(New_Node
).Next
;
167 -- A negative free store value means that the links of the nodes in
168 -- the free store have not been initialized. In this case, the nodes
169 -- are physically contiguous in the array, starting at the index that
170 -- is the absolute value of the Container.Free, and continuing until
171 -- the end of the array (Nodes'Last).
173 New_Node
:= abs Container
.Free
;
175 -- As above, we perform this assignment first, before modifying any
178 N
(New_Node
).Element
:= New_Item
;
179 Container
.Free
:= Container
.Free
- 1;
184 (Container
: in out List
;
185 Stream
: not null access Root_Stream_Type
'Class;
186 New_Node
: out Count_Type
)
188 N
: Node_Array
renames Container
.Nodes
;
191 if Container
.Free
>= 0 then
192 New_Node
:= Container
.Free
;
194 -- We always perform the assignment first, before we change container
195 -- state, in order to defend against exceptions duration assignment.
197 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
198 Container
.Free
:= N
(New_Node
).Next
;
201 -- A negative free store value means that the links of the nodes in
202 -- the free store have not been initialized. In this case, the nodes
203 -- are physically contiguous in the array, starting at the index that
204 -- is the absolute value of the Container.Free, and continuing until
205 -- the end of the array (Nodes'Last).
207 New_Node
:= abs Container
.Free
;
209 -- As above, we perform this assignment first, before modifying any
212 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
213 Container
.Free
:= Container
.Free
- 1;
222 (Container
: in out List
;
223 New_Item
: Element_Type
;
224 Count
: Count_Type
:= 1)
227 Insert
(Container
, No_Element
, New_Item
, Count
);
234 procedure Assign
(Target
: in out List
; Source
: List
) is
235 SN
: Node_Array
renames Source
.Nodes
;
239 if Target
'Address = Source
'Address then
243 if Target
.Capacity
< Source
.Length
then
244 raise Capacity_Error
-- ???
245 with "Target capacity is less than Source length";
252 Target
.Append
(SN
(J
).Element
);
261 procedure Clear
(Container
: in out List
) is
262 N
: Node_Array
renames Container
.Nodes
;
266 if Container
.Length
= 0 then
267 pragma Assert
(Container
.First
= 0);
268 pragma Assert
(Container
.Last
= 0);
269 pragma Assert
(Container
.Busy
= 0);
270 pragma Assert
(Container
.Lock
= 0);
274 pragma Assert
(Container
.First
>= 1);
275 pragma Assert
(Container
.Last
>= 1);
276 pragma Assert
(N
(Container
.First
).Prev
= 0);
277 pragma Assert
(N
(Container
.Last
).Next
= 0);
279 if Container
.Busy
> 0 then
280 raise Program_Error
with
281 "attempt to tamper with cursors (list is busy)";
284 while Container
.Length
> 1 loop
285 X
:= Container
.First
;
286 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
288 Container
.First
:= N
(X
).Next
;
289 N
(Container
.First
).Prev
:= 0;
291 Container
.Length
:= Container
.Length
- 1;
296 X
:= Container
.First
;
297 pragma Assert
(X
= Container
.Last
);
299 Container
.First
:= 0;
301 Container
.Length
:= 0;
306 ------------------------
307 -- Constant_Reference --
308 ------------------------
310 function Constant_Reference
311 (Container
: aliased List
;
312 Position
: Cursor
) return Constant_Reference_Type
315 if Position
.Container
= null then
316 raise Constraint_Error
with "Position cursor has no element";
318 elsif Position
.Container
/= Container
'Unrestricted_Access then
319 raise Program_Error
with
320 "Position cursor designates wrong container";
323 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
326 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
328 return (Element
=> N
.Element
'Access);
331 end Constant_Reference
;
339 Item
: Element_Type
) return Boolean
342 return Find
(Container
, Item
) /= No_Element
;
349 function Copy
(Source
: List
; Capacity
: Count_Type
:= 0) return List
is
355 elsif Capacity
>= Source
.Length
then
358 raise Capacity_Error
with "Capacity value too small";
361 return Target
: List
(Capacity
=> C
) do
362 Assign
(Target
=> Target
, Source
=> Source
);
371 (Container
: in out List
;
372 Position
: in out Cursor
;
373 Count
: Count_Type
:= 1)
375 N
: Node_Array
renames Container
.Nodes
;
379 if Position
.Node
= 0 then
380 raise Constraint_Error
with
381 "Position cursor has no element";
384 if Position
.Container
/= Container
'Unrestricted_Access then
385 raise Program_Error
with
386 "Position cursor designates wrong container";
389 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
390 pragma Assert
(Container
.First
>= 1);
391 pragma Assert
(Container
.Last
>= 1);
392 pragma Assert
(N
(Container
.First
).Prev
= 0);
393 pragma Assert
(N
(Container
.Last
).Next
= 0);
395 if Position
.Node
= Container
.First
then
396 Delete_First
(Container
, Count
);
397 Position
:= No_Element
;
402 Position
:= No_Element
;
406 if Container
.Busy
> 0 then
407 raise Program_Error
with
408 "attempt to tamper with cursors (list is busy)";
411 for Index
in 1 .. Count
loop
412 pragma Assert
(Container
.Length
>= 2);
415 Container
.Length
:= Container
.Length
- 1;
417 if X
= Container
.Last
then
418 Position
:= No_Element
;
420 Container
.Last
:= N
(X
).Prev
;
421 N
(Container
.Last
).Next
:= 0;
427 Position
.Node
:= N
(X
).Next
;
429 N
(N
(X
).Next
).Prev
:= N
(X
).Prev
;
430 N
(N
(X
).Prev
).Next
:= N
(X
).Next
;
435 Position
:= No_Element
;
442 procedure Delete_First
443 (Container
: in out List
;
444 Count
: Count_Type
:= 1)
446 N
: Node_Array
renames Container
.Nodes
;
450 if Count
>= Container
.Length
then
459 if Container
.Busy
> 0 then
460 raise Program_Error
with
461 "attempt to tamper with cursors (list is busy)";
464 for J
in 1 .. Count
loop
465 X
:= Container
.First
;
466 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
468 Container
.First
:= N
(X
).Next
;
469 N
(Container
.First
).Prev
:= 0;
471 Container
.Length
:= Container
.Length
- 1;
481 procedure Delete_Last
482 (Container
: in out List
;
483 Count
: Count_Type
:= 1)
485 N
: Node_Array
renames Container
.Nodes
;
489 if Count
>= Container
.Length
then
498 if Container
.Busy
> 0 then
499 raise Program_Error
with
500 "attempt to tamper with cursors (list is busy)";
503 for J
in 1 .. Count
loop
505 pragma Assert
(N
(N
(X
).Prev
).Next
= Container
.Last
);
507 Container
.Last
:= N
(X
).Prev
;
508 N
(Container
.Last
).Next
:= 0;
510 Container
.Length
:= Container
.Length
- 1;
520 function Element
(Position
: Cursor
) return Element_Type
is
522 if Position
.Node
= 0 then
523 raise Constraint_Error
with
524 "Position cursor has no element";
527 pragma Assert
(Vet
(Position
), "bad cursor in Element");
529 return Position
.Container
.Nodes
(Position
.Node
).Element
;
537 procedure Finalize
(Object
: in out Iterator
) is
539 if Object
.Container
/= null then
541 B
: Natural renames Object
.Container
.all.Busy
;
555 Position
: Cursor
:= No_Element
) return Cursor
557 Nodes
: Node_Array
renames Container
.Nodes
;
558 Node
: Count_Type
:= Position
.Node
;
562 Node
:= Container
.First
;
565 if Position
.Container
/= Container
'Unrestricted_Access then
566 raise Program_Error
with
567 "Position cursor designates wrong container";
570 pragma Assert
(Vet
(Position
), "bad cursor in Find");
573 -- Per AI05-0022, the container implementation is required to detect
574 -- element tampering by a generic actual subprogram.
577 B
: Natural renames Container
'Unrestricted_Access.Busy
;
578 L
: Natural renames Container
'Unrestricted_Access.Lock
;
588 if Nodes
(Node
).Element
= Item
then
593 Node
:= Nodes
(Node
).Next
;
602 return Cursor
'(Container'Unrestricted_Access, Result);
617 function First (Container : List) return Cursor is
619 if Container.First = 0 then
622 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
626 function First
(Object
: Iterator
) return Cursor
is
628 -- The value of the iterator object's Node component influences the
629 -- behavior of the First (and Last) selector function.
631 -- When the Node component is 0, this means the iterator object was
632 -- constructed without a start expression, in which case the (forward)
633 -- iteration starts from the (logical) beginning of the entire sequence
634 -- of items (corresponding to Container.First, for a forward iterator).
636 -- Otherwise, this is iteration over a partial sequence of items. When
637 -- the Node component is positive, the iterator object was constructed
638 -- with a start expression, that specifies the position from which the
639 -- (forward) partial iteration begins.
641 if Object
.Node
= 0 then
642 return Bounded_Doubly_Linked_Lists
.First
(Object
.Container
.all);
644 return Cursor
'(Object.Container, Object.Node);
652 function First_Element (Container : List) return Element_Type is
654 if Container.First = 0 then
655 raise Constraint_Error with "list is empty";
657 return Container.Nodes (Container.First).Element;
666 (Container : in out List;
669 pragma Assert (X > 0);
670 pragma Assert (X <= Container.Capacity);
672 N : Node_Array renames Container.Nodes;
673 pragma Assert (N (X).Prev >= 0); -- node is active
676 -- The list container actually contains two lists: one for the "active"
677 -- nodes that contain elements that have been inserted onto the list,
678 -- and another for the "inactive" nodes for the free store.
680 -- We desire that merely declaring an object should have only minimal
681 -- cost; specially, we want to avoid having to initialize the free
682 -- store (to fill in the links), especially if the capacity is large.
684 -- The head of the free list is indicated by Container.Free. If its
685 -- value is non-negative, then the free store has been initialized in
686 -- the "normal" way: Container.Free points to the head of the list of
687 -- free (inactive) nodes, and the value 0 means the free list is empty.
688 -- Each node on the free list has been initialized to point to the next
689 -- free node (via its Next component), and the value 0 means that this
690 -- is the last free node.
692 -- If Container.Free is negative, then the links on the free store have
693 -- not been initialized. In this case the link values are implied: the
694 -- free store comprises the components of the node array started with
695 -- the absolute value of Container.Free, and continuing until the end of
696 -- the array (Nodes'Last).
698 -- If the list container is manipulated on one end only (for example if
699 -- the container were being used as a stack), then there is no need to
700 -- initialize the free store, since the inactive nodes are physically
701 -- contiguous (in fact, they lie immediately beyond the logical end
702 -- being manipulated). The only time we need to actually initialize the
703 -- nodes in the free store is if the node that becomes inactive is not
704 -- at the end of the list. The free store would then be discontiguous
705 -- and so its nodes would need to be linked in the traditional way.
708 -- It might be possible to perform an optimization here. Suppose that
709 -- the free store can be represented as having two parts: one comprising
710 -- the non-contiguous inactive nodes linked together in the normal way,
711 -- and the other comprising the contiguous inactive nodes (that are not
712 -- linked together, at the end of the nodes array). This would allow us
713 -- to never have to initialize the free store, except in a lazy way as
714 -- nodes become inactive.
716 -- When an element is deleted from the list container, its node becomes
717 -- inactive, and so we set its Prev component to a negative value, to
718 -- indicate that it is now inactive. This provides a useful way to
719 -- detect a dangling cursor reference (and which is used in Vet).
721 N (X).Prev := -1; -- Node is deallocated (not on active list)
723 if Container.Free >= 0 then
725 -- The free store has previously been initialized. All we need to
726 -- do here is link the newly-free'd node onto the free list.
728 N (X).Next := Container.Free;
731 elsif X + 1 = abs Container.Free then
733 -- The free store has not been initialized, and the node becoming
734 -- inactive immediately precedes the start of the free store. All
735 -- we need to do is move the start of the free store back by one.
737 -- Note: initializing Next to zero is not strictly necessary but
738 -- seems cleaner and marginally safer.
741 Container.Free := Container.Free + 1;
744 -- The free store has not been initialized, and the node becoming
745 -- inactive does not immediately precede the free store. Here we
746 -- first initialize the free store (meaning the links are given
747 -- values in the traditional way), and then link the newly-free'd
748 -- node onto the head of the free store.
751 -- See the comments above for an optimization opportunity. If the
752 -- next link for a node on the free store is negative, then this
753 -- means the remaining nodes on the free store are physically
754 -- contiguous, starting as the absolute value of that index value.
756 Container.Free := abs Container.Free;
758 if Container.Free > Container.Capacity then
762 for I in Container.Free .. Container.Capacity - 1 loop
766 N (Container.Capacity).Next := 0;
769 N (X).Next := Container.Free;
774 ---------------------
775 -- Generic_Sorting --
776 ---------------------
778 package body Generic_Sorting is
784 function Is_Sorted (Container : List) return Boolean is
785 B : Natural renames Container'Unrestricted_Access.Busy;
786 L : Natural renames Container'Unrestricted_Access.Lock;
788 Nodes : Node_Array renames Container.Nodes;
794 -- Per AI05-0022, the container implementation is required to detect
795 -- element tampering by a generic actual subprogram.
800 Node := Container.First;
802 for J in 2 .. Container.Length loop
803 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
808 Node := Nodes (Node).Next;
828 (Target : in out List;
829 Source : in out List)
832 -- The semantics of Merge changed slightly per AI05-0021. It was
833 -- originally the case that if Target and Source denoted the same
834 -- container object, then the GNAT implementation of Merge did
835 -- nothing. However, it was argued that RM05 did not precisely
836 -- specify the semantics for this corner case. The decision of the
837 -- ARG was that if Target and Source denote the same non-empty
838 -- container object, then Program_Error is raised.
840 if Source.Is_Empty then
844 if Target'Address = Source'Address then
845 raise Program_Error with
846 "Target and Source denote same non-empty container";
849 if Target.Length > Count_Type'Last - Source.Length then
850 raise Constraint_Error with "new length exceeds maximum";
853 if Target.Length + Source.Length > Target.Capacity then
854 raise Capacity_Error with "new length exceeds target capacity";
857 if Target.Busy > 0 then
858 raise Program_Error with
859 "attempt to tamper with cursors of Target (list is busy)";
862 if Source.Busy > 0 then
863 raise Program_Error with
864 "attempt to tamper with cursors of Source (list is busy)";
867 -- Per AI05-0022, the container implementation is required to detect
868 -- element tampering by a generic actual subprogram.
871 TB : Natural renames Target.Busy;
872 TL : Natural renames Target.Lock;
874 SB : Natural renames Source.Busy;
875 SL : Natural renames Source.Lock;
877 LN : Node_Array renames Target.Nodes;
878 RN : Node_Array renames Source.Nodes;
880 LI, LJ, RI, RJ : Count_Type;
892 pragma Assert (RN (RI).Next = 0
893 or else not (RN (RN (RI).Next).Element <
897 Splice_Internal (Target, 0, Source);
901 pragma Assert (LN (LI).Next = 0
902 or else not (LN (LN (LI).Next).Element <
905 if RN (RI).Element < LN (LI).Element then
908 Splice_Internal (Target, LI, Source, RJ, LJ);
937 procedure Sort (Container : in out List) is
938 N : Node_Array renames Container.Nodes;
940 procedure Partition (Pivot, Back : Count_Type);
941 -- What does this do ???
943 procedure Sort (Front, Back : Count_Type);
944 -- Internal procedure, what does it do??? rename it???
950 procedure Partition (Pivot, Back : Count_Type) is
954 Node := N (Pivot).Next;
955 while Node /= Back loop
956 if N (Node).Element < N (Pivot).Element then
958 Prev : constant Count_Type := N (Node).Prev;
959 Next : constant Count_Type := N (Node).Next;
962 N (Prev).Next := Next;
965 Container.Last := Prev;
967 N (Next).Prev := Prev;
970 N (Node).Next := Pivot;
971 N (Node).Prev := N (Pivot).Prev;
973 N (Pivot).Prev := Node;
975 if N (Node).Prev = 0 then
976 Container.First := Node;
978 N (N (Node).Prev).Next := Node;
985 Node := N (Node).Next;
994 procedure Sort (Front, Back : Count_Type) is
995 Pivot : constant Count_Type :=
996 (if Front = 0 then Container.First else N (Front).Next);
998 if Pivot /= Back then
999 Partition (Pivot, Back);
1000 Sort (Front, Pivot);
1005 -- Start of processing for Sort
1008 if Container.Length <= 1 then
1012 pragma Assert (N (Container.First).Prev = 0);
1013 pragma Assert (N (Container.Last).Next = 0);
1015 if Container.Busy > 0 then
1016 raise Program_Error with
1017 "attempt to tamper with cursors (list is busy)";
1020 -- Per AI05-0022, the container implementation is required to detect
1021 -- element tampering by a generic actual subprogram.
1024 B : Natural renames Container.Busy;
1025 L : Natural renames Container.Lock;
1031 Sort (Front => 0, Back => 0);
1043 pragma Assert (N (Container.First).Prev = 0);
1044 pragma Assert (N (Container.Last).Next = 0);
1047 end Generic_Sorting;
1053 function Has_Element (Position : Cursor) return Boolean is
1055 pragma Assert (Vet (Position), "bad cursor in Has_Element");
1056 return Position.Node /= 0;
1064 (Container : in out List;
1066 New_Item : Element_Type;
1067 Position : out Cursor;
1068 Count : Count_Type := 1)
1070 New_Node : Count_Type;
1073 if Before.Container /= null then
1074 if Before.Container /= Container'Unrestricted_Access then
1075 raise Program_Error with
1076 "Before cursor designates wrong list";
1079 pragma Assert (Vet (Before), "bad cursor in Insert");
1087 if Container.Length > Container.Capacity - Count then
1088 raise Capacity_Error with "capacity exceeded";
1091 if Container.Busy > 0 then
1092 raise Program_Error with
1093 "attempt to tamper with cursors (list is busy)";
1096 Allocate (Container, New_Item, New_Node);
1097 Insert_Internal (Container, Before.Node, New_Node => New_Node);
1098 Position := Cursor'(Container
'Unchecked_Access, Node
=> New_Node
);
1100 for Index
in Count_Type
'(2) .. Count loop
1101 Allocate (Container, New_Item, New_Node => New_Node);
1102 Insert_Internal (Container, Before.Node, New_Node => New_Node);
1107 (Container : in out List;
1109 New_Item : Element_Type;
1110 Count : Count_Type := 1)
1113 pragma Unreferenced (Position);
1115 Insert (Container, Before, New_Item, Position, Count);
1119 (Container : in out List;
1121 Position : out Cursor;
1122 Count : Count_Type := 1)
1124 New_Item : Element_Type;
1125 pragma Unmodified (New_Item);
1126 -- OK to reference, see below
1129 -- There is no explicit element provided, but in an instance the element
1130 -- type may be a scalar with a Default_Value aspect, or a composite
1131 -- type with such a scalar component, or components with default
1132 -- initialization, so insert the specified number of possibly
1133 -- initialized elements at the given position.
1135 Insert (Container, Before, New_Item, Position, Count);
1138 ---------------------
1139 -- Insert_Internal --
1140 ---------------------
1142 procedure Insert_Internal
1143 (Container : in out List;
1144 Before : Count_Type;
1145 New_Node : Count_Type)
1147 N : Node_Array renames Container.Nodes;
1150 if Container.Length = 0 then
1151 pragma Assert (Before = 0);
1152 pragma Assert (Container.First = 0);
1153 pragma Assert (Container.Last = 0);
1155 Container.First := New_Node;
1156 N (Container.First).Prev := 0;
1158 Container.Last := New_Node;
1159 N (Container.Last).Next := 0;
1161 -- Before = zero means append
1163 elsif Before = 0 then
1164 pragma Assert (N (Container.Last).Next = 0);
1166 N (Container.Last).Next := New_Node;
1167 N (New_Node).Prev := Container.Last;
1169 Container.Last := New_Node;
1170 N (Container.Last).Next := 0;
1172 -- Before = Container.First means prepend
1174 elsif Before = Container.First then
1175 pragma Assert (N (Container.First).Prev = 0);
1177 N (Container.First).Prev := New_Node;
1178 N (New_Node).Next := Container.First;
1180 Container.First := New_Node;
1181 N (Container.First).Prev := 0;
1184 pragma Assert (N (Container.First).Prev = 0);
1185 pragma Assert (N (Container.Last).Next = 0);
1187 N (New_Node).Next := Before;
1188 N (New_Node).Prev := N (Before).Prev;
1190 N (N (Before).Prev).Next := New_Node;
1191 N (Before).Prev := New_Node;
1194 Container.Length := Container.Length + 1;
1195 end Insert_Internal;
1201 function Is_Empty (Container : List) return Boolean is
1203 return Container.Length = 0;
1212 Process : not null access procedure (Position : Cursor))
1214 B : Natural renames Container'Unrestricted_Access.all.Busy;
1215 Node : Count_Type := Container.First;
1221 while Node /= 0 loop
1222 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1223 Node
:= Container
.Nodes
(Node
).Next
;
1236 return List_Iterator_Interfaces
.Reversible_Iterator
'Class
1238 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1241 -- The value of the Node component influences the behavior of the First
1242 -- and Last selector functions of the iterator object. When the Node
1243 -- component is 0 (as is the case here), this means the iterator
1244 -- object was constructed without a start expression. This is a
1245 -- complete iterator, meaning that the iteration starts from the
1246 -- (logical) beginning of the sequence of items.
1248 -- Note: For a forward iterator, Container.First is the beginning, and
1249 -- for a reverse iterator, Container.Last is the beginning.
1251 return It
: constant Iterator
:=
1252 Iterator
'(Limited_Controlled with
1253 Container => Container'Unrestricted_Access,
1263 return List_Iterator_Interfaces.Reversible_Iterator'class
1265 B : Natural renames Container'Unrestricted_Access.all.Busy;
1268 -- It was formerly the case that when Start = No_Element, the partial
1269 -- iterator was defined to behave the same as for a complete iterator,
1270 -- and iterate over the entire sequence of items. However, those
1271 -- semantics were unintuitive and arguably error-prone (it is too easy
1272 -- to accidentally create an endless loop), and so they were changed,
1273 -- per the ARG meeting in Denver on 2011/11. However, there was no
1274 -- consensus about what positive meaning this corner case should have,
1275 -- and so it was decided to simply raise an exception. This does imply,
1276 -- however, that it is not possible to use a partial iterator to specify
1277 -- an empty sequence of items.
1279 if Start = No_Element then
1280 raise Constraint_Error with
1281 "Start position for iterator equals No_Element";
1284 if Start.Container /= Container'Unrestricted_Access then
1285 raise Program_Error with
1286 "Start cursor of Iterate designates wrong list";
1289 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1291 -- The value of the Node component influences the behavior of the First
1292 -- and Last selector functions of the iterator object. When the Node
1293 -- component is positive (as is the case here), it means that this
1294 -- is a partial iteration, over a subset of the complete sequence of
1295 -- items. The iterator object was constructed with a start expression,
1296 -- indicating the position from which the iteration begins. Note that
1297 -- the start position has the same value irrespective of whether this
1298 -- is a forward or reverse iteration.
1300 return It : constant Iterator :=
1301 Iterator'(Limited_Controlled
with
1302 Container
=> Container
'Unrestricted_Access,
1313 function Last
(Container
: List
) return Cursor
is
1315 if Container
.Last
= 0 then
1318 return Cursor
'(Container'Unrestricted_Access, Container.Last);
1322 function Last (Object : Iterator) return Cursor is
1324 -- The value of the iterator object's Node component influences the
1325 -- behavior of the Last (and First) selector function.
1327 -- When the Node component is 0, this means the iterator object was
1328 -- constructed without a start expression, in which case the (reverse)
1329 -- iteration starts from the (logical) beginning of the entire sequence
1330 -- (corresponding to Container.Last, for a reverse iterator).
1332 -- Otherwise, this is iteration over a partial sequence of items. When
1333 -- the Node component is positive, the iterator object was constructed
1334 -- with a start expression, that specifies the position from which the
1335 -- (reverse) partial iteration begins.
1337 if Object.Node = 0 then
1338 return Bounded_Doubly_Linked_Lists.Last (Object.Container.all);
1340 return Cursor'(Object
.Container
, Object
.Node
);
1348 function Last_Element
(Container
: List
) return Element_Type
is
1350 if Container
.Last
= 0 then
1351 raise Constraint_Error
with "list is empty";
1353 return Container
.Nodes
(Container
.Last
).Element
;
1361 function Length
(Container
: List
) return Count_Type
is
1363 return Container
.Length
;
1371 (Target
: in out List
;
1372 Source
: in out List
)
1374 N
: Node_Array
renames Source
.Nodes
;
1378 if Target
'Address = Source
'Address then
1382 if Target
.Capacity
< Source
.Length
then
1383 raise Capacity_Error
with "Source length exceeds Target capacity";
1386 if Source
.Busy
> 0 then
1387 raise Program_Error
with
1388 "attempt to tamper with cursors of Source (list is busy)";
1391 -- Clear target, note that this checks busy bits of Target
1395 while Source
.Length
> 1 loop
1396 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1397 pragma Assert
(Source
.Last
/= Source
.First
);
1398 pragma Assert
(N
(Source
.First
).Prev
= 0);
1399 pragma Assert
(N
(Source
.Last
).Next
= 0);
1401 -- Copy first element from Source to Target
1404 Append
(Target
, N
(X
).Element
);
1406 -- Unlink first node of Source
1408 Source
.First
:= N
(X
).Next
;
1409 N
(Source
.First
).Prev
:= 0;
1411 Source
.Length
:= Source
.Length
- 1;
1413 -- The representation invariants for Source have been restored. It is
1414 -- now safe to free the unlinked node, without fear of corrupting the
1415 -- active links of Source.
1417 -- Note that the algorithm we use here models similar algorithms used
1418 -- in the unbounded form of the doubly-linked list container. In that
1419 -- case, Free is an instantation of Unchecked_Deallocation, which can
1420 -- fail (because PE will be raised if controlled Finalize fails), so
1421 -- we must defer the call until the last step. Here in the bounded
1422 -- form, Free merely links the node we have just "deallocated" onto a
1423 -- list of inactive nodes, so technically Free cannot fail. However,
1424 -- for consistency, we handle Free the same way here as we do for the
1425 -- unbounded form, with the pessimistic assumption that it can fail.
1430 if Source
.Length
= 1 then
1431 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1432 pragma Assert
(Source
.Last
= Source
.First
);
1433 pragma Assert
(N
(Source
.First
).Prev
= 0);
1434 pragma Assert
(N
(Source
.Last
).Next
= 0);
1436 -- Copy element from Source to Target
1439 Append
(Target
, N
(X
).Element
);
1441 -- Unlink node of Source
1447 -- Return the unlinked node to the free store
1457 procedure Next
(Position
: in out Cursor
) is
1459 Position
:= Next
(Position
);
1462 function Next
(Position
: Cursor
) return Cursor
is
1464 if Position
.Node
= 0 then
1468 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1471 Nodes
: Node_Array
renames Position
.Container
.Nodes
;
1472 Node
: constant Count_Type
:= Nodes
(Position
.Node
).Next
;
1477 return Cursor
'(Position.Container, Node);
1484 Position : Cursor) return Cursor
1487 if Position.Container = null then
1489 elsif Position.Container /= Object.Container then
1490 raise Program_Error with
1491 "Position cursor of Next designates wrong list";
1493 return Next (Position);
1502 (Container : in out List;
1503 New_Item : Element_Type;
1504 Count : Count_Type := 1)
1507 Insert (Container, First (Container), New_Item, Count);
1514 procedure Previous (Position : in out Cursor) is
1516 Position := Previous (Position);
1519 function Previous (Position : Cursor) return Cursor is
1521 if Position.Node = 0 then
1525 pragma Assert (Vet (Position), "bad cursor in Previous");
1528 Nodes : Node_Array renames Position.Container.Nodes;
1529 Node : constant Count_Type := Nodes (Position.Node).Prev;
1534 return Cursor'(Position
.Container
, Node
);
1541 Position
: Cursor
) return Cursor
1544 if Position
.Container
= null then
1546 elsif Position
.Container
/= Object
.Container
then
1547 raise Program_Error
with
1548 "Position cursor of Previous designates wrong list";
1550 return Previous
(Position
);
1558 procedure Query_Element
1560 Process
: not null access procedure (Element
: Element_Type
))
1563 if Position
.Node
= 0 then
1564 raise Constraint_Error
with
1565 "Position cursor has no element";
1568 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1571 C
: List
renames Position
.Container
.all'Unrestricted_Access.all;
1572 B
: Natural renames C
.Busy
;
1573 L
: Natural renames C
.Lock
;
1580 N
: Node_Type
renames C
.Nodes
(Position
.Node
);
1582 Process
(N
.Element
);
1600 (Stream
: not null access Root_Stream_Type
'Class;
1603 N
: Count_Type
'Base;
1608 Count_Type
'Base'Read (Stream, N);
1611 raise Program_Error with "bad list length (corrupt stream)";
1616 elsif N > Item.Capacity then
1617 raise Constraint_Error with "length exceeds capacity";
1620 for Idx in 1 .. N loop
1621 Allocate (Item, Stream, New_Node => X);
1622 Insert_Internal (Item, Before => 0, New_Node => X);
1628 (Stream : not null access Root_Stream_Type'Class;
1632 raise Program_Error with "attempt to stream list cursor";
1636 (Stream : not null access Root_Stream_Type'Class;
1637 Item : out Reference_Type)
1640 raise Program_Error with "attempt to stream reference";
1644 (Stream : not null access Root_Stream_Type'Class;
1645 Item : out Constant_Reference_Type)
1648 raise Program_Error with "attempt to stream reference";
1656 (Container : aliased in out List;
1657 Position : Cursor) return Reference_Type
1660 if Position.Container = null then
1661 raise Constraint_Error with "Position cursor has no element";
1663 elsif Position.Container /= Container'Unrestricted_Access then
1664 raise Program_Error with
1665 "Position cursor designates wrong container";
1668 pragma Assert (Vet (Position), "bad cursor in function Reference");
1671 N : Node_Type renames Container.Nodes (Position.Node);
1673 return (Element => N.Element'Access);
1678 ---------------------
1679 -- Replace_Element --
1680 ---------------------
1682 procedure Replace_Element
1683 (Container : in out List;
1685 New_Item : Element_Type)
1688 if Position.Container = null then
1689 raise Constraint_Error with "Position cursor has no element";
1691 elsif Position.Container /= Container'Unchecked_Access then
1692 raise Program_Error with
1693 "Position cursor designates wrong container";
1695 elsif Container.Lock > 0 then
1696 raise Program_Error with
1697 "attempt to tamper with elements (list is locked)";
1700 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1702 Container.Nodes (Position.Node).Element := New_Item;
1704 end Replace_Element;
1706 ----------------------
1707 -- Reverse_Elements --
1708 ----------------------
1710 procedure Reverse_Elements (Container : in out List) is
1711 N : Node_Array renames Container.Nodes;
1712 I : Count_Type := Container.First;
1713 J : Count_Type := Container.Last;
1715 procedure Swap (L, R : Count_Type);
1721 procedure Swap (L, R : Count_Type) is
1722 LN : constant Count_Type := N (L).Next;
1723 LP : constant Count_Type := N (L).Prev;
1725 RN : constant Count_Type := N (R).Next;
1726 RP : constant Count_Type := N (R).Prev;
1741 pragma Assert (RP = L);
1755 -- Start of processing for Reverse_Elements
1758 if Container.Length <= 1 then
1762 pragma Assert (N (Container.First).Prev = 0);
1763 pragma Assert (N (Container.Last).Next = 0);
1765 if Container.Busy > 0 then
1766 raise Program_Error with
1767 "attempt to tamper with cursors (list is busy)";
1770 Container.First := J;
1771 Container.Last := I;
1773 Swap (L => I, R => J);
1781 Swap (L => J, R => I);
1790 pragma Assert (N (Container.First).Prev = 0);
1791 pragma Assert (N (Container.Last).Next = 0);
1792 end Reverse_Elements;
1798 function Reverse_Find
1800 Item : Element_Type;
1801 Position : Cursor := No_Element) return Cursor
1803 Node : Count_Type := Position.Node;
1807 Node := Container.Last;
1810 if Position.Container /= Container'Unrestricted_Access then
1811 raise Program_Error with
1812 "Position cursor designates wrong container";
1815 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1818 -- Per AI05-0022, the container implementation is required to detect
1819 -- element tampering by a generic actual subprogram.
1822 B : Natural renames Container'Unrestricted_Access.Busy;
1823 L : Natural renames Container'Unrestricted_Access.Lock;
1825 Result : Count_Type;
1832 while Node /= 0 loop
1833 if Container.Nodes (Node).Element = Item then
1838 Node := Container.Nodes (Node).Prev;
1847 return Cursor'(Container
'Unrestricted_Access, Result
);
1858 ---------------------
1859 -- Reverse_Iterate --
1860 ---------------------
1862 procedure Reverse_Iterate
1864 Process
: not null access procedure (Position
: Cursor
))
1866 C
: List
renames Container
'Unrestricted_Access.all;
1867 B
: Natural renames C
.Busy
;
1869 Node
: Count_Type
:= Container
.Last
;
1875 while Node
/= 0 loop
1876 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1877 Node := Container.Nodes (Node).Prev;
1886 end Reverse_Iterate;
1893 (Target : in out List;
1895 Source : in out List)
1898 if Before.Container /= null then
1899 if Before.Container /= Target'Unrestricted_Access then
1900 raise Program_Error with
1901 "Before cursor designates wrong container";
1904 pragma Assert (Vet (Before), "bad cursor in Splice");
1907 if Target'Address = Source'Address or else Source.Length = 0 then
1910 elsif Target.Length > Count_Type'Last - Source.Length then
1911 raise Constraint_Error with "new length exceeds maximum";
1913 elsif Target.Length + Source.Length > Target.Capacity then
1914 raise Capacity_Error with "new length exceeds target capacity";
1916 elsif Target.Busy > 0 then
1917 raise Program_Error with
1918 "attempt to tamper with cursors of Target (list is busy)";
1920 elsif Source.Busy > 0 then
1921 raise Program_Error with
1922 "attempt to tamper with cursors of Source (list is busy)";
1925 Splice_Internal (Target, Before.Node, Source);
1930 (Container : in out List;
1934 N : Node_Array renames Container.Nodes;
1937 if Before.Container /= null then
1938 if Before.Container /= Container'Unchecked_Access then
1939 raise Program_Error with
1940 "Before cursor designates wrong container";
1943 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1946 if Position.Node = 0 then
1947 raise Constraint_Error with "Position cursor has no element";
1950 if Position.Container /= Container'Unrestricted_Access then
1951 raise Program_Error with
1952 "Position cursor designates wrong container";
1955 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1957 if Position.Node = Before.Node
1958 or else N (Position.Node).Next = Before.Node
1963 pragma Assert (Container.Length >= 2);
1965 if Container.Busy > 0 then
1966 raise Program_Error with
1967 "attempt to tamper with cursors (list is busy)";
1970 if Before.Node = 0 then
1971 pragma Assert (Position.Node /= Container.Last);
1973 if Position.Node = Container.First then
1974 Container.First := N (Position.Node).Next;
1975 N (Container.First).Prev := 0;
1977 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1978 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1981 N (Container.Last).Next := Position.Node;
1982 N (Position.Node).Prev := Container.Last;
1984 Container.Last := Position.Node;
1985 N (Container.Last).Next := 0;
1990 if Before.Node = Container.First then
1991 pragma Assert (Position.Node /= Container.First);
1993 if Position.Node = Container.Last then
1994 Container.Last := N (Position.Node).Prev;
1995 N (Container.Last).Next := 0;
1997 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1998 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2001 N (Container.First).Prev := Position.Node;
2002 N (Position.Node).Next := Container.First;
2004 Container.First := Position.Node;
2005 N (Container.First).Prev := 0;
2010 if Position.Node = Container.First then
2011 Container.First := N (Position.Node).Next;
2012 N (Container.First).Prev := 0;
2014 elsif Position.Node = Container.Last then
2015 Container.Last := N (Position.Node).Prev;
2016 N (Container.Last).Next := 0;
2019 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2020 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2023 N (N (Before.Node).Prev).Next := Position.Node;
2024 N (Position.Node).Prev := N (Before.Node).Prev;
2026 N (Before.Node).Prev := Position.Node;
2027 N (Position.Node).Next := Before.Node;
2029 pragma Assert (N (Container.First).Prev = 0);
2030 pragma Assert (N (Container.Last).Next = 0);
2034 (Target : in out List;
2036 Source : in out List;
2037 Position : in out Cursor)
2039 Target_Position : Count_Type;
2042 if Target'Address = Source'Address then
2043 Splice (Target, Before, Position);
2047 if Before.Container /= null then
2048 if Before.Container /= Target'Unrestricted_Access then
2049 raise Program_Error with
2050 "Before cursor designates wrong container";
2053 pragma Assert (Vet (Before), "bad Before cursor in Splice");
2056 if Position.Node = 0 then
2057 raise Constraint_Error with "Position cursor has no element";
2060 if Position.Container /= Source'Unrestricted_Access then
2061 raise Program_Error with
2062 "Position cursor designates wrong container";
2065 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2067 if Target.Length >= Target.Capacity then
2068 raise Capacity_Error with "Target is full";
2071 if Target.Busy > 0 then
2072 raise Program_Error with
2073 "attempt to tamper with cursors of Target (list is busy)";
2076 if Source.Busy > 0 then
2077 raise Program_Error with
2078 "attempt to tamper with cursors of Source (list is busy)";
2083 Before => Before.Node,
2085 Src_Pos => Position.Node,
2086 Tgt_Pos => Target_Position);
2088 Position := Cursor'(Target
'Unrestricted_Access, Target_Position
);
2091 ---------------------
2092 -- Splice_Internal --
2093 ---------------------
2095 procedure Splice_Internal
2096 (Target
: in out List
;
2097 Before
: Count_Type
;
2098 Source
: in out List
)
2100 N
: Node_Array
renames Source
.Nodes
;
2104 -- This implements the corresponding Splice operation, after the
2105 -- parameters have been vetted, and corner-cases disposed of.
2107 pragma Assert
(Target
'Address /= Source
'Address);
2108 pragma Assert
(Source
.Length
> 0);
2109 pragma Assert
(Source
.First
/= 0);
2110 pragma Assert
(N
(Source
.First
).Prev
= 0);
2111 pragma Assert
(Source
.Last
/= 0);
2112 pragma Assert
(N
(Source
.Last
).Next
= 0);
2113 pragma Assert
(Target
.Length
<= Count_Type
'Last - Source
.Length
);
2114 pragma Assert
(Target
.Length
+ Source
.Length
<= Target
.Capacity
);
2116 while Source
.Length
> 1 loop
2117 -- Copy first element of Source onto Target
2119 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2120 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2122 -- Unlink the first node from Source
2125 pragma Assert
(N
(N
(X
).Next
).Prev
= X
);
2127 Source
.First
:= N
(X
).Next
;
2128 N
(Source
.First
).Prev
:= 0;
2130 Source
.Length
:= Source
.Length
- 1;
2132 -- Return the Source node to its free store
2137 -- Copy first (and only remaining) element of Source onto Target
2139 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2140 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2142 -- Unlink the node from Source
2145 pragma Assert
(X
= Source
.Last
);
2152 -- Return the Source node to its free store
2155 end Splice_Internal
;
2157 procedure Splice_Internal
2158 (Target
: in out List
;
2159 Before
: Count_Type
; -- node of Target
2160 Source
: in out List
;
2161 Src_Pos
: Count_Type
; -- node of Source
2162 Tgt_Pos
: out Count_Type
)
2164 N
: Node_Array
renames Source
.Nodes
;
2167 -- This implements the corresponding Splice operation, after the
2168 -- parameters have been vetted, and corner-cases handled.
2170 pragma Assert
(Target
'Address /= Source
'Address);
2171 pragma Assert
(Target
.Length
< Target
.Capacity
);
2172 pragma Assert
(Source
.Length
> 0);
2173 pragma Assert
(Source
.First
/= 0);
2174 pragma Assert
(N
(Source
.First
).Prev
= 0);
2175 pragma Assert
(Source
.Last
/= 0);
2176 pragma Assert
(N
(Source
.Last
).Next
= 0);
2177 pragma Assert
(Src_Pos
/= 0);
2179 Allocate
(Target
, N
(Src_Pos
).Element
, New_Node
=> Tgt_Pos
);
2180 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> Tgt_Pos
);
2182 if Source
.Length
= 1 then
2183 pragma Assert
(Source
.First
= Source
.Last
);
2184 pragma Assert
(Src_Pos
= Source
.First
);
2189 elsif Src_Pos
= Source
.First
then
2190 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2192 Source
.First
:= N
(Src_Pos
).Next
;
2193 N
(Source
.First
).Prev
:= 0;
2195 elsif Src_Pos
= Source
.Last
then
2196 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2198 Source
.Last
:= N
(Src_Pos
).Prev
;
2199 N
(Source
.Last
).Next
:= 0;
2202 pragma Assert
(Source
.Length
>= 3);
2203 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2204 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2206 N
(N
(Src_Pos
).Next
).Prev
:= N
(Src_Pos
).Prev
;
2207 N
(N
(Src_Pos
).Prev
).Next
:= N
(Src_Pos
).Next
;
2210 Source
.Length
:= Source
.Length
- 1;
2211 Free
(Source
, Src_Pos
);
2212 end Splice_Internal
;
2219 (Container
: in out List
;
2224 raise Constraint_Error
with "I cursor has no element";
2228 raise Constraint_Error
with "J cursor has no element";
2231 if I
.Container
/= Container
'Unchecked_Access then
2232 raise Program_Error
with "I cursor designates wrong container";
2235 if J
.Container
/= Container
'Unchecked_Access then
2236 raise Program_Error
with "J cursor designates wrong container";
2239 if I
.Node
= J
.Node
then
2243 if Container
.Lock
> 0 then
2244 raise Program_Error
with
2245 "attempt to tamper with elements (list is locked)";
2248 pragma Assert
(Vet
(I
), "bad I cursor in Swap");
2249 pragma Assert
(Vet
(J
), "bad J cursor in Swap");
2252 EI
: Element_Type
renames Container
.Nodes
(I
.Node
).Element
;
2253 EJ
: Element_Type
renames Container
.Nodes
(J
.Node
).Element
;
2255 EI_Copy
: constant Element_Type
:= EI
;
2267 procedure Swap_Links
2268 (Container
: in out List
;
2273 raise Constraint_Error
with "I cursor has no element";
2277 raise Constraint_Error
with "J cursor has no element";
2280 if I
.Container
/= Container
'Unrestricted_Access then
2281 raise Program_Error
with "I cursor designates wrong container";
2284 if J
.Container
/= Container
'Unrestricted_Access then
2285 raise Program_Error
with "J cursor designates wrong container";
2288 if I
.Node
= J
.Node
then
2292 if Container
.Busy
> 0 then
2293 raise Program_Error
with
2294 "attempt to tamper with cursors (list is busy)";
2297 pragma Assert
(Vet
(I
), "bad I cursor in Swap_Links");
2298 pragma Assert
(Vet
(J
), "bad J cursor in Swap_Links");
2301 I_Next
: constant Cursor
:= Next
(I
);
2305 Splice
(Container
, Before
=> I
, Position
=> J
);
2309 J_Next
: constant Cursor
:= Next
(J
);
2313 Splice
(Container
, Before
=> J
, Position
=> I
);
2316 pragma Assert
(Container
.Length
>= 3);
2318 Splice
(Container
, Before
=> I_Next
, Position
=> J
);
2319 Splice
(Container
, Before
=> J_Next
, Position
=> I
);
2326 --------------------
2327 -- Update_Element --
2328 --------------------
2330 procedure Update_Element
2331 (Container
: in out List
;
2333 Process
: not null access procedure (Element
: in out Element_Type
))
2336 if Position
.Node
= 0 then
2337 raise Constraint_Error
with "Position cursor has no element";
2340 if Position
.Container
/= Container
'Unchecked_Access then
2341 raise Program_Error
with
2342 "Position cursor designates wrong container";
2345 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
2348 B
: Natural renames Container
.Busy
;
2349 L
: Natural renames Container
.Lock
;
2356 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
2358 Process
(N
.Element
);
2375 function Vet
(Position
: Cursor
) return Boolean is
2377 if Position
.Node
= 0 then
2378 return Position
.Container
= null;
2381 if Position
.Container
= null then
2386 L
: List
renames Position
.Container
.all;
2387 N
: Node_Array
renames L
.Nodes
;
2390 if L
.Length
= 0 then
2394 if L
.First
= 0 or L
.First
> L
.Capacity
then
2398 if L
.Last
= 0 or L
.Last
> L
.Capacity
then
2402 if N
(L
.First
).Prev
/= 0 then
2406 if N
(L
.Last
).Next
/= 0 then
2410 if Position
.Node
> L
.Capacity
then
2414 -- An invariant of an active node is that its Previous and Next
2415 -- components are non-negative. Operation Free sets the Previous
2416 -- component of the node to the value -1 before actually deallocating
2417 -- the node, to mark the node as inactive. (By "dellocating" we mean
2418 -- only that the node is linked onto a list of inactive nodes used
2419 -- for storage.) This marker gives us a simple way to detect a
2420 -- dangling reference to a node.
2422 if N
(Position
.Node
).Prev
< 0 then -- see Free
2426 if N
(Position
.Node
).Prev
> L
.Capacity
then
2430 if N
(Position
.Node
).Next
= Position
.Node
then
2434 if N
(Position
.Node
).Prev
= Position
.Node
then
2438 if N
(Position
.Node
).Prev
= 0
2439 and then Position
.Node
/= L
.First
2444 pragma Assert
(N
(Position
.Node
).Prev
/= 0
2445 or else Position
.Node
= L
.First
);
2447 if N
(Position
.Node
).Next
= 0
2448 and then Position
.Node
/= L
.Last
2453 pragma Assert
(N
(Position
.Node
).Next
/= 0
2454 or else Position
.Node
= L
.Last
);
2456 if L
.Length
= 1 then
2457 return L
.First
= L
.Last
;
2460 if L
.First
= L
.Last
then
2464 if N
(L
.First
).Next
= 0 then
2468 if N
(L
.Last
).Prev
= 0 then
2472 if N
(N
(L
.First
).Next
).Prev
/= L
.First
then
2476 if N
(N
(L
.Last
).Prev
).Next
/= L
.Last
then
2480 if L
.Length
= 2 then
2481 if N
(L
.First
).Next
/= L
.Last
then
2485 if N
(L
.Last
).Prev
/= L
.First
then
2492 if N
(L
.First
).Next
= L
.Last
then
2496 if N
(L
.Last
).Prev
= L
.First
then
2500 -- Eliminate earlier possibility
2502 if Position
.Node
= L
.First
then
2506 pragma Assert
(N
(Position
.Node
).Prev
/= 0);
2508 -- Eliminate another possibility
2510 if Position
.Node
= L
.Last
then
2514 pragma Assert
(N
(Position
.Node
).Next
/= 0);
2516 if N
(N
(Position
.Node
).Next
).Prev
/= Position
.Node
then
2520 if N
(N
(Position
.Node
).Prev
).Next
/= Position
.Node
then
2524 if L
.Length
= 3 then
2525 if N
(L
.First
).Next
/= Position
.Node
then
2529 if N
(L
.Last
).Prev
/= Position
.Node
then
2543 (Stream
: not null access Root_Stream_Type
'Class;
2549 Count_Type
'Base'Write (Stream, Item.Length);
2552 while Node /= 0 loop
2553 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2554 Node := Item.Nodes (Node).Next;
2559 (Stream : not null access Root_Stream_Type'Class;
2563 raise Program_Error with "attempt to stream list cursor";
2567 (Stream : not null access Root_Stream_Type'Class;
2568 Item : Reference_Type)
2571 raise Program_Error with "attempt to stream reference";
2575 (Stream : not null access Root_Stream_Type'Class;
2576 Item : Constant_Reference_Type)
2579 raise Program_Error with "attempt to stream reference";
2582 end Ada.Containers.Bounded_Doubly_Linked_Lists;