1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.BOUNDED_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2004-2017, 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 Warnings
(Off
, "variable ""Busy*"" is not referenced");
35 pragma Warnings
(Off
, "variable ""Lock*"" is not referenced");
36 -- See comment in Ada.Containers.Helpers
38 -----------------------
39 -- Local Subprograms --
40 -----------------------
43 (Container
: in out List
;
44 New_Item
: Element_Type
;
45 New_Node
: out Count_Type
);
48 (Container
: in out List
;
49 Stream
: not null access Root_Stream_Type
'Class;
50 New_Node
: out Count_Type
);
53 (Container
: in out List
;
56 procedure Insert_Internal
57 (Container
: in out List
;
59 New_Node
: Count_Type
);
61 procedure Splice_Internal
62 (Target
: in out List
;
64 Source
: in out List
);
66 procedure Splice_Internal
67 (Target
: in out List
;
71 Tgt_Pos
: out Count_Type
);
73 function Vet
(Position
: Cursor
) return Boolean;
74 -- Checks invariants of the cursor and its designated container, as a
75 -- simple way of detecting dangling references (see operation Free for a
76 -- description of the detection mechanism), returning True if all checks
77 -- pass. Invocations of Vet are used here as the argument of pragma Assert,
78 -- so the checks are performed only when assertions are enabled.
84 function "=" (Left
, Right
: List
) return Boolean is
86 if Left
.Length
/= Right
.Length
then
90 if Left
.Length
= 0 then
95 -- Per AI05-0022, the container implementation is required to detect
96 -- element tampering by a generic actual subprogram.
98 Lock_Left
: With_Lock
(Left
.TC
'Unrestricted_Access);
99 Lock_Right
: With_Lock
(Right
.TC
'Unrestricted_Access);
101 LN
: Node_Array
renames Left
.Nodes
;
102 RN
: Node_Array
renames Right
.Nodes
;
104 LI
: Count_Type
:= Left
.First
;
105 RI
: Count_Type
:= Right
.First
;
107 for J
in 1 .. Left
.Length
loop
108 if LN
(LI
).Element
/= RN
(RI
).Element
then
125 (Container
: in out List
;
126 New_Item
: Element_Type
;
127 New_Node
: out Count_Type
)
129 N
: Node_Array
renames Container
.Nodes
;
132 if Container
.Free
>= 0 then
133 New_Node
:= Container
.Free
;
135 -- We always perform the assignment first, before we change container
136 -- state, in order to defend against exceptions duration assignment.
138 N
(New_Node
).Element
:= New_Item
;
139 Container
.Free
:= N
(New_Node
).Next
;
142 -- A negative free store value means that the links of the nodes in
143 -- the free store have not been initialized. In this case, the nodes
144 -- are physically contiguous in the array, starting at the index that
145 -- is the absolute value of the Container.Free, and continuing until
146 -- the end of the array (Nodes'Last).
148 New_Node
:= abs Container
.Free
;
150 -- As above, we perform this assignment first, before modifying any
153 N
(New_Node
).Element
:= New_Item
;
154 Container
.Free
:= Container
.Free
- 1;
159 (Container
: in out List
;
160 Stream
: not null access Root_Stream_Type
'Class;
161 New_Node
: out Count_Type
)
163 N
: Node_Array
renames Container
.Nodes
;
166 if Container
.Free
>= 0 then
167 New_Node
:= Container
.Free
;
169 -- We always perform the assignment first, before we change container
170 -- state, in order to defend against exceptions duration assignment.
172 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
173 Container
.Free
:= N
(New_Node
).Next
;
176 -- A negative free store value means that the links of the nodes in
177 -- the free store have not been initialized. In this case, the nodes
178 -- are physically contiguous in the array, starting at the index that
179 -- is the absolute value of the Container.Free, and continuing until
180 -- the end of the array (Nodes'Last).
182 New_Node
:= abs Container
.Free
;
184 -- As above, we perform this assignment first, before modifying any
187 Element_Type
'Read (Stream
, N
(New_Node
).Element
);
188 Container
.Free
:= Container
.Free
- 1;
197 (Container
: in out List
;
198 New_Item
: Element_Type
;
199 Count
: Count_Type
:= 1)
202 Insert
(Container
, No_Element
, New_Item
, Count
);
209 procedure Assign
(Target
: in out List
; Source
: List
) is
210 SN
: Node_Array
renames Source
.Nodes
;
214 if Target
'Address = Source
'Address then
218 if Checks
and then Target
.Capacity
< Source
.Length
then
219 raise Capacity_Error
-- ???
220 with "Target capacity is less than Source length";
227 Target
.Append
(SN
(J
).Element
);
236 procedure Clear
(Container
: in out List
) is
237 N
: Node_Array
renames Container
.Nodes
;
241 if Container
.Length
= 0 then
242 pragma Assert
(Container
.First
= 0);
243 pragma Assert
(Container
.Last
= 0);
244 pragma Assert
(Container
.TC
= (Busy
=> 0, Lock
=> 0));
248 pragma Assert
(Container
.First
>= 1);
249 pragma Assert
(Container
.Last
>= 1);
250 pragma Assert
(N
(Container
.First
).Prev
= 0);
251 pragma Assert
(N
(Container
.Last
).Next
= 0);
253 TC_Check
(Container
.TC
);
255 while Container
.Length
> 1 loop
256 X
:= Container
.First
;
257 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
259 Container
.First
:= N
(X
).Next
;
260 N
(Container
.First
).Prev
:= 0;
262 Container
.Length
:= Container
.Length
- 1;
267 X
:= Container
.First
;
268 pragma Assert
(X
= Container
.Last
);
270 Container
.First
:= 0;
272 Container
.Length
:= 0;
277 ------------------------
278 -- Constant_Reference --
279 ------------------------
281 function Constant_Reference
282 (Container
: aliased List
;
283 Position
: Cursor
) return Constant_Reference_Type
286 if Checks
and then Position
.Container
= null then
287 raise Constraint_Error
with "Position cursor has no element";
290 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
292 raise Program_Error
with
293 "Position cursor designates wrong container";
296 pragma Assert
(Vet
(Position
), "bad cursor in Constant_Reference");
299 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
300 TC
: constant Tamper_Counts_Access
:=
301 Container
.TC
'Unrestricted_Access;
303 return R
: constant Constant_Reference_Type
:=
304 (Element
=> N
.Element
'Access,
305 Control
=> (Controlled
with TC
))
310 end Constant_Reference
;
318 Item
: Element_Type
) return Boolean
321 return Find
(Container
, Item
) /= No_Element
;
328 function Copy
(Source
: List
; Capacity
: Count_Type
:= 0) return List
is
332 if Capacity
< Source
.Length
then
333 if Checks
and then Capacity
/= 0 then
335 with "Requested capacity is less than Source length";
343 return Target
: List
(Capacity
=> C
) do
344 Assign
(Target
=> Target
, Source
=> Source
);
353 (Container
: in out List
;
354 Position
: in out Cursor
;
355 Count
: Count_Type
:= 1)
357 N
: Node_Array
renames Container
.Nodes
;
361 if Checks
and then Position
.Node
= 0 then
362 raise Constraint_Error
with
363 "Position cursor has no element";
366 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
368 raise Program_Error
with
369 "Position cursor designates wrong container";
372 pragma Assert
(Vet
(Position
), "bad cursor in Delete");
373 pragma Assert
(Container
.First
>= 1);
374 pragma Assert
(Container
.Last
>= 1);
375 pragma Assert
(N
(Container
.First
).Prev
= 0);
376 pragma Assert
(N
(Container
.Last
).Next
= 0);
378 if Position
.Node
= Container
.First
then
379 Delete_First
(Container
, Count
);
380 Position
:= No_Element
;
385 Position
:= No_Element
;
389 TC_Check
(Container
.TC
);
391 for Index
in 1 .. Count
loop
392 pragma Assert
(Container
.Length
>= 2);
395 Container
.Length
:= Container
.Length
- 1;
397 if X
= Container
.Last
then
398 Position
:= No_Element
;
400 Container
.Last
:= N
(X
).Prev
;
401 N
(Container
.Last
).Next
:= 0;
407 Position
.Node
:= N
(X
).Next
;
409 N
(N
(X
).Next
).Prev
:= N
(X
).Prev
;
410 N
(N
(X
).Prev
).Next
:= N
(X
).Next
;
415 Position
:= No_Element
;
422 procedure Delete_First
423 (Container
: in out List
;
424 Count
: Count_Type
:= 1)
426 N
: Node_Array
renames Container
.Nodes
;
430 if Count
>= Container
.Length
then
439 TC_Check
(Container
.TC
);
441 for J
in 1 .. Count
loop
442 X
:= Container
.First
;
443 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
445 Container
.First
:= N
(X
).Next
;
446 N
(Container
.First
).Prev
:= 0;
448 Container
.Length
:= Container
.Length
- 1;
458 procedure Delete_Last
459 (Container
: in out List
;
460 Count
: Count_Type
:= 1)
462 N
: Node_Array
renames Container
.Nodes
;
466 if Count
>= Container
.Length
then
475 TC_Check
(Container
.TC
);
477 for J
in 1 .. Count
loop
479 pragma Assert
(N
(N
(X
).Prev
).Next
= Container
.Last
);
481 Container
.Last
:= N
(X
).Prev
;
482 N
(Container
.Last
).Next
:= 0;
484 Container
.Length
:= Container
.Length
- 1;
494 function Element
(Position
: Cursor
) return Element_Type
is
496 if Checks
and then Position
.Node
= 0 then
497 raise Constraint_Error
with
498 "Position cursor has no element";
501 pragma Assert
(Vet
(Position
), "bad cursor in Element");
503 return Position
.Container
.Nodes
(Position
.Node
).Element
;
510 procedure Finalize
(Object
: in out Iterator
) is
512 if Object
.Container
/= null then
513 Unbusy
(Object
.Container
.TC
);
524 Position
: Cursor
:= No_Element
) return Cursor
526 Nodes
: Node_Array
renames Container
.Nodes
;
527 Node
: Count_Type
:= Position
.Node
;
531 Node
:= Container
.First
;
534 if Checks
and then Position
.Container
/= Container
'Unrestricted_Access
536 raise Program_Error
with
537 "Position cursor designates wrong container";
540 pragma Assert
(Vet
(Position
), "bad cursor in Find");
543 -- Per AI05-0022, the container implementation is required to detect
544 -- element tampering by a generic actual subprogram.
547 Lock
: With_Lock
(Container
.TC
'Unrestricted_Access);
550 if Nodes
(Node
).Element
= Item
then
551 return Cursor
'(Container'Unrestricted_Access, Node);
554 Node := Nodes (Node).Next;
565 function First (Container : List) return Cursor is
567 if Container.First = 0 then
570 return Cursor'(Container
'Unrestricted_Access, Container
.First
);
574 function First
(Object
: Iterator
) return Cursor
is
576 -- The value of the iterator object's Node component influences the
577 -- behavior of the First (and Last) selector function.
579 -- When the Node component is 0, this means the iterator object was
580 -- constructed without a start expression, in which case the (forward)
581 -- iteration starts from the (logical) beginning of the entire sequence
582 -- of items (corresponding to Container.First, for a forward iterator).
584 -- Otherwise, this is iteration over a partial sequence of items. When
585 -- the Node component is positive, the iterator object was constructed
586 -- with a start expression, that specifies the position from which the
587 -- (forward) partial iteration begins.
589 if Object
.Node
= 0 then
590 return Bounded_Doubly_Linked_Lists
.First
(Object
.Container
.all);
592 return Cursor
'(Object.Container, Object.Node);
600 function First_Element (Container : List) return Element_Type is
602 if Checks and then Container.First = 0 then
603 raise Constraint_Error with "list is empty";
606 return Container.Nodes (Container.First).Element;
614 (Container : in out List;
617 pragma Assert (X > 0);
618 pragma Assert (X <= Container.Capacity);
620 N : Node_Array renames Container.Nodes;
621 pragma Assert (N (X).Prev >= 0); -- node is active
624 -- The list container actually contains two lists: one for the "active"
625 -- nodes that contain elements that have been inserted onto the list,
626 -- and another for the "inactive" nodes for the free store.
628 -- We desire that merely declaring an object should have only minimal
629 -- cost; specially, we want to avoid having to initialize the free
630 -- store (to fill in the links), especially if the capacity is large.
632 -- The head of the free list is indicated by Container.Free. If its
633 -- value is non-negative, then the free store has been initialized in
634 -- the "normal" way: Container.Free points to the head of the list of
635 -- free (inactive) nodes, and the value 0 means the free list is empty.
636 -- Each node on the free list has been initialized to point to the next
637 -- free node (via its Next component), and the value 0 means that this
638 -- is the last free node.
640 -- If Container.Free is negative, then the links on the free store have
641 -- not been initialized. In this case the link values are implied: the
642 -- free store comprises the components of the node array started with
643 -- the absolute value of Container.Free, and continuing until the end of
644 -- the array (Nodes'Last).
646 -- If the list container is manipulated on one end only (for example if
647 -- the container were being used as a stack), then there is no need to
648 -- initialize the free store, since the inactive nodes are physically
649 -- contiguous (in fact, they lie immediately beyond the logical end
650 -- being manipulated). The only time we need to actually initialize the
651 -- nodes in the free store is if the node that becomes inactive is not
652 -- at the end of the list. The free store would then be discontiguous
653 -- and so its nodes would need to be linked in the traditional way.
656 -- It might be possible to perform an optimization here. Suppose that
657 -- the free store can be represented as having two parts: one comprising
658 -- the non-contiguous inactive nodes linked together in the normal way,
659 -- and the other comprising the contiguous inactive nodes (that are not
660 -- linked together, at the end of the nodes array). This would allow us
661 -- to never have to initialize the free store, except in a lazy way as
662 -- nodes become inactive.
664 -- When an element is deleted from the list container, its node becomes
665 -- inactive, and so we set its Prev component to a negative value, to
666 -- indicate that it is now inactive. This provides a useful way to
667 -- detect a dangling cursor reference (and which is used in Vet).
669 N (X).Prev := -1; -- Node is deallocated (not on active list)
671 if Container.Free >= 0 then
673 -- The free store has previously been initialized. All we need to
674 -- do here is link the newly-free'd node onto the free list.
676 N (X).Next := Container.Free;
679 elsif X + 1 = abs Container.Free then
681 -- The free store has not been initialized, and the node becoming
682 -- inactive immediately precedes the start of the free store. All
683 -- we need to do is move the start of the free store back by one.
685 -- Note: initializing Next to zero is not strictly necessary but
686 -- seems cleaner and marginally safer.
689 Container.Free := Container.Free + 1;
692 -- The free store has not been initialized, and the node becoming
693 -- inactive does not immediately precede the free store. Here we
694 -- first initialize the free store (meaning the links are given
695 -- values in the traditional way), and then link the newly-free'd
696 -- node onto the head of the free store.
699 -- See the comments above for an optimization opportunity. If the
700 -- next link for a node on the free store is negative, then this
701 -- means the remaining nodes on the free store are physically
702 -- contiguous, starting as the absolute value of that index value.
704 Container.Free := abs Container.Free;
706 if Container.Free > Container.Capacity then
710 for I in Container.Free .. Container.Capacity - 1 loop
714 N (Container.Capacity).Next := 0;
717 N (X).Next := Container.Free;
722 ---------------------
723 -- Generic_Sorting --
724 ---------------------
726 package body Generic_Sorting is
732 function Is_Sorted (Container : List) return Boolean is
733 -- Per AI05-0022, the container implementation is required to detect
734 -- element tampering by a generic actual subprogram.
736 Lock : With_Lock (Container.TC'Unrestricted_Access);
738 Nodes : Node_Array renames Container.Nodes;
741 Node := Container.First;
742 for J in 2 .. Container.Length loop
743 if Nodes (Nodes (Node).Next).Element < Nodes (Node).Element then
747 Node := Nodes (Node).Next;
758 (Target : in out List;
759 Source : in out List)
762 -- The semantics of Merge changed slightly per AI05-0021. It was
763 -- originally the case that if Target and Source denoted the same
764 -- container object, then the GNAT implementation of Merge did
765 -- nothing. However, it was argued that RM05 did not precisely
766 -- specify the semantics for this corner case. The decision of the
767 -- ARG was that if Target and Source denote the same non-empty
768 -- container object, then Program_Error is raised.
770 if Source.Is_Empty then
774 if Checks and then Target'Address = Source'Address then
775 raise Program_Error with
776 "Target and Source denote same non-empty container";
779 if Checks and then Target.Length > Count_Type'Last - Source.Length
781 raise Constraint_Error with "new length exceeds maximum";
784 if Checks and then Target.Length + Source.Length > Target.Capacity
786 raise Capacity_Error with "new length exceeds target capacity";
789 TC_Check (Target.TC);
790 TC_Check (Source.TC);
792 -- Per AI05-0022, the container implementation is required to detect
793 -- element tampering by a generic actual subprogram.
796 Lock_Target : With_Lock (Target.TC'Unchecked_Access);
797 Lock_Source : With_Lock (Source.TC'Unchecked_Access);
799 LN : Node_Array renames Target.Nodes;
800 RN : Node_Array renames Source.Nodes;
802 LI, LJ, RI, RJ : Count_Type;
808 pragma Assert (RN (RI).Next = 0
809 or else not (RN (RN (RI).Next).Element <
813 Splice_Internal (Target, 0, Source);
817 pragma Assert (LN (LI).Next = 0
818 or else not (LN (LN (LI).Next).Element <
821 if RN (RI).Element < LN (LI).Element then
824 Splice_Internal (Target, LI, Source, RJ, LJ);
837 procedure Sort (Container : in out List) is
838 N : Node_Array renames Container.Nodes;
840 procedure Partition (Pivot, Back : Count_Type);
841 -- What does this do ???
843 procedure Sort (Front, Back : Count_Type);
844 -- Internal procedure, what does it do??? rename it???
850 procedure Partition (Pivot, Back : Count_Type) is
854 Node := N (Pivot).Next;
855 while Node /= Back loop
856 if N (Node).Element < N (Pivot).Element then
858 Prev : constant Count_Type := N (Node).Prev;
859 Next : constant Count_Type := N (Node).Next;
862 N (Prev).Next := Next;
865 Container.Last := Prev;
867 N (Next).Prev := Prev;
870 N (Node).Next := Pivot;
871 N (Node).Prev := N (Pivot).Prev;
873 N (Pivot).Prev := Node;
875 if N (Node).Prev = 0 then
876 Container.First := Node;
878 N (N (Node).Prev).Next := Node;
885 Node := N (Node).Next;
894 procedure Sort (Front, Back : Count_Type) is
895 Pivot : constant Count_Type :=
896 (if Front = 0 then Container.First else N (Front).Next);
898 if Pivot /= Back then
899 Partition (Pivot, Back);
905 -- Start of processing for Sort
908 if Container.Length <= 1 then
912 pragma Assert (N (Container.First).Prev = 0);
913 pragma Assert (N (Container.Last).Next = 0);
915 TC_Check (Container.TC);
917 -- Per AI05-0022, the container implementation is required to detect
918 -- element tampering by a generic actual subprogram.
921 Lock : With_Lock (Container.TC'Unchecked_Access);
923 Sort (Front => 0, Back => 0);
926 pragma Assert (N (Container.First).Prev = 0);
927 pragma Assert (N (Container.Last).Next = 0);
932 ------------------------
933 -- Get_Element_Access --
934 ------------------------
936 function Get_Element_Access
937 (Position : Cursor) return not null Element_Access is
939 return Position.Container.Nodes (Position.Node).Element'Access;
940 end Get_Element_Access;
946 function Has_Element (Position : Cursor) return Boolean is
948 pragma Assert (Vet (Position), "bad cursor in Has_Element");
949 return Position.Node /= 0;
957 (Container : in out List;
959 New_Item : Element_Type;
960 Position : out Cursor;
961 Count : Count_Type := 1)
963 First_Node : Count_Type;
964 New_Node : Count_Type;
967 if Before.Container /= null then
968 if Checks and then Before.Container /= Container'Unrestricted_Access
970 raise Program_Error with
971 "Before cursor designates wrong list";
974 pragma Assert (Vet (Before), "bad cursor in Insert");
982 if Checks and then Container.Length > Container.Capacity - Count then
983 raise Capacity_Error with "capacity exceeded";
986 TC_Check (Container.TC);
988 Allocate (Container, New_Item, New_Node);
989 First_Node := New_Node;
990 Insert_Internal (Container, Before.Node, New_Node);
992 for Index in Count_Type'(2) .. Count
loop
993 Allocate
(Container
, New_Item
, New_Node
);
994 Insert_Internal
(Container
, Before
.Node
, New_Node
);
997 Position
:= Cursor
'(Container'Unchecked_Access, First_Node);
1001 (Container : in out List;
1003 New_Item : Element_Type;
1004 Count : Count_Type := 1)
1007 pragma Unreferenced (Position);
1009 Insert (Container, Before, New_Item, Position, Count);
1013 (Container : in out List;
1015 Position : out Cursor;
1016 Count : Count_Type := 1)
1018 pragma Warnings (Off);
1019 Default_Initialized_Item : Element_Type;
1020 pragma Unmodified (Default_Initialized_Item);
1021 -- OK to reference, see below. Note that we need to suppress both the
1022 -- front end warning and the back end warning. In addition, pragma
1023 -- Unmodified is needed to suppress the warning ``actual type for
1024 -- "Element_Type" should be fully initialized type'' on certain
1028 -- There is no explicit element provided, but in an instance the element
1029 -- type may be a scalar with a Default_Value aspect, or a composite
1030 -- type with such a scalar component, or components with default
1031 -- initialization, so insert the specified number of possibly
1032 -- initialized elements at the given position.
1034 Insert (Container, Before, Default_Initialized_Item, Position, Count);
1035 pragma Warnings (On);
1038 ---------------------
1039 -- Insert_Internal --
1040 ---------------------
1042 procedure Insert_Internal
1043 (Container : in out List;
1044 Before : Count_Type;
1045 New_Node : Count_Type)
1047 N : Node_Array renames Container.Nodes;
1050 if Container.Length = 0 then
1051 pragma Assert (Before = 0);
1052 pragma Assert (Container.First = 0);
1053 pragma Assert (Container.Last = 0);
1055 Container.First := New_Node;
1056 N (Container.First).Prev := 0;
1058 Container.Last := New_Node;
1059 N (Container.Last).Next := 0;
1061 -- Before = zero means append
1063 elsif Before = 0 then
1064 pragma Assert (N (Container.Last).Next = 0);
1066 N (Container.Last).Next := New_Node;
1067 N (New_Node).Prev := Container.Last;
1069 Container.Last := New_Node;
1070 N (Container.Last).Next := 0;
1072 -- Before = Container.First means prepend
1074 elsif Before = Container.First then
1075 pragma Assert (N (Container.First).Prev = 0);
1077 N (Container.First).Prev := New_Node;
1078 N (New_Node).Next := Container.First;
1080 Container.First := New_Node;
1081 N (Container.First).Prev := 0;
1084 pragma Assert (N (Container.First).Prev = 0);
1085 pragma Assert (N (Container.Last).Next = 0);
1087 N (New_Node).Next := Before;
1088 N (New_Node).Prev := N (Before).Prev;
1090 N (N (Before).Prev).Next := New_Node;
1091 N (Before).Prev := New_Node;
1094 Container.Length := Container.Length + 1;
1095 end Insert_Internal;
1101 function Is_Empty (Container : List) return Boolean is
1103 return Container.Length = 0;
1112 Process : not null access procedure (Position : Cursor))
1114 Busy : With_Busy (Container.TC'Unrestricted_Access);
1115 Node : Count_Type := Container.First;
1118 while Node /= 0 loop
1119 Process (Cursor'(Container
'Unrestricted_Access, Node
));
1120 Node
:= Container
.Nodes
(Node
).Next
;
1126 return List_Iterator_Interfaces
.Reversible_Iterator
'Class
1129 -- The value of the Node component influences the behavior of the First
1130 -- and Last selector functions of the iterator object. When the Node
1131 -- component is 0 (as is the case here), this means the iterator
1132 -- object was constructed without a start expression. This is a
1133 -- complete iterator, meaning that the iteration starts from the
1134 -- (logical) beginning of the sequence of items.
1136 -- Note: For a forward iterator, Container.First is the beginning, and
1137 -- for a reverse iterator, Container.Last is the beginning.
1139 return It
: constant Iterator
:=
1140 Iterator
'(Limited_Controlled with
1141 Container => Container'Unrestricted_Access,
1144 Busy (Container.TC'Unrestricted_Access.all);
1151 return List_Iterator_Interfaces.Reversible_Iterator'class
1154 -- It was formerly the case that when Start = No_Element, the partial
1155 -- iterator was defined to behave the same as for a complete iterator,
1156 -- and iterate over the entire sequence of items. However, those
1157 -- semantics were unintuitive and arguably error-prone (it is too easy
1158 -- to accidentally create an endless loop), and so they were changed,
1159 -- per the ARG meeting in Denver on 2011/11. However, there was no
1160 -- consensus about what positive meaning this corner case should have,
1161 -- and so it was decided to simply raise an exception. This does imply,
1162 -- however, that it is not possible to use a partial iterator to specify
1163 -- an empty sequence of items.
1165 if Checks and then Start = No_Element then
1166 raise Constraint_Error with
1167 "Start position for iterator equals No_Element";
1170 if Checks and then Start.Container /= Container'Unrestricted_Access then
1171 raise Program_Error with
1172 "Start cursor of Iterate designates wrong list";
1175 pragma Assert (Vet (Start), "Start cursor of Iterate is bad");
1177 -- The value of the Node component influences the behavior of the First
1178 -- and Last selector functions of the iterator object. When the Node
1179 -- component is positive (as is the case here), it means that this
1180 -- is a partial iteration, over a subset of the complete sequence of
1181 -- items. The iterator object was constructed with a start expression,
1182 -- indicating the position from which the iteration begins. Note that
1183 -- the start position has the same value irrespective of whether this
1184 -- is a forward or reverse iteration.
1186 return It : constant Iterator :=
1187 Iterator'(Limited_Controlled
with
1188 Container
=> Container
'Unrestricted_Access,
1191 Busy
(Container
.TC
'Unrestricted_Access.all);
1199 function Last
(Container
: List
) return Cursor
is
1201 if Container
.Last
= 0 then
1204 return Cursor
'(Container'Unrestricted_Access, Container.Last);
1208 function Last (Object : Iterator) return Cursor is
1210 -- The value of the iterator object's Node component influences the
1211 -- behavior of the Last (and First) selector function.
1213 -- When the Node component is 0, this means the iterator object was
1214 -- constructed without a start expression, in which case the (reverse)
1215 -- iteration starts from the (logical) beginning of the entire sequence
1216 -- (corresponding to Container.Last, for a reverse iterator).
1218 -- Otherwise, this is iteration over a partial sequence of items. When
1219 -- the Node component is positive, the iterator object was constructed
1220 -- with a start expression, that specifies the position from which the
1221 -- (reverse) partial iteration begins.
1223 if Object.Node = 0 then
1224 return Bounded_Doubly_Linked_Lists.Last (Object.Container.all);
1226 return Cursor'(Object
.Container
, Object
.Node
);
1234 function Last_Element
(Container
: List
) return Element_Type
is
1236 if Checks
and then Container
.Last
= 0 then
1237 raise Constraint_Error
with "list is empty";
1240 return Container
.Nodes
(Container
.Last
).Element
;
1247 function Length
(Container
: List
) return Count_Type
is
1249 return Container
.Length
;
1257 (Target
: in out List
;
1258 Source
: in out List
)
1260 N
: Node_Array
renames Source
.Nodes
;
1264 if Target
'Address = Source
'Address then
1268 if Checks
and then Target
.Capacity
< Source
.Length
then
1269 raise Capacity_Error
with "Source length exceeds Target capacity";
1272 TC_Check
(Source
.TC
);
1274 -- Clear target, note that this checks busy bits of Target
1278 while Source
.Length
> 1 loop
1279 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1280 pragma Assert
(Source
.Last
/= Source
.First
);
1281 pragma Assert
(N
(Source
.First
).Prev
= 0);
1282 pragma Assert
(N
(Source
.Last
).Next
= 0);
1284 -- Copy first element from Source to Target
1287 Append
(Target
, N
(X
).Element
);
1289 -- Unlink first node of Source
1291 Source
.First
:= N
(X
).Next
;
1292 N
(Source
.First
).Prev
:= 0;
1294 Source
.Length
:= Source
.Length
- 1;
1296 -- The representation invariants for Source have been restored. It is
1297 -- now safe to free the unlinked node, without fear of corrupting the
1298 -- active links of Source.
1300 -- Note that the algorithm we use here models similar algorithms used
1301 -- in the unbounded form of the doubly-linked list container. In that
1302 -- case, Free is an instantation of Unchecked_Deallocation, which can
1303 -- fail (because PE will be raised if controlled Finalize fails), so
1304 -- we must defer the call until the last step. Here in the bounded
1305 -- form, Free merely links the node we have just "deallocated" onto a
1306 -- list of inactive nodes, so technically Free cannot fail. However,
1307 -- for consistency, we handle Free the same way here as we do for the
1308 -- unbounded form, with the pessimistic assumption that it can fail.
1313 if Source
.Length
= 1 then
1314 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1315 pragma Assert
(Source
.Last
= Source
.First
);
1316 pragma Assert
(N
(Source
.First
).Prev
= 0);
1317 pragma Assert
(N
(Source
.Last
).Next
= 0);
1319 -- Copy element from Source to Target
1322 Append
(Target
, N
(X
).Element
);
1324 -- Unlink node of Source
1330 -- Return the unlinked node to the free store
1340 procedure Next
(Position
: in out Cursor
) is
1342 Position
:= Next
(Position
);
1345 function Next
(Position
: Cursor
) return Cursor
is
1347 if Position
.Node
= 0 then
1351 pragma Assert
(Vet
(Position
), "bad cursor in Next");
1354 Nodes
: Node_Array
renames Position
.Container
.Nodes
;
1355 Node
: constant Count_Type
:= Nodes
(Position
.Node
).Next
;
1360 return Cursor
'(Position.Container, Node);
1367 Position : Cursor) return Cursor
1370 if Position.Container = null then
1374 if Checks and then Position.Container /= Object.Container then
1375 raise Program_Error with
1376 "Position cursor of Next designates wrong list";
1379 return Next (Position);
1387 (Container : in out List;
1388 New_Item : Element_Type;
1389 Count : Count_Type := 1)
1392 Insert (Container, First (Container), New_Item, Count);
1399 procedure Previous (Position : in out Cursor) is
1401 Position := Previous (Position);
1404 function Previous (Position : Cursor) return Cursor is
1406 if Position.Node = 0 then
1410 pragma Assert (Vet (Position), "bad cursor in Previous");
1413 Nodes : Node_Array renames Position.Container.Nodes;
1414 Node : constant Count_Type := Nodes (Position.Node).Prev;
1419 return Cursor'(Position
.Container
, Node
);
1426 Position
: Cursor
) return Cursor
1429 if Position
.Container
= null then
1433 if Checks
and then Position
.Container
/= Object
.Container
then
1434 raise Program_Error
with
1435 "Position cursor of Previous designates wrong list";
1438 return Previous
(Position
);
1441 ----------------------
1442 -- Pseudo_Reference --
1443 ----------------------
1445 function Pseudo_Reference
1446 (Container
: aliased List
'Class) return Reference_Control_Type
1448 TC
: constant Tamper_Counts_Access
:= Container
.TC
'Unrestricted_Access;
1450 return R
: constant Reference_Control_Type
:= (Controlled
with TC
) do
1453 end Pseudo_Reference
;
1459 procedure Query_Element
1461 Process
: not null access procedure (Element
: Element_Type
))
1464 if Checks
and then Position
.Node
= 0 then
1465 raise Constraint_Error
with
1466 "Position cursor has no element";
1469 pragma Assert
(Vet
(Position
), "bad cursor in Query_Element");
1472 Lock
: With_Lock
(Position
.Container
.TC
'Unrestricted_Access);
1473 C
: List
renames Position
.Container
.all'Unrestricted_Access.all;
1474 N
: Node_Type
renames C
.Nodes
(Position
.Node
);
1476 Process
(N
.Element
);
1485 (Stream
: not null access Root_Stream_Type
'Class;
1488 N
: Count_Type
'Base;
1493 Count_Type
'Base'Read (Stream, N);
1495 if Checks and then N < 0 then
1496 raise Program_Error with "bad list length (corrupt stream)";
1503 if Checks and then N > Item.Capacity then
1504 raise Constraint_Error with "length exceeds capacity";
1507 for Idx in 1 .. N loop
1508 Allocate (Item, Stream, New_Node => X);
1509 Insert_Internal (Item, Before => 0, New_Node => X);
1514 (Stream : not null access Root_Stream_Type'Class;
1518 raise Program_Error with "attempt to stream list cursor";
1522 (Stream : not null access Root_Stream_Type'Class;
1523 Item : out Reference_Type)
1526 raise Program_Error with "attempt to stream reference";
1530 (Stream : not null access Root_Stream_Type'Class;
1531 Item : out Constant_Reference_Type)
1534 raise Program_Error with "attempt to stream reference";
1542 (Container : aliased in out List;
1543 Position : Cursor) return Reference_Type
1546 if Checks and then Position.Container = null then
1547 raise Constraint_Error with "Position cursor has no element";
1550 if Checks and then Position.Container /= Container'Unrestricted_Access
1552 raise Program_Error with
1553 "Position cursor designates wrong container";
1556 pragma Assert (Vet (Position), "bad cursor in function Reference");
1559 N : Node_Type renames Container.Nodes (Position.Node);
1560 TC : constant Tamper_Counts_Access :=
1561 Container.TC'Unrestricted_Access;
1563 return R : constant Reference_Type :=
1564 (Element => N.Element'Access,
1565 Control => (Controlled with TC))
1572 ---------------------
1573 -- Replace_Element --
1574 ---------------------
1576 procedure Replace_Element
1577 (Container : in out List;
1579 New_Item : Element_Type)
1582 if Checks and then Position.Container = null then
1583 raise Constraint_Error with "Position cursor has no element";
1586 if Checks and then Position.Container /= Container'Unchecked_Access then
1587 raise Program_Error with
1588 "Position cursor designates wrong container";
1591 TE_Check (Container.TC);
1593 pragma Assert (Vet (Position), "bad cursor in Replace_Element");
1595 Container.Nodes (Position.Node).Element := New_Item;
1596 end Replace_Element;
1598 ----------------------
1599 -- Reverse_Elements --
1600 ----------------------
1602 procedure Reverse_Elements (Container : in out List) is
1603 N : Node_Array renames Container.Nodes;
1604 I : Count_Type := Container.First;
1605 J : Count_Type := Container.Last;
1607 procedure Swap (L, R : Count_Type);
1613 procedure Swap (L, R : Count_Type) is
1614 LN : constant Count_Type := N (L).Next;
1615 LP : constant Count_Type := N (L).Prev;
1617 RN : constant Count_Type := N (R).Next;
1618 RP : constant Count_Type := N (R).Prev;
1633 pragma Assert (RP = L);
1647 -- Start of processing for Reverse_Elements
1650 if Container.Length <= 1 then
1654 pragma Assert (N (Container.First).Prev = 0);
1655 pragma Assert (N (Container.Last).Next = 0);
1657 TC_Check (Container.TC);
1659 Container.First := J;
1660 Container.Last := I;
1662 Swap (L => I, R => J);
1670 Swap (L => J, R => I);
1679 pragma Assert (N (Container.First).Prev = 0);
1680 pragma Assert (N (Container.Last).Next = 0);
1681 end Reverse_Elements;
1687 function Reverse_Find
1689 Item : Element_Type;
1690 Position : Cursor := No_Element) return Cursor
1692 Node : Count_Type := Position.Node;
1696 Node := Container.Last;
1699 if Checks and then Position.Container /= Container'Unrestricted_Access
1701 raise Program_Error with
1702 "Position cursor designates wrong container";
1705 pragma Assert (Vet (Position), "bad cursor in Reverse_Find");
1708 -- Per AI05-0022, the container implementation is required to detect
1709 -- element tampering by a generic actual subprogram.
1712 Lock : With_Lock (Container.TC'Unrestricted_Access);
1714 while Node /= 0 loop
1715 if Container.Nodes (Node).Element = Item then
1716 return Cursor'(Container
'Unrestricted_Access, Node
);
1719 Node
:= Container
.Nodes
(Node
).Prev
;
1726 ---------------------
1727 -- Reverse_Iterate --
1728 ---------------------
1730 procedure Reverse_Iterate
1732 Process
: not null access procedure (Position
: Cursor
))
1734 Busy
: With_Busy
(Container
.TC
'Unrestricted_Access);
1735 Node
: Count_Type
:= Container
.Last
;
1738 while Node
/= 0 loop
1739 Process
(Cursor
'(Container'Unrestricted_Access, Node));
1740 Node := Container.Nodes (Node).Prev;
1742 end Reverse_Iterate;
1749 (Target : in out List;
1751 Source : in out List)
1754 if Before.Container /= null then
1755 if Checks and then Before.Container /= Target'Unrestricted_Access then
1756 raise Program_Error with
1757 "Before cursor designates wrong container";
1760 pragma Assert (Vet (Before), "bad cursor in Splice");
1763 if Target'Address = Source'Address or else Source.Length = 0 then
1767 if Checks and then Target.Length > Count_Type'Last - Source.Length then
1768 raise Constraint_Error with "new length exceeds maximum";
1771 if Checks and then Target.Length + Source.Length > Target.Capacity then
1772 raise Capacity_Error with "new length exceeds target capacity";
1775 TC_Check (Target.TC);
1776 TC_Check (Source.TC);
1778 Splice_Internal (Target, Before.Node, Source);
1782 (Container : in out List;
1786 N : Node_Array renames Container.Nodes;
1789 if Before.Container /= null then
1790 if Checks and then Before.Container /= Container'Unchecked_Access then
1791 raise Program_Error with
1792 "Before cursor designates wrong container";
1795 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1798 if Checks and then Position.Node = 0 then
1799 raise Constraint_Error with "Position cursor has no element";
1802 if Checks and then Position.Container /= Container'Unrestricted_Access
1804 raise Program_Error with
1805 "Position cursor designates wrong container";
1808 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1810 if Position.Node = Before.Node
1811 or else N (Position.Node).Next = Before.Node
1816 pragma Assert (Container.Length >= 2);
1818 TC_Check (Container.TC);
1820 if Before.Node = 0 then
1821 pragma Assert (Position.Node /= Container.Last);
1823 if Position.Node = Container.First then
1824 Container.First := N (Position.Node).Next;
1825 N (Container.First).Prev := 0;
1827 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1828 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1831 N (Container.Last).Next := Position.Node;
1832 N (Position.Node).Prev := Container.Last;
1834 Container.Last := Position.Node;
1835 N (Container.Last).Next := 0;
1840 if Before.Node = Container.First then
1841 pragma Assert (Position.Node /= Container.First);
1843 if Position.Node = Container.Last then
1844 Container.Last := N (Position.Node).Prev;
1845 N (Container.Last).Next := 0;
1847 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1848 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1851 N (Container.First).Prev := Position.Node;
1852 N (Position.Node).Next := Container.First;
1854 Container.First := Position.Node;
1855 N (Container.First).Prev := 0;
1860 if Position.Node = Container.First then
1861 Container.First := N (Position.Node).Next;
1862 N (Container.First).Prev := 0;
1864 elsif Position.Node = Container.Last then
1865 Container.Last := N (Position.Node).Prev;
1866 N (Container.Last).Next := 0;
1869 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1870 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1873 N (N (Before.Node).Prev).Next := Position.Node;
1874 N (Position.Node).Prev := N (Before.Node).Prev;
1876 N (Before.Node).Prev := Position.Node;
1877 N (Position.Node).Next := Before.Node;
1879 pragma Assert (N (Container.First).Prev = 0);
1880 pragma Assert (N (Container.Last).Next = 0);
1884 (Target : in out List;
1886 Source : in out List;
1887 Position : in out Cursor)
1889 Target_Position : Count_Type;
1892 if Target'Address = Source'Address then
1893 Splice (Target, Before, Position);
1897 if Before.Container /= null then
1898 if Checks and then Before.Container /= Target'Unrestricted_Access then
1899 raise Program_Error with
1900 "Before cursor designates wrong container";
1903 pragma Assert (Vet (Before), "bad Before cursor in Splice");
1906 if Checks and then Position.Node = 0 then
1907 raise Constraint_Error with "Position cursor has no element";
1910 if Checks and then Position.Container /= Source'Unrestricted_Access then
1911 raise Program_Error with
1912 "Position cursor designates wrong container";
1915 pragma Assert (Vet (Position), "bad Position cursor in Splice");
1917 if Checks and then Target.Length >= Target.Capacity then
1918 raise Capacity_Error with "Target is full";
1921 TC_Check (Target.TC);
1922 TC_Check (Source.TC);
1926 Before => Before.Node,
1928 Src_Pos => Position.Node,
1929 Tgt_Pos => Target_Position);
1931 Position := Cursor'(Target
'Unrestricted_Access, Target_Position
);
1934 ---------------------
1935 -- Splice_Internal --
1936 ---------------------
1938 procedure Splice_Internal
1939 (Target
: in out List
;
1940 Before
: Count_Type
;
1941 Source
: in out List
)
1943 N
: Node_Array
renames Source
.Nodes
;
1947 -- This implements the corresponding Splice operation, after the
1948 -- parameters have been vetted, and corner-cases disposed of.
1950 pragma Assert
(Target
'Address /= Source
'Address);
1951 pragma Assert
(Source
.Length
> 0);
1952 pragma Assert
(Source
.First
/= 0);
1953 pragma Assert
(N
(Source
.First
).Prev
= 0);
1954 pragma Assert
(Source
.Last
/= 0);
1955 pragma Assert
(N
(Source
.Last
).Next
= 0);
1956 pragma Assert
(Target
.Length
<= Count_Type
'Last - Source
.Length
);
1957 pragma Assert
(Target
.Length
+ Source
.Length
<= Target
.Capacity
);
1959 while Source
.Length
> 1 loop
1960 -- Copy first element of Source onto Target
1962 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
1963 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
1965 -- Unlink the first node from Source
1968 pragma Assert
(N
(N
(X
).Next
).Prev
= X
);
1970 Source
.First
:= N
(X
).Next
;
1971 N
(Source
.First
).Prev
:= 0;
1973 Source
.Length
:= Source
.Length
- 1;
1975 -- Return the Source node to its free store
1980 -- Copy first (and only remaining) element of Source onto Target
1982 Allocate
(Target
, N
(Source
.First
).Element
, New_Node
=> X
);
1983 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> X
);
1985 -- Unlink the node from Source
1988 pragma Assert
(X
= Source
.Last
);
1995 -- Return the Source node to its free store
1998 end Splice_Internal
;
2000 procedure Splice_Internal
2001 (Target
: in out List
;
2002 Before
: Count_Type
; -- node of Target
2003 Source
: in out List
;
2004 Src_Pos
: Count_Type
; -- node of Source
2005 Tgt_Pos
: out Count_Type
)
2007 N
: Node_Array
renames Source
.Nodes
;
2010 -- This implements the corresponding Splice operation, after the
2011 -- parameters have been vetted, and corner-cases handled.
2013 pragma Assert
(Target
'Address /= Source
'Address);
2014 pragma Assert
(Target
.Length
< Target
.Capacity
);
2015 pragma Assert
(Source
.Length
> 0);
2016 pragma Assert
(Source
.First
/= 0);
2017 pragma Assert
(N
(Source
.First
).Prev
= 0);
2018 pragma Assert
(Source
.Last
/= 0);
2019 pragma Assert
(N
(Source
.Last
).Next
= 0);
2020 pragma Assert
(Src_Pos
/= 0);
2022 Allocate
(Target
, N
(Src_Pos
).Element
, New_Node
=> Tgt_Pos
);
2023 Insert_Internal
(Target
, Before
=> Before
, New_Node
=> Tgt_Pos
);
2025 if Source
.Length
= 1 then
2026 pragma Assert
(Source
.First
= Source
.Last
);
2027 pragma Assert
(Src_Pos
= Source
.First
);
2032 elsif Src_Pos
= Source
.First
then
2033 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2035 Source
.First
:= N
(Src_Pos
).Next
;
2036 N
(Source
.First
).Prev
:= 0;
2038 elsif Src_Pos
= Source
.Last
then
2039 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2041 Source
.Last
:= N
(Src_Pos
).Prev
;
2042 N
(Source
.Last
).Next
:= 0;
2045 pragma Assert
(Source
.Length
>= 3);
2046 pragma Assert
(N
(N
(Src_Pos
).Next
).Prev
= Src_Pos
);
2047 pragma Assert
(N
(N
(Src_Pos
).Prev
).Next
= Src_Pos
);
2049 N
(N
(Src_Pos
).Next
).Prev
:= N
(Src_Pos
).Prev
;
2050 N
(N
(Src_Pos
).Prev
).Next
:= N
(Src_Pos
).Next
;
2053 Source
.Length
:= Source
.Length
- 1;
2054 Free
(Source
, Src_Pos
);
2055 end Splice_Internal
;
2062 (Container
: in out List
;
2066 if Checks
and then I
.Node
= 0 then
2067 raise Constraint_Error
with "I cursor has no element";
2070 if Checks
and then J
.Node
= 0 then
2071 raise Constraint_Error
with "J cursor has no element";
2074 if Checks
and then I
.Container
/= Container
'Unchecked_Access then
2075 raise Program_Error
with "I cursor designates wrong container";
2078 if Checks
and then J
.Container
/= Container
'Unchecked_Access then
2079 raise Program_Error
with "J cursor designates wrong container";
2082 if I
.Node
= J
.Node
then
2086 TE_Check
(Container
.TC
);
2088 pragma Assert
(Vet
(I
), "bad I cursor in Swap");
2089 pragma Assert
(Vet
(J
), "bad J cursor in Swap");
2092 EI
: Element_Type
renames Container
.Nodes
(I
.Node
).Element
;
2093 EJ
: Element_Type
renames Container
.Nodes
(J
.Node
).Element
;
2095 EI_Copy
: constant Element_Type
:= EI
;
2107 procedure Swap_Links
2108 (Container
: in out List
;
2112 if Checks
and then I
.Node
= 0 then
2113 raise Constraint_Error
with "I cursor has no element";
2116 if Checks
and then J
.Node
= 0 then
2117 raise Constraint_Error
with "J cursor has no element";
2120 if Checks
and then I
.Container
/= Container
'Unrestricted_Access then
2121 raise Program_Error
with "I cursor designates wrong container";
2124 if Checks
and then J
.Container
/= Container
'Unrestricted_Access then
2125 raise Program_Error
with "J cursor designates wrong container";
2128 if I
.Node
= J
.Node
then
2132 TC_Check
(Container
.TC
);
2134 pragma Assert
(Vet
(I
), "bad I cursor in Swap_Links");
2135 pragma Assert
(Vet
(J
), "bad J cursor in Swap_Links");
2138 I_Next
: constant Cursor
:= Next
(I
);
2142 Splice
(Container
, Before
=> I
, Position
=> J
);
2146 J_Next
: constant Cursor
:= Next
(J
);
2150 Splice
(Container
, Before
=> J
, Position
=> I
);
2153 pragma Assert
(Container
.Length
>= 3);
2155 Splice
(Container
, Before
=> I_Next
, Position
=> J
);
2156 Splice
(Container
, Before
=> J_Next
, Position
=> I
);
2163 --------------------
2164 -- Update_Element --
2165 --------------------
2167 procedure Update_Element
2168 (Container
: in out List
;
2170 Process
: not null access procedure (Element
: in out Element_Type
))
2173 if Checks
and then Position
.Node
= 0 then
2174 raise Constraint_Error
with "Position cursor has no element";
2177 if Checks
and then Position
.Container
/= Container
'Unchecked_Access then
2178 raise Program_Error
with
2179 "Position cursor designates wrong container";
2182 pragma Assert
(Vet
(Position
), "bad cursor in Update_Element");
2185 Lock
: With_Lock
(Container
.TC
'Unchecked_Access);
2186 N
: Node_Type
renames Container
.Nodes
(Position
.Node
);
2188 Process
(N
.Element
);
2196 function Vet
(Position
: Cursor
) return Boolean is
2198 if Position
.Node
= 0 then
2199 return Position
.Container
= null;
2202 if Position
.Container
= null then
2207 L
: List
renames Position
.Container
.all;
2208 N
: Node_Array
renames L
.Nodes
;
2211 if L
.Length
= 0 then
2215 if L
.First
= 0 or L
.First
> L
.Capacity
then
2219 if L
.Last
= 0 or L
.Last
> L
.Capacity
then
2223 if N
(L
.First
).Prev
/= 0 then
2227 if N
(L
.Last
).Next
/= 0 then
2231 if Position
.Node
> L
.Capacity
then
2235 -- An invariant of an active node is that its Previous and Next
2236 -- components are non-negative. Operation Free sets the Previous
2237 -- component of the node to the value -1 before actually deallocating
2238 -- the node, to mark the node as inactive. (By "dellocating" we mean
2239 -- only that the node is linked onto a list of inactive nodes used
2240 -- for storage.) This marker gives us a simple way to detect a
2241 -- dangling reference to a node.
2243 if N
(Position
.Node
).Prev
< 0 then -- see Free
2247 if N
(Position
.Node
).Prev
> L
.Capacity
then
2251 if N
(Position
.Node
).Next
= Position
.Node
then
2255 if N
(Position
.Node
).Prev
= Position
.Node
then
2259 if N
(Position
.Node
).Prev
= 0
2260 and then Position
.Node
/= L
.First
2265 pragma Assert
(N
(Position
.Node
).Prev
/= 0
2266 or else Position
.Node
= L
.First
);
2268 if N
(Position
.Node
).Next
= 0
2269 and then Position
.Node
/= L
.Last
2274 pragma Assert
(N
(Position
.Node
).Next
/= 0
2275 or else Position
.Node
= L
.Last
);
2277 if L
.Length
= 1 then
2278 return L
.First
= L
.Last
;
2281 if L
.First
= L
.Last
then
2285 if N
(L
.First
).Next
= 0 then
2289 if N
(L
.Last
).Prev
= 0 then
2293 if N
(N
(L
.First
).Next
).Prev
/= L
.First
then
2297 if N
(N
(L
.Last
).Prev
).Next
/= L
.Last
then
2301 if L
.Length
= 2 then
2302 if N
(L
.First
).Next
/= L
.Last
then
2306 if N
(L
.Last
).Prev
/= L
.First
then
2313 if N
(L
.First
).Next
= L
.Last
then
2317 if N
(L
.Last
).Prev
= L
.First
then
2321 -- Eliminate earlier possibility
2323 if Position
.Node
= L
.First
then
2327 pragma Assert
(N
(Position
.Node
).Prev
/= 0);
2329 -- Eliminate another possibility
2331 if Position
.Node
= L
.Last
then
2335 pragma Assert
(N
(Position
.Node
).Next
/= 0);
2337 if N
(N
(Position
.Node
).Next
).Prev
/= Position
.Node
then
2341 if N
(N
(Position
.Node
).Prev
).Next
/= Position
.Node
then
2345 if L
.Length
= 3 then
2346 if N
(L
.First
).Next
/= Position
.Node
then
2350 if N
(L
.Last
).Prev
/= Position
.Node
then
2364 (Stream
: not null access Root_Stream_Type
'Class;
2370 Count_Type
'Base'Write (Stream, Item.Length);
2373 while Node /= 0 loop
2374 Element_Type'Write (Stream, Item.Nodes (Node).Element);
2375 Node := Item.Nodes (Node).Next;
2380 (Stream : not null access Root_Stream_Type'Class;
2384 raise Program_Error with "attempt to stream list cursor";
2388 (Stream : not null access Root_Stream_Type'Class;
2389 Item : Reference_Type)
2392 raise Program_Error with "attempt to stream reference";
2396 (Stream : not null access Root_Stream_Type'Class;
2397 Item : Constant_Reference_Type)
2400 raise Program_Error with "attempt to stream reference";
2403 end Ada.Containers.Bounded_Doubly_Linked_Lists;