1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- ADA.CONTAINERS.FORMAL_DOUBLY_LINKED_LISTS --
9 -- Copyright (C) 2010-2016, 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/>. --
26 ------------------------------------------------------------------------------
28 with System
; use type System
.Address
;
30 package body Ada
.Containers
.Formal_Doubly_Linked_Lists
with
34 -----------------------
35 -- Local Subprograms --
36 -----------------------
39 (Container
: in out List
;
40 New_Item
: Element_Type
;
41 New_Node
: out Count_Type
);
44 (Container
: in out List
;
45 New_Node
: out Count_Type
);
48 (Container
: in out List
;
51 procedure Insert_Internal
52 (Container
: in out List
;
54 New_Node
: Count_Type
);
56 function Vet
(L
: List
; Position
: Cursor
) return Boolean;
62 function "=" (Left
, Right
: List
) return Boolean is
66 if Left
'Address = Right
'Address then
70 if Left
.Length
/= Right
.Length
then
77 if Left
.Nodes
(LI
).Element
/= Right
.Nodes
(LI
).Element
then
81 LI
:= Left
.Nodes
(LI
).Next
;
82 RI
:= Right
.Nodes
(RI
).Next
;
93 (Container
: in out List
;
94 New_Item
: Element_Type
;
95 New_Node
: out Count_Type
)
97 N
: Node_Array
renames Container
.Nodes
;
100 if Container
.Free
>= 0 then
101 New_Node
:= Container
.Free
;
102 N
(New_Node
).Element
:= New_Item
;
103 Container
.Free
:= N
(New_Node
).Next
;
106 New_Node
:= abs Container
.Free
;
107 N
(New_Node
).Element
:= New_Item
;
108 Container
.Free
:= Container
.Free
- 1;
113 (Container
: in out List
;
114 New_Node
: out Count_Type
)
116 N
: Node_Array
renames Container
.Nodes
;
119 if Container
.Free
>= 0 then
120 New_Node
:= Container
.Free
;
121 Container
.Free
:= N
(New_Node
).Next
;
124 New_Node
:= abs Container
.Free
;
125 Container
.Free
:= Container
.Free
- 1;
134 (Container
: in out List
;
135 New_Item
: Element_Type
;
136 Count
: Count_Type
:= 1)
139 Insert
(Container
, No_Element
, New_Item
, Count
);
146 procedure Assign
(Target
: in out List
; Source
: List
) is
147 N
: Node_Array
renames Source
.Nodes
;
151 if Target
'Address = Source
'Address then
155 if Target
.Capacity
< Source
.Length
then
156 raise Constraint_Error
with -- ???
157 "Source length exceeds Target capacity";
164 Append
(Target
, N
(J
).Element
);
173 procedure Clear
(Container
: in out List
) is
174 N
: Node_Array
renames Container
.Nodes
;
178 if Container
.Length
= 0 then
179 pragma Assert
(Container
.First
= 0);
180 pragma Assert
(Container
.Last
= 0);
184 pragma Assert
(Container
.First
>= 1);
185 pragma Assert
(Container
.Last
>= 1);
186 pragma Assert
(N
(Container
.First
).Prev
= 0);
187 pragma Assert
(N
(Container
.Last
).Next
= 0);
189 while Container
.Length
> 1 loop
190 X
:= Container
.First
;
192 Container
.First
:= N
(X
).Next
;
193 N
(Container
.First
).Prev
:= 0;
195 Container
.Length
:= Container
.Length
- 1;
200 X
:= Container
.First
;
202 Container
.First
:= 0;
204 Container
.Length
:= 0;
215 Item
: Element_Type
) return Boolean
218 return Find
(Container
, Item
) /= No_Element
;
227 Capacity
: Count_Type
:= 0) return List
229 C
: constant Count_Type
:= Count_Type
'Max (Source
.Capacity
, Capacity
);
234 if 0 < Capacity
and then Capacity
< Source
.Capacity
then
235 raise Capacity_Error
;
239 while N
<= Source
.Capacity
loop
240 P
.Nodes
(N
).Prev
:= Source
.Nodes
(N
).Prev
;
241 P
.Nodes
(N
).Next
:= Source
.Nodes
(N
).Next
;
242 P
.Nodes
(N
).Element
:= Source
.Nodes
(N
).Element
;
246 P
.Free
:= Source
.Free
;
247 P
.Length
:= Source
.Length
;
248 P
.First
:= Source
.First
;
249 P
.Last
:= Source
.Last
;
252 N
:= Source
.Capacity
+ 1;
262 ---------------------
263 -- Current_To_Last --
264 ---------------------
266 function Current_To_Last
268 Current
: Cursor
) return List
is
269 Curs
: Cursor
:= First
(Container
);
270 C
: List
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
274 if Curs
= No_Element
then
279 if Current
/= No_Element
and not Has_Element
(Container
, Current
) then
280 raise Constraint_Error
;
283 while Curs
.Node
/= Current
.Node
loop
286 Curs
:= Next
(Container
, (Node
=> Node
));
297 (Container
: in out List
;
298 Position
: in out Cursor
;
299 Count
: Count_Type
:= 1)
301 N
: Node_Array
renames Container
.Nodes
;
305 if not Has_Element
(Container
=> Container
,
306 Position
=> Position
)
308 raise Constraint_Error
with
309 "Position cursor has no element";
312 pragma Assert
(Vet
(Container
, Position
), "bad cursor in Delete");
313 pragma Assert
(Container
.First
>= 1);
314 pragma Assert
(Container
.Last
>= 1);
315 pragma Assert
(N
(Container
.First
).Prev
= 0);
316 pragma Assert
(N
(Container
.Last
).Next
= 0);
318 if Position
.Node
= Container
.First
then
319 Delete_First
(Container
, Count
);
320 Position
:= No_Element
;
325 Position
:= No_Element
;
329 for Index
in 1 .. Count
loop
330 pragma Assert
(Container
.Length
>= 2);
333 Container
.Length
:= Container
.Length
- 1;
335 if X
= Container
.Last
then
336 Position
:= No_Element
;
338 Container
.Last
:= N
(X
).Prev
;
339 N
(Container
.Last
).Next
:= 0;
345 Position
.Node
:= N
(X
).Next
;
346 pragma Assert
(N
(Position
.Node
).Prev
>= 0);
348 N
(N
(X
).Next
).Prev
:= N
(X
).Prev
;
349 N
(N
(X
).Prev
).Next
:= N
(X
).Next
;
353 Position
:= No_Element
;
360 procedure Delete_First
361 (Container
: in out List
;
362 Count
: Count_Type
:= 1)
364 N
: Node_Array
renames Container
.Nodes
;
368 if Count
>= Container
.Length
then
377 for J
in 1 .. Count
loop
378 X
:= Container
.First
;
379 pragma Assert
(N
(N
(X
).Next
).Prev
= Container
.First
);
381 Container
.First
:= N
(X
).Next
;
382 N
(Container
.First
).Prev
:= 0;
384 Container
.Length
:= Container
.Length
- 1;
394 procedure Delete_Last
395 (Container
: in out List
;
396 Count
: Count_Type
:= 1)
398 N
: Node_Array
renames Container
.Nodes
;
402 if Count
>= Container
.Length
then
411 for J
in 1 .. Count
loop
413 pragma Assert
(N
(N
(X
).Prev
).Next
= Container
.Last
);
415 Container
.Last
:= N
(X
).Prev
;
416 N
(Container
.Last
).Next
:= 0;
418 Container
.Length
:= Container
.Length
- 1;
430 Position
: Cursor
) return Element_Type
433 if not Has_Element
(Container
=> Container
, Position
=> Position
) then
434 raise Constraint_Error
with
435 "Position cursor has no element";
438 return Container
.Nodes
(Position
.Node
).Element
;
448 Position
: Cursor
:= No_Element
) return Cursor
450 From
: Count_Type
:= Position
.Node
;
453 if From
= 0 and Container
.Length
= 0 then
458 From
:= Container
.First
;
461 if Position
.Node
/= 0 and then
462 not Has_Element
(Container
, Position
)
464 raise Constraint_Error
with
465 "Position cursor has no element";
469 if Container
.Nodes
(From
).Element
= Item
then
470 return (Node
=> From
);
473 From
:= Container
.Nodes
(From
).Next
;
483 function First
(Container
: List
) return Cursor
is
485 if Container
.First
= 0 then
489 return (Node
=> Container
.First
);
496 function First_Element
(Container
: List
) return Element_Type
is
497 F
: constant Count_Type
:= Container
.First
;
500 raise Constraint_Error
with "list is empty";
502 return Container
.Nodes
(F
).Element
;
506 -----------------------
507 -- First_To_Previous --
508 -----------------------
510 function First_To_Previous
512 Current
: Cursor
) return List
514 Curs
: Cursor
:= Current
;
515 C
: List
(Container
.Capacity
) := Copy
(Container
, Container
.Capacity
);
519 if Curs
= No_Element
then
522 elsif not Has_Element
(Container
, Curs
) then
523 raise Constraint_Error
;
526 while Curs
.Node
/= 0 loop
529 Curs
:= Next
(Container
, (Node
=> Node
));
534 end First_To_Previous
;
541 (Container
: in out List
;
544 pragma Assert
(X
> 0);
545 pragma Assert
(X
<= Container
.Capacity
);
547 N
: Node_Array
renames Container
.Nodes
;
550 N
(X
).Prev
:= -1; -- Node is deallocated (not on active list)
552 if Container
.Free
>= 0 then
553 N
(X
).Next
:= Container
.Free
;
556 elsif X
+ 1 = abs Container
.Free
then
557 N
(X
).Next
:= 0; -- Not strictly necessary, but marginally safer
558 Container
.Free
:= Container
.Free
+ 1;
561 Container
.Free
:= abs Container
.Free
;
563 if Container
.Free
> Container
.Capacity
then
567 for J
in Container
.Free
.. Container
.Capacity
- 1 loop
571 N
(Container
.Capacity
).Next
:= 0;
574 N
(X
).Next
:= Container
.Free
;
579 ---------------------
580 -- Generic_Sorting --
581 ---------------------
583 package body Generic_Sorting
with SPARK_Mode
=> Off
is
589 function Is_Sorted
(Container
: List
) return Boolean is
590 Nodes
: Node_Array
renames Container
.Nodes
;
591 Node
: Count_Type
:= Container
.First
;
594 for J
in 2 .. Container
.Length
loop
595 if Nodes
(Nodes
(Node
).Next
).Element
< Nodes
(Node
).Element
then
598 Node
:= Nodes
(Node
).Next
;
610 (Target
: in out List
;
611 Source
: in out List
)
613 LN
: Node_Array
renames Target
.Nodes
;
614 RN
: Node_Array
renames Source
.Nodes
;
619 if Target
'Address = Source
'Address then
623 LI
:= First
(Target
);
624 RI
:= First
(Source
);
625 while RI
.Node
/= 0 loop
626 pragma Assert
(RN
(RI
.Node
).Next
= 0
627 or else not (RN
(RN
(RI
.Node
).Next
).Element
<
628 RN
(RI
.Node
).Element
));
631 Splice
(Target
, No_Element
, Source
);
635 pragma Assert
(LN
(LI
.Node
).Next
= 0
636 or else not (LN
(LN
(LI
.Node
).Next
).Element
<
637 LN
(LI
.Node
).Element
));
639 if RN
(RI
.Node
).Element
< LN
(LI
.Node
).Element
then
642 pragma Warnings
(Off
, RJ
);
644 RI
.Node
:= RN
(RI
.Node
).Next
;
645 Splice
(Target
, LI
, Source
, RJ
);
649 LI
.Node
:= LN
(LI
.Node
).Next
;
658 procedure Sort
(Container
: in out List
) is
659 N
: Node_Array
renames Container
.Nodes
;
661 procedure Partition
(Pivot
, Back
: Count_Type
);
662 procedure Sort
(Front
, Back
: Count_Type
);
668 procedure Partition
(Pivot
, Back
: Count_Type
) is
672 Node
:= N
(Pivot
).Next
;
673 while Node
/= Back
loop
674 if N
(Node
).Element
< N
(Pivot
).Element
then
676 Prev
: constant Count_Type
:= N
(Node
).Prev
;
677 Next
: constant Count_Type
:= N
(Node
).Next
;
680 N
(Prev
).Next
:= Next
;
683 Container
.Last
:= Prev
;
685 N
(Next
).Prev
:= Prev
;
688 N
(Node
).Next
:= Pivot
;
689 N
(Node
).Prev
:= N
(Pivot
).Prev
;
691 N
(Pivot
).Prev
:= Node
;
693 if N
(Node
).Prev
= 0 then
694 Container
.First
:= Node
;
696 N
(N
(Node
).Prev
).Next
:= Node
;
703 Node
:= N
(Node
).Next
;
712 procedure Sort
(Front
, Back
: Count_Type
) is
717 Pivot
:= Container
.First
;
719 Pivot
:= N
(Front
).Next
;
722 if Pivot
/= Back
then
723 Partition
(Pivot
, Back
);
729 -- Start of processing for Sort
732 if Container
.Length
<= 1 then
736 pragma Assert
(N
(Container
.First
).Prev
= 0);
737 pragma Assert
(N
(Container
.Last
).Next
= 0);
739 Sort
(Front
=> 0, Back
=> 0);
741 pragma Assert
(N
(Container
.First
).Prev
= 0);
742 pragma Assert
(N
(Container
.Last
).Next
= 0);
751 function Has_Element
(Container
: List
; Position
: Cursor
) return Boolean is
753 if Position
.Node
= 0 then
757 return Container
.Nodes
(Position
.Node
).Prev
/= -1;
765 (Container
: in out List
;
767 New_Item
: Element_Type
;
768 Position
: out Cursor
;
769 Count
: Count_Type
:= 1)
774 if Before
.Node
/= 0 then
775 pragma Assert
(Vet
(Container
, Before
), "bad cursor in Insert");
783 if Container
.Length
> Container
.Capacity
- Count
then
784 raise Constraint_Error
with "new length exceeds capacity";
787 Allocate
(Container
, New_Item
, New_Node
=> J
);
788 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
789 Position
:= (Node
=> J
);
791 for Index
in 2 .. Count
loop
792 Allocate
(Container
, New_Item
, New_Node
=> J
);
793 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
798 (Container
: in out List
;
800 New_Item
: Element_Type
;
801 Count
: Count_Type
:= 1)
805 Insert
(Container
, Before
, New_Item
, Position
, Count
);
809 (Container
: in out List
;
811 Position
: out Cursor
;
812 Count
: Count_Type
:= 1)
817 if Before
.Node
/= 0 then
818 pragma Assert
(Vet
(Container
, Before
), "bad cursor in Insert");
826 if Container
.Length
> Container
.Capacity
- Count
then
827 raise Constraint_Error
with "new length exceeds capacity";
830 Allocate
(Container
, New_Node
=> J
);
831 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
832 Position
:= (Node
=> J
);
834 for Index
in 2 .. Count
loop
835 Allocate
(Container
, New_Node
=> J
);
836 Insert_Internal
(Container
, Before
.Node
, New_Node
=> J
);
840 ---------------------
841 -- Insert_Internal --
842 ---------------------
844 procedure Insert_Internal
845 (Container
: in out List
;
847 New_Node
: Count_Type
)
849 N
: Node_Array
renames Container
.Nodes
;
852 if Container
.Length
= 0 then
853 pragma Assert
(Before
= 0);
854 pragma Assert
(Container
.First
= 0);
855 pragma Assert
(Container
.Last
= 0);
857 Container
.First
:= New_Node
;
858 Container
.Last
:= New_Node
;
860 N
(Container
.First
).Prev
:= 0;
861 N
(Container
.Last
).Next
:= 0;
863 elsif Before
= 0 then
864 pragma Assert
(N
(Container
.Last
).Next
= 0);
866 N
(Container
.Last
).Next
:= New_Node
;
867 N
(New_Node
).Prev
:= Container
.Last
;
869 Container
.Last
:= New_Node
;
870 N
(Container
.Last
).Next
:= 0;
872 elsif Before
= Container
.First
then
873 pragma Assert
(N
(Container
.First
).Prev
= 0);
875 N
(Container
.First
).Prev
:= New_Node
;
876 N
(New_Node
).Next
:= Container
.First
;
878 Container
.First
:= New_Node
;
879 N
(Container
.First
).Prev
:= 0;
882 pragma Assert
(N
(Container
.First
).Prev
= 0);
883 pragma Assert
(N
(Container
.Last
).Next
= 0);
885 N
(New_Node
).Next
:= Before
;
886 N
(New_Node
).Prev
:= N
(Before
).Prev
;
888 N
(N
(Before
).Prev
).Next
:= New_Node
;
889 N
(Before
).Prev
:= New_Node
;
892 Container
.Length
:= Container
.Length
+ 1;
899 function Is_Empty
(Container
: List
) return Boolean is
901 return Length
(Container
) = 0;
908 function Last
(Container
: List
) return Cursor
is
910 if Container
.Last
= 0 then
914 return (Node
=> Container
.Last
);
921 function Last_Element
(Container
: List
) return Element_Type
is
922 L
: constant Count_Type
:= Container
.Last
;
925 raise Constraint_Error
with "list is empty";
927 return Container
.Nodes
(L
).Element
;
935 function Length
(Container
: List
) return Count_Type
is
937 return Container
.Length
;
945 (Target
: in out List
;
946 Source
: in out List
)
948 N
: Node_Array
renames Source
.Nodes
;
952 if Target
'Address = Source
'Address then
956 if Target
.Capacity
< Source
.Length
then
957 raise Constraint_Error
with -- ???
958 "Source length exceeds Target capacity";
963 while Source
.Length
> 1 loop
964 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
965 pragma Assert
(Source
.Last
/= Source
.First
);
966 pragma Assert
(N
(Source
.First
).Prev
= 0);
967 pragma Assert
(N
(Source
.Last
).Next
= 0);
969 -- Copy first element from Source to Target
972 Append
(Target
, N
(X
).Element
); -- optimize away???
974 -- Unlink first node of Source
976 Source
.First
:= N
(X
).Next
;
977 N
(Source
.First
).Prev
:= 0;
979 Source
.Length
:= Source
.Length
- 1;
981 -- The representation invariants for Source have been restored. It is
982 -- now safe to free the unlinked node, without fear of corrupting the
983 -- active links of Source.
985 -- Note that the algorithm we use here models similar algorithms used
986 -- in the unbounded form of the doubly-linked list container. In that
987 -- case, Free is an instantation of Unchecked_Deallocation, which can
988 -- fail (because PE will be raised if controlled Finalize fails), so
989 -- we must defer the call until the last step. Here in the bounded
990 -- form, Free merely links the node we have just "deallocated" onto a
991 -- list of inactive nodes, so technically Free cannot fail. However,
992 -- for consistency, we handle Free the same way here as we do for the
993 -- unbounded form, with the pessimistic assumption that it can fail.
998 if Source
.Length
= 1 then
999 pragma Assert
(Source
.First
in 1 .. Source
.Capacity
);
1000 pragma Assert
(Source
.Last
= Source
.First
);
1001 pragma Assert
(N
(Source
.First
).Prev
= 0);
1002 pragma Assert
(N
(Source
.Last
).Next
= 0);
1004 -- Copy element from Source to Target
1007 Append
(Target
, N
(X
).Element
);
1009 -- Unlink node of Source
1015 -- Return the unlinked node to the free store
1025 procedure Next
(Container
: List
; Position
: in out Cursor
) is
1027 Position
:= Next
(Container
, Position
);
1030 function Next
(Container
: List
; Position
: Cursor
) return Cursor
is
1032 if Position
.Node
= 0 then
1036 if not Has_Element
(Container
, Position
) then
1037 raise Program_Error
with "Position cursor has no element";
1040 return (Node
=> Container
.Nodes
(Position
.Node
).Next
);
1048 (Container
: in out List
;
1049 New_Item
: Element_Type
;
1050 Count
: Count_Type
:= 1)
1053 Insert
(Container
, First
(Container
), New_Item
, Count
);
1060 procedure Previous
(Container
: List
; Position
: in out Cursor
) is
1062 Position
:= Previous
(Container
, Position
);
1065 function Previous
(Container
: List
; Position
: Cursor
) return Cursor
is
1067 if Position
.Node
= 0 then
1071 if not Has_Element
(Container
, Position
) then
1072 raise Program_Error
with "Position cursor has no element";
1075 return (Node
=> Container
.Nodes
(Position
.Node
).Prev
);
1078 ---------------------
1079 -- Replace_Element --
1080 ---------------------
1082 procedure Replace_Element
1083 (Container
: in out List
;
1085 New_Item
: Element_Type
)
1088 if not Has_Element
(Container
, Position
) then
1089 raise Constraint_Error
with "Position cursor has no element";
1093 (Vet
(Container
, Position
), "bad cursor in Replace_Element");
1095 Container
.Nodes
(Position
.Node
).Element
:= New_Item
;
1096 end Replace_Element
;
1098 ----------------------
1099 -- Reverse_Elements --
1100 ----------------------
1102 procedure Reverse_Elements
(Container
: in out List
) is
1103 N
: Node_Array
renames Container
.Nodes
;
1104 I
: Count_Type
:= Container
.First
;
1105 J
: Count_Type
:= Container
.Last
;
1107 procedure Swap
(L
, R
: Count_Type
);
1113 procedure Swap
(L
, R
: Count_Type
) is
1114 LN
: constant Count_Type
:= N
(L
).Next
;
1115 LP
: constant Count_Type
:= N
(L
).Prev
;
1117 RN
: constant Count_Type
:= N
(R
).Next
;
1118 RP
: constant Count_Type
:= N
(R
).Prev
;
1133 pragma Assert
(RP
= L
);
1147 -- Start of processing for Reverse_Elements
1150 if Container
.Length
<= 1 then
1154 pragma Assert
(N
(Container
.First
).Prev
= 0);
1155 pragma Assert
(N
(Container
.Last
).Next
= 0);
1157 Container
.First
:= J
;
1158 Container
.Last
:= I
;
1160 Swap
(L
=> I
, R
=> J
);
1168 Swap
(L
=> J
, R
=> I
);
1177 pragma Assert
(N
(Container
.First
).Prev
= 0);
1178 pragma Assert
(N
(Container
.Last
).Next
= 0);
1179 end Reverse_Elements
;
1185 function Reverse_Find
1187 Item
: Element_Type
;
1188 Position
: Cursor
:= No_Element
) return Cursor
1190 CFirst
: Count_Type
:= Position
.Node
;
1194 CFirst
:= Container
.First
;
1197 if Container
.Length
= 0 then
1201 while CFirst
/= 0 loop
1202 if Container
.Nodes
(CFirst
).Element
= Item
then
1203 return (Node
=> CFirst
);
1205 CFirst
:= Container
.Nodes
(CFirst
).Prev
;
1218 (Target
: in out List
;
1220 Source
: in out List
)
1222 SN
: Node_Array
renames Source
.Nodes
;
1225 if Before
.Node
/= 0 then
1226 pragma Assert
(Vet
(Target
, Before
), "bad cursor in Splice");
1229 if Target
'Address = Source
'Address
1230 or else Source
.Length
= 0
1235 pragma Assert
(SN
(Source
.First
).Prev
= 0);
1236 pragma Assert
(SN
(Source
.Last
).Next
= 0);
1238 if Target
.Length
> Count_Type
'Base'Last - Source.Length then
1239 raise Constraint_Error with "new length exceeds maximum";
1242 if Target.Length + Source.Length > Target.Capacity then
1243 raise Constraint_Error;
1247 Insert (Target, Before, SN (Source.Last).Element);
1248 Delete_Last (Source);
1249 exit when Is_Empty (Source);
1254 (Target : in out List;
1256 Source : in out List;
1257 Position : in out Cursor)
1259 Target_Position : Cursor;
1262 if Target'Address = Source'Address then
1263 Splice (Target, Before, Position);
1267 if Position.Node = 0 then
1268 raise Constraint_Error with "Position cursor has no element";
1271 pragma Assert (Vet (Source, Position), "bad Position cursor in Splice");
1273 if Target.Length >= Target.Capacity then
1274 raise Constraint_Error;
1278 (Container => Target,
1280 New_Item => Source.Nodes (Position.Node).Element,
1281 Position => Target_Position);
1283 Delete (Source, Position);
1284 Position := Target_Position;
1288 (Container : in out List;
1292 N : Node_Array renames Container.Nodes;
1295 if Before.Node /= 0 then
1297 (Vet (Container, Before), "bad Before cursor in Splice");
1300 if Position.Node = 0 then
1301 raise Constraint_Error with "Position cursor has no element";
1305 (Vet (Container, Position), "bad Position cursor in Splice");
1307 if Position.Node = Before.Node
1308 or else N (Position.Node).Next = Before.Node
1313 pragma Assert (Container.Length >= 2);
1315 if Before.Node = 0 then
1316 pragma Assert (Position.Node /= Container.Last);
1318 if Position.Node = Container.First then
1319 Container.First := N (Position.Node).Next;
1320 N (Container.First).Prev := 0;
1323 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1324 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1327 N (Container.Last).Next := Position.Node;
1328 N (Position.Node).Prev := Container.Last;
1330 Container.Last := Position.Node;
1331 N (Container.Last).Next := 0;
1336 if Before.Node = Container.First then
1337 pragma Assert (Position.Node /= Container.First);
1339 if Position.Node = Container.Last then
1340 Container.Last := N (Position.Node).Prev;
1341 N (Container.Last).Next := 0;
1344 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1345 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1348 N (Container.First).Prev := Position.Node;
1349 N (Position.Node).Next := Container.First;
1351 Container.First := Position.Node;
1352 N (Container.First).Prev := 0;
1357 if Position.Node = Container.First then
1358 Container.First := N (Position.Node).Next;
1359 N (Container.First).Prev := 0;
1361 elsif Position.Node = Container.Last then
1362 Container.Last := N (Position.Node).Prev;
1363 N (Container.Last).Next := 0;
1366 N (N (Position.Node).Prev).Next := N (Position.Node).Next;
1367 N (N (Position.Node).Next).Prev := N (Position.Node).Prev;
1370 N (N (Before.Node).Prev).Next := Position.Node;
1371 N (Position.Node).Prev := N (Before.Node).Prev;
1373 N (Before.Node).Prev := Position.Node;
1374 N (Position.Node).Next := Before.Node;
1376 pragma Assert (N (Container.First).Prev = 0);
1377 pragma Assert (N (Container.Last).Next = 0);
1384 function Strict_Equal (Left, Right : List) return Boolean is
1385 CL : Count_Type := Left.First;
1386 CR : Count_Type := Right.First;
1389 while CL /= 0 or CR /= 0 loop
1391 Left.Nodes (CL).Element /= Right.Nodes (CL).Element
1396 CL := Left.Nodes (CL).Next;
1397 CR := Right.Nodes (CR).Next;
1408 (Container : in out List;
1413 raise Constraint_Error with "I cursor has no element";
1417 raise Constraint_Error with "J cursor has no element";
1420 if I.Node = J.Node then
1424 pragma Assert (Vet (Container, I), "bad I cursor in Swap");
1425 pragma Assert (Vet (Container, J), "bad J cursor in Swap");
1428 NN : Node_Array renames Container.Nodes;
1429 NI : Node_Type renames NN (I.Node);
1430 NJ : Node_Type renames NN (J.Node);
1432 EI_Copy : constant Element_Type := NI.Element;
1435 NI.Element := NJ.Element;
1436 NJ.Element := EI_Copy;
1444 procedure Swap_Links
1445 (Container : in out List;
1448 I_Next, J_Next : Cursor;
1452 raise Constraint_Error with "I cursor has no element";
1456 raise Constraint_Error with "J cursor has no element";
1459 if I.Node = J.Node then
1463 pragma Assert (Vet (Container, I), "bad I cursor in Swap_Links");
1464 pragma Assert (Vet (Container, J), "bad J cursor in Swap_Links");
1466 I_Next := Next (Container, I);
1469 Splice (Container, Before => I, Position => J);
1472 J_Next := Next (Container, J);
1475 Splice (Container, Before => J, Position => I);
1478 pragma Assert (Container.Length >= 3);
1479 Splice (Container, Before => I_Next, Position => J);
1480 Splice (Container, Before => J_Next, Position => I);
1489 function Vet (L : List; Position : Cursor) return Boolean is
1490 N : Node_Array renames L.Nodes;
1493 if L.Length = 0 then
1505 if Position.Node > L.Capacity then
1509 if N (Position.Node).Prev < 0
1510 or else N (Position.Node).Prev > L.Capacity
1515 if N (Position.Node).Next > L.Capacity then
1519 if N (L.First).Prev /= 0 then
1523 if N (L.Last).Next /= 0 then
1527 if N (Position.Node).Prev = 0
1528 and then Position.Node /= L.First
1533 if N (Position.Node).Next = 0
1534 and then Position.Node /= L.Last
1539 if L.Length = 1 then
1540 return L.First = L.Last;
1543 if L.First = L.Last then
1547 if N (L.First).Next = 0 then
1551 if N (L.Last).Prev = 0 then
1555 if N (N (L.First).Next).Prev /= L.First then
1559 if N (N (L.Last).Prev).Next /= L.Last then
1563 if L.Length = 2 then
1564 if N (L.First).Next /= L.Last then
1568 if N (L.Last).Prev /= L.First then
1575 if N (L.First).Next = L.Last then
1579 if N (L.Last).Prev = L.First then
1583 if Position.Node = L.First then
1587 if Position.Node = L.Last then
1591 if N (Position.Node).Next = 0 then
1595 if N (Position.Node).Prev = 0 then
1599 if N (N (Position.Node).Next).Prev /= Position.Node then
1603 if N (N (Position.Node).Prev).Next /= Position.Node then
1607 if L.Length = 3 then
1608 if N (L.First).Next /= Position.Node then
1612 if N (L.Last).Prev /= Position.Node then
1620 end Ada.Containers.Formal_Doubly_Linked_Lists;