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 -----------------------
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 Adjust
(Control
: in out Reference_Control_Type
) is
236 if Control
.Container
/= null then
238 C
: List
renames Control
.Container
.all;
239 B
: Natural renames C
.Busy
;
240 L
: Natural renames C
.Lock
;
252 procedure Assign
(Target
: in out List
; Source
: List
) is
253 SN
: Node_Array
renames Source
.Nodes
;
257 if Target
'Address = Source
'Address then
261 if Target
.Capacity
< Source
.Length
then
262 raise Capacity_Error
-- ???
263 with "Target capacity is less than Source length";
270 Target
.Append
(SN
(J
).Element
);
279 procedure Clear
(Container
: in out List
) is
280 N
: Node_Array
renames Container
.Nodes
;
284 if Container
.Length
= 0 then
285 pragma Assert
(Container
.First
= 0);
286 pragma Assert
(Container
.Last
= 0);
287 pragma Assert
(Container
.Busy
= 0);
288 pragma Assert
(Container
.Lock
= 0);
292 pragma Assert
(Container
.First
>= 1);
293 pragma Assert
(Container
.Last
>= 1);
294 pragma Assert
(N
(Container
.First
).Prev
= 0);
295 pragma Assert
(N
(Container
.Last
).Next
= 0);
297 if Container
.Busy
> 0 then
298 raise Program_Error
with
299 "attempt to tamper with cursors (list is busy)";
302 while Container
.Length
> 1 loop
303 X
:= Container
.First
;
304 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
306 Container
.First
:= N
(X
).Next
;
307 N
(Container
.First
).Prev
:= 0;
309 Container
.Length
:= Container
.Length
- 1;
314 X
:= Container
.First
;
315 pragma Assert
(X
= Container
.Last
);
317 Container
.First
:= 0;
319 Container
.Length
:= 0;
324 ------------------------
325 -- Constant_Reference --
326 ------------------------
328 function Constant_Reference
329 (Container
: aliased List
;
330 Position
: Cursor
) return Constant_Reference_Type
333 if Position
.Container
= null then
334 raise Constraint_Error
with "Position cursor has no element";
336 elsif Position
.Container
/= Container
'Unrestricted_Access then
337 raise Program_Error
with
338 "Position cursor designates wrong container";
341 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
344 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
345 B
: Natural renames Position
.Container
.Busy
;
346 L
: Natural renames Position
.Container
.Lock
;
348 return R
: constant Constant_Reference_Type
:=
349 (Element
=> N
.Element
'Access,
350 Control
=> (Controlled
with Container
'Unrestricted_Access))
357 end Constant_Reference
;
365 Item
: Element_Type
) return Boolean
368 return Find
(Container
, Item
) /= No_Element
;
375 function Copy
(Source
: List
; Capacity
: Count_Type
:= 0) return List
is
381 elsif Capacity
>= Source
.Length
then
384 raise Capacity_Error
with "Capacity value too small";
387 return Target
: List
(Capacity
=> C
) do
388 Assign
(Target
=> Target
, Source
=> Source
);
397 (Container
: in out List
;
398 Position
: in out Cursor
;
399 Count
: Count_Type
:= 1)
401 N
: Node_Array
renames Container
.Nodes
;
405 if Position
.Node
= 0 then
406 raise Constraint_Error
with
407 "Position cursor has no element";
410 if Position
.Container
/= Container
'Unrestricted_Access then
411 raise Program_Error
with
412 "Position cursor designates wrong container";
415 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
416 pragma Assert
(Container
.First
>= 1);
417 pragma Assert
(Container
.Last
>= 1);
418 pragma Assert
(N
(Container
.First
).Prev
= 0);
419 pragma Assert
(N
(Container
.Last
).Next
= 0);
421 if Position
.Node
= Container
.First
then
422 Delete_First
(Container
, Count
);
423 Position
:= No_Element
;
428 Position
:= No_Element
;
432 if Container
.Busy
> 0 then
433 raise Program_Error
with
434 "attempt to tamper with cursors (list is busy)";
437 for Index
in 1 .. Count
loop
438 pragma Assert
(Container
.Length
>= 2);
441 Container
.Length
:= Container
.Length
- 1;
443 if X
= Container
.Last
then
444 Position
:= No_Element
;
446 Container
.Last
:= N
(X
).Prev
;
447 N
(Container
.Last
).Next
:= 0;
453 Position
.Node
:= N
(X
).Next
;
455 N
(N
(X
).Next
).Prev
:= N
(X
).Prev
;
456 N
(N
(X
).Prev
).Next
:= N
(X
).Next
;
461 Position
:= No_Element
;
468 procedure Delete_First
469 (Container
: in out List
;
470 Count
: Count_Type
:= 1)
472 N
: Node_Array
renames Container
.Nodes
;
476 if Count
>= Container
.Length
then
485 if Container
.Busy
> 0 then
486 raise Program_Error
with
487 "attempt to tamper with cursors (list is busy)";
490 for J
in 1 .. Count
loop
491 X
:= Container
.First
;
492 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
494 Container
.First
:= N
(X
).Next
;
495 N
(Container
.First
).Prev
:= 0;
497 Container
.Length
:= Container
.Length
- 1;
507 procedure Delete_Last
508 (Container
: in out List
;
509 Count
: Count_Type
:= 1)
511 N
: Node_Array
renames Container
.Nodes
;
515 if Count
>= Container
.Length
then
524 if Container
.Busy
> 0 then
525 raise Program_Error
with
526 "attempt to tamper with cursors (list is busy)";
529 for J
in 1 .. Count
loop
531 pragma Assert
(N
(N
(X
).Prev
).Next
= Container
.Last
);
533 Container
.Last
:= N
(X
).Prev
;
534 N
(Container
.Last
).Next
:= 0;
536 Container
.Length
:= Container
.Length
- 1;
546 function Element
(Position
: Cursor
) return Element_Type
is
548 if Position
.Node
= 0 then
549 raise Constraint_Error
with
550 "Position cursor has no element";
553 pragma Assert
(Vet
(Position
), "bad cursor in Element");
555 return Position
.Container
.Nodes
(Position
.Node
).Element
;
563 procedure Finalize
(Object
: in out Iterator
) is
565 if Object
.Container
/= null then
567 B
: Natural renames Object
.Container
.all.Busy
;
574 procedure Finalize
(Control
: in out Reference_Control_Type
) is
576 if Control
.Container
/= null then
578 C
: List
renames Control
.Container
.all;
579 B
: Natural renames C
.Busy
;
580 L
: Natural renames C
.Lock
;
586 Control
.Container
:= null;
597 Position
: Cursor
:= No_Element
) return Cursor
599 Nodes
: Node_Array
renames Container
.Nodes
;
600 Node
: Count_Type
:= Position
.Node
;
604 Node
:= Container
.First
;
607 if Position
.Container
/= Container
'Unrestricted_Access then
608 raise Program_Error
with
609 "Position cursor designates wrong container";
612 pragma Assert
(Vet
(Position
), "bad cursor in Find");
615 -- Per AI05-0022, the container implementation is required to detect
616 -- element tampering by a generic actual subprogram.
619 B
: Natural renames Container
'Unrestricted_Access.Busy
;
620 L
: Natural renames Container
'Unrestricted_Access.Lock
;
630 if Nodes
(Node
).Element
= Item
then
635 Node
:= Nodes
(Node
).Next
;
644 return Cursor
'(Container'Unrestricted_Access, Result);
659 function First (Container : List) return Cursor is
661 if Container.First = 0 then
664 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
668 function First
(Object
: Iterator
) return Cursor
is
670 -- The value of the iterator object's Node component influences the
671 -- behavior of the First (and Last) selector function.
673 -- When the Node component is 0, this means the iterator object was
674 -- constructed without a start expression, in which case the (forward)
675 -- iteration starts from the (logical) beginning of the entire sequence
676 -- of items (corresponding to Container.First, for a forward iterator).
678 -- Otherwise, this is iteration over a partial sequence of items. When
679 -- the Node component is positive, the iterator object was constructed
680 -- with a start expression, that specifies the position from which the
681 -- (forward) partial iteration begins.
683 if Object
.Node
= 0 then
684 return Bounded_Doubly_Linked_Lists
.First
(Object
.Container
.all);
686 return Cursor
'(Object.Container, Object.Node);
694 function First_Element (Container : List) return Element_Type is
696 if Container.First = 0 then
697 raise Constraint_Error with "list is empty";
699 return Container.Nodes (Container.First).Element;
708 (Container : in out List;
711 pragma Assert (X > 0);
712 pragma Assert (X <= Container.Capacity);
714 N : Node_Array renames Container.Nodes;
715 pragma Assert (N (X).Prev >= 0); -- node is active
718 -- The list container actually contains two lists: one for the "active"
719 -- nodes that contain elements that have been inserted onto the list,
720 -- and another for the "inactive" nodes for the free store.
722 -- We desire that merely declaring an object should have only minimal
723 -- cost; specially, we want to avoid having to initialize the free
724 -- store (to fill in the links), especially if the capacity is large.
726 -- The head of the free list is indicated by Container.Free. If its
727 -- value is non-negative, then the free store has been initialized in
728 -- the "normal" way: Container.Free points to the head of the list of
729 -- free (inactive) nodes, and the value 0 means the free list is empty.
730 -- Each node on the free list has been initialized to point to the next
731 -- free node (via its Next component), and the value 0 means that this
732 -- is the last free node.
734 -- If Container.Free is negative, then the links on the free store have
735 -- not been initialized. In this case the link values are implied: the
736 -- free store comprises the components of the node array started with
737 -- the absolute value of Container.Free, and continuing until the end of
738 -- the array (Nodes'Last).
740 -- If the list container is manipulated on one end only (for example if
741 -- the container were being used as a stack), then there is no need to
742 -- initialize the free store, since the inactive nodes are physically
743 -- contiguous (in fact, they lie immediately beyond the logical end
744 -- being manipulated). The only time we need to actually initialize the
745 -- nodes in the free store is if the node that becomes inactive is not
746 -- at the end of the list. The free store would then be discontiguous
747 -- and so its nodes would need to be linked in the traditional way.
750 -- It might be possible to perform an optimization here. Suppose that
751 -- the free store can be represented as having two parts: one comprising
752 -- the non-contiguous inactive nodes linked together in the normal way,
753 -- and the other comprising the contiguous inactive nodes (that are not
754 -- linked together, at the end of the nodes array). This would allow us
755 -- to never have to initialize the free store, except in a lazy way as
756 -- nodes become inactive.
758 -- When an element is deleted from the list container, its node becomes
759 -- inactive, and so we set its Prev component to a negative value, to
760 -- indicate that it is now inactive. This provides a useful way to
761 -- detect a dangling cursor reference (and which is used in Vet).
763 N (X).Prev := -1; -- Node is deallocated (not on active list)
765 if Container.Free >= 0 then
767 -- The free store has previously been initialized. All we need to
768 -- do here is link the newly-free'd node onto the free list.
770 N (X).Next := Container.Free;
773 elsif X + 1 = abs Container.Free then
775 -- The free store has not been initialized, and the node becoming
776 -- inactive immediately precedes the start of the free store. All
777 -- we need to do is move the start of the free store back by one.
779 -- Note: initializing Next to zero is not strictly necessary but
780 -- seems cleaner and marginally safer.
783 Container.Free := Container.Free + 1;
786 -- The free store has not been initialized, and the node becoming
787 -- inactive does not immediately precede the free store. Here we
788 -- first initialize the free store (meaning the links are given
789 -- values in the traditional way), and then link the newly-free'd
790 -- node onto the head of the free store.
793 -- See the comments above for an optimization opportunity. If the
794 -- next link for a node on the free store is negative, then this
795 -- means the remaining nodes on the free store are physically
796 -- contiguous, starting as the absolute value of that index value.
798 Container.Free := abs Container.Free;
800 if Container.Free > Container.Capacity then
804 for I in Container.Free .. Container.Capacity - 1 loop
808 N (Container.Capacity).Next := 0;
811 N (X).Next := Container.Free;
816 ---------------------
817 -- Generic_Sorting --
818 ---------------------
820 package body Generic_Sorting is
826 function Is_Sorted (Container : List) return Boolean is
827 B : Natural renames Container'Unrestricted_Access.Busy;
828 L : Natural renames Container'Unrestricted_Access.Lock;
830 Nodes : Node_Array renames Container.Nodes;
836 -- Per AI05-0022, the container implementation is required to detect
837 -- element tampering by a generic actual subprogram.
842 Node := Container.First;
844 for J in 2 .. Container.Length loop
845 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
850 Node := Nodes (Node).Next;
870 (Target : in out List;
871 Source : in out List)
874 -- The semantics of Merge changed slightly per AI05-0021. It was
875 -- originally the case that if Target and Source denoted the same
876 -- container object, then the GNAT implementation of Merge did
877 -- nothing. However, it was argued that RM05 did not precisely
878 -- specify the semantics for this corner case. The decision of the
879 -- ARG was that if Target and Source denote the same non-empty
880 -- container object, then Program_Error is raised.
882 if Source.Is_Empty then
886 if Target'Address = Source'Address then
887 raise Program_Error with
888 "Target and Source denote same non-empty container";
891 if Target.Length > Count_Type'Last - Source.Length then
892 raise Constraint_Error with "new length exceeds maximum";
895 if Target.Length + Source.Length > Target.Capacity then
896 raise Capacity_Error with "new length exceeds target capacity";
899 if Target.Busy > 0 then
900 raise Program_Error with
901 "attempt to tamper with cursors of Target (list is busy)";
904 if Source.Busy > 0 then
905 raise Program_Error with
906 "attempt to tamper with cursors of Source (list is busy)";
909 -- Per AI05-0022, the container implementation is required to detect
910 -- element tampering by a generic actual subprogram.
913 TB : Natural renames Target.Busy;
914 TL : Natural renames Target.Lock;
916 SB : Natural renames Source.Busy;
917 SL : Natural renames Source.Lock;
919 LN : Node_Array renames Target.Nodes;
920 RN : Node_Array renames Source.Nodes;
922 LI, LJ, RI, RJ : Count_Type;
934 pragma Assert (RN (RI).Next = 0
935 or else not (RN (RN (RI).Next).Element <
939 Splice_Internal (Target, 0, Source);
943 pragma Assert (LN (LI).Next = 0
944 or else not (LN (LN (LI).Next).Element <
947 if RN (RI).Element < LN (LI).Element then
950 Splice_Internal (Target, LI, Source, RJ, LJ);
979 procedure Sort (Container : in out List) is
980 N : Node_Array renames Container.Nodes;
982 procedure Partition (Pivot, Back : Count_Type);
983 -- What does this do ???
985 procedure Sort (Front, Back : Count_Type);
986 -- Internal procedure, what does it do??? rename it???
992 procedure Partition (Pivot, Back : Count_Type) is
996 Node := N (Pivot).Next;
997 while Node /= Back loop
998 if N (Node).Element < N (Pivot).Element then
1000 Prev : constant Count_Type := N (Node).Prev;
1001 Next : constant Count_Type := N (Node).Next;
1004 N (Prev).Next := Next;
1007 Container.Last := Prev;
1009 N (Next).Prev := Prev;
1012 N (Node).Next := Pivot;
1013 N (Node).Prev := N (Pivot).Prev;
1015 N (Pivot).Prev := Node;
1017 if N (Node).Prev = 0 then
1018 Container.First := Node;
1020 N (N (Node).Prev).Next := Node;
1027 Node := N (Node).Next;
1036 procedure Sort (Front, Back : Count_Type) is
1037 Pivot : constant Count_Type :=
1038 (if Front = 0 then Container.First else N (Front).Next);
1040 if Pivot /= Back then
1041 Partition (Pivot, Back);
1042 Sort (Front, Pivot);
1047 -- Start of processing for Sort
1050 if Container.Length <= 1 then
1054 pragma Assert (N (Container.First).Prev = 0);
1055 pragma Assert (N (Container.Last).Next = 0);
1057 if Container.Busy > 0 then
1058 raise Program_Error with
1059 "attempt to tamper with cursors (list is busy)";
1062 -- Per AI05-0022, the container implementation is required to detect
1063 -- element tampering by a generic actual subprogram.
1066 B : Natural renames Container.Busy;
1067 L : Natural renames Container.Lock;
1073 Sort (Front => 0, Back => 0);
1085 pragma Assert (N (Container.First).Prev = 0);
1086 pragma Assert (N (Container.Last).Next = 0);
1089 end Generic_Sorting;
1095 function Has_Element (Position : Cursor) return Boolean is
1097 pragma Assert (Vet (Position), "bad cursor in Has_Element");
1098 return Position.Node /= 0;
1106 (Container : in out List;
1108 New_Item : Element_Type;
1109 Position : out Cursor;
1110 Count : Count_Type := 1)
1112 First_Node : Count_Type;
1113 New_Node : Count_Type;
1116 if Before.Container /= null then
1117 if Before.Container /= Container'Unrestricted_Access then
1118 raise Program_Error with
1119 "Before cursor designates wrong list";
1122 pragma Assert (Vet (Before), "bad cursor in Insert");
1130 if Container.Length > Container.Capacity - Count then
1131 raise Capacity_Error with "capacity exceeded";
1134 if Container.Busy > 0 then
1135 raise Program_Error with
1136 "attempt to tamper with cursors (list is busy)";
1139 Allocate (Container, New_Item, New_Node);
1140 First_Node := New_Node;
1141 Insert_Internal (Container, Before.Node, New_Node);
1143 for Index in Count_Type'(2) .. Count
loop
1144 Allocate
(Container
, New_Item
, New_Node
);
1145 Insert_Internal
(Container
, Before
.Node
, New_Node
);
1148 Position
:= Cursor
'(Container'Unchecked_Access, First_Node);
1152 (Container : in out List;
1154 New_Item : Element_Type;
1155 Count : Count_Type := 1)
1158 pragma Unreferenced (Position);
1160 Insert (Container, Before, New_Item, Position, Count);
1164 (Container : in out List;
1166 Position : out Cursor;
1167 Count : Count_Type := 1)
1169 New_Item : Element_Type;
1170 pragma Unmodified (New_Item);
1171 -- OK to reference, see below
1174 -- There is no explicit element provided, but in an instance the element
1175 -- type may be a scalar with a Default_Value aspect, or a composite
1176 -- type with such a scalar component, or components with default
1177 -- initialization, so insert the specified number of possibly
1178 -- initialized elements at the given position.
1180 Insert (Container, Before, New_Item, Position, Count);
1183 ---------------------
1184 -- Insert_Internal --
1185 ---------------------
1187 procedure Insert_Internal
1188 (Container : in out List;
1189 Before : Count_Type;
1190 New_Node : Count_Type)
1192 N : Node_Array renames Container.Nodes;
1195 if Container.Length = 0 then
1196 pragma Assert (Before = 0);
1197 pragma Assert (Container.First = 0);
1198 pragma Assert (Container.Last = 0);
1200 Container.First := New_Node;
1201 N (Container.First).Prev := 0;
1203 Container.Last := New_Node;
1204 N (Container.Last).Next := 0;
1206 -- Before = zero means append
1208 elsif Before = 0 then
1209 pragma Assert (N (Container.Last).Next = 0);
1211 N (Container.Last).Next := New_Node;
1212 N (New_Node).Prev := Container.Last;
1214 Container.Last := New_Node;
1215 N (Container.Last).Next := 0;
1217 -- Before = Container.First means prepend
1219 elsif Before = Container.First then
1220 pragma Assert (N (Container.First).Prev = 0);
1222 N (Container.First).Prev := New_Node;
1223 N (New_Node).Next := Container.First;
1225 Container.First := New_Node;
1226 N (Container.First).Prev := 0;
1229 pragma Assert (N (Container.First).Prev = 0);
1230 pragma Assert (N (Container.Last).Next = 0);
1232 N (New_Node).Next := Before;
1233 N (New_Node).Prev := N (Before).Prev;
1235 N (N (Before).Prev).Next := New_Node;
1236 N (Before).Prev := New_Node;
1239 Container.Length := Container.Length + 1;
1240 end Insert_Internal;
1246 function Is_Empty (Container : List) return Boolean is
1248 return Container.Length = 0;
1257 Process : not null access procedure (Position : Cursor))
1259 B : Natural renames Container'Unrestricted_Access.all.Busy;
1260 Node : Count_Type := Container.First;
1266 while Node /= 0 loop
1267 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1268 Node
:= Container
.Nodes
(Node
).Next
;
1281 return List_Iterator_Interfaces
.Reversible_Iterator
'Class
1283 B
: Natural renames Container
'Unrestricted_Access.all.Busy
;
1286 -- The value of the Node component influences the behavior of the First
1287 -- and Last selector functions of the iterator object. When the Node
1288 -- component is 0 (as is the case here), this means the iterator
1289 -- object was constructed without a start expression. This is a
1290 -- complete iterator, meaning that the iteration starts from the
1291 -- (logical) beginning of the sequence of items.
1293 -- Note: For a forward iterator, Container.First is the beginning, and
1294 -- for a reverse iterator, Container.Last is the beginning.
1296 return It
: constant Iterator
:=
1297 Iterator
'(Limited_Controlled with
1298 Container => Container'Unrestricted_Access,
1308 return List_Iterator_Interfaces.Reversible_Iterator'class
1310 B : Natural renames Container'Unrestricted_Access.all.Busy;
1313 -- It was formerly the case that when Start = No_Element, the partial
1314 -- iterator was defined to behave the same as for a complete iterator,
1315 -- and iterate over the entire sequence of items. However, those
1316 -- semantics were unintuitive and arguably error-prone (it is too easy
1317 -- to accidentally create an endless loop), and so they were changed,
1318 -- per the ARG meeting in Denver on 2011/11. However, there was no
1319 -- consensus about what positive meaning this corner case should have,
1320 -- and so it was decided to simply raise an exception. This does imply,
1321 -- however, that it is not possible to use a partial iterator to specify
1322 -- an empty sequence of items.
1324 if Start = No_Element then
1325 raise Constraint_Error with
1326 "Start position for iterator equals No_Element";
1329 if Start.Container /= Container'Unrestricted_Access then
1330 raise Program_Error with
1331 "Start cursor of Iterate designates wrong list";
1334 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1336 -- The value of the Node component influences the behavior of the First
1337 -- and Last selector functions of the iterator object. When the Node
1338 -- component is positive (as is the case here), it means that this
1339 -- is a partial iteration, over a subset of the complete sequence of
1340 -- items. The iterator object was constructed with a start expression,
1341 -- indicating the position from which the iteration begins. Note that
1342 -- the start position has the same value irrespective of whether this
1343 -- is a forward or reverse iteration.
1345 return It : constant Iterator :=
1346 Iterator'(Limited_Controlled
with
1347 Container
=> Container
'Unrestricted_Access,
1358 function Last
(Container
: List
) return Cursor
is
1360 if Container
.Last
= 0 then
1363 return Cursor
'(Container'Unrestricted_Access, Container.Last);
1367 function Last (Object : Iterator) return Cursor is
1369 -- The value of the iterator object's Node component influences the
1370 -- behavior of the Last (and First) selector function.
1372 -- When the Node component is 0, this means the iterator object was
1373 -- constructed without a start expression, in which case the (reverse)
1374 -- iteration starts from the (logical) beginning of the entire sequence
1375 -- (corresponding to Container.Last, for a reverse iterator).
1377 -- Otherwise, this is iteration over a partial sequence of items. When
1378 -- the Node component is positive, the iterator object was constructed
1379 -- with a start expression, that specifies the position from which the
1380 -- (reverse) partial iteration begins.
1382 if Object.Node = 0 then
1383 return Bounded_Doubly_Linked_Lists.Last (Object.Container.all);
1385 return Cursor'(Object
.Container
, Object
.Node
);
1393 function Last_Element
(Container
: List
) return Element_Type
is
1395 if Container
.Last
= 0 then
1396 raise Constraint_Error
with "list is empty";
1398 return Container
.Nodes
(Container
.Last
).Element
;
1406 function Length
(Container
: List
) return Count_Type
is
1408 return Container
.Length
;
1416 (Target
: in out List
;
1417 Source
: in out List
)
1419 N
: Node_Array
renames Source
.Nodes
;
1423 if Target
'Address = Source
'Address then
1427 if Target
.Capacity
< Source
.Length
then
1428 raise Capacity_Error
with "Source length exceeds Target capacity";
1431 if Source
.Busy
> 0 then
1432 raise Program_Error
with
1433 "attempt to tamper with cursors of Source (list is busy)";
1436 -- Clear target, note that this checks busy bits of Target
1440 while Source
.Length
> 1 loop
1441 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1442 pragma Assert
(Source
.Last
/= Source
.First
);
1443 pragma Assert
(N
(Source
.First
).Prev
= 0);
1444 pragma Assert
(N
(Source
.Last
).Next
= 0);
1446 -- Copy first element from Source to Target
1449 Append
(Target
, N
(X
).Element
);
1451 -- Unlink first node of Source
1453 Source
.First
:= N
(X
).Next
;
1454 N
(Source
.First
).Prev
:= 0;
1456 Source
.Length
:= Source
.Length
- 1;
1458 -- The representation invariants for Source have been restored. It is
1459 -- now safe to free the unlinked node, without fear of corrupting the
1460 -- active links of Source.
1462 -- Note that the algorithm we use here models similar algorithms used
1463 -- in the unbounded form of the doubly-linked list container. In that
1464 -- case, Free is an instantation of Unchecked_Deallocation, which can
1465 -- fail (because PE will be raised if controlled Finalize fails), so
1466 -- we must defer the call until the last step. Here in the bounded
1467 -- form, Free merely links the node we have just "deallocated" onto a
1468 -- list of inactive nodes, so technically Free cannot fail. However,
1469 -- for consistency, we handle Free the same way here as we do for the
1470 -- unbounded form, with the pessimistic assumption that it can fail.
1475 if Source
.Length
= 1 then
1476 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1477 pragma Assert
(Source
.Last
= Source
.First
);
1478 pragma Assert
(N
(Source
.First
).Prev
= 0);
1479 pragma Assert
(N
(Source
.Last
).Next
= 0);
1481 -- Copy element from Source to Target
1484 Append
(Target
, N
(X
).Element
);
1486 -- Unlink node of Source
1492 -- Return the unlinked node to the free store
1502 procedure Next
(Position
: in out Cursor
) is
1504 Position
:= Next
(Position
);
1507 function Next
(Position
: Cursor
) return Cursor
is
1509 if Position
.Node
= 0 then
1513 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1516 Nodes
: Node_Array
renames Position
.Container
.Nodes
;
1517 Node
: constant Count_Type
:= Nodes
(Position
.Node
).Next
;
1522 return Cursor
'(Position.Container, Node);
1529 Position : Cursor) return Cursor
1532 if Position.Container = null then
1534 elsif Position.Container /= Object.Container then
1535 raise Program_Error with
1536 "Position cursor of Next designates wrong list";
1538 return Next (Position);
1547 (Container : in out List;
1548 New_Item : Element_Type;
1549 Count : Count_Type := 1)
1552 Insert (Container, First (Container), New_Item, Count);
1559 procedure Previous (Position : in out Cursor) is
1561 Position := Previous (Position);
1564 function Previous (Position : Cursor) return Cursor is
1566 if Position.Node = 0 then
1570 pragma Assert (Vet (Position), "bad cursor in Previous");
1573 Nodes : Node_Array renames Position.Container.Nodes;
1574 Node : constant Count_Type := Nodes (Position.Node).Prev;
1579 return Cursor'(Position
.Container
, Node
);
1586 Position
: Cursor
) return Cursor
1589 if Position
.Container
= null then
1591 elsif Position
.Container
/= Object
.Container
then
1592 raise Program_Error
with
1593 "Position cursor of Previous designates wrong list";
1595 return Previous
(Position
);
1603 procedure Query_Element
1605 Process
: not null access procedure (Element
: Element_Type
))
1608 if Position
.Node
= 0 then
1609 raise Constraint_Error
with
1610 "Position cursor has no element";
1613 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1616 C
: List
renames Position
.Container
.all'Unrestricted_Access.all;
1617 B
: Natural renames C
.Busy
;
1618 L
: Natural renames C
.Lock
;
1625 N
: Node_Type
renames C
.Nodes
(Position
.Node
);
1627 Process
(N
.Element
);
1645 (Stream
: not null access Root_Stream_Type
'Class;
1648 N
: Count_Type
'Base;
1653 Count_Type
'Base'Read (Stream, N);
1656 raise Program_Error with "bad list length (corrupt stream)";
1661 elsif N > Item.Capacity then
1662 raise Constraint_Error with "length exceeds capacity";
1665 for Idx in 1 .. N loop
1666 Allocate (Item, Stream, New_Node => X);
1667 Insert_Internal (Item, Before => 0, New_Node => X);
1673 (Stream : not null access Root_Stream_Type'Class;
1677 raise Program_Error with "attempt to stream list cursor";
1681 (Stream : not null access Root_Stream_Type'Class;
1682 Item : out Reference_Type)
1685 raise Program_Error with "attempt to stream reference";
1689 (Stream : not null access Root_Stream_Type'Class;
1690 Item : out Constant_Reference_Type)
1693 raise Program_Error with "attempt to stream reference";
1701 (Container : aliased in out List;
1702 Position : Cursor) return Reference_Type
1705 if Position.Container = null then
1706 raise Constraint_Error with "Position cursor has no element";
1708 elsif Position.Container /= Container'Unrestricted_Access then
1709 raise Program_Error with
1710 "Position cursor designates wrong container";
1713 pragma Assert (Vet (Position), "bad cursor in function Reference");
1716 N : Node_Type renames Container.Nodes (Position.Node);
1717 B : Natural renames Container.Busy;
1718 L : Natural renames Container.Lock;
1720 return R : constant Reference_Type :=
1721 (Element => N.Element'Access,
1722 Control => (Controlled with Container'Unrestricted_Access))
1731 ---------------------
1732 -- Replace_Element --
1733 ---------------------
1735 procedure Replace_Element
1736 (Container : in out List;
1738 New_Item : Element_Type)
1741 if Position.Container = null then
1742 raise Constraint_Error with "Position cursor has no element";
1744 elsif Position.Container /= Container'Unchecked_Access then
1745 raise Program_Error with
1746 "Position cursor designates wrong container";
1748 elsif Container.Lock > 0 then
1749 raise Program_Error with
1750 "attempt to tamper with elements (list is locked)";
1753 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1755 Container.Nodes (Position.Node).Element := New_Item;
1757 end Replace_Element;
1759 ----------------------
1760 -- Reverse_Elements --
1761 ----------------------
1763 procedure Reverse_Elements (Container : in out List) is
1764 N : Node_Array renames Container.Nodes;
1765 I : Count_Type := Container.First;
1766 J : Count_Type := Container.Last;
1768 procedure Swap (L, R : Count_Type);
1774 procedure Swap (L, R : Count_Type) is
1775 LN : constant Count_Type := N (L).Next;
1776 LP : constant Count_Type := N (L).Prev;
1778 RN : constant Count_Type := N (R).Next;
1779 RP : constant Count_Type := N (R).Prev;
1794 pragma Assert (RP = L);
1808 -- Start of processing for Reverse_Elements
1811 if Container.Length <= 1 then
1815 pragma Assert (N (Container.First).Prev = 0);
1816 pragma Assert (N (Container.Last).Next = 0);
1818 if Container.Busy > 0 then
1819 raise Program_Error with
1820 "attempt to tamper with cursors (list is busy)";
1823 Container.First := J;
1824 Container.Last := I;
1826 Swap (L => I, R => J);
1834 Swap (L => J, R => I);
1843 pragma Assert (N (Container.First).Prev = 0);
1844 pragma Assert (N (Container.Last).Next = 0);
1845 end Reverse_Elements;
1851 function Reverse_Find
1853 Item : Element_Type;
1854 Position : Cursor := No_Element) return Cursor
1856 Node : Count_Type := Position.Node;
1860 Node := Container.Last;
1863 if Position.Container /= Container'Unrestricted_Access then
1864 raise Program_Error with
1865 "Position cursor designates wrong container";
1868 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1871 -- Per AI05-0022, the container implementation is required to detect
1872 -- element tampering by a generic actual subprogram.
1875 B : Natural renames Container'Unrestricted_Access.Busy;
1876 L : Natural renames Container'Unrestricted_Access.Lock;
1878 Result : Count_Type;
1885 while Node /= 0 loop
1886 if Container.Nodes (Node).Element = Item then
1891 Node := Container.Nodes (Node).Prev;
1900 return Cursor'(Container
'Unrestricted_Access, Result
);
1911 ---------------------
1912 -- Reverse_Iterate --
1913 ---------------------
1915 procedure Reverse_Iterate
1917 Process
: not null access procedure (Position
: Cursor
))
1919 C
: List
renames Container
'Unrestricted_Access.all;
1920 B
: Natural renames C
.Busy
;
1922 Node
: Count_Type
:= Container
.Last
;
1928 while Node
/= 0 loop
1929 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1930 Node := Container.Nodes (Node).Prev;
1939 end Reverse_Iterate;
1946 (Target : in out List;
1948 Source : in out List)
1951 if Before.Container /= null then
1952 if Before.Container /= Target'Unrestricted_Access then
1953 raise Program_Error with
1954 "Before cursor designates wrong container";
1957 pragma Assert (Vet (Before), "bad cursor in Splice");
1960 if Target'Address = Source'Address or else Source.Length = 0 then
1963 elsif Target.Length > Count_Type'Last - Source.Length then
1964 raise Constraint_Error with "new length exceeds maximum";
1966 elsif Target.Length + Source.Length > Target.Capacity then
1967 raise Capacity_Error with "new length exceeds target capacity";
1969 elsif Target.Busy > 0 then
1970 raise Program_Error with
1971 "attempt to tamper with cursors of Target (list is busy)";
1973 elsif Source.Busy > 0 then
1974 raise Program_Error with
1975 "attempt to tamper with cursors of Source (list is busy)";
1978 Splice_Internal (Target, Before.Node, Source);
1983 (Container : in out List;
1987 N : Node_Array renames Container.Nodes;
1990 if Before.Container /= null then
1991 if Before.Container /= Container'Unchecked_Access then
1992 raise Program_Error with
1993 "Before cursor designates wrong container";
1996 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1999 if Position.Node = 0 then
2000 raise Constraint_Error with "Position cursor has no element";
2003 if Position.Container /= Container'Unrestricted_Access then
2004 raise Program_Error with
2005 "Position cursor designates wrong container";
2008 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2010 if Position.Node = Before.Node
2011 or else N (Position.Node).Next = Before.Node
2016 pragma Assert (Container.Length >= 2);
2018 if Container.Busy > 0 then
2019 raise Program_Error with
2020 "attempt to tamper with cursors (list is busy)";
2023 if Before.Node = 0 then
2024 pragma Assert (Position.Node /= Container.Last);
2026 if Position.Node = Container.First then
2027 Container.First := N (Position.Node).Next;
2028 N (Container.First).Prev := 0;
2030 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2031 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2034 N (Container.Last).Next := Position.Node;
2035 N (Position.Node).Prev := Container.Last;
2037 Container.Last := Position.Node;
2038 N (Container.Last).Next := 0;
2043 if Before.Node = Container.First then
2044 pragma Assert (Position.Node /= Container.First);
2046 if Position.Node = Container.Last then
2047 Container.Last := N (Position.Node).Prev;
2048 N (Container.Last).Next := 0;
2050 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2051 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2054 N (Container.First).Prev := Position.Node;
2055 N (Position.Node).Next := Container.First;
2057 Container.First := Position.Node;
2058 N (Container.First).Prev := 0;
2063 if Position.Node = Container.First then
2064 Container.First := N (Position.Node).Next;
2065 N (Container.First).Prev := 0;
2067 elsif Position.Node = Container.Last then
2068 Container.Last := N (Position.Node).Prev;
2069 N (Container.Last).Next := 0;
2072 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
2073 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
2076 N (N (Before.Node).Prev).Next := Position.Node;
2077 N (Position.Node).Prev := N (Before.Node).Prev;
2079 N (Before.Node).Prev := Position.Node;
2080 N (Position.Node).Next := Before.Node;
2082 pragma Assert (N (Container.First).Prev = 0);
2083 pragma Assert (N (Container.Last).Next = 0);
2087 (Target : in out List;
2089 Source : in out List;
2090 Position : in out Cursor)
2092 Target_Position : Count_Type;
2095 if Target'Address = Source'Address then
2096 Splice (Target, Before, Position);
2100 if Before.Container /= null then
2101 if Before.Container /= Target'Unrestricted_Access then
2102 raise Program_Error with
2103 "Before cursor designates wrong container";
2106 pragma Assert (Vet (Before), "bad Before cursor in Splice");
2109 if Position.Node = 0 then
2110 raise Constraint_Error with "Position cursor has no element";
2113 if Position.Container /= Source'Unrestricted_Access then
2114 raise Program_Error with
2115 "Position cursor designates wrong container";
2118 pragma Assert (Vet (Position), "bad Position cursor in Splice");
2120 if Target.Length >= Target.Capacity then
2121 raise Capacity_Error with "Target is full";
2124 if Target.Busy > 0 then
2125 raise Program_Error with
2126 "attempt to tamper with cursors of Target (list is busy)";
2129 if Source.Busy > 0 then
2130 raise Program_Error with
2131 "attempt to tamper with cursors of Source (list is busy)";
2136 Before => Before.Node,
2138 Src_Pos => Position.Node,
2139 Tgt_Pos => Target_Position);
2141 Position := Cursor'(Target
'Unrestricted_Access, Target_Position
);
2144 ---------------------
2145 -- Splice_Internal --
2146 ---------------------
2148 procedure Splice_Internal
2149 (Target
: in out List
;
2150 Before
: Count_Type
;
2151 Source
: in out List
)
2153 N
: Node_Array
renames Source
.Nodes
;
2157 -- This implements the corresponding Splice operation, after the
2158 -- parameters have been vetted, and corner-cases disposed of.
2160 pragma Assert
(Target
'Address /= Source
'Address);
2161 pragma Assert
(Source
.Length
> 0);
2162 pragma Assert
(Source
.First
/= 0);
2163 pragma Assert
(N
(Source
.First
).Prev
= 0);
2164 pragma Assert
(Source
.Last
/= 0);
2165 pragma Assert
(N
(Source
.Last
).Next
= 0);
2166 pragma Assert
(Target
.Length
<= Count_Type
'Last - Source
.Length
);
2167 pragma Assert
(Target
.Length
+ Source
.Length
<= Target
.Capacity
);
2169 while Source
.Length
> 1 loop
2170 -- Copy first element of Source onto Target
2172 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2173 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2175 -- Unlink the first node from Source
2178 pragma Assert
(N
(N
(X
).Next
).Prev
= X
);
2180 Source
.First
:= N
(X
).Next
;
2181 N
(Source
.First
).Prev
:= 0;
2183 Source
.Length
:= Source
.Length
- 1;
2185 -- Return the Source node to its free store
2190 -- Copy first (and only remaining) element of Source onto Target
2192 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
2193 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
2195 -- Unlink the node from Source
2198 pragma Assert
(X
= Source
.Last
);
2205 -- Return the Source node to its free store
2208 end Splice_Internal
;
2210 procedure Splice_Internal
2211 (Target
: in out List
;
2212 Before
: Count_Type
; -- node of Target
2213 Source
: in out List
;
2214 Src_Pos
: Count_Type
; -- node of Source
2215 Tgt_Pos
: out Count_Type
)
2217 N
: Node_Array
renames Source
.Nodes
;
2220 -- This implements the corresponding Splice operation, after the
2221 -- parameters have been vetted, and corner-cases handled.
2223 pragma Assert
(Target
'Address /= Source
'Address);
2224 pragma Assert
(Target
.Length
< Target
.Capacity
);
2225 pragma Assert
(Source
.Length
> 0);
2226 pragma Assert
(Source
.First
/= 0);
2227 pragma Assert
(N
(Source
.First
).Prev
= 0);
2228 pragma Assert
(Source
.Last
/= 0);
2229 pragma Assert
(N
(Source
.Last
).Next
= 0);
2230 pragma Assert
(Src_Pos
/= 0);
2232 Allocate
(Target
, N
(Src_Pos
).Element
, New_Node
=> Tgt_Pos
);
2233 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> Tgt_Pos
);
2235 if Source
.Length
= 1 then
2236 pragma Assert
(Source
.First
= Source
.Last
);
2237 pragma Assert
(Src_Pos
= Source
.First
);
2242 elsif Src_Pos
= Source
.First
then
2243 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2245 Source
.First
:= N
(Src_Pos
).Next
;
2246 N
(Source
.First
).Prev
:= 0;
2248 elsif Src_Pos
= Source
.Last
then
2249 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2251 Source
.Last
:= N
(Src_Pos
).Prev
;
2252 N
(Source
.Last
).Next
:= 0;
2255 pragma Assert
(Source
.Length
>= 3);
2256 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2257 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2259 N
(N
(Src_Pos
).Next
).Prev
:= N
(Src_Pos
).Prev
;
2260 N
(N
(Src_Pos
).Prev
).Next
:= N
(Src_Pos
).Next
;
2263 Source
.Length
:= Source
.Length
- 1;
2264 Free
(Source
, Src_Pos
);
2265 end Splice_Internal
;
2272 (Container
: in out List
;
2277 raise Constraint_Error
with "I cursor has no element";
2281 raise Constraint_Error
with "J cursor has no element";
2284 if I
.Container
/= Container
'Unchecked_Access then
2285 raise Program_Error
with "I cursor designates wrong container";
2288 if J
.Container
/= Container
'Unchecked_Access then
2289 raise Program_Error
with "J cursor designates wrong container";
2292 if I
.Node
= J
.Node
then
2296 if Container
.Lock
> 0 then
2297 raise Program_Error
with
2298 "attempt to tamper with elements (list is locked)";
2301 pragma Assert
(Vet
(I
), "bad I cursor in Swap");
2302 pragma Assert
(Vet
(J
), "bad J cursor in Swap");
2305 EI
: Element_Type
renames Container
.Nodes
(I
.Node
).Element
;
2306 EJ
: Element_Type
renames Container
.Nodes
(J
.Node
).Element
;
2308 EI_Copy
: constant Element_Type
:= EI
;
2320 procedure Swap_Links
2321 (Container
: in out List
;
2326 raise Constraint_Error
with "I cursor has no element";
2330 raise Constraint_Error
with "J cursor has no element";
2333 if I
.Container
/= Container
'Unrestricted_Access then
2334 raise Program_Error
with "I cursor designates wrong container";
2337 if J
.Container
/= Container
'Unrestricted_Access then
2338 raise Program_Error
with "J cursor designates wrong container";
2341 if I
.Node
= J
.Node
then
2345 if Container
.Busy
> 0 then
2346 raise Program_Error
with
2347 "attempt to tamper with cursors (list is busy)";
2350 pragma Assert
(Vet
(I
), "bad I cursor in Swap_Links");
2351 pragma Assert
(Vet
(J
), "bad J cursor in Swap_Links");
2354 I_Next
: constant Cursor
:= Next
(I
);
2358 Splice
(Container
, Before
=> I
, Position
=> J
);
2362 J_Next
: constant Cursor
:= Next
(J
);
2366 Splice
(Container
, Before
=> J
, Position
=> I
);
2369 pragma Assert
(Container
.Length
>= 3);
2371 Splice
(Container
, Before
=> I_Next
, Position
=> J
);
2372 Splice
(Container
, Before
=> J_Next
, Position
=> I
);
2379 --------------------
2380 -- Update_Element --
2381 --------------------
2383 procedure Update_Element
2384 (Container
: in out List
;
2386 Process
: not null access procedure (Element
: in out Element_Type
))
2389 if Position
.Node
= 0 then
2390 raise Constraint_Error
with "Position cursor has no element";
2393 if Position
.Container
/= Container
'Unchecked_Access then
2394 raise Program_Error
with
2395 "Position cursor designates wrong container";
2398 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
2401 B
: Natural renames Container
.Busy
;
2402 L
: Natural renames Container
.Lock
;
2409 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
2411 Process
(N
.Element
);
2428 function Vet
(Position
: Cursor
) return Boolean is
2430 if Position
.Node
= 0 then
2431 return Position
.Container
= null;
2434 if Position
.Container
= null then
2439 L
: List
renames Position
.Container
.all;
2440 N
: Node_Array
renames L
.Nodes
;
2443 if L
.Length
= 0 then
2447 if L
.First
= 0 or L
.First
> L
.Capacity
then
2451 if L
.Last
= 0 or L
.Last
> L
.Capacity
then
2455 if N
(L
.First
).Prev
/= 0 then
2459 if N
(L
.Last
).Next
/= 0 then
2463 if Position
.Node
> L
.Capacity
then
2467 -- An invariant of an active node is that its Previous and Next
2468 -- components are non-negative. Operation Free sets the Previous
2469 -- component of the node to the value -1 before actually deallocating
2470 -- the node, to mark the node as inactive. (By "dellocating" we mean
2471 -- only that the node is linked onto a list of inactive nodes used
2472 -- for storage.) This marker gives us a simple way to detect a
2473 -- dangling reference to a node.
2475 if N
(Position
.Node
).Prev
< 0 then -- see Free
2479 if N
(Position
.Node
).Prev
> L
.Capacity
then
2483 if N
(Position
.Node
).Next
= Position
.Node
then
2487 if N
(Position
.Node
).Prev
= Position
.Node
then
2491 if N
(Position
.Node
).Prev
= 0
2492 and then Position
.Node
/= L
.First
2497 pragma Assert
(N
(Position
.Node
).Prev
/= 0
2498 or else Position
.Node
= L
.First
);
2500 if N
(Position
.Node
).Next
= 0
2501 and then Position
.Node
/= L
.Last
2506 pragma Assert
(N
(Position
.Node
).Next
/= 0
2507 or else Position
.Node
= L
.Last
);
2509 if L
.Length
= 1 then
2510 return L
.First
= L
.Last
;
2513 if L
.First
= L
.Last
then
2517 if N
(L
.First
).Next
= 0 then
2521 if N
(L
.Last
).Prev
= 0 then
2525 if N
(N
(L
.First
).Next
).Prev
/= L
.First
then
2529 if N
(N
(L
.Last
).Prev
).Next
/= L
.Last
then
2533 if L
.Length
= 2 then
2534 if N
(L
.First
).Next
/= L
.Last
then
2538 if N
(L
.Last
).Prev
/= L
.First
then
2545 if N
(L
.First
).Next
= L
.Last
then
2549 if N
(L
.Last
).Prev
= L
.First
then
2553 -- Eliminate earlier possibility
2555 if Position
.Node
= L
.First
then
2559 pragma Assert
(N
(Position
.Node
).Prev
/= 0);
2561 -- Eliminate another possibility
2563 if Position
.Node
= L
.Last
then
2567 pragma Assert
(N
(Position
.Node
).Next
/= 0);
2569 if N
(N
(Position
.Node
).Next
).Prev
/= Position
.Node
then
2573 if N
(N
(Position
.Node
).Prev
).Next
/= Position
.Node
then
2577 if L
.Length
= 3 then
2578 if N
(L
.First
).Next
/= Position
.Node
then
2582 if N
(L
.Last
).Prev
/= Position
.Node
then
2596 (Stream
: not null access Root_Stream_Type
'Class;
2602 Count_Type
'Base'Write (Stream, Item.Length);
2605 while Node /= 0 loop
2606 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2607 Node := Item.Nodes (Node).Next;
2612 (Stream : not null access Root_Stream_Type'Class;
2616 raise Program_Error with "attempt to stream list cursor";
2620 (Stream : not null access Root_Stream_Type'Class;
2621 Item : Reference_Type)
2624 raise Program_Error with "attempt to stream reference";
2628 (Stream : not null access Root_Stream_Type'Class;
2629 Item : Constant_Reference_Type)
2632 raise Program_Error with "attempt to stream reference";
2635 end Ada.Containers.Bounded_Doubly_Linked_Lists;