1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.BOUNDED_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2004-2014, 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 pragma Annotate
(CodePeer
, Skip_Analysis
);
36 -----------------------
37 -- Local Subprograms --
38 -----------------------
41 (Container
: in out List
;
42 New_Item
: Element_Type
;
43 New_Node
: out Count_Type
);
46 (Container
: in out List
;
47 Stream
: not null access Root_Stream_Type
'Class;
48 New_Node
: out Count_Type
);
51 (Container
: in out List
;
54 procedure Insert_Internal
55 (Container
: in out List
;
57 New_Node
: Count_Type
);
59 procedure Splice_Internal
60 (Target
: in out List
;
62 Source
: in out List
);
64 procedure Splice_Internal
65 (Target
: in out List
;
69 Tgt_Pos
: out Count_Type
);
71 function Vet
(Position
: Cursor
) return Boolean;
72 -- Checks invariants of the cursor and its designated container, as a
73 -- simple way of detecting dangling references (see operation Free for a
74 -- description of the detection mechanism), returning True if all checks
75 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
76 -- so the checks are performed only when assertions are enabled.
82 function "=" (Left
, Right
: List
) return Boolean is
83 BL
: Natural renames Left
'Unrestricted_Access.Busy
;
84 LL
: Natural renames Left
'Unrestricted_Access.Lock
;
86 BR
: Natural renames Right
'Unrestricted_Access.Busy
;
87 LR
: Natural renames Right
'Unrestricted_Access.Lock
;
89 LN
: Node_Array
renames Left
.Nodes
;
90 RN
: Node_Array
renames Right
.Nodes
;
98 if Left
'Address = Right
'Address then
102 if Left
.Length
/= Right
.Length
then
106 -- Per AI05-0022, the container implementation is required to detect
107 -- element tampering by a generic actual subprogram.
118 for J
in 1 .. Left
.Length
loop
119 if LN
(LI
).Element
/= RN
(RI
).Element
then
152 (Container
: in out List
;
153 New_Item
: Element_Type
;
154 New_Node
: out Count_Type
)
156 N
: Node_Array
renames Container
.Nodes
;
159 if Container
.Free
>= 0 then
160 New_Node
:= Container
.Free
;
162 -- We always perform the assignment first, before we change container
163 -- state, in order to defend against exceptions duration assignment.
165 N
(New_Node
).Element
:= New_Item
;
166 Container
.Free
:= N
(New_Node
).Next
;
169 -- A negative free store value means that the links of the nodes in
170 -- the free store have not been initialized. In this case, the nodes
171 -- are physically contiguous in the array, starting at the index that
172 -- is the absolute value of the Container.Free, and continuing until
173 -- the end of the array (Nodes'Last).
175 New_Node
:= abs Container
.Free
;
177 -- As above, we perform this assignment first, before modifying any
180 N
(New_Node
).Element
:= New_Item
;
181 Container
.Free
:= Container
.Free
- 1;
186 (Container
: in out List
;
187 Stream
: not null access Root_Stream_Type
'Class;
188 New_Node
: out Count_Type
)
190 N
: Node_Array
renames Container
.Nodes
;
193 if Container
.Free
>= 0 then
194 New_Node
:= Container
.Free
;
196 -- We always perform the assignment first, before we change container
197 -- state, in order to defend against exceptions duration assignment.
199 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
200 Container
.Free
:= N
(New_Node
).Next
;
203 -- A negative free store value means that the links of the nodes in
204 -- the free store have not been initialized. In this case, the nodes
205 -- are physically contiguous in the array, starting at the index that
206 -- is the absolute value of the Container.Free, and continuing until
207 -- the end of the array (Nodes'Last).
209 New_Node
:= abs Container
.Free
;
211 -- As above, we perform this assignment first, before modifying any
214 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
215 Container
.Free
:= Container
.Free
- 1;
224 (Container
: in out List
;
225 New_Item
: Element_Type
;
226 Count
: Count_Type
:= 1)
229 Insert
(Container
, No_Element
, New_Item
, Count
);
236 procedure Adjust
(Control
: in out Reference_Control_Type
) is
238 if Control
.Container
/= null then
240 C
: List
renames Control
.Container
.all;
241 B
: Natural renames C
.Busy
;
242 L
: Natural renames C
.Lock
;
254 procedure Assign
(Target
: in out List
; Source
: List
) is
255 SN
: Node_Array
renames Source
.Nodes
;
259 if Target
'Address = Source
'Address then
263 if Target
.Capacity
< Source
.Length
then
264 raise Capacity_Error
-- ???
265 with "Target capacity is less than Source length";
272 Target
.Append
(SN
(J
).Element
);
281 procedure Clear
(Container
: in out List
) is
282 N
: Node_Array
renames Container
.Nodes
;
286 if Container
.Length
= 0 then
287 pragma Assert
(Container
.First
= 0);
288 pragma Assert
(Container
.Last
= 0);
289 pragma Assert
(Container
.Busy
= 0);
290 pragma Assert
(Container
.Lock
= 0);
294 pragma Assert
(Container
.First
>= 1);
295 pragma Assert
(Container
.Last
>= 1);
296 pragma Assert
(N
(Container
.First
).Prev
= 0);
297 pragma Assert
(N
(Container
.Last
).Next
= 0);
299 if Container
.Busy
> 0 then
300 raise Program_Error
with
301 "attempt to tamper with cursors (list is busy)";
304 while Container
.Length
> 1 loop
305 X
:= Container
.First
;
306 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
308 Container
.First
:= N
(X
).Next
;
309 N
(Container
.First
).Prev
:= 0;
311 Container
.Length
:= Container
.Length
- 1;
316 X
:= Container
.First
;
317 pragma Assert
(X
= Container
.Last
);
319 Container
.First
:= 0;
321 Container
.Length
:= 0;
326 ------------------------
327 -- Constant_Reference --
328 ------------------------
330 function Constant_Reference
331 (Container
: aliased List
;
332 Position
: Cursor
) return Constant_Reference_Type
335 if Position
.Container
= null then
336 raise Constraint_Error
with "Position cursor has no element";
338 elsif Position
.Container
/= Container
'Unrestricted_Access then
339 raise Program_Error
with
340 "Position cursor designates wrong container";
343 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
346 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
347 B
: Natural renames Position
.Container
.Busy
;
348 L
: Natural renames Position
.Container
.Lock
;
350 return R
: constant Constant_Reference_Type
:=
351 (Element
=> N
.Element
'Access,
352 Control
=> (Controlled
with Container
'Unrestricted_Access))
359 end Constant_Reference
;
367 Item
: Element_Type
) return Boolean
370 return Find
(Container
, Item
) /= No_Element
;
377 function Copy
(Source
: List
; Capacity
: Count_Type
:= 0) return List
is
383 elsif Capacity
>= Source
.Length
then
386 raise Capacity_Error
with "Capacity value too small";
389 return Target
: List
(Capacity
=> C
) do
390 Assign
(Target
=> Target
, Source
=> Source
);
399 (Container
: in out List
;
400 Position
: in out Cursor
;
401 Count
: Count_Type
:= 1)
403 N
: Node_Array
renames Container
.Nodes
;
407 if Position
.Node
= 0 then
408 raise Constraint_Error
with
409 "Position cursor has no element";
412 if Position
.Container
/= Container
'Unrestricted_Access then
413 raise Program_Error
with
414 "Position cursor designates wrong container";
417 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
418 pragma Assert
(Container
.First
>= 1);
419 pragma Assert
(Container
.Last
>= 1);
420 pragma Assert
(N
(Container
.First
).Prev
= 0);
421 pragma Assert
(N
(Container
.Last
).Next
= 0);
423 if Position
.Node
= Container
.First
then
424 Delete_First
(Container
, Count
);
425 Position
:= No_Element
;
430 Position
:= No_Element
;
434 if Container
.Busy
> 0 then
435 raise Program_Error
with
436 "attempt to tamper with cursors (list is busy)";
439 for Index
in 1 .. Count
loop
440 pragma Assert
(Container
.Length
>= 2);
443 Container
.Length
:= Container
.Length
- 1;
445 if X
= Container
.Last
then
446 Position
:= No_Element
;
448 Container
.Last
:= N
(X
).Prev
;
449 N
(Container
.Last
).Next
:= 0;
455 Position
.Node
:= N
(X
).Next
;
457 N
(N
(X
).Next
).Prev
:= N
(X
).Prev
;
458 N
(N
(X
).Prev
).Next
:= N
(X
).Next
;
463 Position
:= No_Element
;
470 procedure Delete_First
471 (Container
: in out List
;
472 Count
: Count_Type
:= 1)
474 N
: Node_Array
renames Container
.Nodes
;
478 if Count
>= Container
.Length
then
487 if Container
.Busy
> 0 then
488 raise Program_Error
with
489 "attempt to tamper with cursors (list is busy)";
492 for J
in 1 .. Count
loop
493 X
:= Container
.First
;
494 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
496 Container
.First
:= N
(X
).Next
;
497 N
(Container
.First
).Prev
:= 0;
499 Container
.Length
:= Container
.Length
- 1;
509 procedure Delete_Last
510 (Container
: in out List
;
511 Count
: Count_Type
:= 1)
513 N
: Node_Array
renames Container
.Nodes
;
517 if Count
>= Container
.Length
then
526 if Container
.Busy
> 0 then
527 raise Program_Error
with
528 "attempt to tamper with cursors (list is busy)";
531 for J
in 1 .. Count
loop
533 pragma Assert
(N
(N
(X
).Prev
).Next
= Container
.Last
);
535 Container
.Last
:= N
(X
).Prev
;
536 N
(Container
.Last
).Next
:= 0;
538 Container
.Length
:= Container
.Length
- 1;
548 function Element
(Position
: Cursor
) return Element_Type
is
550 if Position
.Node
= 0 then
551 raise Constraint_Error
with
552 "Position cursor has no element";
555 pragma Assert
(Vet
(Position
), "bad cursor in Element");
557 return Position
.Container
.Nodes
(Position
.Node
).Element
;
565 procedure Finalize
(Object
: in out Iterator
) is
567 if Object
.Container
/= null then
569 B
: Natural renames Object
.Container
.all.Busy
;
576 procedure Finalize
(Control
: in out Reference_Control_Type
) is
578 if Control
.Container
/= null then
580 C
: List
renames Control
.Container
.all;
581 B
: Natural renames C
.Busy
;
582 L
: Natural renames C
.Lock
;
588 Control
.Container
:= null;
599 Position
: Cursor
:= No_Element
) return Cursor
601 Nodes
: Node_Array
renames Container
.Nodes
;
602 Node
: Count_Type
:= Position
.Node
;
606 Node
:= Container
.First
;
609 if Position
.Container
/= Container
'Unrestricted_Access then
610 raise Program_Error
with
611 "Position cursor designates wrong container";
614 pragma Assert
(Vet
(Position
), "bad cursor in Find");
617 -- Per AI05-0022, the container implementation is required to detect
618 -- element tampering by a generic actual subprogram.
621 B
: Natural renames Container
'Unrestricted_Access.Busy
;
622 L
: Natural renames Container
'Unrestricted_Access.Lock
;
632 if Nodes
(Node
).Element
= Item
then
637 Node
:= Nodes
(Node
).Next
;
646 return Cursor
'(Container'Unrestricted_Access, Result);
661 function First (Container : List) return Cursor is
663 if Container.First = 0 then
666 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
670 function First
(Object
: Iterator
) return Cursor
is
672 -- The value of the iterator object's Node component influences the
673 -- behavior of the First (and Last) selector function.
675 -- When the Node component is 0, this means the iterator object was
676 -- constructed without a start expression, in which case the (forward)
677 -- iteration starts from the (logical) beginning of the entire sequence
678 -- of items (corresponding to Container.First, for a forward iterator).
680 -- Otherwise, this is iteration over a partial sequence of items. When
681 -- the Node component is positive, the iterator object was constructed
682 -- with a start expression, that specifies the position from which the
683 -- (forward) partial iteration begins.
685 if Object
.Node
= 0 then
686 return Bounded_Doubly_Linked_Lists
.First
(Object
.Container
.all);
688 return Cursor
'(Object.Container, Object.Node);
696 function First_Element (Container : List) return Element_Type is
698 if Container.First = 0 then
699 raise Constraint_Error with "list is empty";
701 return Container.Nodes (Container.First).Element;
710 (Container : in out List;
713 pragma Assert (X > 0);
714 pragma Assert (X <= Container.Capacity);
716 N : Node_Array renames Container.Nodes;
717 pragma Assert (N (X).Prev >= 0); -- node is active
720 -- The list container actually contains two lists: one for the "active"
721 -- nodes that contain elements that have been inserted onto the list,
722 -- and another for the "inactive" nodes for the free store.
724 -- We desire that merely declaring an object should have only minimal
725 -- cost; specially, we want to avoid having to initialize the free
726 -- store (to fill in the links), especially if the capacity is large.
728 -- The head of the free list is indicated by Container.Free. If its
729 -- value is non-negative, then the free store has been initialized in
730 -- the "normal" way: Container.Free points to the head of the list of
731 -- free (inactive) nodes, and the value 0 means the free list is empty.
732 -- Each node on the free list has been initialized to point to the next
733 -- free node (via its Next component), and the value 0 means that this
734 -- is the last free node.
736 -- If Container.Free is negative, then the links on the free store have
737 -- not been initialized. In this case the link values are implied: the
738 -- free store comprises the components of the node array started with
739 -- the absolute value of Container.Free, and continuing until the end of
740 -- the array (Nodes'Last).
742 -- If the list container is manipulated on one end only (for example if
743 -- the container were being used as a stack), then there is no need to
744 -- initialize the free store, since the inactive nodes are physically
745 -- contiguous (in fact, they lie immediately beyond the logical end
746 -- being manipulated). The only time we need to actually initialize the
747 -- nodes in the free store is if the node that becomes inactive is not
748 -- at the end of the list. The free store would then be discontiguous
749 -- and so its nodes would need to be linked in the traditional way.
752 -- It might be possible to perform an optimization here. Suppose that
753 -- the free store can be represented as having two parts: one comprising
754 -- the non-contiguous inactive nodes linked together in the normal way,
755 -- and the other comprising the contiguous inactive nodes (that are not
756 -- linked together, at the end of the nodes array). This would allow us
757 -- to never have to initialize the free store, except in a lazy way as
758 -- nodes become inactive.
760 -- When an element is deleted from the list container, its node becomes
761 -- inactive, and so we set its Prev component to a negative value, to
762 -- indicate that it is now inactive. This provides a useful way to
763 -- detect a dangling cursor reference (and which is used in Vet).
765 N (X).Prev := -1; -- Node is deallocated (not on active list)
767 if Container.Free >= 0 then
769 -- The free store has previously been initialized. All we need to
770 -- do here is link the newly-free'd node onto the free list.
772 N (X).Next := Container.Free;
775 elsif X + 1 = abs Container.Free then
777 -- The free store has not been initialized, and the node becoming
778 -- inactive immediately precedes the start of the free store. All
779 -- we need to do is move the start of the free store back by one.
781 -- Note: initializing Next to zero is not strictly necessary but
782 -- seems cleaner and marginally safer.
785 Container.Free := Container.Free + 1;
788 -- The free store has not been initialized, and the node becoming
789 -- inactive does not immediately precede the free store. Here we
790 -- first initialize the free store (meaning the links are given
791 -- values in the traditional way), and then link the newly-free'd
792 -- node onto the head of the free store.
795 -- See the comments above for an optimization opportunity. If the
796 -- next link for a node on the free store is negative, then this
797 -- means the remaining nodes on the free store are physically
798 -- contiguous, starting as the absolute value of that index value.
800 Container.Free := abs Container.Free;
802 if Container.Free > Container.Capacity then
806 for I in Container.Free .. Container.Capacity - 1 loop
810 N (Container.Capacity).Next := 0;
813 N (X).Next := Container.Free;
818 ---------------------
819 -- Generic_Sorting --
820 ---------------------
822 package body Generic_Sorting is
828 function Is_Sorted (Container : List) return Boolean is
829 B : Natural renames Container'Unrestricted_Access.Busy;
830 L : Natural renames Container'Unrestricted_Access.Lock;
832 Nodes : Node_Array renames Container.Nodes;
838 -- Per AI05-0022, the container implementation is required to detect
839 -- element tampering by a generic actual subprogram.
844 Node := Container.First;
846 for J in 2 .. Container.Length loop
847 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
852 Node := Nodes (Node).Next;
872 (Target : in out List;
873 Source : in out List)
876 -- The semantics of Merge changed slightly per AI05-0021. It was
877 -- originally the case that if Target and Source denoted the same
878 -- container object, then the GNAT implementation of Merge did
879 -- nothing. However, it was argued that RM05 did not precisely
880 -- specify the semantics for this corner case. The decision of the
881 -- ARG was that if Target and Source denote the same non-empty
882 -- container object, then Program_Error is raised.
884 if Source.Is_Empty then
888 if Target'Address = Source'Address then
889 raise Program_Error with
890 "Target and Source denote same non-empty container";
893 if Target.Length > Count_Type'Last - Source.Length then
894 raise Constraint_Error with "new length exceeds maximum";
897 if Target.Length + Source.Length > Target.Capacity then
898 raise Capacity_Error with "new length exceeds target capacity";
901 if Target.Busy > 0 then
902 raise Program_Error with
903 "attempt to tamper with cursors of Target (list is busy)";
906 if Source.Busy > 0 then
907 raise Program_Error with
908 "attempt to tamper with cursors of Source (list is busy)";
911 -- Per AI05-0022, the container implementation is required to detect
912 -- element tampering by a generic actual subprogram.
915 TB : Natural renames Target.Busy;
916 TL : Natural renames Target.Lock;
918 SB : Natural renames Source.Busy;
919 SL : Natural renames Source.Lock;
921 LN : Node_Array renames Target.Nodes;
922 RN : Node_Array renames Source.Nodes;
924 LI, LJ, RI, RJ : Count_Type;
936 pragma Assert (RN (RI).Next = 0
937 or else not (RN (RN (RI).Next).Element <
941 Splice_Internal (Target, 0, Source);
945 pragma Assert (LN (LI).Next = 0
946 or else not (LN (LN (LI).Next).Element <
949 if RN (RI).Element < LN (LI).Element then
952 Splice_Internal (Target, LI, Source, RJ, LJ);
981 procedure Sort (Container : in out List) is
982 N : Node_Array renames Container.Nodes;
984 procedure Partition (Pivot, Back : Count_Type);
985 -- What does this do ???
987 procedure Sort (Front, Back : Count_Type);
988 -- Internal procedure, what does it do??? rename it???
994 procedure Partition (Pivot, Back : Count_Type) is
998 Node := N (Pivot).Next;
999 while Node /= Back loop
1000 if N (Node).Element < N (Pivot).Element then
1002 Prev : constant Count_Type := N (Node).Prev;
1003 Next : constant Count_Type := N (Node).Next;
1006 N (Prev).Next := Next;
1009 Container.Last := Prev;
1011 N (Next).Prev := Prev;
1014 N (Node).Next := Pivot;
1015 N (Node).Prev := N (Pivot).Prev;
1017 N (Pivot).Prev := Node;
1019 if N (Node).Prev = 0 then
1020 Container.First := Node;
1022 N (N (Node).Prev).Next := Node;
1029 Node := N (Node).Next;
1038 procedure Sort (Front, Back : Count_Type) is
1039 Pivot : constant Count_Type :=
1040 (if Front = 0 then Container.First else N (Front).Next);
1042 if Pivot /= Back then
1043 Partition (Pivot, Back);
1044 Sort (Front, Pivot);
1049 -- Start of processing for Sort
1052 if Container.Length <= 1 then
1056 pragma Assert (N (Container.First).Prev = 0);
1057 pragma Assert (N (Container.Last).Next = 0);
1059 if Container.Busy > 0 then
1060 raise Program_Error with
1061 "attempt to tamper with cursors (list is busy)";
1064 -- Per AI05-0022, the container implementation is required to detect
1065 -- element tampering by a generic actual subprogram.
1068 B : Natural renames Container.Busy;
1069 L : Natural renames Container.Lock;
1075 Sort (Front => 0, Back => 0);
1087 pragma Assert (N (Container.First).Prev = 0);
1088 pragma Assert (N (Container.Last).Next = 0);
1091 end Generic_Sorting;
1097 function Has_Element (Position : Cursor) return Boolean is
1099 pragma Assert (Vet (Position), "bad cursor in Has_Element");
1100 return Position.Node /= 0;
1108 (Container : in out List;
1110 New_Item : Element_Type;
1111 Position : out Cursor;
1112 Count : Count_Type := 1)
1114 First_Node : Count_Type;
1115 New_Node : Count_Type;
1118 if Before.Container /= null then
1119 if Before.Container /= Container'Unrestricted_Access then
1120 raise Program_Error with
1121 "Before cursor designates wrong list";
1124 pragma Assert (Vet (Before), "bad cursor in Insert");
1132 if Container.Length > Container.Capacity - Count then
1133 raise Capacity_Error with "capacity exceeded";
1136 if Container.Busy > 0 then
1137 raise Program_Error with
1138 "attempt to tamper with cursors (list is busy)";
1141 Allocate (Container, New_Item, New_Node);
1142 First_Node := New_Node;
1143 Insert_Internal (Container, Before.Node, New_Node);
1145 for Index in Count_Type'(2) .. Count
loop
1146 Allocate
(Container
, New_Item
, New_Node
);
1147 Insert_Internal
(Container
, Before
.Node
, New_Node
);
1150 Position
:= Cursor
'(Container'Unchecked_Access, First_Node);
1154 (Container : in out List;
1156 New_Item : Element_Type;
1157 Count : Count_Type := 1)
1160 pragma Unreferenced (Position);
1162 Insert (Container, Before, New_Item, Position, Count);
1166 (Container : in out List;
1168 Position : out Cursor;
1169 Count : Count_Type := 1)
1171 New_Item : Element_Type;
1172 pragma Unmodified (New_Item);
1173 -- OK to reference, see below
1176 -- There is no explicit element provided, but in an instance the element
1177 -- type may be a scalar with a Default_Value aspect, or a composite
1178 -- type with such a scalar component, or components with default
1179 -- initialization, so insert the specified number of possibly
1180 -- initialized elements at the given position.
1182 Insert (Container, Before, New_Item, Position, Count);
1185 ---------------------
1186 -- Insert_Internal --
1187 ---------------------
1189 procedure Insert_Internal
1190 (Container : in out List;
1191 Before : Count_Type;
1192 New_Node : Count_Type)
1194 N : Node_Array renames Container.Nodes;
1197 if Container.Length = 0 then
1198 pragma Assert (Before = 0);
1199 pragma Assert (Container.First = 0);
1200 pragma Assert (Container.Last = 0);
1202 Container.First := New_Node;
1203 N (Container.First).Prev := 0;
1205 Container.Last := New_Node;
1206 N (Container.Last).Next := 0;
1208 -- Before = zero means append
1210 elsif Before = 0 then
1211 pragma Assert (N (Container.Last).Next = 0);
1213 N (Container.Last).Next := New_Node;
1214 N (New_Node).Prev := Container.Last;
1216 Container.Last := New_Node;
1217 N (Container.Last).Next := 0;
1219 -- Before = Container.First means prepend
1221 elsif Before = Container.First then
1222 pragma Assert (N (Container.First).Prev = 0);
1224 N (Container.First).Prev := New_Node;
1225 N (New_Node).Next := Container.First;
1227 Container.First := New_Node;
1228 N (Container.First).Prev := 0;
1231 pragma Assert (N (Container.First).Prev = 0);
1232 pragma Assert (N (Container.Last).Next = 0);
1234 N (New_Node).Next := Before;
1235 N (New_Node).Prev := N (Before).Prev;
1237 N (N (Before).Prev).Next := New_Node;
1238 N (Before).Prev := New_Node;
1241 Container.Length := Container.Length + 1;
1242 end Insert_Internal;
1248 function Is_Empty (Container : List) return Boolean is
1250 return Container.Length = 0;
1259 Process : not null access procedure (Position : Cursor))
1261 B : Natural renames Container'Unrestricted_Access.all.Busy;
1262 Node : Count_Type := Container.First;
1268 while Node /= 0 loop
1269 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1270 Node
:= Container
.Nodes
(Node
).Next
;
1283 return List_Iterator_Interfaces
.Reversible_Iterator
'Class
1285 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1288 -- The value of the Node component influences the behavior of the First
1289 -- and Last selector functions of the iterator object. When the Node
1290 -- component is 0 (as is the case here), this means the iterator
1291 -- object was constructed without a start expression. This is a
1292 -- complete iterator, meaning that the iteration starts from the
1293 -- (logical) beginning of the sequence of items.
1295 -- Note: For a forward iterator, Container.First is the beginning, and
1296 -- for a reverse iterator, Container.Last is the beginning.
1298 return It
: constant Iterator
:=
1299 Iterator
'(Limited_Controlled with
1300 Container => Container'Unrestricted_Access,
1310 return List_Iterator_Interfaces.Reversible_Iterator'class
1312 B : Natural renames Container'Unrestricted_Access.all.Busy;
1315 -- It was formerly the case that when Start = No_Element, the partial
1316 -- iterator was defined to behave the same as for a complete iterator,
1317 -- and iterate over the entire sequence of items. However, those
1318 -- semantics were unintuitive and arguably error-prone (it is too easy
1319 -- to accidentally create an endless loop), and so they were changed,
1320 -- per the ARG meeting in Denver on 2011/11. However, there was no
1321 -- consensus about what positive meaning this corner case should have,
1322 -- and so it was decided to simply raise an exception. This does imply,
1323 -- however, that it is not possible to use a partial iterator to specify
1324 -- an empty sequence of items.
1326 if Start = No_Element then
1327 raise Constraint_Error with
1328 "Start position for iterator equals No_Element";
1331 if Start.Container /= Container'Unrestricted_Access then
1332 raise Program_Error with
1333 "Start cursor of Iterate designates wrong list";
1336 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1338 -- The value of the Node component influences the behavior of the First
1339 -- and Last selector functions of the iterator object. When the Node
1340 -- component is positive (as is the case here), it means that this
1341 -- is a partial iteration, over a subset of the complete sequence of
1342 -- items. The iterator object was constructed with a start expression,
1343 -- indicating the position from which the iteration begins. Note that
1344 -- the start position has the same value irrespective of whether this
1345 -- is a forward or reverse iteration.
1347 return It : constant Iterator :=
1348 Iterator'(Limited_Controlled
with
1349 Container
=> Container
'Unrestricted_Access,
1360 function Last
(Container
: List
) return Cursor
is
1362 if Container
.Last
= 0 then
1365 return Cursor
'(Container'Unrestricted_Access, Container.Last);
1369 function Last (Object : Iterator) return Cursor is
1371 -- The value of the iterator object's Node component influences the
1372 -- behavior of the Last (and First) selector function.
1374 -- When the Node component is 0, this means the iterator object was
1375 -- constructed without a start expression, in which case the (reverse)
1376 -- iteration starts from the (logical) beginning of the entire sequence
1377 -- (corresponding to Container.Last, for a reverse iterator).
1379 -- Otherwise, this is iteration over a partial sequence of items. When
1380 -- the Node component is positive, the iterator object was constructed
1381 -- with a start expression, that specifies the position from which the
1382 -- (reverse) partial iteration begins.
1384 if Object.Node = 0 then
1385 return Bounded_Doubly_Linked_Lists.Last (Object.Container.all);
1387 return Cursor'(Object
.Container
, Object
.Node
);
1395 function Last_Element
(Container
: List
) return Element_Type
is
1397 if Container
.Last
= 0 then
1398 raise Constraint_Error
with "list is empty";
1400 return Container
.Nodes
(Container
.Last
).Element
;
1408 function Length
(Container
: List
) return Count_Type
is
1410 return Container
.Length
;
1418 (Target
: in out List
;
1419 Source
: in out List
)
1421 N
: Node_Array
renames Source
.Nodes
;
1425 if Target
'Address = Source
'Address then
1429 if Target
.Capacity
< Source
.Length
then
1430 raise Capacity_Error
with "Source length exceeds Target capacity";
1433 if Source
.Busy
> 0 then
1434 raise Program_Error
with
1435 "attempt to tamper with cursors of Source (list is busy)";
1438 -- Clear target, note that this checks busy bits of Target
1442 while Source
.Length
> 1 loop
1443 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1444 pragma Assert
(Source
.Last
/= Source
.First
);
1445 pragma Assert
(N
(Source
.First
).Prev
= 0);
1446 pragma Assert
(N
(Source
.Last
).Next
= 0);
1448 -- Copy first element from Source to Target
1451 Append
(Target
, N
(X
).Element
);
1453 -- Unlink first node of Source
1455 Source
.First
:= N
(X
).Next
;
1456 N
(Source
.First
).Prev
:= 0;
1458 Source
.Length
:= Source
.Length
- 1;
1460 -- The representation invariants for Source have been restored. It is
1461 -- now safe to free the unlinked node, without fear of corrupting the
1462 -- active links of Source.
1464 -- Note that the algorithm we use here models similar algorithms used
1465 -- in the unbounded form of the doubly-linked list container. In that
1466 -- case, Free is an instantation of Unchecked_Deallocation, which can
1467 -- fail (because PE will be raised if controlled Finalize fails), so
1468 -- we must defer the call until the last step. Here in the bounded
1469 -- form, Free merely links the node we have just "deallocated" onto a
1470 -- list of inactive nodes, so technically Free cannot fail. However,
1471 -- for consistency, we handle Free the same way here as we do for the
1472 -- unbounded form, with the pessimistic assumption that it can fail.
1477 if Source
.Length
= 1 then
1478 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1479 pragma Assert
(Source
.Last
= Source
.First
);
1480 pragma Assert
(N
(Source
.First
).Prev
= 0);
1481 pragma Assert
(N
(Source
.Last
).Next
= 0);
1483 -- Copy element from Source to Target
1486 Append
(Target
, N
(X
).Element
);
1488 -- Unlink node of Source
1494 -- Return the unlinked node to the free store
1504 procedure Next
(Position
: in out Cursor
) is
1506 Position
:= Next
(Position
);
1509 function Next
(Position
: Cursor
) return Cursor
is
1511 if Position
.Node
= 0 then
1515 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1518 Nodes
: Node_Array
renames Position
.Container
.Nodes
;
1519 Node
: constant Count_Type
:= Nodes
(Position
.Node
).Next
;
1524 return Cursor
'(Position.Container, Node);
1531 Position : Cursor) return Cursor
1534 if Position.Container = null then
1536 elsif Position.Container /= Object.Container then
1537 raise Program_Error with
1538 "Position cursor of Next designates wrong list";
1540 return Next (Position);
1549 (Container : in out List;
1550 New_Item : Element_Type;
1551 Count : Count_Type := 1)
1554 Insert (Container, First (Container), New_Item, Count);
1561 procedure Previous (Position : in out Cursor) is
1563 Position := Previous (Position);
1566 function Previous (Position : Cursor) return Cursor is
1568 if Position.Node = 0 then
1572 pragma Assert (Vet (Position), "bad cursor in Previous");
1575 Nodes : Node_Array renames Position.Container.Nodes;
1576 Node : constant Count_Type := Nodes (Position.Node).Prev;
1581 return Cursor'(Position
.Container
, Node
);
1588 Position
: Cursor
) return Cursor
1591 if Position
.Container
= null then
1593 elsif Position
.Container
/= Object
.Container
then
1594 raise Program_Error
with
1595 "Position cursor of Previous designates wrong list";
1597 return Previous
(Position
);
1605 procedure Query_Element
1607 Process
: not null access procedure (Element
: Element_Type
))
1610 if Position
.Node
= 0 then
1611 raise Constraint_Error
with
1612 "Position cursor has no element";
1615 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1618 C
: List
renames Position
.Container
.all'Unrestricted_Access.all;
1619 B
: Natural renames C
.Busy
;
1620 L
: Natural renames C
.Lock
;
1627 N
: Node_Type
renames C
.Nodes
(Position
.Node
);
1629 Process
(N
.Element
);
1647 (Stream
: not null access Root_Stream_Type
'Class;
1650 N
: Count_Type
'Base;
1655 Count_Type
'Base'Read (Stream, N);
1658 raise Program_Error with "bad list length (corrupt stream)";
1663 elsif N > Item.Capacity then
1664 raise Constraint_Error with "length exceeds capacity";
1667 for Idx in 1 .. N loop
1668 Allocate (Item, Stream, New_Node => X);
1669 Insert_Internal (Item, Before => 0, New_Node => X);
1675 (Stream : not null access Root_Stream_Type'Class;
1679 raise Program_Error with "attempt to stream list cursor";
1683 (Stream : not null access Root_Stream_Type'Class;
1684 Item : out Reference_Type)
1687 raise Program_Error with "attempt to stream reference";
1691 (Stream : not null access Root_Stream_Type'Class;
1692 Item : out Constant_Reference_Type)
1695 raise Program_Error with "attempt to stream reference";
1703 (Container : aliased in out List;
1704 Position : Cursor) return Reference_Type
1707 if Position.Container = null then
1708 raise Constraint_Error with "Position cursor has no element";
1710 elsif Position.Container /= Container'Unrestricted_Access then
1711 raise Program_Error with
1712 "Position cursor designates wrong container";
1715 pragma Assert (Vet (Position), "bad cursor in function Reference");
1718 N : Node_Type renames Container.Nodes (Position.Node);
1719 B : Natural renames Container.Busy;
1720 L : Natural renames Container.Lock;
1722 return R : constant Reference_Type :=
1723 (Element => N.Element'Access,
1724 Control => (Controlled with Container'Unrestricted_Access))
1733 ---------------------
1734 -- Replace_Element --
1735 ---------------------
1737 procedure Replace_Element
1738 (Container : in out List;
1740 New_Item : Element_Type)
1743 if Position.Container = null then
1744 raise Constraint_Error with "Position cursor has no element";
1746 elsif Position.Container /= Container'Unchecked_Access then
1747 raise Program_Error with
1748 "Position cursor designates wrong container";
1750 elsif Container.Lock > 0 then
1751 raise Program_Error with
1752 "attempt to tamper with elements (list is locked)";
1755 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1757 Container.Nodes (Position.Node).Element := New_Item;
1759 end Replace_Element;
1761 ----------------------
1762 -- Reverse_Elements --
1763 ----------------------
1765 procedure Reverse_Elements (Container : in out List) is
1766 N : Node_Array renames Container.Nodes;
1767 I : Count_Type := Container.First;
1768 J : Count_Type := Container.Last;
1770 procedure Swap (L, R : Count_Type);
1776 procedure Swap (L, R : Count_Type) is
1777 LN : constant Count_Type := N (L).Next;
1778 LP : constant Count_Type := N (L).Prev;
1780 RN : constant Count_Type := N (R).Next;
1781 RP : constant Count_Type := N (R).Prev;
1796 pragma Assert (RP = L);
1810 -- Start of processing for Reverse_Elements
1813 if Container.Length <= 1 then
1817 pragma Assert (N (Container.First).Prev = 0);
1818 pragma Assert (N (Container.Last).Next = 0);
1820 if Container.Busy > 0 then
1821 raise Program_Error with
1822 "attempt to tamper with cursors (list is busy)";
1825 Container.First := J;
1826 Container.Last := I;
1828 Swap (L => I, R => J);
1836 Swap (L => J, R => I);
1845 pragma Assert (N (Container.First).Prev = 0);
1846 pragma Assert (N (Container.Last).Next = 0);
1847 end Reverse_Elements;
1853 function Reverse_Find
1855 Item : Element_Type;
1856 Position : Cursor := No_Element) return Cursor
1858 Node : Count_Type := Position.Node;
1862 Node := Container.Last;
1865 if Position.Container /= Container'Unrestricted_Access then
1866 raise Program_Error with
1867 "Position cursor designates wrong container";
1870 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1873 -- Per AI05-0022, the container implementation is required to detect
1874 -- element tampering by a generic actual subprogram.
1877 B : Natural renames Container'Unrestricted_Access.Busy;
1878 L : Natural renames Container'Unrestricted_Access.Lock;
1880 Result : Count_Type;
1887 while Node /= 0 loop
1888 if Container.Nodes (Node).Element = Item then
1893 Node := Container.Nodes (Node).Prev;
1902 return Cursor'(Container
'Unrestricted_Access, Result
);
1913 ---------------------
1914 -- Reverse_Iterate --
1915 ---------------------
1917 procedure Reverse_Iterate
1919 Process
: not null access procedure (Position
: Cursor
))
1921 C
: List
renames Container
'Unrestricted_Access.all;
1922 B
: Natural renames C
.Busy
;
1924 Node
: Count_Type
:= Container
.Last
;
1930 while Node
/= 0 loop
1931 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1932 Node := Container.Nodes (Node).Prev;
1941 end Reverse_Iterate;
1948 (Target : in out List;
1950 Source : in out List)
1953 if Before.Container /= null then
1954 if Before.Container /= Target'Unrestricted_Access then
1955 raise Program_Error with
1956 "Before cursor designates wrong container";
1959 pragma Assert (Vet (Before), "bad cursor in Splice");
1962 if Target'Address = Source'Address or else Source.Length = 0 then
1965 elsif Target.Length > Count_Type'Last - Source.Length then
1966 raise Constraint_Error with "new length exceeds maximum";
1968 elsif Target.Length + Source.Length > Target.Capacity then
1969 raise Capacity_Error with "new length exceeds target capacity";
1971 elsif Target.Busy > 0 then
1972 raise Program_Error with
1973 "attempt to tamper with cursors of Target (list is busy)";
1975 elsif Source.Busy > 0 then
1976 raise Program_Error with
1977 "attempt to tamper with cursors of Source (list is busy)";
1980 Splice_Internal (Target, Before.Node, Source);
1985 (Container : in out List;
1989 N : Node_Array renames Container.Nodes;
1992 if Before.Container /= null then
1993 if Before.Container /= Container'Unchecked_Access then
1994 raise Program_Error with
1995 "Before cursor designates wrong container";
1998 pragma Assert (Vet (Before), "bad Before cursor in Splice");
2001 if Position.Node = 0 then
2002 raise Constraint_Error with "Position cursor has no element";
2005 if Position.Container /= Container'Unrestricted_Access then
2006 raise Program_Error with
2007 "Position cursor designates wrong container";
2010 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2012 if Position.Node = Before.Node
2013 or else N (Position.Node).Next = Before.Node
2018 pragma Assert (Container.Length >= 2);
2020 if Container.Busy > 0 then
2021 raise Program_Error with
2022 "attempt to tamper with cursors (list is busy)";
2025 if Before.Node = 0 then
2026 pragma Assert (Position.Node /= Container.Last);
2028 if Position.Node = Container.First then
2029 Container.First := N (Position.Node).Next;
2030 N (Container.First).Prev := 0;
2032 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2033 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2036 N (Container.Last).Next := Position.Node;
2037 N (Position.Node).Prev := Container.Last;
2039 Container.Last := Position.Node;
2040 N (Container.Last).Next := 0;
2045 if Before.Node = Container.First then
2046 pragma Assert (Position.Node /= Container.First);
2048 if Position.Node = Container.Last then
2049 Container.Last := N (Position.Node).Prev;
2050 N (Container.Last).Next := 0;
2052 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2053 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2056 N (Container.First).Prev := Position.Node;
2057 N (Position.Node).Next := Container.First;
2059 Container.First := Position.Node;
2060 N (Container.First).Prev := 0;
2065 if Position.Node = Container.First then
2066 Container.First := N (Position.Node).Next;
2067 N (Container.First).Prev := 0;
2069 elsif Position.Node = Container.Last then
2070 Container.Last := N (Position.Node).Prev;
2071 N (Container.Last).Next := 0;
2074 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2075 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2078 N (N (Before.Node).Prev).Next := Position.Node;
2079 N (Position.Node).Prev := N (Before.Node).Prev;
2081 N (Before.Node).Prev := Position.Node;
2082 N (Position.Node).Next := Before.Node;
2084 pragma Assert (N (Container.First).Prev = 0);
2085 pragma Assert (N (Container.Last).Next = 0);
2089 (Target : in out List;
2091 Source : in out List;
2092 Position : in out Cursor)
2094 Target_Position : Count_Type;
2097 if Target'Address = Source'Address then
2098 Splice (Target, Before, Position);
2102 if Before.Container /= null then
2103 if Before.Container /= Target'Unrestricted_Access then
2104 raise Program_Error with
2105 "Before cursor designates wrong container";
2108 pragma Assert (Vet (Before), "bad Before cursor in Splice");
2111 if Position.Node = 0 then
2112 raise Constraint_Error with "Position cursor has no element";
2115 if Position.Container /= Source'Unrestricted_Access then
2116 raise Program_Error with
2117 "Position cursor designates wrong container";
2120 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2122 if Target.Length >= Target.Capacity then
2123 raise Capacity_Error with "Target is full";
2126 if Target.Busy > 0 then
2127 raise Program_Error with
2128 "attempt to tamper with cursors of Target (list is busy)";
2131 if Source.Busy > 0 then
2132 raise Program_Error with
2133 "attempt to tamper with cursors of Source (list is busy)";
2138 Before => Before.Node,
2140 Src_Pos => Position.Node,
2141 Tgt_Pos => Target_Position);
2143 Position := Cursor'(Target
'Unrestricted_Access, Target_Position
);
2146 ---------------------
2147 -- Splice_Internal --
2148 ---------------------
2150 procedure Splice_Internal
2151 (Target
: in out List
;
2152 Before
: Count_Type
;
2153 Source
: in out List
)
2155 N
: Node_Array
renames Source
.Nodes
;
2159 -- This implements the corresponding Splice operation, after the
2160 -- parameters have been vetted, and corner-cases disposed of.
2162 pragma Assert
(Target
'Address /= Source
'Address);
2163 pragma Assert
(Source
.Length
> 0);
2164 pragma Assert
(Source
.First
/= 0);
2165 pragma Assert
(N
(Source
.First
).Prev
= 0);
2166 pragma Assert
(Source
.Last
/= 0);
2167 pragma Assert
(N
(Source
.Last
).Next
= 0);
2168 pragma Assert
(Target
.Length
<= Count_Type
'Last - Source
.Length
);
2169 pragma Assert
(Target
.Length
+ Source
.Length
<= Target
.Capacity
);
2171 while Source
.Length
> 1 loop
2172 -- Copy first element of Source onto Target
2174 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2175 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2177 -- Unlink the first node from Source
2180 pragma Assert
(N
(N
(X
).Next
).Prev
= X
);
2182 Source
.First
:= N
(X
).Next
;
2183 N
(Source
.First
).Prev
:= 0;
2185 Source
.Length
:= Source
.Length
- 1;
2187 -- Return the Source node to its free store
2192 -- Copy first (and only remaining) element of Source onto Target
2194 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2195 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2197 -- Unlink the node from Source
2200 pragma Assert
(X
= Source
.Last
);
2207 -- Return the Source node to its free store
2210 end Splice_Internal
;
2212 procedure Splice_Internal
2213 (Target
: in out List
;
2214 Before
: Count_Type
; -- node of Target
2215 Source
: in out List
;
2216 Src_Pos
: Count_Type
; -- node of Source
2217 Tgt_Pos
: out Count_Type
)
2219 N
: Node_Array
renames Source
.Nodes
;
2222 -- This implements the corresponding Splice operation, after the
2223 -- parameters have been vetted, and corner-cases handled.
2225 pragma Assert
(Target
'Address /= Source
'Address);
2226 pragma Assert
(Target
.Length
< Target
.Capacity
);
2227 pragma Assert
(Source
.Length
> 0);
2228 pragma Assert
(Source
.First
/= 0);
2229 pragma Assert
(N
(Source
.First
).Prev
= 0);
2230 pragma Assert
(Source
.Last
/= 0);
2231 pragma Assert
(N
(Source
.Last
).Next
= 0);
2232 pragma Assert
(Src_Pos
/= 0);
2234 Allocate
(Target
, N
(Src_Pos
).Element
, New_Node
=> Tgt_Pos
);
2235 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> Tgt_Pos
);
2237 if Source
.Length
= 1 then
2238 pragma Assert
(Source
.First
= Source
.Last
);
2239 pragma Assert
(Src_Pos
= Source
.First
);
2244 elsif Src_Pos
= Source
.First
then
2245 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2247 Source
.First
:= N
(Src_Pos
).Next
;
2248 N
(Source
.First
).Prev
:= 0;
2250 elsif Src_Pos
= Source
.Last
then
2251 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2253 Source
.Last
:= N
(Src_Pos
).Prev
;
2254 N
(Source
.Last
).Next
:= 0;
2257 pragma Assert
(Source
.Length
>= 3);
2258 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2259 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2261 N
(N
(Src_Pos
).Next
).Prev
:= N
(Src_Pos
).Prev
;
2262 N
(N
(Src_Pos
).Prev
).Next
:= N
(Src_Pos
).Next
;
2265 Source
.Length
:= Source
.Length
- 1;
2266 Free
(Source
, Src_Pos
);
2267 end Splice_Internal
;
2274 (Container
: in out List
;
2279 raise Constraint_Error
with "I cursor has no element";
2283 raise Constraint_Error
with "J cursor has no element";
2286 if I
.Container
/= Container
'Unchecked_Access then
2287 raise Program_Error
with "I cursor designates wrong container";
2290 if J
.Container
/= Container
'Unchecked_Access then
2291 raise Program_Error
with "J cursor designates wrong container";
2294 if I
.Node
= J
.Node
then
2298 if Container
.Lock
> 0 then
2299 raise Program_Error
with
2300 "attempt to tamper with elements (list is locked)";
2303 pragma Assert
(Vet
(I
), "bad I cursor in Swap");
2304 pragma Assert
(Vet
(J
), "bad J cursor in Swap");
2307 EI
: Element_Type
renames Container
.Nodes
(I
.Node
).Element
;
2308 EJ
: Element_Type
renames Container
.Nodes
(J
.Node
).Element
;
2310 EI_Copy
: constant Element_Type
:= EI
;
2322 procedure Swap_Links
2323 (Container
: in out List
;
2328 raise Constraint_Error
with "I cursor has no element";
2332 raise Constraint_Error
with "J cursor has no element";
2335 if I
.Container
/= Container
'Unrestricted_Access then
2336 raise Program_Error
with "I cursor designates wrong container";
2339 if J
.Container
/= Container
'Unrestricted_Access then
2340 raise Program_Error
with "J cursor designates wrong container";
2343 if I
.Node
= J
.Node
then
2347 if Container
.Busy
> 0 then
2348 raise Program_Error
with
2349 "attempt to tamper with cursors (list is busy)";
2352 pragma Assert
(Vet
(I
), "bad I cursor in Swap_Links");
2353 pragma Assert
(Vet
(J
), "bad J cursor in Swap_Links");
2356 I_Next
: constant Cursor
:= Next
(I
);
2360 Splice
(Container
, Before
=> I
, Position
=> J
);
2364 J_Next
: constant Cursor
:= Next
(J
);
2368 Splice
(Container
, Before
=> J
, Position
=> I
);
2371 pragma Assert
(Container
.Length
>= 3);
2373 Splice
(Container
, Before
=> I_Next
, Position
=> J
);
2374 Splice
(Container
, Before
=> J_Next
, Position
=> I
);
2381 --------------------
2382 -- Update_Element --
2383 --------------------
2385 procedure Update_Element
2386 (Container
: in out List
;
2388 Process
: not null access procedure (Element
: in out Element_Type
))
2391 if Position
.Node
= 0 then
2392 raise Constraint_Error
with "Position cursor has no element";
2395 if Position
.Container
/= Container
'Unchecked_Access then
2396 raise Program_Error
with
2397 "Position cursor designates wrong container";
2400 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
2403 B
: Natural renames Container
.Busy
;
2404 L
: Natural renames Container
.Lock
;
2411 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
2413 Process
(N
.Element
);
2430 function Vet
(Position
: Cursor
) return Boolean is
2432 if Position
.Node
= 0 then
2433 return Position
.Container
= null;
2436 if Position
.Container
= null then
2441 L
: List
renames Position
.Container
.all;
2442 N
: Node_Array
renames L
.Nodes
;
2445 if L
.Length
= 0 then
2449 if L
.First
= 0 or L
.First
> L
.Capacity
then
2453 if L
.Last
= 0 or L
.Last
> L
.Capacity
then
2457 if N
(L
.First
).Prev
/= 0 then
2461 if N
(L
.Last
).Next
/= 0 then
2465 if Position
.Node
> L
.Capacity
then
2469 -- An invariant of an active node is that its Previous and Next
2470 -- components are non-negative. Operation Free sets the Previous
2471 -- component of the node to the value -1 before actually deallocating
2472 -- the node, to mark the node as inactive. (By "dellocating" we mean
2473 -- only that the node is linked onto a list of inactive nodes used
2474 -- for storage.) This marker gives us a simple way to detect a
2475 -- dangling reference to a node.
2477 if N
(Position
.Node
).Prev
< 0 then -- see Free
2481 if N
(Position
.Node
).Prev
> L
.Capacity
then
2485 if N
(Position
.Node
).Next
= Position
.Node
then
2489 if N
(Position
.Node
).Prev
= Position
.Node
then
2493 if N
(Position
.Node
).Prev
= 0
2494 and then Position
.Node
/= L
.First
2499 pragma Assert
(N
(Position
.Node
).Prev
/= 0
2500 or else Position
.Node
= L
.First
);
2502 if N
(Position
.Node
).Next
= 0
2503 and then Position
.Node
/= L
.Last
2508 pragma Assert
(N
(Position
.Node
).Next
/= 0
2509 or else Position
.Node
= L
.Last
);
2511 if L
.Length
= 1 then
2512 return L
.First
= L
.Last
;
2515 if L
.First
= L
.Last
then
2519 if N
(L
.First
).Next
= 0 then
2523 if N
(L
.Last
).Prev
= 0 then
2527 if N
(N
(L
.First
).Next
).Prev
/= L
.First
then
2531 if N
(N
(L
.Last
).Prev
).Next
/= L
.Last
then
2535 if L
.Length
= 2 then
2536 if N
(L
.First
).Next
/= L
.Last
then
2540 if N
(L
.Last
).Prev
/= L
.First
then
2547 if N
(L
.First
).Next
= L
.Last
then
2551 if N
(L
.Last
).Prev
= L
.First
then
2555 -- Eliminate earlier possibility
2557 if Position
.Node
= L
.First
then
2561 pragma Assert
(N
(Position
.Node
).Prev
/= 0);
2563 -- Eliminate another possibility
2565 if Position
.Node
= L
.Last
then
2569 pragma Assert
(N
(Position
.Node
).Next
/= 0);
2571 if N
(N
(Position
.Node
).Next
).Prev
/= Position
.Node
then
2575 if N
(N
(Position
.Node
).Prev
).Next
/= Position
.Node
then
2579 if L
.Length
= 3 then
2580 if N
(L
.First
).Next
/= Position
.Node
then
2584 if N
(L
.Last
).Prev
/= Position
.Node
then
2598 (Stream
: not null access Root_Stream_Type
'Class;
2604 Count_Type
'Base'Write (Stream, Item.Length);
2607 while Node /= 0 loop
2608 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2609 Node := Item.Nodes (Node).Next;
2614 (Stream : not null access Root_Stream_Type'Class;
2618 raise Program_Error with "attempt to stream list cursor";
2622 (Stream : not null access Root_Stream_Type'Class;
2623 Item : Reference_Type)
2626 raise Program_Error with "attempt to stream reference";
2630 (Stream : not null access Root_Stream_Type'Class;
2631 Item : Constant_Reference_Type)
2634 raise Program_Error with "attempt to stream reference";
2637 end Ada.Containers.Bounded_Doubly_Linked_Lists;